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