1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Library file that has miscellaneous support for npe(7d) 29 */ 30 31 #include <sys/conf.h> 32 #include <sys/pci.h> 33 #include <sys/sunndi.h> 34 #include <sys/acpi/acpi.h> 35 #include <sys/acpi/acpi_pci.h> 36 #include <sys/acpica.h> 37 #include <sys/pci_cap.h> 38 #include <sys/pcie_impl.h> 39 #include <sys/x86_archext.h> 40 #include <io/pciex/pcie_nvidia.h> 41 #include <io/pciex/pcie_nb5000.h> 42 43 /* 44 * Prototype declaration 45 */ 46 void npe_query_acpi_mcfg(dev_info_t *dip); 47 void npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl); 48 int npe_disable_empty_bridges_workaround(dev_info_t *child); 49 void npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl); 50 void npe_intel_error_mask(ddi_acc_handle_t cfg_hdl); 51 boolean_t npe_is_child_pci(dev_info_t *dip); 52 boolean_t check_and_set_mmcfg(dev_info_t *dip); 53 54 /* 55 * Default ecfga base address 56 */ 57 int64_t npe_default_ecfga_base = 0xE0000000; 58 59 extern uint32_t npe_aer_uce_mask; 60 extern boolean_t pcie_full_scan; 61 62 /* AMD's northbridges vendor-id and device-ids */ 63 #define AMD_NTBRDIGE_VID 0x1022 /* AMD vendor-id */ 64 #define AMD_HT_NTBRIDGE_DID 0x1100 /* HT Configuration */ 65 #define AMD_AM_NTBRIDGE_DID 0x1101 /* Address Map */ 66 #define AMD_DC_NTBRIDGE_DID 0x1102 /* DRAM Controller */ 67 #define AMD_MC_NTBRIDGE_DID 0x1103 /* Misc Controller */ 68 #define AMD_K10_NTBRIDGE_DID_0 0x1200 69 #define AMD_K10_NTBRIDGE_DID_1 0x1201 70 #define AMD_K10_NTBRIDGE_DID_2 0x1202 71 #define AMD_K10_NTBRIDGE_DID_3 0x1203 72 #define AMD_K10_NTBRIDGE_DID_4 0x1204 73 74 /* 75 * Check if the given device is an AMD northbridge 76 */ 77 #define IS_BAD_AMD_NTBRIDGE(vid, did) \ 78 (((vid) == AMD_NTBRDIGE_VID) && \ 79 (((did) == AMD_HT_NTBRIDGE_DID) || \ 80 ((did) == AMD_AM_NTBRIDGE_DID) || \ 81 ((did) == AMD_DC_NTBRIDGE_DID) || \ 82 ((did) == AMD_MC_NTBRIDGE_DID))) 83 84 #define IS_K10_AMD_NTBRIDGE(vid, did) \ 85 (((vid) == AMD_NTBRDIGE_VID) && \ 86 (((did) == AMD_K10_NTBRIDGE_DID_0) || \ 87 ((did) == AMD_K10_NTBRIDGE_DID_1) || \ 88 ((did) == AMD_K10_NTBRIDGE_DID_2) || \ 89 ((did) == AMD_K10_NTBRIDGE_DID_3) || \ 90 ((did) == AMD_K10_NTBRIDGE_DID_4))) 91 92 #define MSR_AMD_NB_MMIO_CFG_BADDR 0xc0010058 93 #define AMD_MMIO_CFG_BADDR_ADDR_MASK 0xFFFFFFF00000ULL 94 #define AMD_MMIO_CFG_BADDR_ENA_MASK 0x000000000001ULL 95 #define AMD_MMIO_CFG_BADDR_ENA_ON 0x000000000001ULL 96 #define AMD_MMIO_CFG_BADDR_ENA_OFF 0x000000000000ULL 97 98 99 /* 100 * Query the MCFG table using ACPI. If MCFG is found, setup the 101 * 'ecfga-base-address' (Enhanced Configuration Access base address) 102 * property accordingly. Otherwise, set the value of the property 103 * to the default value. 104 */ 105 void 106 npe_query_acpi_mcfg(dev_info_t *dip) 107 { 108 MCFG_TABLE *mcfgp; 109 CFG_BASE_ADDR_ALLOC *cfg_baap; 110 char *cfg_baa_endp; 111 uint64_t ecfga_base; 112 113 /* Query the MCFG table using ACPI */ 114 if (AcpiGetTable(ACPI_SIG_MCFG, 1, (ACPI_TABLE_HEADER **)&mcfgp) == 115 AE_OK) { 116 117 cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList; 118 cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length; 119 120 while ((char *)cfg_baap < cfg_baa_endp) { 121 ecfga_base = cfg_baap->base_addr; 122 if (ecfga_base != (uint64_t)0) { 123 /* 124 * Setup the 'ecfga-base-address' property to 125 * the base_addr found in the MCFG and return. 126 */ 127 (void) ndi_prop_update_int64(DDI_DEV_T_NONE, 128 dip, "ecfga-base-address", ecfga_base); 129 return; 130 } 131 cfg_baap++; 132 } 133 } 134 /* 135 * If MCFG is not found or ecfga_base is not found in MCFG table, 136 * set the 'ecfga-base-address' property to the default value. 137 */ 138 (void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip, 139 "ecfga-base-address", npe_default_ecfga_base); 140 } 141 142 143 /* 144 * Enable reporting of AER capability next pointer. 145 * This needs to be done only for CK8-04 devices 146 * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13 147 * NOTE: BIOS is disabling this, it needs to be enabled temporarily 148 */ 149 void 150 npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl) 151 { 152 ushort_t cya1; 153 154 if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) && 155 (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) == 156 NVIDIA_CK804_DEVICE_ID) && 157 (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >= 158 NVIDIA_CK804_AER_VALID_REVID)) { 159 cya1 = pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF); 160 if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK)) 161 (void) pci_config_put16(cfg_hdl, 162 NVIDIA_CK804_VEND_CYA1_OFF, 163 cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL); 164 } 165 } 166 167 /* 168 * If the bridge is empty, disable it 169 */ 170 int 171 npe_disable_empty_bridges_workaround(dev_info_t *child) 172 { 173 /* 174 * Do not bind drivers to empty bridges. 175 * Fail above, if the bridge is found to be hotplug capable 176 */ 177 if (ddi_driver_major(child) == ddi_name_to_major("pcie_pci") && 178 ddi_get_child(child) == NULL && 179 ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 180 "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE) 181 return (1); 182 183 return (0); 184 } 185 186 void 187 npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl) { 188 uint32_t regs; 189 uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID); 190 uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID); 191 192 if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) { 193 /* Disable ECRC for all devices */ 194 regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask | 195 PCIE_AER_UCE_ECRC; 196 pcie_set_aer_uce_mask(regs); 197 198 /* 199 * Turn full scan on since the Error Source ID register may not 200 * have the correct ID. 201 */ 202 pcie_full_scan = B_TRUE; 203 } 204 } 205 206 void 207 npe_intel_error_mask(ddi_acc_handle_t cfg_hdl) { 208 uint32_t regs; 209 uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID); 210 211 if (vendor_id == INTEL_VENDOR_ID) { 212 /* 213 * Due to an errata in Intel's ESB2 southbridge, all ECRCs 214 * generation/checking need to be disabled. There is a 215 * workaround by setting a proprietary bit in the ESB2, but it 216 * is not well documented or understood. If that bit is set in 217 * the future, then ECRC generation/checking should be enabled 218 * again. 219 * 220 * Disable ECRC generation/checking by masking ECRC in the AER 221 * UE Mask. The pcie misc module would then automatically 222 * disable ECRC generation/checking in the AER Control register. 223 */ 224 regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC; 225 pcie_set_aer_uce_mask(regs); 226 } 227 } 228 229 /* 230 * Check's if this child is a PCI device. 231 * Child is a PCI device if: 232 * parent has a dev_type of "pci" 233 * -and- 234 * child does not have a dev_type of "pciex" 235 * 236 * If the parent is not of dev_type "pci", then assume it is "pciex" and all 237 * children should support using PCIe style MMCFG access. 238 * 239 * If parent's dev_type is "pci" and child is "pciex", then also enable using 240 * PCIe style MMCFG access. This covers the case where NPE is "pci" and a PCIe 241 * RP is beneath. 242 */ 243 boolean_t 244 npe_child_is_pci(dev_info_t *dip) { 245 char *dev_type; 246 boolean_t parent_is_pci, child_is_pciex; 247 248 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip), 249 DDI_PROP_DONTPASS, "device_type", &dev_type) == 250 DDI_PROP_SUCCESS) { 251 parent_is_pci = (strcmp(dev_type, "pci") == 0); 252 ddi_prop_free(dev_type); 253 } else { 254 parent_is_pci = B_FALSE; 255 } 256 257 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 258 "device_type", &dev_type) == DDI_PROP_SUCCESS) { 259 child_is_pciex = (strcmp(dev_type, "pciex") == 0); 260 ddi_prop_free(dev_type); 261 } else { 262 child_is_pciex = B_FALSE; 263 } 264 265 return (parent_is_pci && !child_is_pciex); 266 } 267 268 /* 269 * Checks to see if MMCFG is supported and enables it if necessary. 270 * Returns: TRUE is MMCFG is support, FLASE is not. 271 * 272 * In general if a device sits below a parent who's "dev_type" is "pciex" the 273 * support MMCFG. Otherwise, default back to legacy IOCFG access. 274 * 275 * Enable Legacy PCI config space access for AMD K8 north bridges. 276 * Host bridge: AMD HyperTransport Technology Configuration 277 * Host bridge: AMD Address Map 278 * Host bridge: AMD DRAM Controller 279 * Host bridge: AMD Miscellaneous Control 280 * These devices do not support MMCFG access. 281 * 282 * Enable MMCFG via msr for AMD K10 north bridges 283 */ 284 boolean_t 285 npe_check_and_set_mmcfg(dev_info_t *dip) 286 { 287 int vendor_id, device_id; 288 int64_t data; 289 290 vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 291 "vendor-id", -1); 292 device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 293 "device-id", -1); 294 295 if (IS_K10_AMD_NTBRIDGE(vendor_id, device_id)) { 296 data = ddi_prop_get_int64(DDI_DEV_T_ANY, dip, 0, 297 "ecfga-base-address", 0); 298 data &= AMD_MMIO_CFG_BADDR_ADDR_MASK; 299 data |= AMD_MMIO_CFG_BADDR_ENA_ON; 300 wrmsr(MSR_AMD_NB_MMIO_CFG_BADDR, data); 301 } 302 303 return !(npe_child_is_pci(dip) || 304 IS_BAD_AMD_NTBRIDGE(vendor_id, device_id)); 305 } 306