18d7fafffSZhi-Jun Robin Fu /* 28d7fafffSZhi-Jun Robin Fu * CDDL HEADER START 38d7fafffSZhi-Jun Robin Fu * 48d7fafffSZhi-Jun Robin Fu * The contents of this file are subject to the terms of the 58d7fafffSZhi-Jun Robin Fu * Common Development and Distribution License (the "License"). 68d7fafffSZhi-Jun Robin Fu * You may not use this file except in compliance with the License. 78d7fafffSZhi-Jun Robin Fu * 88d7fafffSZhi-Jun Robin Fu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98d7fafffSZhi-Jun Robin Fu * or http://www.opensolaris.org/os/licensing. 108d7fafffSZhi-Jun Robin Fu * See the License for the specific language governing permissions 118d7fafffSZhi-Jun Robin Fu * and limitations under the License. 128d7fafffSZhi-Jun Robin Fu * 138d7fafffSZhi-Jun Robin Fu * When distributing Covered Code, include this CDDL HEADER in each 148d7fafffSZhi-Jun Robin Fu * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158d7fafffSZhi-Jun Robin Fu * If applicable, add the following below this CDDL HEADER, with the 168d7fafffSZhi-Jun Robin Fu * fields enclosed by brackets "[]" replaced with your own identifying 178d7fafffSZhi-Jun Robin Fu * information: Portions Copyright [yyyy] [name of copyright owner] 188d7fafffSZhi-Jun Robin Fu * 198d7fafffSZhi-Jun Robin Fu * CDDL HEADER END 208d7fafffSZhi-Jun Robin Fu */ 218d7fafffSZhi-Jun Robin Fu /* 228d7fafffSZhi-Jun Robin Fu * Copyright 2010 Advanced Micro Devices, Inc. 238d7fafffSZhi-Jun Robin Fu * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 248d7fafffSZhi-Jun Robin Fu */ 258d7fafffSZhi-Jun Robin Fu 268d7fafffSZhi-Jun Robin Fu /* 278d7fafffSZhi-Jun Robin Fu * PCI Mechanism 1 low-level routines with ECS support for AMD family >= 0x10 288d7fafffSZhi-Jun Robin Fu */ 298d7fafffSZhi-Jun Robin Fu 308d7fafffSZhi-Jun Robin Fu #include <sys/controlregs.h> 318d7fafffSZhi-Jun Robin Fu #include <sys/cpuvar.h> 328d7fafffSZhi-Jun Robin Fu #include <sys/types.h> 338d7fafffSZhi-Jun Robin Fu #include <sys/pci.h> 348d7fafffSZhi-Jun Robin Fu #include <sys/pci_impl.h> 358d7fafffSZhi-Jun Robin Fu #include <sys/sunddi.h> 368d7fafffSZhi-Jun Robin Fu #include <sys/pci_cfgspace_impl.h> 378d7fafffSZhi-Jun Robin Fu #include <sys/x86_archext.h> 388d7fafffSZhi-Jun Robin Fu 398d7fafffSZhi-Jun Robin Fu boolean_t 408d7fafffSZhi-Jun Robin Fu pci_check_amd_ioecs(void) 418d7fafffSZhi-Jun Robin Fu { 428d7fafffSZhi-Jun Robin Fu struct cpuid_regs cp; 438d7fafffSZhi-Jun Robin Fu int family; 448d7fafffSZhi-Jun Robin Fu 45*7417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) 468d7fafffSZhi-Jun Robin Fu return (B_FALSE); 478d7fafffSZhi-Jun Robin Fu 488d7fafffSZhi-Jun Robin Fu /* 498d7fafffSZhi-Jun Robin Fu * Get the CPU vendor string from CPUID. 508d7fafffSZhi-Jun Robin Fu * This PCI mechanism only applies to AMD CPUs. 518d7fafffSZhi-Jun Robin Fu */ 528d7fafffSZhi-Jun Robin Fu cp.cp_eax = 0; 538d7fafffSZhi-Jun Robin Fu (void) __cpuid_insn(&cp); 548d7fafffSZhi-Jun Robin Fu 558d7fafffSZhi-Jun Robin Fu if ((cp.cp_ebx != 0x68747541) || /* Auth */ 568d7fafffSZhi-Jun Robin Fu (cp.cp_edx != 0x69746e65) || /* enti */ 578d7fafffSZhi-Jun Robin Fu (cp.cp_ecx != 0x444d4163)) /* cAMD */ 588d7fafffSZhi-Jun Robin Fu return (B_FALSE); 598d7fafffSZhi-Jun Robin Fu 608d7fafffSZhi-Jun Robin Fu /* 618d7fafffSZhi-Jun Robin Fu * Get the CPU family from CPUID. 628d7fafffSZhi-Jun Robin Fu * This PCI mechanism is only available on family 0x10 or higher. 638d7fafffSZhi-Jun Robin Fu */ 648d7fafffSZhi-Jun Robin Fu cp.cp_eax = 1; 658d7fafffSZhi-Jun Robin Fu (void) __cpuid_insn(&cp); 668d7fafffSZhi-Jun Robin Fu family = ((cp.cp_eax >> 8) & 0xf) + ((cp.cp_eax >> 20) & 0xff); 678d7fafffSZhi-Jun Robin Fu 688d7fafffSZhi-Jun Robin Fu if (family < 0x10) 698d7fafffSZhi-Jun Robin Fu return (B_FALSE); 708d7fafffSZhi-Jun Robin Fu 718d7fafffSZhi-Jun Robin Fu /* 728d7fafffSZhi-Jun Robin Fu * Set the EnableCf8ExtCfg bit in the Northbridge Configuration Register 738d7fafffSZhi-Jun Robin Fu * to enable accessing PCI ECS using in/out instructions. 748d7fafffSZhi-Jun Robin Fu */ 758d7fafffSZhi-Jun Robin Fu wrmsr(MSR_AMD_NB_CFG, rdmsr(MSR_AMD_NB_CFG) | AMD_GH_NB_CFG_EN_ECS); 768d7fafffSZhi-Jun Robin Fu return (B_TRUE); 778d7fafffSZhi-Jun Robin Fu } 788d7fafffSZhi-Jun Robin Fu 798d7fafffSZhi-Jun Robin Fu /* 808d7fafffSZhi-Jun Robin Fu * Macro to setup PCI Extended Configuration Space (ECS) address to give to 818d7fafffSZhi-Jun Robin Fu * "in/out" instructions 828d7fafffSZhi-Jun Robin Fu */ 838d7fafffSZhi-Jun Robin Fu #define PCI_CADDR1_ECS(b, d, f, r) \ 848d7fafffSZhi-Jun Robin Fu (PCI_CADDR1((b), (d), (f), (r)) | ((((r) >> 8) & 0xf) << 24)) 858d7fafffSZhi-Jun Robin Fu 868d7fafffSZhi-Jun Robin Fu /* 878d7fafffSZhi-Jun Robin Fu * Per PCI 2.1 section 3.7.4.1 and PCI-PCI Bridge Architecture 1.0 section 888d7fafffSZhi-Jun Robin Fu * 5.3.1.2: dev=31 func=7 reg=0 means a special cycle. We don't want to 898d7fafffSZhi-Jun Robin Fu * trigger that by accident, so we pretend that dev 31, func 7 doesn't 908d7fafffSZhi-Jun Robin Fu * exist. If we ever want special cycle support, we'll add explicit 918d7fafffSZhi-Jun Robin Fu * special cycle support. 928d7fafffSZhi-Jun Robin Fu */ 938d7fafffSZhi-Jun Robin Fu 948d7fafffSZhi-Jun Robin Fu uint8_t 958d7fafffSZhi-Jun Robin Fu pci_mech1_amd_getb(int bus, int device, int function, int reg) 968d7fafffSZhi-Jun Robin Fu { 978d7fafffSZhi-Jun Robin Fu uint8_t val; 988d7fafffSZhi-Jun Robin Fu 998d7fafffSZhi-Jun Robin Fu if (device == PCI_MECH1_SPEC_CYCLE_DEV && 1008d7fafffSZhi-Jun Robin Fu function == PCI_MECH1_SPEC_CYCLE_FUNC) { 1018d7fafffSZhi-Jun Robin Fu return (0xff); 1028d7fafffSZhi-Jun Robin Fu } 1038d7fafffSZhi-Jun Robin Fu 1048d7fafffSZhi-Jun Robin Fu mutex_enter(&pcicfg_mutex); 1058d7fafffSZhi-Jun Robin Fu outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg)); 1068d7fafffSZhi-Jun Robin Fu val = inb(PCI_CONFDATA | (reg & 0x3)); 1078d7fafffSZhi-Jun Robin Fu mutex_exit(&pcicfg_mutex); 1088d7fafffSZhi-Jun Robin Fu return (val); 1098d7fafffSZhi-Jun Robin Fu } 1108d7fafffSZhi-Jun Robin Fu 1118d7fafffSZhi-Jun Robin Fu uint16_t 1128d7fafffSZhi-Jun Robin Fu pci_mech1_amd_getw(int bus, int device, int function, int reg) 1138d7fafffSZhi-Jun Robin Fu { 1148d7fafffSZhi-Jun Robin Fu uint16_t val; 1158d7fafffSZhi-Jun Robin Fu 1168d7fafffSZhi-Jun Robin Fu if (device == PCI_MECH1_SPEC_CYCLE_DEV && 1178d7fafffSZhi-Jun Robin Fu function == PCI_MECH1_SPEC_CYCLE_FUNC) { 1188d7fafffSZhi-Jun Robin Fu return (0xffff); 1198d7fafffSZhi-Jun Robin Fu } 1208d7fafffSZhi-Jun Robin Fu 1218d7fafffSZhi-Jun Robin Fu mutex_enter(&pcicfg_mutex); 1228d7fafffSZhi-Jun Robin Fu outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg)); 1238d7fafffSZhi-Jun Robin Fu val = inw(PCI_CONFDATA | (reg & 0x2)); 1248d7fafffSZhi-Jun Robin Fu mutex_exit(&pcicfg_mutex); 1258d7fafffSZhi-Jun Robin Fu return (val); 1268d7fafffSZhi-Jun Robin Fu } 1278d7fafffSZhi-Jun Robin Fu 1288d7fafffSZhi-Jun Robin Fu uint32_t 1298d7fafffSZhi-Jun Robin Fu pci_mech1_amd_getl(int bus, int device, int function, int reg) 1308d7fafffSZhi-Jun Robin Fu { 1318d7fafffSZhi-Jun Robin Fu uint32_t val; 1328d7fafffSZhi-Jun Robin Fu 1338d7fafffSZhi-Jun Robin Fu if (device == PCI_MECH1_SPEC_CYCLE_DEV && 1348d7fafffSZhi-Jun Robin Fu function == PCI_MECH1_SPEC_CYCLE_FUNC) { 1358d7fafffSZhi-Jun Robin Fu return (0xffffffffu); 1368d7fafffSZhi-Jun Robin Fu } 1378d7fafffSZhi-Jun Robin Fu 1388d7fafffSZhi-Jun Robin Fu mutex_enter(&pcicfg_mutex); 1398d7fafffSZhi-Jun Robin Fu outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg)); 1408d7fafffSZhi-Jun Robin Fu val = inl(PCI_CONFDATA); 1418d7fafffSZhi-Jun Robin Fu mutex_exit(&pcicfg_mutex); 1428d7fafffSZhi-Jun Robin Fu return (val); 1438d7fafffSZhi-Jun Robin Fu } 1448d7fafffSZhi-Jun Robin Fu 1458d7fafffSZhi-Jun Robin Fu void 1468d7fafffSZhi-Jun Robin Fu pci_mech1_amd_putb(int bus, int device, int function, int reg, uint8_t val) 1478d7fafffSZhi-Jun Robin Fu { 1488d7fafffSZhi-Jun Robin Fu if (device == PCI_MECH1_SPEC_CYCLE_DEV && 1498d7fafffSZhi-Jun Robin Fu function == PCI_MECH1_SPEC_CYCLE_FUNC) { 1508d7fafffSZhi-Jun Robin Fu return; 1518d7fafffSZhi-Jun Robin Fu } 1528d7fafffSZhi-Jun Robin Fu 1538d7fafffSZhi-Jun Robin Fu mutex_enter(&pcicfg_mutex); 1548d7fafffSZhi-Jun Robin Fu outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg)); 1558d7fafffSZhi-Jun Robin Fu outb(PCI_CONFDATA | (reg & 0x3), val); 1568d7fafffSZhi-Jun Robin Fu mutex_exit(&pcicfg_mutex); 1578d7fafffSZhi-Jun Robin Fu } 1588d7fafffSZhi-Jun Robin Fu 1598d7fafffSZhi-Jun Robin Fu void 1608d7fafffSZhi-Jun Robin Fu pci_mech1_amd_putw(int bus, int device, int function, int reg, uint16_t val) 1618d7fafffSZhi-Jun Robin Fu { 1628d7fafffSZhi-Jun Robin Fu if (device == PCI_MECH1_SPEC_CYCLE_DEV && 1638d7fafffSZhi-Jun Robin Fu function == PCI_MECH1_SPEC_CYCLE_FUNC) { 1648d7fafffSZhi-Jun Robin Fu return; 1658d7fafffSZhi-Jun Robin Fu } 1668d7fafffSZhi-Jun Robin Fu 1678d7fafffSZhi-Jun Robin Fu mutex_enter(&pcicfg_mutex); 1688d7fafffSZhi-Jun Robin Fu outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg)); 1698d7fafffSZhi-Jun Robin Fu outw(PCI_CONFDATA | (reg & 0x2), val); 1708d7fafffSZhi-Jun Robin Fu mutex_exit(&pcicfg_mutex); 1718d7fafffSZhi-Jun Robin Fu } 1728d7fafffSZhi-Jun Robin Fu 1738d7fafffSZhi-Jun Robin Fu void 1748d7fafffSZhi-Jun Robin Fu pci_mech1_amd_putl(int bus, int device, int function, int reg, uint32_t val) 1758d7fafffSZhi-Jun Robin Fu { 1768d7fafffSZhi-Jun Robin Fu if (device == PCI_MECH1_SPEC_CYCLE_DEV && 1778d7fafffSZhi-Jun Robin Fu function == PCI_MECH1_SPEC_CYCLE_FUNC) { 1788d7fafffSZhi-Jun Robin Fu return; 1798d7fafffSZhi-Jun Robin Fu } 1808d7fafffSZhi-Jun Robin Fu 1818d7fafffSZhi-Jun Robin Fu mutex_enter(&pcicfg_mutex); 1828d7fafffSZhi-Jun Robin Fu outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg)); 1838d7fafffSZhi-Jun Robin Fu outl(PCI_CONFDATA, val); 1848d7fafffSZhi-Jun Robin Fu mutex_exit(&pcicfg_mutex); 1858d7fafffSZhi-Jun Robin Fu } 186