changeset 11245:28613b254aad

6831378 identify device type during early boot
author Zhi-Jun Robin Fu <Zhijun.Fu@Sun.COM>
date Fri, 04 Dec 2009 12:16:40 +0800
parents 36368caa105c
children 544fdabd3ed3
files usr/src/pkgdefs/SUNWcakr.u/prototype_com usr/src/pkgdefs/SUNWcakr.v/prototype_com usr/src/pkgdefs/SUNWckr/prototype_sparc usr/src/tools/scripts/bfu.sh usr/src/uts/common/io/pciex/hotplug/pcishpc.c usr/src/uts/common/io/pciex/pci_cfgacc.c usr/src/uts/common/io/pciex/pcie.c usr/src/uts/common/io/pciex/pcieb.c usr/src/uts/common/sys/pci_cfgacc.h usr/src/uts/common/sys/pcie_impl.h usr/src/uts/i86pc/Makefile.files usr/src/uts/i86pc/Makefile.rules usr/src/uts/i86pc/io/pci/pci_tools.c usr/src/uts/i86pc/io/pciex/npe.c usr/src/uts/i86pc/io/pciex/npe_misc.c usr/src/uts/i86pc/os/acpi_fw.h usr/src/uts/i86pc/os/fakebop.c usr/src/uts/i86pc/os/pci_cfgacc_x86.c usr/src/uts/i86pc/os/pci_cfgspace.c usr/src/uts/i86pc/sys/pci_cfgacc_x86.h usr/src/uts/i86pc/sys/pci_cfgspace_impl.h usr/src/uts/i86xpv/Makefile.files usr/src/uts/i86xpv/Makefile.rules usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c usr/src/uts/intel/io/pci/pci_boot.c usr/src/uts/intel/io/pci/pci_pci.c usr/src/uts/intel/io/pciex/pcie_nvidia.c usr/src/uts/intel/io/pciex/pcie_nvidia.h usr/src/uts/intel/pci_autoconfig/Makefile usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/pcie/Makefile usr/src/uts/sun4/io/pcicfg.c usr/src/uts/sun4/io/px/px.c usr/src/uts/sun4/io/px/px_ioapi.h usr/src/uts/sun4/io/px/px_lib.h usr/src/uts/sun4/io/px/px_util.c usr/src/uts/sun4u/Makefile.files usr/src/uts/sun4u/Makefile.rules usr/src/uts/sun4u/Makefile.sun4u.shared usr/src/uts/sun4u/io/pci/pci_pci.c usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c usr/src/uts/sun4u/io/px/px_lib4u.c usr/src/uts/sun4u/io/px/px_lib4u.h usr/src/uts/sun4u/pcie/Makefile usr/src/uts/sun4v/Makefile.files usr/src/uts/sun4v/Makefile.rules usr/src/uts/sun4v/Makefile.sun4v.shared usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c usr/src/uts/sun4v/io/pciex/pci_cfgacc_asm.s usr/src/uts/sun4v/io/px/px_hcall.s usr/src/uts/sun4v/io/px/px_lib4v.c usr/src/uts/sun4v/io/px/px_lib4v.h usr/src/uts/sun4v/io/px/px_libhv.c usr/src/uts/sun4v/io/px/px_tools_4v.c usr/src/uts/sun4v/pcie/Makefile usr/src/uts/sun4v/sys/pci_cfgacc_4v.h
diffstat 56 files changed, 2321 insertions(+), 679 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWcakr.u/prototype_com	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/pkgdefs/SUNWcakr.u/prototype_com	Fri Dec 04 12:16:40 2009 +0800
@@ -488,6 +488,7 @@
 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
--- a/usr/src/pkgdefs/SUNWcakr.v/prototype_com	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/pkgdefs/SUNWcakr.v/prototype_com	Fri Dec 04 12:16:40 2009 +0800
@@ -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/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
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc	Fri Dec 04 12:16:40 2009 +0800
@@ -208,7 +208,6 @@
 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
