6470782 x86 pci_pci.c: move it from common area to i86pc
authoranish
Tue, 19 Sep 2006 15:47:25 -0700
changeset 2767 06c926d616c5
parent 2766 897bcb036a29
child 2768 3c77434a8dbb
6470782 x86 pci_pci.c: move it from common area to i86pc
usr/src/pkgdefs/SUNWcakr.i/prototype_com
usr/src/pkgdefs/SUNWckr/prototype_i386
usr/src/uts/common/Makefile.files
usr/src/uts/common/io/pci_pci/pci_pci.c
usr/src/uts/common/sys/pci.h
usr/src/uts/i86pc/Makefile.files
usr/src/uts/i86pc/Makefile.i86pc.shared
usr/src/uts/i86pc/io/pci/pci_pci.c
usr/src/uts/i86pc/io/pciex/pcie_pci.c
usr/src/uts/i86pc/pci_pci/Makefile
usr/src/uts/intel/Makefile.intel.shared
usr/src/uts/intel/Makefile.rules
usr/src/uts/intel/pci_pci/Makefile
--- a/usr/src/pkgdefs/SUNWcakr.i/prototype_com	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/pkgdefs/SUNWcakr.i/prototype_com	Tue Sep 19 15:47:25 2006 -0700
@@ -76,6 +76,7 @@
 f none platform/i86pc/kernel/drv/amd64/mc-amd 755 root sys
 f none platform/i86pc/kernel/drv/amd64/npe 755 root sys
 f none platform/i86pc/kernel/drv/amd64/pci 755 root sys
+f none platform/i86pc/kernel/drv/amd64/pci_pci 755 root sys
 f none platform/i86pc/kernel/drv/amd64/pcie_pci 755 root sys
 f none platform/i86pc/kernel/drv/amd64/power 755 root sys
 f none platform/i86pc/kernel/drv/amd64/rootnex 755 root sys
@@ -91,6 +92,7 @@
 f none platform/i86pc/kernel/drv/mc-amd.conf 644 root sys
 f none platform/i86pc/kernel/drv/npe 755 root sys
 f none platform/i86pc/kernel/drv/pci 755 root sys
+f none platform/i86pc/kernel/drv/pci_pci 755 root sys
 f none platform/i86pc/kernel/drv/pcie_pci 755 root sys
 f none platform/i86pc/kernel/drv/pcie_pci.conf 644 root sys
 f none platform/i86pc/kernel/drv/power 755 root sys
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386	Tue Sep 19 15:47:25 2006 -0700
@@ -95,7 +95,6 @@
 f none kernel/drv/mouse8042 755 root sys
 f none kernel/drv/openeepr 755 root sys
 f none kernel/drv/options 755 root sys
-f none kernel/drv/pci_pci 755 root sys
 f none kernel/drv/pci_to_i2o 755 root sys
 f none kernel/drv/pci_to_i2o.conf 644 root sys
 f none kernel/drv/poll 755 root sys
@@ -271,7 +270,6 @@
 f none kernel/drv/amd64/mouse8042 755 root sys
 f none kernel/drv/amd64/openeepr 755 root sys
 f none kernel/drv/amd64/options 755 root sys
-f none kernel/drv/amd64/pci_pci 755 root sys
 f none kernel/drv/amd64/poll 755 root sys
 f none kernel/drv/amd64/pseudo 755 root sys
 f none kernel/drv/amd64/ptc 755 root sys
--- a/usr/src/uts/common/Makefile.files	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/uts/common/Makefile.files	Tue Sep 19 15:47:25 2006 -0700
@@ -394,8 +394,6 @@
 
 OLDPTY_OBJS +=	tty_ptyconf.o
 
-PCI_PCINEXUS_OBJS += pci_pci.o
-
 PTC_OBJS +=	tty_pty.o
 
 PTSL_OBJS +=	tty_pts.o
