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