summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/fm/topo/modules/common/hostbridge/hostbridge.h6
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c6
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_i3866
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_sparc8
-rw-r--r--usr/src/pkgdefs/common_files/i.drvalias29
-rw-r--r--usr/src/pkgdefs/common_files/i.nametomajor7
-rw-r--r--usr/src/tools/scripts/bfu.sh12
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/io/pciex/pcie.c (renamed from usr/src/uts/common/io/pcie.c)6
-rw-r--r--usr/src/uts/common/io/pciex/pcie_fault.c (renamed from usr/src/uts/common/io/pcie_fault.c)2
-rw-r--r--usr/src/uts/common/io/pciex/pcie_pwr.c (renamed from usr/src/uts/sun4/io/px/pcie_pwr.c)33
-rw-r--r--usr/src/uts/common/io/pciex/pcieb.c2016
-rw-r--r--usr/src/uts/common/io/pciex/pcieb.conf (renamed from usr/src/uts/sun4/io/px/px_pci.conf)4
-rw-r--r--usr/src/uts/common/io/pciex/pcieb.h215
-rw-r--r--usr/src/uts/common/sys/pcie_impl.h5
-rw-r--r--usr/src/uts/common/sys/pcie_pwr.h (renamed from usr/src/uts/sun4/io/px/pcie_pwr.h)8
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_common.c12
-rw-r--r--usr/src/uts/i86pc/io/pciex/inc.flg6
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe_misc.c2
-rw-r--r--usr/src/uts/intel/Makefile.files2
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared2
-rw-r--r--usr/src/uts/intel/io/pciex/pcie_pci.c1781
-rw-r--r--usr/src/uts/intel/io/pciex/pcie_pci.conf36
-rw-r--r--usr/src/uts/intel/io/pciex/pcieb_x86.c679
-rw-r--r--usr/src/uts/intel/os/driver_aliases4
-rw-r--r--usr/src/uts/intel/os/name_to_major2
-rw-r--r--usr/src/uts/intel/pcieb/Makefile (renamed from usr/src/uts/intel/pcie_pci/Makefile)16
-rw-r--r--usr/src/uts/sparc/Makefile.files2
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared2
-rw-r--r--usr/src/uts/sparc/io/pciex/pcieb_plx.h (renamed from usr/src/uts/sun4/io/px/pxb_plx.h)10
-rw-r--r--usr/src/uts/sparc/io/pciex/pcieb_sparc.c508
-rw-r--r--usr/src/uts/sparc/os/driver_aliases13
-rw-r--r--usr/src/uts/sparc/os/name_to_major5
-rw-r--r--usr/src/uts/sparc/pcieb/Makefile (renamed from usr/src/uts/sparc/pxb_plx/Makefile)21
-rw-r--r--usr/src/uts/sparc/pcieb_bcm/Makefile (renamed from usr/src/uts/sparc/pxb_bcm/Makefile)20
-rw-r--r--usr/src/uts/sparc/px_pci/Makefile112
-rw-r--r--usr/src/uts/sun4/io/px/px.c13
-rw-r--r--usr/src/uts/sun4/io/px/px_devctl.c2
-rw-r--r--usr/src/uts/sun4/io/px/px_fm.c6
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.c2273
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.h177
-rw-r--r--usr/src/uts/sun4/io/px/px_util.c4
-rw-r--r--usr/src/uts/sun4u/io/px/px_err.c1
-rw-r--r--usr/src/uts/sun4u/io/px/px_hlib.c1
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c2
46 files changed, 3568 insertions, 4517 deletions
diff --git a/usr/src/lib/fm/topo/modules/common/hostbridge/hostbridge.h b/usr/src/lib/fm/topo/modules/common/hostbridge/hostbridge.h
index ee76315446..0854175722 100644
--- a/usr/src/lib/fm/topo/modules/common/hostbridge/hostbridge.h
+++ b/usr/src/lib/fm/topo/modules/common/hostbridge/hostbridge.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _HOSTBRIDGE_H
#define _HOSTBRIDGE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <libdevinfo.h>
#ifdef __cplusplus
@@ -45,7 +43,7 @@ extern "C" {
#define SCHIZO "pcisch"
#define PSYCHO "pcipsy"
#define NPE "npe"
-#define PCIE_PCI "pcie_pci"
+#define PCIEB "pcieb"
#define PCI_PCI "pci_pci"
#define PCI "pci"
#define PX "px"
diff --git a/usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c b/usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c
index b56d00935c..b8d89db32d 100644
--- a/usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c
+++ b/usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <fm/topo_mod.h>
#include <fm/topo_hc.h>
#include <libdevinfo.h>
@@ -120,7 +118,7 @@ pci_hostbridges_find(topo_mod_t *mod, tnode_t *ptn)
}
hbcnt++;
}
- if (strcmp(di_driver_name(cnode), PCIE_PCI) == 0) {
+ if (strcmp(di_driver_name(cnode), PCIEB) == 0) {
if (rc_process(mod, ptn, hbcnt, cnode) < 0) {
if (hbcnt == 0)
topo_node_range_destroy(ptn,
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_i386 b/usr/src/pkgdefs/SUNWckr/prototype_i386
index c36ca4dd08..8a0cdd82c4 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386
@@ -119,8 +119,8 @@ f none kernel/drv/nulldriver 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/pcie_pci 755 root sys
-f none kernel/drv/pcie_pci.conf 644 root sys
+f none kernel/drv/pcieb 755 root sys
+f none kernel/drv/pcieb.conf 644 root sys
f none kernel/drv/physmem 755 root sys
f none kernel/drv/poll 755 root sys
f none kernel/drv/power 755 root sys
@@ -338,7 +338,7 @@ f none kernel/drv/amd64/nulldriver 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/pcie_pci 755 root sys
+f none kernel/drv/amd64/pcieb 755 root sys
f none kernel/drv/amd64/physmem 755 root sys
f none kernel/drv/amd64/poll 755 root sys
f none kernel/drv/amd64/power 755 root sys
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc
index b87c24d06e..334dda12f0 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc
@@ -63,8 +63,7 @@ d none kernel/dacf/sparcv9 755 root sys
f none kernel/dacf/sparcv9/consconfig_dacf 755 root sys
f none kernel/dacf/sparcv9/net_dacf 755 root sys
f none kernel/drv/dad.conf 644 root sys
-f none kernel/drv/px_pci.conf 644 root sys
-f none kernel/drv/pxb_plx.conf 644 root sys
+f none kernel/drv/pcieb.conf 644 root sys
e sdconf kernel/drv/sd.conf 644 root sys
e preserve kernel/drv/uata.conf 644 root sys
d none kernel/drv/sparcv9 755 root sys
@@ -113,9 +112,8 @@ f none kernel/drv/sparcv9/poll 755 root sys
f none kernel/drv/sparcv9/pseudo 755 root sys
f none kernel/drv/sparcv9/ptc 755 root sys
f none kernel/drv/sparcv9/ptsl 755 root sys
-f none kernel/drv/sparcv9/px_pci 755 root sys
-f none kernel/drv/sparcv9/pxb_bcm 755 root sys
-f none kernel/drv/sparcv9/pxb_plx 755 root sys
+f none kernel/drv/sparcv9/pcieb 755 root sys
+f none kernel/drv/sparcv9/pcieb_bcm 755 root sys
f none kernel/drv/sparcv9/ramdisk 755 root sys
f none kernel/drv/sparcv9/random 755 root sys
f none kernel/drv/sparcv9/rts 755 root sys
diff --git a/usr/src/pkgdefs/common_files/i.drvalias b/usr/src/pkgdefs/common_files/i.drvalias
index 0dd7c5c391..060454af42 100644
--- a/usr/src/pkgdefs/common_files/i.drvalias
+++ b/usr/src/pkgdefs/common_files/i.drvalias
@@ -21,10 +21,9 @@
#
#
-# Copyright 2007 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"
PATH=/usr/bin:/usr/sbin:$PATH; export PATH
@@ -89,6 +88,28 @@ obsolete_sparc()
-e '/^[ ]*px_pci[ ][ ]*"pci10b5,8532"[ #].*$/d' \
-e '/^[ ]*px_pci[ ][ ]*"pci10b5,8516"$/d' \
-e '/^[ ]*px_pci[ ][ ]*"pci10b5,8516"[ #].*$/d' \
+ -e '/^[ ]*px_pci[ ][ ]*"pciexclass,060400"$/d' \
+ -e '/^[ ]*px_pci[ ][ ]*"pciexclass,060400"[ #].*$/d' \
+ -e '/^[ ]*pxb_bcm[ ][ ]*"pciex1166,103"$/d' \
+ -e '/^[ ]*pxb_bcm[ ][ ]*"pciex1166,103"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8114"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8114"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8532"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8532"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8516"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8516"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8548"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8548"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8533"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8533"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8517"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8517"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8518"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex10b5,8518"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex108e,9010"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex108e,9010"[ #].*$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex108e,9020"$/d' \
+ -e '/^[ ]*pxb_plx[ ][ ]*"pciex108e,9020"[ #].*$/d' \
-e '/^[ ]*sx[ ][ ]*SUNW,sx$/d' \
-e '/^[ ]*sx[ ][ ]*SUNW,sx[ #].*$/d' \
-e '/^[ ]*sx[ ][ ]*"SUNW,sx"$/d' \
@@ -150,6 +171,10 @@ obsolete_i386() {
-e '/^[ ]*pcie_pci[ ][ ]*"pciex1011,21"[ #].*$/d' \
-e '/^[ ]*pcie_pci[ ][ ]*"pciex1014,22"$/d' \
-e '/^[ ]*pcie_pci[ ][ ]*"pciex1014,22"[ #].*$/d' \
+ -e '/^[ ]*pcie_pci[ ][ ]*"pciexclass,060400"$/d' \
+ -e '/^[ ]*pcie_pci[ ][ ]*"pciexclass,060400"[ #].*$/d' \
+ -e '/^[ ]*pcie_pci[ ][ ]*"pciexclass,060401"$/d' \
+ -e '/^[ ]*pcie_pci[ ][ ]*"pciexclass,060401"[ #].*$/d' \
-e '/^[ ]*spwr[ ][ ]*"pci10b8,0005"$/d' \
-e '/^[ ]*spwr[ ][ ]*"pci10b8,0005"[ #].*$/d' \
-e '/^[ ]*chs[ ][ ]*"pci1014,2e"$/d' \
diff --git a/usr/src/pkgdefs/common_files/i.nametomajor b/usr/src/pkgdefs/common_files/i.nametomajor
index 12cb51d1aa..cdf1db4e90 100644
--- a/usr/src/pkgdefs/common_files/i.nametomajor
+++ b/usr/src/pkgdefs/common_files/i.nametomajor
@@ -21,10 +21,9 @@
#
#
-# 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"
PATH=/usr/bin:/usr/sbin:$PATH; export PATH
@@ -104,6 +103,9 @@ obsolete_sparc()
obs["soc"] = 1;
obs["sc_nct"] = 1;
obs["tomtppm"] = 1;
+ obs["px_pci"] = 1;
+ obs["pxb_bcm"] = 1;
+ obs["pxb_plx"] = 1;
} !($1 in obs) { print $0 }'
}
@@ -179,6 +181,7 @@ obsolete_i386()
obs["pci_to_i2o"] = 1;
obs["i2o_scsi"] = 1;
obs["i2o_bs"] = 1;
+ obs["pcie_pci"] = 1;
} !($1 in obs) { print $0 }'
}
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index 383fe21cfe..f63bc624de 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -7759,6 +7759,18 @@ mondo_loop() {
rmdir $root/usr/include/sys/i2o/ 2>/dev/null
#
+ # Remove px_pci, pxb_plx, pxb_bcm, pcie_pci
+ #
+ rm -f $root/kernel/drv/px_pci.conf
+ rm -f $root/kernel/drv/sparcv9/px_pci
+ rm -f $root/kernel/drv/pxb_plx.conf
+ rm -f $root/kernel/drv/sparcv9/pxb_plx
+ rm -f $root/kernel/drv/sparcv9/pxb_bcm
+ rm -f $root/kernel/drv/pcie_pci.conf
+ rm -f $root/kernel/drv/pcie_pci
+ rm -f $root/kernel/drv/amd64/pcie_pci
+
+ #
# Remove /usr/ccs/bin dependency files that now live in
# /usr/share/lib/ccs
#
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index bea36dc659..d06ac373ba 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1771,6 +1771,7 @@ INCLUDE_PATH += $(INC_PATH) $(CCYFLAG)$(UTSBASE)/common
#
PCIE_MISC_OBJS += pcie.o pcie_fault.o
+PCIEB_OBJS += pcieb.o pcie_pwr.o
# Chelsio N110 10G NIC driver module
#
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 6bde281698..0049e42f49 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -656,6 +656,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/hme/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/pciex/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/hotplug/hpcsvc/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1875,6 +1879,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/fcoe/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hme/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/pciex/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hotplug/hpcsvc/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/io/pcie.c b/usr/src/uts/common/io/pciex/pcie.c
index f14d4cb1ea..4f39719d6b 100644
--- a/usr/src/uts/common/io/pcie.c
+++ b/usr/src/uts/common/io/pciex/pcie.c
@@ -577,8 +577,6 @@ pcie_init_bus(dev_info_t *cdip)
/* Save the Header Type */
bus_p->bus_hdr_type = PCIE_GET(8, bus_p, PCI_CONF_HEADER);
bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
- bus_p->bus_pcie2pci_secbus = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, 0,
- "pcie2pci-sec-bus", 0);
/* 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))
@@ -1027,7 +1025,7 @@ pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
/*
* As part of the probing, the PCI fcode interpreter may setup a DMA
* request if a given card has a fcode on it using dip and rdip of the
- * AP (attachment point) i.e, dip and rdip of px/px_pci driver. In this
+ * AP (attachment point) i.e, dip and rdip of px/pcieb driver. In this
* case, return a invalid value for the bdf since we cannot get to the
* bdf value of the actual device which will be initiating this DMA.
*/
@@ -1037,7 +1035,7 @@ pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
cdip = pcie_get_my_childs_dip(dip, rdip);
/*
- * For a given rdip, return the bdf value of dip's (px or px_pci)
+ * For a given rdip, return the bdf value of dip's (px or pcieb)
* immediate child or secondary bus-id if dip is a PCIe2PCI bridge.
*
* XXX - For now, return a invalid bdf value for all PCI and PCI-X
diff --git a/usr/src/uts/common/io/pcie_fault.c b/usr/src/uts/common/io/pciex/pcie_fault.c
index 2dd656a06e..ae540274c3 100644
--- a/usr/src/uts/common/io/pcie_fault.c
+++ b/usr/src/uts/common/io/pciex/pcie_fault.c
@@ -1850,7 +1850,7 @@ pf_get_pcie_bridge(pf_data_t *pfd_p, pcie_req_id_t secbus)
for (bdg_pfd_p = pfd_p->pe_next; bdg_pfd_p;
bdg_pfd_p = bdg_pfd_p->pe_next) {
if (PCIE_IS_PCIE_BDG(PCIE_PFD2BUS(bdg_pfd_p)) &&
- PCIE_PFD2BUS(bdg_pfd_p)->bus_pcie2pci_secbus == secbus)
+ PCIE_PFD2BUS(bdg_pfd_p)->bus_bdg_secbus == secbus)
return (bdg_pfd_p);
}
diff --git a/usr/src/uts/sun4/io/px/pcie_pwr.c b/usr/src/uts/common/io/pciex/pcie_pwr.c
index fe96966b3a..bc352cfc71 100644
--- a/usr/src/uts/sun4/io/px/pcie_pwr.c
+++ b/usr/src/uts/common/io/pciex/pcie_pwr.c
@@ -19,16 +19,13 @@
* 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.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/ddi.h>
#include <sys/kmem.h>
-#include <sys/async.h>
#include <sys/sysmacros.h>
#include <sys/sunddi.h>
#include <sys/sunpm.h>
@@ -39,7 +36,7 @@
#include <sys/pcie.h>
#include <sys/pcie_impl.h>
#include <sys/promif.h> /* prom_printf */
-#include "pcie_pwr.h"
+#include <sys/pcie_pwr.h>
#if defined(DEBUG)
@@ -126,6 +123,11 @@ pcie_power(dev_info_t *dip, int component, int level)
int pmcaps = pwr_p->pwr_pmcaps;
int ret = DDI_FAILURE;
+#if defined(__i386) || defined(__amd64)
+ if (dip)
+ return (DDI_SUCCESS);
+#endif /* defined(__i386) || defined(__amd64) */
+
ASSERT(level != PM_LEVEL_UNKNOWN);
/* PM should not asking for a level, which is unsupported */
ASSERT(level == PM_LEVEL_D0 || level == PM_LEVEL_D3 ||
@@ -276,6 +278,11 @@ pcie_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
int rv = DDI_SUCCESS;
int level_allowed, comp;
+#if defined(__i386) || defined(__amd64)
+ if (dip)
+ return (DDI_SUCCESS);
+#endif /* defined(__i386) || defined(__amd64) */
+
switch (op) {
case BUS_POWER_PRE_NOTIFICATION:
case BUS_POWER_POST_NOTIFICATION:
@@ -520,7 +527,7 @@ pcie_add_comps(dev_info_t *dip, dev_info_t *cdip, pcie_pwr_t *pwr_p)
* Allocate counters per child. This is a part of pcie
* pm info. If there is no pcie pm info, allocate it here.
* pcie pm info might already be there for pci express nexus
- * driver e.g. px_pci. For all leaf nodes, it is allocated here.
+ * driver e.g. pcieb. For all leaf nodes, it is allocated here.
*/
if ((pcie_pm_p = PCIE_PMINFO(cdip)) == NULL) {
pcie_pm_p = (pcie_pm_t *)kmem_zalloc(
@@ -576,7 +583,7 @@ pcie_remove_comps(dev_info_t *dip, dev_info_t *cdip, pcie_pwr_t *pwr_p)
}
/*
- * Power management related initialization common to px and px_pci
+ * Power management related initialization common to px and pcieb
*/
int
pwr_common_setup(dev_info_t *dip)
@@ -822,7 +829,7 @@ pcie_is_pcie(dev_info_t *dip)
}
/*
- * Called by px_attach or pxb_attach:: DDI_RESUME
+ * Called by px_attach or pcieb_attach:: DDI_RESUME
*/
int
pcie_pwr_resume(dev_info_t *dip)
@@ -830,6 +837,11 @@ pcie_pwr_resume(dev_info_t *dip)
dev_info_t *cdip;
pcie_pwr_t *pwr_p = NULL;
+#if defined(__i386) || defined(__amd64)
+ if (dip)
+ return (DDI_SUCCESS);
+#endif /* defined(__i386) || defined(__amd64) */
+
if (PCIE_PMINFO(dip))
pwr_p = PCIE_NEXUS_PMINFO(dip);
@@ -908,6 +920,11 @@ pcie_pwr_suspend(dev_info_t *dip)
int *child_counters = NULL; /* per child dip counters */
pcie_pwr_t *pwr_p = NULL;
+#if defined(__i386) || defined(__amd64)
+ if (dip)
+ return (DDI_SUCCESS);
+#endif /* defined(__i386) || defined(__amd64) */
+
if (PCIE_PMINFO(dip))
pwr_p = PCIE_NEXUS_PMINFO(dip);
diff --git a/usr/src/uts/common/io/pciex/pcieb.c b/usr/src/uts/common/io/pciex/pcieb.c
new file mode 100644
index 0000000000..fa2a9d8f85
--- /dev/null
+++ b/usr/src/uts/common/io/pciex/pcieb.c
@@ -0,0 +1,2016 @@
+/*
+ * 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 x86 and SPARC PCI-E to PCI bus bridge nexus driver
+ */
+
+#include <sys/sysmacros.h>
+#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/fm/util.h>
+#include <sys/pcie.h>
+#include <sys/pci_cap.h>
+#include <sys/pcie_impl.h>
+#include <sys/hotplug/pci/pcihp.h>
+#include <sys/hotplug/pci/pciehpc.h>
+#include <sys/hotplug/pci/pcishpc.h>
+#include <sys/open.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/promif.h> /* prom_printf */
+#include <sys/disp.h>
+#include <sys/pcie_pwr.h>
+#include "pcieb.h"
+#ifdef PX_PLX
+#include <io/pciex/pcieb_plx.h>
+#endif /* PX_PLX */
+
+/*LINTLIBRARY*/
+
+/* panic flag */
+int pcieb_die = PF_ERR_FATAL_FLAGS;
+
+/* flag to turn on MSI support */
+int pcieb_enable_msi = 1;
+
+#if defined(DEBUG)
+uint_t pcieb_dbg_print = 0;
+
+static char *pcieb_debug_sym [] = { /* same sequence as pcieb_debug_bit */
+ /* 0 */ "attach",
+ /* 1 */ "pwr",
+ /* 2 */ "intr"
+};
+#endif /* DEBUG */
+
+static int pcieb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, off_t,
+ off_t, caddr_t *);
+static int pcieb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
+ void *);
+static int pcieb_fm_init(pcieb_devstate_t *pcieb_p);
+static void pcieb_fm_fini(pcieb_devstate_t *pcieb_p);
+static int pcieb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
+ ddi_iblock_cookie_t *ibc_p);
+static int pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+ ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg,
+ ddi_dma_handle_t *handlep);
+static int pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
+ ddi_dma_handle_t handle, enum ddi_dma_ctlops cmd, off_t *offp,
+ size_t *lenp, caddr_t *objp, uint_t cache_flags);
+static int pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip,
+ ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
+
+static struct bus_ops pcieb_bus_ops = {
+ BUSO_REV,
+ pcieb_bus_map,
+ 0,
+ 0,
+ 0,
+ i_ddi_map_fault,
+ ddi_dma_map,
+ pcieb_dma_allochdl,
+ ddi_dma_freehdl,
+ ddi_dma_bindhdl,
+ ddi_dma_unbindhdl,
+ ddi_dma_flush,
+ ddi_dma_win,
+ pcieb_dma_mctl,
+ pcieb_ctlops,
+ ddi_bus_prop_op,
+ ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */
+ ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */
+ ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */
+ ndi_post_event, /* (*bus_post_event)(); */
+ NULL, /* (*bus_intr_ctl)(); */
+ NULL, /* (*bus_config)(); */
+ NULL, /* (*bus_unconfig)(); */
+ pcieb_fm_init_child, /* (*bus_fm_init)(); */
+ NULL, /* (*bus_fm_fini)(); */
+ i_ndi_busop_access_enter, /* (*bus_fm_access_enter)(); */
+ i_ndi_busop_access_exit, /* (*bus_fm_access_exit)(); */
+ pcie_bus_power, /* (*bus_power)(); */
+ pcieb_intr_ops /* (*bus_intr_op)(); */
+};
+
+static int pcieb_open(dev_t *, int, int, cred_t *);
+static int pcieb_close(dev_t, int, int, cred_t *);
+static int pcieb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static int pcieb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
+ caddr_t, int *);
+static int pcieb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static uint_t pcieb_intr_handler(caddr_t arg1, caddr_t arg2);
+
+/* PM related functions */
+static int pcieb_pwr_setup(dev_info_t *dip);
+static int pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p);
+static void pcieb_pwr_teardown(dev_info_t *dip);
+static int pcieb_pwr_disable(dev_info_t *dip);
+
+/* Hotplug related functions */
+static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
+static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
+static int pcieb_init_hotplug(pcieb_devstate_t *pcieb);
+static void pcieb_id_props(pcieb_devstate_t *pcieb);
+
+/*
+ * soft state pointer
+ */
+void *pcieb_state;
+
+static struct cb_ops pcieb_cb_ops = {
+ pcieb_open, /* open */
+ pcieb_close, /* close */
+ nodev, /* strategy */
+ nodev, /* print */
+ nodev, /* dump */
+ nodev, /* read */
+ nodev, /* write */
+ pcieb_ioctl, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ nochpoll, /* poll */
+ pcieb_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 pcieb_probe(dev_info_t *);
+static int pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
+static int pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
+
+static struct dev_ops pcieb_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* refcnt */
+ pcieb_info, /* info */
+ nulldev, /* identify */
+ pcieb_probe, /* probe */
+ pcieb_attach, /* attach */
+ pcieb_detach, /* detach */
+ nulldev, /* reset */
+ &pcieb_cb_ops, /* driver operations */
+ &pcieb_bus_ops, /* bus operations */
+ pcie_power, /* power */
+ ddi_quiesce_not_needed, /* quiesce */
+};
+
+/*
+ * Module linkage information for the kernel.
+ */
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* Type of module */
+ "PCIe to PCI nexus driver",
+ &pcieb_ops, /* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modldrv,
+ NULL
+};
+
+/*
+ * forward function declarations:
+ */
+static void pcieb_uninitchild(dev_info_t *);
+static int pcieb_initchild(dev_info_t *child);
+static void pcieb_create_ranges_prop(dev_info_t *, ddi_acc_handle_t);
+static boolean_t pcieb_is_pcie_device_type(dev_info_t *dip);
+
+/* interrupt related declarations */
+static int pcieb_msi_supported(dev_info_t *);
+static int pcieb_intr_attach(pcieb_devstate_t *pcieb);
+static int pcieb_intr_init(pcieb_devstate_t *pcieb_p, int intr_type);
+static void pcieb_intr_fini(pcieb_devstate_t *pcieb_p);
+
+int
+_init(void)
+{
+ int e;
+
+ if ((e = ddi_soft_state_init(&pcieb_state, sizeof (pcieb_devstate_t),
+ 1)) == 0 && (e = mod_install(&modlinkage)) != 0)
+ ddi_soft_state_fini(&pcieb_state);
+ return (e);
+}
+
+int
+_fini(void)
+{
+ int e;
+
+ if ((e = mod_remove(&modlinkage)) == 0) {
+ ddi_soft_state_fini(&pcieb_state);
+ }
+ return (e);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+/*ARGSUSED*/
+static int
+pcieb_probe(dev_info_t *devi)
+{
+ return (DDI_PROBE_SUCCESS);
+}
+
+static int
+pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
+{
+ int instance;
+ char device_type[8];
+ pcieb_devstate_t *pcieb;
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(devi);
+ ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
+ uint8_t dev_type = bus_p->bus_dev_type;
+
+ switch (cmd) {
+ case DDI_RESUME:
+ (void) pcie_pwr_resume(devi);
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+
+ case DDI_ATTACH:
+ break;
+ }
+
+ if (!(PCIE_IS_BDG(bus_p))) {
+ PCIEB_DEBUG(DBG_ATTACH, devi, "This is not a switch or"
+ " bridge\n");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * If PCIE_LINKCTL_LINK_DISABLE bit in the PCIe Config
+ * Space (PCIe Capability Link Control Register) is set,
+ * then do not bind the driver.
+ */
+ if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & PCIE_LINKCTL_LINK_DISABLE)
+ return (DDI_FAILURE);
+
+ /*
+ * Allocate and get soft state structure.
+ */
+ instance = ddi_get_instance(devi);
+ if (ddi_soft_state_zalloc(pcieb_state, instance) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ pcieb = ddi_get_soft_state(pcieb_state, instance);
+ pcieb->pcieb_dip = devi;
+ pcieb->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED;
+
+ if ((pcieb_fm_init(pcieb)) != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_ATTACH, devi, "Failed in pcieb_fm_init\n");
+ goto fail;
+ }
+ pcieb->pcieb_init_flags |= PCIEB_INIT_FM;
+
+ mutex_init(&pcieb->pcieb_mutex, NULL, MUTEX_DRIVER, NULL);
+ mutex_init(&pcieb->pcieb_err_mutex, NULL, MUTEX_DRIVER,
+ (void *)pcieb->pcieb_fm_ibc);
+ mutex_init(&pcieb->pcieb_peek_poke_mutex, NULL, MUTEX_DRIVER,
+ (void *)pcieb->pcieb_fm_ibc);
+
+ /* create special properties for device identification */
+ pcieb_id_props(pcieb);
+
+ /*
+ * Power management setup. This also makes sure that switch/bridge
+ * is at D0 during attach.
+ */
+ if (pwr_common_setup(devi) != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_PWR, devi, "pwr_common_setup failed\n");
+ goto fail;
+ }
+
+ if (pcieb_pwr_setup(devi) != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_PWR, devi, "pxb_pwr_setup failed \n");
+ goto fail;
+ }
+
+ /*
+ * Make sure the "device_type" property exists.
+ */
+ if (pcieb_is_pcie_device_type(devi))
+ (void) strcpy(device_type, "pciex");
+ else
+ (void) strcpy(device_type, "pci");
+
+ (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
+ "device_type", device_type);
+
+ /*
+ * Check whether the "ranges" property is present.
+ * Otherwise create the ranges property by reading
+ * the configuration registers
+ */
+ if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
+ "ranges") == 0) {
+ pcieb_create_ranges_prop(devi, config_handle);
+ }
+
+ if (PCIE_IS_PCI_BDG(bus_p))
+ pcieb_set_pci_perf_parameters(devi, config_handle);
+
+#ifdef PX_PLX
+ pcieb_attach_plx_workarounds(pcieb);
+#endif /* PX_PLX */
+
+ /* Initialize hotplug */
+ pcieb->pcieb_hotplug_capable = B_FALSE;
+
+ if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
+ (void) pcieb_init_hotplug(pcieb);
+ }
+
+ /*
+ * Initialize interrupt handlers. Ignore return value.
+ */
+ (void) pcieb_intr_attach(pcieb);
+
+ if (pcieb->pcieb_hotplug_capable == B_FALSE) {
+ /*
+ * (for non hotplug bus) this would create ":devctl" minor
+ * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
+ * to this bus.
+ */
+ if (ddi_create_minor_node(devi, "devctl", S_IFCHR,
+ PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR),
+ DDI_NT_NEXUS, 0) != DDI_SUCCESS)
+ goto fail;
+ }
+
+ PCIEB_DEBUG(DBG_ATTACH, devi,
+ "pcieb_attach: this nexus %s hotplug slots\n",
+ pcieb->pcieb_hotplug_capable == B_TRUE ? "has":"has no");
+
+ /* Do any platform specific workarounds needed at this time */
+ pcieb_plat_attach_workaround(devi);
+
+ /*
+ * If this is a root port, determine and set the max payload size.
+ * Since this will involve scanning the fabric, all error enabling
+ * and sw workarounds should be in place before doing this.
+ */
+ if (PCIE_IS_RP(bus_p))
+ pcie_init_root_port_mps(devi);
+
+ ddi_report_dev(devi);
+ return (DDI_SUCCESS);
+
+fail:
+ (void) pcieb_detach(devi, DDI_DETACH);
+ return (DDI_FAILURE);
+}
+
+static int
+pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
+{
+ pcieb_devstate_t *pcieb;
+ int error = DDI_SUCCESS;
+
+ switch (cmd) {
+ case DDI_SUSPEND:
+ error = pcie_pwr_suspend(devi);
+ return (error);
+
+ case DDI_DETACH:
+ break;
+
+ default:
+ return (DDI_FAILURE);
+ }
+
+ pcieb = ddi_get_soft_state(pcieb_state, ddi_get_instance(devi));
+
+ /* remove interrupt handlers */
+ pcieb_intr_fini(pcieb);
+
+ if (pcieb->pcieb_hotplug_capable == B_TRUE) {
+ if (pcihp_uninit(devi) == DDI_FAILURE)
+ error = DDI_FAILURE;
+
+ if (pcieb->pcieb_hpc_type == HPC_PCIE)
+ (void) pciehpc_uninit(devi);
+ else if (pcieb->pcieb_hpc_type == HPC_SHPC)
+ (void) pcishpc_uninit(devi);
+ } else {
+ ddi_remove_minor_node(devi, "devctl");
+ }
+
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
+
+ (void) ndi_prop_remove(DDI_DEV_T_NONE, pcieb->pcieb_dip,
+ "pcie_ce_mask");
+
+ if (pcieb->pcieb_init_flags & PCIEB_INIT_FM)
+ pcieb_fm_fini(pcieb);
+
+ pcieb_pwr_teardown(devi);
+ pwr_common_teardown(devi);
+
+ mutex_destroy(&pcieb->pcieb_peek_poke_mutex);
+ mutex_destroy(&pcieb->pcieb_err_mutex);
+ mutex_destroy(&pcieb->pcieb_mutex);
+
+ /*
+ * And finally free the per-pci soft state.
+ */
+ ddi_soft_state_free(pcieb_state, ddi_get_instance(devi));
+
+ return (DDI_SUCCESS);
+}
+
+static int
+pcieb_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));
+}
+
+static int
+pcieb_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;
+ pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
+ ddi_get_instance(dip));
+ struct detachspec *ds;
+ struct attachspec *as;
+
+ switch (ctlop) {
+ case DDI_CTLOPS_REPORTDEV:
+ if (rdip == (dev_info_t *)0)
+ return (DDI_FAILURE);
+ cmn_err(CE_CONT, "?PCIE-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 (pcieb_initchild((dev_info_t *)arg));
+
+ case DDI_CTLOPS_UNINITCHILD:
+ pcieb_uninitchild((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:
+ return (pcieb_plat_peekpoke(dip, rdip, ctlop, arg, result));
+ case DDI_CTLOPS_ATTACH:
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
+ as = (struct attachspec *)arg;
+ switch (as->when) {
+ case DDI_PRE:
+ if (as->cmd == DDI_RESUME) {
+ pcie_clear_errors(rdip);
+ if (pcieb_plat_ctlops(rdip, ctlop, arg) !=
+ DDI_SUCCESS)
+ return (DDI_FAILURE);
+ }
+
+ if (as->cmd == DDI_ATTACH)
+ return (pcie_pm_hold(dip));
+
+ return (DDI_SUCCESS);
+
+ case DDI_POST:
+ if (as->cmd == DDI_ATTACH && as->result != DDI_SUCCESS)
+ pcie_pm_release(dip);
+
+ if (as->result == DDI_SUCCESS) {
+ pf_init(rdip, (void *)pcieb->pcieb_fm_ibc,
+ as->cmd);
+
+ (void) pcieb_plat_ctlops(rdip, ctlop, arg);
+ }
+
+ /*
+ * For empty hotplug-capable slots, we should explicitly
+ * disable the errors, so that we won't panic upon
+ * unsupported hotplug messages.
+ */
+ if ((!ddi_prop_exists(DDI_DEV_T_ANY, rdip,
+ DDI_PROP_DONTPASS, "hotplug-capable")) ||
+ ddi_get_child(rdip)) {
+ (void) pcie_postattach_child(rdip);
+ return (DDI_SUCCESS);
+ }
+
+ pcie_disable_errors(rdip);
+
+ return (DDI_SUCCESS);
+ default:
+ break;
+ }
+ return (DDI_SUCCESS);
+
+ case DDI_CTLOPS_DETACH:
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
+ ds = (struct detachspec *)arg;
+ switch (ds->when) {
+ case DDI_PRE:
+ pf_fini(rdip, ds->cmd);
+ return (DDI_SUCCESS);
+
+ case DDI_POST:
+ if (pcieb_plat_ctlops(rdip, ctlop, arg) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ if (ds->cmd == DDI_DETACH &&
+ ds->result == DDI_SUCCESS) {
+ return (pcie_pm_remove_child(dip, rdip));
+ }
+ return (DDI_SUCCESS);
+ default:
+ break;
+ }
+ return (DDI_SUCCESS);
+ 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 |
+ ((uint64_t)drv_regp[rn].pci_size_hi << 32);
+ }
+
+ kmem_free(drv_regp, reglen);
+ return (DDI_SUCCESS);
+}
+
+/*
+ * name_child
+ *
+ * This function is called from init_child to name a node. It is
+ * also passed as a callback for node merging functions.
+ *
+ * return value: DDI_SUCCESS, DDI_FAILURE
+ */
+static int
+pcieb_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_FAILURE);
+ }
+ (void) snprintf(name, namelen, "%s", *unit_addr);
+ ddi_prop_free(unit_addr);
+ return (DDI_SUCCESS);
+ }
+
+ /*
+ * Get the address portion of the node name based on
+ * the function and device number.
+ */
+ 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[0].pci_phys_hi);
+ func = PCI_REG_FUNC_G(pci_rp[0].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
+pcieb_initchild(dev_info_t *child)
+{
+ char name[MAXNAMELEN];
+ int result = DDI_FAILURE;
+ pcieb_devstate_t *pcieb =
+ (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
+ ddi_get_instance(ddi_get_parent(child)));
+
+ /*
+ * Name the child
+ */
+ if (pcieb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) {
+ result = DDI_FAILURE;
+ goto done;
+ }
+ 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;
+
+ /*
+ * Try to merge the properties from this prototype
+ * node into real h/w nodes.
+ */
+ if (ndi_merge_node(child, pcieb_name_child) != DDI_SUCCESS) {
+ /*
+ * Merged ok - return failure to remove the node.
+ */
+ ddi_set_name_addr(child, NULL);
+ result = DDI_FAILURE;
+ goto done;
+ }
+
+ /* workaround for ddivs to run under PCI-E */
+ if (pci_allow_pseudo_children) {
+ result = DDI_SUCCESS;
+ goto done;
+ }
+
+ /*
+ * 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);
+ result = DDI_NOT_WELL_FORMED;
+ goto done;
+ }
+
+ /* platform specific initchild */
+ pcieb_plat_initchild(child);
+
+ if (pcie_pm_hold(pcieb->pcieb_dip) != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_PWR, pcieb->pcieb_dip,
+ "INITCHILD: px_pm_hold failed\n");
+ result = DDI_FAILURE;
+ goto done;
+ }
+ /* Any return from here must call pcie_pm_release */
+
+ /*
+ * If configuration registers were previously saved by
+ * child (before it entered D3), then let the child do the
+ * restore to set up the config regs as it'll first need to
+ * power the device out of D3.
+ */
+ if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
+ "config-regs-saved-by-child") == 1) {
+ PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child),
+ "INITCHILD: config regs to be restored by child"
+ " for %s@%s\n", ddi_node_name(child),
+ ddi_get_name_addr(child));
+
+ result = DDI_SUCCESS;
+ goto cleanup;
+ }
+
+ PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child),
+ "INITCHILD: config regs setup for %s@%s\n",
+ ddi_node_name(child), ddi_get_name_addr(child));
+
+ if (!pcie_init_bus(child) || pcie_initchild(child) != DDI_SUCCESS) {
+ result = DDI_FAILURE;
+ goto cleanup;
+ }
+
+#ifdef PX_PLX
+ if (pcieb_init_plx_workarounds(pcieb, child) == DDI_FAILURE) {
+ result = DDI_FAILURE;
+ goto cleanup;
+ }
+#endif /* PX_PLX */
+
+ result = DDI_SUCCESS;
+cleanup:
+ pcie_pm_release(pcieb->pcieb_dip);
+done:
+ return (result);
+}
+
+static void
+pcieb_uninitchild(dev_info_t *dip)
+{
+
+ pcie_uninitchild(dip);
+
+ pcieb_plat_uninitchild(dip);
+
+ ddi_set_name_addr(dip, NULL);
+
+ /*
+ * Strip the node to properly convert it back to prototype form
+ */
+ ddi_remove_minor_node(dip, NULL);
+
+ ddi_prop_remove_all(dip);
+}
+
+static boolean_t
+pcieb_is_pcie_device_type(dev_info_t *dip)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+
+ if (PCIE_IS_SW(bus_p) || PCIE_IS_RP(bus_p) || PCIE_IS_PCI2PCIE(bus_p))
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+static int
+pcieb_intr_attach(pcieb_devstate_t *pcieb)
+{
+ int intr_types;
+ dev_info_t *dip = pcieb->pcieb_dip;
+
+ /* Allow platform specific code to do any initialization first */
+ pcieb_plat_intr_attach(pcieb);
+
+ /*
+ * Initialize interrupt handlers.
+ * If both MSI and FIXED are supported, try to attach MSI first.
+ * If MSI fails for any reason, then try FIXED, but only allow one
+ * type to be attached.
+ */
+ if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_supported_types"
+ " failed\n");
+ goto FAIL;
+ }
+
+ if ((intr_types & DDI_INTR_TYPE_MSI) &&
+ (pcieb_msi_supported(dip) == DDI_SUCCESS)) {
+ if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_MSI) == DDI_SUCCESS)
+ intr_types = DDI_INTR_TYPE_MSI;
+ else {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "Unable to attach MSI"
+ " handler\n");
+ }
+ }
+
+ if (intr_types != DDI_INTR_TYPE_MSI) {
+ /*
+ * MSIs are not supported or MSI initialization failed. For Root
+ * Ports mark this so error handling might try to fallback to
+ * some other mechanism if available (machinecheck etc.).
+ */
+ if (PCIE_IS_RP(PCIE_DIP2UPBUS(dip)))
+ pcieb->pcieb_no_aer_msi = B_TRUE;
+ }
+
+ if (intr_types & DDI_INTR_TYPE_FIXED) {
+ if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_FIXED) !=
+ DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_ATTACH, dip,
+ "Unable to attach INTx handler\n");
+ goto FAIL;
+ }
+ }
+ return (DDI_SUCCESS);
+
+FAIL:
+ return (DDI_FAILURE);
+}
+
+/*
+ * This function initializes internally generated interrupts only.
+ * It does not affect any interrupts generated by downstream devices
+ * or the forwarding of them.
+ *
+ * Enable Device Specific Interrupts or Hotplug features here.
+ * Enabling features may change how many interrupts are requested
+ * by the device. If features are not enabled first, the
+ * device might not ask for any interrupts.
+ */
+static int
+pcieb_intr_init(pcieb_devstate_t *pcieb, int intr_type)
+{
+ dev_info_t *dip = pcieb->pcieb_dip;
+ int nintrs, request, count, x;
+ int intr_cap = 0;
+ int inum = 0;
+ int ret, hp_msi_off;
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
+ uint16_t vendorid = bus_p->bus_dev_ven_id & 0xFFFF;
+ boolean_t is_hp = B_FALSE;
+ boolean_t is_pme = B_FALSE;
+
+ PCIEB_DEBUG(DBG_ATTACH, dip, "pcieb_intr_init: Attaching %s handler\n",
+ (intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx");
+
+ request = 0;
+ if (pcieb->pcieb_hotplug_capable) {
+ request++;
+ is_hp = B_TRUE;
+ }
+
+ /*
+ * Hotplug and PME share the same MSI vector. If hotplug is not
+ * supported check if MSI is needed for PME.
+ */
+ if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p) &&
+ (vendorid == NVIDIA_VENDOR_ID)) {
+ is_pme = B_TRUE;
+ if (!is_hp)
+ request++;
+ }
+
+ /*
+ * Setup MSI if this device is a Rootport and has AER. Currently no
+ * SPARC Root Port supports fabric errors being reported through it.
+ */
+ if (intr_type == DDI_INTR_TYPE_MSI) {
+ if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p))
+ request++;
+ }
+
+ if (request == 0)
+ return (DDI_SUCCESS);
+
+ /*
+ * Get number of supported interrupts.
+ *
+ * Several Bridges/Switches will not have this property set, resulting
+ * in a FAILURE, if the device is not configured in a way that
+ * interrupts are needed. (eg. hotplugging)
+ */
+ ret = ddi_intr_get_nintrs(dip, intr_type, &nintrs);
+ if ((ret != DDI_SUCCESS) || (nintrs == 0)) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_nintrs ret:%d"
+ " req:%d\n", ret, nintrs);
+ return (DDI_FAILURE);
+ }
+
+ PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0x%x: ddi_intr_get_nintrs: nintrs %d",
+ " request %d\n", bus_p->bus_bdf, nintrs, request);
+
+ if (request > nintrs)
+ request = nintrs;
+
+ /* Allocate an array of interrupt handlers */
+ pcieb->pcieb_htable_size = sizeof (ddi_intr_handle_t) * request;
+ pcieb->pcieb_htable = kmem_zalloc(pcieb->pcieb_htable_size,
+ KM_SLEEP);
+ pcieb->pcieb_init_flags |= PCIEB_INIT_HTABLE;
+
+ ret = ddi_intr_alloc(dip, pcieb->pcieb_htable, intr_type, inum,
+ request, &count, DDI_INTR_ALLOC_NORMAL);
+ if ((ret != DDI_SUCCESS) || (count == 0)) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_alloc() ret: %d ask: %d"
+ " actual: %d\n", ret, request, count);
+ goto FAIL;
+ }
+ pcieb->pcieb_init_flags |= PCIEB_INIT_ALLOC;
+
+ /* Save the actual number of interrupts allocated */
+ pcieb->pcieb_intr_count = count;
+ if (count < request) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0%x: Requested Intr: %d"
+ " Received: %d\n", bus_p->bus_bdf, request, count);
+ }
+
+ /*
+ * NVidia (MCP55 and other) chipsets have a errata that if the number
+ * of requested MSI intrs is not allocated we have to fall back to INTx.
+ */
+ if (intr_type == DDI_INTR_TYPE_MSI) {
+ if (PCIE_IS_RP(bus_p) && (vendorid == NVIDIA_VENDOR_ID)) {
+ if (request != count)
+ goto FAIL;
+ }
+ }
+
+ /* Get interrupt priority */
+ ret = ddi_intr_get_pri(pcieb->pcieb_htable[0],
+ &pcieb->pcieb_intr_priority);
+ if (ret != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_pri() ret: %d\n",
+ ret);
+ goto FAIL;
+ }
+
+ if (pcieb->pcieb_intr_priority >= LOCK_LEVEL) {
+ pcieb->pcieb_intr_priority = LOCK_LEVEL - 1;
+ ret = ddi_intr_set_pri(pcieb->pcieb_htable[0],
+ pcieb->pcieb_intr_priority);
+ if (ret != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_set_pri() ret:"
+ " %d\n", ret);
+
+ goto FAIL;
+ }
+ }
+
+ mutex_init(&pcieb->pcieb_intr_mutex, NULL, MUTEX_DRIVER, NULL);
+
+ pcieb->pcieb_init_flags |= PCIEB_INIT_MUTEX;
+
+ for (count = 0; count < pcieb->pcieb_intr_count; count++) {
+ ret = ddi_intr_add_handler(pcieb->pcieb_htable[count],
+ pcieb_intr_handler, (caddr_t)pcieb,
+ (caddr_t)(uintptr_t)(inum + count));
+
+ if (ret != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "Cannot add "
+ "interrupt(%d)\n", ret);
+ break;
+ }
+ }
+
+ /* If unsucessful, remove the added handlers */
+ if (ret != DDI_SUCCESS) {
+ for (x = 0; x < count; x++) {
+ (void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]);
+ }
+ goto FAIL;
+ }
+
+ pcieb->pcieb_init_flags |= PCIEB_INIT_HANDLER;
+
+ (void) ddi_intr_get_cap(pcieb->pcieb_htable[0], &intr_cap);
+
+ /*
+ * Get this intr lock because we are not quite ready to handle
+ * interrupts immediately after enabling it. The MSI multi register
+ * gets programmed in ddi_intr_enable after which we need to get the
+ * MSI offsets for Hotplug/AER.
+ */
+ mutex_enter(&pcieb->pcieb_intr_mutex);
+
+ if (intr_cap & DDI_INTR_FLAG_BLOCK) {
+ (void) ddi_intr_block_enable(pcieb->pcieb_htable,
+ pcieb->pcieb_intr_count);
+ pcieb->pcieb_init_flags |= PCIEB_INIT_BLOCK;
+ } else {
+ for (count = 0; count < pcieb->pcieb_intr_count; count++) {
+ (void) ddi_intr_enable(pcieb->pcieb_htable[count]);
+ }
+ }
+ pcieb->pcieb_init_flags |= PCIEB_INIT_ENABLE;
+
+ /* Save the interrupt type */
+ pcieb->pcieb_intr_type = intr_type;
+
+ /* Get the MSI offset for hotplug/PME from the PCIe cap reg */
+ if (intr_type == DDI_INTR_TYPE_MSI) {
+ hp_msi_off = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL,
+ bus_p->bus_pcie_off, PCIE_PCIECAP) &
+ PCIE_PCIECAP_INT_MSG_NUM;
+
+ if (hp_msi_off >= count) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in PCIe "
+ "cap > max allocated %d\n", hp_msi_off, count);
+ mutex_exit(&pcieb->pcieb_intr_mutex);
+ goto FAIL;
+ }
+
+ if (is_hp)
+ pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_HP;
+
+ if (is_pme)
+ pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_PME;
+ } else {
+ /* INTx handles only Hotplug interrupts */
+ if (is_hp)
+ pcieb->pcieb_isr_tab[0] |= PCIEB_INTR_SRC_HP;
+ }
+
+
+ /*
+ * Get the MSI offset for errors from the AER Root Error status
+ * register.
+ */
+ if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p)) {
+ if (PCIE_HAS_AER(bus_p)) {
+ int aer_msi_off;
+ aer_msi_off = (PCI_XCAP_GET32(bus_p->bus_cfg_hdl, NULL,
+ bus_p->bus_aer_off, PCIE_AER_RE_STS) >>
+ PCIE_AER_RE_STS_MSG_NUM_SHIFT) &
+ PCIE_AER_RE_STS_MSG_NUM_MASK;
+
+ if (aer_msi_off >= count) {
+ PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in"
+ " AER cap > max allocated %d\n",
+ aer_msi_off, count);
+ mutex_exit(&pcieb->pcieb_intr_mutex);
+ goto FAIL;
+ }
+ pcieb->pcieb_isr_tab[aer_msi_off] |= PCIEB_INTR_SRC_AER;
+ } else {
+ /*
+ * This RP does not have AER. Fallback to the
+ * SERR+Machinecheck approach if available.
+ */
+ pcieb->pcieb_no_aer_msi = B_TRUE;
+ }
+ }
+
+ mutex_exit(&pcieb->pcieb_intr_mutex);
+
+ return (DDI_SUCCESS);
+
+FAIL:
+ return (DDI_FAILURE);
+}
+
+static void
+pcieb_intr_fini(pcieb_devstate_t *pcieb)
+{
+ int x;
+ int count = pcieb->pcieb_intr_count;
+ int flags = pcieb->pcieb_init_flags;
+
+ if ((flags & PCIEB_INIT_ENABLE) &&
+ (flags & PCIEB_INIT_BLOCK)) {
+ (void) ddi_intr_block_disable(pcieb->pcieb_htable, count);
+ flags &= ~(PCIEB_INIT_ENABLE |
+ PCIEB_INIT_BLOCK);
+ }
+
+ if (flags & PCIEB_INIT_MUTEX)
+ mutex_destroy(&pcieb->pcieb_intr_mutex);
+
+ for (x = 0; x < count; x++) {
+ if (flags & PCIEB_INIT_ENABLE)
+ (void) ddi_intr_disable(pcieb->pcieb_htable[x]);
+
+ if (flags & PCIEB_INIT_HANDLER)
+ (void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]);
+
+ if (flags & PCIEB_INIT_ALLOC)
+ (void) ddi_intr_free(pcieb->pcieb_htable[x]);
+ }
+
+ flags &= ~(PCIEB_INIT_ENABLE | PCIEB_INIT_HANDLER | PCIEB_INIT_ALLOC |
+ PCIEB_INIT_MUTEX);
+
+ if (flags & PCIEB_INIT_HTABLE)
+ kmem_free(pcieb->pcieb_htable, pcieb->pcieb_htable_size);
+
+ flags &= ~PCIEB_INIT_HTABLE;
+
+ pcieb->pcieb_init_flags &= flags;
+}
+
+/*
+ * Checks if this device needs MSIs enabled or not.
+ */
+/*ARGSUSED*/
+static int
+pcieb_msi_supported(dev_info_t *dip)
+{
+ return ((pcieb_enable_msi && pcieb_plat_msi_supported(dip)) ?
+ DDI_SUCCESS: DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+int
+pcieb_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
+ ddi_iblock_cookie_t *ibc)
+{
+ pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
+ ddi_get_instance(dip));
+
+ ASSERT(ibc != NULL);
+ *ibc = pcieb->pcieb_fm_ibc;
+
+ return (DEVI(dip)->devi_fmhdl->fh_cap | DDI_FM_ACCCHK_CAPABLE |
+ DDI_FM_DMACHK_CAPABLE);
+}
+
+static int
+pcieb_fm_init(pcieb_devstate_t *pcieb_p)
+{
+ dev_info_t *dip = pcieb_p->pcieb_dip;
+ int fm_cap = DDI_FM_EREPORT_CAPABLE;
+
+ /*
+ * Request our capability level and get our parents capability
+ * and ibc.
+ */
+ ddi_fm_init(dip, &fm_cap, &pcieb_p->pcieb_fm_ibc);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * Breakdown our FMA resources
+ */
+static void
+pcieb_fm_fini(pcieb_devstate_t *pcieb_p)
+{
+ /*
+ * Clean up allocated fm structures
+ */
+ ddi_fm_fini(pcieb_p->pcieb_dip);
+}
+
+static int
+pcieb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
+{
+ pcieb_devstate_t *pcieb_p;
+ minor_t minor = getminor(*devp);
+ int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+
+ /*
+ * Make sure the open is for the right file type.
+ */
+ if (otyp != OTYP_CHR)
+ return (EINVAL);
+
+ /*
+ * Get the soft state structure for the device.
+ */
+ pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
+ instance);
+
+ if (pcieb_p == NULL)
+ return (ENXIO);
+
+ if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
+ return ((pcihp_get_cb_ops())->cb_open(devp, flags,
+ otyp, credp));
+
+ /*
+ * Handle the open by tracking the device state.
+ */
+ mutex_enter(&pcieb_p->pcieb_mutex);
+ if (flags & FEXCL) {
+ if (pcieb_p->pcieb_soft_state != PCIEB_SOFT_STATE_CLOSED) {
+ mutex_exit(&pcieb_p->pcieb_mutex);
+ return (EBUSY);
+ }
+ pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN_EXCL;
+ } else {
+ if (pcieb_p->pcieb_soft_state == PCIEB_SOFT_STATE_OPEN_EXCL) {
+ mutex_exit(&pcieb_p->pcieb_mutex);
+ return (EBUSY);
+ }
+ pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN;
+ }
+ mutex_exit(&pcieb_p->pcieb_mutex);
+ return (0);
+}
+
+static int
+pcieb_close(dev_t dev, int flags, int otyp, cred_t *credp)
+{
+ pcieb_devstate_t *pcieb_p;
+ minor_t minor = getminor(dev);
+ int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+
+ if (otyp != OTYP_CHR)
+ return (EINVAL);
+
+ pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
+ instance);
+
+ if (pcieb_p == NULL)
+ return (ENXIO);
+
+ if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
+ return ((pcihp_get_cb_ops())->cb_close(dev, flags,
+ otyp, credp));
+
+ mutex_enter(&pcieb_p->pcieb_mutex);
+ pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED;
+ mutex_exit(&pcieb_p->pcieb_mutex);
+ return (0);
+}
+
+static int
+pcieb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rvalp)
+{
+ pcieb_devstate_t *pcieb_p;
+ dev_info_t *self;
+ struct devctl_iocdata *dcp;
+ uint_t bus_state;
+ int rv = 0;
+ minor_t minor = getminor(dev);
+ int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+
+ pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
+ instance);
+
+ if (pcieb_p == NULL)
+ return (ENXIO);
+
+ self = pcieb_p->pcieb_dip;
+ if (pcieb_p->pcieb_hotplug_capable == B_TRUE) {
+ rv = ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
+ arg, mode, credp, rvalp));
+
+ pcieb_plat_ioctl_hotplug(self, rv, cmd);
+ return (rv);
+ }
+
+ /*
+ * We can use the generic implementation for these ioctls
+ */
+ switch (cmd) {
+ case DEVCTL_DEVICE_GETSTATE:
+ case DEVCTL_DEVICE_ONLINE:
+ case DEVCTL_DEVICE_OFFLINE:
+ case DEVCTL_BUS_GETSTATE:
+ return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
+ }
+
+ /*
+ * read devctl ioctl data
+ */
+ if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
+ return (EFAULT);
+
+ switch (cmd) {
+
+ case DEVCTL_DEVICE_RESET:
+ rv = ENOTSUP;
+ break;
+
+ case DEVCTL_BUS_QUIESCE:
+ if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
+ if (bus_state == BUS_QUIESCED)
+ break;
+ (void) ndi_set_bus_state(self, BUS_QUIESCED);
+ break;
+
+ case DEVCTL_BUS_UNQUIESCE:
+ if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
+ if (bus_state == BUS_ACTIVE)
+ break;
+ (void) ndi_set_bus_state(self, BUS_ACTIVE);
+ break;
+
+ case DEVCTL_BUS_RESET:
+ rv = ENOTSUP;
+ break;
+
+ case DEVCTL_BUS_RESETALL:
+ rv = ENOTSUP;
+ break;
+
+ default:
+ rv = ENOTTY;
+ }
+
+ ndi_dc_freehdl(dcp);
+ return (rv);
+}
+
+static int
+pcieb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
+ int flags, char *name, caddr_t valuep, int *lengthp)
+{
+ pcieb_devstate_t *pcieb_p;
+ minor_t minor = getminor(dev);
+ int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+
+ pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
+ instance);
+
+ if (pcieb_p == NULL)
+ return (ENXIO);
+
+ if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
+ return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op,
+ flags, name, valuep, lengthp));
+
+ return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
+}
+
+/*ARGSUSED*/
+static int
+pcieb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+{
+ pcieb_devstate_t *pcieb_p; /* per pcieb state pointer */
+ minor_t minor = getminor((dev_t)arg);
+ int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
+
+ pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
+ instance);
+
+ switch (infocmd) {
+ default:
+ return (DDI_FAILURE);
+
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)(intptr_t)instance;
+ return (DDI_SUCCESS);
+
+ case DDI_INFO_DEVT2DEVINFO:
+ if (pcieb_p == NULL)
+ return (DDI_FAILURE);
+ *result = (void *)pcieb_p->pcieb_dip;
+ return (DDI_SUCCESS);
+ }
+}
+
+/*
+ * Common interrupt handler for hotplug, PME and errors.
+ */
+static uint_t
+pcieb_intr_handler(caddr_t arg1, caddr_t arg2)
+{
+ pcieb_devstate_t *pcieb_p = (pcieb_devstate_t *)arg1;
+ dev_info_t *dip = pcieb_p->pcieb_dip;
+ ddi_fm_error_t derr;
+ int sts = 0;
+ int ret = DDI_INTR_UNCLAIMED;
+ int isrc;
+
+ if (!(pcieb_p->pcieb_init_flags & PCIEB_INIT_ENABLE))
+ goto FAIL;
+
+ mutex_enter(&pcieb_p->pcieb_intr_mutex);
+ isrc = pcieb_p->pcieb_isr_tab[(int)(uintptr_t)arg2];
+ mutex_exit(&pcieb_p->pcieb_intr_mutex);
+
+ PCIEB_DEBUG(DBG_INTR, dip, "Received intr number %d\n",
+ (int)(uintptr_t)arg2);
+
+ if (isrc == PCIEB_INTR_SRC_UNKNOWN)
+ goto FAIL;
+
+ if (isrc & PCIEB_INTR_SRC_HP) {
+ if (pcieb_p->pcieb_hpc_type == HPC_PCIE)
+ ret = pciehpc_intr(dip);
+ else if (pcieb_p->pcieb_hpc_type == HPC_SHPC)
+ ret = pcishpc_intr(dip);
+ }
+
+ if (isrc & PCIEB_INTR_SRC_PME)
+ ret = DDI_INTR_CLAIMED;
+
+ /* AER Error */
+ if (isrc & PCIEB_INTR_SRC_AER) {
+ /*
+ * If MSI is shared with PME/hotplug then check Root Error
+ * Status Reg before claiming it. For now it's ok since
+ * we know we get 2 MSIs.
+ */
+ ret = DDI_INTR_CLAIMED;
+ bzero(&derr, sizeof (ddi_fm_error_t));
+ derr.fme_version = DDI_FME_VERSION;
+ mutex_enter(&pcieb_p->pcieb_peek_poke_mutex);
+ mutex_enter(&pcieb_p->pcieb_err_mutex);
+
+ if ((DEVI(dip)->devi_fmhdl->fh_cap) & DDI_FM_EREPORT_CAPABLE)
+ sts = pf_scan_fabric(dip, &derr, NULL);
+
+ mutex_exit(&pcieb_p->pcieb_err_mutex);
+ mutex_exit(&pcieb_p->pcieb_peek_poke_mutex);
+ if (pcieb_die & sts)
+ fm_panic("%s-%d: PCI(-X) Express Fatal Error. (0x%x)",
+ ddi_driver_name(dip), ddi_get_instance(dip), sts);
+ }
+FAIL:
+ return (ret);
+}
+
+/*
+ * Some PCI-X to PCI-E bridges do not support full 64-bit addressing on the
+ * PCI-X side of the bridge. We build a special version of this driver for
+ * those bridges, which uses PCIEB_ADDR_LIMIT_LO and/or PCIEB_ADDR_LIMIT_HI
+ * to define the range of values which the chip can handle. The code below
+ * then clamps the DMA address range supplied by the driver, preventing the
+ * PCI-E nexus driver from allocating any memory the bridge can't deal
+ * with.
+ */
+static int
+pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+ ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg,
+ ddi_dma_handle_t *handlep)
+{
+ int ret;
+#ifdef BCM_SW_WORKAROUNDS
+ uint64_t lim;
+
+ /*
+ * If the leaf device's limits are outside than what the Broadcom
+ * bridge can handle, we need to clip the values passed up the chain.
+ */
+ lim = attr_p->dma_attr_addr_lo;
+ attr_p->dma_attr_addr_lo = MAX(lim, PCIEB_ADDR_LIMIT_LO);
+
+ lim = attr_p->dma_attr_addr_hi;
+ attr_p->dma_attr_addr_hi = MIN(lim, PCIEB_ADDR_LIMIT_HI);
+
+#endif /* BCM_SW_WORKAROUNDS */
+
+ /*
+ * This is a software workaround to fix the Broadcom 5714/5715 PCIe-PCI
+ * bridge prefetch bug. Intercept the DMA alloc handle request and set
+ * PX_DMAI_FLAGS_MAP_BUFZONE flag in the handle. If this flag is set,
+ * the px nexus driver will allocate an extra page & make it valid one,
+ * for any DVMA request that comes from any of the Broadcom bridge child
+ * devices.
+ */
+ if ((ret = ddi_dma_allochdl(dip, rdip, attr_p, waitfp, arg,
+ handlep)) == DDI_SUCCESS) {
+ ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*handlep;
+#ifdef BCM_SW_WORKAROUNDS
+ mp->dmai_inuse |= PX_DMAI_FLAGS_MAP_BUFZONE;
+#endif /* BCM_SW_WORKAROUNDS */
+ /*
+ * For a given rdip, update mp->dmai_bdf with the bdf value
+ * of pcieb's immediate child or secondary bus-id of the
+ * PCIe2PCI bridge.
+ */
+ mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip);
+ }
+
+ return (ret);
+}
+
+/*
+ * FDVMA feature is not supported for any child device of Broadcom 5714/5715
+ * PCIe-PCI bridge due to prefetch bug. Return failure immediately, so that
+ * these drivers will switch to regular DVMA path.
+ */
+/*ARGSUSED*/
+static int
+pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
+ enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp,
+ uint_t cache_flags)
+{
+ int ret;
+
+#ifdef BCM_SW_WORKAROUNDS
+ if (cmd == DDI_DMA_RESERVE)
+ return (DDI_FAILURE);
+#endif /* BCM_SW_WORKAROUNDS */
+
+ if (((ret = ddi_dma_mctl(dip, rdip, handle, cmd, offp, lenp, objp,
+ cache_flags)) == DDI_SUCCESS) && (cmd == DDI_DMA_RESERVE)) {
+ ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*objp;
+
+ /*
+ * For a given rdip, update mp->dmai_bdf with the bdf value
+ * of pcieb's immediate child or secondary bus-id of the
+ * PCIe2PCI bridge.
+ */
+ mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip);
+ }
+
+ return (ret);
+}
+
+static int
+pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
+ ddi_intr_handle_impl_t *hdlp, void *result)
+{
+ return (pcieb_plat_intr_ops(dip, rdip, intr_op, hdlp, result));
+
+}
+
+/*ARGSUSED*/
+static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+ uint16_t cap_ptr;
+
+ if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
+ DDI_FAILURE) {
+ uint16_t slotimpl = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
+ PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
+ if (slotimpl)
+ if (PCI_CAP_GET32(config_handle, NULL, cap_ptr,
+ PCIE_SLOTCAP) & PCIE_SLOTCAP_HP_CAPABLE)
+ return (DDI_SUCCESS);
+ }
+
+ return (DDI_FAILURE);
+}
+
+static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+ return (pcieb_plat_pcishpc_probe(dip, config_handle));
+}
+
+/*
+ * Initialize hotplug framework if we are hotpluggable.
+ * Sets flag in the soft state if Hot Plug is supported and initialized
+ * properly.
+ */
+/*ARGSUSED*/
+static int
+pcieb_init_hotplug(pcieb_devstate_t *pcieb)
+{
+ int rv = DDI_FAILURE;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip);
+ ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
+ uint8_t dev_type = bus_p->bus_dev_type;
+
+#ifdef PX_PLX
+ uint16_t vid = bus_p->bus_dev_ven_id & 0xFFFF;
+ uint16_t did = bus_p->bus_dev_ven_id >> 16;
+ if ((vid == PXB_VENDOR_PLX) && (did == PXB_DEVICE_PLX_8532) &&
+ (bus_p->bus_rev_id <= PXB_DEVICE_PLX_AA_REV))
+ return (DDI_SUCCESS);
+#endif /* PX_PLX */
+
+ if (((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT)) &&
+ (pcieb_pciehpc_probe(pcieb->pcieb_dip,
+ config_handle) == DDI_SUCCESS)) {
+ pcieb->pcieb_hpc_type = HPC_PCIE;
+ } else if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
+ (pcieb_pcishpc_probe(pcieb->pcieb_dip,
+ config_handle) == DDI_SUCCESS)) {
+ pcieb->pcieb_hpc_type = HPC_SHPC;
+ } else {
+ pcieb->pcieb_hpc_type = HPC_NONE;
+ return (DDI_SUCCESS);
+ }
+
+ pcieb->pcieb_hotplug_capable = B_TRUE;
+
+ if (pcieb->pcieb_hpc_type == HPC_PCIE)
+ rv = pciehpc_init(pcieb->pcieb_dip, NULL);
+ else if (pcieb->pcieb_hpc_type == HPC_SHPC)
+ rv = pcishpc_init(pcieb->pcieb_dip);
+
+ if (rv != DDI_SUCCESS)
+ goto fail;
+
+ if (pcihp_init(pcieb->pcieb_dip) != DDI_SUCCESS) {
+ if (pcieb->pcieb_hpc_type == HPC_PCIE)
+ (void) pciehpc_uninit(pcieb->pcieb_dip);
+ else if (pcieb->pcieb_hpc_type == HPC_SHPC)
+ (void) pcishpc_uninit(pcieb->pcieb_dip);
+
+ goto fail;
+ }
+
+ (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip,
+ "hotplug-capable");
+
+ return (DDI_SUCCESS);
+
+fail:
+ pcieb->pcieb_hpc_type = HPC_NONE;
+ pcieb->pcieb_hotplug_capable = B_FALSE;
+ cmn_err(CE_WARN, "%s%d: Failed setting hotplug framework",
+ ddi_driver_name(pcieb->pcieb_dip),
+ ddi_get_instance(pcieb->pcieb_dip));
+
+ return (DDI_FAILURE);
+}
+
+/*
+ * Power management related initialization specific to pcieb.
+ * Called by pcieb_attach()
+ */
+static int
+pcieb_pwr_setup(dev_info_t *dip)
+{
+ char *comp_array[5];
+ int i;
+ ddi_acc_handle_t conf_hdl;
+ uint16_t pmcap, cap_ptr;
+ pcie_pwr_t *pwr_p;
+
+ /* Some platforms/devices may choose to disable PM */
+ if (pcieb_plat_pwr_disable(dip)) {
+ (void) pcieb_pwr_disable(dip);
+ return (DDI_SUCCESS);
+ }
+
+ ASSERT(PCIE_PMINFO(dip));
+ pwr_p = PCIE_NEXUS_PMINFO(dip);
+ ASSERT(pwr_p);
+
+ /* Code taken from pci_pci driver */
+ if (pci_config_setup(dip, &pwr_p->pwr_conf_hdl) != DDI_SUCCESS) {
+ PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: pci_config_setup "
+ "failed\n");
+ return (DDI_FAILURE);
+ }
+ conf_hdl = pwr_p->pwr_conf_hdl;
+
+ /*
+ * Walk the capabilities searching for a PM entry.
+ */
+ if ((PCI_CAP_LOCATE(conf_hdl, PCI_CAP_ID_PM, &cap_ptr)) ==
+ DDI_FAILURE) {
+ PCIEB_DEBUG(DBG_PWR, dip, "switch/bridge does not support PM. "
+ " PCI PM data structure not found in config header\n");
+ pci_config_teardown(&conf_hdl);
+ return (DDI_SUCCESS);
+ }
+ /*
+ * Save offset to pmcsr for future references.
+ */
+ pwr_p->pwr_pmcsr_offset = cap_ptr + PCI_PMCSR;
+ pmcap = PCI_CAP_GET16(conf_hdl, NULL, cap_ptr, PCI_PMCAP);
+ if (pmcap & PCI_PMCAP_D1) {
+ PCIEB_DEBUG(DBG_PWR, dip, "D1 state supported\n");
+ pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D1;
+ }
+ if (pmcap & PCI_PMCAP_D2) {
+ PCIEB_DEBUG(DBG_PWR, dip, "D2 state supported\n");
+ pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D2;
+ }
+
+ i = 0;
+ comp_array[i++] = "NAME=PCIe switch/bridge PM";
+ comp_array[i++] = "0=Power Off (D3)";
+ if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D2)
+ comp_array[i++] = "1=D2";
+ if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D1)
+ comp_array[i++] = "2=D1";
+ comp_array[i++] = "3=Full Power D0";
+
+ /*
+ * Create pm-components property, if it does not exist already.
+ */
+ if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
+ "pm-components", comp_array, i) != DDI_PROP_SUCCESS) {
+ PCIEB_DEBUG(DBG_PWR, dip, "could not create pm-components "
+ " prop\n");
+ pci_config_teardown(&conf_hdl);
+ return (DDI_FAILURE);
+ }
+ return (pcieb_pwr_init_and_raise(dip, pwr_p));
+}
+
+/*
+ * undo whatever is done in pcieb_pwr_setup. called by pcieb_detach()
+ */
+static void
+pcieb_pwr_teardown(dev_info_t *dip)
+{
+ pcie_pwr_t *pwr_p;
+
+ if (!PCIE_PMINFO(dip) || !(pwr_p = PCIE_NEXUS_PMINFO(dip)))
+ return;
+
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components");
+ if (pwr_p->pwr_conf_hdl)
+ pci_config_teardown(&pwr_p->pwr_conf_hdl);
+}
+
+/*
+ * Initializes the power level and raise the power to D0, if it is
+ * not at D0.
+ */
+static int
+pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p)
+{
+ uint16_t pmcsr;
+ int ret = DDI_SUCCESS;
+
+ /*
+ * Intialize our power level from PMCSR. The common code initializes
+ * this to UNKNOWN. There is no guarantee that we will be at full
+ * power at attach. If we are not at D0, raise the power.
+ */
+ pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl, pwr_p->pwr_pmcsr_offset);
+ pmcsr &= PCI_PMCSR_STATE_MASK;
+ switch (pmcsr) {
+ case PCI_PMCSR_D0:
+ pwr_p->pwr_func_lvl = PM_LEVEL_D0;
+ break;
+
+ case PCI_PMCSR_D1:
+ pwr_p->pwr_func_lvl = PM_LEVEL_D1;
+ break;
+
+ case PCI_PMCSR_D2:
+ pwr_p->pwr_func_lvl = PM_LEVEL_D2;
+ break;
+
+ case PCI_PMCSR_D3HOT:
+ pwr_p->pwr_func_lvl = PM_LEVEL_D3;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Raise the power to D0. */
+ if (pwr_p->pwr_func_lvl != PM_LEVEL_D0 &&
+ ((ret = pm_raise_power(dip, 0, PM_LEVEL_D0)) != DDI_SUCCESS)) {
+ /*
+ * Read PMCSR again. If it is at D0, ignore the return
+ * value from pm_raise_power.
+ */
+ pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl,
+ pwr_p->pwr_pmcsr_offset);
+ if ((pmcsr & PCI_PMCSR_STATE_MASK) == PCI_PMCSR_D0)
+ ret = DDI_SUCCESS;
+ else {
+ PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: could not "
+ "raise power to D0 \n");
+ }
+ }
+ if (ret == DDI_SUCCESS)
+ pwr_p->pwr_func_lvl = PM_LEVEL_D0;
+ return (ret);
+}
+
+/*
+ * Disable PM for x86 and PLX 8532 switch.
+ * For PLX Transitioning one port on this switch to low power causes links
+ * on other ports on the same station to die. Due to PLX erratum #34, we
+ * can't allow the downstream device go to non-D0 state.
+ */
+static int
+pcieb_pwr_disable(dev_info_t *dip)
+{
+ pcie_pwr_t *pwr_p;
+
+ ASSERT(PCIE_PMINFO(dip));
+ pwr_p = PCIE_NEXUS_PMINFO(dip);
+ ASSERT(pwr_p);
+ PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_disable: disabling PM\n");
+ pwr_p->pwr_func_lvl = PM_LEVEL_D0;
+ pwr_p->pwr_flags = PCIE_NO_CHILD_PM;
+ return (DDI_SUCCESS);
+}
+
+#ifdef DEBUG
+int pcieb_dbg_intr_print = 0;
+void
+pcieb_dbg(uint_t bit, dev_info_t *dip, char *fmt, ...)
+{
+ va_list ap;
+
+ if (!pcieb_dbg_print)
+ return;
+
+ if (dip)
+ prom_printf("%s(%d): %s", ddi_driver_name(dip),
+ ddi_get_instance(dip), pcieb_debug_sym[bit]);
+
+ va_start(ap, fmt);
+ if (servicing_interrupt()) {
+ if (pcieb_dbg_intr_print)
+ prom_vprintf(fmt, ap);
+ } else {
+ prom_vprintf(fmt, ap);
+ }
+
+ va_end(ap);
+}
+#endif
+
+static void
+pcieb_id_props(pcieb_devstate_t *pcieb)
+{
+ uint64_t serialid = 0; /* 40b field of EUI-64 serial no. register */
+ uint16_t cap_ptr;
+ uint8_t fic = 0; /* 1 = first in chassis device */
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip);
+ ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
+
+ /*
+ * Identify first in chassis. In the special case of a Sun branded
+ * PLX device, it obviously is first in chassis. Otherwise, in the
+ * general case, look for an Expansion Slot Register and check its
+ * first-in-chassis bit.
+ */
+#ifdef PX_PLX
+ uint16_t vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
+ uint16_t device_id = bus_p->bus_dev_ven_id >> 16;
+ if ((vendor_id == PXB_VENDOR_SUN) &&
+ ((device_id == PXB_DEVICE_PLX_PCIX) ||
+ (device_id == PXB_DEVICE_PLX_PCIE))) {
+ fic = 1;
+ }
+#endif /* PX_PLX */
+ if ((fic == 0) && ((PCI_CAP_LOCATE(config_handle,
+ PCI_CAP_ID_SLOT_ID, &cap_ptr)) != DDI_FAILURE)) {
+ uint8_t esr = PCI_CAP_GET8(config_handle, NULL,
+ cap_ptr, PCI_CAP_ID_REGS_OFF);
+ if (PCI_CAPSLOT_FIC(esr))
+ fic = 1;
+ }
+
+ if ((PCI_CAP_LOCATE(config_handle,
+ PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_SER), &cap_ptr)) != DDI_FAILURE) {
+ /* Serialid can be 0 thru a full 40b number */
+ serialid = PCI_XCAP_GET32(config_handle, NULL,
+ cap_ptr, PCIE_SER_SID_UPPER_DW);
+ serialid <<= 32;
+ serialid |= PCI_XCAP_GET32(config_handle, NULL,
+ cap_ptr, PCIE_SER_SID_LOWER_DW);
+ }
+
+ if (fic)
+ (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip,
+ "first-in-chassis");
+ if (serialid)
+ (void) ddi_prop_update_int64(DDI_DEV_T_NONE, pcieb->pcieb_dip,
+ "serialid#", serialid);
+}
+
+static void
+pcieb_create_ranges_prop(dev_info_t *dip,
+ ddi_acc_handle_t config_handle)
+{
+ uint32_t base, limit;
+ pcieb_ranges_t ranges[PCIEB_RANGE_LEN];
+ uint8_t io_base_lo, io_limit_lo;
+ uint16_t io_base_hi, io_limit_hi, mem_base, mem_limit;
+ int i = 0, rangelen = sizeof (pcieb_ranges_t)/sizeof (int);
+
+ io_base_lo = pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW);
+ io_limit_lo = pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW);
+ io_base_hi = pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI);
+ io_limit_hi = pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI);
+ mem_base = pci_config_get16(config_handle, PCI_BCNF_MEM_BASE);
+ mem_limit = pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT);
+
+ /*
+ * Create ranges for IO space
+ */
+ ranges[i].size_low = ranges[i].size_high = 0;
+ ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
+ ranges[i].child_high = ranges[i].parent_high |=
+ (PCI_REG_REL_M | PCI_ADDR_IO);
+ base = PCIEB_16bit_IOADDR(io_base_lo);
+ limit = PCIEB_16bit_IOADDR(io_limit_lo);
+
+ if ((io_base_lo & 0xf) == PCIEB_32BIT_IO) {
+ base = PCIEB_LADDR(base, io_base_hi);
+ }
+ if ((io_limit_lo & 0xf) == PCIEB_32BIT_IO) {
+ limit = PCIEB_LADDR(limit, io_limit_hi);
+ }
+
+ if ((io_base_lo & PCIEB_32BIT_IO) && (io_limit_hi > 0)) {
+ base = PCIEB_LADDR(base, io_base_hi);
+ limit = PCIEB_LADDR(limit, io_limit_hi);
+ }
+
+ /*
+ * Create ranges for 32bit memory space
+ */
+ base = PCIEB_32bit_MEMADDR(mem_base);
+ limit = PCIEB_32bit_MEMADDR(mem_limit);
+ ranges[i].size_low = ranges[i].size_high = 0;
+ ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
+ ranges[i].child_high = ranges[i].parent_high |=
+ (PCI_REG_REL_M | PCI_ADDR_MEM32);
+ ranges[i].child_low = ranges[i].parent_low = base;
+ if (limit >= base) {
+ ranges[i].size_low = limit - base + PCIEB_MEMGRAIN;
+ i++;
+ }
+
+ if (i) {
+ (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
+ (int *)ranges, i * rangelen);
+ }
+}
+
+/*
+ * For PCI and PCI-X devices including PCIe2PCI bridge, initialize
+ * cache-line-size and latency timer configuration registers.
+ */
+void
+pcieb_set_pci_perf_parameters(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
+{
+ uint_t n;
+
+ /* Initialize cache-line-size configuration register if needed */
+ if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "cache-line-size", 0) == 0) {
+ pci_config_put8(cfg_hdl, PCI_CONF_CACHE_LINESZ,
+ PCIEB_CACHE_LINE_SIZE);
+ n = pci_config_get8(cfg_hdl, PCI_CONF_CACHE_LINESZ);
+ if (n != 0) {
+ (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+ "cache-line-size", n);
+ }
+ }
+
+ /* Initialize latency timer configuration registers if needed */
+ if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "latency-timer", 0) == 0) {
+ uchar_t min_gnt, latency_timer;
+ uchar_t header_type;
+
+ /* Determine the configuration header type */
+ header_type = pci_config_get8(cfg_hdl, PCI_CONF_HEADER);
+
+ if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
+ latency_timer = PCIEB_LATENCY_TIMER;
+ pci_config_put8(cfg_hdl, PCI_BCNF_LATENCY_TIMER,
+ latency_timer);
+ } else {
+ min_gnt = pci_config_get8(cfg_hdl, PCI_CONF_MIN_G);
+ latency_timer = min_gnt * 8;
+ }
+
+ pci_config_put8(cfg_hdl, PCI_CONF_LATENCY_TIMER,
+ latency_timer);
+ n = pci_config_get8(cfg_hdl, PCI_CONF_LATENCY_TIMER);
+ if (n != 0) {
+ (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+ "latency-timer", n);
+ }
+ }
+}
diff --git a/usr/src/uts/sun4/io/px/px_pci.conf b/usr/src/uts/common/io/pciex/pcieb.conf
index c0172bcd95..7af98706b2 100644
--- a/usr/src/uts/sun4/io/px/px_pci.conf
+++ b/usr/src/uts/common/io/pciex/pcieb.conf
@@ -19,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2007 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"
-#
# Force load driver to support hotplug activity
#
ddi-forceattach=1;
diff --git a/usr/src/uts/common/io/pciex/pcieb.h b/usr/src/uts/common/io/pciex/pcieb.h
new file mode 100644
index 0000000000..17a9052172
--- /dev/null
+++ b/usr/src/uts/common/io/pciex/pcieb.h
@@ -0,0 +1,215 @@
+/*
+ * 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_PCIEB_H
+#define _SYS_PCIEB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(DEBUG)
+#define PCIEB_DEBUG pcieb_dbg
+extern void pcieb_dbg(uint_t bit, dev_info_t *dip, char *fmt, ...);
+#else /* DEBUG */
+#define PCIEB_DEBUG 0 &&
+#endif /* DEBUG */
+
+typedef enum { /* same sequence as pcieb_debug_sym[] */
+ /* 0 */ DBG_ATTACH,
+ /* 1 */ DBG_PWR,
+ /* 2 */ DBG_INTR
+} pcieb_debug_bit_t;
+
+/*
+ * Intel specific register offsets with bit definitions.
+ */
+#define PCIEB_PX_CAPABILITY_ID 0x44
+#define PCIEB_BRIDGE_CONF 0x40
+
+/*
+ * PCI/PCI-E Configuration register specific values.
+ */
+#define PX_PMODE 0x4000 /* PCI/PCIX Mode */
+#define PX_PFREQ_66 0x200 /* PCI clock frequency */
+#define PX_PFREQ_100 0x400
+#define PX_PFREQ_133 0x600
+#define PX_PMRE 0x80 /* Peer memory read enable */
+
+/*
+ * Downstream delayed transaction resource partitioning.
+ */
+#define PX_ODTP 0x40 /* Max. of two entries PX and PCI */
+
+/*
+ * Maximum upstream delayed transaction.
+ */
+#define PX_MDT_44 0x00
+#define PX_MDT_11 0x01
+#define PX_MDT_22 0x10
+
+
+#define NUM_LOGICAL_SLOTS 32
+#define PCIEB_RANGE_LEN 2
+#define PCIEB_32BIT_IO 1
+#define PCIEB_32bit_MEM 1
+#define PCIEB_MEMGRAIN 0x100000
+#define PCIEB_IOGRAIN 0x1000
+
+#define PCIEB_16bit_IOADDR(addr) ((uint16_t)(((uint8_t)(addr) & 0xF0) << 8))
+#define PCIEB_LADDR(lo, hi) (((uint16_t)(hi) << 16) | (uint16_t)(lo))
+#define PCIEB_32bit_MEMADDR(addr) (PCIEB_LADDR(0, ((uint16_t)(addr) & 0xFFF0)))
+
+/*
+ * The following typedef is used to represent an entry in the "ranges"
+ * property of a device node.
+ */
+typedef struct {
+ uint32_t child_high;
+ uint32_t child_mid;
+ uint32_t child_low;
+ uint32_t parent_high;
+ uint32_t parent_mid;
+ uint32_t parent_low;
+ uint32_t size_high;
+ uint32_t size_low;
+} pcieb_ranges_t;
+
+typedef enum { HPC_NONE, HPC_PCIE, HPC_SHPC, HPC_OUTBAND } pcieb_hpc_type_t;
+
+typedef struct {
+ dev_info_t *pcieb_dip;
+
+ /* Hotplug support */
+ boolean_t pcieb_hotplug_capable;
+ pcieb_hpc_type_t pcieb_hpc_type;
+
+ /* Interrupt support */
+ ddi_intr_handle_t *pcieb_htable; /* Intr Handlers */
+ int pcieb_htable_size; /* htable size */
+ int pcieb_intr_count; /* Num of Intr */
+ uint_t pcieb_intr_priority; /* Intr Priority */
+ int pcieb_intr_type; /* (MSI | FIXED) */
+ int pcieb_isr_tab[4]; /* MSI source offset */
+
+ uint_t pcieb_soft_state;
+ int pcieb_init_flags;
+ kmutex_t pcieb_mutex; /* Soft state mutex */
+ kmutex_t pcieb_intr_mutex; /* Intr handler mutex */
+ kmutex_t pcieb_err_mutex; /* Error mutex */
+ kmutex_t pcieb_peek_poke_mutex; /* Peekpoke mutex */
+
+ /* FMA */
+ boolean_t pcieb_no_aer_msi;
+ ddi_iblock_cookie_t pcieb_fm_ibc;
+} pcieb_devstate_t;
+
+/*
+ * soft state pointer
+ */
+extern void *pcieb_state;
+
+/* soft state flags */
+#define PCIEB_SOFT_STATE_CLOSED 0x00
+#define PCIEB_SOFT_STATE_OPEN 0x01
+#define PCIEB_SOFT_STATE_OPEN_EXCL 0x02
+
+/* init flags */
+#define PCIEB_INIT_MUTEX 0x01
+#define PCIEB_INIT_HTABLE 0x02
+#define PCIEB_INIT_ALLOC 0x04
+#define PCIEB_INIT_HANDLER 0x08
+#define PCIEB_INIT_ENABLE 0x10
+#define PCIEB_INIT_BLOCK 0x20
+#define PCIEB_INIT_FM 0x40
+
+#define PCIEB_INTR_SRC_UNKNOWN 0x0 /* must be 0 */
+#define PCIEB_INTR_SRC_HP 0x1
+#define PCIEB_INTR_SRC_PME 0x2
+#define PCIEB_INTR_SRC_AER 0x4
+
+/*
+ * Need to put vendor ids in a common file and not platform specific files
+ * as is done today. Until then putting this vendor id define here.
+ */
+#define NVIDIA_VENDOR_ID 0x10de /* Nvidia Vendor Id */
+
+#ifdef BCM_SW_WORKAROUNDS
+
+/* Workaround for address space limitation in Broadcom 5714/5715 */
+#define PCIEB_ADDR_LIMIT_LO 0ull
+#define PCIEB_ADDR_LIMIT_HI ((1ull << 40) - 1)
+
+#endif /* BCM_SW_WORKAROUNDS */
+
+/*
+ * The following values are used to initialize the cache line size
+ * and latency timer registers for PCI, PCI-X and PCIe2PCI devices.
+ */
+#define PCIEB_CACHE_LINE_SIZE 0x10 /* 64 bytes in # of DWORDs */
+#define PCIEB_LATENCY_TIMER 0x40 /* 64 PCI cycles */
+
+extern void pcieb_set_pci_perf_parameters(dev_info_t *dip,
+ ddi_acc_handle_t config_handle);
+extern void pcieb_plat_attach_workaround(dev_info_t *dip);
+extern void pcieb_plat_intr_attach(pcieb_devstate_t *pcieb);
+extern void pcieb_plat_initchild(dev_info_t *child);
+extern void pcieb_plat_uninitchild(dev_info_t *child);
+extern void pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd);
+extern int pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop,
+ void *arg);
+extern int pcieb_plat_pcishpc_probe(dev_info_t *dip,
+ ddi_acc_handle_t config_handle);
+extern int pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip,
+ ddi_ctl_enum_t ctlop, void *arg, void *result);
+extern int pcieb_plat_intr_ops(dev_info_t *dip, dev_info_t *rdip,
+ ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
+extern boolean_t pcieb_plat_msi_supported(dev_info_t *dip);
+extern boolean_t pcieb_plat_pwr_disable(dev_info_t *dip);
+
+#if defined(__i386) || defined(__amd64)
+extern void pcieb_intel_error_workaround(dev_info_t *dip);
+extern void pcieb_intel_serr_workaround(dev_info_t *dip, boolean_t mcheck);
+extern void pcieb_intel_rber_workaround(dev_info_t *dip);
+extern void pcieb_intel_sw_workaround(dev_info_t *dip);
+extern void pcieb_intel_mps_workaround(dev_info_t *dip);
+extern void pcieb_init_osc(dev_info_t *dip);
+extern void pcieb_peekpoke_cb(dev_info_t *, ddi_fm_error_t *);
+extern int pcishpc_init(dev_info_t *dip);
+extern int pcishpc_uninit(dev_info_t *dip);
+extern int pcishpc_intr(dev_info_t *dip);
+#endif /* defined(__i386) || defined(__amd64) */
+
+#ifdef PX_PLX
+extern void pcieb_attach_plx_workarounds(pcieb_devstate_t *pcieb);
+extern int pcieb_init_plx_workarounds(pcieb_devstate_t *pcieb,
+ dev_info_t *child);
+#endif /* PX_PLX */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_PCIEB_H */
diff --git a/usr/src/uts/common/sys/pcie_impl.h b/usr/src/uts/common/sys/pcie_impl.h
index 817211192f..1e88407b1c 100644
--- a/usr/src/uts/common/sys/pcie_impl.h
+++ b/usr/src/uts/common/sys/pcie_impl.h
@@ -37,7 +37,7 @@ extern "C" {
#define PCI_GET_SEC_BUS(dip) \
PCIE_DIP2BUS(dip)->bus_bdg_secbus
#define PCI_GET_PCIE2PCI_SECBUS(dip) \
- PCIE_DIP2BUS(dip)->bus_pcie2pci_secbus
+ PCIE_DIP2BUS(dip)->bus_bdg_secbus
#define DEVI_PORT_TYPE_PCI \
((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8) | \
@@ -124,7 +124,7 @@ extern "C" {
/*
* The following flag is used for Broadcom 5714/5715 bridge prefetch issue.
- * This flag will be used both by px and px_pci nexus drivers.
+ * This flag will be used both by px and pcieb nexus drivers.
*/
#define PX_DMAI_FLAGS_MAP_BUFZONE 0x40000
@@ -253,7 +253,6 @@ typedef struct pcie_bus {
uint32_t bus_dev_ven_id; /* device/vendor ID */
uint8_t bus_rev_id; /* revision ID */
uint8_t bus_hdr_type; /* pci header type, see pci.h */
- pcie_req_id_t bus_pcie2pci_secbus; /* PCIe2PCI Bridge secbus num */
uint16_t bus_dev_type; /* PCI-E dev type, see pcie.h */
uint8_t bus_bdg_secbus; /* Bridge secondary bus num */
uint16_t bus_pcie_off; /* PCIe Capability Offset */
diff --git a/usr/src/uts/sun4/io/px/pcie_pwr.h b/usr/src/uts/common/sys/pcie_pwr.h
index ec08e1634b..4cb32af372 100644
--- a/usr/src/uts/sun4/io/px/pcie_pwr.h
+++ b/usr/src/uts/common/sys/pcie_pwr.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_PCIE_PWR_H
#define _SYS_PCIE_PWR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -147,8 +145,8 @@ typedef struct pcie_pm {
*/
/*
- * We link pcie_pwr.o into several drivers (px, px_pci, pxb_bcm, pxb_plx), which
- * causes the symbols below to be duplicated. This isn't an issue in
+ * We link pcie_pwr.o into several drivers (px, pcieb, pcieb_bcm, pcieb_plx),
+ * which causes the symbols below to be duplicated. This isn't an issue in
* practice, since they aren't used from outside the module that they're
* part of. However, lint does not know this, and when it does global
* crosschecks for the kernel, it complains. To prevent this, we rename the
diff --git a/usr/src/uts/i86pc/io/pci/pci_common.c b/usr/src/uts/i86pc/io/pci/pci_common.c
index cde3e67cfb..e9ddc98526 100644
--- a/usr/src/uts/i86pc/io/pci/pci_common.c
+++ b/usr/src/uts/i86pc/io/pci/pci_common.c
@@ -178,7 +178,7 @@ pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
-static int pcie_pci_intr_pri_counter = 0;
+static int pcieb_intr_pri_counter = 0;
/*
* pci_common_intr_ops: bus_intr_op() function for interrupt support
@@ -311,13 +311,13 @@ SUPPORTED_TYPES_OUT:
(psm_intr_ops != NULL) &&
(pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
/*
- * Following check is a special case for 'pcie_pci'.
+ * Following check is a special case for 'pcieb'.
* This makes sure vectors with the right priority
- * are allocated for pcie_pci during ALLOC time.
+ * are allocated for pcieb during ALLOC time.
*/
- if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) {
+ if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
hdlp->ih_pri =
- (pcie_pci_intr_pri_counter % 2) ? 4 : 7;
+ (pcieb_intr_pri_counter % 2) ? 4 : 7;
pciepci = 1;
} else
hdlp->ih_pri = priority;
@@ -394,7 +394,7 @@ SUPPORTED_TYPES_OUT:
ispec = (struct intrspec *)isp;
if (ispec)
ispec->intrspec_pri = hdlp->ih_pri;
- ++pcie_pci_intr_pri_counter;
+ ++pcieb_intr_pri_counter;
}
} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
diff --git a/usr/src/uts/i86pc/io/pciex/inc.flg b/usr/src/uts/i86pc/io/pciex/inc.flg
index 3757e5750e..42c94632c8 100644
--- a/usr/src/uts/i86pc/io/pciex/inc.flg
+++ b/usr/src/uts/i86pc/io/pciex/inc.flg
@@ -21,12 +21,10 @@
#
#
-# Copyright 2007 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 file brings down all that is needed to build the
# x86 PCI Express code.
#
@@ -58,7 +56,7 @@ find_files "s.*" \
usr/src/uts/i86pc/npe \
usr/src/uts/i86xpv/npe \
usr/src/uts/intel/pci_autoconfig \
- usr/src/uts/intel/pcie_pci \
+ usr/src/uts/intel/pcieb \
usr/src/uts/intel/pciehpc \
usr/src/uts/intel/pcicfg
diff --git a/usr/src/uts/i86pc/io/pciex/npe_misc.c b/usr/src/uts/i86pc/io/pciex/npe_misc.c
index 676a5b9b4a..59dfbce86e 100644
--- a/usr/src/uts/i86pc/io/pciex/npe_misc.c
+++ b/usr/src/uts/i86pc/io/pciex/npe_misc.c
@@ -191,7 +191,7 @@ npe_disable_empty_bridges_workaround(dev_info_t *child)
* Do not bind drivers to empty bridges.
* Fail above, if the bridge is found to be hotplug capable
*/
- if (ddi_driver_major(child) == ddi_name_to_major("pcie_pci") &&
+ if (ddi_driver_major(child) == ddi_name_to_major("pcieb") &&
ddi_get_child(child) == NULL &&
ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
"pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files
index 98b40700ab..b00253f54e 100644
--- a/usr/src/uts/intel/Makefile.files
+++ b/usr/src/uts/intel/Makefile.files
@@ -148,9 +148,9 @@ GHD_OBJS += ghd.o ghd_debug.o ghd_dma.o ghd_queue.o ghd_scsa.o \
I915_OBJS += i915_dma.o i915_drv.o i915_irq.o i915_mem.o
NSKERN_OBJS += nsc_asm.o
PCICFG_OBJS += pcicfg.o
-PCI_E_PCINEXUS_OBJS += pcie_pci.o
PCI_PCINEXUS_OBJS += pci_pci.o
PCIEHPCNEXUS_OBJS += pciehpc_acpi.o
+PCIEB_OBJS += pcieb_x86.o
PIT_BEEP_OBJS += pit_beep.o
POWER_OBJS += power.o
PCI_AUTOCONFIG_OBJS += pci_autoconfig.o pci_boot.o pcie_nvidia.o \
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index ac16b73280..85075459e0 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -279,7 +279,7 @@ DRV_KMODS += nxge
DRV_KMODS += openeepr
DRV_KMODS += pci_pci
DRV_KMODS += pcic
-DRV_KMODS += pcie_pci
+DRV_KMODS += pcieb
DRV_KMODS += physmem
DRV_KMODS += pcan
DRV_KMODS += pcwl
diff --git a/usr/src/uts/intel/io/pciex/pcie_pci.c b/usr/src/uts/intel/io/pciex/pcie_pci.c
deleted file mode 100644
index 6d8f6d9ef4..0000000000
--- a/usr/src/uts/intel/io/pciex/pcie_pci.c
+++ /dev/null
@@ -1,1781 +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 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * PCI-E 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/util.h>
-#include <sys/fm/protocol.h>
-#include <sys/pcie.h>
-#include <sys/pci_cap.h>
-#include <sys/pcie_impl.h>
-#include <sys/pcie_acpi.h>
-#include <sys/hotplug/pci/pcihp.h>
-#include <sys/hotplug/pci/pciehpc.h>
-#include <sys/hotplug/hpctrl.h>
-#include <io/pciex/pcie_nvidia.h>
-#include <io/pciex/pcie_nb5000.h>
-
-#ifdef DEBUG
-static int pepb_debug = 0;
-#define PEPB_DEBUG(args) if (pepb_debug) cmn_err args
-#else
-#define PEPB_DEBUG(args)
-#endif
-
-/*
- * interfaces from misc/pcie
- */
-static int pepb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, off_t,
- off_t, caddr_t *);
-static int pepb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
- void *);
-static int pepb_fm_init(dev_info_t *, dev_info_t *, int,
- ddi_iblock_cookie_t *);
-
-struct bus_ops pepb_bus_ops = {
- BUSO_REV,
- pepb_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,
- pepb_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)(); */
- pepb_fm_init, /* (*bus_fm_init)(); */
- NULL, /* (*bus_fm_fini)(); */
- NULL, /* (*bus_fm_access_enter)(); */
- NULL, /* (*bus_fm_access_exit)(); */
- NULL, /* (*bus_power)(); */
- i_ddi_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 pepb_open(dev_t *, int, int, cred_t *);
-static int pepb_close(dev_t, int, int, cred_t *);
-static int pepb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
-static int pepb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
- caddr_t, int *);
-static int pepb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
-static void pepb_peekpoke_cb(dev_info_t *, ddi_fm_error_t *);
-static uint_t pepb_intr_handler(caddr_t arg1, caddr_t arg2);
-
-struct cb_ops pepb_cb_ops = {
- pepb_open, /* open */
- pepb_close, /* close */
- nodev, /* strategy */
- nodev, /* print */
- nodev, /* dump */
- nodev, /* read */
- nodev, /* write */
- pepb_ioctl, /* ioctl */
- nodev, /* devmap */
- nodev, /* mmap */
- nodev, /* segmap */
- nochpoll, /* poll */
- pepb_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 pepb_probe(dev_info_t *);
-static int pepb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
-static int pepb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
-static int pepb_check_slot_disabled(dev_info_t *dip);
-
-struct dev_ops pepb_ops = {
- DEVO_REV, /* devo_rev */
- 0, /* refcnt */
- pepb_info, /* info */
- nulldev, /* identify */
- pepb_probe, /* probe */
- pepb_attach, /* attach */
- pepb_detach, /* detach */
- nulldev, /* reset */
- &pepb_cb_ops, /* driver operations */
- &pepb_bus_ops, /* bus operations */
- NULL, /* power */
- ddi_quiesce_not_needed, /* quiesce */
-};
-
-/*
- * Module linkage information for the kernel.
- */
-
-static struct modldrv modldrv = {
- &mod_driverops, /* Type of module */
- "PCIe to PCI nexus driver",
- &pepb_ops, /* driver ops */
-};
-
-static struct modlinkage modlinkage = {
- MODREV_1,
- (void *)&modldrv,
- NULL
-};
-
-/*
- * soft state pointer and structure template:
- */
-static void *pepb_state;
-
-typedef struct {
- dev_info_t *dip;
-
- /*
- * 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];
-
- /*
- * hot plug support
- */
- int inband_hpc; /* inband HPC type */
-
- /*
- * interrupt support
- */
- ddi_intr_handle_t *htable; /* interrupt handles */
- int htable_size; /* htable size */
- int intr_count; /* Num of Intr */
- uint_t intr_priority; /* Intr Priority */
- int intr_type; /* (MSI | FIXED) */
- int isr_tab[4]; /* MSI source offset */
- uint32_t soft_state; /* soft state flags */
- kmutex_t pepb_mutex; /* Mutex for this ctrl */
- kmutex_t pepb_err_mutex; /* Error handling mutex */
- kmutex_t pepb_peek_poke_mutex;
- boolean_t pepb_no_aer_msi;
- ddi_iblock_cookie_t pepb_fm_ibc;
-} pepb_devstate_t;
-
-/* soft state flags */
-#define PEPB_SOFT_STATE_INIT_HTABLE 0x01 /* htable kmem_alloced */
-#define PEPB_SOFT_STATE_INIT_ALLOC 0x02 /* ddi_intr_alloc called */
-#define PEPB_SOFT_STATE_INIT_HANDLER 0x04 /* ddi_intr_add_handler done */
-#define PEPB_SOFT_STATE_INIT_ENABLE 0x08 /* ddi_intr_enable called */
-#define PEPB_SOFT_STATE_INIT_BLOCK 0x10 /* ddi_intr_block_enable done */
-#define PEPB_SOFT_STATE_INIT_MUTEX 0x20 /* mutex initialized */
-
-/* default interrupt priority for all interrupts (hotplug or non-hotplug */
-#define PEPB_INTR_PRI 1
-
-#define PEPB_INTR_SRC_UNKNOWN 0x0 /* must be 0 */
-#define PEPB_INTR_SRC_HP 0x1
-#define PEPB_INTR_SRC_PME 0x2
-#define PEPB_INTR_SRC_AER 0x4
-
-/* flag to turn on MSI support */
-int pepb_enable_msi = 1;
-
-/* panic on PF_PANIC flag */
-int pepb_die = PF_ERR_FATAL_FLAGS;
-
-extern errorq_t *pci_target_queue;
-
-/*
- * forward function declarations:
- */
-static void pepb_uninitchild(dev_info_t *);
-static int pepb_initchild(dev_info_t *child);
-static void pepb_save_config_regs(pepb_devstate_t *pepb_p);
-static void pepb_restore_config_regs(pepb_devstate_t *pepb_p);
-static boolean_t pepb_is_pcie_device_type(dev_info_t *dip);
-
-/* interrupt related declarations */
-static int pepb_msi_intr_supported(dev_info_t *, int intr_type);
-static int pepb_intr_init(pepb_devstate_t *pepb_p, int intr_type);
-static void pepb_intr_fini(pepb_devstate_t *pepb_p);
-
-/* Intel Workarounds */
-static void pepb_intel_serr_workaround(dev_info_t *dip, boolean_t mcheck);
-static void pepb_intel_rber_workaround(dev_info_t *dip);
-static void pepb_intel_mps_workaround(dev_info_t *dip);
-static void pepb_intel_sw_workaround(dev_info_t *dip);
-int pepb_intel_workaround_disable = 0;
-
-int
-_init(void)
-{
- int e;
-
- if ((e = ddi_soft_state_init(&pepb_state, sizeof (pepb_devstate_t),
- 1)) == 0 && (e = mod_install(&modlinkage)) != 0)
- ddi_soft_state_fini(&pepb_state);
- return (e);
-}
-
-int
-_fini(void)
-{
- int e;
-
- if ((e = mod_remove(&modlinkage)) == 0) {
- /*
- * Destroy pci_target_queue, and set it to NULL.
- */
- if (pci_target_queue)
- errorq_destroy(pci_target_queue);
- pci_target_queue = NULL;
- ddi_soft_state_fini(&pepb_state);
- }
- return (e);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
- return (mod_info(&modlinkage, modinfop));
-}
-
-/*ARGSUSED*/
-static int
-pepb_probe(dev_info_t *devi)
-{
- return (DDI_PROBE_SUCCESS);
-}
-
-static int
-pepb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
-{
- int instance, intr_types, fmcap;
- char device_type[8];
- pepb_devstate_t *pepb;
- pcie_bus_t *bus_p = PCIE_DIP2UPBUS(devi);
- ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
-
- switch (cmd) {
- case DDI_RESUME:
-
- /*
- * Get the soft state structure for the bridge.
- */
- pepb = ddi_get_soft_state(pepb_state, ddi_get_instance(devi));
- pepb_restore_config_regs(pepb);
- return (DDI_SUCCESS);
-
- default:
- return (DDI_FAILURE);
-
- case DDI_ATTACH:
- break;
- }
-
- /*
- * If PCIE_LINKCTL_LINK_DISABLE bit in the PCIe Config
- * Space (PCIe Capability Link Control Register) is set,
- * then do not bind the driver.
- */
- if (pepb_check_slot_disabled(devi) == 1)
- return (DDI_FAILURE);
-
- /*
- * Allocate and get soft state structure.
- */
- instance = ddi_get_instance(devi);
- if (ddi_soft_state_zalloc(pepb_state, instance) != DDI_SUCCESS)
- return (DDI_FAILURE);
- pepb = ddi_get_soft_state(pepb_state, instance);
- pepb->dip = devi;
-
- /*
- * initialize fma support before we start accessing config space
- */
- pci_targetq_init();
- fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
- DDI_FM_DMACHK_CAPABLE;
- ddi_fm_init(devi, &fmcap, &pepb->pepb_fm_ibc);
-
- mutex_init(&pepb->pepb_err_mutex, NULL, MUTEX_DRIVER,
- (void *)pepb->pepb_fm_ibc);
- mutex_init(&pepb->pepb_peek_poke_mutex, NULL, MUTEX_DRIVER,
- (void *)pepb->pepb_fm_ibc);
-
- /*
- * Make sure the "device_type" property exists.
- */
- if (pepb_is_pcie_device_type(devi))
- (void) strcpy(device_type, "pciex");
- else
- (void) strcpy(device_type, "pci");
- (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
- "device_type", device_type);
-
- /* probe for inband HPC */
- pepb->inband_hpc = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
- DDI_PROP_DONTPASS, "pci-hotplug-type", INBAND_HPC_NONE);
-
- /*
- * 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, "Failed to setup hotplug framework");
- else {
- /*
- * If there is an inband PCI-E HPC then initialize it.
- * The failure is not considered fatal for the system
- * so log the message and ignore the failure.
- */
- if (pepb->inband_hpc == INBAND_HPC_PCIE &&
- pciehpc_init(devi, NULL) != DDI_SUCCESS) {
- pepb->inband_hpc = INBAND_HPC_NONE;
- cmn_err(CE_CONT, "!Failed to initialize inband hotplug "
- "controller");
- }
- }
-
- /*
- * Call _OSC method for 2 reasons:
- * 1. Hotplug: To determine if it is native or ACPI mode.
- *
- * 2. Error handling: Inform firmware that OS can support AER error
- * handling. Currently we don't care for what the BIOS response was
- * and instead setup interrupts for error handling as if it were
- * supported.
- *
- * For hotpluggable slots the _OSC method has already been called as
- * part of the hotplug initialization above.
- * For non-hotpluggable slots we need to call the _OSC method only for
- * Root Ports (for AER support).
- */
- if (!pcie_is_osc(devi) && PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p)) {
- uint32_t osc_flags = OSC_CONTROL_PCIE_ADV_ERR;
- (void) pcie_acpi_osc(devi, &osc_flags);
- }
-
- /*
- * Initialize interrupt handlers.
- */
- if (ddi_intr_get_supported_types(devi, &intr_types) != DDI_SUCCESS)
- goto next_step;
-
- PEPB_DEBUG((CE_NOTE, "%s#%d: intr_types = 0x%x\n",
- ddi_driver_name(devi), ddi_get_instance(devi), intr_types));
-
- if (pepb_msi_intr_supported(devi, intr_types) == DDI_SUCCESS) {
- if (pepb_intr_init(pepb, DDI_INTR_TYPE_MSI) == DDI_SUCCESS)
- goto next_step;
- else
- PEPB_DEBUG((CE_WARN,
- "%s#%d: Unable to attach MSI handler",
- ddi_driver_name(devi), ddi_get_instance(devi)));
- }
-
- /*
- * If we are here that means MSIs were not enabled. For errors fall back
- * to the SERR+Machinecheck approach on certain Intel chipsets.
- */
- if (PCIE_IS_RP(bus_p))
- pepb->pepb_no_aer_msi = B_TRUE;
-
- /*
- * Only register hotplug interrupts for now.
- * Check if device supports PCIe hotplug or not?
- * If yes, register fixed interrupts if ILINE is valid.
- * Fix error handling for INTx.
- */
- if (pepb->inband_hpc == INBAND_HPC_PCIE) {
- uint8_t iline;
-
- iline = pci_config_get8(config_handle, PCI_CONF_ILINE);
-
- if (iline == 0 || iline > 15)
- goto next_step;
-
- if (pepb_intr_init(pepb, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS)
- PEPB_DEBUG((CE_WARN,
- "%s#%d: Unable to attach INTx handler",
- ddi_driver_name(devi), ddi_get_instance(devi)));
- }
-
-next_step:
- /* Must apply workaround only after all initialization is done */
- pepb_intel_serr_workaround(devi, pepb->pepb_no_aer_msi);
- pepb_intel_rber_workaround(devi);
- pepb_intel_sw_workaround(devi);
- pepb_intel_mps_workaround(devi);
-
- /*
- * If this is a root port, determine and set the max payload size.
- * Since this will involve scanning the fabric, all error enabling
- * and sw workarounds should be in place before doing this.
- */
- if (PCIE_IS_RP(bus_p))
- pcie_init_root_port_mps(devi);
-
- ddi_report_dev(devi);
- return (DDI_SUCCESS);
-}
-
-static int
-pepb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
-{
- pepb_devstate_t *pepb;
-
- switch (cmd) {
- case DDI_SUSPEND:
- pepb = ddi_get_soft_state(pepb_state, ddi_get_instance(devi));
- pepb_save_config_regs(pepb);
- return (DDI_SUCCESS);
-
- case DDI_DETACH:
- break;
-
- default:
- return (DDI_FAILURE);
- }
-
- (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
- pepb = ddi_get_soft_state(pepb_state, ddi_get_instance(devi));
-
- /* remove interrupt handlers */
- pepb_intr_fini(pepb);
-
- /* uninitialize inband PCI-E HPC if present */
- if (pepb->inband_hpc == INBAND_HPC_PCIE)
- (void) pciehpc_uninit(devi);
-
- /*
- * Uninitialize hotplug support on this bus.
- */
- (void) pcihp_uninit(devi);
-
- mutex_destroy(&pepb->pepb_err_mutex);
- mutex_destroy(&pepb->pepb_peek_poke_mutex);
- ddi_fm_fini(devi);
-
- /*
- * And finally free the per-pci soft state.
- */
- ddi_soft_state_free(pepb_state, ddi_get_instance(devi));
-
- return (DDI_SUCCESS);
-}
-
-static int
-pepb_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));
-}
-
-static int
-pepb_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;
- pepb_devstate_t *pepb = ddi_get_soft_state(pepb_state,
- ddi_get_instance(dip));
- struct detachspec *ds;
- struct attachspec *as;
-
- switch (ctlop) {
- case DDI_CTLOPS_REPORTDEV:
- if (rdip == (dev_info_t *)0)
- return (DDI_FAILURE);
- cmn_err(CE_CONT, "?PCIE-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 (pepb_initchild((dev_info_t *)arg));
-
- case DDI_CTLOPS_UNINITCHILD:
- pepb_uninitchild((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:
- if (!PCIE_IS_RP(PCIE_DIP2BUS(dip)))
- return (ddi_ctlops(dip, rdip, ctlop, arg, result));
- return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
- ddi_ctlops, &pepb->pepb_err_mutex,
- &pepb->pepb_peek_poke_mutex,
- pepb_peekpoke_cb));
-
- case DDI_CTLOPS_ATTACH:
- if (!pcie_is_child(dip, rdip))
- return (DDI_SUCCESS);
-
- as = (struct attachspec *)arg;
- if ((as->when == DDI_POST) && (as->result == DDI_SUCCESS)) {
- pf_init(rdip, (void *)pepb->pepb_fm_ibc, as->cmd);
- (void) pcie_postattach_child(rdip);
-
- /*
- * For leaf devices supporting RBER and AER, we need
- * to apply this workaround on them after attach to be
- * notified of UEs that would otherwise be ignored
- * as CEs on Intel chipsets currently
- */
- pepb_intel_rber_workaround(rdip);
- }
-
- if (as->cmd == DDI_RESUME && as->when == DDI_PRE)
- if (pci_pre_resume(rdip) != DDI_SUCCESS)
- return (DDI_FAILURE);
-
- return (DDI_SUCCESS);
-
- case DDI_CTLOPS_DETACH:
- if (!pcie_is_child(dip, rdip))
- return (DDI_SUCCESS);
-
- ds = (struct detachspec *)arg;
- if (ds->when == DDI_PRE)
- pf_fini(rdip, ds->cmd);
-
- if (ds->cmd == DDI_SUSPEND && ds->when == DDI_POST)
- if (pci_post_suspend(rdip) != DDI_SUCCESS)
- return (DDI_FAILURE);
-
- return (DDI_SUCCESS);
- 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
-pepb_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
-pepb_initchild(dev_info_t *child)
-{
- struct ddi_parent_private_data *pdptr;
- struct pcie_bus *bus_p;
- char name[MAXNAMELEN];
-
- if (pepb_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, pepb_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-E */
- 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);
- }
-
- 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);
-
- bus_p = pcie_init_bus(child);
- if (!bus_p || pcie_initchild(child) != DDI_SUCCESS)
- return (DDI_FAILURE);
-
- return (DDI_SUCCESS);
-}
-
-static void
-pepb_uninitchild(dev_info_t *dip)
-{
- struct ddi_parent_private_data *pdptr;
-
- pcie_uninitchild(dip);
-
- 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);
-
- ddi_prop_remove_all(dip);
-}
-
-/*
- * pepb_save_config_regs
- *
- * This routine saves the state of the configuration registers of all
- * the child nodes of each PBM.
- *
- * used by: pepb_detach() on suspends
- *
- * return value: none
- *
- * XXX: Need to save PCI-E config registers including MSI
- */
-static void
-pepb_save_config_regs(pepb_devstate_t *pepb_p)
-{
- int i;
- dev_info_t *dip;
- ddi_acc_handle_t config_handle;
-
- for (i = 0, dip = ddi_get_child(pepb_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(pepb_p->dip),
- ddi_get_instance(pepb_p->dip),
- ddi_driver_name(dip),
- ddi_get_instance(dip));
- continue;
- }
-
- pepb_p->config_state[i].dip = dip;
- pepb_p->config_state[i].command =
- pci_config_get16(config_handle, PCI_CONF_COMM);
- pepb_p->config_state[i].header_type =
- pci_config_get8(config_handle, PCI_CONF_HEADER);
-
- if ((pepb_p->config_state[i].header_type & PCI_HEADER_TYPE_M) ==
- PCI_HEADER_ONE)
- pepb_p->config_state[i].bridge_control =
- pci_config_get16(config_handle, PCI_BCNF_BCNTRL);
-
- pepb_p->config_state[i].cache_line_size =
- pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
- pepb_p->config_state[i].latency_timer =
- pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
-
- if ((pepb_p->config_state[i].header_type &
- PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
- pepb_p->config_state[i].sec_latency_timer =
- pci_config_get8(config_handle,
- PCI_BCNF_LATENCY_TIMER);
-
- pci_config_teardown(&config_handle);
- }
- pepb_p->config_state_index = i;
-}
-
-
-/*
- * pepb_restore_config_regs
- *
- * This routine restores the state of the configuration registers of all
- * the child nodes of each PBM.
- *
- * used by: pepb_attach() on resume
- *
- * return value: none
- *
- * XXX: Need to restore PCI-E config registers including MSI
- */
-static void
-pepb_restore_config_regs(pepb_devstate_t *pepb_p)
-{
- int i;
- dev_info_t *dip;
- ddi_acc_handle_t config_handle;
-
- for (i = 0; i < pepb_p->config_state_index; i++) {
- dip = pepb_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(pepb_p->dip),
- ddi_get_instance(pepb_p->dip),
- ddi_driver_name(dip),
- ddi_get_instance(dip));
- continue;
- }
- pci_config_put16(config_handle, PCI_CONF_COMM,
- pepb_p->config_state[i].command);
- if ((pepb_p->config_state[i].header_type & PCI_HEADER_TYPE_M) ==
- PCI_HEADER_ONE)
- pci_config_put16(config_handle, PCI_BCNF_BCNTRL,
- pepb_p->config_state[i].bridge_control);
-
- pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
- pepb_p->config_state[i].cache_line_size);
- pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
- pepb_p->config_state[i].latency_timer);
-
- if ((pepb_p->config_state[i].header_type &
- PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
- pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
- pepb_p->config_state[i].sec_latency_timer);
-
- pci_config_teardown(&config_handle);
- }
-}
-
-static boolean_t
-pepb_is_pcie_device_type(dev_info_t *dip)
-{
- pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
-
- if (PCIE_IS_SW(bus_p) || PCIE_IS_RP(bus_p) || PCIE_IS_PCI2PCIE(bus_p))
- return (B_TRUE);
-
- return (B_FALSE);
-}
-
-/*
- * This function initializes internally generated interrupts only.
- * It does not affect any interrupts generated by downstream devices
- * or the forwarding of them.
- *
- * Enable Device Specific Interrupts or Hotplug features here.
- * Enabling features may change how many interrupts are requested
- * by the device. If features are not enabled first, the
- * device might not ask for any interrupts.
- */
-static int
-pepb_intr_init(pepb_devstate_t *pepb_p, int intr_type)
-{
- dev_info_t *dip = pepb_p->dip;
- int nintrs, request, count, x;
- int intr_cap = 0;
- int inum = 0;
- int ret, hp_msi_off, aer_msi_off;
- pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
- uint16_t vendorid = bus_p->bus_dev_ven_id & 0xFFFF;
- boolean_t is_hp = B_FALSE;
- boolean_t is_pme = B_FALSE;
-
- PEPB_DEBUG((CE_NOTE, "pepb_intr_init: Attaching %s handler\n",
- (intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx"));
-
- request = 0;
- if (pepb_p->inband_hpc == INBAND_HPC_PCIE) {
- request++;
- is_hp = B_TRUE;
- }
-
- /*
- * Hotplug and PME share the same MSI vector. If hotplug is not
- * supported check if MSI is needed for PME.
- */
- if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p) &&
- (vendorid == NVIDIA_VENDOR_ID)) {
- is_pme = B_TRUE;
- if (!is_hp)
- request++;
- }
-
- /* Setup MSI if this device is a Rootport and has AER. */
- if (intr_type == DDI_INTR_TYPE_MSI) {
- if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p))
- request++;
- }
-
- if (request == 0)
- return (DDI_FAILURE);
-
- /*
- * Get number of supported interrupts.
- *
- * Several Bridges/Switches will not have this property set, resulting
- * in a FAILURE, if the device is not configured in a way that
- * interrupts are needed. (eg. hotplugging)
- */
- ret = ddi_intr_get_nintrs(dip, intr_type, &nintrs);
- if ((ret != DDI_SUCCESS) || (nintrs == 0)) {
- PEPB_DEBUG((CE_NOTE, "ddi_intr_get_nintrs ret:%d req:%d\n",
- ret, nintrs));
- return (DDI_FAILURE);
- }
-
- PEPB_DEBUG((CE_NOTE, "bdf 0x%x: ddi_intr_get_nintrs: nintrs %d, request"
- " %d\n", bus_p->bus_bdf, nintrs, request));
-
- if (request > nintrs)
- request = nintrs;
-
- /* Allocate an array of interrupt handlers */
- pepb_p->htable_size = sizeof (ddi_intr_handle_t) * request;
- pepb_p->htable = kmem_zalloc(pepb_p->htable_size, KM_SLEEP);
- pepb_p->soft_state |= PEPB_SOFT_STATE_INIT_HTABLE;
-
- ret = ddi_intr_alloc(dip, pepb_p->htable, intr_type, inum, request,
- &count, DDI_INTR_ALLOC_NORMAL);
- if ((ret != DDI_SUCCESS) || (count == 0)) {
- PEPB_DEBUG((CE_WARN, "ddi_intr_alloc() ret: %d ask: %d"
- " actual: %d\n", ret, request, count));
- goto FAIL;
- }
- pepb_p->soft_state |= PEPB_SOFT_STATE_INIT_ALLOC;
-
- /* Save the actual number of interrupts allocated */
- pepb_p->intr_count = count;
- if (count < request) {
- PEPB_DEBUG((CE_WARN, "bdf 0%x: Requested Intr: %d Received:"
- " %d\n", bus_p->bus_bdf, request, count));
- }
-
- /*
- * NVidia (MCP55 and other) chipsets have a errata that if the number
- * of requested MSI intrs is not allocated we have to fall back to INTx.
- */
- if (intr_type == DDI_INTR_TYPE_MSI) {
- if (PCIE_IS_RP(bus_p) && (vendorid == NVIDIA_VENDOR_ID)) {
- if (request != count)
- goto FAIL;
- }
- }
-
- /* Get interrupt priority */
- ret = ddi_intr_get_pri(pepb_p->htable[0], &pepb_p->intr_priority);
- if (ret != DDI_SUCCESS) {
- PEPB_DEBUG((CE_WARN, "ddi_intr_get_pri() ret: %d\n", ret));
- goto FAIL;
- }
-
- /* initialize the interrupt mutex */
- mutex_init(&pepb_p->pepb_mutex, NULL, MUTEX_DRIVER,
- DDI_INTR_PRI(pepb_p->intr_priority));
- pepb_p->soft_state |= PEPB_SOFT_STATE_INIT_MUTEX;
-
- for (count = 0; count < pepb_p->intr_count; count++) {
- ret = ddi_intr_add_handler(pepb_p->htable[count],
- pepb_intr_handler, (caddr_t)pepb_p,
- (caddr_t)(uintptr_t)(inum + count));
-
- if (ret != DDI_SUCCESS) {
- PEPB_DEBUG((CE_WARN, "Cannot add interrupt(%d)\n",
- ret));
- break;
- }
- }
-
- /* If unsucessful, remove the added handlers */
- if (ret != DDI_SUCCESS) {
- for (x = 0; x < count; x++) {
- (void) ddi_intr_remove_handler(pepb_p->htable[x]);
- }
- goto FAIL;
- }
-
- pepb_p->soft_state |= PEPB_SOFT_STATE_INIT_HANDLER;
-
- (void) ddi_intr_get_cap(pepb_p->htable[0], &intr_cap);
-
- /*
- * Get this intr lock because we are not quite ready to handle
- * interrupts immediately after enabling it. The MSI multi register
- * gets programmed in ddi_intr_enable after which we need to get the
- * MSI offsets for Hotplug/AER.
- */
- mutex_enter(&pepb_p->pepb_mutex);
-
- if (intr_cap & DDI_INTR_FLAG_BLOCK) {
- (void) ddi_intr_block_enable(pepb_p->htable,
- pepb_p->intr_count);
- pepb_p->soft_state |= PEPB_SOFT_STATE_INIT_BLOCK;
- } else {
- for (count = 0; count < pepb_p->intr_count; count++) {
- (void) ddi_intr_enable(pepb_p->htable[count]);
- }
- }
- pepb_p->soft_state |= PEPB_SOFT_STATE_INIT_ENABLE;
-
- /* Save the interrupt type */
- pepb_p->intr_type = intr_type;
-
- /* Get the MSI offset for hotplug/PME from the PCIe cap reg */
- if (intr_type == DDI_INTR_TYPE_MSI) {
- hp_msi_off = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL,
- bus_p->bus_pcie_off, PCIE_PCIECAP) &
- PCIE_PCIECAP_INT_MSG_NUM;
-
- if (hp_msi_off >= count) {
- PEPB_DEBUG((CE_NOTE, "%s%d: MSI number %d in PCIe cap >"
- " max allocated %d\n", ddi_driver_name(dip),
- ddi_get_instance(dip), hp_msi_off, count));
- mutex_exit(&pepb_p->pepb_mutex);
- goto FAIL;
- }
-
- if (is_hp)
- pepb_p->isr_tab[hp_msi_off] |= PEPB_INTR_SRC_HP;
-
- if (is_pme)
- pepb_p->isr_tab[hp_msi_off] |= PEPB_INTR_SRC_PME;
- } else {
- /* INTx handles only Hotplug interrupts */
- if (is_hp)
- pepb_p->isr_tab[0] |= PEPB_INTR_SRC_HP;
- }
-
- /*
- * Get the MSI offset for errors from the AER Root Error status
- * register.
- */
- if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p)) {
- if (PCIE_HAS_AER(bus_p)) {
- aer_msi_off = (PCI_XCAP_GET32(bus_p->bus_cfg_hdl, NULL,
- bus_p->bus_aer_off, PCIE_AER_RE_STS) >>
- PCIE_AER_RE_STS_MSG_NUM_SHIFT) &
- PCIE_AER_RE_STS_MSG_NUM_MASK;
-
- if (aer_msi_off >= count) {
- PEPB_DEBUG((CE_NOTE, "%s%d: MSI number %d in"
- " AER cap > max allocated %d\n",
- ddi_driver_name(dip), ddi_get_instance(dip),
- aer_msi_off, count));
- mutex_exit(&pepb_p->pepb_mutex);
- goto FAIL;
- }
- pepb_p->isr_tab[aer_msi_off] |= PEPB_INTR_SRC_AER;
- } else {
- /*
- * This RP does not have AER. Fallback to the
- * SERR+Machinecheck approach.
- */
- pepb_p->pepb_no_aer_msi = B_TRUE;
- }
- }
-
- mutex_exit(&pepb_p->pepb_mutex);
-
- return (DDI_SUCCESS);
-
-FAIL:
- pepb_intr_fini(pepb_p);
-
- return (DDI_FAILURE);
-}
-
-static void
-pepb_intr_fini(pepb_devstate_t *pepb_p)
-{
- int x;
- int count = pepb_p->intr_count;
- int flags = pepb_p->soft_state;
-
- if ((flags & PEPB_SOFT_STATE_INIT_ENABLE) &&
- (flags & PEPB_SOFT_STATE_INIT_BLOCK)) {
- (void) ddi_intr_block_disable(pepb_p->htable, count);
- flags &= ~(PEPB_SOFT_STATE_INIT_ENABLE |
- PEPB_SOFT_STATE_INIT_BLOCK);
- }
-
- if (flags & PEPB_SOFT_STATE_INIT_MUTEX) {
- /* destroy the mutex */
- mutex_destroy(&pepb_p->pepb_mutex);
- }
-
- for (x = 0; x < count; x++) {
- if (flags & PEPB_SOFT_STATE_INIT_ENABLE)
- (void) ddi_intr_disable(pepb_p->htable[x]);
-
- if (flags & PEPB_SOFT_STATE_INIT_HANDLER)
- (void) ddi_intr_remove_handler(pepb_p->htable[x]);
-
- if (flags & PEPB_SOFT_STATE_INIT_ALLOC)
- (void) ddi_intr_free(pepb_p->htable[x]);
- }
-
- flags &= ~(PEPB_SOFT_STATE_INIT_ENABLE |
- PEPB_SOFT_STATE_INIT_HANDLER |
- PEPB_SOFT_STATE_INIT_ALLOC | PEPB_SOFT_STATE_INIT_MUTEX);
-
- if (flags & PEPB_SOFT_STATE_INIT_HTABLE)
- kmem_free(pepb_p->htable, pepb_p->htable_size);
-
- flags &= ~PEPB_SOFT_STATE_INIT_HTABLE;
-
- pepb_p->soft_state &= flags;
-}
-
-/*
- * Checks if this device needs MSIs enabled or not.
- */
-static int
-pepb_msi_intr_supported(dev_info_t *dip, int intr_type)
-{
- uint16_t vendor_id, device_id;
- pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
-
- if (!(intr_type & DDI_INTR_TYPE_MSI) || !pepb_enable_msi)
- return (DDI_FAILURE);
-
- vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
- device_id = bus_p->bus_dev_ven_id >> 16;
- /*
- * Intel ESB2 switches have a errata which prevents using MSIs
- * for hotplug.
- */
- if ((vendor_id == INTEL_VENDOR_ID) &&
- INTEL_ESB2_SW_PCIE_DEV_ID(device_id))
- return (DDI_FAILURE);
-
- return (DDI_SUCCESS);
-}
-
-/*ARGSUSED*/
-int
-pepb_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
- ddi_iblock_cookie_t *ibc)
-{
- pepb_devstate_t *pepb = ddi_get_soft_state(pepb_state,
- ddi_get_instance(dip));
-
- ASSERT(ibc != NULL);
- *ibc = pepb->pepb_fm_ibc;
-
- return (DEVI(dip)->devi_fmhdl->fh_cap);
-}
-
-static int
-pepb_check_slot_disabled(dev_info_t *dip)
-{
- return ((PCIE_CAP_GET(16, PCIE_DIP2BUS(dip), PCIE_LINKCTL) &
- PCIE_LINKCTL_LINK_DISABLE) ? 1 : 0);
-}
-
-static int
-pepb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
-{
- return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
-}
-
-static int
-pepb_close(dev_t dev, int flags, int otyp, cred_t *credp)
-{
- return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
-}
-
-static int
-pepb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
- int *rvalp)
-{
- int rv, inst;
- pepb_devstate_t *pepb;
- dev_info_t *dip;
-
- rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, credp,
- rvalp);
-
- /*
- * like in attach, since hotplugging can change error registers,
- * we need to ensure that the proper bits are set on this port
- * after a configure operation
- */
- if (rv == HPC_SUCCESS && cmd == DEVCTL_AP_CONFIGURE) {
- inst = PCIHP_AP_MINOR_NUM_TO_INSTANCE(getminor(dev));
- pepb = ddi_get_soft_state(pepb_state, inst);
- dip = pepb->dip;
-
- pepb_intel_serr_workaround(dip, pepb->pepb_no_aer_msi);
- pepb_intel_rber_workaround(dip);
- pepb_intel_sw_workaround(dip);
- }
-
- return (rv);
-}
-
-static int
-pepb_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
-pepb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
-{
- return (pcihp_info(dip, cmd, arg, result));
-}
-
-void
-pepb_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
- (void) pf_scan_fabric(dip, derr, NULL);
-}
-
-typedef struct x86_error_reg {
- uint32_t offset;
- uint_t size;
- uint32_t mask;
- uint32_t value1; /* Value for MSI case */
- uint32_t value2; /* Value for machinecheck case */
-} x86_error_reg_t;
-
-typedef struct x86_error_tbl {
- uint16_t vendor_id;
- uint16_t device_id_low;
- uint16_t device_id_high;
- uint8_t rev_id_low;
- uint8_t rev_id_high;
- x86_error_reg_t *error_regs;
- int error_regs_len;
-} x86_error_tbl_t;
-
-/*
- * Chipset and device specific settings that are required for error handling
- * (reporting, fowarding, and response at the RC) beyond the standard
- * registers in the PCIE and AER caps.
- *
- * The Northbridge Root Port settings also apply to the ESI port. The ESI
- * port is a special leaf device but functions like a root port connected
- * to the Southbridge and receives all the onboard Southbridge errors
- * including those from Southbridge Root Ports. However, this does not
- * include the Southbridge Switch Ports which act like normal switch ports
- * and is connected to the Northbridge through a separate link.
- *
- * PCIE errors from the ESB2 Southbridge RPs are simply fowarded to the ESI
- * port on the Northbridge.
- *
- * Currently without FMA support, we want UEs (Fatal and Non-Fatal) to panic
- * the system, except for URs. We do this by having the Root Ports respond
- * with a System Error and having that trigger a Machine Check (MCE).
- */
-
-/*
- * 7300 Northbridge Root Ports
- */
-static x86_error_reg_t intel_7300_rp_regs[] = {
- /* Command Register - Enable SERR */
- {0x4, 16, 0xFFFF, 0x0, PCI_COMM_SERR_ENABLE},
-
- /* Root Control Register - SERR on NFE/FE */
- {0x88, 16, 0x0, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
-
- /* AER UE Mask - Mask UR */
- {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-
- /* PEXCTRL[21] check for certain malformed TLP types and MSI enable */
- {0x48, 32, 0xFFFFFFFF, 0xC0200000, 0x200000},
- /* PEXCTRL3[7]. MSI RAS error enable */
- {0x4D, 32, 0xFFFFFFFF, 0x1, 0x0},
-
- /* PEX_ERR_DOCMD[7:0] */
- {0x144, 8, 0x0, 0x0, 0xF0},
-
- /* EMASK_UNCOR_PEX[21:0] UE mask */
- {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-
- /* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
- {0x150, 8, 0x0, 0x0, 0x1},
-};
-#define INTEL_7300_RP_REGS_LEN \
- (sizeof (intel_7300_rp_regs) / sizeof (x86_error_reg_t))
-
-/*
- * 5000 Northbridge Root Ports
- */
-static x86_error_reg_t intel_5000_rp_regs[] = {
- /* Command Register - Enable SERR */
- {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
-
- /* Root Control Register - SERR on NFE/FE/CE */
- {0x88, 16, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
- PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
-
- /* AER UE Mask - Mask UR */
- {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-
- /* PEXCTRL[21] check for certain malformed TLP type */
- {0x48, 32, 0xFFFFFFFF, 0xC0200000, 0x200000},
- /* PEXCTRL3[7]. MSI RAS error enable. */
- {0x4D, 32, 0xFFFFFFFF, 0x1, 0x0},
-
- /* PEX_ERR_DOCMD[7:0] */
- {0x144, 8, 0x0, 0x0, 0xF0},
-
- /* EMASK_UNCOR_PEX[21:0] UE mask */
- {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-
- /* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
- {0x150, 8, 0x0, 0x0, 0x1},
-};
-#define INTEL_5000_RP_REGS_LEN \
- (sizeof (intel_5000_rp_regs) / sizeof (x86_error_reg_t))
-
-/*
- * 5400 Northbridge Root Ports.
- */
-static x86_error_reg_t intel_5400_rp_regs[] = {
- /* Command Register - Enable SERR */
- {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
-
- /* Root Control Register - SERR on NFE/FE */
- {0x88, 16, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
- PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
-
- /* AER UE Mask - Mask UR */
- {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-
- /* PEXCTRL[21] check for certain malformed TLP types */
- {0x48, 32, 0xFFFFFFFF, 0xC0200000, 0x200000},
- /* PEXCTRL3. MSI RAS error enable. */
- {0x4E, 8, 0x0, 0x1, 0x0},
-
- /* PEX_ERR_DOCMD[11:0] */
- {0x144, 16, 0x0, 0x0, 0xFF0},
-
- /* PEX_ERR_PIN_MASK[4:0] do not mask ERR[2:0] pins used by DOCMD */
- {0x146, 16, 0x0, 0x10, 0x10},
-
- /* EMASK_UNCOR_PEX[21:0] UE mask */
- {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-
- /* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
- {0x150, 8, 0x0, 0x0, 0x1},
-};
-#define INTEL_5400_RP_REGS_LEN \
- (sizeof (intel_5400_rp_regs) / sizeof (x86_error_reg_t))
-
-
-/*
- * ESB2 Southbridge Root Ports
- */
-static x86_error_reg_t intel_esb2_rp_regs[] = {
- /* Command Register - Enable SERR */
- {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
-
- /* Root Control Register - SERR on NFE/FE */
- {0x5c, 16, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
- PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
- PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
-
- /* UEM[20:0] UE mask (write-once) */
- {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-};
-#define INTEL_ESB2_RP_REGS_LEN \
- (sizeof (intel_esb2_rp_regs) / sizeof (x86_error_reg_t))
-
-
-/*
- * ESB2 Southbridge Switch Ports
- */
-static x86_error_reg_t intel_esb2_sw_regs[] = {
- /* Command Register - Enable SERR */
- {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
-
- /* AER UE Mask - Mask UR */
- {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
-};
-#define INTEL_ESB2_SW_REGS_LEN \
- (sizeof (intel_esb2_sw_regs) / sizeof (x86_error_reg_t))
-
-
-x86_error_tbl_t x86_error_init_tbl[] = {
- /* Intel 7300: 3600 = ESI, 3604-360A = NB root ports */
- {0x8086, 0x3600, 0x3600, 0x0, 0xFF,
- intel_7300_rp_regs, INTEL_7300_RP_REGS_LEN},
- {0x8086, 0x3604, 0x360A, 0x0, 0xFF,
- intel_7300_rp_regs, INTEL_7300_RP_REGS_LEN},
-
- /* Intel 5000: 25C0, 25D0, 25D4, 25D8 = ESI */
- {0x8086, 0x25C0, 0x25C0, 0x0, 0xFF,
- intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
- {0x8086, 0x25D0, 0x25D0, 0x0, 0xFF,
- intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
- {0x8086, 0x25D4, 0x25D4, 0x0, 0xFF,
- intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
- {0x8086, 0x25D8, 0x25D8, 0x0, 0xFF,
- intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
-
- /* Intel 5000: 25E2-25E7 and 25F7-25FA = NB root ports */
- {0x8086, 0x25E2, 0x25E7, 0x0, 0xFF,
- intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
- {0x8086, 0x25F7, 0x25FA, 0x0, 0xFF,
- intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
-
- /* Intel 5400: 4000-4001, 4003 = ESI and 4021-4029 = NB root ports */
- {0x8086, 0x4000, 0x4001, 0x0, 0xFF,
- intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
- {0x8086, 0x4003, 0x4003, 0x0, 0xFF,
- intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
- {0x8086, 0x4021, 0x4029, 0x0, 0xFF,
- intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
-
- /* Intel 631xESB/632xESB aka ESB2: 2690-2697 = SB root ports */
- {0x8086, 0x2690, 0x2697, 0x0, 0xFF,
- intel_esb2_rp_regs, INTEL_ESB2_RP_REGS_LEN},
-
- /* Intel Switches on esb2: 3500-3503, 3510-351B */
- {0x8086, 0x3500, 0x3503, 0x0, 0xFF,
- intel_esb2_sw_regs, INTEL_ESB2_SW_REGS_LEN},
- {0x8086, 0x3510, 0x351B, 0x0, 0xFF,
- intel_esb2_sw_regs, INTEL_ESB2_SW_REGS_LEN},
-
- /* XXX Intel PCIe-PCIx on esb2: 350C */
-};
-static int x86_error_init_tbl_len =
- sizeof (x86_error_init_tbl) / sizeof (x86_error_tbl_t);
-
-
-static int
-pepb_get_bdf(dev_info_t *dip, int *busp, int *devp, int *funcp)
-{
- pci_regspec_t *regspec;
- int reglen;
- int rv;
-
- rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "reg", (int **)&regspec, (uint_t *)&reglen);
- if (rv != DDI_SUCCESS)
- return (rv);
-
- if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) {
- ddi_prop_free(regspec);
- return (DDI_FAILURE);
- }
-
- /* Get phys_hi from first element. All have same bdf. */
- *busp = PCI_REG_BUS_G(regspec->pci_phys_hi);
- *devp = PCI_REG_DEV_G(regspec->pci_phys_hi);
- *funcp = PCI_REG_FUNC_G(regspec->pci_phys_hi);
-
- ddi_prop_free(regspec);
- return (DDI_SUCCESS);
-}
-
-/*
- * The main goal of this workaround is to set chipset specific settings if
- * MSIs happen to be enabled on this device. Otherwise make the system
- * Machine Check/Panic if an UE is detected in the fabric.
- */
-static void
-pepb_intel_serr_workaround(dev_info_t *dip, boolean_t mcheck)
-{
- uint16_t vid, did;
- uint8_t rid;
- int bus, dev, func;
- int i, j;
- x86_error_tbl_t *tbl;
- x86_error_reg_t *reg;
- ddi_acc_handle_t cfg_hdl;
- pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
- uint16_t bdf = bus_p->bus_bdf;
-
- if (pepb_intel_workaround_disable)
- return;
-
- (void) pci_config_setup(dip, &cfg_hdl);
- vid = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
- did = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
- rid = pci_config_get8(cfg_hdl, PCI_CONF_REVID);
-
- if (pepb_get_bdf(dip, &bus, &dev, &func) != DDI_SUCCESS) {
- PEPB_DEBUG((CE_WARN, "%s#%d: pepb_get_bdf() failed",
- ddi_driver_name(dip), ddi_get_instance(dip)));
- return;
- }
-
- PEPB_DEBUG((CE_NOTE, "VID:0x%x DID:0x%x RID:0x%x bdf=%x.%x.%x, "
- "dip:0x%p", vid, did, rid, bus, dev, func, (void *)dip));
-
- tbl = x86_error_init_tbl;
- for (i = 0; i < x86_error_init_tbl_len; i++, tbl++) {
- if (!((vid == tbl->vendor_id) &&
- (did >= tbl->device_id_low) &&
- (did <= tbl->device_id_high) &&
- (rid >= tbl->rev_id_low) &&
- (rid <= tbl->rev_id_high)))
- continue;
-
- if (mcheck && PCIE_IS_RP(bus_p))
- pcie_set_rber_fatal(dip, B_TRUE);
-
- reg = tbl->error_regs;
- for (j = 0; j < tbl->error_regs_len; j++, reg++) {
- uint32_t data = 0xDEADBEEF;
- uint32_t value = 0xDEADBEEF;
- switch (reg->size) {
- case 32:
- data = (uint32_t)pci_config_get32(cfg_hdl,
- reg->offset);
- value = (mcheck ?
- ((data & reg->mask) | reg->value2) :
- ((data & reg->mask) | reg->value1));
- pci_config_put32(cfg_hdl, reg->offset, value);
- value = (uint32_t)pci_config_get32(cfg_hdl,
- reg->offset);
- break;
- case 16:
- data = (uint32_t)pci_config_get16(cfg_hdl,
- reg->offset);
- value = (mcheck ?
- ((data & reg->mask) | reg->value2) :
- ((data & reg->mask) | reg->value1));
- pci_config_put16(cfg_hdl, reg->offset,
- (uint16_t)value);
- value = (uint32_t)pci_config_get16(cfg_hdl,
- reg->offset);
- break;
- case 8:
- data = (uint32_t)pci_config_get8(cfg_hdl,
- reg->offset);
- value = (mcheck ?
- ((data & reg->mask) | reg->value2) :
- ((data & reg->mask) | reg->value1));
- pci_config_put8(cfg_hdl, reg->offset,
- (uint8_t)value);
- value = (uint32_t)pci_config_get8(cfg_hdl,
- reg->offset);
- break;
- }
-
- PEPB_DEBUG((CE_NOTE, "bdf:%x mcheck:%d size:%d off:0x%x"
- " mask:0x%x value:0x%x + orig:0x%x -> 0x%x", bdf,
- mcheck, reg->size, reg->offset, reg->mask,
- (mcheck ? reg->value2 : reg->value1),
- data, value));
- }
- }
-
- pci_config_teardown(&cfg_hdl);
-}
-
-/*
- * For devices that support Role Base Errors, make several UE have a FATAL
- * severity. That way a Fatal Message will be sent instead of a Correctable
- * Message. Without full FMA support, CEs will be ignored.
- */
-uint32_t pepb_rber_sev = (PCIE_AER_UCE_TRAINING | PCIE_AER_UCE_DLP |
- PCIE_AER_UCE_SD | PCIE_AER_UCE_PTLP | PCIE_AER_UCE_FCP | PCIE_AER_UCE_TO |
- PCIE_AER_UCE_CA | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP | PCIE_AER_UCE_ECRC);
-
-static void
-pepb_intel_rber_workaround(dev_info_t *dip)
-{
- uint32_t rber;
- pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
-
- if (pepb_intel_workaround_disable)
- return;
-
- /*
- * Check Root Port's machinecheck setting to determine if this
- * workaround is needed or not.
- */
- if (!pcie_get_rber_fatal(dip))
- return;
-
- if (!PCIE_IS_PCIE(bus_p) || !PCIE_HAS_AER(bus_p))
- return;
-
- rber = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
- PCIE_DEVCAP_ROLE_BASED_ERR_REP;
- if (!rber)
- return;
-
- PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, pepb_rber_sev);
-}
-
-/*
- * Workaround for certain switches regardless of platform
- */
-static void
-pepb_intel_sw_workaround(dev_info_t *dip)
-{
- uint16_t vid, regw;
- ddi_acc_handle_t cfg_hdl;
-
- if (pepb_intel_workaround_disable)
- return;
-
- if (!PCIE_IS_SW(PCIE_DIP2BUS(dip)))
- return;
-
- (void) pci_config_setup(dip, &cfg_hdl);
- vid = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
-
- /*
- * Intel and PLX switches require SERR in CMD reg to foward error
- * messages, though this is not PCIE spec-compliant behavior.
- * To prevent the switches themselves from reporting errors on URs
- * when the CMD reg has SERR enabled (which is expected according to
- * the PCIE spec) we rely on masking URs in the AER cap.
- */
- if (vid == 0x8086 || vid == 0x10B5) {
- regw = pci_config_get16(cfg_hdl, PCI_CONF_COMM);
- pci_config_put16(cfg_hdl, PCI_CONF_COMM,
- regw | PCI_COMM_SERR_ENABLE);
- }
-
- pci_config_teardown(&cfg_hdl);
-}
-
-/*
- * The Intel 5000 Chipset has an errata that requires read completion
- * coalescing to be disabled if the Max Payload Size is set to 256 bytes.
- */
-static void
-pepb_intel_mps_workaround(dev_info_t *dip)
-{
- uint16_t vid, did;
- uint32_t pexctrl;
- pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
-
- vid = bus_p->bus_dev_ven_id & 0xFFFF;
- did = bus_p->bus_dev_ven_id >> 16;
-
- if ((vid == INTEL_VENDOR_ID) && INTEL_NB5000_PCIE_DEV_ID(did)) {
- pexctrl = pci_config_get32(bus_p->bus_cfg_hdl,
- INTEL_NB5000_PEXCTRL_OFFSET);
- /*
- * Turn off coalescing (bit 10)
- */
- pexctrl &= ~INTEL_NB5000_PEXCTRL_COALESCE_EN;
-
- pci_config_put32(bus_p->bus_cfg_hdl,
- INTEL_NB5000_PEXCTRL_OFFSET, pexctrl);
- }
-}
-
-/*
- * Common interrupt handler for hotplug, PME and errors.
- */
-static uint_t
-pepb_intr_handler(caddr_t arg1, caddr_t arg2)
-{
- pepb_devstate_t *pepb_p = (pepb_devstate_t *)arg1;
- dev_info_t *dip = pepb_p->dip;
- ddi_fm_error_t derr;
- int sts = 0;
- int ret = DDI_INTR_UNCLAIMED;
- int isrc;
-
- mutex_enter(&pepb_p->pepb_mutex);
- if (!(pepb_p->soft_state & PEPB_SOFT_STATE_INIT_ENABLE))
- goto FAIL;
-
- isrc = pepb_p->isr_tab[(int)(uintptr_t)arg2];
-
- PEPB_DEBUG((CE_NOTE, "pepb_intr_handler: received intr number %d\n",
- (int)(uintptr_t)arg2));
-
- if (isrc == PEPB_INTR_SRC_UNKNOWN)
- goto FAIL;
-
- if (isrc & PEPB_INTR_SRC_HP)
- ret = pciehpc_intr(dip);
-
- if (isrc & PEPB_INTR_SRC_PME) {
- PEPB_DEBUG((CE_NOTE, "pepb_pwr_msi_intr: received intr number"
- "%d\n", (int)(uintptr_t)arg2));
- ret = DDI_INTR_CLAIMED;
- }
-
- /* AER Error */
- if (isrc & PEPB_INTR_SRC_AER) {
- /*
- * If MSI is shared with PME/hotplug then check Root Error
- * Status Reg before claiming it. For now it's ok since
- * we know we get 2 MSIs.
- */
- ret = DDI_INTR_CLAIMED;
- bzero(&derr, sizeof (ddi_fm_error_t));
- derr.fme_version = DDI_FME_VERSION;
- mutex_enter(&pepb_p->pepb_peek_poke_mutex);
- mutex_enter(&pepb_p->pepb_err_mutex);
-
- if ((DEVI(dip)->devi_fmhdl->fh_cap) & DDI_FM_EREPORT_CAPABLE)
- sts = pf_scan_fabric(dip, &derr, NULL);
-
- mutex_exit(&pepb_p->pepb_err_mutex);
- mutex_exit(&pepb_p->pepb_peek_poke_mutex);
-
- if (pepb_die & sts)
- fm_panic("%s-%d: PCI(-X) Express Fatal Error",
- ddi_driver_name(dip), ddi_get_instance(dip));
- }
-FAIL:
- mutex_exit(&pepb_p->pepb_mutex);
- return (ret);
-}
diff --git a/usr/src/uts/intel/io/pciex/pcie_pci.conf b/usr/src/uts/intel/io/pciex/pcie_pci.conf
deleted file mode 100644
index b8d0d8b148..0000000000
--- a/usr/src/uts/intel/io/pciex/pcie_pci.conf
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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 2005 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Force load driver to support hotplug activity
-#
-ddi-forceattach=1;
-
-#
-# force interrupt priorities to be one
-# otherwise this driver binds as bridge device with priority 12
-#
-interrupt-priorities=1;
diff --git a/usr/src/uts/intel/io/pciex/pcieb_x86.c b/usr/src/uts/intel/io/pciex/pcieb_x86.c
new file mode 100644
index 0000000000..605b7aa509
--- /dev/null
+++ b/usr/src/uts/intel/io/pciex/pcieb_x86.c
@@ -0,0 +1,679 @@
+/*
+ * 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.
+ */
+
+/* x86 specific code used by the pcieb driver */
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/kmem.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/pcie.h>
+#include <sys/pci_cap.h>
+#include <sys/pcie_impl.h>
+#include <sys/pcie_acpi.h>
+#include <sys/hotplug/hpctrl.h>
+#include <io/pciex/pcieb.h>
+#include <io/pciex/pcie_nb5000.h>
+
+/* Flag to turn off intel error handling workarounds */
+int pcieb_intel_workaround_disable = 0;
+
+void
+pcieb_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
+ (void) pf_scan_fabric(dip, derr, NULL);
+}
+
+int
+pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
+ void *arg, void *result)
+{
+ pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
+ ddi_get_instance(dip));
+
+ if (!PCIE_IS_RP(PCIE_DIP2BUS(dip)))
+ return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
+ return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
+ ddi_ctlops, &pcieb->pcieb_err_mutex,
+ &pcieb->pcieb_peek_poke_mutex,
+ pcieb_peekpoke_cb));
+}
+
+/* x86 specific workarounds needed at the end of pcieb attach */
+void
+pcieb_plat_attach_workaround(dev_info_t *dip)
+{
+ /* Must apply workaround only after all initialization is done */
+ pcieb_intel_error_workaround(dip);
+ pcieb_intel_mps_workaround(dip);
+
+}
+
+/* Workarounds to enable error handling on certain Intel chipsets */
+void
+pcieb_intel_error_workaround(dev_info_t *dip)
+{
+ pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
+ ddi_get_instance(dip));
+
+ pcieb_intel_serr_workaround(dip, pcieb->pcieb_no_aer_msi);
+ pcieb_intel_rber_workaround(dip);
+ pcieb_intel_sw_workaround(dip);
+}
+
+int
+pcieb_plat_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
+ ddi_intr_handle_impl_t *hdlp, void *result)
+{
+ return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
+}
+
+/* shpc is not supported on x86 */
+/*ARGSUSED*/
+int
+pcieb_plat_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+ return (DDI_FAILURE);
+}
+
+/*
+ * Dummy functions to get around the fact that there's no shpc module on x86
+ * today
+ */
+/*ARGSUSED*/
+int
+pcishpc_init(dev_info_t *dip)
+{
+ return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+int
+pcishpc_uninit(dev_info_t *dip)
+{
+ return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+int
+pcishpc_intr(dev_info_t *dip)
+{
+ return (DDI_INTR_UNCLAIMED);
+}
+
+/*ARGSUSED*/
+boolean_t
+pcieb_plat_pwr_disable(dev_info_t *dip)
+{
+ /* Always disable on x86 */
+ return (B_TRUE);
+}
+
+boolean_t
+pcieb_plat_msi_supported(dev_info_t *dip)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
+ uint16_t vendor_id, device_id;
+ vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
+ device_id = bus_p->bus_dev_ven_id >> 16;
+
+ /*
+ * Intel ESB2 switches have a errata which prevents using MSIs
+ * for hotplug.
+ */
+ return (((vendor_id == INTEL_VENDOR_ID) &&
+ INTEL_ESB2_SW_PCIE_DEV_ID(device_id)) ? B_FALSE : B_TRUE);
+}
+
+void
+pcieb_plat_intr_attach(pcieb_devstate_t *pcieb)
+{
+ /*
+ * _OSC initialization needs to be done before interrupts are
+ * initialized.
+ */
+ pcieb_init_osc(pcieb->pcieb_dip);
+}
+
+void
+pcieb_plat_initchild(dev_info_t *child)
+{
+ struct ddi_parent_private_data *pdptr;
+ 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);
+}
+
+void
+pcieb_plat_uninitchild(dev_info_t *child)
+{
+ struct ddi_parent_private_data *pdptr;
+
+ if ((pdptr = ddi_get_parent_data(child)) != NULL)
+ kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
+
+ ddi_set_parent_data(child, NULL);
+}
+
+/* _OSC related */
+void
+pcieb_init_osc(dev_info_t *devi) {
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(devi);
+ uint32_t osc_flags = OSC_CONTROL_PCIE_ADV_ERR;
+
+ /*
+ * Call _OSC method for 2 reasons:
+ * 1. Hotplug: To determine if it is native or ACPI mode.
+ *
+ * 2. Error handling: Inform firmware that OS can support AER error
+ * handling. Currently we don't care for what the BIOS response was
+ * and instead setup interrupts for error handling as if it were
+ * supported.
+ *
+ * For hotpluggable slots the _OSC method has already been called as
+ * part of the hotplug initialization.
+ * For non-hotpluggable slots we need to call the _OSC method only for
+ * Root Ports (for AER support).
+ */
+ if (!pcie_is_osc(devi) && PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p))
+ (void) pcie_acpi_osc(devi, &osc_flags);
+}
+
+/*
+ * Intel chip specific workarounds. Right now they're limited to the 5000, 5400
+ * and 7300 series chipsets.
+ */
+typedef struct x86_error_reg {
+ uint32_t offset;
+ uint_t size;
+ uint32_t mask;
+ uint32_t value1; /* Value for MSI case */
+ uint32_t value2; /* Value for machinecheck case */
+} x86_error_reg_t;
+
+typedef struct x86_error_tbl {
+ uint16_t vendor_id;
+ uint16_t device_id_low;
+ uint16_t device_id_high;
+ uint8_t rev_id_low;
+ uint8_t rev_id_high;
+ x86_error_reg_t *error_regs;
+ int error_regs_len;
+} x86_error_tbl_t;
+
+/*
+ * Chipset and device specific settings that are required for error handling
+ * (reporting, fowarding, and response at the RC) beyond the standard
+ * registers in the PCIE and AER caps.
+ *
+ * The Northbridge Root Port settings also apply to the ESI port. The ESI
+ * port is a special leaf device but functions like a root port connected
+ * to the Southbridge and receives all the onboard Southbridge errors
+ * including those from Southbridge Root Ports. However, this does not
+ * include the Southbridge Switch Ports which act like normal switch ports
+ * and is connected to the Northbridge through a separate link.
+ *
+ * PCIE errors from the ESB2 Southbridge RPs are simply fowarded to the ESI
+ * port on the Northbridge.
+ *
+ * If MSIs don't work we want UEs (Fatal and Non-Fatal) to panic the system,
+ * except for URs. We do this by having the Root Ports respond with a System
+ * Error and having that trigger a Machine Check (MCE).
+ */
+
+/*
+ * 7300 Northbridge Root Ports
+ */
+static x86_error_reg_t intel_7300_rp_regs[] = {
+ /* Command Register - Enable SERR */
+ {0x4, 16, 0xFFFF, 0x0, PCI_COMM_SERR_ENABLE},
+
+ /* Root Control Register - SERR on NFE/FE */
+ {0x88, 16, 0x0, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
+
+ /* AER UE Mask - Mask UR */
+ {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+
+ /* PEXCTRL[21] check for certain malformed TLP types and MSI enable */
+ {0x48, 32, 0xFFFFFFFF, 0xC0200000, 0x200000},
+ /* PEXCTRL3[7]. MSI RAS error enable */
+ {0x4D, 32, 0xFFFFFFFF, 0x1, 0x0},
+
+ /* PEX_ERR_DOCMD[7:0] */
+ {0x144, 8, 0x0, 0x0, 0xF0},
+
+ /* EMASK_UNCOR_PEX[21:0] UE mask */
+ {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+
+ /* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
+ {0x150, 8, 0x0, 0x0, 0x1},
+};
+#define INTEL_7300_RP_REGS_LEN \
+ (sizeof (intel_7300_rp_regs) / sizeof (x86_error_reg_t))
+
+/*
+ * 5000 Northbridge Root Ports
+ */
+static x86_error_reg_t intel_5000_rp_regs[] = {
+ /* Command Register - Enable SERR */
+ {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
+
+ /* Root Control Register - SERR on NFE/FE/CE */
+ {0x88, 16, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
+ PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
+
+ /* AER UE Mask - Mask UR */
+ {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+
+ /* PEXCTRL[21] check for certain malformed TLP type */
+ {0x48, 32, 0xFFFFFFFF, 0xC0200000, 0x200000},
+ /* PEXCTRL3[7]. MSI RAS error enable. */
+ {0x4D, 32, 0xFFFFFFFF, 0x1, 0x0},
+
+ /* PEX_ERR_DOCMD[7:0] */
+ {0x144, 8, 0x0, 0x0, 0xF0},
+
+ /* EMASK_UNCOR_PEX[21:0] UE mask */
+ {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+
+ /* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
+ {0x150, 8, 0x0, 0x0, 0x1},
+};
+#define INTEL_5000_RP_REGS_LEN \
+ (sizeof (intel_5000_rp_regs) / sizeof (x86_error_reg_t))
+
+/*
+ * 5400 Northbridge Root Ports.
+ */
+static x86_error_reg_t intel_5400_rp_regs[] = {
+ /* Command Register - Enable SERR */
+ {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
+
+ /* Root Control Register - SERR on NFE/FE */
+ {0x88, 16, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
+ PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
+
+ /* AER UE Mask - Mask UR */
+ {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+
+ /* PEXCTRL[21] check for certain malformed TLP types */
+ {0x48, 32, 0xFFFFFFFF, 0xC0200000, 0x200000},
+ /* PEXCTRL3. MSI RAS error enable. */
+ {0x4E, 8, 0x0, 0x1, 0x0},
+
+ /* PEX_ERR_DOCMD[11:0] */
+ {0x144, 16, 0x0, 0x0, 0xFF0},
+
+ /* PEX_ERR_PIN_MASK[4:0] do not mask ERR[2:0] pins used by DOCMD */
+ {0x146, 16, 0x0, 0x10, 0x10},
+
+ /* EMASK_UNCOR_PEX[21:0] UE mask */
+ {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+
+ /* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
+ {0x150, 8, 0x0, 0x0, 0x1},
+};
+#define INTEL_5400_RP_REGS_LEN \
+ (sizeof (intel_5400_rp_regs) / sizeof (x86_error_reg_t))
+
+
+/*
+ * ESB2 Southbridge Root Ports
+ */
+static x86_error_reg_t intel_esb2_rp_regs[] = {
+ /* Command Register - Enable SERR */
+ {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
+
+ /* Root Control Register - SERR on NFE/FE */
+ {0x5c, 16, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
+ PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
+
+ /* UEM[20:0] UE mask (write-once) */
+ {0x148, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+};
+#define INTEL_ESB2_RP_REGS_LEN \
+ (sizeof (intel_esb2_rp_regs) / sizeof (x86_error_reg_t))
+
+
+/*
+ * ESB2 Southbridge Switch Ports
+ */
+static x86_error_reg_t intel_esb2_sw_regs[] = {
+ /* Command Register - Enable SERR */
+ {0x4, 16, 0xFFFF, PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
+
+ /* AER UE Mask - Mask UR */
+ {0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
+};
+#define INTEL_ESB2_SW_REGS_LEN \
+ (sizeof (intel_esb2_sw_regs) / sizeof (x86_error_reg_t))
+
+
+x86_error_tbl_t x86_error_init_tbl[] = {
+ /* Intel 7300: 3600 = ESI, 3604-360A = NB root ports */
+ {0x8086, 0x3600, 0x3600, 0x0, 0xFF,
+ intel_7300_rp_regs, INTEL_7300_RP_REGS_LEN},
+ {0x8086, 0x3604, 0x360A, 0x0, 0xFF,
+ intel_7300_rp_regs, INTEL_7300_RP_REGS_LEN},
+
+ /* Intel 5000: 25C0, 25D0, 25D4, 25D8 = ESI */
+ {0x8086, 0x25C0, 0x25C0, 0x0, 0xFF,
+ intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
+ {0x8086, 0x25D0, 0x25D0, 0x0, 0xFF,
+ intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
+ {0x8086, 0x25D4, 0x25D4, 0x0, 0xFF,
+ intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
+ {0x8086, 0x25D8, 0x25D8, 0x0, 0xFF,
+ intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
+
+ /* Intel 5000: 25E2-25E7 and 25F7-25FA = NB root ports */
+ {0x8086, 0x25E2, 0x25E7, 0x0, 0xFF,
+ intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
+ {0x8086, 0x25F7, 0x25FA, 0x0, 0xFF,
+ intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
+
+ /* Intel 5400: 4000-4001, 4003 = ESI and 4021-4029 = NB root ports */
+ {0x8086, 0x4000, 0x4001, 0x0, 0xFF,
+ intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
+ {0x8086, 0x4003, 0x4003, 0x0, 0xFF,
+ intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
+ {0x8086, 0x4021, 0x4029, 0x0, 0xFF,
+ intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
+
+ /* Intel 631xESB/632xESB aka ESB2: 2690-2697 = SB root ports */
+ {0x8086, 0x2690, 0x2697, 0x0, 0xFF,
+ intel_esb2_rp_regs, INTEL_ESB2_RP_REGS_LEN},
+
+ /* Intel Switches on esb2: 3500-3503, 3510-351B */
+ {0x8086, 0x3500, 0x3503, 0x0, 0xFF,
+ intel_esb2_sw_regs, INTEL_ESB2_SW_REGS_LEN},
+ {0x8086, 0x3510, 0x351B, 0x0, 0xFF,
+ intel_esb2_sw_regs, INTEL_ESB2_SW_REGS_LEN},
+
+ /* XXX Intel PCIe-PCIx on esb2: 350C */
+};
+static int x86_error_init_tbl_len =
+ sizeof (x86_error_init_tbl) / sizeof (x86_error_tbl_t);
+
+/*
+ * The main goal of this workaround is to set chipset specific settings if
+ * MSIs happen to be enabled on this device. Otherwise make the system
+ * Machine Check/Panic if an UE is detected in the fabric.
+ */
+void
+pcieb_intel_serr_workaround(dev_info_t *dip, boolean_t mcheck)
+{
+ uint16_t vid, did;
+ uint8_t rid;
+ int i, j;
+ x86_error_tbl_t *tbl;
+ x86_error_reg_t *reg;
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
+ ddi_acc_handle_t cfg_hdl = bus_p->bus_cfg_hdl;
+ uint16_t bdf = bus_p->bus_bdf;
+
+ if (pcieb_intel_workaround_disable)
+ return;
+
+ vid = bus_p->bus_dev_ven_id & 0xFFFF;
+ did = bus_p->bus_dev_ven_id >> 16;
+ rid = bus_p->bus_rev_id;
+
+ PCIEB_DEBUG(DBG_ATTACH, dip, "VID:0x%x DID:0x%x RID:0x%x bdf=0x%x\n",
+ vid, did, rid, bdf);
+
+ tbl = x86_error_init_tbl;
+ for (i = 0; i < x86_error_init_tbl_len; i++, tbl++) {
+ if (!((vid == tbl->vendor_id) &&
+ (did >= tbl->device_id_low) &&
+ (did <= tbl->device_id_high) &&
+ (rid >= tbl->rev_id_low) &&
+ (rid <= tbl->rev_id_high)))
+ continue;
+
+ if (mcheck && PCIE_IS_RP(bus_p))
+ pcie_set_rber_fatal(dip, B_TRUE);
+
+ reg = tbl->error_regs;
+ for (j = 0; j < tbl->error_regs_len; j++, reg++) {
+ uint32_t data = 0xDEADBEEF;
+ uint32_t value = 0xDEADBEEF;
+ switch (reg->size) {
+ case 32:
+ data = (uint32_t)pci_config_get32(cfg_hdl,
+ reg->offset);
+ value = (mcheck ?
+ ((data & reg->mask) | reg->value2) :
+ ((data & reg->mask) | reg->value1));
+ pci_config_put32(cfg_hdl, reg->offset, value);
+ value = (uint32_t)pci_config_get32(cfg_hdl,
+ reg->offset);
+ break;
+ case 16:
+ data = (uint32_t)pci_config_get16(cfg_hdl,
+ reg->offset);
+ value = (mcheck ?
+ ((data & reg->mask) | reg->value2) :
+ ((data & reg->mask) | reg->value1));
+ pci_config_put16(cfg_hdl, reg->offset,
+ (uint16_t)value);
+ value = (uint32_t)pci_config_get16(cfg_hdl,
+ reg->offset);
+ break;
+ case 8:
+ data = (uint32_t)pci_config_get8(cfg_hdl,
+ reg->offset);
+ value = (mcheck ?
+ ((data & reg->mask) | reg->value2) :
+ ((data & reg->mask) | reg->value1));
+ pci_config_put8(cfg_hdl, reg->offset,
+ (uint8_t)value);
+ value = (uint32_t)pci_config_get8(cfg_hdl,
+ reg->offset);
+ break;
+ }
+
+ PCIEB_DEBUG(DBG_ATTACH, dip, "bdf:%x mcheck:%d size:%d "
+ "off:0x%x mask:0x%x value:0x%x + orig:0x%x -> "
+ "0x%x\n", bdf, mcheck, reg->size, reg->offset,
+ reg->mask, (mcheck ? reg->value2 : reg->value1),
+ data, value);
+ }
+ }
+}
+
+/*
+ * For devices that support Role Base Errors, make several UE have a FATAL
+ * severity. That way a Fatal Message will be sent instead of a Correctable
+ * Message. Without full FMA support, CEs will be ignored.
+ */
+uint32_t pcieb_rber_sev = (PCIE_AER_UCE_TRAINING | PCIE_AER_UCE_DLP |
+ PCIE_AER_UCE_SD | PCIE_AER_UCE_PTLP | PCIE_AER_UCE_FCP | PCIE_AER_UCE_TO |
+ PCIE_AER_UCE_CA | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP | PCIE_AER_UCE_ECRC);
+
+void
+pcieb_intel_rber_workaround(dev_info_t *dip)
+{
+ uint32_t rber;
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
+
+ if (pcieb_intel_workaround_disable)
+ return;
+
+ /*
+ * Check Root Port's machinecheck setting to determine if this
+ * workaround is needed or not.
+ */
+ if (!pcie_get_rber_fatal(dip))
+ return;
+
+ if (!PCIE_IS_PCIE(bus_p) || !PCIE_HAS_AER(bus_p))
+ return;
+
+ rber = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
+ PCIE_DEVCAP_ROLE_BASED_ERR_REP;
+ if (!rber)
+ return;
+
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, pcieb_rber_sev);
+}
+
+/*
+ * The Intel 5000 Chipset has an errata that requires read completion
+ * coalescing to be disabled if the Max Payload Size is set to 256 bytes.
+ */
+void
+pcieb_intel_mps_workaround(dev_info_t *dip)
+{
+ uint16_t vid, did;
+ uint32_t pexctrl;
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
+
+ vid = bus_p->bus_dev_ven_id & 0xFFFF;
+ did = bus_p->bus_dev_ven_id >> 16;
+
+ if ((vid == INTEL_VENDOR_ID) && INTEL_NB5000_PCIE_DEV_ID(did)) {
+ pexctrl = pci_config_get32(bus_p->bus_cfg_hdl,
+ INTEL_NB5000_PEXCTRL_OFFSET);
+ /*
+ * Turn off coalescing (bit 10)
+ */
+ pexctrl &= ~INTEL_NB5000_PEXCTRL_COALESCE_EN;
+
+ pci_config_put32(bus_p->bus_cfg_hdl,
+ INTEL_NB5000_PEXCTRL_OFFSET, pexctrl);
+ }
+}
+
+/*
+ * Workaround for certain switches regardless of platform
+ */
+void
+pcieb_intel_sw_workaround(dev_info_t *dip)
+{
+ uint16_t vid, regw;
+ pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
+ ddi_acc_handle_t cfg_hdl = bus_p->bus_cfg_hdl;
+
+ if (pcieb_intel_workaround_disable)
+ return;
+
+ if (!PCIE_IS_SW(PCIE_DIP2BUS(dip)))
+ return;
+
+ vid = bus_p->bus_dev_ven_id & 0xFFFF;
+ /*
+ * Intel and PLX switches require SERR in CMD reg to foward error
+ * messages, though this is not PCIE spec-compliant behavior.
+ * To prevent the switches themselves from reporting errors on URs
+ * when the CMD reg has SERR enabled (which is expected according to
+ * the PCIE spec) we rely on masking URs in the AER cap.
+ */
+ if (vid == 0x8086 || vid == 0x10B5) {
+ regw = pci_config_get16(cfg_hdl, PCI_CONF_COMM);
+ pci_config_put16(cfg_hdl, PCI_CONF_COMM,
+ regw | PCI_COMM_SERR_ENABLE);
+ }
+}
+
+int
+pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg)
+{
+ struct detachspec *ds;
+ struct attachspec *as;
+
+ switch (ctlop) {
+ case DDI_CTLOPS_DETACH:
+ ds = (struct detachspec *)arg;
+ switch (ds->when) {
+ case DDI_POST:
+ if (ds->cmd == DDI_SUSPEND) {
+ if (pci_post_suspend(rdip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case DDI_CTLOPS_ATTACH:
+ as = (struct attachspec *)arg;
+ switch (as->when) {
+ case DDI_PRE:
+ if (as->cmd == DDI_RESUME) {
+ if (pci_pre_resume(rdip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ }
+ break;
+ case DDI_POST:
+ /*
+ * For leaf devices supporting RBER and AER, we
+ * need to apply this workaround on them after
+ * attach to be notified of UEs that would
+ * otherwise be ignored as CEs on Intel chipsets
+ * currently
+ */
+ pcieb_intel_rber_workaround(rdip);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return (DDI_SUCCESS);
+}
+
+void
+pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd)
+{
+ /*
+ * like in attach, since hotplugging can change error registers,
+ * we need to ensure that the proper bits are set on this port
+ * after a configure operation
+ */
+ if ((rv == HPC_SUCCESS) && (cmd == DEVCTL_AP_CONFIGURE))
+ pcieb_intel_error_workaround(dip);
+}
diff --git a/usr/src/uts/intel/os/driver_aliases b/usr/src/uts/intel/os/driver_aliases
index 420404560d..fe9bb3e226 100644
--- a/usr/src/uts/intel/os/driver_aliases
+++ b/usr/src/uts/intel/os/driver_aliases
@@ -1,6 +1,6 @@
npe "pciex_root_complex"
-pcie_pci "pciexclass,060400"
-pcie_pci "pciexclass,060401"
+pcieb "pciexclass,060400"
+pcieb "pciexclass,060401"
pci_pci "pciclass,060400"
pci_pci "pciclass,060401"
pci_pci "pci1011,1"
diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major
index fe4850d74c..df3e1ce7cc 100644
--- a/usr/src/uts/intel/os/name_to_major
+++ b/usr/src/uts/intel/os/name_to_major
@@ -109,7 +109,7 @@ smbios 180
power 181
zfs 182
npe 183
-pcie_pci 184
+pcieb 184
kssl 185
mc-amd 186
tzmon 187
diff --git a/usr/src/uts/intel/pcie_pci/Makefile b/usr/src/uts/intel/pcieb/Makefile
index 51a4ba8a6d..420476a8cb 100644
--- a/usr/src/uts/intel/pcie_pci/Makefile
+++ b/usr/src/uts/intel/pcieb/Makefile
@@ -19,14 +19,12 @@
# CDDL HEADER END
#
#
-# uts/intel/pcie_pci/Makefile
+# uts/intel/pcieb/Makefile
#
-# Copyright 2007 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 makefile drives the production of the pcie_pci driver kernel
+# This makefile drives the production of the pcieb driver kernel
# module.
#
@@ -38,11 +36,11 @@ UTSBASE = ../..
#
# Define the module and object file sets.
#
-MODULE = pcie_pci
-OBJECTS = $(PCI_E_PCINEXUS_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(PCI_E_PCINEXUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+MODULE = pcieb
+OBJECTS = $(PCIEB_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(PCIEB_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR = $(UTSBASE)/intel/io/pciex
+CONF_SRCDIR = $(UTSBASE)/common/io/pciex
#
# Include common rules.
diff --git a/usr/src/uts/sparc/Makefile.files b/usr/src/uts/sparc/Makefile.files
index 22e344f15f..9839926d80 100644
--- a/usr/src/uts/sparc/Makefile.files
+++ b/usr/src/uts/sparc/Makefile.files
@@ -64,8 +64,8 @@ FD_OBJS += fd_asm.o
CPR_SPARC_OBJS += cpr_sparc.o
PCI_PCI_OBJS += pci_pci.o pci_debug.o pci_pwr.o pcix.o
-PX_PCI_OBJS += px_pci.o pcie_pwr.o
PCIE_MISC_OBJS += pcie_plat.o
+PCIEB_OBJS += pcieb_sparc.o
FCODE_OBJS += fcode.o
NSKERN_OBJS += nsc_asm.o
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 8d3f3d09e9..5ff4d10821 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -278,7 +278,7 @@ DRV_KMODS += wusb_df hwahc hwarc wusb_ca
DRV_KMODS += hci1394 av1394 scsa1394 dcam1394
DRV_KMODS += sbp2
DRV_KMODS += ib ibd rdsib sdp iser daplt hermon tavor
-DRV_KMODS += pci_pci px_pci pxb_plx pxb_bcm pcie
+DRV_KMODS += pci_pci pcieb pcieb_bcm pcie
DRV_KMODS += i8042 kb8042 mouse8042
DRV_KMODS += fcode
DRV_KMODS += mpt_sas
diff --git a/usr/src/uts/sun4/io/px/pxb_plx.h b/usr/src/uts/sparc/io/pciex/pcieb_plx.h
index f2f407a01d..be0f15f1d1 100644
--- a/usr/src/uts/sun4/io/px/pxb_plx.h
+++ b/usr/src/uts/sparc/io/pciex/pcieb_plx.h
@@ -23,8 +23,8 @@
* Use is subject to license terms.
*/
-#ifndef _SYS_PXB_PLX_H
-#define _SYS_PXB_PLX_H
+#ifndef _SYS_PCIEB_PLX_H
+#define _SYS_PCIEB_PLX_H
#ifdef __cplusplus
extern "C" {
@@ -51,8 +51,12 @@ extern "C" {
#define PLX_CAM_PORT_12 0x2f8
#define PLX_RO_MODE_BIT 0x20
+#define IS_PLX_VENDORID(x) (x == PXB_VENDOR_PLX)
+
+static int pxb_tlp_count = 64;
+
#ifdef __cplusplus
}
#endif
-#endif /* _SYS_PXB_PLX_H */
+#endif /* _SYS_PCIEB_PLX_H */
diff --git a/usr/src/uts/sparc/io/pciex/pcieb_sparc.c b/usr/src/uts/sparc/io/pciex/pcieb_sparc.c
new file mode 100644
index 0000000000..385c4a3aa3
--- /dev/null
+++ b/usr/src/uts/sparc/io/pciex/pcieb_sparc.c
@@ -0,0 +1,508 @@
+/*
+ * 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.
+ */
+
+/* SPARC specific code used by the pcieb driver */
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/kmem.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/pcie.h>
+#include <sys/pci_cap.h>
+#include <sys/pcie_impl.h>
+#include <io/pciex/pcieb.h>
+#include "pcieb_plx.h"
+
+/*LINTLIBRARY*/
+
+/* PLX specific functions */
+#ifdef PX_PLX
+static void plx_ro_disable(pcieb_devstate_t *pcieb);
+#ifdef PRINT_PLX_SEEPROM_CRC
+static void pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p);
+#endif /* PRINT_PLX_SEEPROM_CRC */
+#endif /* PX_PLX */
+
+int
+pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
+ void *arg, void *result)
+{
+ return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+}
+
+/*ARGSUSED*/
+void
+pcieb_plat_attach_workaround(dev_info_t *dip)
+{
+}
+
+int
+pcieb_plat_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
+ ddi_intr_handle_impl_t *hdlp, void *result)
+{
+ dev_info_t *cdip = rdip;
+ pci_regspec_t *pci_rp;
+ int reglen, len;
+ uint32_t d, intr;
+
+ if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) ||
+ (hdlp->ih_type != DDI_INTR_TYPE_FIXED))
+ goto done;
+
+ /*
+ * If the interrupt-map property is defined at this
+ * node, it will have performed the interrupt
+ * translation as part of the property, so no
+ * rotation needs to be done.
+ */
+ if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "interrupt-map", &len) == DDI_PROP_SUCCESS)
+ goto done;
+
+ cdip = pcie_get_my_childs_dip(dip, rdip);
+
+ /*
+ * Use the devices reg property to determine its
+ * PCI bus number and device number.
+ */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
+ "reg", (caddr_t)&pci_rp, &reglen) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
+ intr = hdlp->ih_vector;
+
+ /* spin the interrupt */
+ d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
+ if ((intr >= PCI_INTA) && (intr <= PCI_INTD))
+ hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1);
+ else
+ cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range",
+ ddi_driver_name(rdip), ddi_get_instance(rdip),
+ ddi_driver_name(dip), intr);
+
+ kmem_free(pci_rp, reglen);
+
+done:
+ /* Pass up the request to our parent. */
+ return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
+}
+
+int
+pcieb_plat_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+ uint16_t cap_ptr;
+ if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_HOTPLUG, &cap_ptr)) !=
+ DDI_FAILURE) {
+ return (DDI_SUCCESS);
+ }
+
+ return (DDI_FAILURE);
+}
+
+/*
+ * Disable PM on PLX. For PLX Transitioning one port on this switch to
+ * low power causes links on other ports on the same station to die.
+ * Due to PLX erratum #34, we can't allow the downstream device go to
+ * non-D0 state.
+ */
+boolean_t
+pcieb_plat_pwr_disable(dev_info_t *dip)
+{
+ uint16_t vendor_id = (PCIE_DIP2UPBUS(dip)->bus_dev_ven_id) & 0xFFFF;
+ return (IS_PLX_VENDORID(vendor_id) ? B_TRUE : B_FALSE);
+}
+
+/*ARGSUSED*/
+boolean_t
+pcieb_plat_msi_supported(dev_info_t *dip)
+{
+ return (B_TRUE);
+}
+
+/*ARGSUSED*/
+void
+pcieb_plat_intr_attach(pcieb_devstate_t *pcieb)
+{
+}
+
+/*ARGSUSED*/
+int
+pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg)
+{
+ return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+void
+pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd)
+{
+}
+
+void
+pcieb_plat_initchild(dev_info_t *child)
+{
+ intptr_t ppd = NULL;
+ /*
+ * XXX set ppd to 1 to disable iommu BDF protection on SPARC.
+ * It relies on unused parent private data for PCI devices.
+ */
+ if (ddi_prop_exists(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
+ "dvma-share"))
+ ppd = 1;
+
+ ddi_set_parent_data(child, (void *)ppd);
+}
+
+void
+pcieb_plat_uninitchild(dev_info_t *child)
+{
+ /*
+ * XXX Clear parent private data used as a flag to disable
+ * iommu BDF protection
+ */
+ if ((intptr_t)ddi_get_parent_data(child) == 1)
+ ddi_set_parent_data(child, NULL);
+}
+
+#ifdef PX_PLX
+/*
+ * These are PLX specific workarounds needed during attach.
+ */
+void
+pcieb_attach_plx_workarounds(pcieb_devstate_t *pcieb)
+{
+ dev_info_t *dip = pcieb->pcieb_dip;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
+ uint_t bus_num, primary, secondary;
+ uint8_t dev_type = bus_p->bus_dev_type;
+ uint16_t vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
+
+ if (!IS_PLX_VENDORID(vendor_id))
+ return;
+
+ /*
+ * Due to a PLX HW bug we need to disable the receiver error CE on all
+ * ports. To this end we create a property "pcie_ce_mask" with value
+ * set to PCIE_AER_CE_RECEIVER_ERR. The pcie module will check for this
+ * property before setting the AER CE mask.
+ */
+ (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
+ "pcie_ce_mask", PCIE_AER_CE_RECEIVER_ERR);
+
+ /*
+ * There is a bug in the PLX 8114 bridge, such that an 8-bit
+ * write to the secondary bus number register will corrupt an
+ * internal shadow copy of the primary bus number. Reading
+ * out the registers and writing the same values back as
+ * 16-bits resolves the problem. This bug was reported by
+ * PLX as errata #19.
+ */
+ primary = pci_config_get8(config_handle, PCI_BCNF_PRIBUS);
+ secondary = pci_config_get8(config_handle, PCI_BCNF_SECBUS);
+ bus_num = (secondary << 8) | primary;
+ pci_config_put16(config_handle, PCI_BCNF_PRIBUS, bus_num);
+
+ /*
+ * Workaround for a race condition between hotplug
+ * initialization and actual MSI interrupt registration
+ * for hotplug functionality. The hotplug initialization
+ * generates an INTx interrupt for hotplug events and this
+ * INTx interrupt may interfere with shared leaf drivers
+ * using same INTx interrupt, which may eventually block
+ * the leaf drivers.
+ */
+ if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
+ pci_config_put16(config_handle, PCI_CONF_COMM,
+ pci_config_get16(config_handle, PCI_CONF_COMM) |
+ PCI_COMM_INTX_DISABLE);
+ }
+
+ /*
+ * Disable PLX Special Relaxed Ordering
+ */
+ plx_ro_disable(pcieb);
+
+#ifdef PRINT_PLX_SEEPROM_CRC
+ /* check seeprom CRC to ensure the platform config is right */
+ (void) pcieb_print_plx_seeprom_crc_data(pcieb);
+#endif /* PRINT_PLX_SEEPROM_CRC */
+}
+
+/*
+ * These are PLX specific workarounds called during child's initchild.
+ */
+int
+pcieb_init_plx_workarounds(pcieb_devstate_t *pcieb, dev_info_t *child)
+{
+ int i;
+ int result = DDI_FAILURE;
+ uint16_t reg = 0;
+ ddi_acc_handle_t config_handle;
+ uint16_t vendor_id =
+ (PCIE_DIP2UPBUS(pcieb->pcieb_dip))->bus_dev_ven_id & 0xFFFF;
+
+ if (!IS_PLX_VENDORID(vendor_id))
+ return (DDI_SUCCESS);
+
+ /*
+ * Due to a PLX HW bug, a SW workaround to prevent the chip from
+ * wedging is needed. SW just needs to tranfer 64 TLPs from
+ * the downstream port to the child device.
+ * The most benign way of doing this is to read the ID register
+ * 64 times. This SW workaround should have minimum performance
+ * impact and shouldn't cause a problem for all other bridges
+ * and switches.
+ *
+ * The code needs to be written in a way to make sure it isn't
+ * optimized out.
+ */
+ if (!pxb_tlp_count) {
+ result = DDI_SUCCESS;
+ goto done;
+ }
+
+ if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
+ result = DDI_FAILURE;
+ goto done;
+ }
+
+ for (i = 0; i < pxb_tlp_count; i += 1)
+ reg |= pci_config_get16(config_handle, PCI_CONF_VENID);
+
+ if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(pcieb->pcieb_dip)))
+ pcieb_set_pci_perf_parameters(child, config_handle);
+
+ pci_config_teardown(&config_handle);
+ result = DDI_SUCCESS;
+done:
+ return (result);
+}
+
+/*
+ * Disable PLX specific relaxed ordering mode. Due to PLX
+ * erratum #6, use of this mode with Cut-Through Cancellation
+ * can result in dropped Completion type packets.
+ *
+ * Clear the Relaxed Ordering Mode on 8533 and 8548 switches.
+ * To disable RO, clear bit 5 in offset 0x664, an undocumented
+ * bit in the PLX spec, on Ports 0, 8 and 12. Proprietary PLX
+ * registers are normally accessible only via memspace from Port
+ * 0. If port 0 is attached go ahead and disable RO on Port 0,
+ * 8 and 12, if they exist.
+ */
+static void
+plx_ro_disable(pcieb_devstate_t *pcieb)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip);
+ dev_info_t *dip = pcieb->pcieb_dip;
+ uint16_t device_id = bus_p->bus_dev_ven_id >> 16;
+ pci_regspec_t *reg_spec, *addr_spec;
+ int rlen, alen;
+ int orig_rsize, new_rsize;
+ uint_t rnum, anum;
+ ddi_device_acc_attr_t attr;
+ ddi_acc_handle_t hdl;
+ caddr_t regsp;
+ uint32_t val, port_enable;
+ char *offset;
+ char *port_offset;
+
+ if (!((device_id == PXB_DEVICE_PLX_8533) ||
+ (device_id == PXB_DEVICE_PLX_8548)))
+ return;
+
+ /* You can also only do this on Port 0 */
+ val = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
+ val = (val >> PCIE_LINKCAP_PORT_NUMBER_SHIFT) &
+ PCIE_LINKCAP_PORT_NUMBER_MASK;
+
+ PCIEB_DEBUG(DBG_ATTACH, dip, "PLX RO Disable : bdf=0x%x port=%d\n",
+ bus_p->bus_bdf, val);
+
+ if (val != 0)
+ return;
+
+ /*
+ * Read the reg property, but allocate extra space incase we need to add
+ * a new entry later.
+ */
+ if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
+ &orig_rsize) != DDI_SUCCESS)
+ return;
+
+ new_rsize = orig_rsize + sizeof (pci_regspec_t);
+ reg_spec = kmem_alloc(new_rsize, KM_SLEEP);
+
+ if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
+ (caddr_t)reg_spec, &orig_rsize) != DDI_SUCCESS)
+ goto fail;
+
+ /* Find the mem32 reg property */
+ rlen = orig_rsize / sizeof (pci_regspec_t);
+ for (rnum = 0; rnum < rlen; rnum++) {
+ if ((reg_spec[rnum].pci_phys_hi & PCI_ADDR_MASK) ==
+ PCI_ADDR_MEM32)
+ goto fix;
+ }
+
+ /*
+ * Mem32 reg property was not found.
+ * Look for it in assign-address property.
+ */
+ addr_spec = bus_p->bus_assigned_addr;
+ alen = bus_p->bus_assigned_entries;
+ for (anum = 0; anum < alen; anum++) {
+ if ((addr_spec[anum].pci_phys_hi & PCI_ADDR_MASK) ==
+ PCI_ADDR_MEM32)
+ goto update;
+ }
+
+ /* Unable to find mem space assigned address, give up. */
+ goto fail;
+
+update:
+ /*
+ * Add the mem32 access to the reg spec.
+ * Use the last entry which was previously allocated.
+ */
+ reg_spec[rnum].pci_phys_hi = (addr_spec[anum].pci_phys_hi &
+ ~PCI_REG_REL_M);
+ reg_spec[rnum].pci_phys_mid = 0;
+ reg_spec[rnum].pci_phys_low = 0;
+ reg_spec[rnum].pci_size_hi = addr_spec[anum].pci_size_hi;
+ reg_spec[rnum].pci_size_low = addr_spec[anum].pci_size_low;
+
+ /* Create the new reg_spec data and update the property */
+ if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
+ (int *)reg_spec, (new_rsize / sizeof (int))) != DDI_SUCCESS)
+ goto fail;
+
+fix:
+ attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
+ attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
+ attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+
+ if (ddi_regs_map_setup(dip, rnum, &regsp, 0, 0, &attr,
+ &hdl) != DDI_SUCCESS)
+ goto fail;
+
+ /* Grab register which shows which ports are enabled */
+ offset = (char *)regsp + PLX_INGRESS_PORT_ENABLE;
+ port_enable = ddi_get32(hdl, (uint32_t *)offset);
+
+ if ((port_enable == 0xFFFFFFFF) || (port_enable == 0))
+ goto done;
+
+ offset = (char *)regsp + PLX_INGRESS_CONTROL_SHADOW;
+
+ /* Disable RO on Port 0 */
+ port_offset = 0x0 + offset;
+ val = ddi_get32(hdl, (uint32_t *)port_offset);
+ if (val & PLX_RO_MODE_BIT)
+ val ^= PLX_RO_MODE_BIT;
+ ddi_put32(hdl, (uint32_t *)port_offset, val);
+
+ /* Disable RO on Port 8, but make sure its enabled */
+ if (!(port_enable & (1 << 8)))
+ goto port12;
+
+ port_offset = (8 * 0x1000) + offset;
+ val = ddi_get32(hdl, (uint32_t *)port_offset);
+ if (val & PLX_RO_MODE_BIT)
+ val ^= PLX_RO_MODE_BIT;
+ ddi_put32(hdl, (uint32_t *)port_offset, val);
+
+port12:
+ /* Disable RO on Port 12, but make sure it exists */
+ if (!(port_enable & (1 << 12)))
+ goto done;
+
+ port_offset = (12 * 0x1000) + offset;
+ val = ddi_get32(hdl, (uint32_t *)port_offset);
+ if (val & PLX_RO_MODE_BIT)
+ val ^= PLX_RO_MODE_BIT;
+ ddi_put32(hdl, (uint32_t *)port_offset, val);
+
+ goto done;
+
+done:
+ ddi_regs_map_free(&hdl);
+fail:
+ kmem_free(reg_spec, new_rsize);
+}
+
+#ifdef PRINT_PLX_SEEPROM_CRC
+static void
+pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p)
+{
+ ddi_acc_handle_t h;
+ dev_info_t *dip = pcieb_p->pcieb_dip;
+ uint16_t vendorid = (PCIE_DIP2BUS(dip)->bus_dev_ven_id) & 0xFFFF;
+ int nregs;
+ caddr_t mp;
+ off_t bar_size;
+ ddi_device_acc_attr_t mattr = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_STRUCTURE_LE_ACC,
+ DDI_STRICTORDER_ACC
+ };
+ uint32_t addr_reg_off = 0x260, data_reg_off = 0x264, data = 0x6BE4;
+
+ if (vendorid != PXB_VENDOR_PLX)
+ return;
+ if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
+ return;
+ if (nregs < 2) /* check for CONF entry only, no BARs */
+ return;
+ if (ddi_dev_regsize(dip, 1, &bar_size) != DDI_SUCCESS)
+ return;
+ if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mp, 0, bar_size,
+ &mattr, &h) != DDI_SUCCESS)
+ return;
+ ddi_put32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off), data);
+ delay(drv_usectohz(1000000));
+ printf("%s#%d: EEPROM StatusReg = %x, CRC = %x\n",
+ ddi_driver_name(dip), ddi_get_instance(dip),
+ ddi_get32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off)),
+ ddi_get32(h, (uint32_t *)((uchar_t *)mp + data_reg_off)));
+#ifdef PLX_HOT_RESET_DISABLE
+ /* prevent hot reset from propogating downstream. */
+ data = ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC));
+ ddi_put32(h, (uint32_t *)((uchar_t *)mp + 0x1DC), data | 0x80000);
+ delay(drv_usectohz(1000000));
+ printf("%s#%d: EEPROM 0x1DC prewrite=%x postwrite=%x\n",
+ ddi_driver_name(dip), ddi_get_instance(dip), data,
+ ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC)));
+#endif /* PLX_HOT_RESET_DISABLE */
+ ddi_regs_map_free(&h);
+}
+#endif /* PRINT_PLX_SEEPROM_CRC */
+#endif /* PX_PLX */
diff --git a/usr/src/uts/sparc/os/driver_aliases b/usr/src/uts/sparc/os/driver_aliases
index 4c95e31eb4..8add121d44 100644
--- a/usr/src/uts/sparc/os/driver_aliases
+++ b/usr/src/uts/sparc/os/driver_aliases
@@ -145,17 +145,8 @@ ibd "ib.ipib"
px "SUNW,sun4v-pci"
px "pciex108e,80f0"
px "pciex108e,80f8"
-px_pci "pciexclass,060400"
-pxb_bcm "pciex1166,103"
-pxb_plx "pciex10b5,8114"
-pxb_plx "pciex10b5,8532"
-pxb_plx "pciex10b5,8516"
-pxb_plx "pciex10b5,8548"
-pxb_plx "pciex10b5,8533"
-pxb_plx "pciex10b5,8517"
-pxb_plx "pciex10b5,8518"
-pxb_plx "pciex108e,9010"
-pxb_plx "pciex108e,9020"
+pcieb "pciexclass,060400"
+pcieb_bcm "pciex1166,103"
vnex "SUNW,sun4v-virtual-devices"
vnex "SUNW,virtual-devices"
mi2cv "fire-i2c"
diff --git a/usr/src/uts/sparc/os/name_to_major b/usr/src/uts/sparc/os/name_to_major
index ee5c8793df..f384fa995d 100644
--- a/usr/src/uts/sparc/os/name_to_major
+++ b/usr/src/uts/sparc/os/name_to_major
@@ -189,7 +189,7 @@ ntwdt 240
dld 241
aggr 242
px 243
-px_pci 244
+pcieb 244
qcn 245
vnex 246
glvc 247
@@ -212,8 +212,7 @@ scfd 263
mc-opl 264
dm2s 265
oplkmdrv 266
-pxb_bcm 267
-pxb_plx 268
+pcieb_bcm 267
n2rng 269
physmem 270
ds_snmp 271
diff --git a/usr/src/uts/sparc/pxb_plx/Makefile b/usr/src/uts/sparc/pcieb/Makefile
index 5c1e21036c..f6690fec79 100644
--- a/usr/src/uts/sparc/pxb_plx/Makefile
+++ b/usr/src/uts/sparc/pcieb/Makefile
@@ -19,14 +19,12 @@
# CDDL HEADER END
#
#
-# uts/sparc/pxb_plx/Makefile
+# uts/sparc/pcieb/Makefile
#
-# Copyright 2007 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 makefile drives the production of the pxb_plx driver kernel module
+# This makefile drives the production of the pcieb driver kernel module
#
# sparc implementation architecture dependent
#
@@ -39,11 +37,11 @@ UTSBASE = ../..
#
# Define the module and object file sets.
#
-MODULE = pxb_plx
-OBJECTS = $(PX_PCI_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(PX_PCI_OBJS:%.o=$(LINTS_DIR)/%.ln)
+MODULE = pcieb
+OBJECTS = $(PCIEB_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(PCIEB_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR = $(UTSBASE)/sun4/io/px/
+CONF_SRCDIR = $(UTSBASE)/common/io/pciex/
#
# Include common rules.
@@ -58,11 +56,6 @@ LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
#
-# Include sun4 specific headers files
-#
-INC_PATH += -I$(UTSBASE)/sun4
-
-#
# lint pass one enforcement
#
CFLAGS += $(CCVERBOSE)
diff --git a/usr/src/uts/sparc/pxb_bcm/Makefile b/usr/src/uts/sparc/pcieb_bcm/Makefile
index 750867e7eb..a6eee4a8ce 100644
--- a/usr/src/uts/sparc/pxb_bcm/Makefile
+++ b/usr/src/uts/sparc/pcieb_bcm/Makefile
@@ -19,14 +19,13 @@
# CDDL HEADER END
#
#
-# uts/sparc/pxb_bcm/Makefile
+# uts/sparc/pcieb_bcm/Makefile
#
-# Copyright 2006 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 makefile drives the production of the pxb_bcm driver kernel module
+# This makefile drives the production of the pcieb_bcm driver kernel module
#
# sparc implementation architecture dependent
#
@@ -39,9 +38,9 @@ UTSBASE = ../..
#
# Define the module and object file sets.
#
-MODULE = pxb_bcm
-OBJECTS = $(PX_PCI_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(PX_PCI_OBJS:%.o=$(LINTS_DIR)/%.ln)
+MODULE = pcieb_bcm
+OBJECTS = $(PCIEB_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(PCIEB_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
#
@@ -57,11 +56,6 @@ LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
-# Include sun4 specific headers files
-#
-INC_PATH += -I$(UTSBASE)/sun4
-
-#
# lint pass one enforcement
#
CFLAGS += $(CCVERBOSE)
@@ -75,7 +69,7 @@ CFLAGS += -dalign
# Enable Broadcom 5714/5715 workaround code and lint duplicate symbol
# avoidance hack
#
-CPPFLAGS += -DBCM_SW_WORKAROUNDS -DPX_MOD_NAME=pxb_bcm
+CPPFLAGS += -DBCM_SW_WORKAROUNDS -DPX_MOD_NAME=pcieb_bcm
#
# Dependency
diff --git a/usr/src/uts/sparc/px_pci/Makefile b/usr/src/uts/sparc/px_pci/Makefile
deleted file mode 100644
index 7bd7e1c8b6..0000000000
--- a/usr/src/uts/sparc/px_pci/Makefile
+++ /dev/null
@@ -1,112 +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/px_pci/Makefile
-#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# This makefile drives the production of the px_pci driver kernel module
-#
-# sparc 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 = px_pci
-OBJECTS = $(PX_PCI_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(PX_PCI_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR = $(UTSBASE)/sun4/io/px/
-
-#
-# Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-# Define targets
-#
-ALL_TARGET = $(BINARY) $(SRC_CONFFILE)
-LINT_TARGET = $(MODULE).lint
-INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
-
-#
-# Include sun4 specific headers files
-#
-INC_PATH += -I$(UTSBASE)/sun4
-
-#
-# lint pass one enforcement
-#
-CFLAGS += $(CCVERBOSE)
-
-#
-# Turn on doubleword alignment for 64 bit registers
-#
-CFLAGS += -dalign
-
-#
-# Dependency
-#
-LDFLAGS += -dy -Nmisc/pcie -Nmisc/pcishpc -Nmisc/pcihp -Nmisc/pciehpc
-
-#
-# 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
-
-#
-# 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
diff --git a/usr/src/uts/sun4/io/px/px.c b/usr/src/uts/sun4/io/px/px.c
index c2de28bc8a..22eff51642 100644
--- a/usr/src/uts/sun4/io/px/px.c
+++ b/usr/src/uts/sun4/io/px/px.c
@@ -43,7 +43,7 @@
#include "px_obj.h"
#include <sys/pci_tools.h>
#include "px_tools_ext.h"
-#include "pcie_pwr.h"
+#include <sys/pcie_pwr.h>
/*LINTLIBRARY*/
@@ -63,8 +63,6 @@ static void px_set_mps(px_t *px_p);
extern int pcie_max_mps;
-extern errorq_t *pci_target_queue;
-
/*
* function prototypes for hotplug routines:
*/
@@ -174,13 +172,6 @@ _fini(void)
e = mod_remove(&modlinkage);
if (e != DDI_SUCCESS)
return (e);
- /*
- * Destroy pci_target_queue, and set it to NULL.
- */
- if (pci_target_queue)
- errorq_destroy(pci_target_queue);
-
- pci_target_queue = NULL;
/* Free px soft state */
ddi_soft_state_fini(&px_state_p);
@@ -720,7 +711,7 @@ px_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
* There may be a need to differentiate between PCI
* and PCI-Ex devices so the following range check is
* done correctly, depending on the implementation of
- * px_pci bridge nexus driver.
+ * pcieb bridge nexus driver.
*/
if ((off >= PCIE_CONF_HDR_SIZE) ||
(len > PCIE_CONF_HDR_SIZE) ||
diff --git a/usr/src/uts/sun4/io/px/px_devctl.c b/usr/src/uts/sun4/io/px/px_devctl.c
index b140cdd89f..253dfd6503 100644
--- a/usr/src/uts/sun4/io/px/px_devctl.c
+++ b/usr/src/uts/sun4/io/px/px_devctl.c
@@ -42,7 +42,7 @@
#include "px_obj.h"
#include <sys/pci_tools.h>
#include "px_tools_ext.h"
-#include "pcie_pwr.h"
+#include <sys/pcie_pwr.h>
/*LINTLIBRARY*/
diff --git a/usr/src/uts/sun4/io/px/px_fm.c b/usr/src/uts/sun4/io/px/px_fm.c
index 987957ce96..958c18f42b 100644
--- a/usr/src/uts/sun4/io/px/px_fm.c
+++ b/usr/src/uts/sun4/io/px/px_fm.c
@@ -77,12 +77,6 @@ px_fm_attach(px_t *px_p)
DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
/*
- * Initialize pci_target_queue for FMA handling of
- * pci errors.
- */
- pci_targetq_init();
-
- /*
* check parents' capability
*/
ddi_fm_init(dip, &px_p->px_fm_cap, &px_p->px_fm_ibc);
diff --git a/usr/src/uts/sun4/io/px/px_pci.c b/usr/src/uts/sun4/io/px/px_pci.c
deleted file mode 100644
index 18671c5a7b..0000000000
--- a/usr/src/uts/sun4/io/px/px_pci.c
+++ /dev/null
@@ -1,2273 +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 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-
-/*
- * Sun4 PCI Express to PCI bus bridge nexus driver
- */
-
-#include <sys/sysmacros.h>
-#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/ddi_subrdefs.h>
-#include <sys/time.h>
-#include <sys/proc.h>
-#include <sys/thread.h>
-#include <sys/disp.h>
-#include <sys/condvar.h>
-#include <sys/callb.h>
-#include <sys/pcie.h>
-#include <sys/pcie_impl.h>
-#include <sys/pci_impl.h>
-#include <sys/ddi.h>
-#include <sys/sunndi.h>
-#include <sys/pci_cap.h>
-#include <sys/hotplug/pci/pcihp.h>
-#include <sys/hotplug/pci/pciehpc.h>
-#include <sys/hotplug/pci/pcishpc.h>
-#include <sys/open.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <sys/promif.h> /* prom_printf */
-#include "pcie_pwr.h"
-#include "px_pci.h"
-#ifdef PX_PLX
-#include "pxb_plx.h"
-#endif /* PX_PLX */
-
-#if defined(DEBUG)
-#define DBG pxb_dbg
-static void pxb_dbg(uint_t bit, dev_info_t *dip, char *fmt, ...);
-static uint_t pxb_dbg_print = 0;
-
-#else /* DEBUG */
-
-#define DBG 0 &&
-
-#endif /* DEBUG */
-
-typedef enum { /* same sequence as px_debug_sym[] */
- /* 0 */ DBG_ATTACH,
- /* 1 */ DBG_PWR
-} pxb_debug_bit_t;
-
-static char *pxb_debug_sym [] = { /* same sequence as px_debug_bit */
- /* 0 */ "attach",
- /* 1 */ "pwr"
-};
-
-/* Tunables. Beware: Some are for debug purpose only. */
-/*
- * PXB MSI tunable:
- *
- * By default MSI is enabled on all supported platforms.
- */
-static boolean_t pxb_enable_msi = B_TRUE; /* MSI enabled if TRUE, else INTX */
-
-static int pxb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
- off_t, off_t, caddr_t *);
-static int pxb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
- ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg,
- ddi_dma_handle_t *handlep);
-static int pxb_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
- ddi_dma_handle_t handle, enum ddi_dma_ctlops cmd, off_t *offp,
- size_t *lenp, caddr_t *objp, uint_t cache_flags);
-static int pxb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
- void *, void *);
-static int pxb_intr_ops(dev_info_t *dip, dev_info_t *rdip,
- ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
-
-/*
- * FMA functions
- */
-static int pxb_fm_init(pxb_devstate_t *pxb_p);
-static void pxb_fm_fini(pxb_devstate_t *pxb_p);
-static int pxb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
- ddi_iblock_cookie_t *ibc_p);
-
-static void pxb_set_pci_perf_parameters(dev_info_t *dip,
- ddi_acc_handle_t config_handle);
-#ifdef PRINT_PLX_SEEPROM_CRC
-static void pxb_print_plx_seeprom_crc_data(pxb_devstate_t *pxb_p);
-#endif
-
-static struct bus_ops pxb_bus_ops = {
- BUSO_REV,
- pxb_bus_map,
- 0,
- 0,
- 0,
- i_ddi_map_fault,
- ddi_dma_map,
- pxb_dma_allochdl,
- ddi_dma_freehdl,
- ddi_dma_bindhdl,
- ddi_dma_unbindhdl,
- ddi_dma_flush,
- ddi_dma_win,
- pxb_dma_mctl,
- pxb_ctlops,
- ddi_bus_prop_op,
- ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */
- ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */
- ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */
- ndi_post_event, /* (*bus_post_event)(); */
- NULL, /* (*bus_intr_ctl)(); */
- NULL, /* (*bus_config)(); */
- NULL, /* (*bus_unconfig)(); */
- pxb_fm_init_child, /* (*bus_fm_init)(); */
- NULL, /* (*bus_fm_fini)(); */
- i_ndi_busop_access_enter, /* (*bus_fm_access_enter)(); */
- i_ndi_busop_access_exit, /* (*bus_fm_access_fini)(); */
- pcie_bus_power, /* (*bus_power)(); */
- pxb_intr_ops /* (*bus_intr_op)(); */
-};
-
-static int pxb_open(dev_t *devp, int flags, int otyp, cred_t *credp);
-static int pxb_close(dev_t dev, int flags, int otyp, cred_t *credp);
-static int pxb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
- cred_t *credp, int *rvalp);
-static int pxb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
- int flags, char *name, caddr_t valuep, int *lengthp);
-
-static struct cb_ops pxb_cb_ops = {
- pxb_open, /* open */
- pxb_close, /* close */
- nulldev, /* strategy */
- nulldev, /* print */
- nulldev, /* dump */
- nulldev, /* read */
- nulldev, /* write */
- pxb_ioctl, /* ioctl */
- nodev, /* devmap */
- nodev, /* mmap */
- nodev, /* segmap */
- nochpoll, /* poll */
- pxb_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 pxb_probe(dev_info_t *);
-static int pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
-static int pxb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
-static int pxb_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
- void *arg, void **result);
-static int pxb_pwr_setup(dev_info_t *dip);
-static int pxb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p);
-static void pxb_pwr_teardown(dev_info_t *dip);
-
-/* PLX specific functions */
-#ifdef PX_PLX
-static int plx_pwr_disable(dev_info_t *dip);
-static void plx_ro_disable(pxb_devstate_t *pxb);
-#endif /* PX_PLX */
-
-
-/* Hotplug related functions */
-static int pxb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
-static int pxb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
-static int pxb_init_hotplug(pxb_devstate_t *pxb);
-static void pxb_id_props(pxb_devstate_t *pxb);
-
-static struct dev_ops pxb_ops = {
- DEVO_REV, /* devo_rev */
- 0, /* refcnt */
- pxb_info, /* info */
- nulldev, /* identify */
- pxb_probe, /* probe */
- pxb_attach, /* attach */
- pxb_detach, /* detach */
- nulldev, /* reset */
- &pxb_cb_ops, /* driver operations */
- &pxb_bus_ops, /* bus operations */
- pcie_power, /* power entry */
- ddi_quiesce_not_needed, /* quiesce */
-};
-
-/*
- * Module linkage information for the kernel.
- */
-
-static struct modldrv modldrv = {
- &mod_driverops, /* Type of module */
- "PCIe/PCI nexus driver",
- &pxb_ops, /* driver ops */
-};
-
-static struct modlinkage modlinkage = {
- MODREV_1,
- (void *)&modldrv,
- NULL
-};
-
-/*
- * soft state pointer and structure template:
- */
-void *pxb_state;
-
-/*
- * SW workaround for PLX HW bug Flag
- */
-static int pxb_tlp_count = 64;
-
-/*
- * forward function declarations:
- */
-static int pxb_intr_init(pxb_devstate_t *pxb, int intr_type);
-static void pxb_intr_fini(pxb_devstate_t *pxb);
-static uint_t pxb_intr(caddr_t arg1, caddr_t arg2);
-static int pxb_intr_attach(pxb_devstate_t *pxb);
-
-static void pxb_removechild(dev_info_t *);
-static int pxb_initchild(dev_info_t *child);
-static void pxb_create_ranges_prop(dev_info_t *, ddi_acc_handle_t);
-
-int
-_init(void)
-{
- int e;
- if ((e = ddi_soft_state_init(&pxb_state, sizeof (pxb_devstate_t),
- 1)) == 0 && (e = mod_install(&modlinkage)) != 0)
- ddi_soft_state_fini(&pxb_state);
- return (e);
-}
-
-int
-_fini(void)
-{
- int e;
-
- if ((e = mod_remove(&modlinkage)) == 0)
- ddi_soft_state_fini(&pxb_state);
- return (e);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
- return (mod_info(&modlinkage, modinfop));
-}
-
-/*ARGSUSED*/
-static int
-pxb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
-{
- pxb_devstate_t *pxb_p; /* per pxb state pointer */
- minor_t minor = getminor((dev_t)arg);
- int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
- pxb_p = (pxb_devstate_t *)ddi_get_soft_state(pxb_state,
- instance);
-
- switch (infocmd) {
- default:
- return (DDI_FAILURE);
-
- case DDI_INFO_DEVT2INSTANCE:
- *result = (void *)(intptr_t)instance;
- return (DDI_SUCCESS);
-
- case DDI_INFO_DEVT2DEVINFO:
- if (pxb_p == NULL)
- return (DDI_FAILURE);
- *result = (void *)pxb_p->pxb_dip;
- return (DDI_SUCCESS);
- }
-}
-
-/*ARGSUSED*/
-static int
-pxb_probe(register dev_info_t *devi)
-{
- return (DDI_PROBE_SUCCESS);
-}
-
-static boolean_t
-pxb_is_pcie_device_type(dev_info_t *dip)
-{
- pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
-
- if (PCIE_IS_SW(bus_p) || PCIE_IS_RP(bus_p) || PCIE_IS_PCI2PCIE(bus_p))
- return (B_TRUE);
-
- return (B_FALSE);
-}
-
-/*ARGSUSED*/
-static int
-pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
-{
- pcie_bus_t *bus_p = PCIE_DIP2BUS(devi);
- int instance;
- pxb_devstate_t *pxb;
- ddi_acc_handle_t config_handle;
- char device_type[8];
- uint8_t dev_type = bus_p->bus_dev_type;
-#ifdef PX_PLX
- uint_t bus_num, primary, secondary;
-#endif /* PX_PLX */
-
- instance = ddi_get_instance(devi);
-
- switch (cmd) {
- case DDI_RESUME:
- DBG(DBG_ATTACH, devi, "DDI_RESUME\n");
- /*
- * Get the soft state structure for the bridge.
- */
- pxb = (pxb_devstate_t *)ddi_get_soft_state(pxb_state, instance);
- (void) pcie_pwr_resume(devi);
-
- return (DDI_SUCCESS);
-
- case DDI_ATTACH:
- DBG(DBG_ATTACH, devi, "DDI_ATTACH\n");
-
- /* Follow through to below the switch statement */
- break;
- default:
- return (DDI_FAILURE);
- }
-
- /*
- * Allocate and get soft state structure.
- */
- if (ddi_soft_state_zalloc(pxb_state, instance) != DDI_SUCCESS) {
- DBG(DBG_ATTACH, devi, "Unable to allocate soft state.\n");
- return (DDI_FAILURE);
- }
-
- pxb = (pxb_devstate_t *)ddi_get_soft_state(pxb_state, instance);
- pxb->pxb_dip = devi;
- pxb->pxb_soft_state = PXB_SOFT_STATE_CLOSED;
-
- /* Create Mutex */
- mutex_init(&pxb->pxb_mutex, NULL, MUTEX_DRIVER, NULL);
- pxb->pxb_init_flags = PXB_INIT_MUTEX;
-
- /* Setup and save the config space pointer */
- if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) {
- DBG(DBG_ATTACH, devi, "Failed in pci_config_setup call\n");
- goto fail;
- }
- pxb->pxb_config_handle = config_handle;
- pxb->pxb_init_flags |= PXB_INIT_CONFIG_HANDLE;
-
- /* Save the vendor id and device id */
- pxb->pxb_vendor_id = pci_config_get16(config_handle, PCI_CONF_VENID);
- pxb->pxb_device_id = pci_config_get16(config_handle, PCI_CONF_DEVID);
- pxb->pxb_rev_id = pci_config_get8(config_handle, PCI_CONF_REVID);
-
- /* create special properties for device identification */
- pxb_id_props(pxb);
-
- /*
- * Power management setup. This also makes sure that switch/bridge
- * is at D0 during attach.
- */
- if (pwr_common_setup(devi) != DDI_SUCCESS) {
- DBG(DBG_PWR, devi, "pwr_common_setup failed\n");
- goto fail;
- }
-
-#ifdef PX_PLX
- if (plx_pwr_disable(devi) != DDI_SUCCESS) {
- DBG(DBG_PWR, devi, "plx_pwr_disable failed \n");
-#else
- if (pxb_pwr_setup(devi) != DDI_SUCCESS) {
- DBG(DBG_PWR, devi, "pxb_pwr_setup failed \n");
-#endif /* PX_PLX */
- goto fail;
- }
-
- if (!(PCIE_IS_BDG(bus_p))) {
- DBG(DBG_ATTACH, devi, "This is not a switch or bridge\n");
- goto fail;
- }
-
- /*
- * Make sure the "device_type" property exists.
- */
- if (pxb_is_pcie_device_type(devi))
- (void) strcpy(device_type, "pciex");
- else
- (void) strcpy(device_type, "pci");
-
- (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
- "device_type", device_type);
-
- /*
- * Check whether the "ranges" property is present.
- * Otherwise create the ranges property by reading
- * the configuration registers
- */
- if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
- "ranges") == 0) {
- pxb_create_ranges_prop(devi, config_handle);
- }
-
- /*
- * Create an integer property with PCIE2PCI bridge's secondary
- * PCI bus number. This property will be read and saved in all
- * PCI and PCI-X device driver's parent private data structure
- * as part of their init child function.
- */
- if (PCIE_IS_PCI_BDG(bus_p)) {
- if (ndi_prop_update_int(DDI_DEV_T_NONE, pxb->pxb_dip,
- "pcie2pci-sec-bus", pci_config_get8(config_handle,
- PCI_BCNF_SECBUS)) != DDI_PROP_SUCCESS) {
- DBG(DBG_ATTACH, pxb->pxb_dip,
- "ndi_prop_update_int() failed\n");
- goto fail;
- }
-
- pxb_set_pci_perf_parameters(devi, config_handle);
- }
-
- /*
- * Initialize hotplug support on this bus except for the PLX 8532
- * revision AA. At a minimum (for non hotplug bus) this would create
- * ":devctl" minor node to support DEVCTL_DEVICE_* and DEVCTL_BUS_*
- * ioctls to this bus. This all takes place if this nexus has hot-plug
- * slots and successfully initializes Hot Plug Framework.
- */
- pxb->pxb_hotplug_capable = B_FALSE;
-
-#ifdef PX_PLX
- /*
- * Due to a PLX HW bug we need to disable the receiver error CE on all
- * ports. To this end we create a property "pcie_ce_mask" with value
- * set to PCIE_AER_CE_RECEIVER_ERR. The pcie module will check for this
- * property before setting the AER CE mask.
- */
- (void) ddi_prop_update_int(DDI_DEV_T_NONE, pxb->pxb_dip,
- "pcie_ce_mask", PCIE_AER_CE_RECEIVER_ERR);
-
- /*
- * There is a bug in the PLX 8114 bridge, such that an 8-bit
- * write to the secondary bus number register will corrupt an
- * internal shadow copy of the primary bus number. Reading
- * out the registers and writing the same values back as
- * 16-bits resolves the problem. This bug was reported by
- * PLX as errata #19.
- */
- primary = pci_config_get8(config_handle, PCI_BCNF_PRIBUS);
- secondary = pci_config_get8(config_handle, PCI_BCNF_SECBUS);
- bus_num = (secondary << 8) | primary;
- pci_config_put16(config_handle, PCI_BCNF_PRIBUS, bus_num);
-
- /*
- * Disable PLX Special Relaxed Ordering
- */
- plx_ro_disable(pxb);
-
- if ((pxb->pxb_device_id == PXB_DEVICE_PLX_8532) &&
- (pxb->pxb_rev_id <= PXB_DEVICE_PLX_AA_REV))
- goto hotplug_done;
-#endif /* PX_PLX */
-
- if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
- (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
- (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
- (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
-#ifdef PX_PLX
- /*
- * Workaround for a race condition between hotplug
- * initialization and actual MSI interrupt registration
- * for hotplug functionality. The hotplug initialization
- * generates an INTx interrupt for hotplug events and this
- * INTx interrupt may interfere with shared leaf drivers
- * using same INTx interrupt, which may eventually block
- * the leaf drivers.
- */
- pci_config_put16(config_handle, PCI_CONF_COMM,
- pci_config_get16(config_handle, PCI_CONF_COMM) |
- PCI_COMM_INTX_DISABLE);
-#endif /* PX_PLX */
-
- if (pxb_init_hotplug(pxb) != DDI_SUCCESS)
- goto fail;
- }
-
-hotplug_done:
-#ifdef PRINT_PLX_SEEPROM_CRC
- /* check seeprom CRC to ensure the platform config is right */
- (void) pxb_print_plx_seeprom_crc_data(pxb);
-#endif
-
- if (pxb->pxb_hotplug_capable == B_FALSE) {
- /*
- * create minor node for devctl interfaces
- */
- if (ddi_create_minor_node(devi, "devctl", S_IFCHR,
- PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR),
- DDI_NT_NEXUS, 0) != DDI_SUCCESS)
- goto fail;
- }
-
- DBG(DBG_ATTACH, devi,
- "pxb_attach(): this nexus %s hotplug slots\n",
- pxb->pxb_hotplug_capable == B_TRUE ? "has":"has no");
-
- if ((pxb_fm_init(pxb)) != DDI_SUCCESS) {
- DBG(DBG_ATTACH, devi, "Failed in px_pci_fm_attach\n");
- goto fail;
- }
- pxb->pxb_init_flags |= PXB_INIT_FM;
-
- /*
- * If this is a root port, determine and set the max payload size.
- */
- if (PCIE_IS_RP(bus_p))
- pcie_init_root_port_mps(devi);
-
- ddi_report_dev(devi);
-
- return (DDI_SUCCESS);
-
-fail:
- (void) pxb_detach(devi, DDI_DETACH);
-
- return (DDI_FAILURE);
-}
-
-/*ARGSUSED*/
-static int
-pxb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
-{
- pxb_devstate_t *pxb;
- int error = DDI_SUCCESS;
-
- switch (cmd) {
- case DDI_DETACH:
- /*
- * And finally free the per-pci soft state after
- * uninitializing hotplug support for this bus in
- * opposite order of attach.
- */
- pxb = (pxb_devstate_t *)
- ddi_get_soft_state(pxb_state, ddi_get_instance(devi));
-
-#ifdef PX_PLX
- (void) ndi_prop_remove(DDI_DEV_T_NONE, pxb->pxb_dip,
- "pcie_ce_mask");
-#endif /* PX_PLX */
-
- if (pxb->pxb_hotplug_capable == B_TRUE) {
- if (pcihp_uninit(devi) == DDI_FAILURE)
- error = DDI_FAILURE;
-
- if (pxb->pxb_hpc_type == HPC_PCIE)
- (void) pciehpc_uninit(devi);
- else if (pxb->pxb_hpc_type == HPC_SHPC)
- (void) pcishpc_uninit(devi);
-
- pxb_intr_fini(pxb);
- }
- else
- ddi_remove_minor_node(devi, "devctl");
-
- (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
-
- if (pxb->pxb_init_flags & PXB_INIT_FM)
- pxb_fm_fini(pxb);
-
- (void) ndi_prop_remove(DDI_DEV_T_NONE, pxb->pxb_dip,
- "pcie2pci-sec-bus");
-
- if (pxb->pxb_init_flags & PXB_INIT_CONFIG_HANDLE)
- pci_config_teardown(&pxb->pxb_config_handle);
-
- pxb_pwr_teardown(devi);
- pwr_common_teardown(devi);
- if (pxb->pxb_init_flags & PXB_INIT_MUTEX)
- mutex_destroy(&pxb->pxb_mutex);
-
- ddi_soft_state_free(pxb_state, ddi_get_instance(devi));
-
- return (error);
-
- case DDI_SUSPEND:
- pxb = (pxb_devstate_t *)
- ddi_get_soft_state(pxb_state, ddi_get_instance(devi));
-
- error = pcie_pwr_suspend(devi);
-
- return (error);
- }
- return (DDI_FAILURE);
-}
-
-/*ARGSUSED*/
-static int
-pxb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
- off_t offset, off_t len, caddr_t *vaddrp)
-{
- register 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
-pxb_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;
- struct detachspec *ds;
- struct attachspec *as;
- pxb_devstate_t *pxb_p;
-
- pxb_p = (pxb_devstate_t *)ddi_get_soft_state(pxb_state,
- ddi_get_instance(dip));
-
- 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 (pxb_initchild((dev_info_t *)arg));
-
- case DDI_CTLOPS_UNINITCHILD:
- pxb_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_ATTACH:
- if (!pcie_is_child(dip, rdip))
- return (DDI_SUCCESS);
-
- as = (struct attachspec *)arg;
- switch (as->when) {
- case DDI_PRE:
- if (as->cmd == DDI_ATTACH) {
- DBG(DBG_PWR, dip, "PRE_ATTACH for %s@%d\n",
- ddi_driver_name(rdip),
- ddi_get_instance(rdip));
- return (pcie_pm_hold(dip));
- }
- if (as->cmd == DDI_RESUME) {
- DBG(DBG_PWR, dip, "PRE_RESUME for %s@%d\n",
- ddi_driver_name(rdip),
- ddi_get_instance(rdip));
-
- pcie_clear_errors(rdip);
- }
- return (DDI_SUCCESS);
-
- case DDI_POST: {
- DBG(DBG_PWR, dip, "POST_ATTACH for %s@%d\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip));
- if (as->cmd == DDI_ATTACH && as->result != DDI_SUCCESS)
- pcie_pm_release(dip);
-
- if (as->result == DDI_SUCCESS)
- pf_init(rdip, (void *)pxb_p->pxb_fm_ibc,
- as->cmd);
-
- /*
- * For empty hotplug-capable slots, we should explicitly
- * disable the errors, so that we won't panic upon
- * unsupported hotplug messages.
- */
- if ((!ddi_prop_exists(DDI_DEV_T_ANY, rdip,
- DDI_PROP_DONTPASS, "hotplug-capable")) ||
- ddi_get_child(rdip)) {
- (void) pcie_postattach_child(rdip);
- return (DDI_SUCCESS);
- }
-
- pcie_disable_errors(rdip);
-
- return (DDI_SUCCESS);
- }
- default:
- break;
- }
- break;
-
- case DDI_CTLOPS_DETACH:
- if (!pcie_is_child(dip, rdip))
- return (DDI_SUCCESS);
-
- ds = (struct detachspec *)arg;
- switch (ds->when) {
- case DDI_PRE:
- pf_fini(rdip, ds->cmd);
- return (DDI_SUCCESS);
-
- case DDI_POST:
- if (ds->cmd == DDI_DETACH &&
- ds->result == DDI_SUCCESS) {
- DBG(DBG_PWR, dip, "POST_DETACH for %s@%d\n",
- ddi_driver_name(rdip),
- ddi_get_instance(rdip));
- return (pcie_pm_remove_child(dip, rdip));
- }
- return (DDI_SUCCESS);
- default:
- break;
- }
- break;
-
- 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 |
- ((uint64_t)drv_regp[rn].pci_size_hi << 32);
- }
-
- kmem_free(drv_regp, reglen);
- return (DDI_SUCCESS);
-}
-
-
-static int
-pxb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
- ddi_intr_handle_impl_t *hdlp, void *result)
-{
- dev_info_t *cdip = rdip;
- pci_regspec_t *pci_rp;
- int reglen, len;
- uint32_t d, intr;
-
- if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) ||
- (hdlp->ih_type != DDI_INTR_TYPE_FIXED))
- goto done;
-
- /*
- * If the interrupt-map property is defined at this
- * node, it will have performed the interrupt
- * translation as part of the property, so no
- * rotation needs to be done.
- */
- if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "interrupt-map", &len) == DDI_PROP_SUCCESS)
- goto done;
-
- cdip = pcie_get_my_childs_dip(dip, rdip);
-
- /*
- * Use the devices reg property to determine its
- * PCI bus number and device number.
- */
- if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
- "reg", (caddr_t)&pci_rp, &reglen) != DDI_SUCCESS)
- return (DDI_FAILURE);
-
- intr = hdlp->ih_vector;
-
- /* spin the interrupt */
- d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
- if ((intr >= PCI_INTA) && (intr <= PCI_INTD))
- hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1);
- else
- cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range",
- ddi_driver_name(rdip), ddi_get_instance(rdip),
- ddi_driver_name(dip), intr);
-
- kmem_free(pci_rp, reglen);
-
-done:
- /* Pass up the request to our parent. */
- return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
-}
-
-/*
- * name_child
- *
- * This function is called from init_child to name a node. It is
- * also passed as a callback for node merging functions.
- *
- * return value: DDI_SUCCESS, DDI_FAILURE
- */
-static int
-pxb_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;
-
- /*
- * 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) {
- 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 name node from %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_FAILURE);
- }
- (void) snprintf(name, namelen, "%s", *unit_addr);
- ddi_prop_free(unit_addr);
- return (DDI_SUCCESS);
- }
-
- /*
- * Get the address portion of the node name based on
- * the function and device number.
- */
- if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
- "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
- return (DDI_FAILURE);
- }
-
- slot = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
- func = PCI_REG_FUNC_G(pci_rp[0].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
-pxb_initchild(dev_info_t *child)
-{
- char name[MAXNAMELEN];
- pxb_devstate_t *pxb;
- int result = DDI_FAILURE;
- intptr_t ppd = NULL;
-#ifdef PX_PLX
- int i;
- uint16_t reg = 0;
- ddi_acc_handle_t config_handle;
-#endif /* PX_PLX */
-
- /*
- * Name the child
- */
- if (pxb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) {
- result = DDI_FAILURE;
- goto done;
- }
-
- /*
- * XXX set ppd to 1 to disable iommu BDF protection
- * It relies on unused parent private data for PCI devices.
- */
- if (ddi_prop_exists(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
- "dvma-share"))
- ppd = 1;
-
- ddi_set_name_addr(child, name);
- ddi_set_parent_data(child, (void *)ppd);
-
- /*
- * 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;
-
- /*
- * Try to merge the properties from this prototype
- * node into real h/w nodes.
- */
- if (ndi_merge_node(child, pxb_name_child) == DDI_SUCCESS) {
- /*
- * Merged ok - return failure to remove the node.
- */
- ddi_set_name_addr(child, NULL);
- ddi_remove_minor_node(child, NULL);
- result = DDI_FAILURE;
- goto done;
- }
-
- /* workaround for ddivs to run under PCI */
- if (pci_allow_pseudo_children) {
- result = DDI_SUCCESS;
- goto done;
- }
-
- /*
- * 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);
- ddi_remove_minor_node(child, NULL);
- result = DDI_NOT_WELL_FORMED;
- goto done;
- }
-
- ddi_set_parent_data(child, (void *)ppd);
-
- pxb = (pxb_devstate_t *)ddi_get_soft_state(pxb_state,
- ddi_get_instance(ddi_get_parent(child)));
-
- if (pcie_pm_hold(pxb->pxb_dip) != DDI_SUCCESS) {
- DBG(DBG_PWR, pxb->pxb_dip,
- "INITCHILD: px_pm_hold failed\n");
- result = DDI_FAILURE;
- goto done;
- }
- /* Any return from here must call pcie_pm_release */
-
- /*
- * If configuration registers were previously saved by
- * child (before it entered D3), then let the child do the
- * restore to set up the config regs as it'll first need to
- * power the device out of D3.
- */
- if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
- "config-regs-saved-by-child") == 1) {
- DBG(DBG_PWR, ddi_get_parent(child),
- "INITCHILD: config regs to be restored by child"
- " for %s@%s\n", ddi_node_name(child),
- ddi_get_name_addr(child));
-
- result = DDI_SUCCESS;
- goto cleanup;
- }
-
- DBG(DBG_PWR, ddi_get_parent(child),
- "INITCHILD: config regs setup for %s@%s\n",
- ddi_node_name(child), ddi_get_name_addr(child));
-
- if (!pcie_init_bus(child) || pcie_initchild(child) != DDI_SUCCESS) {
- result = DDI_FAILURE;
- goto cleanup;
- }
-
-#ifdef PX_PLX
- /*
- * Due to a PLX HW bug, a SW workaround to prevent the chip from
- * wedging is needed. SW just needs to tranfer 64 TLPs from
- * the downstream port to the child device.
- * The most benign way of doing this is to read the ID register
- * 64 times. This SW workaround should have minimum performance
- * impact and shouldn't cause a problem for all other bridges
- * and switches.
- *
- * The code needs to be written in a way to make sure it isn't
- * optimized out.
- */
- if (!pxb_tlp_count) {
- result = DDI_SUCCESS;
- goto cleanup;
- }
-
- if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
- result = DDI_FAILURE;
- goto cleanup;
- }
-
- for (i = 0; i < pxb_tlp_count; i += 1)
- reg |= pci_config_get16(config_handle, PCI_CONF_VENID);
-
- if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(pxb->pxb_dip)))
- pxb_set_pci_perf_parameters(child, config_handle);
-
- pci_config_teardown(&config_handle);
-#endif /* PX_PLX */
-
- result = DDI_SUCCESS;
-cleanup:
- pcie_pm_release(pxb->pxb_dip);
-done:
- return (result);
-}
-
-static int
-pxb_intr_attach(pxb_devstate_t *pxb)
-{
- int intr_types;
- dev_info_t *devi;
-
- devi = pxb->pxb_dip;
- /*
- * Initialize interrupt handlers.
- * If both MSI and FIXED are supported, try to attach MSI first.
- * If MSI fails for any reason, then try FIXED, but only allow one
- * type to be attached.
- */
- if (ddi_intr_get_supported_types(devi, &intr_types) != DDI_SUCCESS) {
- DBG(DBG_ATTACH, devi, "ddi_intr_get_supported_types failed\n");
- return (DDI_FAILURE);
- }
-
- if ((intr_types & DDI_INTR_TYPE_MSI) && pxb_enable_msi) {
- if (pxb_intr_init(pxb, DDI_INTR_TYPE_MSI) == DDI_SUCCESS)
- intr_types = DDI_INTR_TYPE_MSI;
- else
- DBG(DBG_ATTACH, devi, "Unable to attach MSI handler\n");
- }
-
- if (intr_types & DDI_INTR_TYPE_FIXED) {
- if (pxb_intr_init(pxb, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
- DBG(DBG_ATTACH, devi,
- "Unable to attach INTx handler\n");
- return (DDI_FAILURE);
- }
- }
- return (DDI_SUCCESS);
-}
-
-/*
- * This function initializes internally generated interrupts only.
- * It does not affect any interrupts generated by downstream devices
- * or the forwarding of them.
- *
- * Enable Device Specific Interrupts or Hotplug features here.
- * Enabling features may change how many interrupts are requested
- * by the device. If features are not enabled first, the
- * device might not ask for any interrupts.
- */
-static int
-pxb_intr_init(pxb_devstate_t *pxb, int intr_type)
-{
- dev_info_t *dip = pxb->pxb_dip;
- int request, count, x;
- int ret;
- int intr_cap = 0;
-
- DBG(DBG_ATTACH, dip,
- "Attaching %s handler\n",
- (intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx");
-
- /*
- * Get number of requested interrupts. If none requested or DDI_FAILURE
- * just return DDI_SUCCESS.
- *
- * Several Bridges/Switches will not have this property set, resulting
- * in a FAILURE, if the device is not configured in a way that
- * interrupts are needed. (eg. hotplugging)
- */
- ret = ddi_intr_get_nintrs(dip, intr_type, &request);
- if (ret != DDI_SUCCESS || request == 0) {
- DBG(DBG_ATTACH, dip,
- "ddi_intr_get_nintrs() ret: %d req %d\n", ret, request);
-
- return (DDI_SUCCESS);
- }
-
- /* Find out how many MSI's are available. */
- if (intr_type == DDI_INTR_TYPE_MSI) {
- ret = ddi_intr_get_navail(dip, intr_type, &count);
- if ((ret != DDI_SUCCESS) || (count == 0)) {
- DBG(DBG_ATTACH, dip,
- "ddi_intr_get_navail() ret: %d available: %d\n",
- ret, count);
-
- goto fail;
- }
-
- if (request < count) {
- DBG(DBG_ATTACH, dip,
- "Requested Intr: %d Available: %d\n",
- request, count);
-
- request = count;
- }
- }
-
- /* Allocate an array of interrupt handlers */
- pxb->pxb_htable_size = sizeof (ddi_intr_handle_t) * request;
- pxb->pxb_htable = kmem_zalloc(pxb->pxb_htable_size, KM_SLEEP);
- pxb->pxb_init_flags |= PXB_INIT_HTABLE;
-
- ret = ddi_intr_alloc(dip, pxb->pxb_htable, intr_type,
- 0, request, &count, DDI_INTR_ALLOC_NORMAL);
- if ((ret != DDI_SUCCESS) || (count == 0)) {
- DBG(DBG_ATTACH, dip,
- "ddi_intr_alloc() ret: %d ask: %d actual: %d\n",
- ret, request, count);
-
- goto fail;
- }
-
- /* Save the actually number of interrupts allocated */
- pxb->pxb_intr_count = count;
- if (count < request) {
- DBG(DBG_ATTACH, dip,
- "Requested Intr: %d Received: %d\n",
- request, count);
- }
- pxb->pxb_init_flags |= PXB_INIT_ALLOC;
-
-
- /* Get interrupt priority */
- ret = ddi_intr_get_pri(pxb->pxb_htable[0], &pxb->pxb_intr_priority);
- if (ret != DDI_SUCCESS) {
- DBG(DBG_ATTACH, dip, "ddi_intr_get_pri() ret: %d\n", ret);
-
- goto fail;
- }
-
- if (pxb->pxb_intr_priority >= LOCK_LEVEL) {
- pxb->pxb_intr_priority = LOCK_LEVEL - 1;
- ret = ddi_intr_set_pri(pxb->pxb_htable[0],
- pxb->pxb_intr_priority);
- if (ret != DDI_SUCCESS) {
- DBG(DBG_ATTACH, dip, "ddi_intr_set_pri() ret: %d\n",
- ret);
-
- goto fail;
- }
- }
-
- for (count = 0; count < pxb->pxb_intr_count; count++) {
- ret = ddi_intr_add_handler(pxb->pxb_htable[count],
- pxb_intr, (caddr_t)pxb, NULL);
-
- if (ret != DDI_SUCCESS) {
- DBG(DBG_ATTACH, dip,
- "ddi_intr_add_handler() ret: %d\n",
- ret);
-
- break;
- }
- }
-
- /* If unsucessful remove the added handlers */
- if (ret != DDI_SUCCESS) {
- for (x = 0; x < count; x++) {
- (void) ddi_intr_remove_handler(pxb->pxb_htable[x]);
- }
- goto fail;
- }
-
- pxb->pxb_init_flags |= PXB_INIT_HANDLER;
-
- (void) ddi_intr_get_cap(pxb->pxb_htable[0], &intr_cap);
-
- if (intr_cap & DDI_INTR_FLAG_BLOCK) {
- (void) ddi_intr_block_enable(pxb->pxb_htable,
- pxb->pxb_intr_count);
- pxb->pxb_init_flags |= PXB_INIT_BLOCK;
- } else {
- for (count = 0; count < pxb->pxb_intr_count; count++) {
- (void) ddi_intr_enable(pxb->pxb_htable[count]);
- }
- }
- pxb->pxb_init_flags |= PXB_INIT_ENABLE;
-
- /* Save the interrupt type */
- pxb->pxb_intr_type = intr_type;
-
- return (DDI_SUCCESS);
-
-fail:
- pxb_intr_fini(pxb);
-
- return (DDI_FAILURE);
-}
-
-static void
-pxb_intr_fini(pxb_devstate_t *pxb)
-{
- int x;
- int count = pxb->pxb_intr_count;
- int flags = pxb->pxb_init_flags;
-
- if ((flags & PXB_INIT_ENABLE) && (flags & PXB_INIT_BLOCK)) {
- (void) ddi_intr_block_disable(pxb->pxb_htable, count);
- flags &= ~(PXB_INIT_ENABLE | PXB_INIT_BLOCK);
- }
-
- for (x = 0; x < count; x++) {
- if (flags & PXB_INIT_ENABLE)
- (void) ddi_intr_disable(pxb->pxb_htable[x]);
-
- if (flags & PXB_INIT_HANDLER)
- (void) ddi_intr_remove_handler(pxb->pxb_htable[x]);
-
- if (flags & PXB_INIT_ALLOC)
- (void) ddi_intr_free(pxb->pxb_htable[x]);
- }
-
- flags &= ~(PXB_INIT_ENABLE | PXB_INIT_HANDLER | PXB_INIT_ALLOC);
-
- if (flags & PXB_INIT_HTABLE)
- kmem_free(pxb->pxb_htable, pxb->pxb_htable_size);
-
- flags &= ~PXB_INIT_HTABLE;
-
- pxb->pxb_init_flags &= flags;
-}
-
-/*
- * This only handles internal errors, not bus errors.
- * Currently the only known interrupt would be from hotplugging.
- */
-/*ARGSUSED*/
-static uint_t
-pxb_intr(caddr_t arg1, caddr_t arg2)
-{
- pxb_devstate_t *pxb = (pxb_devstate_t *)arg1;
- dev_info_t *dip = pxb->pxb_dip;
- int rval = DDI_INTR_UNCLAIMED;
-
- if (pxb->pxb_hotplug_capable == B_TRUE) {
- if (pxb->pxb_hpc_type == HPC_PCIE)
- rval = pciehpc_intr(pxb->pxb_dip);
- else
- if (pxb->pxb_hpc_type == HPC_SHPC)
- rval = pcishpc_intr(pxb->pxb_dip);
- }
- if ((rval == DDI_INTR_UNCLAIMED) &&
- (pxb->pxb_intr_type == DDI_INTR_TYPE_MSI))
- cmn_err(CE_WARN, "%s%d: Cannot handle interrupt",
- ddi_driver_name(dip), ddi_get_instance(dip));
-
- return (rval);
-}
-
-static void
-pxb_removechild(dev_info_t *dip)
-{
- ddi_set_name_addr(dip, NULL);
-
- /*
- * Strip the node to properly convert it back to prototype form
- */
- ddi_remove_minor_node(dip, NULL);
-
- /*
- * XXX Clear parent private data used as a flag to disable
- * iommu BDF protection
- */
- if ((intptr_t)ddi_get_parent_data(dip) == 1)
- ddi_set_parent_data(dip, NULL);
-
- impl_rem_dev_props(dip);
-
- pcie_uninitchild(dip);
-}
-
-/*
- * Initialize hotplug framework if we are hotpluggable.
- * Sets flag in the soft state if Hot Plug is supported and initialized
- * properly.
- */
-/*ARGSUSED*/
-static int
-pxb_init_hotplug(pxb_devstate_t *pxb)
-{
- int rv = DDI_FAILURE;
- uint8_t dev_type = PCIE_DIP2BUS(pxb->pxb_dip)->bus_dev_type;
-
- if (((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
- (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE) ||
- (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT)) &&
- (pxb_pciehpc_probe(pxb->pxb_dip,
- pxb->pxb_config_handle) == DDI_SUCCESS)) {
- pxb->pxb_hpc_type = HPC_PCIE;
- } else if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
- (pxb_pcishpc_probe(pxb->pxb_dip,
- pxb->pxb_config_handle) == DDI_SUCCESS)) {
- pxb->pxb_hpc_type = HPC_SHPC;
- } else {
- pxb->pxb_hpc_type = HPC_NONE;
- return (DDI_SUCCESS);
- }
-
- pxb->pxb_hotplug_capable = B_TRUE;
- if (pxb_intr_attach(pxb) != DDI_SUCCESS)
- goto fail;
-
- if (pxb->pxb_hpc_type == HPC_PCIE)
- rv = pciehpc_init(pxb->pxb_dip, NULL);
- else if (pxb->pxb_hpc_type == HPC_SHPC)
- rv = pcishpc_init(pxb->pxb_dip);
-
- if (rv != DDI_SUCCESS)
- goto fail;
-
- if (pcihp_init(pxb->pxb_dip) != DDI_SUCCESS) {
- if (pxb->pxb_hpc_type == HPC_PCIE)
- (void) pciehpc_uninit(pxb->pxb_dip);
- else if (pxb->pxb_hpc_type == HPC_SHPC)
- (void) pcishpc_uninit(pxb->pxb_dip);
-
- goto fail;
- }
-
- (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pxb->pxb_dip,
- "hotplug-capable");
-
- return (DDI_SUCCESS);
-
-fail:
- pxb->pxb_hpc_type = HPC_NONE;
- pxb->pxb_hotplug_capable = B_FALSE;
- cmn_err(CE_WARN, "%s%d: Failed setting hotplug framework",
- ddi_driver_name(pxb->pxb_dip), ddi_get_instance(pxb->pxb_dip));
-
- return (DDI_FAILURE);
-}
-
-static void
-pxb_create_ranges_prop(dev_info_t *dip,
- ddi_acc_handle_t config_handle)
-{
- uint32_t base, limit;
- pxb_ranges_t ranges[PXB_RANGE_LEN];
- uint8_t io_base_lo, io_limit_lo;
- uint16_t io_base_hi, io_limit_hi, mem_base, mem_limit;
- int i = 0, rangelen = sizeof (pxb_ranges_t)/sizeof (int);
-
- io_base_lo = pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW);
- io_limit_lo = pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW);
- io_base_hi = pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI);
- io_limit_hi = pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI);
- mem_base = pci_config_get16(config_handle, PCI_BCNF_MEM_BASE);
- mem_limit = pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT);
-
- /*
- * Create ranges for IO space
- */
- ranges[i].size_low = ranges[i].size_high = 0;
- ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
- ranges[i].child_high = ranges[i].parent_high |=
- (PCI_REG_REL_M | PCI_ADDR_IO);
- base = PXB_16bit_IOADDR(io_base_lo);
- limit = PXB_16bit_IOADDR(io_limit_lo);
-
- if ((io_base_lo & 0xf) == PXB_32BIT_IO) {
- base = PXB_LADDR(base, io_base_hi);
- }
- if ((io_limit_lo & 0xf) == PXB_32BIT_IO) {
- limit = PXB_LADDR(limit, io_limit_hi);
- }
-
- if ((io_base_lo & PXB_32BIT_IO) && (io_limit_hi > 0)) {
- base = PXB_LADDR(base, io_base_hi);
- limit = PXB_LADDR(limit, io_limit_hi);
- }
-
- /*
- * Create ranges for 32bit memory space
- */
- base = PXB_32bit_MEMADDR(mem_base);
- limit = PXB_32bit_MEMADDR(mem_limit);
- ranges[i].size_low = ranges[i].size_high = 0;
- ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
- ranges[i].child_high = ranges[i].parent_high |=
- (PCI_REG_REL_M | PCI_ADDR_MEM32);
- ranges[i].child_low = ranges[i].parent_low = base;
- if (limit >= base) {
- ranges[i].size_low = limit - base + PXB_MEMGRAIN;
- i++;
- }
-
- if (i) {
- (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
- (int *)ranges, i * rangelen);
- }
-}
-
-/*ARGSUSED*/
-static int
-pxb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
-{
- pxb_devstate_t *pxb_p;
- minor_t minor = getminor(*devp);
- int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
- /*
- * Make sure the open is for the right file type.
- */
- if (otyp != OTYP_CHR)
- return (EINVAL);
-
- /*
- * Get the soft state structure for the device.
- */
- pxb_p = (pxb_devstate_t *)ddi_get_soft_state(pxb_state,
- instance);
-
- if (pxb_p == NULL)
- return (ENXIO);
-
- if (pxb_p->pxb_hotplug_capable == B_TRUE)
- return ((pcihp_get_cb_ops())->cb_open(devp, flags,
- otyp, credp));
-
- /*
- * Handle the open by tracking the device state.
- */
- mutex_enter(&pxb_p->pxb_mutex);
- if (flags & FEXCL) {
- if (pxb_p->pxb_soft_state != PXB_SOFT_STATE_CLOSED) {
- mutex_exit(&pxb_p->pxb_mutex);
- return (EBUSY);
- }
- pxb_p->pxb_soft_state = PXB_SOFT_STATE_OPEN_EXCL;
- } else {
- if (pxb_p->pxb_soft_state == PXB_SOFT_STATE_OPEN_EXCL) {
- mutex_exit(&pxb_p->pxb_mutex);
- return (EBUSY);
- }
- pxb_p->pxb_soft_state = PXB_SOFT_STATE_OPEN;
- }
- mutex_exit(&pxb_p->pxb_mutex);
- return (0);
-}
-
-
-/*ARGSUSED*/
-static int
-pxb_close(dev_t dev, int flags, int otyp, cred_t *credp)
-{
- pxb_devstate_t *pxb_p;
- minor_t minor = getminor(dev);
- int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
- if (otyp != OTYP_CHR)
- return (EINVAL);
-
- pxb_p = (pxb_devstate_t *)ddi_get_soft_state(pxb_state,
- instance);
-
- if (pxb_p == NULL)
- return (ENXIO);
-
- if (pxb_p->pxb_hotplug_capable == B_TRUE)
- return ((pcihp_get_cb_ops())->cb_close(dev, flags,
- otyp, credp));
-
- mutex_enter(&pxb_p->pxb_mutex);
- pxb_p->pxb_soft_state = PXB_SOFT_STATE_CLOSED;
- mutex_exit(&pxb_p->pxb_mutex);
- return (0);
-}
-
-
-/*
- * pxb_ioctl: devctl hotplug controls
- */
-/*ARGSUSED*/
-static int
-pxb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
- int *rvalp)
-{
- pxb_devstate_t *pxb_p;
- dev_info_t *self;
- struct devctl_iocdata *dcp;
- uint_t bus_state;
- int rv = 0;
- minor_t minor = getminor(dev);
- int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
- pxb_p = (pxb_devstate_t *)ddi_get_soft_state(pxb_state,
- instance);
-
- if (pxb_p == NULL)
- return (ENXIO);
-
- if (pxb_p->pxb_hotplug_capable == B_TRUE)
- return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
- arg, mode, credp, rvalp));
-
- self = pxb_p->pxb_dip;
-
- /*
- * We can use the generic implementation for these ioctls
- */
- switch (cmd) {
- case DEVCTL_DEVICE_GETSTATE:
- case DEVCTL_DEVICE_ONLINE:
- case DEVCTL_DEVICE_OFFLINE:
- case DEVCTL_BUS_GETSTATE:
- return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
- }
-
- /*
- * read devctl ioctl data
- */
- if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
- return (EFAULT);
-
- switch (cmd) {
-
- case DEVCTL_DEVICE_RESET:
- rv = ENOTSUP;
- break;
-
- case DEVCTL_BUS_QUIESCE:
- if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
- if (bus_state == BUS_QUIESCED)
- break;
- (void) ndi_set_bus_state(self, BUS_QUIESCED);
- break;
-
- case DEVCTL_BUS_UNQUIESCE:
- if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
- if (bus_state == BUS_ACTIVE)
- break;
- (void) ndi_set_bus_state(self, BUS_ACTIVE);
- break;
-
- case DEVCTL_BUS_RESET:
- rv = ENOTSUP;
- break;
-
- case DEVCTL_BUS_RESETALL:
- rv = ENOTSUP;
- break;
-
- default:
- rv = ENOTTY;
- }
-
- ndi_dc_freehdl(dcp);
- return (rv);
-}
-
-static int pxb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
- int flags, char *name, caddr_t valuep, int *lengthp)
-{
- pxb_devstate_t *pxb_p;
- minor_t minor = getminor(dev);
- int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
-
- pxb_p = (pxb_devstate_t *)ddi_get_soft_state(pxb_state,
- instance);
-
- if (pxb_p == NULL)
- return (ENXIO);
-
- if (pxb_p->pxb_hotplug_capable == B_TRUE)
- return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op,
- flags, name, valuep, lengthp));
-
- return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
-}
-
-#ifdef PX_PLX
-/*
- * Disable PM for PLX 8532 switch. Transitioning one port on
- * this switch to low power causes links on other ports on the
- * same station to die.
- * Due to PLX erratum #34, we can't allow the downstream device
- * go to non-D0 state.
- */
-static int
-plx_pwr_disable(dev_info_t *dip)
-{
- pcie_pwr_t *pwr_p;
-
- ASSERT(PCIE_PMINFO(dip));
- pwr_p = PCIE_NEXUS_PMINFO(dip);
- ASSERT(pwr_p);
- DBG(DBG_PWR, dip, "plx_pwr_disable: PLX8532/PLX8516 found "
- "disabling PM\n");
- pwr_p->pwr_func_lvl = PM_LEVEL_D0;
- pwr_p->pwr_flags = PCIE_NO_CHILD_PM;
- return (DDI_SUCCESS);
-}
-#endif /* PX_PLX */
-
-/*
- * Power management related initialization specific to px_pci.
- * Called by pxb_attach()
- */
-static int
-pxb_pwr_setup(dev_info_t *dip)
-{
- char *comp_array[5];
- int i;
- ddi_acc_handle_t conf_hdl;
- uint16_t pmcap, cap_ptr;
- pcie_pwr_t *pwr_p;
-
- ASSERT(PCIE_PMINFO(dip));
- pwr_p = PCIE_NEXUS_PMINFO(dip);
- ASSERT(pwr_p);
-
- /* Code taken from pci_pci driver */
- if (pci_config_setup(dip, &pwr_p->pwr_conf_hdl) != DDI_SUCCESS) {
- DBG(DBG_PWR, dip, "pxb_pwr_setup: pci_config_setup failed\n");
- return (DDI_FAILURE);
- }
- conf_hdl = pwr_p->pwr_conf_hdl;
-
- /*
- * Walk the capabilities searching for a PM entry.
- */
- if ((PCI_CAP_LOCATE(conf_hdl, PCI_CAP_ID_PM, &cap_ptr)) ==
- DDI_FAILURE) {
- DBG(DBG_PWR, dip, "switch/bridge does not support PM. PCI"
- " PM data structure not found in config header\n");
- pci_config_teardown(&conf_hdl);
- return (DDI_SUCCESS);
- }
- /*
- * Save offset to pmcsr for future references.
- */
- pwr_p->pwr_pmcsr_offset = cap_ptr + PCI_PMCSR;
- pmcap = PCI_CAP_GET16(conf_hdl, NULL, cap_ptr, PCI_PMCAP);
- if (pmcap & PCI_PMCAP_D1) {
- DBG(DBG_PWR, dip, "D1 state supported\n");
- pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D1;
- }
- if (pmcap & PCI_PMCAP_D2) {
- DBG(DBG_PWR, dip, "D2 state supported\n");
- pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D2;
- }
-
- i = 0;
- comp_array[i++] = "NAME=PCIe switch/bridge PM";
- comp_array[i++] = "0=Power Off (D3)";
- if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D2)
- comp_array[i++] = "1=D2";
- if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D1)
- comp_array[i++] = "2=D1";
- comp_array[i++] = "3=Full Power D0";
-
- /*
- * Create pm-components property, if it does not exist already.
- */
- if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
- "pm-components", comp_array, i) != DDI_PROP_SUCCESS) {
- DBG(DBG_PWR, dip, "could not create pm-components prop\n");
- pci_config_teardown(&conf_hdl);
- return (DDI_FAILURE);
- }
- return (pxb_pwr_init_and_raise(dip, pwr_p));
-}
-
-/*
- * Initializes the power level and raise the power to D0, if it is
- * not at D0.
- */
-static int
-pxb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p)
-{
- uint16_t pmcsr;
- int ret = DDI_SUCCESS;
-
- /*
- * Intialize our power level from PMCSR. The common code initializes
- * this to UNKNOWN. There is no guarantee that we will be at full
- * power at attach. If we are not at D0, raise the power.
- */
- pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl, pwr_p->pwr_pmcsr_offset);
- pmcsr &= PCI_PMCSR_STATE_MASK;
- switch (pmcsr) {
- case PCI_PMCSR_D0:
- pwr_p->pwr_func_lvl = PM_LEVEL_D0;
- break;
-
- case PCI_PMCSR_D1:
- pwr_p->pwr_func_lvl = PM_LEVEL_D1;
- break;
-
- case PCI_PMCSR_D2:
- pwr_p->pwr_func_lvl = PM_LEVEL_D2;
- break;
-
- case PCI_PMCSR_D3HOT:
- pwr_p->pwr_func_lvl = PM_LEVEL_D3;
- break;
-
- default:
- break;
- }
-
- /* Raise the power to D0. */
- if (pwr_p->pwr_func_lvl != PM_LEVEL_D0 &&
- ((ret = pm_raise_power(dip, 0, PM_LEVEL_D0)) != DDI_SUCCESS)) {
- /*
- * Read PMCSR again. If it is at D0, ignore the return
- * value from pm_raise_power.
- */
- pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl,
- pwr_p->pwr_pmcsr_offset);
- if ((pmcsr & PCI_PMCSR_STATE_MASK) == PCI_PMCSR_D0)
- ret = DDI_SUCCESS;
- else {
- DBG(DBG_PWR, dip, "pxb_pwr_setup: could not raise "
- "power to D0 \n");
- }
- }
- if (ret == DDI_SUCCESS)
- pwr_p->pwr_func_lvl = PM_LEVEL_D0;
- return (ret);
-}
-
-static int
-pxb_fm_init(pxb_devstate_t *pxb_p)
-{
- dev_info_t *dip = pxb_p->pxb_dip;
- int fm_cap = DDI_FM_EREPORT_CAPABLE |
- DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
-
- /*
- * Request our capability level and get our parents capability
- * and ibc.
- */
- ddi_fm_init(dip, &fm_cap, &pxb_p->pxb_fm_ibc);
-
- pci_ereport_setup(dip);
-
- return (DDI_SUCCESS);
-}
-
-/*
- * Breakdown our FMA resources
- */
-static void
-pxb_fm_fini(pxb_devstate_t *pxb_p)
-{
- dev_info_t *dip = pxb_p->pxb_dip;
- /*
- * Clean up allocated fm structures
- */
- ddi_fm_fini(dip);
-}
-
-/*
- * Function used to initialize FMA for our children nodes. Called
- * through pci busops when child node calls ddi_fm_init.
- */
-/*ARGSUSED*/
-int
-pxb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
- ddi_iblock_cookie_t *ibc_p)
-{
- pxb_devstate_t *pxb_p = (pxb_devstate_t *)
- ddi_get_soft_state(pxb_state, ddi_get_instance(dip));
- *ibc_p = pxb_p->pxb_fm_ibc;
- return (DEVI(dip)->devi_fmhdl->fh_cap | DDI_FM_DMACHK_CAPABLE);
-}
-
-/*
- * undo whatever is done in pxb_pwr_setup. called by pxb_detach()
- */
-static void
-pxb_pwr_teardown(dev_info_t *dip)
-{
- pcie_pwr_t *pwr_p;
-
- if (!PCIE_PMINFO(dip) || !(pwr_p = PCIE_NEXUS_PMINFO(dip)))
- return;
-
- (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components");
- if (pwr_p->pwr_conf_hdl)
- pci_config_teardown(&pwr_p->pwr_conf_hdl);
-}
-
-/*ARGSUSED*/
-static int pxb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
-{
- uint16_t cap_ptr;
-
- if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
- DDI_FAILURE) {
- uint16_t slotimpl = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
- PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
- if (slotimpl)
- if (PCI_CAP_GET32(config_handle, NULL, cap_ptr,
- PCIE_SLOTCAP) & PCIE_SLOTCAP_HP_CAPABLE)
- return (DDI_SUCCESS);
- }
-
- return (DDI_FAILURE);
-
-}
-
-/*ARGSUSED*/
-static int pxb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
-{
- uint16_t cap_ptr;
-
- if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_HOTPLUG, &cap_ptr)) !=
- DDI_FAILURE) {
- return (DDI_SUCCESS);
- }
-
- return (DDI_FAILURE);
-
-}
-
-/*
- * For PCI and PCI-X devices including PCIe2PCI bridge, initialize
- * cache-line-size and latency timer configuration registers.
- */
-static void
-pxb_set_pci_perf_parameters(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
-{
- uint_t n;
-
- /* Initialize cache-line-size configuration register if needed */
- if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "cache-line-size", 0) == 0) {
- pci_config_put8(cfg_hdl, PCI_CONF_CACHE_LINESZ,
- PXB_CACHE_LINE_SIZE);
- n = pci_config_get8(cfg_hdl, PCI_CONF_CACHE_LINESZ);
- if (n != 0) {
- (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
- "cache-line-size", n);
- }
- }
-
- /* Initialize latency timer configuration registers if needed */
- if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "latency-timer", 0) == 0) {
- uchar_t min_gnt, latency_timer;
- uchar_t header_type;
-
- /* Determine the configuration header type */
- header_type = pci_config_get8(cfg_hdl, PCI_CONF_HEADER);
-
- if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
- latency_timer = PXB_LATENCY_TIMER;
- pci_config_put8(cfg_hdl, PCI_BCNF_LATENCY_TIMER,
- latency_timer);
- } else {
- min_gnt = pci_config_get8(cfg_hdl, PCI_CONF_MIN_G);
- latency_timer = min_gnt * 8;
- }
-
- pci_config_put8(cfg_hdl, PCI_CONF_LATENCY_TIMER,
- latency_timer);
- n = pci_config_get8(cfg_hdl, PCI_CONF_LATENCY_TIMER);
- if (n != 0) {
- (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
- "latency-timer", n);
- }
- }
-}
-
-#ifdef PRINT_PLX_SEEPROM_CRC
-static void
-pxb_print_plx_seeprom_crc_data(pxb_devstate_t *pxb_p)
-{
- ddi_acc_handle_t h;
- dev_info_t *dip = pxb_p->pxb_dip;
- int nregs;
- caddr_t mp;
- off_t bar_size;
- ddi_device_acc_attr_t mattr = {
- DDI_DEVICE_ATTR_V0,
- DDI_STRUCTURE_LE_ACC,
- DDI_STRICTORDER_ACC
- };
- uint32_t addr_reg_off = 0x260, data_reg_off = 0x264, data = 0x6BE4;
-
- if (pxb_p->pxb_vendor_id != PXB_VENDOR_PLX)
- return;
- if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
- return;
- if (nregs < 2) /* check for CONF entry only, no BARs */
- return;
- if (ddi_dev_regsize(dip, 1, &bar_size) != DDI_SUCCESS)
- return;
- if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mp, 0, bar_size,
- &mattr, &h) != DDI_SUCCESS)
- return;
- ddi_put32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off), data);
- delay(drv_usectohz(1000000));
- printf("%s#%d: EEPROM StatusReg = %x, CRC = %x\n",
- ddi_driver_name(dip), ddi_get_instance(dip),
- ddi_get32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off)),
- ddi_get32(h, (uint32_t *)((uchar_t *)mp + data_reg_off)));
-#ifdef PLX_HOT_RESET_DISABLE
- /* prevent hot reset from propogating downstream. */
- data = ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC));
- ddi_put32(h, (uint32_t *)((uchar_t *)mp + 0x1DC), data | 0x80000);
- delay(drv_usectohz(1000000));
- printf("%s#%d: EEPROM 0x1DC prewrite=%x postwrite=%x\n",
- ddi_driver_name(dip), ddi_get_instance(dip), data,
- ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC)));
-#endif
- ddi_regs_map_free(&h);
-}
-#endif
-
-static void
-pxb_id_props(pxb_devstate_t *pxb)
-{
- uint64_t serialid = 0; /* 40b field of EUI-64 serial no. register */
- uint16_t cap_ptr;
- uint8_t fic = 0; /* 1 = first in chassis device */
-
- /*
- * Identify first in chassis. In the special case of a Sun branded
- * PLX device, it obviously is first in chassis. Otherwise, in the
- * general case, look for an Expansion Slot Register and check its
- * first-in-chassis bit.
- */
-#ifdef PX_PLX
- if ((pxb->pxb_vendor_id == PXB_VENDOR_SUN) &&
- ((pxb->pxb_device_id == PXB_DEVICE_PLX_PCIX) ||
- (pxb->pxb_device_id == PXB_DEVICE_PLX_PCIE))) {
- fic = 1;
- }
-#endif /* PX_PLX */
- if ((fic == 0) && ((PCI_CAP_LOCATE(pxb->pxb_config_handle,
- PCI_CAP_ID_SLOT_ID, &cap_ptr)) != DDI_FAILURE)) {
- uint8_t esr = PCI_CAP_GET8(pxb->pxb_config_handle, NULL,
- cap_ptr, PCI_CAP_ID_REGS_OFF);
- if (PCI_CAPSLOT_FIC(esr))
- fic = 1;
- }
-
- if ((PCI_CAP_LOCATE(pxb->pxb_config_handle,
- PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_SER), &cap_ptr)) != DDI_FAILURE) {
- /* Serialid can be 0 thru a full 40b number */
- serialid = PCI_XCAP_GET32(pxb->pxb_config_handle, NULL,
- cap_ptr, PCIE_SER_SID_UPPER_DW);
- serialid <<= 32;
- serialid |= PCI_XCAP_GET32(pxb->pxb_config_handle, NULL,
- cap_ptr, PCIE_SER_SID_LOWER_DW);
- }
-
- if (fic)
- (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pxb->pxb_dip,
- "first-in-chassis");
- if (serialid)
- (void) ddi_prop_update_int64(DDI_DEV_T_NONE, pxb->pxb_dip,
- "serialid#", serialid);
-}
-
-/*
- * Some PCI-X to PCI-E bridges do not support full 64-bit addressing on the
- * PCI-X side of the bridge. We build a special version of this driver for
- * those bridges, which uses PXB_ADDR_LIMIT_LO and/or PXB_ADDR_LIMIT_HI
- * to define the range of values which the chip can handle. The code below
- * then clamps the DMA address range supplied by the driver, preventing the
- * PCI-E nexus driver from allocating any memory the bridge can't deal
- * with.
- */
-static int
-pxb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
- ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg,
- ddi_dma_handle_t *handlep)
-{
- int ret;
-#ifdef BCM_SW_WORKAROUNDS
- uint64_t lim;
-
- /*
- * If the leaf device's limits are outside than what the Broadcom
- * bridge can handle, we need to clip the values passed up the chain.
- */
- lim = attr_p->dma_attr_addr_lo;
- attr_p->dma_attr_addr_lo = MAX(lim, PXB_ADDR_LIMIT_LO);
-
- lim = attr_p->dma_attr_addr_hi;
- attr_p->dma_attr_addr_hi = MIN(lim, PXB_ADDR_LIMIT_HI);
-
-#endif /* BCM_SW_WORKAROUNDS */
-
- /*
- * This is a software workaround to fix the Broadcom 5714/5715 PCIe-PCI
- * bridge prefetch bug. Intercept the DMA alloc handle request and set
- * PX_DMAI_FLAGS_MAP_BUFZONE flag in the handle. If this flag is set,
- * the px nexus driver will allocate an extra page & make it valid one,
- * for any DVMA request that comes from any of the Broadcom bridge child
- * devices.
- */
- if ((ret = ddi_dma_allochdl(dip, rdip, attr_p, waitfp, arg,
- handlep)) == DDI_SUCCESS) {
- ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*handlep;
-#ifdef BCM_SW_WORKAROUNDS
- mp->dmai_inuse |= PX_DMAI_FLAGS_MAP_BUFZONE;
-#endif /* BCM_SW_WORKAROUNDS */
- /*
- * For a given rdip, update mp->dmai_bdf with the bdf value
- * of px_pci's immediate child or secondary bus-id of the
- * PCIe2PCI bridge.
- */
- mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip);
- }
-
- return (ret);
-}
-
-/*
- * FDVMA feature is not supported for any child device of Broadcom 5714/5715
- * PCIe-PCI bridge due to prefetch bug. Return failure immediately, so that
- * these drivers will switch to regular DVMA path.
- */
-/*ARGSUSED*/
-static int
-pxb_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
- enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp,
- uint_t cache_flags)
-{
- int ret;
-
-#ifdef BCM_SW_WORKAROUNDS
- if (cmd == DDI_DMA_RESERVE)
- return (DDI_FAILURE);
-#endif /* BCM_SW_WORKAROUNDS */
-
- if (((ret = ddi_dma_mctl(dip, rdip, handle, cmd, offp, lenp, objp,
- cache_flags)) == DDI_SUCCESS) && (cmd == DDI_DMA_RESERVE)) {
- ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*objp;
-
- /*
- * For a given rdip, update mp->dmai_bdf with the bdf value
- * of px_pci's immediate child or secondary bus-id of the
- * PCIe2PCI bridge.
- */
- mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip);
- }
-
- return (ret);
-}
-
-#ifdef DEBUG
-static void
-pxb_dbg(uint_t bit, dev_info_t *dip, char *fmt, ...)
-{
- va_list ap;
-
- if (!(bit & pxb_dbg_print))
- return;
-
- if (dip)
- prom_printf("%s(%d): %s", ddi_driver_name(dip),
- ddi_get_instance(dip), pxb_debug_sym[bit]);
-body:
- va_start(ap, fmt);
- if (ap)
- prom_vprintf(fmt, ap);
- else
- prom_printf(fmt);
-
- va_end(ap);
-}
-#endif
-
-
-#ifdef PX_PLX
-/*
- * Disable PLX specific relaxed ordering mode. Due to PLX
- * erratum #6, use of this mode with Cut-Through Cancellation
- * can result in dropped Completion type packets.
- *
- * Clear the Relaxed Ordering Mode on 8533 and 8548 switches.
- * To disable RO, clear bit 5 in offset 0x664, an undocumented
- * bit in the PLX spec, on Ports 0, 8 and 12. Proprietary PLX
- * registers are normally accessible only via memspace from Port
- * 0. If port 0 is attached go ahead and disable RO on Port 0,
- * 8 and 12, if they exist.
- */
-static void
-plx_ro_disable(pxb_devstate_t *pxb)
-{
- pcie_bus_t *bus_p = PCIE_DIP2BUS(pxb->pxb_dip);
- dev_info_t *dip = pxb->pxb_dip;
- pci_regspec_t *reg_spec, *addr_spec;
- int rlen, alen;
- int orig_rsize, new_rsize;
- uint_t rnum, anum;
- ddi_device_acc_attr_t attr;
- ddi_acc_handle_t hdl;
- caddr_t regsp;
- uint32_t val, port_enable;
- char *offset;
- char *port_offset;
-
- if (!((pxb->pxb_device_id == PXB_DEVICE_PLX_8533) ||
- (pxb->pxb_device_id == PXB_DEVICE_PLX_8548)))
- return;
-
- /* You can also only do this on Port 0 */
- val = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
- val = (val >> PCIE_LINKCAP_PORT_NUMBER_SHIFT) &
- PCIE_LINKCAP_PORT_NUMBER_MASK;
-
- DBG(DBG_ATTACH, dip, "PLX RO Disable : bdf=0x%x port=%d\n",
- bus_p->bus_bdf, val);
-
- if (val != 0)
- return;
-
- /*
- * Read the reg property, but allocate extra space incase we need to add
- * a new entry later.
- */
- if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
- &orig_rsize) != DDI_SUCCESS)
- return;
-
- new_rsize = orig_rsize + sizeof (pci_regspec_t);
- reg_spec = kmem_alloc(new_rsize, KM_SLEEP);
-
- if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
- (caddr_t)reg_spec, &orig_rsize) != DDI_SUCCESS)
- goto fail;
-
- /* Find the mem32 reg property */
- rlen = orig_rsize / sizeof (pci_regspec_t);
- for (rnum = 0; rnum < rlen; rnum++) {
- if ((reg_spec[rnum].pci_phys_hi & PCI_ADDR_MASK) ==
- PCI_ADDR_MEM32)
- goto fix;
- }
-
- /*
- * Mem32 reg property was not found.
- * Look for it in assign-address property.
- */
- addr_spec = bus_p->bus_assigned_addr;
- alen = bus_p->bus_assigned_entries;
- for (anum = 0; anum < alen; anum++) {
- if ((addr_spec[anum].pci_phys_hi & PCI_ADDR_MASK) ==
- PCI_ADDR_MEM32)
- goto update;
- }
-
- /* Unable to find mem space assigned address, give up. */
- goto fail;
-
-update:
- /*
- * Add the mem32 access to the reg spec.
- * Use the last entry which was previously allocated.
- */
- reg_spec[rnum].pci_phys_hi = (addr_spec[anum].pci_phys_hi &
- ~PCI_REG_REL_M);
- reg_spec[rnum].pci_phys_mid = 0;
- reg_spec[rnum].pci_phys_low = 0;
- reg_spec[rnum].pci_size_hi = addr_spec[anum].pci_size_hi;
- reg_spec[rnum].pci_size_low = addr_spec[anum].pci_size_low;
-
- /* Create the new reg_spec data and update the property */
- if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
- (int *)reg_spec, (new_rsize / sizeof (int))) != DDI_SUCCESS)
- goto fail;
-
-fix:
- attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
- attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
- attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
-
- if (ddi_regs_map_setup(dip, rnum, &regsp, 0, 0, &attr,
- &hdl) != DDI_SUCCESS)
- goto fail;
-
- /* Grab register which shows which ports are enabled */
- offset = (char *)regsp + PLX_INGRESS_PORT_ENABLE;
- port_enable = ddi_get32(hdl, (uint32_t *)offset);
-
- if ((port_enable == 0xFFFFFFFF) || (port_enable == 0))
- goto done;
-
- offset = (char *)regsp + PLX_INGRESS_CONTROL_SHADOW;
-
- /* Disable RO on Port 0 */
- port_offset = 0x0 + offset;
- val = ddi_get32(hdl, (uint32_t *)port_offset);
- if (val & PLX_RO_MODE_BIT)
- val ^= PLX_RO_MODE_BIT;
- ddi_put32(hdl, (uint32_t *)port_offset, val);
-
- /* Disable RO on Port 8, but make sure its enabled */
- if (!(port_enable & (1 << 8)))
- goto port12;
-
- port_offset = (8 * 0x1000) + offset;
- val = ddi_get32(hdl, (uint32_t *)port_offset);
- if (val & PLX_RO_MODE_BIT)
- val ^= PLX_RO_MODE_BIT;
- ddi_put32(hdl, (uint32_t *)port_offset, val);
-
-port12:
- /* Disable RO on Port 12, but make sure it exists */
- if (!(port_enable & (1 << 12)))
- goto done;
-
- port_offset = (12 * 0x1000) + offset;
- val = ddi_get32(hdl, (uint32_t *)port_offset);
- if (val & PLX_RO_MODE_BIT)
- val ^= PLX_RO_MODE_BIT;
- ddi_put32(hdl, (uint32_t *)port_offset, val);
-
-done:
- ddi_regs_map_free(&hdl);
-fail:
- kmem_free(reg_spec, new_rsize);
-}
-#endif /* PX_PLX */
diff --git a/usr/src/uts/sun4/io/px/px_pci.h b/usr/src/uts/sun4/io/px/px_pci.h
deleted file mode 100644
index 1303de878b..0000000000
--- a/usr/src/uts/sun4/io/px/px_pci.h
+++ /dev/null
@@ -1,177 +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 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SYS_PX_PCI_H
-#define _SYS_PX_PCI_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Intel specific register offsets with bit definitions.
- */
-#define PXB_PX_CAPABILITY_ID 0x44
-#define PXB_BRIDGE_CONF 0x40
-
-/*
- * PCI/PCI-E Configuration register specific values.
- */
-#define PX_PMODE 0x4000 /* PCI/PCIX Mode */
-#define PX_PFREQ_66 0x200 /* PCI clock frequency */
-#define PX_PFREQ_100 0x400
-#define PX_PFREQ_133 0x600
-#define PX_PMRE 0x80 /* Peer memory read enable */
-
-/*
- * Downstream delayed transaction resource partitioning.
- */
-#define PX_ODTP 0x40 /* Max. of two entries PX and PCI */
-
-/*
- * Maximum upstream delayed transaction.
- */
-#define PX_MDT_44 0x00
-#define PX_MDT_11 0x01
-#define PX_MDT_22 0x10
-
-
-#define NUM_LOGICAL_SLOTS 32
-#define PXB_RANGE_LEN 2
-#define PXB_32BIT_IO 1
-#define PXB_32bit_MEM 1
-#define PXB_MEMGRAIN 0x100000
-#define PXB_IOGRAIN 0x1000
-
-#define PXB_16bit_IOADDR(addr) ((uint16_t)(((uint8_t)(addr) & 0xF0) << 8))
-#define PXB_LADDR(lo, hi) (((uint16_t)(hi) << 16) | (uint16_t)(lo))
-#define PXB_32bit_MEMADDR(addr) (PXB_LADDR(0, ((uint16_t)(addr) & 0xFFF0)))
-
-typedef struct slot_table {
- uchar_t bus_id[128];
- uchar_t slot_name[32];
- uint8_t device_no;
- uint8_t phys_slot_num;
-} slot_table_t;
-
-/*
- * The following typedef is used to represent an entry in the "ranges"
- * property of a device node.
- */
-typedef struct {
- uint32_t child_high;
- uint32_t child_mid;
- uint32_t child_low;
- uint32_t parent_high;
- uint32_t parent_mid;
- uint32_t parent_low;
- uint32_t size_high;
- uint32_t size_low;
-} pxb_ranges_t;
-
-typedef enum { HPC_NONE, HPC_PCIE, HPC_SHPC, HPC_OUTBAND } pxb_hpc_type_t;
-
-typedef struct {
- dev_info_t *pxb_dip;
-
- ddi_acc_handle_t pxb_config_handle;
-
- /* Interrupt */
- ddi_intr_handle_t *pxb_htable; /* Intr Handlers */
- int pxb_htable_size; /* htable size */
- int pxb_intr_count; /* Num of Intr */
- uint_t pxb_intr_priority; /* Intr Priority */
- int pxb_intr_type; /* (MSI | FIXED) */
-
- /*
- * HP support
- */
- boolean_t pxb_hotplug_capable;
- pxb_hpc_type_t pxb_hpc_type;
-
- kmutex_t pxb_mutex;
- uint_t pxb_soft_state;
-
- /* Initialization flags */
- int pxb_init_flags;
-
- /* FMA */
- ddi_iblock_cookie_t pxb_fm_ibc;
-
- /* Vendor Device Id */
- uint16_t pxb_vendor_id;
- uint16_t pxb_device_id;
- uint8_t pxb_rev_id;
-} pxb_devstate_t;
-
-/*
- * soft state pointer and structure template:
- */
-extern void *pxb_state;
-
-/* pxb soft states */
-#define PXB_SOFT_STATE_CLOSED 0x00
-#define PXB_SOFT_STATE_OPEN 0x01
-#define PXB_SOFT_STATE_OPEN_EXCL 0x02
-
-/* pxb init flags */
-#define PXB_INIT_MUTEX 0x01
-#define PXB_INIT_CONFIG_HANDLE 0x02
-#define PXB_INIT_HTABLE 0x04
-#define PXB_INIT_ALLOC 0x08
-#define PXB_INIT_HANDLER 0x10
-#define PXB_INIT_ENABLE 0x20
-#define PXB_INIT_BLOCK 0x40
-#define PXB_INIT_FM 0x80
-
-#define PXB_HOTPLUG_INTR_PRI (LOCK_LEVEL - 1)
-
-/* functionality checks */
-#define PXB_MSI 1
-#define PXB_LINK_INIT 2
-#define PXB_HOTPLUG_MSGS 3
-
-#ifdef BCM_SW_WORKAROUNDS
-
-/* Workaround for address space limitation in Broadcom 5714/5715 */
-#define PXB_ADDR_LIMIT_LO 0ull
-#define PXB_ADDR_LIMIT_HI ((1ull << 40) - 1)
-
-#endif /* BCM_SW_WORKAROUNDS */
-
-/*
- * The following values are used to initialize the cache line size
- * and latency timer registers for PCI, PCI-X and PCIe2PCI devices.
- */
-#define PXB_CACHE_LINE_SIZE 0x10 /* 64 bytes in # of DWORDs */
-#define PXB_LATENCY_TIMER 0x40 /* 64 PCI cycles */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SYS_PX_PCI_H */
diff --git a/usr/src/uts/sun4/io/px/px_util.c b/usr/src/uts/sun4/io/px/px_util.c
index 0d4cf63bfe..7b951d2c5d 100644
--- a/usr/src/uts/sun4/io/px/px_util.c
+++ b/usr/src/uts/sun4/io/px/px_util.c
@@ -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.
*/
@@ -39,7 +39,7 @@
#include <sys/sunndi.h>
#include <sys/ddi_impldefs.h>
#include "px_obj.h"
-#include "pcie_pwr.h"
+#include <sys/pcie_pwr.h>
/*LINTLIBRARY*/
diff --git a/usr/src/uts/sun4u/io/px/px_err.c b/usr/src/uts/sun4u/io/px/px_err.c
index b5d753a0f5..c1c8d49a0b 100644
--- a/usr/src/uts/sun4u/io/px/px_err.c
+++ b/usr/src/uts/sun4u/io/px/px_err.c
@@ -41,7 +41,6 @@
#include <sys/membar.h>
#include <sys/machcpuvar.h>
#include <sys/platform_module.h>
-#include "pcie_pwr.h"
#include "px_lib4u.h"
#include "px_err.h"
#include "px_err_impl.h"
diff --git a/usr/src/uts/sun4u/io/px/px_hlib.c b/usr/src/uts/sun4u/io/px/px_hlib.c
index 6a292fc299..a98657031c 100644
--- a/usr/src/uts/sun4u/io/px/px_hlib.c
+++ b/usr/src/uts/sun4u/io/px/px_hlib.c
@@ -31,7 +31,6 @@
#include <sys/iommutsb.h>
#include <sys/pci.h>
#include <sys/hotplug/pci/pciehpc.h>
-#include <pcie_pwr.h>
#include <px_obj.h>
#include "px_regs.h"
#include "oberon_regs.h"
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c
index f9b98235d4..a8c655d8e2 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c
@@ -43,7 +43,7 @@
#include <sys/hotplug/pci/pciehpc.h>
#include <sys/spl.h>
#include <px_obj.h>
-#include <pcie_pwr.h>
+#include <sys/pcie_pwr.h>
#include "px_tools_var.h"
#include <px_regs.h>
#include <px_csr.h>