--- a/usr/src/tools/scripts/bfu.sh	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/tools/scripts/bfu.sh	Fri Dec 04 12:16:40 2009 +0800
@@ -7242,6 +7242,16 @@
 	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.
         #
--- a/usr/src/uts/common/io/pciex/hotplug/pcishpc.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/common/io/pciex/hotplug/pcishpc.c	Fri Dec 04 12:16:40 2009 +0800
@@ -950,11 +950,13 @@
 	/*
 	 * 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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/pciex/pci_cfgacc.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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);
+}
--- a/usr/src/uts/common/io/pciex/pcie.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/common/io/pciex/pcie.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
     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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 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:
  *
- * PCIe Bus Private Data contains commonly used PCI/PCIe information and offsets
- * to key registers.
+ * 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
+ *
+ * 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;
-	}
-
-	bus_p->bus_cfg_hdl = eh;
-	bus_p->bus_fm_flags = 0;
-	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
+	rcdip = pcie_get_rc_dip(dip);
+	ASSERT(rcdip != NULL);
 
-	/* 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;
-	}
-
-	/* 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);
-
+	/* 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 = PCIE_GET(8, bus_p, PCI_CONF_HEADER);
+	bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER);
 	bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
 
-	/* 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;
+	/*
+	 * 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;
 
-		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;
+	status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT);
+	if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP))
+		goto caps_done; /* capability not supported */
+
+	/* Relevant conventional capabilities first */
+
+	/* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */
+	num_cap = 2;
 
-		/* 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;
-	}
-
-	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;
+	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;
 	}
 
-	/* Save the Range information if device is a switch/bridge */
-	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;
+	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;
 
-		/* 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;
+			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;
 		}
-
-		/* get secondary bus number */
-		bus_p->bus_bdg_secbus = PCIE_GET(8, bus_p, PCI_BCNF_SECBUS);
-
-		/* 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);
 	}
 
-	/* 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;
+	/* Check and save PCI hotplug (SHPC) capability information */
+	if (PCIE_IS_BDG(bus_p)) {
+		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;
+			}
+		}
+	}
+
+	/* Then, relevant extended capabilities */
 
+	if (!PCIE_IS_PCIE(bus_p))
+		goto caps_done;
+
+	/* 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 @@
 		}
 	}
 
-	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;
 
-	if (PCIE_IS_HOTPLUG_CAPABLE(cdip))
-		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
+	ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
+
+	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;
+
+	/* 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_mps = 0;
+		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);
+	}
 
-	pcie_init_plat(cdip);
+	/* 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(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 @@
 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 @@
 			*empty_mem_range = B_TRUE;
 	}
 }
+
 #endif /* defined(__i386) || defined(__amd64) */
--- a/usr/src/uts/common/io/pciex/pcieb.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/common/io/pciex/pcieb.c	Fri Dec 04 12:16:40 2009 +0800
@@ -780,7 +780,7 @@
 	    "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;
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/pci_cfgacc.h	Fri Dec 04 12:16:40 2009 +0800
@@ -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 */
--- a/usr/src/uts/common/sys/pcie_impl.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/common/sys/pcie_impl.h	Fri Dec 04 12:16:40 2009 +0800
@@ -59,6 +59,9 @@
 #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_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 @@
 	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 @@
 		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 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 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);
--- a/usr/src/uts/i86pc/Makefile.files	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/Makefile.files	Fri Dec 04 12:16:40 2009 +0800
@@ -94,6 +94,8 @@
 	mpcore.o		\
 	notes.o			\
 	pci_bios.o		\
+	pci_cfgacc.o		\
+	pci_cfgacc_x86.o	\
 	pci_cfgspace.o		\
 	pci_mech1.o		\
 	pci_mech2.o		\
--- a/usr/src/uts/i86pc/Makefile.rules	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/Makefile.rules	Fri Dec 04 12:16:40 2009 +0800
@@ -151,6 +151,10 @@
 	$(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/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))
 
