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