summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/pkgdefs/SUNWcakr.u/prototype_com1
-rw-r--r--usr/src/pkgdefs/SUNWcakr.v/prototype_com5
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_sparc1
-rw-r--r--usr/src/tools/scripts/bfu.sh10
-rw-r--r--usr/src/uts/common/io/pciex/hotplug/pcishpc.c4
-rw-r--r--usr/src/uts/common/io/pciex/pci_cfgacc.c120
-rw-r--r--usr/src/uts/common/io/pciex/pcie.c568
-rw-r--r--usr/src/uts/common/io/pciex/pcieb.c2
-rw-r--r--usr/src/uts/common/sys/pci_cfgacc.h87
-rw-r--r--usr/src/uts/common/sys/pcie_impl.h31
-rw-r--r--usr/src/uts/i86pc/Makefile.files2
-rw-r--r--usr/src/uts/i86pc/Makefile.rules7
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_tools.c243
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe.c7
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe_misc.c38
-rw-r--r--usr/src/uts/i86pc/os/acpi_fw.h24
-rw-r--r--usr/src/uts/i86pc/os/fakebop.c40
-rw-r--r--usr/src/uts/i86pc/os/pci_cfgacc_x86.c301
-rw-r--r--usr/src/uts/i86pc/os/pci_cfgspace.c43
-rw-r--r--usr/src/uts/i86pc/sys/pci_cfgacc_x86.h82
-rw-r--r--usr/src/uts/i86pc/sys/pci_cfgspace_impl.h11
-rw-r--r--usr/src/uts/i86xpv/Makefile.files2
-rw-r--r--usr/src/uts/i86xpv/Makefile.rules7
-rw-r--r--usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c119
-rw-r--r--usr/src/uts/intel/io/pci/pci_boot.c87
-rw-r--r--usr/src/uts/intel/io/pci/pci_pci.c4
-rw-r--r--usr/src/uts/intel/io/pciex/pcie_nvidia.c17
-rw-r--r--usr/src/uts/intel/io/pciex/pcie_nvidia.h5
-rw-r--r--usr/src/uts/intel/pci_autoconfig/Makefile2
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared2
-rw-r--r--usr/src/uts/sun4/io/pcicfg.c141
-rw-r--r--usr/src/uts/sun4/io/px/px.c31
-rw-r--r--usr/src/uts/sun4/io/px/px_ioapi.h13
-rw-r--r--usr/src/uts/sun4/io/px/px_lib.h9
-rw-r--r--usr/src/uts/sun4/io/px/px_util.c3
-rw-r--r--usr/src/uts/sun4u/Makefile.files2
-rw-r--r--usr/src/uts/sun4u/Makefile.rules13
-rw-r--r--usr/src/uts/sun4u/Makefile.sun4u.shared1
-rw-r--r--usr/src/uts/sun4u/io/pci/pci_pci.c4
-rw-r--r--usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c139
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c55
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.h4
-rw-r--r--usr/src/uts/sun4u/pcie/Makefile (renamed from usr/src/uts/sparc/pcie/Makefile)39
-rw-r--r--usr/src/uts/sun4v/Makefile.files1
-rw-r--r--usr/src/uts/sun4v/Makefile.rules13
-rw-r--r--usr/src/uts/sun4v/Makefile.sun4v.shared1
-rw-r--r--usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c130
-rw-r--r--usr/src/uts/sun4v/io/pciex/pci_cfgacc_asm.s89
-rw-r--r--usr/src/uts/sun4v/io/px/px_hcall.s48
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.c31
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.h8
-rw-r--r--usr/src/uts/sun4v/io/px/px_libhv.c2
-rw-r--r--usr/src/uts/sun4v/io/px/px_tools_4v.c51
-rw-r--r--usr/src/uts/sun4v/pcie/Makefile90
-rw-r--r--usr/src/uts/sun4v/sys/pci_cfgacc_4v.h46
55 files changed, 2239 insertions, 597 deletions
diff --git a/usr/src/pkgdefs/SUNWcakr.u/prototype_com b/usr/src/pkgdefs/SUNWcakr.u/prototype_com
index fa6f163a0d..3cd948c18f 100644
--- a/usr/src/pkgdefs/SUNWcakr.u/prototype_com
+++ b/usr/src/pkgdefs/SUNWcakr.u/prototype_com
@@ -488,6 +488,7 @@ f none platform/sun4u/kernel/misc/sparcv9/i2c_svc 755 root sys
l none platform/sun4u/kernel/misc/sparcv9/md5=../../../kernel/crypto/sparcv9/md5
f none platform/sun4u/kernel/misc/sparcv9/obpsym 755 root sys
f none platform/sun4u/kernel/misc/sparcv9/opl_cfg 755 root sys
+f none platform/sun4u/kernel/misc/sparcv9/pcie 755 root sys
f none platform/sun4u/kernel/misc/sparcv9/platmod 755 root sys
f none platform/sun4u/kernel/misc/sparcv9/sbd 755 root sys
l none platform/sun4u/kernel/misc/sparcv9/sha1=../../../kernel/crypto/sparcv9/sha1
diff --git a/usr/src/pkgdefs/SUNWcakr.v/prototype_com b/usr/src/pkgdefs/SUNWcakr.v/prototype_com
index dc0c8441d0..ad4f253201 100644
--- a/usr/src/pkgdefs/SUNWcakr.v/prototype_com
+++ b/usr/src/pkgdefs/SUNWcakr.v/prototype_com
@@ -19,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
@@ -85,6 +83,7 @@ f none platform/sun4v/kernel/misc/sparcv9/kmdbmod 755 root sys
f none platform/sun4v/kernel/misc/sparcv9/bootdev 755 root sys
f none platform/sun4v/kernel/misc/sparcv9/forthdebug 755 root sys
f none platform/sun4v/kernel/misc/sparcv9/obpsym 755 root sys
+f none platform/sun4v/kernel/misc/sparcv9/pcie 755 root sys
f none platform/sun4v/kernel/misc/sparcv9/platmod 755 root sys
f none platform/sun4v/kernel/misc/sparcv9/vis 755 root sys
d none platform/sun4v/kernel/sparcv9 755 root sys
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc
index ca972aa401..347fcf988f 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc
@@ -208,7 +208,6 @@ f none kernel/misc/sparcv9/mac 755 root sys
l none kernel/misc/sparcv9/md5=../../../kernel/crypto/sparcv9/md5
f none kernel/misc/sparcv9/mii 755 root sys
f none kernel/misc/sparcv9/neti 755 root sys
-f none kernel/misc/sparcv9/pcie 755 root sys
f none kernel/misc/sparcv9/pcihp 755 root sys
f none kernel/misc/sparcv9/pcmcia 755 root sys
f none kernel/misc/sparcv9/rpcsec 755 root sys
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index a19e2d9789..4f506787c3 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -7242,6 +7242,16 @@ mondo_loop() {
rm -f $usr/sbin/hotplug
#
+ # Remove old pcie misc module. Also remove new pcie modules for
+ # backward bfu.
+ #
+ if [ $target_isa = sparc ]; then
+ rm -f $root/kernel/misc/sparcv9/pcie
+ rm -f $root/platform/sun4u/kernel/misc/sparcv9/pcie
+ rm -f $root/platform/sun4v/kernel/misc/sparcv9/pcie
+ fi
+
+ #
# Remove the IPsec encryption and authentication modules.
# IPsec now uses the Kernel Crypto Framework for crypto.
#
diff --git a/usr/src/uts/common/io/pciex/hotplug/pcishpc.c b/usr/src/uts/common/io/pciex/hotplug/pcishpc.c
index 272ea39a2d..583b33bf57 100644
--- a/usr/src/uts/common/io/pciex/hotplug/pcishpc.c
+++ b/usr/src/uts/common/io/pciex/hotplug/pcishpc.c
@@ -950,11 +950,13 @@ pcishpc_destroy_controller(dev_info_t *dip)
/*
* Deallocate the slot state structures for this controller.
*/
+ PCIE_SET_HP_CTRL(dip, NULL);
+ bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
+
(void) pcishpc_destroy_slots(ctrl_p);
cv_destroy(&ctrl_p->hc_cmd_comp_cv);
mutex_destroy(&ctrl_p->hc_mutex);
kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
- bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
PCIE_DBG("pcishpc_destroy_controller() success\n");
return (DDI_SUCCESS);
diff --git a/usr/src/uts/common/io/pciex/pci_cfgacc.c b/usr/src/uts/common/io/pciex/pci_cfgacc.c
new file mode 100644
index 0000000000..3022d08872
--- /dev/null
+++ b/usr/src/uts/common/io/pciex/pci_cfgacc.c
@@ -0,0 +1,120 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/pci_cfgacc.h>
+
+#define PCI_CFGACC_FILLREQ(r, d, b, o, s, w, v) \
+ {(r).rcdip = (d); (r).bdf = (b); (r).offset = (o); \
+ (r).size = (s); (r).write = w; (r).ioacc = B_FALSE; \
+ VAL64(&(r)) = (v); }
+
+/*
+ * Common interfaces for accessing pci config space
+ */
+
+/*
+ * This pointer should be initialized before using, here doesn't check it.
+ * For x86:
+ * initialized at the end of pci_check();
+ * For Sparc:
+ * initialized in the px_attach().
+ */
+void (*pci_cfgacc_acc_p)(pci_cfgacc_req_t *req);
+
+uint8_t
+pci_cfgacc_get8(dev_info_t *rcdip, uint16_t bdf, uint16_t off)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 1, B_FALSE, 0);
+ (*pci_cfgacc_acc_p)(&req);
+ return (VAL8(&req));
+}
+
+void
+pci_cfgacc_put8(dev_info_t *rcdip, uint16_t bdf, uint16_t off, uint8_t data)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 1, B_TRUE, data);
+ (*pci_cfgacc_acc_p)(&req);
+}
+
+uint16_t
+pci_cfgacc_get16(dev_info_t *rcdip, uint16_t bdf, uint16_t off)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 2, B_FALSE, 0);
+ (*pci_cfgacc_acc_p)(&req);
+ return (VAL16(&req));
+}
+
+void
+pci_cfgacc_put16(dev_info_t *rcdip, uint16_t bdf, uint16_t off, uint16_t data)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 2, B_TRUE, data);
+ (*pci_cfgacc_acc_p)(&req);
+}
+
+uint32_t
+pci_cfgacc_get32(dev_info_t *rcdip, uint16_t bdf, uint16_t off)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 4, B_FALSE, 0);
+ (*pci_cfgacc_acc_p)(&req);
+ return (VAL32(&req));
+}
+
+void
+pci_cfgacc_put32(dev_info_t *rcdip, uint16_t bdf, uint16_t off, uint32_t data)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 4, B_TRUE, data);
+ (*pci_cfgacc_acc_p)(&req);
+}
+
+uint64_t
+pci_cfgacc_get64(dev_info_t *rcdip, uint16_t bdf, uint16_t off)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 8, B_FALSE, 0);
+ (*pci_cfgacc_acc_p)(&req);
+ return (VAL64(&req));
+}
+
+void
+pci_cfgacc_put64(dev_info_t *rcdip, uint16_t bdf, uint16_t off, uint64_t data)
+{
+ pci_cfgacc_req_t req;
+
+ PCI_CFGACC_FILLREQ(req, rcdip, bdf, off, 8, B_TRUE, data);
+ (*pci_cfgacc_acc_p)(&req);
+}
diff --git a/usr/src/uts/common/io/pciex/pcie.c b/usr/src/uts/common/io/pciex/pcie.c
index 58fb89f90b..a1e43fc27e 100644
--- a/usr/src/uts/common/io/pciex/pcie.c
+++ b/usr/src/uts/common/io/pciex/pcie.c
@@ -41,6 +41,7 @@
#include <sys/pcie_impl.h>
#include <sys/hotplug/pci/pcie_hp.h>
#include <sys/hotplug/pci/pcicfg.h>
+#include <sys/pci_cfgacc.h>
/* Local functions prototypes */
static void pcie_init_pfd(dev_info_t *);
@@ -144,6 +145,8 @@ static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
caddr_t *addrp, ddi_acc_handle_t *handlep);
static void pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph);
+dev_info_t *pcie_get_rc_dip(dev_info_t *dip);
+
/*
* modload support
*/
@@ -389,6 +392,35 @@ skip:
return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
}
+int
+pcie_init_cfghdl(dev_info_t *cdip)
+{
+ pcie_bus_t *bus_p;
+ ddi_acc_handle_t eh = NULL;
+
+ bus_p = PCIE_DIP2BUS(cdip);
+ if (bus_p == NULL)
+ return (DDI_FAILURE);
+
+ /* Create an config access special to error handling */
+ if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "Cannot setup config access"
+ " for BDF 0x%x\n", bus_p->bus_bdf);
+ return (DDI_FAILURE);
+ }
+
+ bus_p->bus_cfg_hdl = eh;
+ return (DDI_SUCCESS);
+}
+
+void
+pcie_fini_cfghdl(dev_info_t *cdip)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
+
+ pci_config_teardown(&bus_p->bus_cfg_hdl);
+}
+
/*
* PCI-Express child device initialization.
* This function enables generic pci-express interrupts and error
@@ -413,6 +445,9 @@ pcie_initchild(dev_info_t *cdip)
return (DDI_FAILURE);
}
+ if (pcie_init_cfghdl(cdip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
/* Clear the device's status register */
reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
@@ -509,8 +544,10 @@ pcie_initchild(dev_info_t *cdip)
bus_p->bus_ari = B_TRUE;
}
- if (pcie_initchild_mps(cdip) == DDI_FAILURE)
+ if (pcie_initchild_mps(cdip) == DDI_FAILURE) {
+ pcie_fini_cfghdl(cdip);
return (DDI_FAILURE);
+ }
return (DDI_SUCCESS);
}
@@ -702,6 +739,37 @@ pcie_rc_fini_pfd(pf_data_t *pfd_p)
kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
}
+/*
+ * init pcie_bus_t for root complex
+ *
+ * Only a few of the fields in bus_t is valid for root complex.
+ * The fields that are bracketed are initialized in this routine:
+ *
+ * dev_info_t * <bus_dip>
+ * dev_info_t * bus_rp_dip
+ * ddi_acc_handle_t bus_cfg_hdl
+ * uint_t <bus_fm_flags>
+ * pcie_req_id_t bus_bdf
+ * pcie_req_id_t bus_rp_bdf
+ * uint32_t bus_dev_ven_id
+ * uint8_t bus_rev_id
+ * uint8_t <bus_hdr_type>
+ * uint16_t <bus_dev_type>
+ * uint8_t bus_bdg_secbus
+ * uint16_t bus_pcie_off
+ * uint16_t <bus_aer_off>
+ * uint16_t bus_pcix_off
+ * uint16_t bus_ecc_ver
+ * pci_bus_range_t bus_bus_range
+ * ppb_ranges_t * bus_addr_ranges
+ * int bus_addr_entries
+ * pci_regspec_t * bus_assigned_addr
+ * int bus_assigned_entries
+ * pf_data_t * bus_pfd
+ * int bus_mps
+ * uint64_t bus_cfgacc_base
+ * void * bus_plat_private
+ */
void
pcie_rc_init_bus(dev_info_t *dip)
{
@@ -724,140 +792,228 @@ pcie_rc_init_bus(dev_info_t *dip)
void
pcie_rc_fini_bus(dev_info_t *dip)
{
- pcie_bus_t *bus_p = (pcie_bus_t *)ndi_get_bus_private(dip, B_FALSE);
-
+ pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip);
ndi_set_bus_private(dip, B_FALSE, NULL, NULL);
kmem_free(bus_p, sizeof (pcie_bus_t));
}
/*
- * Initialize PCIe Bus Private Data
+ * partially init pcie_bus_t for device (dip,bdf) for accessing pci
+ * config space
+ *
+ * This routine is invoked during boot, either after creating a devinfo node
+ * (x86 case) or during px driver attach (sparc case); it is also invoked
+ * in hotplug context after a devinfo node is created.
+ *
+ * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL
+ * is set:
+ *
+ * dev_info_t * <bus_dip>
+ * dev_info_t * <bus_rp_dip>
+ * ddi_acc_handle_t bus_cfg_hdl
+ * uint_t bus_fm_flags
+ * pcie_req_id_t <bus_bdf>
+ * pcie_req_id_t <bus_rp_bdf>
+ * uint32_t <bus_dev_ven_id>
+ * uint8_t <bus_rev_id>
+ * uint8_t <bus_hdr_type>
+ * uint16_t <bus_dev_type>
+ * uint8_t <bus_bdg_secbus
+ * uint16_t <bus_pcie_off>
+ * uint16_t <bus_aer_off>
+ * uint16_t <bus_pcix_off>
+ * uint16_t <bus_ecc_ver>
+ * pci_bus_range_t bus_bus_range
+ * ppb_ranges_t * bus_addr_ranges
+ * int bus_addr_entries
+ * pci_regspec_t * bus_assigned_addr
+ * int bus_assigned_entries
+ * pf_data_t * bus_pfd
+ * int bus_mps
+ * uint64_t bus_cfgacc_base
+ * void * bus_plat_private
*
- * PCIe Bus Private Data contains commonly used PCI/PCIe information and offsets
- * to key registers.
+ * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL
+ * is set:
+ *
+ * dev_info_t * bus_dip
+ * dev_info_t * bus_rp_dip
+ * ddi_acc_handle_t bus_cfg_hdl
+ * uint_t bus_fm_flags
+ * pcie_req_id_t bus_bdf
+ * pcie_req_id_t bus_rp_bdf
+ * uint32_t bus_dev_ven_id
+ * uint8_t bus_rev_id
+ * uint8_t bus_hdr_type
+ * uint16_t bus_dev_type
+ * uint8_t <bus_bdg_secbus>
+ * uint16_t bus_pcie_off
+ * uint16_t bus_aer_off
+ * uint16_t bus_pcix_off
+ * uint16_t bus_ecc_ver
+ * pci_bus_range_t <bus_bus_range>
+ * ppb_ranges_t * <bus_addr_ranges>
+ * int <bus_addr_entries>
+ * pci_regspec_t * <bus_assigned_addr>
+ * int <bus_assigned_entries>
+ * pf_data_t * <bus_pfd>
+ * int bus_mps
+ * uint64_t bus_cfgacc_base
+ * void * <bus_plat_private>
*/
+
pcie_bus_t *
-pcie_init_bus(dev_info_t *cdip)
+pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags)
{
- pcie_bus_t *bus_p = 0;
- ddi_acc_handle_t eh = NULL;
- int range_size;
- dev_info_t *pdip;
- const char *errstr = NULL;
+ uint16_t status, base, baseptr, num_cap;
+ uint32_t capid;
+ int range_size;
+ pcie_bus_t *bus_p;
+ dev_info_t *rcdip;
+ dev_info_t *pdip;
+ const char *errstr = NULL;
- ASSERT(PCIE_DIP2UPBUS(cdip) == NULL);
+ if (!(flags & PCIE_BUS_INITIAL))
+ goto initial_done;
- /* allocate memory for pcie bus data */
bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
- /* Set back pointer to dip */
- bus_p->bus_dip = cdip;
+ bus_p->bus_dip = dip;
+ bus_p->bus_bdf = bdf;
- /* Create an config access special to error handling */
- if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
- errstr = "Cannot setup config access";
- goto fail;
- }
+ rcdip = pcie_get_rc_dip(dip);
+ ASSERT(rcdip != NULL);
- bus_p->bus_cfg_hdl = eh;
- bus_p->bus_fm_flags = 0;
- bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
+ /* Save the Vendor ID, Device ID and revision ID */
+ bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID);
+ bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID);
+ /* Save the Header Type */
+ bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER);
+ bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
- /* get device's bus/dev/function number */
- if (pcie_get_bdf_from_dip(cdip, &bus_p->bus_bdf) != DDI_SUCCESS) {
- errstr = "Cannot get device BDF";
- goto fail;
- }
+ /*
+ * Figure out the device type and all the relavant capability offsets
+ */
+ /* set default value */
+ bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
- /* Save the Vendor Id Device Id */
- bus_p->bus_dev_ven_id = PCIE_GET(32, bus_p, PCI_CONF_VENID);
- bus_p->bus_rev_id = PCIE_GET(8, bus_p, PCI_CONF_REVID);
+ status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT);
+ if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP))
+ goto caps_done; /* capability not supported */
- /* Save the Header Type */
- bus_p->bus_hdr_type = PCIE_GET(8, bus_p, PCI_CONF_HEADER);
- bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
+ /* Relevant conventional capabilities first */
- /* Figure out the device type and all the relavant capability offsets */
- if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_E, &bus_p->bus_pcie_off))
- != DDI_FAILURE) {
- bus_p->bus_dev_type = PCI_CAP_GET16(eh, NULL,
- bus_p->bus_pcie_off, PCIE_PCIECAP) &
- PCIE_PCIECAP_DEV_TYPE_MASK;
-
- if (PCI_CAP_LOCATE(eh, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_AER),
- &bus_p->bus_aer_off) != DDI_SUCCESS)
- bus_p->bus_aer_off = NULL;
-
- /* Check and save PCIe hotplug capability information */
- if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
- (PCI_CAP_GET16(eh, NULL, bus_p->bus_pcie_off, PCIE_PCIECAP)
- & PCIE_PCIECAP_SLOT_IMPL) &&
- (PCI_CAP_GET32(eh, NULL, bus_p->bus_pcie_off, PCIE_SLOTCAP)
- & PCIE_SLOTCAP_HP_CAPABLE))
- bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
- } else {
- bus_p->bus_pcie_off = NULL;
- bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
+ /* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */
+ num_cap = 2;
+
+ switch (bus_p->bus_hdr_type) {
+ case PCI_HEADER_ZERO:
+ baseptr = PCI_CONF_CAP_PTR;
+ break;
+ case PCI_HEADER_PPB:
+ baseptr = PCI_BCNF_CAP_PTR;
+ break;
+ case PCI_HEADER_CARDBUS:
+ baseptr = PCI_CBUS_CAP_PTR;
+ break;
+ default:
+ cmn_err(CE_WARN, "%s: unexpected pci header type:%x",
+ __func__, bus_p->bus_hdr_type);
+ goto caps_done;
}
- if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &bus_p->bus_pcix_off))
- != DDI_FAILURE) {
- if (PCIE_IS_BDG(bus_p))
- bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p,
- PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
- else
- bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p,
- PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
- } else {
- bus_p->bus_pcix_off = NULL;
- bus_p->bus_ecc_ver = NULL;
+ base = baseptr;
+ for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap;
+ base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) {
+ capid = pci_cfgacc_get8(rcdip, bdf, base);
+ switch (capid) {
+ case PCI_CAP_ID_PCI_E:
+ bus_p->bus_pcie_off = base;
+ bus_p->bus_dev_type = pci_cfgacc_get16(rcdip, bdf,
+ base + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
+
+ /* Check and save PCIe hotplug capability information */
+ if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
+ (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP)
+ & PCIE_PCIECAP_SLOT_IMPL) &&
+ (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP)
+ & PCIE_SLOTCAP_HP_CAPABLE))
+ bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
+
+ num_cap--;
+ break;
+ case PCI_CAP_ID_PCIX:
+ bus_p->bus_pcix_off = base;
+ if (PCIE_IS_BDG(bus_p))
+ bus_p->bus_ecc_ver =
+ pci_cfgacc_get16(rcdip, bdf, base +
+ PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
+ else
+ bus_p->bus_ecc_ver =
+ pci_cfgacc_get16(rcdip, bdf, base +
+ PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
+ num_cap--;
+ break;
+ default:
+ break;
+ }
}
- /* Save the Range information if device is a switch/bridge */
+ /* Check and save PCI hotplug (SHPC) capability information */
if (PCIE_IS_BDG(bus_p)) {
- /* Check and save PCI hotplug (SHPC) capability information */
- if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_HOTPLUG,
- &bus_p->bus_pci_hp_off)) == DDI_SUCCESS)
- bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
-
- /* get "bus_range" property */
- range_size = sizeof (pci_bus_range_t);
- if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
- "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
- != DDI_PROP_SUCCESS) {
- errstr = "Cannot find \"bus-range\" property";
- goto fail;
+ base = baseptr;
+ for (base = pci_cfgacc_get8(rcdip, bdf, base);
+ base; base = pci_cfgacc_get8(rcdip, bdf,
+ base + PCI_CAP_NEXT_PTR)) {
+ capid = pci_cfgacc_get8(rcdip, bdf, base);
+ if (capid == PCI_CAP_ID_PCI_HOTPLUG) {
+ bus_p->bus_pci_hp_off = base;
+ bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
+ break;
+ }
}
+ }
- /* get secondary bus number */
- bus_p->bus_bdg_secbus = PCIE_GET(8, bus_p, PCI_BCNF_SECBUS);
+ /* Then, relevant extended capabilities */
- /* Get "ranges" property */
- if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
- "ranges", (caddr_t)&bus_p->bus_addr_ranges,
- &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
- bus_p->bus_addr_entries = 0;
- bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
- }
+ if (!PCIE_IS_PCIE(bus_p))
+ goto caps_done;
- /* save "assigned-addresses" property array, ignore failues */
- if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
- "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
- &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
- bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
- else
- bus_p->bus_assigned_entries = 0;
+ /* Extended caps: PCIE_EXT_CAP_ID_AER */
+ for (base = PCIE_EXT_CAP; base; base = (capid >>
+ PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) {
+ capid = pci_cfgacc_get32(rcdip, bdf, base);
+ if (capid == PCI_CAP_EINVAL32)
+ break;
+ if (((capid >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK)
+ == PCIE_EXT_CAP_ID_AER) {
+ bus_p->bus_aer_off = base;
+ break;
+ }
+ }
+caps_done:
/* save RP dip and RP bdf */
if (PCIE_IS_RP(bus_p)) {
- bus_p->bus_rp_dip = cdip;
+ bus_p->bus_rp_dip = dip;
bus_p->bus_rp_bdf = bus_p->bus_bdf;
} else {
- for (pdip = ddi_get_parent(cdip); pdip;
+ for (pdip = ddi_get_parent(dip); pdip;
pdip = ddi_get_parent(pdip)) {
pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
/*
+ * If RP dip and RP bdf in parent's bus_t have
+ * been initialized, simply use these instead of
+ * continuing up to the RC.
+ */
+ if (parent_bus_p->bus_rp_dip != NULL) {
+ bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip;
+ bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf;
+ break;
+ }
+
+ /*
* When debugging be aware that some NVIDIA x86
* architectures have 2 nodes for each RP, One at Bus
* 0x0 and one at Bus 0x80. The requester is from Bus
@@ -871,33 +1027,110 @@ pcie_init_bus(dev_info_t *cdip)
}
}
- ndi_set_bus_private(cdip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
+ bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
+ bus_p->bus_fm_flags = 0;
+ bus_p->bus_mps = 0;
+
+ ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
- if (PCIE_IS_HOTPLUG_CAPABLE(cdip))
- (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
+ if (PCIE_IS_HOTPLUG_CAPABLE(dip))
+ (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
"hotplug-capable");
- pcie_init_pfd(cdip);
+initial_done:
+ if (!(flags & PCIE_BUS_FINAL))
+ goto final_done;
- bus_p->bus_mps = 0;
+ /* already initialized? */
+ bus_p = PCIE_DIP2BUS(dip);
+
+ /* Save the Range information if device is a switch/bridge */
+ if (PCIE_IS_BDG(bus_p)) {
+ /* get "bus_range" property */
+ range_size = sizeof (pci_bus_range_t);
+ if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
+ != DDI_PROP_SUCCESS) {
+ errstr = "Cannot find \"bus-range\" property";
+ cmn_err(CE_WARN,
+ "PCIE init err info failed BDF 0x%x:%s\n",
+ bus_p->bus_bdf, errstr);
+ }
+
+ /* get secondary bus number */
+ rcdip = pcie_get_rc_dip(dip);
+ ASSERT(rcdip != NULL);
+
+ bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip,
+ bus_p->bus_bdf, PCI_BCNF_SECBUS);
+
+ /* Get "ranges" property */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "ranges", (caddr_t)&bus_p->bus_addr_ranges,
+ &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
+ bus_p->bus_addr_entries = 0;
+ bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
+ }
+
+ /* save "assigned-addresses" property array, ignore failues */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
+ &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
+ bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
+ else
+ bus_p->bus_assigned_entries = 0;
+
+ pcie_init_pfd(dip);
- pcie_init_plat(cdip);
+ pcie_init_plat(dip);
+
+final_done:
PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
- ddi_driver_name(cdip), (void *)cdip, bus_p->bus_bdf,
+ ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf,
bus_p->bus_bdg_secbus);
#ifdef DEBUG
pcie_print_bus(bus_p);
#endif
return (bus_p);
-fail:
- cmn_err(CE_WARN, "PCIE init err info failed BDF 0x%x:%s\n",
- bus_p->bus_bdf, errstr);
- if (eh)
- pci_config_teardown(&eh);
- kmem_free(bus_p, sizeof (pcie_bus_t));
- return (NULL);
+}
+
+/*
+ * Invoked before destroying devinfo node, mostly during hotplug
+ * operation to free pcie_bus_t data structure
+ */
+/* ARGSUSED */
+void
+pcie_fini_bus(dev_info_t *dip, uint8_t flags)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
+ ASSERT(bus_p);
+
+ if (flags & PCIE_BUS_INITIAL) {
+ pcie_fini_plat(dip);
+ pcie_fini_pfd(dip);
+
+ kmem_free(bus_p->bus_assigned_addr,
+ (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
+ kmem_free(bus_p->bus_addr_ranges,
+ (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
+ /* zero out the fields that have been destroyed */
+ bus_p->bus_assigned_addr = NULL;
+ bus_p->bus_addr_ranges = NULL;
+ bus_p->bus_assigned_entries = 0;
+ bus_p->bus_addr_entries = 0;
+ }
+
+ if (flags & PCIE_BUS_FINAL) {
+ if (PCIE_IS_HOTPLUG_CAPABLE(dip)) {
+ (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
+ "hotplug-capable");
+ }
+
+ ndi_set_bus_private(dip, B_TRUE, NULL, NULL);
+ kmem_free(bus_p, sizeof (pcie_bus_t));
+ }
}
int
@@ -920,31 +1153,109 @@ void
pcie_uninitchild(dev_info_t *cdip)
{
pcie_disable_errors(cdip);
- pcie_fini_bus(cdip);
+ pcie_fini_cfghdl(cdip);
+}
+
+/*
+ * find the root complex dip
+ */
+dev_info_t *
+pcie_get_rc_dip(dev_info_t *dip)
+{
+ dev_info_t *rcdip;
+ pcie_bus_t *rc_bus_p;
+
+ for (rcdip = ddi_get_parent(dip); rcdip;
+ rcdip = ddi_get_parent(rcdip)) {
+ rc_bus_p = PCIE_DIP2BUS(rcdip);
+ if (rc_bus_p && PCIE_IS_RC(rc_bus_p))
+ break;
+ }
+
+ return (rcdip);
+}
+
+static boolean_t
+pcie_is_pci_device(dev_info_t *dip)
+{
+ dev_info_t *pdip;
+ char *device_type;
+
+ pdip = ddi_get_parent(dip);
+ ASSERT(pdip);
+
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
+ "device_type", &device_type) != DDI_PROP_SUCCESS)
+ return (B_FALSE);
+
+ if (strcmp(device_type, "pciex") != 0 &&
+ strcmp(device_type, "pci") != 0) {
+ ddi_prop_free(device_type);
+ return (B_FALSE);
+ }
+
+ ddi_prop_free(device_type);
+ return (B_TRUE);
+}
+
+typedef struct {
+ boolean_t init;
+ uint8_t flags;
+} pcie_bus_arg_t;
+
+/*ARGSUSED*/
+static int
+pcie_fab_do_init_fini(dev_info_t *dip, void *arg)
+{
+ pcie_req_id_t bdf;
+ pcie_bus_arg_t *bus_arg = (pcie_bus_arg_t *)arg;
+
+ if (!pcie_is_pci_device(dip))
+ goto out;
+
+ if (bus_arg->init) {
+ if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS)
+ goto out;
+
+ (void) pcie_init_bus(dip, bdf, bus_arg->flags);
+ } else {
+ (void) pcie_fini_bus(dip, bus_arg->flags);
+ }
+
+ return (DDI_WALK_CONTINUE);
+
+out:
+ return (DDI_WALK_PRUNECHILD);
}
void
-pcie_fini_bus(dev_info_t *cdip)
+pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags)
{
- pcie_bus_t *bus_p;
+ int circular_count;
+ dev_info_t *dip = ddi_get_child(rcdip);
+ pcie_bus_arg_t arg;
- pcie_fini_plat(cdip);
- pcie_fini_pfd(cdip);
+ arg.init = B_TRUE;
+ arg.flags = flags;
- bus_p = PCIE_DIP2UPBUS(cdip);
- ASSERT(bus_p);
+ ndi_devi_enter(rcdip, &circular_count);
+ ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
+ ndi_devi_exit(rcdip, circular_count);
+}
- if (PCIE_IS_HOTPLUG_CAPABLE(cdip))
- (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, "hotplug-capable");
+void
+pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags)
+{
+ int circular_count;
+ dev_info_t *dip = ddi_get_child(rcdip);
+ pcie_bus_arg_t arg;
- pci_config_teardown(&bus_p->bus_cfg_hdl);
- ndi_set_bus_private(cdip, B_TRUE, NULL, NULL);
- kmem_free(bus_p->bus_assigned_addr,
- (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
- kmem_free(bus_p->bus_addr_ranges,
- (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
+ arg.init = B_FALSE;
+ arg.flags = flags;
- kmem_free(bus_p, sizeof (pcie_bus_t));
+ ndi_devi_enter(rcdip, &circular_count);
+ ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
+ ndi_devi_exit(rcdip, circular_count);
}
void
@@ -1980,4 +2291,5 @@ pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range,
*empty_mem_range = B_TRUE;
}
}
+
#endif /* defined(__i386) || defined(__amd64) */
diff --git a/usr/src/uts/common/io/pciex/pcieb.c b/usr/src/uts/common/io/pciex/pcieb.c
index 998027f4a3..53fb1b96b4 100644
--- a/usr/src/uts/common/io/pciex/pcieb.c
+++ b/usr/src/uts/common/io/pciex/pcieb.c
@@ -780,7 +780,7 @@ pcieb_initchild(dev_info_t *child)
"INITCHILD: config regs setup for %s@%s\n",
ddi_node_name(child), ddi_get_name_addr(child));
- if (!pcie_init_bus(child) || pcie_initchild(child) != DDI_SUCCESS) {
+ if (pcie_initchild(child) != DDI_SUCCESS) {
result = DDI_FAILURE;
goto cleanup;
}
diff --git a/usr/src/uts/common/sys/pci_cfgacc.h b/usr/src/uts/common/sys/pci_cfgacc.h
new file mode 100644
index 0000000000..e655734cec
--- /dev/null
+++ b/usr/src/uts/common/sys/pci_cfgacc.h
@@ -0,0 +1,87 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PCI_CFGACC_H
+#define _PCI_CFGACC_H
+
+#include <sys/dditypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ASM
+
+#define PCI_GETBDF(b, d, f) \
+ ((d != 0) ? \
+ ((((uint16_t)b & 0xff) << 8) + (((uint8_t)d & 0x1f) << 3) + \
+ ((uint8_t)f & 0x7)) : \
+ ((((uint16_t)b & 0xff) << 8) + ((uint8_t)f & 0xff)))
+
+typedef union pci_cfg_data {
+ uint8_t b;
+ uint16_t w;
+ uint32_t dw;
+ uint64_t qw;
+} pci_cfg_data_t;
+
+typedef enum pci_config_size {
+ PCI_CFG_SIZE_BYTE = 1,
+ PCI_CFG_SIZE_WORD = 2,
+ PCI_CFG_SIZE_DWORD = 4,
+ PCI_CFG_SIZE_QWORD = 8
+} pci_config_size_t;
+
+typedef struct pci_cfgacc_req {
+ dev_info_t *rcdip;
+ uint16_t bdf;
+ uint16_t offset;
+ uint8_t size;
+ boolean_t write;
+ pci_cfg_data_t value;
+ boolean_t ioacc;
+} pci_cfgacc_req_t;
+#define VAL8(req) ((req)->value.b)
+#define VAL16(req) ((req)->value.w)
+#define VAL32(req) ((req)->value.dw)
+#define VAL64(req) ((req)->value.qw)
+
+extern uint8_t pci_cfgacc_get8(dev_info_t *, uint16_t, uint16_t);
+extern uint16_t pci_cfgacc_get16(dev_info_t *, uint16_t, uint16_t);
+extern uint32_t pci_cfgacc_get32(dev_info_t *, uint16_t, uint16_t);
+extern uint64_t pci_cfgacc_get64(dev_info_t *, uint16_t, uint16_t);
+extern void pci_cfgacc_put8(dev_info_t *, uint16_t, uint16_t, uint8_t);
+extern void pci_cfgacc_put16(dev_info_t *, uint16_t, uint16_t, uint16_t);
+extern void pci_cfgacc_put32(dev_info_t *, uint16_t, uint16_t, uint32_t);
+extern void pci_cfgacc_put64(dev_info_t *, uint16_t, uint16_t, uint64_t);
+extern void pci_cfgacc_acc(pci_cfgacc_req_t *);
+
+#endif /* _ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PCI_CFGACC_H */
diff --git a/usr/src/uts/common/sys/pcie_impl.h b/usr/src/uts/common/sys/pcie_impl.h
index 378e9b94d3..9215ef6378 100644
--- a/usr/src/uts/common/sys/pcie_impl.h
+++ b/usr/src/uts/common/sys/pcie_impl.h
@@ -59,6 +59,9 @@ extern "C" {
#define PCIE_BUS2DIP(bus_p) bus_p->bus_dip
#define PCIE_BUS2PFD(bus_p) PCIE_DIP2PFD(PCIE_BUS2DIP(bus_p))
+/*
+ * These macros depend on initialization of type related data in bus_p.
+ */
#define PCIE_IS_PCIE(bus_p) (bus_p->bus_pcie_off)
#define PCIE_IS_PCIX(bus_p) (bus_p->bus_pcix_off)
#define PCIE_IS_PCI(bus_p) (!PCIE_IS_PCIE(bus_p))
@@ -256,6 +259,16 @@ typedef struct pf_root_fault {
typedef struct pf_data pf_data_t;
+/*
+ * For hot plugged device, these data are init'ed during during probe
+ * For non-hotplugged device, these data are init'ed in pci_autoconfig (on x86),
+ * or in px_attach()(on sparc).
+ *
+ * For root complex the fields are initialized in pcie_rc_init_bus();
+ * for others part of the fields are initialized in pcie_init_bus(),
+ * and part of fields initialized in pcie_post_init_bus(). See comments
+ * on top of respective functions for details.
+ */
typedef struct pcie_bus {
/* Needed for PCI/PCIe fabric error handling */
dev_info_t *bus_dip;
@@ -294,6 +307,8 @@ typedef struct pcie_bus {
pcie_hp_mode_t bus_hp_curr_mode; /* HP mode used */
void *bus_hp_ctrl; /* HP bus ctrl data */
int bus_ari; /* ARI device */
+
+ uint64_t bus_cfgacc_base; /* config space base address */
} pcie_bus_t;
struct pf_data {
@@ -399,6 +414,13 @@ typedef struct {
pcie_disable_errors(dip); \
}
+/*
+ * pcie_init_buspcie_fini_bus specific flags
+ */
+#define PCIE_BUS_INITIAL 0x0001
+#define PCIE_BUS_FINAL 0x0002
+#define PCIE_BUS_ALL (PCIE_BUS_INITIAL | PCIE_BUS_FINAL)
+
#ifdef DEBUG
#define PCIE_DBG pcie_dbg
/* Common Debugging shortcuts */
@@ -441,6 +463,8 @@ extern int pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
extern void pcie_init_root_port_mps(dev_info_t *dip);
extern int pcie_initchild(dev_info_t *dip);
extern void pcie_uninitchild(dev_info_t *dip);
+extern int pcie_init_cfghdl(dev_info_t *dip);
+extern void pcie_fini_cfghdl(dev_info_t *dip);
extern void pcie_clear_errors(dev_info_t *dip);
extern int pcie_postattach_child(dev_info_t *dip);
extern void pcie_enable_errors(dev_info_t *dip);
@@ -448,8 +472,11 @@ extern void pcie_disable_errors(dev_info_t *dip);
extern int pcie_enable_ce(dev_info_t *dip);
extern boolean_t pcie_bridge_is_link_disabled(dev_info_t *);
-extern pcie_bus_t *pcie_init_bus(dev_info_t *cdip);
-extern void pcie_fini_bus(dev_info_t *cdip);
+extern pcie_bus_t *pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf,
+ uint8_t flags);
+extern void pcie_fini_bus(dev_info_t *dip, uint8_t flags);
+extern void pcie_fab_init_bus(dev_info_t *dip, uint8_t flags);
+extern void pcie_fab_fini_bus(dev_info_t *dip, uint8_t flags);
extern void pcie_rc_init_bus(dev_info_t *dip);
extern void pcie_rc_fini_bus(dev_info_t *dip);
extern void pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd);
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index 0aa207afc3..b8558b8202 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -94,6 +94,8 @@ CORE_OBJS += \
mpcore.o \
notes.o \
pci_bios.o \
+ pci_cfgacc.o \
+ pci_cfgacc_x86.o \
pci_cfgspace.o \
pci_mech1.o \
pci_mech2.o \
diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules
index 7622dbf21f..ab82a3537f 100644
--- a/usr/src/uts/i86pc/Makefile.rules
+++ b/usr/src/uts/i86pc/Makefile.rules
@@ -151,6 +151,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/ppm/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/pciex/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/os/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -360,6 +364,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/ppm/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/pciex/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/os/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/i86pc/io/pci/pci_tools.c b/usr/src/uts/i86pc/io/pci/pci_tools.c
index deb4fbb420..2dea113932 100644
--- a/usr/src/uts/i86pc/io/pci/pci_tools.c
+++ b/usr/src/uts/i86pc/io/pci/pci_tools.c
@@ -42,6 +42,7 @@
#include <sys/promif.h>
#include <sys/x86_archext.h>
#include <sys/cpuvar.h>
+#include <sys/pci_cfgacc.h>
#ifdef __xpv
#include <sys/hypervisor.h>
@@ -54,6 +55,7 @@
#define SUCCESS 0
+extern uint64_t mcfg_mem_base;
int pcitool_debug = 0;
/*
@@ -75,14 +77,11 @@ static uint8_t pci_bars[] = {
static uint64_t max_cfg_size = PCI_CONF_HDR_SIZE;
static uint64_t pcitool_swap_endian(uint64_t data, int size);
-static int pcitool_pciex_cfg_access(dev_info_t *dip, pcitool_reg_t *prg,
+static int pcitool_cfg_access(pcitool_reg_t *prg, boolean_t write_flag,
+ boolean_t io_access);
+static int pcitool_io_access(pcitool_reg_t *prg, boolean_t write_flag);
+static int pcitool_mem_access(pcitool_reg_t *prg, uint64_t virt_addr,
boolean_t write_flag);
-static int pcitool_cfg_access(dev_info_t *dip, pcitool_reg_t *prg,
- boolean_t write_flag);
-static int pcitool_io_access(dev_info_t *dip, pcitool_reg_t *prg,
- boolean_t write_flag);
-static int pcitool_mem_access(dev_info_t *dip, pcitool_reg_t *prg,
- uint64_t virt_addr, boolean_t write_flag);
static uint64_t pcitool_map(uint64_t phys_addr, size_t size, size_t *num_pages);
static void pcitool_unmap(uint64_t virt_addr, size_t num_pages);
@@ -243,8 +242,6 @@ pcitool_get_intr_dev_info(dev_info_t *dip, pcitool_intr_dev_t *devs)
devs->dev_inst = ddi_get_instance(dip);
}
-
-/*ARGSUSED*/
static int
pcitool_get_intr(dev_info_t *dip, void *arg, int mode)
{
@@ -438,7 +435,6 @@ pcitool_intr_info(dev_info_t *dip, void *arg, int mode)
* Main function for handling interrupt CPU binding requests and queries.
* Need to implement later
*/
-/*ARGSUSED*/
int
pcitool_intr_admn(dev_info_t *dip, void *arg, int cmd, int mode)
{
@@ -466,16 +462,6 @@ pcitool_intr_admn(dev_info_t *dip, void *arg, int cmd, int mode)
return (rval);
}
-
-/*
- * A note about ontrap handling:
- *
- * X86 systems on which this module was tested return FFs instead of bus errors
- * when accessing devices with invalid addresses. Ontrap handling, which
- * gracefully handles kernel bus errors, is installed anyway, in case future
- * X86 platforms require it.
- */
-
/*
* Perform register accesses on the nexus device itself.
* No explicit PCI nexus device for X86, so not applicable.
@@ -511,158 +497,97 @@ pcitool_swap_endian(uint64_t data, int size)
return (returned_data.data64);
}
-
/*
- * Access device. prg is modified.
+ * A note about ontrap handling:
*
- * Extended config space is available only through memory-mapped access.
- * Standard config space on pci express devices is available either way,
- * so do it memory-mapped here too, for simplicity, if allowed by MCFG.
- * If anything fails, return EINVAL so caller can try I/O access.
+ * X86 systems on which this module was tested return FFs instead of bus errors
+ * when accessing devices with invalid addresses. Ontrap handling, which
+ * gracefully handles kernel bus errors, is installed anyway for I/O and mem
+ * space accessing (not for pci config space), in case future X86 platforms
+ * require it.
*/
-/*ARGSUSED*/
-static int
-pcitool_pciex_cfg_access(dev_info_t *dip, pcitool_reg_t *prg,
- boolean_t write_flag)
-{
- int rval = SUCCESS;
- uint64_t virt_addr;
- size_t num_virt_pages;
- int first_bus, last_bus;
- int64_t *ecfginfo;
- uint_t nelem;
-
- prg->status = PCITOOL_SUCCESS;
-
- if (ddi_prop_lookup_int64_array(DDI_DEV_T_ANY, dip, 0,
- "ecfg", &ecfginfo, &nelem) == DDI_PROP_SUCCESS) {
-
- /*
- * We must have a four-element property; base addr [0] must
- * be nonzero. Also, segment [1] must be 0 for now; we don't
- * handle nonzero segments (or create a property containing
- * them)
- */
- if ((nelem != 4) || (ecfginfo[0] == 0) || (ecfginfo[1] != 0)) {
- ddi_prop_free(ecfginfo);
- return (EINVAL);
- }
-
- prg->phys_addr = ecfginfo[0];
- first_bus = ecfginfo[2];
- last_bus = ecfginfo[3];
-
- ddi_prop_free(ecfginfo);
-
- if (prg->bus_no < first_bus || prg->bus_no > last_bus)
- return (EINVAL);
- } else {
- return (EINVAL);
- }
-
- prg->phys_addr += prg->offset +
- ((prg->bus_no << PCIEX_REG_BUS_SHIFT) |
- (prg->dev_no << PCIEX_REG_DEV_SHIFT) |
- (prg->func_no << PCIEX_REG_FUNC_SHIFT));
-
- virt_addr = pcitool_map(prg->phys_addr,
- PCITOOL_ACC_ATTR_SIZE(prg->acc_attr), &num_virt_pages);
-
- if (virt_addr == NULL)
- return (EINVAL);
-
- rval = pcitool_mem_access(dip, prg, virt_addr, write_flag);
- pcitool_unmap(virt_addr, num_virt_pages);
- return (rval);
-}
/* Access device. prg is modified. */
-/*ARGSUSED*/
static int
-pcitool_cfg_access(dev_info_t *dip, pcitool_reg_t *prg, boolean_t write_flag)
+pcitool_cfg_access(pcitool_reg_t *prg, boolean_t write_flag,
+ boolean_t io_access)
{
int size = PCITOOL_ACC_ATTR_SIZE(prg->acc_attr);
boolean_t big_endian = PCITOOL_ACC_IS_BIG_ENDIAN(prg->acc_attr);
int rval = SUCCESS;
uint64_t local_data;
+ pci_cfgacc_req_t req;
+ uint32_t max_offset;
+
+ if ((size <= 0) || (size > 8) || ((size & (size - 1)) != 0)) {
+ prg->status = PCITOOL_INVALID_SIZE;
+ return (ENOTSUP);
+ }
/*
* NOTE: there is no way to verify whether or not the address is
* valid other than that it is within the maximum offset. The
- * put functions return void and the get functions return ff on
- * error.
+ * put functions return void and the get functions return -1 on error.
*/
- if (prg->offset + size - 1 > 0xFF) {
+ if (io_access)
+ max_offset = 0xFF;
+ else
+ max_offset = 0xFFF;
+ if (prg->offset + size - 1 > max_offset) {
prg->status = PCITOOL_INVALID_ADDRESS;
return (ENOTSUP);
}
prg->status = PCITOOL_SUCCESS;
+ req.rcdip = NULL;
+ req.bdf = PCI_GETBDF(prg->bus_no, prg->dev_no, prg->func_no);
+ req.offset = prg->offset;
+ req.size = size;
+ req.write = write_flag;
+ req.ioacc = io_access;
if (write_flag) {
-
if (big_endian) {
local_data = pcitool_swap_endian(prg->data, size);
} else {
local_data = prg->data;
}
-
- switch (size) {
- case 1:
- (*pci_putb_func)(prg->bus_no, prg->dev_no,
- prg->func_no, prg->offset, local_data);
- break;
- case 2:
- (*pci_putw_func)(prg->bus_no, prg->dev_no,
- prg->func_no, prg->offset, local_data);
- break;
- case 4:
- (*pci_putl_func)(prg->bus_no, prg->dev_no,
- prg->func_no, prg->offset, local_data);
- break;
- default:
- rval = ENOTSUP;
- prg->status = PCITOOL_INVALID_SIZE;
- break;
- }
+ VAL64(&req) = local_data;
+ pci_cfgacc_acc(&req);
} else {
- switch (size) {
- case 1:
- local_data = (*pci_getb_func)(prg->bus_no, prg->dev_no,
- prg->func_no, prg->offset);
- break;
- case 2:
- local_data = (*pci_getw_func)(prg->bus_no, prg->dev_no,
- prg->func_no, prg->offset);
- break;
- case 4:
- local_data = (*pci_getl_func)(prg->bus_no, prg->dev_no,
- prg->func_no, prg->offset);
- break;
- default:
- rval = ENOTSUP;
- prg->status = PCITOOL_INVALID_SIZE;
- break;
+ pci_cfgacc_acc(&req);
+ local_data = VAL64(&req);
+ if (big_endian) {
+ prg->data =
+ pcitool_swap_endian(local_data, size);
+ } else {
+ prg->data = local_data;
}
+ }
+ /*
+ * Check if legacy IO config access is used, in which case
+ * only first 256 bytes are valid.
+ */
+ if (req.ioacc && (prg->offset + size - 1 > 0xFF)) {
+ prg->status = PCITOOL_INVALID_ADDRESS;
+ return (ENOTSUP);
+ }
- if (rval == SUCCESS) {
- if (big_endian) {
- prg->data =
- pcitool_swap_endian(local_data, size);
- } else {
- prg->data = local_data;
- }
- }
+ /* Set phys_addr only if MMIO is used */
+ prg->phys_addr = 0;
+ if (!req.ioacc && mcfg_mem_base != 0) {
+ prg->phys_addr = mcfg_mem_base + prg->offset +
+ ((prg->bus_no << PCIEX_REG_BUS_SHIFT) |
+ (prg->dev_no << PCIEX_REG_DEV_SHIFT) |
+ (prg->func_no << PCIEX_REG_FUNC_SHIFT));
}
- prg->phys_addr = 0; /* Config space is not memory mapped on X86. */
+
return (rval);
}
-
-/*ARGSUSED*/
static int
-pcitool_io_access(dev_info_t *dip, pcitool_reg_t *prg, boolean_t write_flag)
+pcitool_io_access(pcitool_reg_t *prg, boolean_t write_flag)
{
int port = (int)prg->phys_addr;
size_t size = PCITOOL_ACC_ATTR_SIZE(prg->acc_attr);
@@ -750,10 +675,8 @@ pcitool_io_access(dev_info_t *dip, pcitool_reg_t *prg, boolean_t write_flag)
return (rval);
}
-/*ARGSUSED*/
static int
-pcitool_mem_access(dev_info_t *dip, pcitool_reg_t *prg, uint64_t virt_addr,
- boolean_t write_flag)
+pcitool_mem_access(pcitool_reg_t *prg, uint64_t virt_addr, boolean_t write_flag)
{
size_t size = PCITOOL_ACC_ATTR_SIZE(prg->acc_attr);
boolean_t big_endian = PCITOOL_ACC_IS_BIG_ENDIAN(prg->acc_attr);
@@ -922,10 +845,12 @@ pcitool_unmap(uint64_t virt_addr, size_t num_pages)
/* Perform register accesses on PCI leaf devices. */
+/*ARGSUSED*/
int
pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
{
boolean_t write_flag = B_FALSE;
+ boolean_t io_access = B_TRUE;
int rval = 0;
pcitool_reg_t prg;
uint8_t size;
@@ -989,36 +914,10 @@ pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
rval = EINVAL;
goto done_reg;
}
+ if (max_cfg_size == PCIE_CONF_HDR_SIZE)
+ io_access = B_FALSE;
- /*
- * Access device. prg is modified.
- * First, check for AMD K8 northbridges for I/O access
- * (This fix will move in future to pcitool user-land)
- * Next, check for PCIe devices and do
- * memory-mapped access
- * Lastly, check for PCI devices and do I/O access
- */
- if ((prg.bus_no == 0) &&
- (prg.dev_no >= 0x18) &&
- (prg.dev_no <
- (0x18 + ncpus/cpuid_get_ncpu_per_chip(CPU))) &&
- (cpuid_getvendor(CPU) == X86_VENDOR_AMD) &&
- (cpuid_getfamily(CPU) == 0xf)) {
- rval = pcitool_cfg_access(dip, &prg,
- write_flag);
- } else if (max_cfg_size == PCIE_CONF_HDR_SIZE) {
- rval = pcitool_pciex_cfg_access(dip, &prg,
- write_flag);
- if (rval == EINVAL) {
- /* Not valid for MMIO; try IO */
- rval = pcitool_cfg_access(dip, &prg,
- write_flag);
- }
- } else {
- rval = pcitool_cfg_access(dip, &prg,
- write_flag);
- }
-
+ rval = pcitool_cfg_access(&prg, write_flag, io_access);
if (pcitool_debug)
prom_printf(
"config access: data:0x%" PRIx64 "\n",
@@ -1047,7 +946,7 @@ pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
* prg2.offset is the offset into config space of the
* BAR desired. prg.status is modified on error.
*/
- rval = pcitool_cfg_access(dip, &prg2, B_FALSE);
+ rval = pcitool_cfg_access(&prg2, B_FALSE, B_TRUE);
if (rval != SUCCESS) {
if (pcitool_debug)
prom_printf("BAR access failed\n");
@@ -1091,7 +990,7 @@ pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
prg2.data &= PCI_BASE_IO_ADDR_M;
prg.phys_addr = prg2.data + prg.offset;
- rval = pcitool_io_access(dip, &prg, write_flag);
+ rval = pcitool_io_access(&prg, write_flag);
if ((rval != SUCCESS) && (pcitool_debug))
prom_printf("IO access failed\n");
@@ -1129,7 +1028,8 @@ pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
* prg2.status is modified on error.
*/
prg2.offset += 4;
- rval = pcitool_cfg_access(dip, &prg2, B_FALSE);
+ rval = pcitool_cfg_access(&prg2,
+ B_FALSE, B_TRUE);
if (rval != SUCCESS) {
prg.status = prg2.status;
goto done_reg;
@@ -1199,8 +1099,7 @@ pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
goto done_reg;
}
- rval = pcitool_mem_access(dip, &prg, virt_addr,
- write_flag);
+ rval = pcitool_mem_access(&prg, virt_addr, write_flag);
pcitool_unmap(virt_addr, num_virt_pages);
}
done_reg:
diff --git a/usr/src/uts/i86pc/io/pciex/npe.c b/usr/src/uts/i86pc/io/pciex/npe.c
index 6e40f73475..4780df9d62 100644
--- a/usr/src/uts/i86pc/io/pciex/npe.c
+++ b/usr/src/uts/i86pc/io/pciex/npe.c
@@ -308,8 +308,6 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
pcip->pci_dip = devi;
pcip->pci_soft_state = PCI_SOFT_STATE_CLOSED;
- pcie_rc_init_bus(devi);
-
if (pcie_init(devi, NULL) != DDI_SUCCESS)
goto fail1;
@@ -330,6 +328,7 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
npe_query_acpi_mcfg(devi);
ddi_report_dev(devi);
+ pcie_fab_init_bus(devi, PCIE_BUS_FINAL);
return (DDI_SUCCESS);
@@ -353,6 +352,7 @@ npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
switch (cmd) {
case DDI_DETACH:
+ pcie_fab_fini_bus(devi, PCIE_BUS_INITIAL);
/* Uninitialize pcitool support. */
pcitool_uninit(devi);
@@ -363,7 +363,6 @@ npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
ddi_fm_handler_unregister(devi);
- pcie_rc_fini_bus(devi);
pcie_rc_fini_pfd(PCIE_DIP2PFD(devi));
kmem_free(PCIE_DIP2PFD(devi), sizeof (pf_data_t));
@@ -939,7 +938,7 @@ npe_initchild(dev_info_t *child)
pci_config_teardown(&cfg_hdl);
}
- bus_p = pcie_init_bus(child);
+ bus_p = PCIE_DIP2BUS(child);
if (bus_p) {
uint16_t device_id = (uint16_t)(bus_p->bus_dev_ven_id >> 16);
uint16_t vendor_id = (uint16_t)(bus_p->bus_dev_ven_id & 0xFFFF);
diff --git a/usr/src/uts/i86pc/io/pciex/npe_misc.c b/usr/src/uts/i86pc/io/pciex/npe_misc.c
index 94c55d3857..6d91107b3f 100644
--- a/usr/src/uts/i86pc/io/pciex/npe_misc.c
+++ b/usr/src/uts/i86pc/io/pciex/npe_misc.c
@@ -39,6 +39,7 @@
#include <sys/x86_archext.h>
#include <io/pciex/pcie_nvidia.h>
#include <io/pciex/pcie_nb5000.h>
+#include <sys/pci_cfgacc_x86.h>
/*
* Prototype declaration
@@ -57,43 +58,6 @@ int64_t npe_default_ecfga_base = 0xE0000000;
extern uint32_t npe_aer_uce_mask;
-/* AMD's northbridges vendor-id and device-ids */
-#define AMD_NTBRDIGE_VID 0x1022 /* AMD vendor-id */
-#define AMD_HT_NTBRIDGE_DID 0x1100 /* HT Configuration */
-#define AMD_AM_NTBRIDGE_DID 0x1101 /* Address Map */
-#define AMD_DC_NTBRIDGE_DID 0x1102 /* DRAM Controller */
-#define AMD_MC_NTBRIDGE_DID 0x1103 /* Misc Controller */
-#define AMD_K10_NTBRIDGE_DID_0 0x1200
-#define AMD_K10_NTBRIDGE_DID_1 0x1201
-#define AMD_K10_NTBRIDGE_DID_2 0x1202
-#define AMD_K10_NTBRIDGE_DID_3 0x1203
-#define AMD_K10_NTBRIDGE_DID_4 0x1204
-
-/*
- * Check if the given device is an AMD northbridge
- */
-#define IS_BAD_AMD_NTBRIDGE(vid, did) \
- (((vid) == AMD_NTBRDIGE_VID) && \
- (((did) == AMD_HT_NTBRIDGE_DID) || \
- ((did) == AMD_AM_NTBRIDGE_DID) || \
- ((did) == AMD_DC_NTBRIDGE_DID) || \
- ((did) == AMD_MC_NTBRIDGE_DID)))
-
-#define IS_K10_AMD_NTBRIDGE(vid, did) \
- (((vid) == AMD_NTBRDIGE_VID) && \
- (((did) == AMD_K10_NTBRIDGE_DID_0) || \
- ((did) == AMD_K10_NTBRIDGE_DID_1) || \
- ((did) == AMD_K10_NTBRIDGE_DID_2) || \
- ((did) == AMD_K10_NTBRIDGE_DID_3) || \
- ((did) == AMD_K10_NTBRIDGE_DID_4)))
-
-#define MSR_AMD_NB_MMIO_CFG_BADDR 0xc0010058
-#define AMD_MMIO_CFG_BADDR_ADDR_MASK 0xFFFFFFF00000ULL
-#define AMD_MMIO_CFG_BADDR_ENA_MASK 0x000000000001ULL
-#define AMD_MMIO_CFG_BADDR_ENA_ON 0x000000000001ULL
-#define AMD_MMIO_CFG_BADDR_ENA_OFF 0x000000000000ULL
-
-
/*
* Query the MCFG table using ACPI. If MCFG is found, setup the
* 'ecfg' property accordingly. Otherwise, set the values
diff --git a/usr/src/uts/i86pc/os/acpi_fw.h b/usr/src/uts/i86pc/os/acpi_fw.h
index decb3569f0..032e231f3f 100644
--- a/usr/src/uts/i86pc/os/acpi_fw.h
+++ b/usr/src/uts/i86pc/os/acpi_fw.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -161,6 +161,28 @@ struct slit {
*/
extern struct slit *slit_ptr;
+struct cfg_base_addr_alloc {
+ uint64_t base_addr;
+ uint16_t segment;
+ uint8_t start_bno;
+ uint8_t end_bno;
+ uint32_t reserved;
+};
+
+struct mcfg {
+ char Signature[4];
+ uint32_t Length;
+ uint8_t Revision;
+ uint8_t Checksum;
+ char OemId[6];
+ char OemTableId[8];
+ uint32_t OemRevision;
+ char CreatorId[4];
+ uint32_t CreatorRevision;
+ uint8_t Reserved[8];
+ struct cfg_base_addr_alloc CfgBaseAddrAllocList[1];
+};
+
struct dmar {
struct table_header hdr;
uint8_t width;
diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c
index d870c940cc..0d6e6c0851 100644
--- a/usr/src/uts/i86pc/os/fakebop.c
+++ b/usr/src/uts/i86pc/os/fakebop.c
@@ -61,6 +61,7 @@
#include <sys/dmar_acpi.h>
#include <sys/kobj.h>
#include <sys/kobj_lex.h>
+#include <sys/pci_cfgspace_impl.h>
#include "acpi_fw.h"
static int have_console = 0; /* set once primitive console is initialized */
@@ -230,7 +231,7 @@ do_bop_phys_alloc(uint64_t size, uint64_t align)
/*NOTREACHED*/
}
-static uintptr_t
+uintptr_t
alloc_vaddr(size_t size, paddr_t align)
{
uintptr_t rv;
@@ -1861,7 +1862,6 @@ bop_no_more_mem(void)
}
-#ifndef __xpv
/*
* Set ACPI firmware properties
*/
@@ -1873,6 +1873,9 @@ vmap_phys(size_t length, paddr_t pa)
caddr_t va;
size_t len, page;
+#ifdef __xpv
+ pa = pfn_to_pa(xen_assign_pfn(mmu_btop(pa))) | (pa & MMU_PAGEOFFSET);
+#endif
start = P2ALIGN(pa, MMU_PAGESIZE);
end = P2ROUNDUP(pa + length, MMU_PAGESIZE);
len = end - start;
@@ -2047,6 +2050,30 @@ find_fw_table(char *signature)
}
static void
+process_mcfg(struct mcfg *tp)
+{
+ struct cfg_base_addr_alloc *cfg_baap;
+ char *cfg_baa_endp;
+ int64_t ecfginfo[4];
+
+ cfg_baap = tp->CfgBaseAddrAllocList;
+ cfg_baa_endp = ((char *)tp) + tp->Length;
+ while ((char *)cfg_baap < cfg_baa_endp) {
+ if (cfg_baap->base_addr != 0 && cfg_baap->segment == 0) {
+ ecfginfo[0] = cfg_baap->base_addr;
+ ecfginfo[1] = cfg_baap->segment;
+ ecfginfo[2] = cfg_baap->start_bno;
+ ecfginfo[3] = cfg_baap->end_bno;
+ bsetprop(MCFG_PROPNAME, strlen(MCFG_PROPNAME),
+ ecfginfo, sizeof (ecfginfo));
+ break;
+ }
+ cfg_baap++;
+ }
+}
+
+#ifndef __xpv
+static void
process_madt(struct madt *tp)
{
struct madt_processor *cpu, *end;
@@ -2235,9 +2262,9 @@ enumerate_xen_cpus()
static void
build_firmware_properties(void)
{
-#ifndef __xpv
- struct table_header *tp;
+ struct table_header *tp = NULL;
+#ifndef __xpv
if ((tp = find_fw_table("APIC")) != NULL)
process_madt((struct madt *)tp);
@@ -2249,9 +2276,14 @@ build_firmware_properties(void)
if (tp = find_fw_table("DMAR"))
process_dmar((struct dmar *)tp);
+ tp = find_fw_table("MCFG");
#else /* __xpv */
enumerate_xen_cpus();
+ if (DOMAIN_IS_INITDOMAIN(xen_info))
+ tp = find_fw_table("MCFG");
#endif /* __xpv */
+ if (tp != NULL)
+ process_mcfg((struct mcfg *)tp);
}
/*
diff --git a/usr/src/uts/i86pc/os/pci_cfgacc_x86.c b/usr/src/uts/i86pc/os/pci_cfgacc_x86.c
new file mode 100644
index 0000000000..0943a8d9de
--- /dev/null
+++ b/usr/src/uts/i86pc/os/pci_cfgacc_x86.c
@@ -0,0 +1,301 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/systm.h>
+#include <sys/pci_cfgacc.h>
+#include <sys/pci_cfgspace.h>
+#include <sys/pci_cfgspace_impl.h>
+#include <sys/sunddi.h>
+#include <sys/sysmacros.h>
+#include <sys/x86_archext.h>
+#include <sys/pci.h>
+#include <vm/hat_i86.h>
+#include <vm/seg_kmem.h>
+#include <vm/kboot_mmu.h>
+
+#define PCIE_CFG_SPACE_SIZE (PCI_CONF_HDR_SIZE << 4)
+#define PCI_BDF_BUS(bdf) ((((uint16_t)bdf) & 0xff00) >> 8)
+#define PCI_BDF_DEV(bdf) ((((uint16_t)bdf) & 0xf8) >> 3)
+#define PCI_BDF_FUNC(bdf) (((uint16_t)bdf) & 0x7)
+
+/* patchable variables */
+volatile boolean_t pci_cfgacc_force_io = B_FALSE;
+
+extern uintptr_t alloc_vaddr(size_t, paddr_t);
+
+void pci_cfgacc_acc(pci_cfgacc_req_t *);
+
+boolean_t pci_cfgacc_find_workaround(uint16_t);
+/*
+ * IS_P2ALIGNED() is used to make sure offset is 'size'-aligned, so
+ * it's guaranteed that the access will not cross 4k page boundary.
+ * Thus only 1 page is allocated for all config space access, and the
+ * virtual address of that page is cached in pci_cfgacc_virt_base.
+ */
+static caddr_t pci_cfgacc_virt_base = NULL;
+
+static caddr_t
+pci_cfgacc_map(paddr_t phys_addr)
+{
+#ifdef __xpv
+ phys_addr = pfn_to_pa(xen_assign_pfn(mmu_btop(phys_addr))) |
+ (phys_addr & MMU_PAGEOFFSET);
+#endif
+ if (khat_running) {
+ pfn_t pfn = mmu_btop(phys_addr);
+ /*
+ * pci_cfgacc_virt_base may hold address left from early
+ * boot, which points to low mem. Realloc virtual address
+ * in kernel space since it's already late in boot now.
+ * Note: no need to unmap first, clear_boot_mappings() will
+ * do that for us.
+ */
+ if (pci_cfgacc_virt_base < (caddr_t)kernelbase) {
+ if ((pci_cfgacc_virt_base = vmem_alloc(heap_arena,
+ MMU_PAGESIZE, VM_NOSLEEP)) == NULL)
+ return (NULL);
+ }
+ hat_devload(kas.a_hat, pci_cfgacc_virt_base,
+ MMU_PAGESIZE, pfn, PROT_READ | PROT_WRITE |
+ HAT_STRICTORDER, HAT_LOAD_LOCK);
+ } else {
+ paddr_t pa_base = P2ALIGN(phys_addr, MMU_PAGESIZE);
+
+ if (pci_cfgacc_virt_base == NULL) {
+ if ((pci_cfgacc_virt_base = (caddr_t)
+ alloc_vaddr(MMU_PAGESIZE, MMU_PAGESIZE)) == NULL)
+ return (NULL);
+ }
+ kbm_map((uintptr_t)pci_cfgacc_virt_base, pa_base, 0, 0);
+ }
+
+ return (pci_cfgacc_virt_base + (phys_addr & MMU_PAGEOFFSET));
+}
+
+static void
+pci_cfgacc_unmap()
+{
+ if (khat_running)
+ hat_unload(kas.a_hat, pci_cfgacc_virt_base, MMU_PAGESIZE,
+ HAT_UNLOAD_UNLOCK);
+}
+
+static void
+pci_cfgacc_io(pci_cfgacc_req_t *req)
+{
+ uint8_t bus, dev, func, ioacc_offset;
+
+ if (req->offset > 0xff) {
+ if (!req->write)
+ VAL64(req) = (uint64_t)-1;
+ return;
+ }
+
+ bus = PCI_BDF_BUS(req->bdf);
+ dev = PCI_BDF_DEV(req->bdf);
+ func = PCI_BDF_FUNC(req->bdf);
+ ioacc_offset = req->offset;
+ switch (req->size) {
+ case 1:
+ if (req->write)
+ (*pci_putb_func)(bus, dev, func,
+ ioacc_offset, VAL8(req));
+ else
+ VAL8(req) = (*pci_getb_func)(bus, dev, func,
+ ioacc_offset);
+ break;
+ case 2:
+ if (req->write)
+ (*pci_putw_func)(bus, dev, func,
+ ioacc_offset, VAL16(req));
+ else
+ VAL16(req) = (*pci_getw_func)(bus, dev, func,
+ ioacc_offset);
+ break;
+ case 4:
+ if (req->write)
+ (*pci_putl_func)(bus, dev, func,
+ ioacc_offset, VAL32(req));
+ else
+ VAL32(req) = (*pci_getl_func)(bus, dev, func,
+ ioacc_offset);
+ break;
+ default:
+ return;
+ }
+}
+
+static int
+pci_cfgacc_mmio(pci_cfgacc_req_t *req)
+{
+ caddr_t vaddr;
+ paddr_t paddr;
+ int rval = DDI_SUCCESS;
+
+ paddr = (paddr_t)req->bdf << 12;
+ paddr += mcfg_mem_base + req->offset;
+
+ mutex_enter(&pcicfg_mutex);
+ if ((vaddr = pci_cfgacc_map(paddr)) == NULL) {
+ mutex_exit(&pcicfg_mutex);
+ return (DDI_FAILURE);
+ }
+
+ switch (req->size) {
+ case 1:
+ if (req->write)
+ *((uint8_t *)vaddr) = VAL8(req);
+ else
+ VAL8(req) = *((uint8_t *)vaddr);
+ break;
+ case 2:
+ if (req->write)
+ *((uint16_t *)vaddr) = VAL16(req);
+ else
+ VAL16(req) = *((uint16_t *)vaddr);
+ break;
+ case 4:
+ if (req->write)
+ *((uint32_t *)vaddr) = VAL32(req);
+ else
+ VAL32(req) = *((uint32_t *)vaddr);
+ break;
+ case 8:
+ if (req->write)
+ *((uint64_t *)vaddr) = VAL64(req);
+ else
+ VAL64(req) = *((uint64_t *)vaddr);
+ break;
+ default:
+ rval = DDI_FAILURE;
+ }
+ pci_cfgacc_unmap();
+ mutex_exit(&pcicfg_mutex);
+
+ return (rval);
+}
+
+static boolean_t
+pci_cfgacc_valid(pci_cfgacc_req_t *req)
+{
+ return (IS_P2ALIGNED(req->offset, req->size) &&
+ (req->offset < PCIE_CFG_SPACE_SIZE));
+}
+
+void
+pci_cfgacc_acc(pci_cfgacc_req_t *req)
+{
+ uint8_t bus;
+
+ if (!req->write)
+ VAL64(req) = 0;
+
+ if (!pci_cfgacc_valid(req)) {
+ if (!req->write)
+ VAL64(req) = (uint64_t)-1;
+ return;
+ }
+
+ bus = PCI_BDF_BUS(req->bdf);
+ if (pci_cfgacc_force_io || (mcfg_mem_base == NULL) ||
+ (bus < mcfg_bus_start) || (bus > mcfg_bus_end))
+ goto ioacc;
+
+ if (req->ioacc)
+ goto ioacc;
+
+ /* check if workaround is needed */
+ if (pci_cfgacc_find_workaround(req->bdf))
+ goto ioacc;
+
+ if (pci_cfgacc_mmio(req) != DDI_SUCCESS)
+ goto ioacc;
+
+ return;
+
+ioacc:
+ pci_cfgacc_io(req);
+ req->ioacc = B_TRUE;
+}
+
+typedef struct cfgacc_bus_range {
+ struct cfgacc_bus_range *next;
+ uint16_t bdf;
+ uchar_t secbus;
+ uchar_t subbus;
+} cfgacc_bus_range_t;
+
+cfgacc_bus_range_t *pci_cfgacc_bus_head = NULL;
+
+#define BUS_INSERT(prev, el) \
+ el->next = *prev; \
+ *prev = el;
+
+#define BUS_REMOVE(prev, el) \
+ *prev = el->next;
+
+/*
+ * This function is only supposed to be called in device tree setup time,
+ * thus no lock is needed.
+ */
+void
+pci_cfgacc_add_workaround(uint16_t bdf, uchar_t secbus, uchar_t subbus)
+{
+ cfgacc_bus_range_t *entry;
+
+ entry = kmem_zalloc(sizeof (cfgacc_bus_range_t), KM_SLEEP);
+ entry->bdf = bdf;
+ entry->secbus = secbus;
+ entry->subbus = subbus;
+ BUS_INSERT(&pci_cfgacc_bus_head, entry);
+}
+
+boolean_t
+pci_cfgacc_find_workaround(uint16_t bdf)
+{
+ cfgacc_bus_range_t *entry;
+ uchar_t bus;
+
+ for (entry = pci_cfgacc_bus_head; entry != NULL;
+ entry = entry->next) {
+ if (bdf == entry->bdf) {
+ /* found a device which is known to be broken */
+ return (B_TRUE);
+ }
+
+ bus = PCI_BDF_BUS(bdf);
+ if ((bus != 0) && (bus >= entry->secbus) &&
+ (bus <= entry->subbus)) {
+ /*
+ * found a device whose parent/grandparent is
+ * known to be broken.
+ */
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
diff --git a/usr/src/uts/i86pc/os/pci_cfgspace.c b/usr/src/uts/i86pc/os/pci_cfgspace.c
index 02463a56c4..9f11cb9c9d 100644
--- a/usr/src/uts/i86pc/os/pci_cfgspace.c
+++ b/usr/src/uts/i86pc/os/pci_cfgspace.c
@@ -35,12 +35,14 @@
#include <sys/pci_impl.h>
#include <sys/pci_cfgspace.h>
#include <sys/pci_cfgspace_impl.h>
+#include <sys/pci_cfgacc.h>
#if defined(__xpv)
#include <sys/hypervisor.h>
-int pci_max_nbus = 0xFE;
#endif
-
+#if defined(__xpv)
+int pci_max_nbus = 0xFE;
+#endif
int pci_bios_cfg_type = PCI_MECHANISM_UNKNOWN;
int pci_bios_maxbus;
int pci_bios_mech;
@@ -54,10 +56,21 @@ int PCI_CFG_TYPE = 0;
int PCI_PROBE_TYPE = 0;
/*
+ * No valid mcfg_mem_base by default, and accessing pci config space
+ * in mem-mapped way is disabled.
+ */
+uint64_t mcfg_mem_base = 0;
+uint8_t mcfg_bus_start = 0;
+uint8_t mcfg_bus_end = 0xff;
+
+/*
* These function pointers lead to the actual implementation routines
* for configuration space access. Normally they lead to either the
* pci_mech1_* or pci_mech2_* routines, but they can also lead to
* routines that work around chipset bugs.
+ * These functions are accessing pci config space via I/O way.
+ * Pci_cfgacc_get/put functions shoul be used as more common interfaces,
+ * which also provide accessing pci config space via mem-mapped way.
*/
uint8_t (*pci_getb_func)(int bus, int dev, int func, int reg);
uint16_t (*pci_getw_func)(int bus, int dev, int func, int reg);
@@ -66,6 +79,8 @@ void (*pci_putb_func)(int bus, int dev, int func, int reg, uint8_t val);
void (*pci_putw_func)(int bus, int dev, int func, int reg, uint16_t val);
void (*pci_putl_func)(int bus, int dev, int func, int reg, uint32_t val);
+extern void (*pci_cfgacc_acc_p)(pci_cfgacc_req_t *req);
+
/*
* Internal routines
*/
@@ -96,13 +111,14 @@ pci_cfgspace_init(void)
}
/*
- * This code determines if this system supports PCI and which
+ * This code determines if this system supports PCI/PCIE and which
* type of configuration access method is used
*/
-
static int
pci_check(void)
{
+ uint64_t ecfginfo[4];
+
/*
* Only do this once. NB: If this is not a PCI system, and we
* get called twice, we can't detect it and will probably die
@@ -135,8 +151,6 @@ pci_check(void)
*/
pci_bios_maxbus = pci_max_nbus;
}
-
- return (TRUE);
#else /* !__xpv */
pci_bios_cfg_type = pci_check_bios();
@@ -192,9 +206,24 @@ pci_check(void)
default:
return (FALSE);
}
+#endif /* __xpv */
+
+ /*
+ * Try to get a valid mcfg_mem_base in early boot
+ * If failed, leave mem-mapped pci config space accessing disabled
+ * until pci boot code (pci_autoconfig) makes sure this is a PCIE
+ * platform.
+ */
+ if (do_bsys_getprop(NULL, MCFG_PROPNAME, ecfginfo) != -1) {
+ mcfg_mem_base = ecfginfo[0];
+ mcfg_bus_start = ecfginfo[2];
+ mcfg_bus_end = ecfginfo[3];
+ }
+
+ /* See pci_cfgacc.c */
+ pci_cfgacc_acc_p = pci_cfgacc_acc;
return (TRUE);
-#endif /* __xpv */
}
#if !defined(__xpv)
diff --git a/usr/src/uts/i86pc/sys/pci_cfgacc_x86.h b/usr/src/uts/i86pc/sys/pci_cfgacc_x86.h
new file mode 100644
index 0000000000..74adccb3bc
--- /dev/null
+++ b/usr/src/uts/i86pc/sys/pci_cfgacc_x86.h
@@ -0,0 +1,82 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_PCI_CFGACC_X86_H
+#define _SYS_PCI_CFGACC_X86_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* AMD's northbridges vendor-id and device-ids */
+#define AMD_NTBRDIGE_VID 0x1022 /* AMD vendor-id */
+#define AMD_HT_NTBRIDGE_DID 0x1100 /* HT Configuration */
+#define AMD_AM_NTBRIDGE_DID 0x1101 /* Address Map */
+#define AMD_DC_NTBRIDGE_DID 0x1102 /* DRAM Controller */
+#define AMD_MC_NTBRIDGE_DID 0x1103 /* Misc Controller */
+#define AMD_K10_NTBRIDGE_DID_0 0x1200
+#define AMD_K10_NTBRIDGE_DID_1 0x1201
+#define AMD_K10_NTBRIDGE_DID_2 0x1202
+#define AMD_K10_NTBRIDGE_DID_3 0x1203
+#define AMD_K10_NTBRIDGE_DID_4 0x1204
+
+/* AMD's 8132 chipset vendor-id and device-ids */
+#define AMD_8132_BRIDGE_DID 0x7458 /* 8132 PCI-X bridge */
+#define AMD_8132_IOAPIC_DID 0x7459 /* 8132 IO APIC */
+
+/*
+ * Check if the given device is an AMD northbridge
+ */
+#define IS_BAD_AMD_NTBRIDGE(vid, did) \
+ (((vid) == AMD_NTBRDIGE_VID) && \
+ (((did) == AMD_HT_NTBRIDGE_DID) || \
+ ((did) == AMD_AM_NTBRIDGE_DID) || \
+ ((did) == AMD_DC_NTBRIDGE_DID) || \
+ ((did) == AMD_MC_NTBRIDGE_DID)))
+
+#define IS_K10_AMD_NTBRIDGE(vid, did) \
+ (((vid) == AMD_NTBRDIGE_VID) && \
+ (((did) == AMD_K10_NTBRIDGE_DID_0) || \
+ ((did) == AMD_K10_NTBRIDGE_DID_1) || \
+ ((did) == AMD_K10_NTBRIDGE_DID_2) || \
+ ((did) == AMD_K10_NTBRIDGE_DID_3) || \
+ ((did) == AMD_K10_NTBRIDGE_DID_4)))
+
+#define IS_AMD_8132_CHIP(vid, did) \
+ (((vid) == AMD_NTBRDIGE_VID) && \
+ (((did) == AMD_8132_BRIDGE_DID)) || \
+ (((did) == AMD_8132_IOAPIC_DID)))
+
+#define MSR_AMD_NB_MMIO_CFG_BADDR 0xc0010058
+#define AMD_MMIO_CFG_BADDR_ADDR_MASK 0xFFFFFFF00000ULL
+#define AMD_MMIO_CFG_BADDR_ENA_MASK 0x000000000001ULL
+#define AMD_MMIO_CFG_BADDR_ENA_ON 0x000000000001ULL
+#define AMD_MMIO_CFG_BADDR_ENA_OFF 0x000000000000ULL
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_PCI_CFGACC_X86_H */
diff --git a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
index 6b7b88b0ac..34680632f8 100644
--- a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
+++ b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_PCI_CFGSPACE_IMPL_H
#define _SYS_PCI_CFGSPACE_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Routines to support particular PCI chipsets
*/
@@ -98,10 +96,13 @@ extern void pci_orion_putl(int bus, int dev, int func, int reg, uint32_t val);
#define PCI_MECH1_SPEC_CYCLE_DEV 0x1f /* dev to request spec cyc */
#define PCI_MECH1_SPEC_CYCLE_FUNC 0x07 /* func to request spec cyc */
+extern uint64_t mcfg_mem_base;
+extern uint8_t mcfg_bus_start;
+extern uint8_t mcfg_bus_end;
+
/*
* Mutex for all pci config space routines to share
*/
-
extern kmutex_t pcicfg_mutex;
/*
@@ -131,6 +132,8 @@ extern kmutex_t pcicfg_chipset_mutex;
#define N_PCI_IRQ_ROUTES 32
#define N_PCI_IRQ_ROUTES_MAX 255
+#define MCFG_PROPNAME "ecfg"
+
#define FP_OFF(fp) (((uintptr_t)(fp)) & 0xFFFF)
#define FP_SEG(fp) ((((uintptr_t)(fp)) >> 16) & 0xFFFF)
diff --git a/usr/src/uts/i86xpv/Makefile.files b/usr/src/uts/i86xpv/Makefile.files
index e8828cbc4a..e9501d7684 100644
--- a/usr/src/uts/i86xpv/Makefile.files
+++ b/usr/src/uts/i86xpv/Makefile.files
@@ -85,6 +85,8 @@ CORE_OBJS += \
memscrub.o \
notes.o \
pci_bios.o \
+ pci_cfgacc.o \
+ pci_cfgacc_x86.o \
pci_cfgspace.o \
pci_mech1.o \
pci_mech2.o \
diff --git a/usr/src/uts/i86xpv/Makefile.rules b/usr/src/uts/i86xpv/Makefile.rules
index 744450684d..a93bd026c3 100644
--- a/usr/src/uts/i86xpv/Makefile.rules
+++ b/usr/src/uts/i86xpv/Makefile.rules
@@ -106,6 +106,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/xsvc/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/pciex/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
# We need this one to make sure we share dtrace_subr.c with i86pc
# Otherwise we pick up common/os/dtrace_subr.c instead :(
# Note that only the non-commented versions of this hack end up
@@ -243,6 +247,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/gfx_private/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/xsvc/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/pciex/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/xen/io/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c b/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c
index 790b2e727e..78949ebca1 100644
--- a/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c
+++ b/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c
@@ -41,6 +41,8 @@
#include <sys/sunndi.h>
#include <sys/hotplug/pci/pcicfg.h>
#include <sys/ndi_impldefs.h>
+#include <sys/pci_cfgacc.h>
+#include <sys/pcie_impl.h>
/*
* ************************************************************************
@@ -219,7 +221,7 @@ static void debug(char *, uintptr_t, uintptr_t,
static int pcicfg_add_config_reg(dev_info_t *,
uint_t, uint_t, uint_t);
static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
- uint_t *, pcicfg_flags_t);
+ uint_t *, pcicfg_flags_t, boolean_t);
static int pcicfg_match_dev(dev_info_t *, void *);
static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
@@ -238,7 +240,7 @@ static void pcicfg_device_off(ddi_acc_handle_t);
static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
static int pcicfg_free_bridge_resources(dev_info_t *);
static int pcicfg_free_device_resources(dev_info_t *);
-static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t);
+static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
static void pcicfg_config_teardown(ddi_acc_handle_t *);
@@ -266,8 +268,9 @@ static int pcicfg_pcie_dev(dev_info_t *, ddi_acc_handle_t);
static int pcicfg_pcie_device_type(dev_info_t *, ddi_acc_handle_t);
static int pcicfg_pcie_port_type(dev_info_t *, ddi_acc_handle_t);
static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
- uint_t *);
+ uint_t *, boolean_t);
static int pcicfg_find_resource_end(dev_info_t *, void *);
+static boolean_t is_pcie_fabric(dev_info_t *);
static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
@@ -560,6 +563,7 @@ pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
int max_function = PCI_MAX_FUNCTIONS;
int trans_device;
dev_info_t *new_device;
+ boolean_t is_pcie;
if (flags == PCICFG_FLAG_ENABLE_ARI)
return (pcicfg_ari_configure(devi));
@@ -579,6 +583,8 @@ pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
attach_point = devi;
+ is_pcie = is_pcie_fabric(devi);
+
ndi_devi_enter(devi, &circ);
for (func = 0; func < max_function; ) {
@@ -591,7 +597,8 @@ pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
trans_device = device;
switch (rv = pcicfg_probe_children(attach_point,
- bus, trans_device, func & 7, &highest_bus, flags)) {
+ bus, trans_device, func & 7, &highest_bus,
+ flags, is_pcie)) {
case PCICFG_NORESRC:
case PCICFG_FAILURE:
DEBUG2("configure failed: bus [0x%x] device "
@@ -725,6 +732,15 @@ cleanup:
* probe handle - if not, no harm in calling this.
*/
(void) pcicfg_destroy_phdl(new_device);
+ if (is_pcie) {
+ /*
+ * free pcie_bus_t for the sub-tree
+ */
+ if (ddi_get_child(new_device) != NULL)
+ pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
+
+ pcie_fini_bus(new_device, PCIE_BUS_ALL);
+ }
/*
* This will free up the node
*/
@@ -1433,6 +1449,8 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
int func;
int i;
int max_function, trans_device;
+ int circ;
+ boolean_t is_pcie;
if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
max_function = PCICFG_MAX_ARI_FUNCTION;
@@ -1443,6 +1461,9 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
* Cycle through devices to make sure none are busy.
* If a single device is busy fail the whole unconfigure.
*/
+ is_pcie = is_pcie_fabric(devi);
+
+ ndi_devi_enter(devi, &circ);
for (func = 0; func < max_function; func++) {
if ((function != PCICFG_ALL_FUNC) && (function != func))
continue;
@@ -1489,10 +1510,10 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
if (ndi_devi_online(child_dip, NDI_CONFIG)
!= NDI_SUCCESS) {
DEBUG0("Failed to put back devices state\n");
- return (PCICFG_FAILURE);
+ goto fail;
}
}
- return (PCICFG_FAILURE);
+ goto fail;
}
/*
@@ -1521,14 +1542,14 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
PCICFG_SUCCESS) {
cmn_err(CE_WARN,
"ntbridge: unconfigure failed\n");
- return (PCICFG_FAILURE);
+ goto fail;
}
- if (pcicfg_teardown_device(child_dip, flags)
+ if (pcicfg_teardown_device(child_dip, flags, is_pcie)
!= PCICFG_SUCCESS) {
DEBUG2("Failed to tear down device [0x%x]"
"function [0x%x]\n", trans_device, func & 7);
- return (PCICFG_FAILURE);
+ goto fail;
}
}
@@ -1537,11 +1558,16 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
(void) pcie_ari_disable(devi);
}
+ ndi_devi_exit(devi, circ);
return (PCICFG_SUCCESS);
+
+fail:
+ ndi_devi_exit(devi, circ);
+ return (PCICFG_FAILURE);
}
static int
-pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags)
+pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
{
ddi_acc_handle_t handle;
@@ -1561,6 +1587,16 @@ pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags)
pcicfg_device_off(handle);
pcicfg_config_teardown(&handle);
+ if (is_pcie) {
+ /*
+ * free pcie_bus_t for the sub-tree
+ */
+ if (ddi_get_child(dip) != NULL)
+ pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
+
+ pcie_fini_bus(dip, PCIE_BUS_ALL);
+ }
+
/*
* The framework provides this routine which can
* tear down a sub-tree.
@@ -3622,7 +3658,7 @@ pcicfg_update_bridge(pcicfg_phdl_t *entry,
static int
pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
- uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
+ uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
{
dev_info_t *new_child;
ddi_acc_handle_t config_handle;
@@ -3655,6 +3691,10 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
goto failedconfig;
}
+ if (is_pcie)
+ (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
+ PCIE_BUS_INITIAL);
+
/*
* As soon as we have access to config space,
* turn off device. It will get turned on
@@ -3692,9 +3732,8 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
*/
if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
- (void) pcicfg_config_teardown(&config_handle);
- (void) ndi_devi_free(new_child);
- return (PCICFG_NODEVICE);
+ ret = PCICFG_NODEVICE;
+ goto failedchild;
}
/*
@@ -3712,7 +3751,7 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
goto failedchild;
ret = pcicfg_probe_bridge(new_child, config_handle, bus,
- highest_bus);
+ highest_bus, is_pcie);
if (ret != PCICFG_SUCCESS) {
(void) pcicfg_free_bridge_resources(new_child);
goto failedchild;
@@ -3765,6 +3804,13 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
(void) pcicfg_config_teardown(&config_handle);
+ /*
+ * Properties have been setted up, so initialize the remaining
+ * bus_t fields
+ */
+ if (is_pcie)
+ pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
+
return (PCICFG_SUCCESS);
failedchild:
@@ -3773,6 +3819,9 @@ failedchild:
*/
(void) pcicfg_config_teardown(&config_handle);
+ if (is_pcie)
+ pcie_fini_bus(new_child, PCIE_BUS_FINAL);
+
failedconfig:
(void) ndi_devi_free(new_child);
@@ -3972,7 +4021,7 @@ failedchild:
static int
pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
- uint_t *highest_bus)
+ uint_t *highest_bus, boolean_t is_pcie)
{
uint64_t next_bus;
uint_t new_bus, num_slots;
@@ -4415,6 +4464,8 @@ pf_setup_end:
(void) pcicfg_device_on(h);
+ if (is_pcie)
+ pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
!= NDI_SUCCESS) {
DEBUG0("Unable to online bridge\n");
@@ -4445,8 +4496,8 @@ pf_setup_end:
trans_device = i;
if ((rval = pcicfg_probe_children(new_child,
- new_bus, trans_device, j & 7, highest_bus, 0))
- != PCICFG_SUCCESS) {
+ new_bus, trans_device, j & 7, highest_bus,
+ 0, is_pcie)) != PCICFG_SUCCESS) {
if (rval == PCICFG_NODEVICE) {
DEBUG3("No Device at bus [0x%x]"
"device [0x%x] "
@@ -4526,6 +4577,8 @@ next:
*/
VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
== NDI_SUCCESS);
+ if (is_pcie)
+ pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
phdl.dip = new_child;
phdl.memory_base = mem_answer;
@@ -5123,3 +5176,33 @@ pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
return (port_type);
}
+
+/*
+ * Return true if the devinfo node is in a PCI Express hierarchy.
+ */
+static boolean_t
+is_pcie_fabric(dev_info_t *dip)
+{
+ dev_info_t *root = ddi_root_node();
+ dev_info_t *pdip;
+ boolean_t found = B_FALSE;
+ char *bus;
+
+ /*
+ * Does this device reside in a pcie fabric ?
+ */
+ for (pdip = dip; pdip && (pdip != root) && !found;
+ pdip = ddi_get_parent(pdip)) {
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+ DDI_PROP_DONTPASS, "device_type", &bus) !=
+ DDI_PROP_SUCCESS)
+ break;
+
+ if (strcmp(bus, "pciex") == 0)
+ found = B_TRUE;
+
+ ddi_prop_free(bus);
+ }
+
+ return (found);
+}
diff --git a/usr/src/uts/intel/io/pci/pci_boot.c b/usr/src/uts/intel/io/pci/pci_boot.c
index 3a3f468f71..a50d147f25 100644
--- a/usr/src/uts/intel/io/pci/pci_boot.c
+++ b/usr/src/uts/intel/io/pci/pci_boot.c
@@ -29,10 +29,11 @@
#include <sys/sunndi.h>
#include <sys/pci.h>
#include <sys/pci_impl.h>
-#include <sys/pci_cfgspace.h>
+#include <sys/pcie_impl.h>
#include <sys/memlist.h>
#include <sys/bootconf.h>
#include <io/pci/mps_table.h>
+#include <sys/pci_cfgacc.h>
#include <sys/pci_cfgspace.h>
#include <sys/pci_cfgspace_impl.h>
#include <sys/psw.h>
@@ -45,6 +46,7 @@
#include <sys/intel_iommu.h>
#include <sys/iommulib.h>
#include <sys/devcache.h>
+#include <sys/pci_cfgacc_x86.h>
#define pci_getb (*pci_getb_func)
#define pci_getw (*pci_getw_func)
@@ -107,6 +109,9 @@ extern struct memlist *find_bus_res(int, int);
static struct pci_fixundo *undolist = NULL;
static int num_root_bus = 0; /* count of root buses */
extern volatile int acpi_resource_discovery;
+extern uint64_t mcfg_mem_base;
+extern void pci_cfgacc_add_workaround(uint16_t, uchar_t, uchar_t);
+extern dev_info_t *pcie_get_rc_dip(dev_info_t *);
/*
* Module prototypes
@@ -134,6 +139,8 @@ static void pciex_slot_names_prop(dev_info_t *, ushort_t);
static void populate_bus_res(uchar_t bus);
static void memlist_remove_list(struct memlist **list,
struct memlist *remove_list);
+static boolean_t is_pcie_platform(void);
+static void ck804_fix_aer_ptr(dev_info_t *, pcie_req_id_t);
static void pci_scan_bbn(void);
static int pci_unitaddr_cache_valid(void);
@@ -453,6 +460,13 @@ pci_setup_tree(void)
{
uint_t i, root_bus_addr = 0;
+ /*
+ * enable mem-mapped pci config space accessing,
+ * if failed to do so during early boot
+ */
+ if ((mcfg_mem_base == NULL) && is_pcie_platform())
+ mcfg_mem_base = 0xE0000000;
+
alloc_res_array();
for (i = 0; i <= pci_bios_maxbus; i++) {
pci_bus_res[i].par_bus = (uchar_t)-1;
@@ -1864,6 +1878,7 @@ process_devfunc(uchar_t bus, uchar_t dev, uchar_t func, uchar_t header,
ushort_t is_pci_bridge = 0;
struct pci_devfunc *devlist = NULL, *entry = NULL;
gfx_entry_t *gfxp;
+ pcie_req_id_t bdf;
ushort_t deviceid = pci_getw(bus, dev, func, PCI_CONF_DEVID);
@@ -1925,6 +1940,28 @@ process_devfunc(uchar_t bus, uchar_t dev, uchar_t func, uchar_t header,
&is_pci_bridge) == B_TRUE)
pciex = 1;
+ bdf = PCI_GETBDF(bus, dev, func);
+ /*
+ * Record BAD AMD bridges which don't support MMIO config access.
+ */
+ if (IS_BAD_AMD_NTBRIDGE(vendorid, deviceid) ||
+ IS_AMD_8132_CHIP(vendorid, deviceid)) {
+ uchar_t secbus = 0;
+ uchar_t subbus = 0;
+
+ if ((basecl == PCI_CLASS_BRIDGE) &&
+ (subcl == PCI_BRIDGE_PCI)) {
+ secbus = pci_getb(bus, dev, func, PCI_BCNF_SECBUS);
+ subbus = pci_getb(bus, dev, func, PCI_BCNF_SUBBUS);
+ }
+ pci_cfgacc_add_workaround(bdf, secbus, subbus);
+ }
+
+ if (mcfg_mem_base != NULL) {
+ ck804_fix_aer_ptr(dip, bdf);
+ (void) pcie_init_bus(dip, bdf, PCIE_BUS_INITIAL);
+ }
+
/* add properties */
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id", deviceid);
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id", vendorid);
@@ -3289,3 +3326,51 @@ pciex_slot_names_prop(dev_info_t *dip, ushort_t slot_num)
(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "slot-names",
(int *)slotprop, len / sizeof (int));
}
+
+/*
+ * This is currently a hack, a better way is needed to determine if it
+ * is a PCIE platform.
+ */
+static boolean_t
+is_pcie_platform()
+{
+ uint8_t bus;
+
+ for (bus = 0; bus < pci_bios_maxbus; bus++) {
+ if (look_for_any_pciex_device(bus))
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Enable reporting of AER capability next pointer.
+ * This needs to be done only for CK8-04 devices
+ * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
+ * NOTE: BIOS is disabling this, it needs to be enabled temporarily
+ *
+ * This function is adapted from npe_ck804_fix_aer_ptr(), and is
+ * called from pci_boot.c.
+ */
+static void
+ck804_fix_aer_ptr(dev_info_t *dip, pcie_req_id_t bdf)
+{
+ dev_info_t *rcdip;
+ ushort_t cya1;
+
+ rcdip = pcie_get_rc_dip(dip);
+ ASSERT(rcdip != NULL);
+
+ if ((pci_cfgacc_get16(rcdip, bdf, PCI_CONF_VENID) ==
+ NVIDIA_VENDOR_ID) &&
+ (pci_cfgacc_get16(rcdip, bdf, PCI_CONF_DEVID) ==
+ NVIDIA_CK804_DEVICE_ID) &&
+ (pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID) >=
+ NVIDIA_CK804_AER_VALID_REVID)) {
+ cya1 = pci_cfgacc_get16(rcdip, bdf, NVIDIA_CK804_VEND_CYA1_OFF);
+ if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
+ (void) pci_cfgacc_put16(rcdip, bdf,
+ NVIDIA_CK804_VEND_CYA1_OFF,
+ cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
+ }
+}
diff --git a/usr/src/uts/intel/io/pci/pci_pci.c b/usr/src/uts/intel/io/pci/pci_pci.c
index ffeab4628e..0f919da964 100644
--- a/usr/src/uts/intel/io/pci/pci_pci.c
+++ b/usr/src/uts/intel/io/pci/pci_pci.c
@@ -684,7 +684,7 @@ ppb_initchild(dev_info_t *child)
* errors.
*/
if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
- if (pcie_init_bus(child) == NULL)
+ if (pcie_init_cfghdl(child) != DDI_SUCCESS)
return (DDI_FAILURE);
}
@@ -726,7 +726,7 @@ ppb_removechild(dev_info_t *dip)
ddi_get_instance(ddi_get_parent(dip)));
if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
- pcie_fini_bus(dip);
+ pcie_fini_cfghdl(dip);
else if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
ddi_set_parent_data(dip, NULL);
diff --git a/usr/src/uts/intel/io/pciex/pcie_nvidia.c b/usr/src/uts/intel/io/pciex/pcie_nvidia.c
index b419d2dd81..7bc62d4478 100644
--- a/usr/src/uts/intel/io/pciex/pcie_nvidia.c
+++ b/usr/src/uts/intel/io/pciex/pcie_nvidia.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,17 +32,19 @@
#include <sys/pci.h>
#include <sys/sunndi.h>
#include <sys/pcie.h>
+#include <sys/pcie_impl.h>
#include <sys/pci_cfgspace.h>
#include <io/pciex/pcie_nvidia.h>
/*
* PCI Configuration (Nvidia chipsets, PCIe) related library functions
*/
-static boolean_t look_for_any_pciex_device(uchar_t);
/* Globals */
extern int pci_boot_debug;
+extern uint64_t mcfg_mem_base;
+
boolean_t
check_if_device_is_pciex(dev_info_t *cdip, uchar_t bus, uchar_t dev,
uchar_t func, ushort_t *slot_number, ushort_t *is_pci_bridge)
@@ -125,7 +127,7 @@ check_if_device_is_pciex(dev_info_t *cdip, uchar_t bus, uchar_t dev,
* PCI-Express device in the system.
* If found, return B_TRUE else B_FALSE
*/
-static boolean_t
+boolean_t
look_for_any_pciex_device(uchar_t bus)
{
uchar_t dev, func;
@@ -170,10 +172,11 @@ look_for_any_pciex_device(uchar_t bus)
return (B_FALSE);
}
-
boolean_t
create_pcie_root_bus(uchar_t bus, dev_info_t *dip)
{
+ pcie_bus_t *bus_p;
+
/*
* Currently this is being hard-coded.
* We need to figure out if the root bus does indeed
@@ -192,6 +195,12 @@ create_pcie_root_bus(uchar_t bus, dev_info_t *dip)
(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
"compatible", "pciex_root_complex");
+ pcie_rc_init_bus(dip);
+
+ /* save base addr in bus_t for pci_cfgacc_xxx() */
+ bus_p = PCIE_DIP2BUS(dip);
+ bus_p->bus_cfgacc_base = mcfg_mem_base;
+
return (B_TRUE);
}
diff --git a/usr/src/uts/intel/io/pciex/pcie_nvidia.h b/usr/src/uts/intel/io/pciex/pcie_nvidia.h
index b3550a878f..2b01966385 100644
--- a/usr/src/uts/intel/io/pciex/pcie_nvidia.h
+++ b/usr/src/uts/intel/io/pciex/pcie_nvidia.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _PCIEX_PCI_NVIDIA_H
#define _PCIEX_PCI_NVIDIA_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -36,6 +34,7 @@ extern "C" {
/*
* PCI Configuration (Nvidia, PCIe) related library functions
*/
+boolean_t look_for_any_pciex_device(uchar_t);
boolean_t check_if_device_is_pciex(dev_info_t *, uchar_t, uchar_t,
uchar_t, ushort_t *, ushort_t *);
boolean_t create_pcie_root_bus(uchar_t, dev_info_t *);
diff --git a/usr/src/uts/intel/pci_autoconfig/Makefile b/usr/src/uts/intel/pci_autoconfig/Makefile
index 7d2c5e1756..c4d91376bd 100644
--- a/usr/src/uts/intel/pci_autoconfig/Makefile
+++ b/usr/src/uts/intel/pci_autoconfig/Makefile
@@ -56,7 +56,7 @@ LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
-# Depends on acpica ACPI CA interpreter
+# Depends on acpica ACPI CA interpreter and PCI-E framework
#
LDFLAGS += -dy -Nmisc/acpica -Nmisc/pcie
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 537bcfdd03..2fc5aa52e4 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -287,7 +287,7 @@ DRV_KMODS += wusb_df hwahc hwarc wusb_ca
DRV_KMODS += hci1394 av1394 scsa1394 dcam1394
DRV_KMODS += sbp2
DRV_KMODS += ib ibd rdsib sdp iser daplt hermon tavor
-DRV_KMODS += pci_pci pcieb pcieb_bcm pcie
+DRV_KMODS += pci_pci pcieb pcieb_bcm
DRV_KMODS += i8042 kb8042 mouse8042
DRV_KMODS += fcode
DRV_KMODS += mpt_sas
diff --git a/usr/src/uts/sun4/io/pcicfg.c b/usr/src/uts/sun4/io/pcicfg.c
index 3ce92e0d27..1701be2c59 100644
--- a/usr/src/uts/sun4/io/pcicfg.c
+++ b/usr/src/uts/sun4/io/pcicfg.c
@@ -46,6 +46,7 @@
#include <sys/pci_cap.h>
#include <sys/hotplug/pci/pcicfg.h>
#include <sys/ndi_impldefs.h>
+#include <sys/pci_cfgacc.h>
#define PCICFG_DEVICE_TYPE_PCI 1
#define PCICFG_DEVICE_TYPE_PCIE 2
@@ -263,7 +264,7 @@ int pcicfg_dont_interpret = 1;
static int pcicfg_add_config_reg(dev_info_t *,
uint_t, uint_t, uint_t);
static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
- uint_t *, pcicfg_flags_t);
+ uint_t *, pcicfg_flags_t, boolean_t);
#ifdef PCICFG_INTERPRET_FCODE
static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
@@ -271,9 +272,9 @@ static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
#endif
static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t,
- uint_t *, pcicfg_flags_t);
+ uint_t *, pcicfg_flags_t, boolean_t);
static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
- uint_t *);
+ uint_t *, boolean_t);
static int pcicfg_free_all_resources(dev_info_t *);
static int pcicfg_alloc_new_resources(dev_info_t *);
static int pcicfg_match_dev(dev_info_t *, void *);
@@ -302,7 +303,7 @@ static void pcicfg_device_off(ddi_acc_handle_t);
static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int);
static int pcicfg_free_bridge_resources(dev_info_t *);
static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t);
-static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t);
+static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
static void pcicfg_config_teardown(ddi_acc_handle_t *);
static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
@@ -329,6 +330,7 @@ static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
uint32_t, uint32_t, uint_t);
+static boolean_t is_pcie_fabric(dev_info_t *dip);
#ifdef DEBUG
static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
@@ -721,6 +723,7 @@ pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
uint_t highest_bus = 0;
int ari_mode = B_FALSE;
int max_function = PCICFG_MAX_FUNCTION;
+ boolean_t is_pcie;
if (flags == PCICFG_FLAG_ENABLE_ARI)
return (pcicfg_ari_configure(devi));
@@ -738,6 +741,8 @@ pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
bus = pci_bus_range.lo; /* primary bus number of this bus node */
+ is_pcie = is_pcie_fabric(devi);
+
ndi_devi_enter(devi, &circ);
for (func = 0; func < max_function; ) {
if ((function != PCICFG_ALL_FUNC) && (function != func))
@@ -755,7 +760,7 @@ pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
* Try executing fcode if available.
*/
switch (rv = pcicfg_fcode_probe(devi, bus, trans_device,
- func & 7, &highest_bus, flags)) {
+ func & 7, &highest_bus, flags, is_pcie)) {
case PCICFG_FAILURE:
DEBUG2("configure failed: "
"bus [0x%x] device [0x%x]\n",
@@ -865,6 +870,16 @@ cleanup:
* probe handle - if not, no harm in calling this.
*/
(void) pcicfg_destroy_phdl(new_device);
+
+ if (is_pcie) {
+ /*
+ * Free bus_t structure
+ */
+ if (ddi_get_child(new_device) != NULL)
+ pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
+
+ pcie_fini_bus(new_device, PCIE_BUS_ALL);
+ }
/*
* This will free up the node
*/
@@ -1529,6 +1544,8 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
int i;
int max_function;
int trans_device;
+ int circ;
+ boolean_t is_pcie;
if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
max_function = PCICFG_MAX_ARI_FUNCTION;
@@ -1539,6 +1556,9 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
* Cycle through devices to make sure none are busy.
* If a single device is busy fail the whole unconfigure.
*/
+ is_pcie = is_pcie_fabric(devi);
+
+ ndi_devi_enter(devi, &circ);
for (func = 0; func < max_function; func++) {
if (max_function == PCICFG_MAX_ARI_FUNCTION)
@@ -1583,10 +1603,10 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
if (ndi_devi_online(child_dip, NDI_CONFIG)
!= NDI_SUCCESS) {
DEBUG0("Failed to put back devices state\n");
- return (PCICFG_FAILURE);
+ goto fail;
}
}
- return (PCICFG_FAILURE);
+ goto fail;
}
/*
@@ -1613,15 +1633,15 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
PCICFG_SUCCESS) {
cmn_err(CE_WARN,
"ntbridge: unconfigure failed\n");
- return (PCICFG_FAILURE);
+ goto fail;
}
- if (pcicfg_teardown_device(child_dip, flags)
+ if (pcicfg_teardown_device(child_dip, flags, is_pcie)
!= PCICFG_SUCCESS) {
DEBUG2("Failed to tear down device [0x%x]"
"function [0x%x]\n",
trans_device, func & 7);
- return (PCICFG_FAILURE);
+ goto fail;
}
}
@@ -1630,11 +1650,16 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
(void) pcie_ari_disable(devi);
}
+ ndi_devi_exit(devi, circ);
return (PCICFG_SUCCESS);
+
+fail:
+ ndi_devi_exit(devi, circ);
+ return (PCICFG_FAILURE);
}
static int
-pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags)
+pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
{
ddi_acc_handle_t config_handle;
@@ -1657,6 +1682,16 @@ pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags)
pci_config_teardown(&config_handle);
/*
+ * free pcie_bus_t for the sub-tree
+ */
+ if (is_pcie) {
+ if (ddi_get_child(dip) != NULL)
+ pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
+
+ pcie_fini_bus(dip, PCIE_BUS_ALL);
+ }
+
+ /*
* The framework provides this routine which can
* tear down a sub-tree.
*/
@@ -3966,7 +4001,7 @@ pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
static int
pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
- uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
+ uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
{
dev_info_t *new_child;
ddi_acc_handle_t config_handle;
@@ -4008,6 +4043,10 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
goto failedconfig;
}
+ if (is_pcie)
+ (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
+ PCIE_BUS_INITIAL);
+
/*
* As soon as we have access to config space,
* turn off device. It will get turned on
@@ -4071,7 +4110,7 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
goto failedchild;
if (pcicfg_probe_bridge(new_child, config_handle,
- bus, highest_bus) != PCICFG_SUCCESS) {
+ bus, highest_bus, is_pcie) != PCICFG_SUCCESS) {
(void) pcicfg_free_bridge_resources(new_child);
goto failedchild;
}
@@ -4125,11 +4164,21 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
}
(void) pcicfg_config_teardown(&config_handle);
+
+ /*
+ * Properties have been setted up, so initilize the rest fields
+ * in bus_t.
+ */
+ if (is_pcie)
+ pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
+
return (PCICFG_SUCCESS);
failedchild:
(void) pcicfg_config_teardown(&config_handle);
+ if (is_pcie)
+ pcie_fini_bus(new_child, PCIE_BUS_FINAL);
failedconfig:
@@ -4215,7 +4264,6 @@ pcicfg_populate_reg_props(dev_info_t *new_child,
}
}
-
return (PCICFG_SUCCESS);
failedchild:
@@ -4224,7 +4272,7 @@ failedchild:
static int
pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
- uint_t func, uint_t *highest_bus, pcicfg_flags_t flags)
+ uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
{
dev_info_t *new_child;
int8_t header_type;
@@ -4332,6 +4380,11 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
goto failed3;
}
#endif
+
+ if (is_pcie)
+ (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
+ PCIE_BUS_INITIAL);
+
DEBUG0("fcode_probe: conf space mapped.\n");
/*
* As soon as we have access to config space,
@@ -4396,7 +4449,7 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
goto failed;
if ((ret = pcicfg_probe_bridge(new_child, h,
- bus, highest_bus)) != PCICFG_SUCCESS)
+ bus, highest_bus, is_pcie)) != PCICFG_SUCCESS)
(void) pcicfg_free_bridge_resources(new_child);
goto done;
} else {
@@ -4622,12 +4675,16 @@ no_fcode:
#else
pcicfg_unmap_phys(&h, &p);
#endif
+ /* destroy the bus_t before the dev node is gone */
+ if (is_pcie)
+ pcie_fini_bus(new_child, PCIE_BUS_FINAL);
+
(void) ndi_devi_free(new_child);
DEBUG0("No Drop-in Probe device ourself\n");
ret = pcicfg_probe_children(parent, bus, device, func,
- highest_bus, flags);
+ highest_bus, flags, is_pcie);
if (ret != PCICFG_SUCCESS) {
DEBUG0("Could not self probe child\n");
@@ -4680,7 +4737,8 @@ no_fcode:
* warnings on retries of the failed configure.
*/
(void) pcicfg_ntbridge_unconfigure(new_child);
- (void) pcicfg_teardown_device(new_child, flags);
+ (void) pcicfg_teardown_device(new_child,
+ flags, is_pcie);
}
#endif
goto done2;
@@ -4688,6 +4746,13 @@ no_fcode:
}
done:
failed:
+ if (is_pcie) {
+ if (ret == PCICFG_SUCCESS)
+ pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
+ else
+ pcie_fini_bus(new_child, PCIE_BUS_FINAL);
+ }
+
#ifdef EFCODE21554
pcicfg_config_teardown(&h);
#else
@@ -4705,6 +4770,7 @@ failed2:
}
pci_config_teardown(&ph);
}
+
return (ret);
}
@@ -4821,7 +4887,7 @@ failedchild:
static int
pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
- uint_t *highest_bus)
+ uint_t *highest_bus, boolean_t is_pcie)
{
uint64_t next_bus;
uint_t new_bus, num_slots;
@@ -5154,6 +5220,8 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
(void) pcicfg_device_on(h);
+ if (is_pcie)
+ pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
!= NDI_SUCCESS) {
DEBUG0("Unable to online bridge\n");
@@ -5183,7 +5251,8 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
trans_device = i;
if ((rval = pcicfg_fcode_probe(new_child,
- new_bus, trans_device, (j & 7), highest_bus, 0))
+ new_bus, trans_device, (j & 7), highest_bus,
+ 0, is_pcie))
!= PCICFG_SUCCESS) {
if (rval == PCICFG_NODEVICE) {
DEBUG3("No Device at bus [0x%x]"
@@ -5268,6 +5337,8 @@ next:
*/
VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
== NDI_SUCCESS);
+ if (is_pcie)
+ pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
phdl.dip = new_child;
phdl.memory_base = mem_answer;
@@ -6753,3 +6824,33 @@ debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
}
#endif
+
+/*
+ * Return true if the devinfo node is in a PCI Express hierarchy.
+ */
+static boolean_t
+is_pcie_fabric(dev_info_t *dip)
+{
+ dev_info_t *root = ddi_root_node();
+ dev_info_t *pdip;
+ boolean_t found = B_FALSE;
+ char *bus;
+
+ /*
+ * Does this device reside in a pcie fabric ?
+ */
+ for (pdip = dip; pdip && (pdip != root) && !found;
+ pdip = ddi_get_parent(pdip)) {
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+ DDI_PROP_DONTPASS, "device_type", &bus) !=
+ DDI_PROP_SUCCESS)
+ break;
+
+ if (strcmp(bus, "pciex") == 0)
+ found = B_TRUE;
+
+ ddi_prop_free(bus);
+ }
+
+ return (found);
+}
diff --git a/usr/src/uts/sun4/io/px/px.c b/usr/src/uts/sun4/io/px/px.c
index e436063b1b..614dda5bcd 100644
--- a/usr/src/uts/sun4/io/px/px.c
+++ b/usr/src/uts/sun4/io/px/px.c
@@ -42,6 +42,7 @@
#include <sys/pci_tools.h>
#include "px_tools_ext.h"
#include <sys/pcie_pwr.h>
+#include <sys/pci_cfgacc.h>
/*LINTLIBRARY*/
@@ -56,11 +57,11 @@ static int px_cb_attach(px_t *);
static void px_cb_detach(px_t *);
static int px_pwr_setup(dev_info_t *dip);
static void px_pwr_teardown(dev_info_t *dip);
-
static void px_set_mps(px_t *px_p);
+extern void pci_cfgacc_acc(pci_cfgacc_req_t *);
extern int pcie_max_mps;
-
+extern void (*pci_cfgacc_acc_p)(pci_cfgacc_req_t *);
/*
* bus ops and dev ops structures:
*/
@@ -224,11 +225,15 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
int ret = DDI_SUCCESS;
devhandle_t dev_hdl = NULL;
pcie_hp_regops_t regops;
+ pcie_bus_t *bus_p;
switch (cmd) {
case DDI_ATTACH:
DBG(DBG_ATTACH, dip, "DDI_ATTACH\n");
+ /* See pci_cfgacc.c */
+ pci_cfgacc_acc_p = pci_cfgacc_acc;
+
/*
* Allocate and get the per-px soft state structure.
*/
@@ -341,6 +346,25 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
ddi_report_dev(dip);
px_p->px_state = PX_ATTACHED;
+
+ /*
+ * save base addr in bus_t for pci_cfgacc_xxx(), this
+ * depends of px structure being properly initialized.
+ */
+ bus_p = PCIE_DIP2BUS(dip);
+ bus_p->bus_cfgacc_base = px_lib_get_cfgacc_base(dip);
+
+ /*
+ * Partially populate bus_t for all devices in this fabric
+ * for device type macros to work.
+ */
+ /*
+ * Populate bus_t for all devices in this fabric, after FMA
+ * is initializated, so that config access errors could
+ * trigger panic.
+ */
+ pcie_fab_init_bus(dip, PCIE_BUS_ALL);
+
DBG(DBG_ATTACH, dip, "attach success\n");
break;
@@ -449,6 +473,9 @@ px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
return (DDI_FAILURE);
}
+ /* Destroy bus_t for the whole fabric */
+ pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
+
/*
* things which used to be done in obj_destroy
* are now in-lined here.
diff --git a/usr/src/uts/sun4/io/px/px_ioapi.h b/usr/src/uts/sun4/io/px/px_ioapi.h
index 1d5c123185..2a9bdbb49e 100644
--- a/usr/src/uts/sun4/io/px/px_ioapi.h
+++ b/usr/src/uts/sun4/io/px/px_ioapi.h
@@ -232,19 +232,6 @@ typedef enum io_sync_direction {
IO_SYNC_CPU = (uint32_t)0x02
} io_sync_direction_t;
-typedef enum pci_config_size {
- PCI_CFG_SIZE_BYTE = 0,
- PCI_CFG_SIZE_WORD,
- PCI_CFG_SIZE_DWORD
-} pci_config_size_t;
-
-typedef union pci_cfg_data {
- uint8_t b;
- uint16_t w;
- uint32_t dw;
- uint64_t qw;
-} pci_cfg_data_t;
-
/*
* MSI Definitions
*
diff --git a/usr/src/uts/sun4/io/px/px_lib.h b/usr/src/uts/sun4/io/px/px_lib.h
index c0c2d945db..fcef9f452c 100644
--- a/usr/src/uts/sun4/io/px/px_lib.h
+++ b/usr/src/uts/sun4/io/px/px_lib.h
@@ -190,10 +190,6 @@ extern int px_err_add_intr(px_fault_t *px_fault_p);
extern void px_err_rem_intr(px_fault_t *px_fault_p);
extern int px_cb_add_intr(px_fault_t *);
extern void px_cb_rem_intr(px_fault_t *);
-extern uint32_t px_fab_get(px_t *px_p, pcie_req_id_t bdf,
- uint16_t offset);
-extern void px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
- uint32_t val);
/*
* CPR callback
@@ -214,6 +210,11 @@ extern pcie_req_id_t px_lib_get_bdf(px_t *px_p);
extern int px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps);
extern int px_lib_set_root_complex_mps(px_t *px_p, dev_info_t *dip, int mps);
+/*
+ * Config space access
+ */
+extern uint64_t px_lib_get_cfgacc_base(dev_info_t *dip);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/sun4/io/px/px_util.c b/usr/src/uts/sun4/io/px/px_util.c
index 570dc26bd4..b5e9f1b34a 100644
--- a/usr/src/uts/sun4/io/px/px_util.c
+++ b/usr/src/uts/sun4/io/px/px_util.c
@@ -525,8 +525,7 @@ px_init_child(px_t *px_p, dev_info_t *child)
ddi_node_name(child), ddi_get_name_addr(child));
ddi_set_parent_data(child, (void *)ppd);
- if (pcie_init_bus(child))
- (void) pcie_initchild(child);
+ (void) pcie_initchild(child);
/*
* Handle chip specific init-child tasks.
diff --git a/usr/src/uts/sun4u/Makefile.files b/usr/src/uts/sun4u/Makefile.files
index b9c1204bcb..0bbe2dd930 100644
--- a/usr/src/uts/sun4u/Makefile.files
+++ b/usr/src/uts/sun4u/Makefile.files
@@ -182,6 +182,8 @@ CPR_IMPL_OBJS = cpr_impl.o
SBD_OBJS += sbd.o sbd_cpu.o sbd_mem.o sbd_io.o
+PCIE_MISC_OBJS += pci_cfgacc_4u.o pci_cfgacc.o
+
#
# Brand modules
#
diff --git a/usr/src/uts/sun4u/Makefile.rules b/usr/src/uts/sun4u/Makefile.rules
index fcddd0ecce..2e16caa648 100644
--- a/usr/src/uts/sun4u/Makefile.rules
+++ b/usr/src/uts/sun4u/Makefile.rules
@@ -92,6 +92,13 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/io/px/%.c
$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/io/px/%.s
$(COMPILE.s) -o $@ $<
+$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/io/pciex/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/io/pciex/%.s
+ $(COMPILE.s) -o $@ $<
+
$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/ml/%.s
$(COMPILE.s) -o $@ $<
@@ -212,6 +219,12 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/io/px/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/io/px/%.s
@($(LHEAD) $(LINT.s) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/io/pciex/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/io/pciex/%.s
+ @($(LHEAD) $(LINT.s) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/ml/%.s
@($(LHEAD) $(LINT.s) $< $(LTAIL))
diff --git a/usr/src/uts/sun4u/Makefile.sun4u.shared b/usr/src/uts/sun4u/Makefile.sun4u.shared
index 9da3888d2f..3544159026 100644
--- a/usr/src/uts/sun4u/Makefile.sun4u.shared
+++ b/usr/src/uts/sun4u/Makefile.sun4u.shared
@@ -434,6 +434,7 @@ MISC_KMODS += sbd
MISC_KMODS += opl_cfg
MISC_KMODS += zuluvm
MISC_KMODS += gptwo_cpu gptwocfg
+MISC_KMODS += pcie
#
# Brand modules
diff --git a/usr/src/uts/sun4u/io/pci/pci_pci.c b/usr/src/uts/sun4u/io/pci/pci_pci.c
index d2d4718fa1..7733664be3 100644
--- a/usr/src/uts/sun4u/io/pci/pci_pci.c
+++ b/usr/src/uts/sun4u/io/pci/pci_pci.c
@@ -963,7 +963,7 @@ ppb_initchild(dev_info_t *child)
* errors.
*/
if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
- if (pcie_init_bus(child) == NULL) {
+ if (pcie_init_cfghdl(child) != DDI_SUCCESS) {
pci_config_teardown(&config_handle);
return (DDI_FAILURE);
}
@@ -997,7 +997,7 @@ ppb_uninitchild(dev_info_t *child)
* SG OPL FMA specific
*/
if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
- pcie_fini_bus(child);
+ pcie_fini_cfghdl(child);
ppb_removechild(child);
}
diff --git a/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c b/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c
new file mode 100644
index 0000000000..65296bec24
--- /dev/null
+++ b/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/promif.h>
+#include <sys/pci.h>
+#include <sys/sysmacros.h>
+#include <sys/pcie_impl.h>
+#include <sys/machsystm.h>
+#include <sys/byteorder.h>
+#include <sys/pci_cfgacc.h>
+
+#define PCI_CFG_SPACE (PCI_REG_ADDR_G(PCI_ADDR_CONFIG))
+#define PCIE_CFG_SPACE_SIZE (PCI_CONF_HDR_SIZE << 4)
+
+/* RC BDF Shift in a Phyiscal Address */
+#define RC_PA_BDF_SHIFT 12
+#define RC_BDF_TO_CFGADDR(bdf, offset) (((bdf) << RC_PA_BDF_SHIFT) + (offset))
+
+static boolean_t
+pci_cfgacc_valid(pci_cfgacc_req_t *req)
+{
+ /* do not support 64 bit pci config space access */
+ return (IS_P2ALIGNED(req->offset, req->size) &&
+ (req->offset < PCIE_CFG_SPACE_SIZE) &&
+ ((req->size == 1) || (req->size == 2) ||
+ (req->size == 4) || (req->size == 8)));
+}
+
+/*
+ * Unprotected raw reads/writes of fabric device's config space.
+ */
+static uint64_t
+pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size)
+{
+ pcie_bus_t *bus_p;
+ uint64_t base_addr;
+ uint64_t val;
+
+ if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
+ return ((uint64_t)-1);
+
+ base_addr = bus_p->bus_cfgacc_base;
+ base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
+
+ switch (size) {
+ case 1:
+ val = ldbphysio(base_addr);
+ break;
+ case 2:
+ val = ldhphysio(base_addr);
+ break;
+ case 4:
+ val = ldphysio(base_addr);
+ break;
+ case 8:
+ val = lddphysio(base_addr);
+ break;
+ default:
+ return ((uint64_t)-1);
+ }
+
+ return (LE_64(val));
+}
+
+static void
+pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
+ uint64_t val)
+{
+ pcie_bus_t *bus_p;
+ uint64_t base_addr;
+
+ if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
+ return;
+
+ base_addr = bus_p->bus_cfgacc_base;
+ base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
+
+ val = LE_64(val);
+
+ switch (size) {
+ case 1:
+ stbphysio(base_addr, val);
+ break;
+ case 2:
+ sthphysio(base_addr, val);
+ break;
+ case 4:
+ stphysio(base_addr, val);
+ break;
+ case 8:
+ stdphysio(base_addr, val);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+pci_cfgacc_acc(pci_cfgacc_req_t *req)
+{
+ /* is request valid? */
+ if (!pci_cfgacc_valid(req)) {
+ if (!req->write)
+ VAL64(req) = (uint64_t)-1;
+ return;
+ }
+
+ if (req->write) {
+ pci_cfgacc_set(req->rcdip, req->bdf, req->offset,
+ req->size, VAL64(req));
+ } else {
+ VAL64(req) = pci_cfgacc_get(req->rcdip, req->bdf,
+ req->offset, req->size);
+ }
+}
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c
index 0a588ebe6e..349ed33cf8 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c
@@ -2344,45 +2344,6 @@ px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status)
#endif /* FMA */
/*
- * Unprotected raw reads/writes of fabric device's config space.
- * Only used for temporary PCI-E Fabric Error Handling.
- */
-uint32_t
-px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset)
-{
- pci_ranges_t *rp = px_p->px_ranges_p;
- uint64_t range_prop, base_addr;
- int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
- uint32_t val;
-
- /* Get Fire's Physical Base Address */
- range_prop = px_get_range_prop(px_p, rp, bank);
-
- /* Get config space first. */
- base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset);
-
- val = ldphysio(base_addr);
-
- return (LE_32(val));
-}
-
-void
-px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
- uint32_t val) {
- pci_ranges_t *rp = px_p->px_ranges_p;
- uint64_t range_prop, base_addr;
- int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
-
- /* Get Fire's Physical Base Address */
- range_prop = px_get_range_prop(px_p, rp, bank);
-
- /* Get config space first. */
- base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset);
-
- stphysio(base_addr, LE_32(val));
-}
-
-/*
* cpr callback
*
* disable fabric error msg interrupt prior to suspending
@@ -2521,6 +2482,22 @@ px_get_range_prop(px_t *px_p, pci_ranges_t *rp, int bank)
}
/*
+ * fetch the config space base addr of the root complex
+ * note this depends on px structure being initialized
+ */
+uint64_t
+px_lib_get_cfgacc_base(dev_info_t *dip)
+{
+ int instance = DIP_TO_INST(dip);
+ px_t *px_p = INST_TO_STATE(instance);
+ pci_ranges_t *rp = px_p->px_ranges_p;
+ int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
+
+ /* Get Fire's Physical Base Address */
+ return (px_get_range_prop(px_p, rp, bank));
+}
+
+/*
* add cpr callback
*/
void
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.h b/usr/src/uts/sun4u/io/px/px_lib4u.h
index 45c15ea65d..6828929cad 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.h
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.h
@@ -280,10 +280,6 @@ typedef struct eq_rec {
/* TLU Control register bits */
#define TLU_REMAIN_DETECT_QUIET 8
-/* PX BDF Shift in a Phyiscal Address - used FMA Fabric only */
-#define PX_PA_BDF_SHIFT 12
-#define PX_BDF_TO_CFGADDR(bdf, offset) (((bdf) << PX_PA_BDF_SHIFT) + (offset))
-
/*
* Fire hardware specific version definitions.
* All Fire versions > 2.0 will be numerically greater than FIRE_MOD_REV_20
diff --git a/usr/src/uts/sparc/pcie/Makefile b/usr/src/uts/sun4u/pcie/Makefile
index f65b5491e5..ba42c6770a 100644
--- a/usr/src/uts/sparc/pcie/Makefile
+++ b/usr/src/uts/sun4u/pcie/Makefile
@@ -19,13 +19,16 @@
# CDDL HEADER END
#
#
-# uts/sparc/pcie/Makefile
+# uts/sun4u/pcie/Makefile
+#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# This makefile drives the production of the PCIE driver kernel module.
#
-# sparc architecture dependent
+# This makefile drives the production of the sun4u/kernel/misc/sparcv9/pcie module
+# for PCI-E Error handling support in PCI-E nexus drivers.
+#
+# sun4u implementation architecture dependent
#
#
@@ -41,12 +44,12 @@ OBJECTS = $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%) \
$(PCI_STRING_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln) \
$(PCI_STRING_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
+ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
#
# Include common rules.
#
-include $(UTSBASE)/sparc/Makefile.sparc
+include $(UTSBASE)/sun4u/Makefile.sun4u
#
# Define targets
@@ -56,32 +59,11 @@ LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
-# lint pass one enforcement
-#
-CFLAGS += $(CCVERBOSE)
-
-#
-# Dependency
+# Dependency
#
LDFLAGS += -dy -Nmisc/busra
#
-# Overrides
-#
-MODSTUBS_DIR = $(OBJS_DIR)
-$(MODSTUBS_O) := AS_CPPFLAGS += -DPCIE_MODULE
-CLEANFILES += $(MODSTUBS_O)
-
-#
-# For now, disable these lint checks; maintainers should endeavor
-# to investigate and remove these for maximum lint coverage.
-# Please do not carry these forward to new Makefiles.
-#
-LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN
-LINTTAGS += -erroff=E_STATIC_UNUSED
-LINTTAGS += -erroff=E_SUSPICIOUS_COMPARISON
-
-#
# Default build targets.
#
.KEEP_STATE:
@@ -102,6 +84,7 @@ clean.lint: $(CLEAN_LINT_DEPS)
install: $(INSTALL_DEPS)
+#
# Include common targets.
#
-include $(UTSBASE)/sparc/Makefile.targ
+include $(UTSBASE)/sun4u/Makefile.targ
diff --git a/usr/src/uts/sun4v/Makefile.files b/usr/src/uts/sun4v/Makefile.files
index 9746292e0b..3b0a435ff0 100644
--- a/usr/src/uts/sun4v/Makefile.files
+++ b/usr/src/uts/sun4v/Makefile.files
@@ -169,6 +169,7 @@ DS_OBJS = ds_common.o ds_drv.o
FAULT_ISO_OBJS = fault_iso.o
OBPSYM_OBJS += obpsym.o obpsym_1275.o
PLATSVC_OBJS = platsvc.o mdeg.o
+PCIE_MISC_OBJS += pci_cfgacc_4v.o pci_cfgacc_asm.o pci_cfgacc.o
#
# Brand modules
diff --git a/usr/src/uts/sun4v/Makefile.rules b/usr/src/uts/sun4v/Makefile.rules
index 3a4952e961..d20d930e9d 100644
--- a/usr/src/uts/sun4v/Makefile.rules
+++ b/usr/src/uts/sun4v/Makefile.rules
@@ -98,6 +98,13 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/glvc/%.c
$(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/glvc/%.s
$(COMPILE.s) -o $@ $<
+$(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/pciex/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/io/pciex/%.s
+ $(COMPILE.s) -o $@ $<
+
$(OBJS_DIR)/%.o: $(UTSBASE)/sun4v/vm/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -202,6 +209,12 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/n2rng/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/n2rng/%.s
@($(LHEAD) $(LINT.s) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/pciex/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/io/pciex/%.s
+ @($(LHEAD) $(LINT.s) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4v/ml/%.s
@($(LHEAD) $(LINT.s) $< $(LTAIL))
diff --git a/usr/src/uts/sun4v/Makefile.sun4v.shared b/usr/src/uts/sun4v/Makefile.sun4v.shared
index 0b27ee8299..6d7e6a1ea2 100644
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared
+++ b/usr/src/uts/sun4v/Makefile.sun4v.shared
@@ -396,6 +396,7 @@ MISC_KMODS += obpsym
MISC_KMODS += platmod
MISC_KMODS += platsvc
MISC_KMODS += vis
+MISC_KMODS += pcie
# md5 optimized for Niagara
#
diff --git a/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c
new file mode 100644
index 0000000000..653de54b4c
--- /dev/null
+++ b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c
@@ -0,0 +1,130 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Common PCI configuration space access routines
+ */
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/promif.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/kmem.h>
+#include <sys/obpdefs.h>
+#include <sys/sysmacros.h>
+#include <sys/pci.h>
+#include <sys/spl.h>
+#include <sys/pcie_impl.h>
+#include <sys/pci_cfgacc_4v.h>
+
+#define PCIE_CFG_SPACE_SIZE (PCI_CONF_HDR_SIZE << 4)
+
+/* RC BDF Shift in a Phyiscal Address */
+#define RC_RA_BDF_SHIFT 8
+
+static boolean_t
+pci_cfgacc_valid(pci_cfgacc_req_t *req)
+{
+ /* do not support 64 bit pci config space access */
+ return (IS_P2ALIGNED(req->offset, req->size) &&
+ (req->offset < PCIE_CFG_SPACE_SIZE) &&
+ ((req->size == 1) || (req->size == 2) ||
+ (req->size == 4) || (req->size == 8)));
+}
+
+/*
+ * Unprotected raw reads/writes of fabric device's config space.
+ */
+static uint64_t
+pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size)
+{
+ pcie_bus_t *bus_p;
+ uint64_t devhdl;
+ uint64_t devaddr;
+ uint64_t data = 0;
+
+ if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
+ return ((uint64_t)-1);
+
+ devhdl = bus_p->bus_cfgacc_base;
+ devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT;
+
+ (void) hvio_config_get(devhdl, devaddr,
+ offset, size, (pci_cfg_data_t *)&data);
+
+ return (data);
+}
+
+static void
+pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
+ uint64_t val)
+{
+ pcie_bus_t *bus_p;
+ uint64_t devhdl;
+ uint64_t devaddr;
+ pci_cfg_data_t wdata = { 0 };
+
+ if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
+ return;
+
+ devhdl = bus_p->bus_cfgacc_base;
+ devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT;
+
+ wdata.qw = val;
+ (void) hvio_config_put(devhdl, devaddr, offset, size, wdata);
+}
+
+void
+pci_cfgacc_acc(pci_cfgacc_req_t *req)
+{
+ /* is request valid? */
+ if (!pci_cfgacc_valid(req)) {
+ if (!req->write)
+ VAL64(req) = (uint64_t)-1;
+ return;
+ }
+
+ if (req->write) {
+ pci_cfgacc_set(req->rcdip, req->bdf, req->offset,
+ req->size, VAL64(req));
+ } else {
+ VAL64(req) = pci_cfgacc_get(req->rcdip, req->bdf,
+ req->offset, req->size);
+ switch (req->size) {
+ case 1:
+ VAL8(req) = (uint8_t)VAL64(req);
+ break;
+ case 2:
+ VAL16(req) = (uint16_t)VAL64(req);
+ break;
+ case 4:
+ VAL32(req) = (uint32_t)VAL64(req);
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/usr/src/uts/sun4v/io/pciex/pci_cfgacc_asm.s b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_asm.s
new file mode 100644
index 0000000000..6d1eb503ef
--- /dev/null
+++ b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_asm.s
@@ -0,0 +1,89 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Assembly language support for pci config space access on sun4v
+ */
+
+#include <sys/asm_linkage.h>
+#include <sys/hypervisor_api.h>
+#include <sys/dditypes.h>
+#include <sys/pci_cfgacc.h>
+#include <io/px/px_ioapi.h>
+#include <io/px/px_lib4v.h>
+
+#if defined(lint) || defined(__lint)
+
+/*ARGSUSED*/
+uint64_t
+hvio_config_get(devhandle_t dev_hdl, pci_device_t bdf, pci_config_offset_t off,
+ pci_config_size_t size, pci_cfg_data_t *data_p)
+{ return (0); }
+
+/*ARGSUSED*/
+uint64_t
+hvio_config_put(devhandle_t dev_hdl, pci_device_t bdf, pci_config_offset_t off,
+ pci_config_size_t size, pci_cfg_data_t data)
+{ return (0); }
+
+#else /* lint || __lint */
+
+ /*
+ * arg0 - devhandle
+ * arg1 - pci_device
+ * arg2 - pci_config_offset
+ * arg3 - pci_config_size (1, 2 or 4 byte)
+ *
+ * ret0 - status
+ * ret1 - error_flag
+ * ret2 - pci_cfg_data
+ */
+ ENTRY(hvio_config_get)
+ mov HVIO_CONFIG_GET, %o5
+ ta FAST_TRAP
+ movrnz %o1, -1, %o2
+ stx %o2, [%o4]
+ retl
+ nop
+ SET_SIZE(hvio_config_get)
+
+ /*
+ * arg0 - devhandle
+ * arg1 - pci_device
+ * arg2 - pci_config_offset
+ * arg3 - pci_config_size (1, 2 or 4 byte)
+ * arg4 - pci_cfg_data
+ *
+ * ret0 - status
+ * ret1 - error_flag
+ */
+ ENTRY(hvio_config_put)
+ mov HVIO_CONFIG_PUT, %o5
+ ta FAST_TRAP
+ retl
+ nop
+ SET_SIZE(hvio_config_put)
+#endif
diff --git a/usr/src/uts/sun4v/io/px/px_hcall.s b/usr/src/uts/sun4v/io/px/px_hcall.s
index 44d7957406..3e9f24896a 100644
--- a/usr/src/uts/sun4v/io/px/px_hcall.s
+++ b/usr/src/uts/sun4v/io/px/px_hcall.s
@@ -38,18 +38,6 @@
/*ARGSUSED*/
uint64_t
-hvio_config_get(devhandle_t dev_hdl, pci_device_t bdf, pci_config_offset_t off,
- pci_config_size_t size, pci_cfg_data_t *data_p)
-{ return (0); }
-
-/*ARGSUSED*/
-uint64_t
-hvio_config_put(devhandle_t dev_hdl, pci_device_t bdf, pci_config_offset_t off,
- pci_config_size_t size, pci_cfg_data_t data)
-{ return (0); }
-
-/*ARGSUSED*/
-uint64_t
hvio_iommu_map(devhandle_t dev_hdl, tsbid_t tsbid, pages_t pages,
io_attributes_t attr, io_page_list_t *io_page_list_p,
pages_t *pages_mapped)
@@ -218,42 +206,6 @@ px_phys_acc_4v(uint64_t dummy, uint64_t from_addr, uint64_t to_addr)
/*
* arg0 - devhandle
- * arg1 - pci_device
- * arg2 - pci_config_offset
- * arg3 - pci_config_size
- *
- * ret0 - status
- * ret1 - error_flag
- * ret2 - pci_cfg_data
- */
- ENTRY(hvio_config_get)
- mov HVIO_CONFIG_GET, %o5
- ta FAST_TRAP
- movrnz %o1, -1, %o2
- stx %o2, [%o4]
- retl
- nop
- SET_SIZE(hvio_config_get)
-
- /*
- * arg0 - devhandle
- * arg1 - pci_device
- * arg2 - pci_config_offset
- * arg3 - pci_config_size
- * arg4 - pci_cfg_data
- *
- * ret0 - status
- * ret1 - error_flag
- */
- ENTRY(hvio_config_put)
- mov HVIO_CONFIG_PUT, %o5
- ta FAST_TRAP
- retl
- nop
- SET_SIZE(hvio_config_put)
-
- /*
- * arg0 - devhandle
* arg1 - tsbid
* arg2 - pages
* arg3 - io_attributes
diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.c b/usr/src/uts/sun4v/io/px/px_lib4v.c
index b2f552c32a..eaa968f768 100644
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c
@@ -40,6 +40,9 @@
#include <sys/machsystm.h>
#include "px_lib4v.h"
#include "px_err.h"
+#include <sys/pci_cfgacc.h>
+#include <sys/pci_cfgacc_4v.h>
+
/* mask for the ranges property in calculating the real PFN range */
uint_t px_ranges_phi_mask = ((1 << 28) -1);
@@ -1929,28 +1932,16 @@ px_pmeq_intr(caddr_t arg)
}
/*
- * Unprotected raw reads/writes of fabric device's config space.
- * Only used for temporary PCI-E Fabric Error Handling.
+ * fetch the config space base addr of the root complex
+ * note this depends on px structure being initialized
*/
-uint32_t
-px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset) {
- uint64_t data = 0;
-
- (void) hvio_config_get(px_p->px_dev_hdl,
- (bdf << PX_RA_BDF_SHIFT), offset, 4,
- (pci_cfg_data_t *)&data);
-
- return ((uint32_t)data);
-}
-
-void
-px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
- uint32_t val) {
- pci_cfg_data_t wdata = { 0 };
+uint64_t
+px_lib_get_cfgacc_base(dev_info_t *dip)
+{
+ int instance = DIP_TO_INST(dip);
+ px_t *px_p = INST_TO_STATE(instance);
- wdata.qw = (uint32_t)val;
- (void) hvio_config_put(px_p->px_dev_hdl,
- (bdf << PX_RA_BDF_SHIFT), offset, 4, wdata);
+ return (px_p->px_dev_hdl);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.h b/usr/src/uts/sun4v/io/px/px_lib4v.h
index e9be90a7eb..2aaeffbd73 100644
--- a/usr/src/uts/sun4v/io/px/px_lib4v.h
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.h
@@ -79,9 +79,6 @@ extern "C" {
*/
#define DEVHDLE_MASK 0xFFFFFFF
-/* PX BDF Shift in a Phyiscal Address - used FMA Fabric only */
-#define PX_RA_BDF_SHIFT 8
-
#define PX_ADDR2PFN(addr, index, flags, i) \
((flags & MMU_MAP_PFN) ? \
PX_GET_MP_PFN((ddi_dma_impl_t *)(addr), (index + i)) : \
@@ -99,11 +96,6 @@ extern "C" {
#define PX_VPCI_MINOR_VER_1 0x1ull
#define PX_VPCI_MINOR_VER PX_VPCI_MINOR_VER_1
-extern uint64_t hvio_config_get(devhandle_t dev_hdl, pci_device_t bdf,
- pci_config_offset_t off, pci_config_size_t size, pci_cfg_data_t *data_p);
-extern uint64_t hvio_config_put(devhandle_t dev_hdl, pci_device_t bdf,
- pci_config_offset_t off, pci_config_size_t size, pci_cfg_data_t data);
-
extern uint64_t hvio_iommu_map(devhandle_t dev_hdl, tsbid_t tsbid,
pages_t pages, io_attributes_t attr, io_page_list_t *io_page_list_p,
pages_t *pages_mapped);
diff --git a/usr/src/uts/sun4v/io/px/px_libhv.c b/usr/src/uts/sun4v/io/px/px_libhv.c
index 7dab243d92..9890c7da55 100644
--- a/usr/src/uts/sun4v/io/px/px_libhv.c
+++ b/usr/src/uts/sun4v/io/px/px_libhv.c
@@ -36,6 +36,8 @@
#include <sys/errno.h>
#include <sys/hypervisor_api.h>
#include <sys/hsvc.h>
+#include <sys/pci_cfgacc.h>
+#include <sys/pci_cfgacc_4v.h>
#include <px_obj.h>
#include <sys/machsystm.h>
#include "px_lib4v.h"
diff --git a/usr/src/uts/sun4v/io/px/px_tools_4v.c b/usr/src/uts/sun4v/io/px/px_tools_4v.c
index 9f06b22575..42ec37636b 100644
--- a/usr/src/uts/sun4v/io/px/px_tools_4v.c
+++ b/usr/src/uts/sun4v/io/px/px_tools_4v.c
@@ -31,6 +31,7 @@
#include <sys/hsvc.h>
#include <px_obj.h>
#include <sys/pci_tools.h>
+#include <sys/pci_cfgacc.h>
#include <px_tools_var.h>
#include "px_lib4v.h"
#include <px_tools_ext.h>
@@ -215,7 +216,6 @@ pxtool_phys_access(px_t *px_p, uintptr_t dev_addr,
* prg_p->phys_addr isn't used.
*/
-/*ARGSUSED*/
int
pxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p,
uint64_t *data_p, boolean_t is_write)
@@ -224,9 +224,15 @@ pxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p,
on_trap_data_t otd;
dev_info_t *dip = px_p->px_dip;
px_pec_t *pec_p = px_p->px_pec_p;
- pci_device_t bdf = PX_GET_BDF(prg_p);
size_t size = PCITOOL_ACC_ATTR_SIZE(prg_p->acc_attr);
int rval = 0;
+ pci_cfgacc_req_t req;
+
+ if ((size <= 0) || (size > 8)) {
+ DBG(DBG_TOOLS, dip, "not supported size.\n");
+ prg_p->status = PCITOOL_INVALID_SIZE;
+ return (ENOTSUP);
+ }
/* Alignment checking. */
if (!IS_P2ALIGNED(prg_p->offset, size)) {
@@ -238,6 +244,11 @@ pxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p,
mutex_enter(&pec_p->pec_pokefault_mutex);
pec_p->pec_ontrap_data = &otd;
+ req.rcdip = dip;
+ req.bdf = PCI_GETBDF(prg_p->bus_no, prg_p->dev_no, prg_p->func_no);
+ req.offset = prg_p->offset;
+ req.size = size;
+ req.write = is_write;
if (is_write) {
if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr))
@@ -259,16 +270,17 @@ pxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p,
break;
}
- DBG(DBG_TOOLS, dip, "put: bdf:0x%x, off:0x%" PRIx64 ", size:"
- "0x%" PRIx64 ", data:0x%" PRIx64 "\n",
- bdf, prg_p->offset, size, data.qw);
+ DBG(DBG_TOOLS, dip, "put: bdf:%d,%d,%d, off:0x%"PRIx64", size:"
+ "0x%"PRIx64", data:0x%"PRIx64"\n",
+ prg_p->bus_no, prg_p->dev_no, prg_p->func_no,
+ prg_p->offset, size, data.qw);
pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;
if (!on_trap(&otd, OT_DATA_ACCESS)) {
otd.ot_trampoline = (uintptr_t)&poke_fault;
- rval = hvio_config_put(px_p->px_dev_hdl, bdf,
- prg_p->offset, size, data);
+ VAL64(&req) = data.qw;
+ pci_cfgacc_acc(&req);
} else
rval = H_EIO;
@@ -283,14 +295,29 @@ pxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p,
if (!on_trap(&otd, OT_DATA_ACCESS)) {
otd.ot_trampoline = (uintptr_t)&peek_fault;
- rval = hvio_config_get(px_p->px_dev_hdl, bdf,
- prg_p->offset, size, &data);
+ pci_cfgacc_acc(&req);
+ data.qw = VAL64(&req);
} else
rval = H_EIO;
- DBG(DBG_TOOLS, dip, "get: bdf:0x%x, off:0x%" PRIx64 ", size:"
- "0x%" PRIx64 ", data:0x%" PRIx64 "\n",
- bdf, prg_p->offset, size, data.qw);
+ switch (size) {
+ case sizeof (uint8_t):
+ data.qw = (uint64_t)data.b;
+ break;
+ case sizeof (uint16_t):
+ data.qw = (uint64_t)data.w;
+ break;
+ case sizeof (uint32_t):
+ data.qw = (uint64_t)data.dw;
+ break;
+ case sizeof (uint64_t):
+ break;
+ }
+
+ DBG(DBG_TOOLS, dip, "get: bdf:%d,%d,%d, off:0x%"PRIx64", size:"
+ "0x%"PRIx64", data:0x%"PRIx64"\n",
+ prg_p->bus_no, prg_p->dev_no, prg_p->func_no,
+ prg_p->offset, size, data.qw);
*data_p = data.qw;
if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr))
diff --git a/usr/src/uts/sun4v/pcie/Makefile b/usr/src/uts/sun4v/pcie/Makefile
new file mode 100644
index 0000000000..5b51172fd5
--- /dev/null
+++ b/usr/src/uts/sun4v/pcie/Makefile
@@ -0,0 +1,90 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/sun4v/pcie/Makefile
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+# This makefile drives the production of the sun4v/kernel/misc/sparcv9/pcie module
+# for PCI-E Error handling support in PCI-E nexus drivers.
+#
+# sun4v implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = pcie
+OBJECTS = $(PCIE_MISC_OBJS:%=$(OBJS_DIR)/%) \
+ $(PCI_STRING_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(PCIE_MISC_OBJS:%.o=$(LINTS_DIR)/%.ln) \
+ $(PCI_STRING_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sun4v/Makefile.sun4v
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Dependency
+#
+LDFLAGS += -dy -Nmisc/busra
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sun4v/Makefile.targ
diff --git a/usr/src/uts/sun4v/sys/pci_cfgacc_4v.h b/usr/src/uts/sun4v/sys/pci_cfgacc_4v.h
new file mode 100644
index 0000000000..1234075561
--- /dev/null
+++ b/usr/src/uts/sun4v/sys/pci_cfgacc_4v.h
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_PCI_CFGACC_4V_H
+#define _SYS_PCI_CFGACC_4V_H
+
+#include <sys/pci.h>
+#include <sys/pci_cfgacc.h>
+#include "../../sun4/io/px/px_ioapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint64_t hvio_config_get(devhandle_t, pci_device_t, pci_config_offset_t,
+ pci_config_size_t, pci_cfg_data_t *);
+extern uint64_t hvio_config_put(devhandle_t, pci_device_t, pci_config_offset_t,
+ pci_config_size_t, pci_cfg_data_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_PCI_CFGACC_4V_H */