--- a/usr/src/uts/common/io/pci_pci/pci_pci.c	Tue Sep 19 15:38:37 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1077 +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
- */
-/*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * PCI to PCI bus bridge nexus driver
- */
-
-#include <sys/conf.h>
-#include <sys/kmem.h>
-#include <sys/debug.h>
-#include <sys/modctl.h>
-#include <sys/autoconf.h>
-#include <sys/ddi_impldefs.h>
-#include <sys/pci.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/sunndi.h>
-#include <sys/ddifm.h>
-#include <sys/ndifm.h>
-#include <sys/fm/protocol.h>
-#include <sys/hotplug/pci/pcihp.h>
-#if defined(__i386) || defined(__amd64)
-#include <sys/pci_intr_lib.h>
-#include <sys/psm.h>
-#endif
-
-/*
- * For PCI Hotplug support, the misc/pcihp module provides devctl control
- * device and cb_ops functions to support hotplug operations.
- */
-char _depends_on[] = "misc/pcihp";
-
-/*
- * The variable controls the default setting of the command register
- * for pci devices.  See ppb_initchild() for details.
- */
-#if defined(__i386) || defined(__amd64)
-static ushort_t ppb_command_default = PCI_COMM_ME |
-					PCI_COMM_MAE |
-					PCI_COMM_IO;
-#else
-static ushort_t ppb_command_default = PCI_COMM_SERR_ENABLE |
-					PCI_COMM_WAIT_CYC_ENAB |
-					PCI_COMM_PARITY_DETECT |
-					PCI_COMM_ME |
-					PCI_COMM_MAE |
-					PCI_COMM_IO;
-#endif
-
-
-static int ppb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
-	off_t, off_t, caddr_t *);
-static int ppb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
-	void *, void *);
-static int	ppb_fm_init(dev_info_t *, dev_info_t *, int,
-		    ddi_iblock_cookie_t *);
-
-static int	ppb_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *);
-
-#if defined(__i386) || defined(__amd64)
-static int ppb_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
-	ddi_intr_handle_impl_t *, void *);
-
-/*
- * Not to allow MSI by default except special case like AMD8132 with
- * MSI enabled.
- * However, this flag can be patched to allow MSI if needed.
- *  0 = default value, MSI is allowed only for special case
- *  1 = MSI supported without check
- * -1 = MSI not supported at all
- */
-int ppb_support_msi = 0;
-#endif
-
-struct bus_ops ppb_bus_ops = {
-	BUSO_REV,
-	ppb_bus_map,
-	0,
-	0,
-	0,
-	i_ddi_map_fault,
-	ddi_dma_map,
-	ddi_dma_allochdl,
-	ddi_dma_freehdl,
-	ddi_dma_bindhdl,
-	ddi_dma_unbindhdl,
-	ddi_dma_flush,
-	ddi_dma_win,
-	ddi_dma_mctl,
-	ppb_ctlops,
-	ddi_bus_prop_op,
-	0,		/* (*bus_get_eventcookie)();	*/
-	0,		/* (*bus_add_eventcall)();	*/
-	0,		/* (*bus_remove_eventcall)();	*/
-	0,		/* (*bus_post_event)();		*/
-	0,		/* (*bus_intr_ctl)();		*/
-	0,		/* (*bus_config)(); 		*/
-	0,		/* (*bus_unconfig)(); 		*/
-	ppb_fm_init,	/* (*bus_fm_init)(); 		*/
-	NULL,		/* (*bus_fm_fini)(); 		*/
-	NULL,		/* (*bus_fm_access_enter)(); 	*/
-	NULL,		/* (*bus_fm_access_exit)(); 	*/
-	NULL,		/* (*bus_power)(); 	*/
-#if defined(__i386) || defined(__amd64)
-	ppb_intr_ops	/* (*bus_intr_op)(); 		*/
-#else
-	i_ddi_intr_ops	/* (*bus_intr_op)(); 		*/
-#endif
-};
-
-/*
- * The goal here is to leverage off of the pcihp.c source without making
- * changes to it.  Call into it's cb_ops directly if needed.
- */
-static int	ppb_open(dev_t *, int, int, cred_t *);
-static int	ppb_close(dev_t, int, int, cred_t *);
-static int	ppb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
-static int	ppb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
-		    caddr_t, int *);
-static int	ppb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
-
-struct cb_ops ppb_cb_ops = {
-	ppb_open,			/* open */
-	ppb_close,			/* close */
-	nodev,				/* strategy */
-	nodev,				/* print */
-	nodev,				/* dump */
-	nodev,				/* read */
-	nodev,				/* write */
-	ppb_ioctl,			/* ioctl */
-	nodev,				/* devmap */
-	nodev,				/* mmap */
-	nodev,				/* segmap */
-	nochpoll,			/* poll */
-	ppb_prop_op,			/* cb_prop_op */
-	NULL,				/* streamtab */
-	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
-	CB_REV,				/* rev */
-	nodev,				/* int (*cb_aread)() */
-	nodev				/* int (*cb_awrite)() */
-};
-
-
-static int ppb_probe(dev_info_t *);
-static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
-static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
-
-struct dev_ops ppb_ops = {
-	DEVO_REV,		/* devo_rev */
-	0,			/* refcnt  */
-	ppb_info,		/* info */
-	nulldev,		/* identify */
-	ppb_probe,		/* probe */
-	ppb_attach,		/* attach */
-	ppb_detach,		/* detach */
-	nulldev,		/* reset */
-	&ppb_cb_ops,		/* driver operations */
-	&ppb_bus_ops		/* bus operations */
-};
-
-/*
- * Module linkage information for the kernel.
- */
-
-static struct modldrv modldrv = {
-	&mod_driverops, /* Type of module */
-	"PCI to PCI bridge nexus driver %I%",
-	&ppb_ops,	/* driver ops */
-};
-
-static struct modlinkage modlinkage = {
-	MODREV_1,
-	(void *)&modldrv,
-	NULL
-};
-
-/*
- * soft state pointer and structure template:
- */
-static void *ppb_state;
-
-typedef struct {
-
-	dev_info_t *dip;
-	int ppb_fmcap;
-	ddi_iblock_cookie_t ppb_fm_ibc;
-	kmutex_t ppb_peek_poke_mutex;
-	kmutex_t ppb_err_mutex;
-
-#if defined(__sparc)
-	/*
-	 * configuration register state for the bus:
-	 */
-	uchar_t ppb_cache_line_size;
-	uchar_t ppb_latency_timer;
-#endif
-
-	/*
-	 * cpr support:
-	 */
-#define	PCI_MAX_DEVICES		32
-#define	PCI_MAX_FUNCTIONS	8
-#define	PCI_MAX_CHILDREN	PCI_MAX_DEVICES * PCI_MAX_FUNCTIONS
-	uint_t config_state_index;
-	struct {
-		dev_info_t *dip;
-		ushort_t command;
-		uchar_t cache_line_size;
-		uchar_t latency_timer;
-		uchar_t header_type;
-		uchar_t sec_latency_timer;
-		ushort_t bridge_control;
-	} config_state[PCI_MAX_CHILDREN];
-} ppb_devstate_t;
-
-#if defined(__sparc)
-/*
- * The following variable enables a workaround for the following obp bug:
- *
- *	1234181 - obp should set latency timer registers in pci
- *		configuration header
- *
- * Until this bug gets fixed in the obp, the following workaround should
- * be enabled.
- */
-static uint_t ppb_set_latency_timer_register = 1;
-
-/*
- * The following variable enables a workaround for an obp bug to be
- * submitted.  A bug requesting a workaround fof this problem has
- * been filed:
- *
- *	1235094 - need workarounds on positron nexus drivers to set cache
- *		line size registers
- *
- * Until this bug gets fixed in the obp, the following workaround should
- * be enabled.
- */
-static uint_t ppb_set_cache_line_size_register = 1;
-#endif
-
-
-/*
- * forward function declarations:
- */
-static void ppb_removechild(dev_info_t *);
-static int ppb_initchild(dev_info_t *child);
-static void ppb_save_config_regs(ppb_devstate_t *ppb_p);
-static void ppb_restore_config_regs(ppb_devstate_t *ppb_p);
-#if	defined(__sparc)
-static int ppb_create_pci_prop(dev_info_t *);
-#endif	/* defined(__sparc) */
-
-
-int
-_init(void)
-{
-	int e;
-
-	if ((e = ddi_soft_state_init(&ppb_state, sizeof (ppb_devstate_t),
-	    1)) == 0 && (e = mod_install(&modlinkage)) != 0)
-		ddi_soft_state_fini(&ppb_state);
-	return (e);
-}
-
-int
-_fini(void)
-{
-	int e;
-
-	if ((e = mod_remove(&modlinkage)) == 0)
-		ddi_soft_state_fini(&ppb_state);
-	return (e);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
-
-/*ARGSUSED*/
-static int
-ppb_probe(dev_info_t *devi)
-{
-	return (DDI_PROBE_SUCCESS);
-}
-
-/*ARGSUSED*/
-static int
-ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
-{
-	int instance;
-	ppb_devstate_t *ppb;
-	ddi_acc_handle_t config_handle;
-
-	switch (cmd) {
-	case DDI_ATTACH:
-
-		/*
-		 * Make sure the "device_type" property exists.
-		 */
-		(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
-		    "device_type", "pci");
-
-		/*
-		 * Allocate and get soft state structure.
-		 */
-		instance = ddi_get_instance(devi);
-		if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS)
-			return (DDI_FAILURE);
-		ppb = ddi_get_soft_state(ppb_state, instance);
-		ppb->dip = devi;
-
-		/*
-		 * don't enable ereports if immediate child of npe
-		 */
-		if (strcmp(ddi_driver_name(ddi_get_parent(devi)), "npe") == 0)
-			ppb->ppb_fmcap = DDI_FM_ERRCB_CAPABLE |
-			    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
-		else
-			ppb->ppb_fmcap = DDI_FM_EREPORT_CAPABLE |
-			    DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
-			    DDI_FM_DMACHK_CAPABLE;
-
-		ddi_fm_init(devi, &ppb->ppb_fmcap, &ppb->ppb_fm_ibc);
-		mutex_init(&ppb->ppb_err_mutex, NULL, MUTEX_DRIVER,
-		    (void *)ppb->ppb_fm_ibc);
-		mutex_init(&ppb->ppb_peek_poke_mutex, NULL, MUTEX_DRIVER,
-		    (void *)ppb->ppb_fm_ibc);
-
-		if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE |
-		    DDI_FM_EREPORT_CAPABLE))
-			pci_ereport_setup(devi);
-		if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE)
-		    ddi_fm_handler_register(devi, ppb_fm_callback, NULL);
-
-		if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) {
-			if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE)
-				ddi_fm_handler_unregister(devi);
-			if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE |
-			    DDI_FM_EREPORT_CAPABLE))
-				pci_ereport_teardown(devi);
-			ddi_fm_fini(devi);
-			ddi_soft_state_free(ppb_state, instance);
-			return (DDI_FAILURE);
-		}
-#if defined(__sparc)
-		ppb->ppb_cache_line_size =
-			pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
-		ppb->ppb_latency_timer =
-			pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
-#endif
-		pci_config_teardown(&config_handle);
-
-		/*
-		 * Initialize hotplug support on this bus. At minimum
-		 * (for non hotplug bus) this would create ":devctl" minor
-		 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
-		 * to this bus.
-		 */
-		if (pcihp_init(devi) != DDI_SUCCESS)
-		    cmn_err(CE_WARN, "pci: Failed to setup hotplug framework");
-
-		ddi_report_dev(devi);
-		return (DDI_SUCCESS);
-
-	case DDI_RESUME:
-
-		/*
-		 * Get the soft state structure for the bridge.
-		 */
-		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi));
-		ppb_restore_config_regs(ppb);
-		return (DDI_SUCCESS);
-
-	default:
-		break;
-	}
-	return (DDI_FAILURE);
-}
-
-/*ARGSUSED*/
-static int
-ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
-{
-	ppb_devstate_t *ppb;
-
-	switch (cmd) {
-	case DDI_DETACH:
-		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
-
-		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi));
-		if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE)
-			ddi_fm_handler_unregister(devi);
-		if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE |
-		    DDI_FM_EREPORT_CAPABLE))
-			pci_ereport_teardown(devi);
-		mutex_destroy(&ppb->ppb_peek_poke_mutex);
-		mutex_destroy(&ppb->ppb_err_mutex);
-		ddi_fm_fini(devi);
-
-		/*
-		 * And finally free the per-pci soft state.
-		 */
-		ddi_soft_state_free(ppb_state, ddi_get_instance(devi));
-
-		/*
-		 * Uninitialize hotplug support on this bus.
-		 */
-		(void) pcihp_uninit(devi);
-		return (DDI_SUCCESS);
-
-	case DDI_SUSPEND:
-		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi));
-		ppb_save_config_regs(ppb);
-		return (DDI_SUCCESS);
-
-	default:
-		break;
-	}
-	return (DDI_FAILURE);
-}
-
-/*ARGSUSED*/
-static int
-ppb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
-	off_t offset, off_t len, caddr_t *vaddrp)
-{
-	dev_info_t *pdip;
-
-	pdip = (dev_info_t *)DEVI(dip)->devi_parent;
-	return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip,
-			rdip, mp, offset, len, vaddrp));
-}
-
-/*ARGSUSED*/
-static int
-ppb_ctlops(dev_info_t *dip, dev_info_t *rdip,
-	ddi_ctl_enum_t ctlop, void *arg, void *result)
-{
-	pci_regspec_t *drv_regp;
-	int	reglen;
-	int	rn;
-	int	totreg;
-	ppb_devstate_t *ppb;
-
-	switch (ctlop) {
-	case DDI_CTLOPS_REPORTDEV:
-		if (rdip == (dev_info_t *)0)
-			return (DDI_FAILURE);
-		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
-		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
-		    ddi_driver_name(rdip),
-		    ddi_get_instance(rdip));
-		return (DDI_SUCCESS);
-
-	case DDI_CTLOPS_INITCHILD:
-		return (ppb_initchild((dev_info_t *)arg));
-
-	case DDI_CTLOPS_UNINITCHILD:
-		ppb_removechild((dev_info_t *)arg);
-		return (DDI_SUCCESS);
-
-	case DDI_CTLOPS_SIDDEV:
-		return (DDI_SUCCESS);
-
-	case DDI_CTLOPS_REGSIZE:
-	case DDI_CTLOPS_NREGS:
-		if (rdip == (dev_info_t *)0)
-			return (DDI_FAILURE);
-		break;
-
-	case DDI_CTLOPS_PEEK:
-	case DDI_CTLOPS_POKE:
-		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(dip));
-		if (strcmp(ddi_driver_name(ddi_get_parent(dip)), "npe") != 0)
-			return (ddi_ctlops(dip, rdip, ctlop, arg, result));
-		return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
-		    ddi_ctlops, &ppb->ppb_err_mutex,
-		    &ppb->ppb_peek_poke_mutex));
-
-	default:
-		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
-	}
-
-	*(int *)result = 0;
-	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip,
-		DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
-		(caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
-		return (DDI_FAILURE);
-
-	totreg = reglen / sizeof (pci_regspec_t);
-	if (ctlop == DDI_CTLOPS_NREGS)
-		*(int *)result = totreg;
-	else if (ctlop == DDI_CTLOPS_REGSIZE) {
-		rn = *(int *)arg;
-		if (rn >= totreg) {
-			kmem_free(drv_regp, reglen);
-			return (DDI_FAILURE);
-		}
-		*(off_t *)result = drv_regp[rn].pci_size_low;
-	}
-
-	kmem_free(drv_regp, reglen);
-	return (DDI_SUCCESS);
-}
-
-static int
-ppb_name_child(dev_info_t *child, char *name, int namelen)
-{
-	pci_regspec_t *pci_rp;
-	uint_t slot, func;
-	char **unit_addr;
-	uint_t n;
-
-	/*
-	 * For .conf nodes, use unit-address property as name
-	 */
-	if (ndi_dev_is_persistent_node(child) == 0) {
-		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
-		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
-		    DDI_PROP_SUCCESS) {
-			cmn_err(CE_WARN,
-			    "cannot find unit-address in %s.conf",
-			    ddi_driver_name(child));
-			return (DDI_FAILURE);
-		}
-		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
-			cmn_err(CE_WARN, "unit-address property in %s.conf"
-			    " not well-formed", ddi_driver_name(child));
-			ddi_prop_free(unit_addr);
-			return (DDI_SUCCESS);
-		}
-		(void) snprintf(name, namelen, "%s", *unit_addr);
-		ddi_prop_free(unit_addr);
-		return (DDI_SUCCESS);
-	}
-
-	/* get child "reg" property */
-	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
-	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
-		return (DDI_FAILURE);
-	}
-
-	/* copy the device identifications */
-	slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
-	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
-
-	if (func != 0)
-		(void) snprintf(name, namelen, "%x,%x", slot, func);
-	else
-		(void) snprintf(name, namelen, "%x", slot);
-
-	ddi_prop_free(pci_rp);
-	return (DDI_SUCCESS);
-}
-
-static int
-ppb_initchild(dev_info_t *child)
-{
-	struct ddi_parent_private_data *pdptr;
-	char name[MAXNAMELEN];
-	ddi_acc_handle_t config_handle;
-	ushort_t command_preserve, command;
-#if !defined(__i386) && !defined(__amd64)
-	ushort_t bcr;
-	uchar_t header_type;
-#endif
-#if defined(__sparc)
-	int ret;
-	uchar_t min_gnt, latency_timer;
-	ppb_devstate_t *ppb;
-#endif
-
-	if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
-		return (DDI_FAILURE);
-	ddi_set_name_addr(child, name);
-
-	/*
-	 * Pseudo nodes indicate a prototype node with per-instance
-	 * properties to be merged into the real h/w device node.
-	 * The interpretation of the unit-address is DD[,F]
-	 * where DD is the device id and F is the function.
-	 */
-	if (ndi_dev_is_persistent_node(child) == 0) {
-		extern int pci_allow_pseudo_children;
-
-		ddi_set_parent_data(child, NULL);
-
-		/*
-		 * Try to merge the properties from this prototype
-		 * node into real h/w nodes.
-		 */
-		if (ndi_merge_node(child, ppb_name_child) == DDI_SUCCESS) {
-			/*
-			 * Merged ok - return failure to remove the node.
-			 */
-			ddi_set_name_addr(child, NULL);
-			return (DDI_FAILURE);
-		}
-
-		/* workaround for ddivs to run under PCI */
-		if (pci_allow_pseudo_children)
-			return (DDI_SUCCESS);
-
-		/*
-		 * The child was not merged into a h/w node,
-		 * but there's not much we can do with it other
-		 * than return failure to cause the node to be removed.
-		 */
-		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
-		    ddi_driver_name(child), ddi_get_name_addr(child),
-		    ddi_driver_name(child));
-		ddi_set_name_addr(child, NULL);
-		return (DDI_NOT_WELL_FORMED);
-	}
-
-	/* transfer select properties from PROM to kernel */
-#if	defined(__sparc)
-	if ((ret = ppb_create_pci_prop(child)) != DDI_SUCCESS)
-		return (ret);
-#endif	/* defined(__sparc) */
-
-	if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "interrupts",
-		-1) != -1) {
-		pdptr = kmem_zalloc((sizeof (struct ddi_parent_private_data) +
-		    sizeof (struct intrspec)), KM_SLEEP);
-		pdptr->par_intr = (struct intrspec *)(pdptr + 1);
-		pdptr->par_nintr = 1;
-		ddi_set_parent_data(child, pdptr);
-	} else
-		ddi_set_parent_data(child, NULL);
-
-	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
-		return (DDI_FAILURE);
-
-#if !defined(__i386) && !defined(__amd64)
-	/*
-	 * Determine the configuration header type.
-	 */
-	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
-#endif
-
-	/*
-	 * Support for the "command-preserve" property.
-	 */
-	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
-						DDI_PROP_DONTPASS,
-						"command-preserve", 0);
-	command = pci_config_get16(config_handle, PCI_CONF_COMM);
-	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
-	command |= (ppb_command_default & ~command_preserve);
-	pci_config_put16(config_handle, PCI_CONF_COMM, command);
-
-#if !defined(__i386) && !defined(__amd64)
-	/*
-	 * If the device has a bus control register then program it
-	 * based on the settings in the command register.
-	 */
-	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
-		/*
-		 * These flags should be moved to uts/common/sys/pci.h:
-		 */
-#ifndef PCI_BCNF_BCNTRL
-#define	PCI_BCNF_BCNTRL			0x3e
-#define	PCI_BCNF_BCNTRL_PARITY_ENABLE	0x0001
-#define	PCI_BCNF_BCNTRL_SERR_ENABLE	0x0002
-#define	PCI_BCNF_BCNTRL_MAST_AB_MODE	0x0020
-#endif
-		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
-		if (ppb_command_default & PCI_COMM_PARITY_DETECT)
-			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
-		if (ppb_command_default & PCI_COMM_SERR_ENABLE)
-			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
-		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
-		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
-	}
-#endif
-
-#if defined(__sparc)
-	/*
-	 * Initialize cache-line-size configuration register if needed.
-	 */
-	if (ppb_set_cache_line_size_register &&
-	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
-	    "cache-line-size", 0) == 0) {
-		ppb = ddi_get_soft_state(ppb_state,
-		    ddi_get_instance(ddi_get_parent(child)));
-		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
-		    ppb->ppb_cache_line_size);
-		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
-		if (n != 0) {
-			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
-			    "cache-line-size", n);
-		}
-	}
-
-	/*
-	 * Initialize latency timer configuration registers if needed.
-	 */
-	if (ppb_set_latency_timer_register &&
-			ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
-					"latency-timer", 0) == 0) {
-
-		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
-			latency_timer = ppb->ppb_latency_timer;
-		/*
-		 * This flags should be moved to uts/common/sys/pci.h:
-		 */
-#ifndef	PCI_BCNF_LATENCY_TIMER
-#define	PCI_BCNF_LATENCY_TIMER		0x1b
-#endif
-			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
-					ppb->ppb_latency_timer);
-		} else {
-			min_gnt = pci_config_get8(config_handle,
-						    PCI_CONF_MIN_G);
-			latency_timer = min_gnt * 8;
-		}
-		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
-				latency_timer);
-		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
-		if (n != 0) {
-			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
-					"latency-timer", n);
-		}
-	}
-#endif
-
-	pci_config_teardown(&config_handle);
-	return (DDI_SUCCESS);
-}
-
-static void
-ppb_removechild(dev_info_t *dip)
-{
-	struct ddi_parent_private_data *pdptr;
-
-	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
-		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
-		ddi_set_parent_data(dip, NULL);
-	}
-	ddi_set_name_addr(dip, NULL);
-
-	/*
-	 * Strip the node to properly convert it back to prototype form
-	 */
-	ddi_remove_minor_node(dip, NULL);
-
-	impl_rem_dev_props(dip);
-}
-
-/*
- * Transfer select properties from PROM to kernel.
- * For x86 pci is already enumerated by the kernel.
- */
-#if	defined(__sparc)
-static int
-ppb_create_pci_prop(dev_info_t *child)
-{
-	pci_regspec_t *pci_rp;
-	int	length;
-	int	value;
-
-	/* get child "reg" property */
-	value = ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_CANSLEEP,
-		"reg", (caddr_t)&pci_rp, &length);
-	if (value != DDI_SUCCESS)
-		return (value);
-
-	(void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, child, "reg",
-		(uchar_t *)pci_rp, length);
-
-	/*
-	 * free the memory allocated by ddi_getlongprop ().
-	 */
-	kmem_free(pci_rp, length);
-
-	/* assign the basic PCI Properties */
-
-	value = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_CANSLEEP,
-		"vendor-id", -1);
-	if (value != -1)
-		(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
-		"vendor-id", value);
-
-	value = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_CANSLEEP,
-		"device-id", -1);
-	if (value != -1)
-		(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
-		"device-id", value);
-
-	value = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_CANSLEEP,
-		"interrupts", -1);
-	if (value != -1)
-		(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
-		"interrupts", value);
-	return (DDI_SUCCESS);
-}
-#endif	/* defined(__sparc) */
-
-
-/*
- * ppb_save_config_regs
- *
- * This routine saves the state of the configuration registers of all
- * the child nodes of each PBM.
- *
- * used by: ppb_detach() on suspends
- *
- * return value: none
- */
-static void
-ppb_save_config_regs(ppb_devstate_t *ppb_p)
-{
-	int i;
-	dev_info_t *dip;
-	ddi_acc_handle_t config_handle;
-
-	for (i = 0, dip = ddi_get_child(ppb_p->dip); dip != NULL;
-			i++, dip = ddi_get_next_sibling(dip)) {
-
-		if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
-			cmn_err(CE_WARN, "%s%d: can't config space for %s%d\n",
-				ddi_driver_name(ppb_p->dip),
-				ddi_get_instance(ppb_p->dip),
-				ddi_driver_name(dip),
-				ddi_get_instance(dip));
-			continue;
-		}
-
-		ppb_p->config_state[i].dip = dip;
-		ppb_p->config_state[i].command =
-			pci_config_get16(config_handle, PCI_CONF_COMM);
-#if !defined(__i386) && !defined(__amd64)
-		ppb_p->config_state[i].header_type =
-			pci_config_get8(config_handle, PCI_CONF_HEADER);
-		if ((ppb_p->config_state[i].header_type & PCI_HEADER_TYPE_M) ==
-				PCI_HEADER_ONE)
-			ppb_p->config_state[i].bridge_control =
-				pci_config_get16(config_handle,
-						PCI_BCNF_BCNTRL);
-#endif
-#if defined(__sparc)
-		ppb_p->config_state[i].cache_line_size =
-			pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
-		ppb_p->config_state[i].latency_timer =
-			pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
-		if ((ppb_p->config_state[i].header_type &
-				PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
-			ppb_p->config_state[i].sec_latency_timer =
-				pci_config_get8(config_handle,
-						PCI_BCNF_LATENCY_TIMER);
-#endif
-		pci_config_teardown(&config_handle);
-	}
-	ppb_p->config_state_index = i;
-}
-
-
-/*
- * ppb_restore_config_regs
- *
- * This routine restores the state of the configuration registers of all
- * the child nodes of each PBM.
- *
- * used by: ppb_attach() on resume
- *
- * return value: none
- */
-static void
-ppb_restore_config_regs(ppb_devstate_t *ppb_p)
-{
-	int i;
-	dev_info_t *dip;
-	ddi_acc_handle_t config_handle;
-
-	for (i = 0; i < ppb_p->config_state_index; i++) {
-		dip = ppb_p->config_state[i].dip;
-		if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
-			cmn_err(CE_WARN, "%s%d: can't config space for %s%d\n",
-				ddi_driver_name(ppb_p->dip),
-				ddi_get_instance(ppb_p->dip),
-				ddi_driver_name(dip),
-				ddi_get_instance(dip));
-			continue;
-		}
-		pci_config_put16(config_handle, PCI_CONF_COMM,
-				ppb_p->config_state[i].command);
-#if !defined(__i386) && !defined(__amd64)
-		if ((ppb_p->config_state[i].header_type & PCI_HEADER_TYPE_M) ==
-				PCI_HEADER_ONE)
-			pci_config_put16(config_handle, PCI_BCNF_BCNTRL,
-					ppb_p->config_state[i].bridge_control);
-#endif
-#if defined(__sparc)
-		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
-				ppb_p->config_state[i].cache_line_size);
-		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
-				ppb_p->config_state[i].latency_timer);
-		if ((ppb_p->config_state[i].header_type &
-				PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
-			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
-				ppb_p->config_state[i].sec_latency_timer);
-#endif
-		pci_config_teardown(&config_handle);
-	}
-}
-
-#if defined(__i386) || defined(__amd64)
-
-#define	PCI_VENID_AMD			0x1022
-#define	PCI_DEVID_8132			0x7458
-#define	PCI_MSI_MAPPING_CAP_OFF		0xF4
-#define	PCI_MSI_MAPPING_CAP_MASK	0xFF01000F
-#define	PCI_MSI_MAPPING_ENABLE		0xA8010008
-
-extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
-		psm_intr_op_t, int *);
-
-/*
- * ppb_intr_ops
- */
-static int
-ppb_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
-    ddi_intr_handle_impl_t *hdlp, void *result)
-{
-	ddi_acc_handle_t config_handle;
-	ddi_intr_handle_impl_t tmp_hdl;
-	uint_t msi_mapping;
-	int types = 0;
-
-	if (intr_op != DDI_INTROP_SUPPORTED_TYPES)
-		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
-
-	DDI_INTR_NEXDBG((CE_CONT,
-	    "ppb_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
-	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
-
-	/* Fixed interrupt is supported by default */
-	*(int *)result = DDI_INTR_TYPE_FIXED;
-
-	if (psm_intr_ops == NULL || ppb_support_msi == -1) {
-		/* MSI is not allowed */
-		DDI_INTR_NEXDBG((CE_CONT, "ppb_intr_ops: psm_intr_ops == NULL "
-		    "or MSI is not allowed\n"));
-	} else if (ppb_support_msi == 1) {
-		/* MSI is always allowed */
-		DDI_INTR_NEXDBG((CE_CONT,
-		    "ppb_intr_ops: MSI is always allowed\n"));
-		if (pci_msi_get_supported_type(rdip, &types) == DDI_SUCCESS) {
-			*(int *)result |= types;
-			bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
-			tmp_hdl.ih_type = *(int *)result;
-			(void) (*psm_intr_ops)(rdip, &tmp_hdl,
-			    PSM_INTR_OP_CHECK_MSI, result);
-		}
-	} else if (pci_config_setup(pdip, &config_handle) == DDI_SUCCESS) {
-		/*
-		 * ppb_support_msi == 0
-		 * only for check special case like AMD8132 which supports MSI
-		 */
-		if ((pci_config_get16(config_handle, PCI_CONF_VENID) ==
-		    PCI_VENID_AMD) && (pci_config_get16(config_handle,
-		    PCI_CONF_DEVID) == PCI_DEVID_8132)) {
-			msi_mapping = pci_config_get32(config_handle,
-					PCI_MSI_MAPPING_CAP_OFF);
-			/* make sure MSI enable bit is on */
-			if ((msi_mapping & PCI_MSI_MAPPING_CAP_MASK) ==
-				PCI_MSI_MAPPING_ENABLE) {
-				/* MSI/X is enable */
-				DDI_INTR_NEXDBG((CE_CONT, "ppb_intr_ops: "
-				    "MSI is allowed for AMD8132\n"));
-				if (pci_msi_get_supported_type(rdip, &types)
-				    == DDI_SUCCESS) {
-					*(int *)result |= types;
-					bzero(&tmp_hdl,
-					    sizeof (ddi_intr_handle_impl_t));
-					tmp_hdl.ih_type = *(int *)result;
-					(void) (*psm_intr_ops)(rdip, &tmp_hdl,
-					    PSM_INTR_OP_CHECK_MSI, result);
-				}
-			}
-		}
-		pci_config_teardown(&config_handle);
-	}
-	DDI_INTR_NEXDBG((CE_CONT,
-	    "ppb_intr_ops: rdip 0x%p, returns supported types: 0x%x\n",
-	    (void *)rdip, *(int *)result));
-	return (DDI_SUCCESS);
-}
-#endif
-
-static int
-ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
-{
-	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
-}
-
-static int
-ppb_close(dev_t dev, int flags, int otyp, cred_t *credp)
-{
-	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
-}
-
-static int
-ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
-{
-	return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, credp,
-	    rvalp));
-}
-
-static int
-ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
-	int flags, char *name, caddr_t valuep, int *lengthp)
-{
-	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
-	    name, valuep, lengthp));
-}
-
-static int
-ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
-{
-	return (pcihp_info(dip, cmd, arg, result));
-}
-
-/*ARGSUSED*/
-static int
-ppb_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
-    ddi_iblock_cookie_t *ibc)
-{
-	ppb_devstate_t  *ppb = ddi_get_soft_state(ppb_state,
-	    ddi_get_instance(dip));
-
-	ASSERT(ibc != NULL);
-	*ibc = ppb->ppb_fm_ibc;
-
-	return (ppb->ppb_fmcap);
-}
-
-/*ARGSUSED*/
-static int
-ppb_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
-{
-	ppb_devstate_t  *ppb = ddi_get_soft_state(ppb_state,
-	    ddi_get_instance(dip));
-
-	mutex_enter(&ppb->ppb_err_mutex);
-	pci_ereport_post(dip, derr, NULL);
-	mutex_exit(&ppb->ppb_err_mutex);
-	return (derr->fme_status);
-}
--- a/usr/src/uts/common/sys/pci.h	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/uts/common/sys/pci.h	Tue Sep 19 15:47:25 2006 -0700
@@ -812,6 +812,9 @@
 #define	PCI_BASE_SIZE	4	/* size of base reg in bytes */
 #define	PCI_CONF_HDR_SIZE	256	/* configuration header size */
 #define	PCI_MAX_BUS_NUM		256		/* Maximum PCI buses allowed */
+#define	PCI_MAX_DEVICES		32		/* Max PCI devices allowed */
+#define	PCI_MAX_FUNCTIONS	8		/* Max PCI functions allowed */
+#define	PCI_MAX_CHILDREN	PCI_MAX_DEVICES * PCI_MAX_FUNCTIONS
 #define	PCI_CLK_33MHZ	(33 * 1000 * 1000)	/* 33MHz clock speed */
 #define	PCI_CLK_66MHZ	(66 * 1000 * 1000)	/* 66MHz clock speed */
 #define	PCI_CLK_133MHZ	(133 * 1000 * 1000)	/* 133MHz clock speed */
--- a/usr/src/uts/i86pc/Makefile.files	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/uts/i86pc/Makefile.files	Tue Sep 19 15:47:25 2006 -0700
@@ -111,6 +111,7 @@
 ROOTNEX_OBJS += rootnex.o
 ISANEXUS_OBJS += isa.o dma_engine.o i8237A.o
 PCINEXUS_OBJS += pci.o pci_common.o pci_kstats.o pci_tools.o
+PCI_PCINEXUS_OBJS += pci_pci.o
 
 TCIC_OBJS +=	tcic.o
 
--- a/usr/src/uts/i86pc/Makefile.i86pc.shared	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/uts/i86pc/Makefile.i86pc.shared	Tue Sep 19 15:47:25 2006 -0700
@@ -242,6 +242,7 @@
 DRV_KMODS	+= rootnex
 DRV_KMODS	+= isa
 DRV_KMODS	+= pci
+DRV_KMODS	+= pci_pci
 DRV_KMODS	+= pcie_pci
 DRV_KMODS	+= npe
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/pci/pci_pci.c	Tue Sep 19 15:47:25 2006 -0700
@@ -0,0 +1,820 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * PCI to PCI bus bridge nexus driver
+ */
+
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/modctl.h>
+#include <sys/autoconf.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/pci.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/ddifm.h>
+#include <sys/ndifm.h>
+#include <sys/fm/protocol.h>
+#include <sys/hotplug/pci/pcihp.h>
+#include <sys/pci_intr_lib.h>
+#include <sys/psm.h>
+
+/*
+ * The variable controls the default setting of the command register
+ * for pci devices.  See ppb_initchild() for details.
+ */
+static ushort_t ppb_command_default = PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO;
+
+
+static int	ppb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
+		    off_t, off_t, caddr_t *);
+static int	ppb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
+		    void *, void *);
+static int	ppb_fm_init(dev_info_t *, dev_info_t *, int,
+		    ddi_iblock_cookie_t *);
+static int	ppb_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *);
+static int	ppb_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
+		    ddi_intr_handle_impl_t *, void *);
+
+/*
+ * ppb_support_msi: Flag that controls MSI support across P2P Bridges.
+ * By default, MSI is not supported.  Special case is AMD-8132 chipset.
+ *
+ * However, MSI support behavior can be patched on a system by changing
+ * the value of this flag as shown below:-
+ *	 0 = default value, MSI is allowed only for special case (AMD-8132)
+ *	 1 = MSI supported without any checks
+ *	-1 = MSI not supported at all
+ */
+int ppb_support_msi = 0;
+
+#define	PCI_VENID_AMD			0x1022		/* AMD vendor-id */
+#define	PCI_DEVID_8132			0x7458		/* 8132 chipset id */
+#define	PCI_MSI_MAPPING_CAP_OFF		0xF4
+#define	PCI_MSI_MAPPING_CAP_MASK	0xFF01000F
+#define	PCI_MSI_MAPPING_ENABLE		0xA8010008
+
+extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
+		    psm_intr_op_t, int *);
+
+struct bus_ops ppb_bus_ops = {
+	BUSO_REV,
+	ppb_bus_map,
+	0,
+	0,
+	0,
+	i_ddi_map_fault,
+	ddi_dma_map,
+	ddi_dma_allochdl,
+	ddi_dma_freehdl,
+	ddi_dma_bindhdl,
+	ddi_dma_unbindhdl,
+	ddi_dma_flush,
+	ddi_dma_win,
+	ddi_dma_mctl,
+	ppb_ctlops,
+	ddi_bus_prop_op,
+	0,		/* (*bus_get_eventcookie)();	*/
+	0,		/* (*bus_add_eventcall)();	*/
+	0,		/* (*bus_remove_eventcall)();	*/
+	0,		/* (*bus_post_event)();		*/
+	0,		/* (*bus_intr_ctl)();		*/
+	0,		/* (*bus_config)(); 		*/
+	0,		/* (*bus_unconfig)(); 		*/
+	ppb_fm_init,	/* (*bus_fm_init)(); 		*/
+	NULL,		/* (*bus_fm_fini)(); 		*/
+	NULL,		/* (*bus_fm_access_enter)(); 	*/
+	NULL,		/* (*bus_fm_access_exit)(); 	*/
+	NULL,		/* (*bus_power)(); 	*/
+	ppb_intr_ops	/* (*bus_intr_op)(); 		*/
+};
+
+/*
+ * The goal here is to leverage off of the pcihp.c source without making
+ * changes to it.  Call into it's cb_ops directly if needed.
+ */
+static int	ppb_open(dev_t *, int, int, cred_t *);
+static int	ppb_close(dev_t, int, int, cred_t *);
+static int	ppb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static int	ppb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
+		    caddr_t, int *);
+static int	ppb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
+
+struct cb_ops ppb_cb_ops = {
+	ppb_open,			/* open */
+	ppb_close,			/* close */
+	nodev,				/* strategy */
+	nodev,				/* print */
+	nodev,				/* dump */
+	nodev,				/* read */
+	nodev,				/* write */
+	ppb_ioctl,			/* ioctl */
+	nodev,				/* devmap */
+	nodev,				/* mmap */
+	nodev,				/* segmap */
+	nochpoll,			/* poll */
+	ppb_prop_op,			/* cb_prop_op */
+	NULL,				/* streamtab */
+	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
+	CB_REV,				/* rev */
+	nodev,				/* int (*cb_aread)() */
+	nodev				/* int (*cb_awrite)() */
+};
+
+
+static int ppb_probe(dev_info_t *);
+static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
+static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
+
+struct dev_ops ppb_ops = {
+	DEVO_REV,		/* devo_rev */
+	0,			/* refcnt  */
+	ppb_info,		/* info */
+	nulldev,		/* identify */
+	ppb_probe,		/* probe */
+	ppb_attach,		/* attach */
+	ppb_detach,		/* detach */
+	nulldev,		/* reset */
+	&ppb_cb_ops,		/* driver operations */
+	&ppb_bus_ops		/* bus operations */
+};
+
+/*
+ * Module linkage information for the kernel.
+ */
+
+static struct modldrv modldrv = {
+	&mod_driverops, /* Type of module */
+	"PCI to PCI bridge nexus driver %I%",
+	&ppb_ops,	/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	(void *)&modldrv,
+	NULL
+};
+
+/*
+ * soft state pointer and structure template:
+ */
+static void *ppb_state;
+
+typedef struct {
+	dev_info_t *dip;
+	int ppb_fmcap;
+	ddi_iblock_cookie_t ppb_fm_ibc;
+	kmutex_t ppb_peek_poke_mutex;
+	kmutex_t ppb_err_mutex;
+
+	/*
+	 * cpr support:
+	 */
+	uint_t config_state_index;
+	struct {
+		dev_info_t *dip;
+		ushort_t command;
+		uchar_t cache_line_size;
+		uchar_t latency_timer;
+		uchar_t header_type;
+		uchar_t sec_latency_timer;
+		ushort_t bridge_control;
+	} config_state[PCI_MAX_CHILDREN];
+} ppb_devstate_t;
+
+
+/*
+ * forward function declarations:
+ */
+static void	ppb_removechild(dev_info_t *);
+static int	ppb_initchild(dev_info_t *child);
+static void	ppb_save_config_regs(ppb_devstate_t *ppb_p);
+static void	ppb_restore_config_regs(ppb_devstate_t *ppb_p);
+
+
+int
+_init(void)
+{
+	int e;
+
+	if ((e = ddi_soft_state_init(&ppb_state, sizeof (ppb_devstate_t),
+	    1)) == 0 && (e = mod_install(&modlinkage)) != 0)
+		ddi_soft_state_fini(&ppb_state);
+	return (e);
+}
+
+int
+_fini(void)
+{
+	int e;
+
+	if ((e = mod_remove(&modlinkage)) == 0)
+		ddi_soft_state_fini(&ppb_state);
+	return (e);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/*ARGSUSED*/
+static int
+ppb_probe(dev_info_t *devi)
+{
+	return (DDI_PROBE_SUCCESS);
+}
+
+/*ARGSUSED*/
+static int
+ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
+{
+	int instance;
+	ppb_devstate_t *ppb;
+	ddi_acc_handle_t config_handle;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+
+		/*
+		 * Make sure the "device_type" property exists.
+		 */
+		(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
+		    "device_type", "pci");
+
+		/*
+		 * Allocate and get soft state structure.
+		 */
+		instance = ddi_get_instance(devi);
+		if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS)
+			return (DDI_FAILURE);
+		ppb = ddi_get_soft_state(ppb_state, instance);
+		ppb->dip = devi;
+
+		/*
+		 * don't enable ereports if immediate child of npe
+		 */
+		if (strcmp(ddi_driver_name(ddi_get_parent(devi)), "npe") == 0)
+			ppb->ppb_fmcap = DDI_FM_ERRCB_CAPABLE |
+			    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
+		else
+			ppb->ppb_fmcap = DDI_FM_EREPORT_CAPABLE |
+			    DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
+			    DDI_FM_DMACHK_CAPABLE;
+
+		ddi_fm_init(devi, &ppb->ppb_fmcap, &ppb->ppb_fm_ibc);
+		mutex_init(&ppb->ppb_err_mutex, NULL, MUTEX_DRIVER,
+		    (void *)ppb->ppb_fm_ibc);
+		mutex_init(&ppb->ppb_peek_poke_mutex, NULL, MUTEX_DRIVER,
+		    (void *)ppb->ppb_fm_ibc);
+
+		if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE |
+		    DDI_FM_EREPORT_CAPABLE))
+			pci_ereport_setup(devi);
+		if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE)
+		    ddi_fm_handler_register(devi, ppb_fm_callback, NULL);
+
+		if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) {
+			if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE)
+				ddi_fm_handler_unregister(devi);
+			if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE |
+			    DDI_FM_EREPORT_CAPABLE))
+				pci_ereport_teardown(devi);
+			ddi_fm_fini(devi);
+			ddi_soft_state_free(ppb_state, instance);
+			return (DDI_FAILURE);
+		}
+		pci_config_teardown(&config_handle);
+
+		/*
+		 * Initialize hotplug support on this bus. At minimum
+		 * (for non hotplug bus) this would create ":devctl" minor
+		 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
+		 * to this bus.
+		 */
+		if (pcihp_init(devi) != DDI_SUCCESS)
+		    cmn_err(CE_WARN, "pci: Failed to setup hotplug framework");
+
+		ddi_report_dev(devi);
+		return (DDI_SUCCESS);
+
+	case DDI_RESUME:
+
+		/*
+		 * Get the soft state structure for the bridge.
+		 */
+		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi));
+		ppb_restore_config_regs(ppb);
+		return (DDI_SUCCESS);
+
+	default:
+		break;
+	}
+	return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int
+ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
+{
+	ppb_devstate_t *ppb;
+
+	switch (cmd) {
+	case DDI_DETACH:
+		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
+
+		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi));
+		if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE)
+			ddi_fm_handler_unregister(devi);
+		if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE |
+		    DDI_FM_EREPORT_CAPABLE))
+			pci_ereport_teardown(devi);
+		mutex_destroy(&ppb->ppb_peek_poke_mutex);
+		mutex_destroy(&ppb->ppb_err_mutex);
+		ddi_fm_fini(devi);
+
+		/*
+		 * And finally free the per-pci soft state.
+		 */
+		ddi_soft_state_free(ppb_state, ddi_get_instance(devi));
+
+		/*
+		 * Uninitialize hotplug support on this bus.
+		 */
+		(void) pcihp_uninit(devi);
+		return (DDI_SUCCESS);
+
+	case DDI_SUSPEND:
+		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi));
+		ppb_save_config_regs(ppb);
+		return (DDI_SUCCESS);
+
+	default:
+		break;
+	}
+	return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int
+ppb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
+	off_t offset, off_t len, caddr_t *vaddrp)
+{
+	dev_info_t *pdip;
+
+	pdip = (dev_info_t *)DEVI(dip)->devi_parent;
+	return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip,
+			rdip, mp, offset, len, vaddrp));
+}
+
+/*ARGSUSED*/
+static int
+ppb_ctlops(dev_info_t *dip, dev_info_t *rdip,
+	ddi_ctl_enum_t ctlop, void *arg, void *result)
+{
+	pci_regspec_t *drv_regp;
+	int	reglen;
+	int	rn;
+	int	totreg;
+	ppb_devstate_t *ppb;
+
+	switch (ctlop) {
+	case DDI_CTLOPS_REPORTDEV:
+		if (rdip == (dev_info_t *)0)
+			return (DDI_FAILURE);
+		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
+		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
+		    ddi_driver_name(rdip),
+		    ddi_get_instance(rdip));
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_INITCHILD:
+		return (ppb_initchild((dev_info_t *)arg));
+
+	case DDI_CTLOPS_UNINITCHILD:
+		ppb_removechild((dev_info_t *)arg);
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_SIDDEV:
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_REGSIZE:
+	case DDI_CTLOPS_NREGS:
+		if (rdip == (dev_info_t *)0)
+			return (DDI_FAILURE);
+		break;
+
+	case DDI_CTLOPS_PEEK:
+	case DDI_CTLOPS_POKE:
+		ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(dip));
+		if (strcmp(ddi_driver_name(ddi_get_parent(dip)), "npe") != 0)
+			return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+		return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
+		    ddi_ctlops, &ppb->ppb_err_mutex,
+		    &ppb->ppb_peek_poke_mutex));
+
+	default:
+		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+	}
+
+	*(int *)result = 0;
+	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip,
+		DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
+		(caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	totreg = reglen / sizeof (pci_regspec_t);
+	if (ctlop == DDI_CTLOPS_NREGS)
+		*(int *)result = totreg;
+	else if (ctlop == DDI_CTLOPS_REGSIZE) {
+		rn = *(int *)arg;
+		if (rn >= totreg) {
+			kmem_free(drv_regp, reglen);
+			return (DDI_FAILURE);
+		}
+		*(off_t *)result = drv_regp[rn].pci_size_low;
+	}
+
+	kmem_free(drv_regp, reglen);
+	return (DDI_SUCCESS);
+}
+
+static int
+ppb_name_child(dev_info_t *child, char *name, int namelen)
+{
+	pci_regspec_t *pci_rp;
+	uint_t slot, func;
+	char **unit_addr;
+	uint_t n;
+
+	/*
+	 * For .conf nodes, use unit-address property as name
+	 */
+	if (ndi_dev_is_persistent_node(child) == 0) {
+		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
+		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
+		    DDI_PROP_SUCCESS) {
+			cmn_err(CE_WARN,
+			    "cannot find unit-address in %s.conf",
+			    ddi_driver_name(child));
+			return (DDI_FAILURE);
+		}
+		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
+			cmn_err(CE_WARN, "unit-address property in %s.conf"
+			    " not well-formed", ddi_driver_name(child));
+			ddi_prop_free(unit_addr);
+			return (DDI_SUCCESS);
+		}
+		(void) snprintf(name, namelen, "%s", *unit_addr);
+		ddi_prop_free(unit_addr);
+		return (DDI_SUCCESS);
+	}
+
+	/* get child "reg" property */
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
+	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
+		return (DDI_FAILURE);
+	}
+
+	/* copy the device identifications */
+	slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
+	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
+
+	if (func != 0)
+		(void) snprintf(name, namelen, "%x,%x", slot, func);
+	else
+		(void) snprintf(name, namelen, "%x", slot);
+
+	ddi_prop_free(pci_rp);
+	return (DDI_SUCCESS);
+}
+
+static int
+ppb_initchild(dev_info_t *child)
+{
+	struct ddi_parent_private_data *pdptr;
+	char name[MAXNAMELEN];
+	ddi_acc_handle_t config_handle;
+	ushort_t command_preserve, command;
+
+	if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+	ddi_set_name_addr(child, name);
+
+	/*
+	 * Pseudo nodes indicate a prototype node with per-instance
+	 * properties to be merged into the real h/w device node.
+	 * The interpretation of the unit-address is DD[,F]
+	 * where DD is the device id and F is the function.
+	 */
+	if (ndi_dev_is_persistent_node(child) == 0) {
+		extern int pci_allow_pseudo_children;
+
+		ddi_set_parent_data(child, NULL);
+
+		/*
+		 * Try to merge the properties from this prototype
+		 * node into real h/w nodes.
+		 */
+		if (ndi_merge_node(child, ppb_name_child) == DDI_SUCCESS) {
+			/*
+			 * Merged ok - return failure to remove the node.
+			 */
+			ddi_set_name_addr(child, NULL);
+			return (DDI_FAILURE);
+		}
+
+		/* workaround for ddivs to run under PCI */
+		if (pci_allow_pseudo_children)
+			return (DDI_SUCCESS);
+
+		/*
+		 * The child was not merged into a h/w node,
+		 * but there's not much we can do with it other
+		 * than return failure to cause the node to be removed.
+		 */
+		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
+		    ddi_driver_name(child), ddi_get_name_addr(child),
+		    ddi_driver_name(child));
+		ddi_set_name_addr(child, NULL);
+		return (DDI_NOT_WELL_FORMED);
+	}
+
+	/* transfer select properties from PROM to kernel */
+	if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "interrupts",
+		-1) != -1) {
+		pdptr = kmem_zalloc((sizeof (struct ddi_parent_private_data) +
+		    sizeof (struct intrspec)), KM_SLEEP);
+		pdptr->par_intr = (struct intrspec *)(pdptr + 1);
+		pdptr->par_nintr = 1;
+		ddi_set_parent_data(child, pdptr);
+	} else
+		ddi_set_parent_data(child, NULL);
+
+	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
+		return (DDI_FAILURE);
+
+	/*
+	 * Support for the "command-preserve" property.
+	 */
+	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
+	    DDI_PROP_DONTPASS, "command-preserve", 0);
+	command = pci_config_get16(config_handle, PCI_CONF_COMM);
+	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
+	command |= (ppb_command_default & ~command_preserve);
+	pci_config_put16(config_handle, PCI_CONF_COMM, command);
+
+	pci_config_teardown(&config_handle);
+	return (DDI_SUCCESS);
+}
+
+static void
+ppb_removechild(dev_info_t *dip)
+{
+	struct ddi_parent_private_data *pdptr;
+
+	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
+		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
+		ddi_set_parent_data(dip, NULL);
+	}
+	ddi_set_name_addr(dip, NULL);
+
+	/*
+	 * Strip the node to properly convert it back to prototype form
+	 */
+	ddi_remove_minor_node(dip, NULL);
+
+	impl_rem_dev_props(dip);
+}
+
+/*
+ * ppb_save_config_regs
+ *
+ * This routine saves the state of the configuration registers of all
+ * the child nodes of each PBM.
+ *
+ * used by: ppb_detach() on suspends
+ *
+ * return value: none
+ */
+static void
+ppb_save_config_regs(ppb_devstate_t *ppb_p)
+{
+	int i;
+	dev_info_t *dip;
+	ddi_acc_handle_t config_handle;
+
+	for (i = 0, dip = ddi_get_child(ppb_p->dip); dip != NULL;
+			i++, dip = ddi_get_next_sibling(dip)) {
+
+		if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
+			cmn_err(CE_WARN, "%s%d: can't config space for %s%d\n",
+				ddi_driver_name(ppb_p->dip),
+				ddi_get_instance(ppb_p->dip),
+				ddi_driver_name(dip),
+				ddi_get_instance(dip));
+			continue;
+		}
+
+		ppb_p->config_state[i].dip = dip;
+		ppb_p->config_state[i].command =
+			pci_config_get16(config_handle, PCI_CONF_COMM);
+		pci_config_teardown(&config_handle);
+	}
+	ppb_p->config_state_index = i;
+}
+
+
+/*
+ * ppb_restore_config_regs
+ *
+ * This routine restores the state of the configuration registers of all
+ * the child nodes of each PBM.
+ *
+ * used by: ppb_attach() on resume
+ *
+ * return value: none
+ */
+static void
+ppb_restore_config_regs(ppb_devstate_t *ppb_p)
+{
+	int i;
+	dev_info_t *dip;
+	ddi_acc_handle_t config_handle;
+
+	for (i = 0; i < ppb_p->config_state_index; i++) {
+		dip = ppb_p->config_state[i].dip;
+		if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
+			cmn_err(CE_WARN, "%s%d: can't config space for %s%d\n",
+				ddi_driver_name(ppb_p->dip),
+				ddi_get_instance(ppb_p->dip),
+				ddi_driver_name(dip),
+				ddi_get_instance(dip));
+			continue;
+		}
+		pci_config_put16(config_handle, PCI_CONF_COMM,
+				ppb_p->config_state[i].command);
+		pci_config_teardown(&config_handle);
+	}
+}
+
+
+/*
+ * ppb_intr_ops
+ */
+static int
+ppb_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
+    ddi_intr_handle_impl_t *hdlp, void *result)
+{
+	ddi_acc_handle_t config_handle;
+	ddi_intr_handle_impl_t tmp_hdl;
+	uint_t msi_mapping;
+	int types = 0;
+
+	if (intr_op != DDI_INTROP_SUPPORTED_TYPES)
+		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
+
+	DDI_INTR_NEXDBG((CE_CONT,
+	    "ppb_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
+	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
+
+	/* Fixed interrupt is supported by default */
+	*(int *)result = DDI_INTR_TYPE_FIXED;
+
+	if (psm_intr_ops == NULL || ppb_support_msi == -1) {
+		/* MSI is not allowed */
+		DDI_INTR_NEXDBG((CE_CONT, "ppb_intr_ops: psm_intr_ops == NULL "
+		    "or MSI is not allowed\n"));
+	} else if (ppb_support_msi == 1) {
+		/* MSI is always allowed */
+		DDI_INTR_NEXDBG((CE_CONT,
+		    "ppb_intr_ops: MSI is always allowed\n"));
+		if (pci_msi_get_supported_type(rdip, &types) == DDI_SUCCESS) {
+			*(int *)result |= types;
+			bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
+			tmp_hdl.ih_type = *(int *)result;
+			(void) (*psm_intr_ops)(rdip, &tmp_hdl,
+			    PSM_INTR_OP_CHECK_MSI, result);
+		}
+	} else if (pci_config_setup(pdip, &config_handle) == DDI_SUCCESS) {
+		/*
+		 * ppb_support_msi == 0 i.e. by default, MSI is disabled
+		 * Check only for special case like AMD8132 which supports MSI
+		 */
+		if ((pci_config_get16(config_handle, PCI_CONF_VENID) ==
+		    PCI_VENID_AMD) && (pci_config_get16(config_handle,
+		    PCI_CONF_DEVID) == PCI_DEVID_8132)) {
+			msi_mapping = pci_config_get32(config_handle,
+					PCI_MSI_MAPPING_CAP_OFF);
+			/* make sure MSI enable bit is on */
+			if ((msi_mapping & PCI_MSI_MAPPING_CAP_MASK) ==
+				PCI_MSI_MAPPING_ENABLE) {
+				/* MSI/X is enable */
+				DDI_INTR_NEXDBG((CE_CONT, "ppb_intr_ops: "
+				    "MSI is allowed for AMD8132\n"));
+				if (pci_msi_get_supported_type(rdip, &types)
+				    == DDI_SUCCESS) {
+					*(int *)result |= types;
+					bzero(&tmp_hdl,
+					    sizeof (ddi_intr_handle_impl_t));
+					tmp_hdl.ih_type = *(int *)result;
+					(void) (*psm_intr_ops)(rdip, &tmp_hdl,
+					    PSM_INTR_OP_CHECK_MSI, result);
+				}
+			}
+		}
+		pci_config_teardown(&config_handle);
+	}
+	DDI_INTR_NEXDBG((CE_CONT,
+	    "ppb_intr_ops: rdip 0x%p, returns supported types: 0x%x\n",
+	    (void *)rdip, *(int *)result));
+	return (DDI_SUCCESS);
+}
+
+static int
+ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
+{
+	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
+}
+
+static int
+ppb_close(dev_t dev, int flags, int otyp, cred_t *credp)
+{
+	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
+}
+
+static int
+ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
+{
+	return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, credp,
+	    rvalp));
+}
+
+static int
+ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
+	int flags, char *name, caddr_t valuep, int *lengthp)
+{
+	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
+	    name, valuep, lengthp));
+}
+
+static int
+ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+	return (pcihp_info(dip, cmd, arg, result));
+}
+
+/*ARGSUSED*/
+static int
+ppb_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
+    ddi_iblock_cookie_t *ibc)
+{
+	ppb_devstate_t  *ppb = ddi_get_soft_state(ppb_state,
+	    ddi_get_instance(dip));
+
+	ASSERT(ibc != NULL);
+	*ibc = ppb->ppb_fm_ibc;
+
+	return (ppb->ppb_fmcap);
+}
+
+/*ARGSUSED*/
+static int
+ppb_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
+{
+	ppb_devstate_t  *ppb = ddi_get_soft_state(ppb_state,
+	    ddi_get_instance(dip));
+
+	mutex_enter(&ppb->ppb_err_mutex);
+	pci_ereport_post(dip, derr, NULL);
+	mutex_exit(&ppb->ppb_err_mutex);
+	return (derr->fme_status);
+}
--- a/usr/src/uts/i86pc/io/pciex/pcie_pci.c	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/uts/i86pc/io/pciex/pcie_pci.c	Tue Sep 19 15:47:25 2006 -0700
@@ -180,9 +180,6 @@
 	/*
 	 * cpr support:
 	 */
-#define	PCI_MAX_DEVICES		32
-#define	PCI_MAX_FUNCTIONS	8
-#define	PCI_MAX_CHILDREN	PCI_MAX_DEVICES * PCI_MAX_FUNCTIONS
 	uint_t	config_state_index;
 	struct {
 		dev_info_t	*dip;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/pci_pci/Makefile	Tue Sep 19 15:47:25 2006 -0700
@@ -0,0 +1,94 @@
+#
+# 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/i86pc/pci_pci/Makefile
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the pci_pci driver kernel module.
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= pci_pci
+OBJECTS		= $(PCI_PCINEXUS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(PCI_PCINEXUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_PSM_DRV_DIR)/$(MODULE)
+
+INC_PATH	+= -I../../i86pc
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# depends on misc/pcihp
+#
+LDFLAGS		+= -dy -Nmisc/pcihp
+
+#
+#	Override defaults to build a unique, local modstubs.o.
+#
+MODSTUBS_DIR	 = $(OBJS_DIR)
+CLEANFILES	+= $(MODSTUBS_O)
+
+#
+#	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)/i86pc/Makefile.targ
--- a/usr/src/uts/intel/Makefile.intel.shared	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/uts/intel/Makefile.intel.shared	Tue Sep 19 15:47:25 2006 -0700
@@ -341,7 +341,6 @@
 #
 #	Machine Specific Driver Modules (/kernel/drv):
 #
-DRV_KMODS	+= pci_pci
 DRV_KMODS	+= options
 $(CLOSED_BUILD)CLOSED_DRV_KMODS	+= scsi_vhci
 
--- a/usr/src/uts/intel/Makefile.rules	Tue Sep 19 15:38:37 2006 -0700
+++ b/usr/src/uts/intel/Makefile.rules	Tue Sep 19 15:47:25 2006 -0700
@@ -135,10 +135,6 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
-$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/pci_pci/%.c
-	$(COMPILE.c) -o $@ $<
-	$(CTFCONVERT_O)
-
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/os/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -221,8 +217,5 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/intel/syscall/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
-$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/pci_pci/%.c
-	@($(LHEAD) $(LINT.c) $< $(LTAIL))
-
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/os/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
--- a/usr/src/uts/intel/pci_pci/Makefile	Tue Sep 19 15:38:37 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +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/intel/pci_pci/Makefile
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the pci_pci driver kernel module.
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pci_pci
-OBJECTS		= $(PCI_PCINEXUS_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCI_PCINEXUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-
-INC_PATH	+= -I../../i86pc
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Override defaults to build a unique, local modstubs.o.
-#
-MODSTUBS_DIR	 = $(OBJS_DIR)
-CLEANFILES	+= $(MODSTUBS_O)
-
-#
-#	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)/intel/Makefile.targ
-