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*b8a9d70fSJoshua 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*b8a9d70fSJoshua M. Clulow * Query the MCFG table using ACPI. If MCFG is found, setup the 'ecfg'
63*b8a9d70fSJoshua M. Clulow * property accordingly. If no table is found, the property remains unset; the
64*b8a9d70fSJoshua M. Clulow * system will not make use of memory-mapped access to PCI Express
65*b8a9d70fSJoshua M. Clulow * configuration space.
6670025d76Sjohnny */
6770025d76Sjohnny void
npe_query_acpi_mcfg(dev_info_t * dip)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
npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)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
npe_disable_empty_bridges_workaround(dev_info_t * child)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
npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl)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
npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl)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
npe_child_is_pci(dev_info_t * dip)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
npe_is_mmcfg_supported(dev_info_t * dip)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
npe_enable_htmsi(ddi_acc_handle_t cfg_hdl)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
npe_enable_htmsi_children(dev_info_t * dip)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
npe_save_htconfig_children(dev_info_t * dip)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
npe_restore_htconfig_children(dev_info_t * dip)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