--- a/usr/src/uts/i86pc/io/pci/pci_tools.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/io/pci/pci_tools.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 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,
-    boolean_t write_flag);
-static int pcitool_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_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 @@
 	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 @@
  * 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 @@
 	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 @@
 	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;
-		}
-
-		if (rval == SUCCESS) {
-			if (big_endian) {
-				prg->data =
-				    pcitool_swap_endian(local_data, size);
-			} else {
-				prg->data = local_data;
-			}
+		pci_cfgacc_acc(&req);
+		local_data = VAL64(&req);
+		if (big_endian) {
+			prg->data =
+			    pcitool_swap_endian(local_data, size);
+		} else {
+			prg->data = local_data;
 		}
 	}
-	prg->phys_addr = 0;	/* Config space is not memory mapped on X86. */
+	/*
+	 * 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);
+	}
+
+	/* 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));
+	}
+
 	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 @@
 	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 @@
 
 
 /* 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 @@
 				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 @@
 			 * 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 @@
 				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 @@
 				 * 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 @@
 				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:
--- a/usr/src/uts/i86pc/io/pciex/npe.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/io/pciex/npe.c	Fri Dec 04 12:16:40 2009 +0800
@@ -308,8 +308,6 @@
 	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_query_acpi_mcfg(devi);
 	ddi_report_dev(devi);
+	pcie_fab_init_bus(devi, PCIE_BUS_FINAL);
 
 	return (DDI_SUCCESS);
 
@@ -353,6 +352,7 @@
 
 	switch (cmd) {
 	case DDI_DETACH:
+		pcie_fab_fini_bus(devi, PCIE_BUS_INITIAL);
 
 		/* Uninitialize pcitool support. */
 		pcitool_uninit(devi);
@@ -363,7 +363,6 @@
 		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 @@
 		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);
--- a/usr/src/uts/i86pc/io/pciex/npe_misc.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/io/pciex/npe_misc.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 
 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
--- a/usr/src/uts/i86pc/os/acpi_fw.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/os/acpi_fw.h	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
  */
 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;
--- a/usr/src/uts/i86pc/os/fakebop.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/os/fakebop.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 	/*NOTREACHED*/
 }
 
-static uintptr_t
+uintptr_t
 alloc_vaddr(size_t size, paddr_t align)
 {
 	uintptr_t rv;
@@ -1861,7 +1862,6 @@
 }
 
 
-#ifndef __xpv
 /*
  * Set ACPI firmware properties
  */
@@ -1873,6 +1873,9 @@
 	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 @@
 }
 
 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 @@
 static void
 build_firmware_properties(void)
 {
+	struct table_header *tp = NULL;
+
 #ifndef __xpv
-	struct table_header *tp;
-
 	if ((tp = find_fw_table("APIC")) != NULL)
 		process_madt((struct madt *)tp);
 
@@ -2249,9 +2276,14 @@
 
 	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);
 }
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/os/pci_cfgacc_x86.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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);
+}
--- a/usr/src/uts/i86pc/os/pci_cfgspace.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/os/pci_cfgspace.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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>
+#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_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_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 @@
 }
 
 /*
- * 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_bios_maxbus = pci_max_nbus;
 	}
-
-	return (TRUE);
 #else /* !__xpv */
 
 	pci_bios_cfg_type = pci_check_bios();
@@ -192,9 +206,24 @@
 	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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/sys/pci_cfgacc_x86.h	Fri Dec 04 12:16:40 2009 +0800
@@ -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 */
--- a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 #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 @@
 #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)
 
--- a/usr/src/uts/i86xpv/Makefile.files	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86xpv/Makefile.files	Fri Dec 04 12:16:40 2009 +0800
@@ -85,6 +85,8 @@
 	memscrub.o		\
 	notes.o			\
 	pci_bios.o		\
+	pci_cfgacc.o		\
+	pci_cfgacc_x86.o	\
 	pci_cfgspace.o		\
 	pci_mech1.o		\
 	pci_mech2.o		\
