70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * CDDL HEADER START
70025d765b044c6d8594bb965a2247a61e991a99johnny *
70025d765b044c6d8594bb965a2247a61e991a99johnny * The contents of this file are subject to the terms of the
7a23d1009aa28ea040052630547929b9c5eb6ab4anish * Common Development and Distribution License (the "License").
7a23d1009aa28ea040052630547929b9c5eb6ab4anish * You may not use this file except in compliance with the License.
70025d765b044c6d8594bb965a2247a61e991a99johnny *
70025d765b044c6d8594bb965a2247a61e991a99johnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
70025d765b044c6d8594bb965a2247a61e991a99johnny * or http://www.opensolaris.org/os/licensing.
70025d765b044c6d8594bb965a2247a61e991a99johnny * See the License for the specific language governing permissions
70025d765b044c6d8594bb965a2247a61e991a99johnny * and limitations under the License.
70025d765b044c6d8594bb965a2247a61e991a99johnny *
70025d765b044c6d8594bb965a2247a61e991a99johnny * When distributing Covered Code, include this CDDL HEADER in each
70025d765b044c6d8594bb965a2247a61e991a99johnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
70025d765b044c6d8594bb965a2247a61e991a99johnny * If applicable, add the following below this CDDL HEADER, with the
70025d765b044c6d8594bb965a2247a61e991a99johnny * fields enclosed by brackets "[]" replaced with your own identifying
70025d765b044c6d8594bb965a2247a61e991a99johnny * information: Portions Copyright [yyyy] [name of copyright owner]
70025d765b044c6d8594bb965a2247a61e991a99johnny *
70025d765b044c6d8594bb965a2247a61e991a99johnny * CDDL HEADER END
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
99abc82310f6fbd4f04276f195f54d54f458be33Joshua M. Clulow * Copyright 2015 Joyent, Inc.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Library file that has miscellaneous support for npe(7d)
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/conf.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/pci.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/sunndi.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/acpi/acpi.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/acpi/acpi_pci.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/acpica.h>
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae#include <sys/pci_cap.h>
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae#include <sys/pcie_impl.h>
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur#include <sys/x86_archext.h>
8a5a0d1e4394737d73b1496b2cd844056e26c1b4anish#include <io/pciex/pcie_nvidia.h>
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet#include <io/pciex/pcie_nb5000.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/pci_cfgacc_x86.h>
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases#include <sys/cpuvar.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Prototype declaration
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnyvoid npe_query_acpi_mcfg(dev_info_t *dip);
337fc9e235877b459e389f54daf9833bbc645439anishvoid npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
7a23d1009aa28ea040052630547929b9c5eb6ab4anishint npe_disable_empty_bridges_workaround(dev_info_t *child);
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyakvoid npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl);
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyakvoid npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaurboolean_t npe_is_child_pci(dev_info_t *dip);
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayasesint npe_enable_htmsi(ddi_acc_handle_t cfg_hdl);
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayasesvoid npe_enable_htmsi_children(dev_info_t *dip);
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayasesint npe_enable_htmsi_flag = 1;
70025d765b044c6d8594bb965a2247a61e991a99johnny
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyakextern uint32_t npe_aer_uce_mask;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
99abc82310f6fbd4f04276f195f54d54f458be33Joshua M. Clulow * Query the MCFG table using ACPI. If MCFG is found, setup the 'ecfg'
99abc82310f6fbd4f04276f195f54d54f458be33Joshua M. Clulow * property accordingly. If no table is found, the property remains unset; the
99abc82310f6fbd4f04276f195f54d54f458be33Joshua M. Clulow * system will not make use of memory-mapped access to PCI Express
99abc82310f6fbd4f04276f195f54d54f458be33Joshua M. Clulow * configuration space.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnyvoid
70025d765b044c6d8594bb965a2247a61e991a99johnnynpe_query_acpi_mcfg(dev_info_t *dip)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny MCFG_TABLE *mcfgp;
70025d765b044c6d8594bb965a2247a61e991a99johnny CFG_BASE_ADDR_ALLOC *cfg_baap;
70025d765b044c6d8594bb965a2247a61e991a99johnny char *cfg_baa_endp;
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick int64_t ecfginfo[4];
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* Query the MCFG table using ACPI */
c1381f4429cde25f5ee926dfa005545a7f220ba9Dana Myers if (AcpiGetTable(ACPI_SIG_MCFG, 1,
c1381f4429cde25f5ee926dfa005545a7f220ba9Dana Myers (ACPI_TABLE_HEADER **)&mcfgp) == AE_OK) {
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList;
70025d765b044c6d8594bb965a2247a61e991a99johnny cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny while ((char *)cfg_baap < cfg_baa_endp) {
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick if (cfg_baap->base_addr != (uint64_t)0 &&
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick cfg_baap->segment == 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * Set up the 'ecfg' property to hold
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * base_addr, segment, and first/last bus.
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * We only do the first entry that maps
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * segment 0; nonzero segments are not yet
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * known, or handled. If they appear,
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * we'll need to figure out which bus node
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * should have which entry by examining the
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick * ACPI _SEG method on each bus node.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ecfginfo[0] = cfg_baap->base_addr;
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ecfginfo[1] = cfg_baap->segment;
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ecfginfo[2] = cfg_baap->start_bno;
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ecfginfo[3] = cfg_baap->end_bno;
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick (void) ndi_prop_update_int64_array(
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick DDI_DEV_T_NONE, dip, "ecfg",
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ecfginfo, 4);
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick break;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny cfg_baap++;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Enable reporting of AER capability next pointer.
70025d765b044c6d8594bb965a2247a61e991a99johnny * This needs to be done only for CK8-04 devices
70025d765b044c6d8594bb965a2247a61e991a99johnny * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
70025d765b044c6d8594bb965a2247a61e991a99johnny * NOTE: BIOS is disabling this, it needs to be enabled temporarily
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnyvoid
337fc9e235877b459e389f54daf9833bbc645439anishnpe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
337fc9e235877b459e389f54daf9833bbc645439anish ushort_t cya1;
70025d765b044c6d8594bb965a2247a61e991a99johnny
2f15eac90d333799a61f99c8b0f11a8524a716b9anish if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) &&
2f15eac90d333799a61f99c8b0f11a8524a716b9anish (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) ==
2f15eac90d333799a61f99c8b0f11a8524a716b9anish NVIDIA_CK804_DEVICE_ID) &&
2f15eac90d333799a61f99c8b0f11a8524a716b9anish (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >=
2f15eac90d333799a61f99c8b0f11a8524a716b9anish NVIDIA_CK804_AER_VALID_REVID)) {
2f15eac90d333799a61f99c8b0f11a8524a716b9anish cya1 = pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF);
2f15eac90d333799a61f99c8b0f11a8524a716b9anish if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
2f15eac90d333799a61f99c8b0f11a8524a716b9anish (void) pci_config_put16(cfg_hdl,
2f15eac90d333799a61f99c8b0f11a8524a716b9anish NVIDIA_CK804_VEND_CYA1_OFF,
2f15eac90d333799a61f99c8b0f11a8524a716b9anish cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
2f15eac90d333799a61f99c8b0f11a8524a716b9anish }
70025d765b044c6d8594bb965a2247a61e991a99johnny}
7a23d1009aa28ea040052630547929b9c5eb6ab4anish
7a23d1009aa28ea040052630547929b9c5eb6ab4anish/*
7a23d1009aa28ea040052630547929b9c5eb6ab4anish * If the bridge is empty, disable it
7a23d1009aa28ea040052630547929b9c5eb6ab4anish */
7a23d1009aa28ea040052630547929b9c5eb6ab4anishint
7a23d1009aa28ea040052630547929b9c5eb6ab4anishnpe_disable_empty_bridges_workaround(dev_info_t *child)
7a23d1009aa28ea040052630547929b9c5eb6ab4anish{
7a23d1009aa28ea040052630547929b9c5eb6ab4anish /*
7a23d1009aa28ea040052630547929b9c5eb6ab4anish * Do not bind drivers to empty bridges.
7a23d1009aa28ea040052630547929b9c5eb6ab4anish * Fail above, if the bridge is found to be hotplug capable
7a23d1009aa28ea040052630547929b9c5eb6ab4anish */
d4bc0535efa2c2219e9f83246a5f371dc7f94273Krishna Elango if (ddi_driver_major(child) == ddi_name_to_major("pcieb") &&
7a23d1009aa28ea040052630547929b9c5eb6ab4anish ddi_get_child(child) == NULL &&
7a23d1009aa28ea040052630547929b9c5eb6ab4anish ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
7a23d1009aa28ea040052630547929b9c5eb6ab4anish "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
7a23d1009aa28ea040052630547929b9c5eb6ab4anish return (1);
7a23d1009aa28ea040052630547929b9c5eb6ab4anish
7a23d1009aa28ea040052630547929b9c5eb6ab4anish return (0);
7a23d1009aa28ea040052630547929b9c5eb6ab4anish}
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaevoid
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyaknpe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae uint32_t regs;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae /* Disable ECRC for all devices */
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae PCIE_AER_UCE_ECRC;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae pcie_set_aer_uce_mask(regs);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae /*
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * Turn full scan on since the Error Source ID register may not
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * have the correct ID.
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae */
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak pcie_force_fullscan();
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae }
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae}
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeetvoid
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyaknpe_intel_error_workaround(ddi_acc_handle_t cfg_hdl) {
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet uint32_t regs;
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet if (vendor_id == INTEL_VENDOR_ID) {
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet /*
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * Due to an errata in Intel's ESB2 southbridge, all ECRCs
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * generation/checking need to be disabled. There is a
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * workaround by setting a proprietary bit in the ESB2, but it
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * is not well documented or understood. If that bit is set in
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * the future, then ECRC generation/checking should be enabled
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * again.
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet *
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * Disable ECRC generation/checking by masking ECRC in the AER
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * UE Mask. The pcie misc module would then automatically
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet * disable ECRC generation/checking in the AER Control register.
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet */
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC;
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet pcie_set_aer_uce_mask(regs);
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak if (INTEL_NB5500_PCIE_DEV_ID(dev_id) ||
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak INTEL_NB5520_PCIE_DEV_ID(dev_id)) {
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak /*
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak * Turn full scan on since the Error Source ID register
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak * may not have the correct ID. See Intel 5520 and
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak * Intel 5500 Chipsets errata #34 and #54 in the August
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak * 2009 specification update, document number
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak * 321329-006.
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak */
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak pcie_force_fullscan();
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak }
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet }
5c0a55ff7158dbb6220c31dda253139cf9cf5fdeet}
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur/*
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * Check's if this child is a PCI device.
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * Child is a PCI device if:
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * parent has a dev_type of "pci"
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * -and-
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * child does not have a dev_type of "pciex"
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur *
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * If the parent is not of dev_type "pci", then assume it is "pciex" and all
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * children should support using PCIe style MMCFG access.
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur *
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * If parent's dev_type is "pci" and child is "pciex", then also enable using
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * PCIe style MMCFG access. This covers the case where NPE is "pci" and a PCIe
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * RP is beneath.
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur */
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaurboolean_t
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaurnpe_child_is_pci(dev_info_t *dip) {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur char *dev_type;
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur boolean_t parent_is_pci, child_is_pciex;
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip),
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur DDI_PROP_DONTPASS, "device_type", &dev_type) ==
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur DDI_PROP_SUCCESS) {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur parent_is_pci = (strcmp(dev_type, "pci") == 0);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur ddi_prop_free(dev_type);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur } else {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur parent_is_pci = B_FALSE;
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur }
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur "device_type", &dev_type) == DDI_PROP_SUCCESS) {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur child_is_pciex = (strcmp(dev_type, "pciex") == 0);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur ddi_prop_free(dev_type);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur } else {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur child_is_pciex = B_FALSE;
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur }
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur return (parent_is_pci && !child_is_pciex);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur}
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur/*
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * Checks to see if MMCFG is supported.
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * Returns: TRUE if MMCFG is supported, FALSE if not.
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur *
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * If a device is attached to a parent whose "dev_type" is "pciex",
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * the device will support MMCFG access. Otherwise, use legacy IOCFG access.
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur *
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * Enable Legacy PCI config space access for AMD K8 north bridges.
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * Host bridge: AMD HyperTransport Technology Configuration
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * Host bridge: AMD Address Map
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * Host bridge: AMD DRAM Controller
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * Host bridge: AMD Miscellaneous Control
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur * These devices do not support MMCFG access.
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur */
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaurboolean_t
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldbergnpe_is_mmcfg_supported(dev_info_t *dip)
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur{
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur int vendor_id, device_id;
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur "vendor-id", -1);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur "device-id", -1);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur return !(npe_child_is_pci(dip) ||
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur IS_BAD_AMD_NTBRIDGE(vendor_id, device_id));
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur}
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesint
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesnpe_enable_htmsi(ddi_acc_handle_t cfg_hdl)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases{
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases uint16_t ptr;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases uint16_t reg;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (pci_htcap_locate(cfg_hdl, PCI_HTCAP_TYPE_MASK,
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases PCI_HTCAP_MSIMAP_TYPE, &ptr) != DDI_SUCCESS)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases return (DDI_FAILURE);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases reg |= PCI_HTCAP_MSIMAP_ENABLE;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases return (DDI_SUCCESS);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases}
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesvoid
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesnpe_enable_htmsi_children(dev_info_t *dip)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases{
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases dev_info_t *cdip = ddi_get_child(dip);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases ddi_acc_handle_t cfg_hdl;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases if (!npe_enable_htmsi_flag)
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases return;
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases /*
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases * Hypertransport MSI remapping only applies to AMD CPUs using
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases * Hypertransport (K8 and above) and not other platforms with non-AMD
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases * CPUs that may be using Hypertransport internally in the chipset(s)
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases */
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases if (!(cpuid_getvendor(CPU) == X86_VENDOR_AMD &&
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases cpuid_getfamily(CPU) >= 0xf))
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases return;
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases cmn_err(CE_NOTE, "!npe_enable_htmsi_children: "
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases "pci_config_setup failed for %s",
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases ddi_node_name(cdip));
c92fa3b52130d028bbc9a30d4fc8169164cd7cbfJimmy Vetayases return;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases }
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases (void) npe_enable_htmsi(cfg_hdl);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases pci_config_teardown(&cfg_hdl);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases }
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases}
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases/*
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases * save config regs for HyperTransport devices without drivers of classes:
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases * memory controller and hostbridge
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases */
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesint
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesnpe_save_htconfig_children(dev_info_t *dip)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases{
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases dev_info_t *cdip = ddi_get_child(dip);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases ddi_acc_handle_t cfg_hdl;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases uint16_t ptr;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases int rval = DDI_SUCCESS;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases uint8_t cl, scl;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (ddi_driver_major(cdip) != DDI_MAJOR_T_NONE)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases continue;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases return (DDI_FAILURE);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases cl = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases scl = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (((cl == PCI_CLASS_MEM && scl == PCI_MEM_RAM) ||
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases (cl == PCI_CLASS_BRIDGE && scl == PCI_BRIDGE_HOST)) &&
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases pci_htcap_locate(cfg_hdl, 0, 0, &ptr) == DDI_SUCCESS) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (pci_save_config_regs(cdip) != DDI_SUCCESS) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases cmn_err(CE_WARN, "Failed to save HT config "
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases "regs for %s\n", ddi_node_name(cdip));
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases rval = DDI_FAILURE;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases } else if (ddi_prop_update_int(DDI_DEV_T_NONE, cdip,
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases "htconfig-saved", 1) != DDI_SUCCESS) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases cmn_err(CE_WARN, "Failed to set htconfig-saved "
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases "property for %s\n", ddi_node_name(cdip));
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases rval = DDI_FAILURE;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases }
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases }
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases pci_config_teardown(&cfg_hdl);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases }
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases return (rval);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases}
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesint
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayasesnpe_restore_htconfig_children(dev_info_t *dip)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases{
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases dev_info_t *cdip = ddi_get_child(dip);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases int rval = DDI_SUCCESS;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases "htconfig-saved", 0) == 0)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases continue;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (pci_restore_config_regs(cdip) != DDI_SUCCESS) {
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases cmn_err(CE_WARN, "Failed to restore HT config "
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases "regs for %s\n", ddi_node_name(cdip));
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases rval = DDI_FAILURE;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases }
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases }
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases return (rval);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases}