xref: /titanic_52/usr/src/uts/i86pc/io/pciex/npe_misc.c (revision bf4de67d4dd018e5f4bb0b566de3dac4ca5ba286)
170025d76Sjohnny /*
270025d76Sjohnny  * CDDL HEADER START
370025d76Sjohnny  *
470025d76Sjohnny  * The contents of this file are subject to the terms of the
57a23d100Sanish  * Common Development and Distribution License (the "License").
67a23d100Sanish  * You may not use this file except in compliance with the License.
770025d76Sjohnny  *
870025d76Sjohnny  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
970025d76Sjohnny  * or http://www.opensolaris.org/os/licensing.
1070025d76Sjohnny  * See the License for the specific language governing permissions
1170025d76Sjohnny  * and limitations under the License.
1270025d76Sjohnny  *
1370025d76Sjohnny  * When distributing Covered Code, include this CDDL HEADER in each
1470025d76Sjohnny  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1570025d76Sjohnny  * If applicable, add the following below this CDDL HEADER, with the
1670025d76Sjohnny  * fields enclosed by brackets "[]" replaced with your own identifying
1770025d76Sjohnny  * information: Portions Copyright [yyyy] [name of copyright owner]
1870025d76Sjohnny  *
1970025d76Sjohnny  * CDDL HEADER END
2070025d76Sjohnny  */
2170025d76Sjohnny 
2270025d76Sjohnny /*
23c92fa3b5SJimmy Vetayases  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24*bf4de67dSJoshua M. Clulow  * Copyright 2015 Joyent, Inc.
2570025d76Sjohnny  */
2670025d76Sjohnny 
2770025d76Sjohnny /*
2870025d76Sjohnny  *	Library file that has miscellaneous support for npe(7d)
2970025d76Sjohnny  */
3070025d76Sjohnny 
3170025d76Sjohnny #include <sys/conf.h>
3270025d76Sjohnny #include <sys/pci.h>
3370025d76Sjohnny #include <sys/sunndi.h>
3470025d76Sjohnny #include <sys/acpi/acpi.h>
3570025d76Sjohnny #include <sys/acpi/acpi_pci.h>
3670025d76Sjohnny #include <sys/acpica.h>
37eae2e508Skrishnae #include <sys/pci_cap.h>
38eae2e508Skrishnae #include <sys/pcie_impl.h>
3949fbdd30SErwin T Tsaur #include <sys/x86_archext.h>
408a5a0d1eSanish #include <io/pciex/pcie_nvidia.h>
415c0a55ffSet142600 #include <io/pciex/pcie_nb5000.h>
42c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc_x86.h>
43c92fa3b5SJimmy Vetayases #include <sys/cpuvar.h>
4470025d76Sjohnny 
4570025d76Sjohnny /*
4670025d76Sjohnny  * Prototype declaration
4770025d76Sjohnny  */
4870025d76Sjohnny void	npe_query_acpi_mcfg(dev_info_t *dip);
49337fc9e2Sanish void	npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
507a23d100Sanish int	npe_disable_empty_bridges_workaround(dev_info_t *child);
51a2de976fSPavel Potoplyak void	npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl);
52a2de976fSPavel Potoplyak void	npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl);
5349fbdd30SErwin T Tsaur boolean_t npe_is_child_pci(dev_info_t *dip);
54c92fa3b5SJimmy Vetayases int	npe_enable_htmsi(ddi_acc_handle_t cfg_hdl);
55c92fa3b5SJimmy Vetayases void	npe_enable_htmsi_children(dev_info_t *dip);
56c92fa3b5SJimmy Vetayases 
57c92fa3b5SJimmy Vetayases int	npe_enable_htmsi_flag = 1;
5870025d76Sjohnny 
59eae2e508Skrishnae extern uint32_t npe_aer_uce_mask;
60eae2e508Skrishnae 
6170025d76Sjohnny /*
62*bf4de67dSJoshua M. Clulow  * Query the MCFG table using ACPI.  If MCFG is found, setup the 'ecfg'
63*bf4de67dSJoshua M. Clulow  * property accordingly.  If no table is found, the property remains unset; the
64*bf4de67dSJoshua M. Clulow  * system will not make use of memory-mapped access to PCI Express
65*bf4de67dSJoshua M. Clulow  * configuration space.
6670025d76Sjohnny  */
6770025d76Sjohnny void
6870025d76Sjohnny npe_query_acpi_mcfg(dev_info_t *dip)
6970025d76Sjohnny {
7070025d76Sjohnny 	MCFG_TABLE *mcfgp;
7170025d76Sjohnny 	CFG_BASE_ADDR_ALLOC *cfg_baap;
7270025d76Sjohnny 	char *cfg_baa_endp;
735c59319bSDan Mick 	int64_t ecfginfo[4];
7470025d76Sjohnny 
7570025d76Sjohnny 	/* Query the MCFG table using ACPI */
76c1381f44SDana Myers 	if (AcpiGetTable(ACPI_SIG_MCFG, 1,
77c1381f44SDana Myers 	    (ACPI_TABLE_HEADER **)&mcfgp) == AE_OK) {
7870025d76Sjohnny 
7970025d76Sjohnny 		cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList;
8070025d76Sjohnny 		cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
8170025d76Sjohnny 
8270025d76Sjohnny 		while ((char *)cfg_baap < cfg_baa_endp) {
835c59319bSDan Mick 			if (cfg_baap->base_addr != (uint64_t)0 &&
845c59319bSDan Mick 			    cfg_baap->segment == 0) {
8570025d76Sjohnny 				/*
865c59319bSDan Mick 				 * Set up the 'ecfg' property to hold
875c59319bSDan Mick 				 * base_addr, segment, and first/last bus.
885c59319bSDan Mick 				 * We only do the first entry that maps
895c59319bSDan Mick 				 * segment 0; nonzero segments are not yet
905c59319bSDan Mick 				 * known, or handled.  If they appear,
915c59319bSDan Mick 				 * we'll need to figure out which bus node
925c59319bSDan Mick 				 * should have which entry by examining the
935c59319bSDan Mick 				 * ACPI _SEG method on each bus node.
9470025d76Sjohnny 				 */
955c59319bSDan Mick 				ecfginfo[0] = cfg_baap->base_addr;
965c59319bSDan Mick 				ecfginfo[1] = cfg_baap->segment;
975c59319bSDan Mick 				ecfginfo[2] = cfg_baap->start_bno;
985c59319bSDan Mick 				ecfginfo[3] = cfg_baap->end_bno;
995c59319bSDan Mick 				(void) ndi_prop_update_int64_array(
1005c59319bSDan Mick 				    DDI_DEV_T_NONE, dip, "ecfg",
1015c59319bSDan Mick 				    ecfginfo, 4);
1025c59319bSDan Mick 				break;
10370025d76Sjohnny 			}
10470025d76Sjohnny 			cfg_baap++;
10570025d76Sjohnny 		}
10670025d76Sjohnny 	}
10770025d76Sjohnny }
10870025d76Sjohnny 
10970025d76Sjohnny /*
11070025d76Sjohnny  * Enable reporting of AER capability next pointer.
11170025d76Sjohnny  * This needs to be done only for CK8-04 devices
11270025d76Sjohnny  * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
11370025d76Sjohnny  * NOTE: BIOS is disabling this, it needs to be enabled temporarily
11470025d76Sjohnny  */
11570025d76Sjohnny void
116337fc9e2Sanish npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
11770025d76Sjohnny {
1188a5a0d1eSanish 	ushort_t cya1;
11970025d76Sjohnny 
1202f15eac9Sanish 	if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) &&
1212f15eac9Sanish 	    (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) ==
1222f15eac9Sanish 	    NVIDIA_CK804_DEVICE_ID) &&
1232f15eac9Sanish 	    (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >=
1242f15eac9Sanish 	    NVIDIA_CK804_AER_VALID_REVID)) {
125337fc9e2Sanish 		cya1 =  pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF);
12670025d76Sjohnny 		if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
1272f15eac9Sanish 			(void) pci_config_put16(cfg_hdl,
1282f15eac9Sanish 			    NVIDIA_CK804_VEND_CYA1_OFF,
12970025d76Sjohnny 			    cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
13070025d76Sjohnny 	}
1312f15eac9Sanish }
1327a23d100Sanish 
1337a23d100Sanish /*
1347a23d100Sanish  * If the bridge is empty, disable it
1357a23d100Sanish  */
1367a23d100Sanish int
1377a23d100Sanish npe_disable_empty_bridges_workaround(dev_info_t *child)
1387a23d100Sanish {
1397a23d100Sanish 	/*
1407a23d100Sanish 	 * Do not bind drivers to empty bridges.
1417a23d100Sanish 	 * Fail above, if the bridge is found to be hotplug capable
1427a23d100Sanish 	 */
143d4bc0535SKrishna Elango 	if (ddi_driver_major(child) == ddi_name_to_major("pcieb") &&
1447a23d100Sanish 	    ddi_get_child(child) == NULL &&
1457a23d100Sanish 	    ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1467a23d100Sanish 	    "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
1477a23d100Sanish 		return (1);
1487a23d100Sanish 
1497a23d100Sanish 	return (0);
1507a23d100Sanish }
151eae2e508Skrishnae 
152eae2e508Skrishnae void
153a2de976fSPavel Potoplyak npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl) {
154eae2e508Skrishnae 	uint32_t regs;
155eae2e508Skrishnae 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
156eae2e508Skrishnae 	uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
157eae2e508Skrishnae 
158eae2e508Skrishnae 	if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
159eae2e508Skrishnae 		/* Disable ECRC for all devices */
160eae2e508Skrishnae 		regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
161eae2e508Skrishnae 		    PCIE_AER_UCE_ECRC;
162eae2e508Skrishnae 		pcie_set_aer_uce_mask(regs);
163eae2e508Skrishnae 
164eae2e508Skrishnae 		/*
165eae2e508Skrishnae 		 * Turn full scan on since the Error Source ID register may not
166eae2e508Skrishnae 		 * have the correct ID.
167eae2e508Skrishnae 		 */
168a2de976fSPavel Potoplyak 		pcie_force_fullscan();
169eae2e508Skrishnae 	}
170eae2e508Skrishnae }
1715c0a55ffSet142600 
1725c0a55ffSet142600 void
173a2de976fSPavel Potoplyak npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl) {
1745c0a55ffSet142600 	uint32_t regs;
1755c0a55ffSet142600 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
176a2de976fSPavel Potoplyak 	uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
1775c0a55ffSet142600 
1785c0a55ffSet142600 	if (vendor_id == INTEL_VENDOR_ID) {
1795c0a55ffSet142600 		/*
1805c0a55ffSet142600 		 * Due to an errata in Intel's ESB2 southbridge, all ECRCs
1815c0a55ffSet142600 		 * generation/checking need to be disabled.  There is a
1825c0a55ffSet142600 		 * workaround by setting a proprietary bit in the ESB2, but it
1835c0a55ffSet142600 		 * is not well documented or understood.  If that bit is set in
1845c0a55ffSet142600 		 * the future, then ECRC generation/checking should be enabled
1855c0a55ffSet142600 		 * again.
1865c0a55ffSet142600 		 *
1875c0a55ffSet142600 		 * Disable ECRC generation/checking by masking ECRC in the AER
1885c0a55ffSet142600 		 * UE Mask.  The pcie misc module would then automatically
1895c0a55ffSet142600 		 * disable ECRC generation/checking in the AER Control register.
1905c0a55ffSet142600 		 */
1915c0a55ffSet142600 		regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC;
1925c0a55ffSet142600 		pcie_set_aer_uce_mask(regs);
193a2de976fSPavel Potoplyak 
194a2de976fSPavel Potoplyak 		if (INTEL_NB5500_PCIE_DEV_ID(dev_id) ||
195a2de976fSPavel Potoplyak 		    INTEL_NB5520_PCIE_DEV_ID(dev_id)) {
196a2de976fSPavel Potoplyak 			/*
197a2de976fSPavel Potoplyak 			 * Turn full scan on since the Error Source ID register
198a2de976fSPavel Potoplyak 			 * may not have the correct ID. See Intel 5520 and
199a2de976fSPavel Potoplyak 			 * Intel 5500 Chipsets errata #34 and #54 in the August
200a2de976fSPavel Potoplyak 			 * 2009 specification update, document number
201a2de976fSPavel Potoplyak 			 * 321329-006.
202a2de976fSPavel Potoplyak 			 */
203a2de976fSPavel Potoplyak 			pcie_force_fullscan();
204a2de976fSPavel Potoplyak 		}
2055c0a55ffSet142600 	}
2065c0a55ffSet142600 }
20749fbdd30SErwin T Tsaur 
20849fbdd30SErwin T Tsaur /*
20949fbdd30SErwin T Tsaur  * Check's if this child is a PCI device.
21049fbdd30SErwin T Tsaur  * Child is a PCI device if:
21149fbdd30SErwin T Tsaur  * parent has a dev_type of "pci"
21249fbdd30SErwin T Tsaur  * -and-
21349fbdd30SErwin T Tsaur  * child does not have a dev_type of "pciex"
21449fbdd30SErwin T Tsaur  *
21549fbdd30SErwin T Tsaur  * If the parent is not of dev_type "pci", then assume it is "pciex" and all
21649fbdd30SErwin T Tsaur  * children should support using PCIe style MMCFG access.
21749fbdd30SErwin T Tsaur  *
21849fbdd30SErwin T Tsaur  * If parent's dev_type is "pci" and child is "pciex", then also enable using
21949fbdd30SErwin T Tsaur  * PCIe style MMCFG access.  This covers the case where NPE is "pci" and a PCIe
22049fbdd30SErwin T Tsaur  * RP is beneath.
22149fbdd30SErwin T Tsaur  */
22249fbdd30SErwin T Tsaur boolean_t
22349fbdd30SErwin T Tsaur npe_child_is_pci(dev_info_t *dip) {
22449fbdd30SErwin T Tsaur 	char *dev_type;
22549fbdd30SErwin T Tsaur 	boolean_t parent_is_pci, child_is_pciex;
22649fbdd30SErwin T Tsaur 
22749fbdd30SErwin T Tsaur 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip),
22849fbdd30SErwin T Tsaur 	    DDI_PROP_DONTPASS, "device_type", &dev_type) ==
22949fbdd30SErwin T Tsaur 	    DDI_PROP_SUCCESS) {
23049fbdd30SErwin T Tsaur 		parent_is_pci = (strcmp(dev_type, "pci") == 0);
23149fbdd30SErwin T Tsaur 		ddi_prop_free(dev_type);
23249fbdd30SErwin T Tsaur 	} else {
23349fbdd30SErwin T Tsaur 		parent_is_pci = B_FALSE;
23449fbdd30SErwin T Tsaur 	}
23549fbdd30SErwin T Tsaur 
23649fbdd30SErwin T Tsaur 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
23749fbdd30SErwin T Tsaur 	    "device_type", &dev_type) == DDI_PROP_SUCCESS) {
23849fbdd30SErwin T Tsaur 		child_is_pciex = (strcmp(dev_type, "pciex") == 0);
23949fbdd30SErwin T Tsaur 		ddi_prop_free(dev_type);
24049fbdd30SErwin T Tsaur 	} else {
24149fbdd30SErwin T Tsaur 		child_is_pciex = B_FALSE;
24249fbdd30SErwin T Tsaur 	}
24349fbdd30SErwin T Tsaur 
24449fbdd30SErwin T Tsaur 	return (parent_is_pci && !child_is_pciex);
24549fbdd30SErwin T Tsaur }
24649fbdd30SErwin T Tsaur 
24749fbdd30SErwin T Tsaur /*
24814f1dfe8SSeth Goldberg  * Checks to see if MMCFG is supported.
24914f1dfe8SSeth Goldberg  * Returns: TRUE if MMCFG is supported, FALSE if not.
25049fbdd30SErwin T Tsaur  *
25114f1dfe8SSeth Goldberg  * If a device is attached to a parent whose "dev_type" is "pciex",
25214f1dfe8SSeth Goldberg  * the device will support MMCFG access.  Otherwise, use legacy IOCFG access.
25349fbdd30SErwin T Tsaur  *
25449fbdd30SErwin T Tsaur  * Enable Legacy PCI config space access for AMD K8 north bridges.
25549fbdd30SErwin T Tsaur  *	Host bridge: AMD HyperTransport Technology Configuration
25649fbdd30SErwin T Tsaur  *	Host bridge: AMD Address Map
25749fbdd30SErwin T Tsaur  *	Host bridge: AMD DRAM Controller
25849fbdd30SErwin T Tsaur  *	Host bridge: AMD Miscellaneous Control
25949fbdd30SErwin T Tsaur  * These devices do not support MMCFG access.
26049fbdd30SErwin T Tsaur  */
26149fbdd30SErwin T Tsaur boolean_t
26214f1dfe8SSeth Goldberg npe_is_mmcfg_supported(dev_info_t *dip)
26349fbdd30SErwin T Tsaur {
26449fbdd30SErwin T Tsaur 	int vendor_id, device_id;
26549fbdd30SErwin T Tsaur 
26649fbdd30SErwin T Tsaur 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
26749fbdd30SErwin T Tsaur 	    "vendor-id", -1);
26849fbdd30SErwin T Tsaur 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
26949fbdd30SErwin T Tsaur 	    "device-id", -1);
27049fbdd30SErwin T Tsaur 
27149fbdd30SErwin T Tsaur 	return !(npe_child_is_pci(dip) ||
27249fbdd30SErwin T Tsaur 	    IS_BAD_AMD_NTBRIDGE(vendor_id, device_id));
27349fbdd30SErwin T Tsaur }
274cb7ea99dSJimmy Vetayases 
275cb7ea99dSJimmy Vetayases int
276cb7ea99dSJimmy Vetayases npe_enable_htmsi(ddi_acc_handle_t cfg_hdl)
277cb7ea99dSJimmy Vetayases {
278cb7ea99dSJimmy Vetayases 	uint16_t ptr;
279cb7ea99dSJimmy Vetayases 	uint16_t reg;
280cb7ea99dSJimmy Vetayases 
281cb7ea99dSJimmy Vetayases 	if (pci_htcap_locate(cfg_hdl, PCI_HTCAP_TYPE_MASK,
282cb7ea99dSJimmy Vetayases 	    PCI_HTCAP_MSIMAP_TYPE, &ptr) != DDI_SUCCESS)
283cb7ea99dSJimmy Vetayases 		return (DDI_FAILURE);
284cb7ea99dSJimmy Vetayases 
285cb7ea99dSJimmy Vetayases 	reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF);
286cb7ea99dSJimmy Vetayases 	reg |= PCI_HTCAP_MSIMAP_ENABLE;
287cb7ea99dSJimmy Vetayases 
288cb7ea99dSJimmy Vetayases 	pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg);
289cb7ea99dSJimmy Vetayases 	return (DDI_SUCCESS);
290cb7ea99dSJimmy Vetayases }
291cb7ea99dSJimmy Vetayases 
292cb7ea99dSJimmy Vetayases void
293cb7ea99dSJimmy Vetayases npe_enable_htmsi_children(dev_info_t *dip)
294cb7ea99dSJimmy Vetayases {
295cb7ea99dSJimmy Vetayases 	dev_info_t *cdip = ddi_get_child(dip);
296cb7ea99dSJimmy Vetayases 	ddi_acc_handle_t cfg_hdl;
297cb7ea99dSJimmy Vetayases 
298c92fa3b5SJimmy Vetayases 	if (!npe_enable_htmsi_flag)
299c92fa3b5SJimmy Vetayases 		return;
300c92fa3b5SJimmy Vetayases 
301c92fa3b5SJimmy Vetayases 	/*
302c92fa3b5SJimmy Vetayases 	 * Hypertransport MSI remapping only applies to AMD CPUs using
303c92fa3b5SJimmy Vetayases 	 * Hypertransport (K8 and above) and not other platforms with non-AMD
304c92fa3b5SJimmy Vetayases 	 * CPUs that may be using Hypertransport internally in the chipset(s)
305c92fa3b5SJimmy Vetayases 	 */
306c92fa3b5SJimmy Vetayases 	if (!(cpuid_getvendor(CPU) == X86_VENDOR_AMD &&
307c92fa3b5SJimmy Vetayases 	    cpuid_getfamily(CPU) >= 0xf))
308c92fa3b5SJimmy Vetayases 		return;
309c92fa3b5SJimmy Vetayases 
310cb7ea99dSJimmy Vetayases 	for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
311cb7ea99dSJimmy Vetayases 		if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) {
312cb7ea99dSJimmy Vetayases 			cmn_err(CE_NOTE, "!npe_enable_htmsi_children: "
313cb7ea99dSJimmy Vetayases 			    "pci_config_setup failed for %s",
314cb7ea99dSJimmy Vetayases 			    ddi_node_name(cdip));
315c92fa3b5SJimmy Vetayases 			return;
316cb7ea99dSJimmy Vetayases 		}
317cb7ea99dSJimmy Vetayases 
318cb7ea99dSJimmy Vetayases 		(void) npe_enable_htmsi(cfg_hdl);
319cb7ea99dSJimmy Vetayases 		pci_config_teardown(&cfg_hdl);
320cb7ea99dSJimmy Vetayases 	}
321cb7ea99dSJimmy Vetayases }
322cb7ea99dSJimmy Vetayases 
323cb7ea99dSJimmy Vetayases /*
324cb7ea99dSJimmy Vetayases  * save config regs for HyperTransport devices without drivers of classes:
325cb7ea99dSJimmy Vetayases  * memory controller and hostbridge
326cb7ea99dSJimmy Vetayases  */
327cb7ea99dSJimmy Vetayases int
328cb7ea99dSJimmy Vetayases npe_save_htconfig_children(dev_info_t *dip)
329cb7ea99dSJimmy Vetayases {
330cb7ea99dSJimmy Vetayases 	dev_info_t *cdip = ddi_get_child(dip);
331cb7ea99dSJimmy Vetayases 	ddi_acc_handle_t cfg_hdl;
332cb7ea99dSJimmy Vetayases 	uint16_t ptr;
333cb7ea99dSJimmy Vetayases 	int rval = DDI_SUCCESS;
334cb7ea99dSJimmy Vetayases 	uint8_t cl, scl;
335cb7ea99dSJimmy Vetayases 
336cb7ea99dSJimmy Vetayases 	for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
337cb7ea99dSJimmy Vetayases 		if (ddi_driver_major(cdip) != DDI_MAJOR_T_NONE)
338cb7ea99dSJimmy Vetayases 			continue;
339cb7ea99dSJimmy Vetayases 
340cb7ea99dSJimmy Vetayases 		if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS)
341cb7ea99dSJimmy Vetayases 			return (DDI_FAILURE);
342cb7ea99dSJimmy Vetayases 
343cb7ea99dSJimmy Vetayases 		cl = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
344cb7ea99dSJimmy Vetayases 		scl = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
345cb7ea99dSJimmy Vetayases 
346cb7ea99dSJimmy Vetayases 		if (((cl == PCI_CLASS_MEM && scl == PCI_MEM_RAM) ||
347cb7ea99dSJimmy Vetayases 		    (cl == PCI_CLASS_BRIDGE && scl == PCI_BRIDGE_HOST)) &&
348cb7ea99dSJimmy Vetayases 		    pci_htcap_locate(cfg_hdl, 0, 0, &ptr) == DDI_SUCCESS) {
349cb7ea99dSJimmy Vetayases 
350cb7ea99dSJimmy Vetayases 			if (pci_save_config_regs(cdip) != DDI_SUCCESS) {
351cb7ea99dSJimmy Vetayases 				cmn_err(CE_WARN, "Failed to save HT config "
352cb7ea99dSJimmy Vetayases 				    "regs for %s\n", ddi_node_name(cdip));
353cb7ea99dSJimmy Vetayases 				rval = DDI_FAILURE;
354cb7ea99dSJimmy Vetayases 
355cb7ea99dSJimmy Vetayases 			} else if (ddi_prop_update_int(DDI_DEV_T_NONE, cdip,
356cb7ea99dSJimmy Vetayases 			    "htconfig-saved", 1) != DDI_SUCCESS) {
357cb7ea99dSJimmy Vetayases 				cmn_err(CE_WARN, "Failed to set htconfig-saved "
358cb7ea99dSJimmy Vetayases 				    "property for %s\n", ddi_node_name(cdip));
359cb7ea99dSJimmy Vetayases 				rval = DDI_FAILURE;
360cb7ea99dSJimmy Vetayases 			}
361cb7ea99dSJimmy Vetayases 		}
362cb7ea99dSJimmy Vetayases 
363cb7ea99dSJimmy Vetayases 		pci_config_teardown(&cfg_hdl);
364cb7ea99dSJimmy Vetayases 	}
365cb7ea99dSJimmy Vetayases 
366cb7ea99dSJimmy Vetayases 	return (rval);
367cb7ea99dSJimmy Vetayases }
368cb7ea99dSJimmy Vetayases 
369cb7ea99dSJimmy Vetayases int
370cb7ea99dSJimmy Vetayases npe_restore_htconfig_children(dev_info_t *dip)
371cb7ea99dSJimmy Vetayases {
372cb7ea99dSJimmy Vetayases 	dev_info_t *cdip = ddi_get_child(dip);
373cb7ea99dSJimmy Vetayases 	int rval = DDI_SUCCESS;
374cb7ea99dSJimmy Vetayases 
375cb7ea99dSJimmy Vetayases 	for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
376cb7ea99dSJimmy Vetayases 		if (ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
377cb7ea99dSJimmy Vetayases 		    "htconfig-saved", 0) == 0)
378cb7ea99dSJimmy Vetayases 			continue;
379cb7ea99dSJimmy Vetayases 
380cb7ea99dSJimmy Vetayases 		if (pci_restore_config_regs(cdip) != DDI_SUCCESS) {
381cb7ea99dSJimmy Vetayases 			cmn_err(CE_WARN, "Failed to restore HT config "
382cb7ea99dSJimmy Vetayases 			    "regs for %s\n", ddi_node_name(cdip));
383cb7ea99dSJimmy Vetayases 			rval = DDI_FAILURE;
384cb7ea99dSJimmy Vetayases 		}
385cb7ea99dSJimmy Vetayases 	}
386cb7ea99dSJimmy Vetayases 
387cb7ea99dSJimmy Vetayases 	return (rval);
388cb7ea99dSJimmy Vetayases }
389