--- a/usr/src/uts/i86xpv/Makefile.rules	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/i86xpv/Makefile.rules	Fri Dec 04 12:16:40 2009 +0800
@@ -106,6 +106,10 @@
 	$(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/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))
 
--- a/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 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 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_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 @@
 	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 @@
 
 	attach_point = devi;
 
+	is_pcie = is_pcie_fabric(devi);
+
 	ndi_devi_enter(devi, &circ);
 	for (func = 0; func < max_function; ) {
 
@@ -591,7 +597,8 @@
 			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 @@
 		 * 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 @@
 	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 @@
 	 * 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 @@
 			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_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 @@
 		(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_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 @@
 
 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 @@
 		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 @@
 	 */
 	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 @@
 			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 @@
 
 	(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 @@
 	 */
 	(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 @@
 
 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 @@
 
 	(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 @@
 				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 @@
 	 */
 	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 @@
 
 	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);
+}
--- a/usr/src/uts/intel/io/pci/pci_boot.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/intel/io/pci/pci_boot.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 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 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 @@
 {
 	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 @@
 	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 @@
 	    &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 @@
 	(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);
+	}
+}
--- a/usr/src/uts/intel/io/pci/pci_pci.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/intel/io/pci/pci_pci.c	Fri Dec 04 12:16:40 2009 +0800
@@ -684,7 +684,7 @@
 	 * 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 @@
 	    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);
--- a/usr/src/uts/intel/io/pciex/pcie_nvidia.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/intel/io/pciex/pcie_nvidia.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
  * 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 @@
 	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 @@
 	(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);
 }
 
--- a/usr/src/uts/intel/io/pciex/pcie_nvidia.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/intel/io/pciex/pcie_nvidia.h	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 /*
  * 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 *);
--- a/usr/src/uts/intel/pci_autoconfig/Makefile	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/intel/pci_autoconfig/Makefile	Fri Dec 04 12:16:40 2009 +0800
@@ -56,7 +56,7 @@
 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
 
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Fri Dec 04 12:16:40 2009 +0800
@@ -287,7 +287,7 @@
 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
--- a/usr/src/uts/sparc/pcie/Makefile	Thu Dec 03 19:18:04 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-#
-# 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/sparc/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
-#
-
-#
-#	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_MISC_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-# lint pass one enforcement
-#
-CFLAGS += $(CCVERBOSE)
-
-#
-#	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:
-
-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)/sparc/Makefile.targ
--- a/usr/src/uts/sun4/io/pcicfg.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4/io/pcicfg.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 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 @@
 #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 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_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 @@
 	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 @@
 
 	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 @@
 		 * 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 @@
 		 * 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 @@
 	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 @@
 	 * 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 @@
 			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_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 @@
 		(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 @@
 	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 @@
 
 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 @@
 		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 @@
 			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 @@
 	}
 
 	(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 @@
 		}
 	}
 
-
 	return (PCICFG_SUCCESS);
 
 failedchild:
@@ -4224,7 +4272,7 @@
 
 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 @@
 		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 @@
 			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 @@
 #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 @@
 				 * 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 @@
 	}
 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 @@
 		}
 		pci_config_teardown(&ph);
 	}
+
 	return (ret);
 }
 
@@ -4821,7 +4887,7 @@
 
 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 @@
 
 	(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 @@
 				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 @@
 	 */
 	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 @@
 			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);
+}
--- a/usr/src/uts/sun4/io/px/px.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 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 @@
 	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 @@
 		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 @@
 			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.
--- a/usr/src/uts/sun4/io/px/px_ioapi.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_ioapi.h	Fri Dec 04 12:16:40 2009 +0800
@@ -232,19 +232,6 @@
 	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
  *
--- a/usr/src/uts/sun4/io/px/px_lib.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_lib.h	Fri Dec 04 12:16:40 2009 +0800
@@ -190,10 +190,6 @@
 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 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
