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 2009 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_workaround(ddi_acc_handle_t cfg_hdl); 50 void npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl); 51 boolean_t npe_is_child_pci(dev_info_t *dip); 52 53 /* 54 * Default ecfga base address 55 */ 56 int64_t npe_default_ecfga_base = 0xE0000000; 57 58 extern uint32_t npe_aer_uce_mask; 59 60 /* AMD's northbridges vendor-id and device-ids */ 61 #define AMD_NTBRDIGE_VID 0x1022 /* AMD vendor-id */ 62 #define AMD_HT_NTBRIDGE_DID 0x1100 /* HT Configuration */ 63 #define AMD_AM_NTBRIDGE_DID 0x1101 /* Address Map */ 64 #define AMD_DC_NTBRIDGE_DID 0x1102 /* DRAM Controller */ 65 #define AMD_MC_NTBRIDGE_DID 0x1103 /* Misc Controller */ 66 #define AMD_K10_NTBRIDGE_DID_0 0x1200 67 #define AMD_K10_NTBRIDGE_DID_1 0x1201 68 #define AMD_K10_NTBRIDGE_DID_2 0x1202 69 #define AMD_K10_NTBRIDGE_DID_3 0x1203 70 #define AMD_K10_NTBRIDGE_DID_4 0x1204 71 72 /* 73 * Check if the given device is an AMD northbridge 74 */ 75 #define IS_BAD_AMD_NTBRIDGE(vid, did) \ 76 (((vid) == AMD_NTBRDIGE_VID) && \ 77 (((did) == AMD_HT_NTBRIDGE_DID) || \ 78 ((did) == AMD_AM_NTBRIDGE_DID) || \ 79 ((did) == AMD_DC_NTBRIDGE_DID) || \ 80 ((did) == AMD_MC_NTBRIDGE_DID))) 81 82 #define IS_K10_AMD_NTBRIDGE(vid, did) \ 83 (((vid) == AMD_NTBRDIGE_VID) && \ 84 (((did) == AMD_K10_NTBRIDGE_DID_0) || \ 85 ((did) == AMD_K10_NTBRIDGE_DID_1) || \ 86 ((did) == AMD_K10_NTBRIDGE_DID_2) || \ 87 ((did) == AMD_K10_NTBRIDGE_DID_3) || \ 88 ((did) == AMD_K10_NTBRIDGE_DID_4))) 89 90 #define MSR_AMD_NB_MMIO_CFG_BADDR 0xc0010058 91 #define AMD_MMIO_CFG_BADDR_ADDR_MASK 0xFFFFFFF00000ULL 92 #define AMD_MMIO_CFG_BADDR_ENA_MASK 0x000000000001ULL 93 #define AMD_MMIO_CFG_BADDR_ENA_ON 0x000000000001ULL 94 #define AMD_MMIO_CFG_BADDR_ENA_OFF 0x000000000000ULL 95 96 97 /* 98 * Query the MCFG table using ACPI. If MCFG is found, setup the 99 * 'ecfg' property accordingly. Otherwise, set the values 100 * to the default values. 101 */ 102 void 103 npe_query_acpi_mcfg(dev_info_t *dip) 104 { 105 MCFG_TABLE *mcfgp; 106 CFG_BASE_ADDR_ALLOC *cfg_baap; 107 char *cfg_baa_endp; 108 int64_t ecfginfo[4]; 109 int ecfg_found = 0; 110 111 /* Query the MCFG table using ACPI */ 112 if (AcpiGetTable(ACPI_SIG_MCFG, 1, 113 (ACPI_TABLE_HEADER **)&mcfgp) == AE_OK) { 114 115 cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList; 116 cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length; 117 118 while ((char *)cfg_baap < cfg_baa_endp) { 119 if (cfg_baap->base_addr != (uint64_t)0 && 120 cfg_baap->segment == 0) { 121 /* 122 * Set up the 'ecfg' property to hold 123 * base_addr, segment, and first/last bus. 124 * We only do the first entry that maps 125 * segment 0; nonzero segments are not yet 126 * known, or handled. If they appear, 127 * we'll need to figure out which bus node 128 * should have which entry by examining the 129 * ACPI _SEG method on each bus node. 130 */ 131 ecfginfo[0] = cfg_baap->base_addr; 132 ecfginfo[1] = cfg_baap->segment; 133 ecfginfo[2] = cfg_baap->start_bno; 134 ecfginfo[3] = cfg_baap->end_bno; 135 (void) ndi_prop_update_int64_array( 136 DDI_DEV_T_NONE, dip, "ecfg", 137 ecfginfo, 4); 138 ecfg_found = 1; 139 break; 140 } 141 cfg_baap++; 142 } 143 } 144 if (ecfg_found) 145 return; 146 /* 147 * If MCFG is not found or ecfga_base is not found in MCFG table, 148 * set the property to the default values. 149 */ 150 ecfginfo[0] = npe_default_ecfga_base; 151 ecfginfo[1] = 0; /* segment 0 */ 152 ecfginfo[2] = 0; /* first bus 0 */ 153 ecfginfo[3] = 0xff; /* last bus ff */ 154 (void) ndi_prop_update_int64_array(DDI_DEV_T_NONE, dip, 155 "ecfg", ecfginfo, 4); 156 } 157 158 159 /* 160 * Enable reporting of AER capability next pointer. 161 * This needs to be done only for CK8-04 devices 162 * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13 163 * NOTE: BIOS is disabling this, it needs to be enabled temporarily 164 */ 165 void 166 npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl) 167 { 168 ushort_t cya1; 169 170 if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) && 171 (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) == 172 NVIDIA_CK804_DEVICE_ID) && 173 (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >= 174 NVIDIA_CK804_AER_VALID_REVID)) { 175 cya1 = pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF); 176 if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK)) 177 (void) pci_config_put16(cfg_hdl, 178 NVIDIA_CK804_VEND_CYA1_OFF, 179 cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL); 180 } 181 } 182 183 /* 184 * If the bridge is empty, disable it 185 */ 186 int 187 npe_disable_empty_bridges_workaround(dev_info_t *child) 188 { 189 /* 190 * Do not bind drivers to empty bridges. 191 * Fail above, if the bridge is found to be hotplug capable 192 */ 193 if (ddi_driver_major(child) == ddi_name_to_major("pcieb") && 194 ddi_get_child(child) == NULL && 195 ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 196 "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE) 197 return (1); 198 199 return (0); 200 } 201 202 void 203 npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl) { 204 uint32_t regs; 205 uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID); 206 uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID); 207 208 if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) { 209 /* Disable ECRC for all devices */ 210 regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask | 211 PCIE_AER_UCE_ECRC; 212 pcie_set_aer_uce_mask(regs); 213 214 /* 215 * Turn full scan on since the Error Source ID register may not 216 * have the correct ID. 217 */ 218 pcie_force_fullscan(); 219 } 220 } 221 222 void 223 npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl) { 224 uint32_t regs; 225 uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID); 226 uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID); 227 228 if (vendor_id == INTEL_VENDOR_ID) { 229 /* 230 * Due to an errata in Intel's ESB2 southbridge, all ECRCs 231 * generation/checking need to be disabled. There is a 232 * workaround by setting a proprietary bit in the ESB2, but it 233 * is not well documented or understood. If that bit is set in 234 * the future, then ECRC generation/checking should be enabled 235 * again. 236 * 237 * Disable ECRC generation/checking by masking ECRC in the AER 238 * UE Mask. The pcie misc module would then automatically 239 * disable ECRC generation/checking in the AER Control register. 240 */ 241 regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC; 242 pcie_set_aer_uce_mask(regs); 243 244 if (INTEL_NB5500_PCIE_DEV_ID(dev_id) || 245 INTEL_NB5520_PCIE_DEV_ID(dev_id)) { 246 /* 247 * Turn full scan on since the Error Source ID register 248 * may not have the correct ID. See Intel 5520 and 249 * Intel 5500 Chipsets errata #34 and #54 in the August 250 * 2009 specification update, document number 251 * 321329-006. 252 */ 253 pcie_force_fullscan(); 254 } 255 } 256 } 257 258 /* 259 * Check's if this child is a PCI device. 260 * Child is a PCI device if: 261 * parent has a dev_type of "pci" 262 * -and- 263 * child does not have a dev_type of "pciex" 264 * 265 * If the parent is not of dev_type "pci", then assume it is "pciex" and all 266 * children should support using PCIe style MMCFG access. 267 * 268 * If parent's dev_type is "pci" and child is "pciex", then also enable using 269 * PCIe style MMCFG access. This covers the case where NPE is "pci" and a PCIe 270 * RP is beneath. 271 */ 272 boolean_t 273 npe_child_is_pci(dev_info_t *dip) { 274 char *dev_type; 275 boolean_t parent_is_pci, child_is_pciex; 276 277 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip), 278 DDI_PROP_DONTPASS, "device_type", &dev_type) == 279 DDI_PROP_SUCCESS) { 280 parent_is_pci = (strcmp(dev_type, "pci") == 0); 281 ddi_prop_free(dev_type); 282 } else { 283 parent_is_pci = B_FALSE; 284 } 285 286 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 287 "device_type", &dev_type) == DDI_PROP_SUCCESS) { 288 child_is_pciex = (strcmp(dev_type, "pciex") == 0); 289 ddi_prop_free(dev_type); 290 } else { 291 child_is_pciex = B_FALSE; 292 } 293 294 return (parent_is_pci && !child_is_pciex); 295 } 296 297 /* 298 * Checks to see if MMCFG is supported. 299 * Returns: TRUE if MMCFG is supported, FALSE if not. 300 * 301 * If a device is attached to a parent whose "dev_type" is "pciex", 302 * the device will support MMCFG access. Otherwise, use legacy IOCFG access. 303 * 304 * Enable Legacy PCI config space access for AMD K8 north bridges. 305 * Host bridge: AMD HyperTransport Technology Configuration 306 * Host bridge: AMD Address Map 307 * Host bridge: AMD DRAM Controller 308 * Host bridge: AMD Miscellaneous Control 309 * These devices do not support MMCFG access. 310 */ 311 boolean_t 312 npe_is_mmcfg_supported(dev_info_t *dip) 313 { 314 int vendor_id, device_id; 315 316 vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 317 "vendor-id", -1); 318 device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 319 "device-id", -1); 320 321 return !(npe_child_is_pci(dip) || 322 IS_BAD_AMD_NTBRIDGE(vendor_id, device_id)); 323 } 324 325 int 326 npe_enable_htmsi(ddi_acc_handle_t cfg_hdl) 327 { 328 uint16_t ptr; 329 uint16_t reg; 330 331 if (pci_htcap_locate(cfg_hdl, PCI_HTCAP_TYPE_MASK, 332 PCI_HTCAP_MSIMAP_TYPE, &ptr) != DDI_SUCCESS) 333 return (DDI_FAILURE); 334 335 reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF); 336 reg |= PCI_HTCAP_MSIMAP_ENABLE; 337 338 pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg); 339 return (DDI_SUCCESS); 340 } 341 342 void 343 npe_enable_htmsi_children(dev_info_t *dip) 344 { 345 dev_info_t *cdip = ddi_get_child(dip); 346 ddi_acc_handle_t cfg_hdl; 347 348 for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { 349 if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) { 350 cmn_err(CE_NOTE, "!npe_enable_htmsi_children: " 351 "pci_config_setup failed for %s", 352 ddi_node_name(cdip)); 353 } 354 355 (void) npe_enable_htmsi(cfg_hdl); 356 pci_config_teardown(&cfg_hdl); 357 } 358 } 359 360 /* 361 * save config regs for HyperTransport devices without drivers of classes: 362 * memory controller and hostbridge 363 */ 364 int 365 npe_save_htconfig_children(dev_info_t *dip) 366 { 367 dev_info_t *cdip = ddi_get_child(dip); 368 ddi_acc_handle_t cfg_hdl; 369 uint16_t ptr; 370 int rval = DDI_SUCCESS; 371 uint8_t cl, scl; 372 373 for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { 374 if (ddi_driver_major(cdip) != DDI_MAJOR_T_NONE) 375 continue; 376 377 if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) 378 return (DDI_FAILURE); 379 380 cl = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS); 381 scl = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS); 382 383 if (((cl == PCI_CLASS_MEM && scl == PCI_MEM_RAM) || 384 (cl == PCI_CLASS_BRIDGE && scl == PCI_BRIDGE_HOST)) && 385 pci_htcap_locate(cfg_hdl, 0, 0, &ptr) == DDI_SUCCESS) { 386 387 if (pci_save_config_regs(cdip) != DDI_SUCCESS) { 388 cmn_err(CE_WARN, "Failed to save HT config " 389 "regs for %s\n", ddi_node_name(cdip)); 390 rval = DDI_FAILURE; 391 392 } else if (ddi_prop_update_int(DDI_DEV_T_NONE, cdip, 393 "htconfig-saved", 1) != DDI_SUCCESS) { 394 cmn_err(CE_WARN, "Failed to set htconfig-saved " 395 "property for %s\n", ddi_node_name(cdip)); 396 rval = DDI_FAILURE; 397 } 398 } 399 400 pci_config_teardown(&cfg_hdl); 401 } 402 403 return (rval); 404 } 405 406 int 407 npe_restore_htconfig_children(dev_info_t *dip) 408 { 409 dev_info_t *cdip = ddi_get_child(dip); 410 int rval = DDI_SUCCESS; 411 412 for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { 413 if (ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 414 "htconfig-saved", 0) == 0) 415 continue; 416 417 if (pci_restore_config_regs(cdip) != DDI_SUCCESS) { 418 cmn_err(CE_WARN, "Failed to restore HT config " 419 "regs for %s\n", ddi_node_name(cdip)); 420 rval = DDI_FAILURE; 421 } 422 } 423 424 return (rval); 425 } 426