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 
     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