--- a/usr/src/uts/sun4/io/px/px_util.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4/io/px/px_util.c	Fri Dec 04 12:16:40 2009 +0800
@@ -525,8 +525,7 @@
 	    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.
--- a/usr/src/uts/sun4u/Makefile.files	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4u/Makefile.files	Fri Dec 04 12:16:40 2009 +0800
@@ -182,6 +182,8 @@
 
 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
 #
--- a/usr/src/uts/sun4u/Makefile.rules	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4u/Makefile.rules	Fri Dec 04 12:16:40 2009 +0800
@@ -92,6 +92,13 @@
 $(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/%.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))
 
--- a/usr/src/uts/sun4u/Makefile.sun4u.shared	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4u/Makefile.sun4u.shared	Fri Dec 04 12:16:40 2009 +0800
@@ -434,6 +434,7 @@
 MISC_KMODS	+= opl_cfg
 MISC_KMODS	+= zuluvm
 MISC_KMODS	+= gptwo_cpu gptwocfg
+MISC_KMODS	+= pcie
 
 #
 #	Brand modules
--- a/usr/src/uts/sun4u/io/pci/pci_pci.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4u/io/pci/pci_pci.c	Fri Dec 04 12:16:40 2009 +0800
@@ -963,7 +963,7 @@
 	 * 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 @@
 	 * 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);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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);
+	}
+}
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c	Fri Dec 04 12:16:40 2009 +0800
@@ -2344,45 +2344,6 @@
 #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 @@
 }
 
 /*
+ * 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
--- a/usr/src/uts/sun4u/io/px/px_lib4u.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.h	Fri Dec 04 12:16:40 2009 +0800
@@ -280,10 +280,6 @@
 /* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4u/pcie/Makefile	Fri Dec 04 12:16:40 2009 +0800
@@ -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/sun4u/pcie/Makefile
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+#	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
+#
+
+#
+#	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)/sun4u/Makefile.sun4u
+
+#
+#	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)/sun4u/Makefile.targ
--- a/usr/src/uts/sun4v/Makefile.files	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/Makefile.files	Fri Dec 04 12:16:40 2009 +0800
@@ -169,6 +169,7 @@
 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
--- a/usr/src/uts/sun4v/Makefile.rules	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/Makefile.rules	Fri Dec 04 12:16:40 2009 +0800
@@ -98,6 +98,13 @@
 $(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/%.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))
 
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/Makefile.sun4v.shared	Fri Dec 04 12:16:40 2009 +0800
@@ -396,6 +396,7 @@
 MISC_KMODS	+= platmod
 MISC_KMODS	+= platsvc
 MISC_KMODS	+= vis
+MISC_KMODS	+= pcie
 
 #	md5 optimized for Niagara
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_4v.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/io/pciex/pci_cfgacc_asm.s	Fri Dec 04 12:16:40 2009 +0800
@@ -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
--- a/usr/src/uts/sun4v/io/px/px_hcall.s	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/io/px/px_hcall.s	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 
 	/*
 	 * 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
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
 }
 
 /*
- * 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);
+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);
 
-	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 };
-
-	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*/
--- a/usr/src/uts/sun4v/io/px/px_lib4v.h	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.h	Fri Dec 04 12:16:40 2009 +0800
@@ -79,9 +79,6 @@
  */
 #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 @@
 #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);
--- a/usr/src/uts/sun4v/io/px/px_libhv.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/io/px/px_libhv.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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"
--- a/usr/src/uts/sun4v/io/px/px_tools_4v.c	Thu Dec 03 19:18:04 2009 -0800
+++ b/usr/src/uts/sun4v/io/px/px_tools_4v.c	Fri Dec 04 12:16:40 2009 +0800
@@ -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 @@
  * 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 @@
 	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 @@
 	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 @@
 				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 @@
 
 		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))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/pcie/Makefile	Fri Dec 04 12:16:40 2009 +0800
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/sys/pci_cfgacc_4v.h	Fri Dec 04 12:16:40 2009 +0800
@@ -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 */