summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorkini <none@none>2006-03-02 17:22:20 -0800
committerkini <none@none>2006-03-02 17:22:20 -0800
commitb65731f1f612238279eb4d997f43589b535c5646 (patch)
tree2e13f2163e4c89fcce481bb6f1d09eb2ec55fc5e /usr/src
parentf18fc2780f13712904943c9253c24cab2e41e92b (diff)
downloadillumos-joyent-b65731f1f612238279eb4d997f43589b535c5646.tar.gz
PSARC/2005/375 PCI Hotplug Extensions for PCIe
PSARC/2006/037 PCI Express Hotplug Framework Interrupt Interfaces 6379464 Integrate PSARC/2005/375 for SPARC PCI Express Hotplug Support 5049969 Make efcode' PCI configurator as the default configurator for SPARC platforms --HG-- rename : usr/src/uts/sun4u/fcode/Makefile => usr/src/uts/sparc/fcode/Makefile rename : usr/src/uts/sun4u/fcodem/Makefile => usr/src/uts/sparc/fcodem/Makefile rename : usr/src/uts/sun4u/fcpci/Makefile => usr/src/uts/sparc/fcpci/Makefile rename : usr/src/uts/sun4u/pcicfg.e/Makefile => usr/src/uts/sparc/pcicfg.e/Makefile rename : usr/src/uts/sun4u/io/pcicfg.e.c => usr/src/uts/sun4/io/pcicfg.e.c rename : usr/src/uts/sun4u/sys/fc_plat.h => usr/src/uts/sun4/sys/fc_plat.h
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf3
-rw-r--r--usr/src/lib/efcode/pci/Makefile.com5
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_sparc3
-rw-r--r--usr/src/pkgdefs/SUNWefc.u/prototype_com54
-rw-r--r--usr/src/pkgdefs/SUNWefcl/prototype_sparc5
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c78
-rw-r--r--usr/src/uts/common/io/hotplug/pcishpc/pcishpc.c2379
-rw-r--r--usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h11
-rw-r--r--usr/src/uts/common/sys/hotplug/pci/pcishpc.h50
-rw-r--r--usr/src/uts/sparc/Makefile.files6
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared4
-rw-r--r--usr/src/uts/sparc/fcode/Makefile (renamed from usr/src/uts/sun4u/fcode/Makefile)21
-rw-r--r--usr/src/uts/sparc/fcodem/Makefile (renamed from usr/src/uts/sun4u/fcodem/Makefile)20
-rw-r--r--usr/src/uts/sparc/fcpci/Makefile (renamed from usr/src/uts/sun4u/fcpci/Makefile)21
-rw-r--r--usr/src/uts/sparc/ml/modstubs.s36
-rw-r--r--usr/src/uts/sparc/pcicfg.e/Makefile (renamed from usr/src/uts/sun4u/pcicfg.e/Makefile)20
-rw-r--r--usr/src/uts/sparc/pciehpc/Makefile87
-rw-r--r--usr/src/uts/sparc/pcihp/Makefile4
-rw-r--r--usr/src/uts/sparc/pcishpc/Makefile87
-rw-r--r--usr/src/uts/sparc/px_pci/Makefile5
-rw-r--r--usr/src/uts/sun4/Makefile.files3
-rw-r--r--usr/src/uts/sun4/io/pcicfg.e.c (renamed from usr/src/uts/sun4u/io/pcicfg.e.c)918
-rw-r--r--usr/src/uts/sun4/io/px/px.c105
-rw-r--r--usr/src/uts/sun4/io/px/px_devctl.c26
-rw-r--r--usr/src/uts/sun4/io/px/px_dma.c4
-rw-r--r--usr/src/uts/sun4/io/px/px_fm.c6
-rw-r--r--usr/src/uts/sun4/io/px/px_lib.h8
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.c529
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.h18
-rw-r--r--usr/src/uts/sun4/io/px/px_var.h9
-rw-r--r--usr/src/uts/sun4/sys/fc_plat.h (renamed from usr/src/uts/sun4u/sys/fc_plat.h)0
-rw-r--r--usr/src/uts/sun4u/Makefile.files1
-rw-r--r--usr/src/uts/sun4u/Makefile.sun4u.shared2
-rw-r--r--usr/src/uts/sun4u/daktari/Makefile11
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c16
-rw-r--r--usr/src/uts/sun4u/montecarlo/Makefile10
-rw-r--r--usr/src/uts/sun4u/px/Makefile4
-rw-r--r--usr/src/uts/sun4u/serengeti/Makefile11
-rw-r--r--usr/src/uts/sun4u/starcat/Makefile10
-rw-r--r--usr/src/uts/sun4u/sys/Makefile2
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.c28
-rw-r--r--usr/src/uts/sun4v/px/Makefile4
44 files changed, 4133 insertions, 500 deletions
diff --git a/usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf b/usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf
index cb151ebf2a..15fb798ce5 100644
--- a/usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf
+++ b/usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf
@@ -22,8 +22,9 @@
#
# ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
EC_dr ESC_dr_req SUNW pcie_pci - - - /usr/lib/pci/pcidr class=$class subclass=$subclass publisher=$publisher dr_request_type=$dr_request_type dr_ap_id=$dr_ap_id
+EC_dr ESC_dr_req SUNW px_pci - - - /usr/lib/pci/pcidr class=$class subclass=$subclass publisher=$publisher dr_request_type=$dr_request_type dr_ap_id=$dr_ap_id
diff --git a/usr/src/lib/efcode/pci/Makefile.com b/usr/src/lib/efcode/pci/Makefile.com
index 759b03e7e9..9d9db0a6c0 100644
--- a/usr/src/lib/efcode/pci/Makefile.com
+++ b/usr/src/lib/efcode/pci/Makefile.com
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -29,6 +29,7 @@
OBJECTS = pci.o
LIBRARY = lfc_upa_pci.a
-SYMLINKS = lfc_pci_pci.so lfc_gptwo_pci.so
+SYMLINKS = lfc_pci_pci.so lfc_gptwo_pci.so lfc_pciex_pciex.so \
+ lfc_pciex_pci.so lfc_pci_pciex.so
include ../../Makefile.efcode
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc
index 352dd57adc..731701cf21 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc
@@ -167,9 +167,10 @@ f none kernel/misc/sparcv9/kcf 755 root sys
f none kernel/misc/sparcv9/krtld 755 root sys
f none kernel/misc/sparcv9/mac 755 root sys
l none kernel/misc/sparcv9/md5=../../../kernel/crypto/sparcv9/md5
-f none kernel/misc/sparcv9/pcicfg 755 root sys
f none kernel/misc/sparcv9/pcie 755 root sys
f none kernel/misc/sparcv9/pcihp 755 root sys
+f none kernel/misc/sparcv9/pciehpc 755 root sys
+f none kernel/misc/sparcv9/pcishpc 755 root sys
f none kernel/misc/sparcv9/pcmcia 755 root sys
f none kernel/misc/sparcv9/rpcsec 755 root sys
f none kernel/misc/sparcv9/scsi 755 root sys
diff --git a/usr/src/pkgdefs/SUNWefc.u/prototype_com b/usr/src/pkgdefs/SUNWefc.u/prototype_com
index 6a7e03e59c..b7fef18ce7 100644
--- a/usr/src/pkgdefs/SUNWefc.u/prototype_com
+++ b/usr/src/pkgdefs/SUNWefc.u/prototype_com
@@ -22,7 +22,7 @@
#
#pragma ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2000-2001,2003 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This required package information file contains a list of package contents.
@@ -46,52 +46,20 @@ i depend
#
# SUNWefc.u
#
+d none kernel 755 root sys
+d none kernel/drv 755 root sys
+f none kernel/drv/fcode.conf 644 root sys
+d none kernel/drv/sparcv9 755 root sys
+f none kernel/drv/sparcv9/fcode 755 root sys
+d none kernel/misc 755 root sys
+d none kernel/misc/sparcv9 755 root sys
+f none kernel/misc/sparcv9/fcodem 755 root sys
+f none kernel/misc/sparcv9/fcpci 755 root sys
+f none kernel/misc/sparcv9/pcicfg.e 755 root sys
d none platform 755 root sys
d none platform/sun4u 755 root sys
d none platform/sun4u/kernel 755 root sys
-d none platform/sun4u/kernel/drv 755 root sys
-f none platform/sun4u/kernel/drv/fcode.conf 644 root sys
-d none platform/sun4u/kernel/drv/sparcv9 755 root sys
-f none platform/sun4u/kernel/drv/sparcv9/fcode 755 root sys
d none platform/sun4u/kernel/misc 755 root sys
d none platform/sun4u/kernel/misc/sparcv9 755 root sys
-f none platform/sun4u/kernel/misc/sparcv9/fcodem 755 root sys
-f none platform/sun4u/kernel/misc/sparcv9/fcpci 755 root sys
-f none platform/sun4u/kernel/misc/sparcv9/pcicfg.e 755 root sys
f none platform/sun4u/kernel/misc/sparcv9/gptwocfg 755 root sys
f none platform/sun4u/kernel/misc/sparcv9/gptwo_cpu 755 root sys
-d none platform/SUNW,Sun-Fire 755 root sys
-d none platform/SUNW,Sun-Fire/kernel 755 root sys
-d none platform/SUNW,Sun-Fire/kernel/misc 755 root sys
-d none platform/SUNW,Sun-Fire/kernel/misc/sparcv9 755 root sys
-s none platform/SUNW,Sun-Fire/kernel/misc/sparcv9/pcicfg=../../../../sun4u/kernel/misc/sparcv9/pcicfg.e
-d none platform/SUNW,Sun-Fire-880 755 root sys
-d none platform/SUNW,Sun-Fire-880/kernel 755 root sys
-d none platform/SUNW,Sun-Fire-880/kernel/misc 755 root sys
-d none platform/SUNW,Sun-Fire-880/kernel/misc/sparcv9 755 root sys
-s none platform/SUNW,Sun-Fire-880/kernel/misc/sparcv9/pcicfg=../../../../sun4u/kernel/misc/sparcv9/pcicfg.e
-d none platform/SUNW,Sun-Fire-15000 755 root sys
-d none platform/SUNW,Sun-Fire-15000/kernel 755 root sys
-d none platform/SUNW,Sun-Fire-15000/kernel/misc 755 root sys
-d none platform/SUNW,Sun-Fire-15000/kernel/misc/sparcv9 755 root sys
-s none platform/SUNW,Sun-Fire-15000/kernel/misc/sparcv9/pcicfg=../../../../sun4u/kernel/misc/sparcv9/pcicfg.e
-d none platform/SUNW,UltraSPARC-IIi-Netract 755 root sys
-d none platform/SUNW,UltraSPARC-IIi-Netract/kernel 755 root sys
-d none platform/SUNW,UltraSPARC-IIi-Netract/kernel/misc 755 root sys
-d none platform/SUNW,UltraSPARC-IIi-Netract/kernel/misc/sparcv9 755 root sys
-s none platform/SUNW,UltraSPARC-IIi-Netract/kernel/misc/sparcv9/pcicfg=../../../../sun4u/kernel/misc/sparcv9/pcicfg.e
-d none platform/SUNW,Netra-T12 755 root sys
-d none platform/SUNW,Netra-T12/kernel 755 root sys
-d none platform/SUNW,Netra-T12/kernel/misc 755 root sys
-d none platform/SUNW,Netra-T12/kernel/misc/sparcv9 755 root sys
-s none platform/SUNW,Netra-T12/kernel/misc/sparcv9/pcicfg=../../../../sun4u/kernel/misc/sparcv9/pcicfg.e
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-40 755 root sys
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-40/kernel 755 root sys
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-40/kernel/misc 755 root sys
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-40/kernel/misc/sparcv9 755 root sys
-s none platform/SUNW,UltraSPARC-IIe-NetraCT-40/kernel/misc/sparcv9/pcicfg=../../../../sun4u/kernel/misc/sparcv9/pcicfg.e
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-60 755 root sys
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-60/kernel 755 root sys
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-60/kernel/misc 755 root sys
-d none platform/SUNW,UltraSPARC-IIe-NetraCT-60/kernel/misc/sparcv9 755 root sys
-s none platform/SUNW,UltraSPARC-IIe-NetraCT-60/kernel/misc/sparcv9/pcicfg=../../../../sun4u/kernel/misc/sparcv9/pcicfg.e
diff --git a/usr/src/pkgdefs/SUNWefcl/prototype_sparc b/usr/src/pkgdefs/SUNWefcl/prototype_sparc
index 0dca26522c..a20f5ac105 100644
--- a/usr/src/pkgdefs/SUNWefcl/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWefcl/prototype_sparc
@@ -22,7 +22,7 @@
#
# ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This required package information file contains a list of package contents.
@@ -64,3 +64,6 @@ f none usr/lib/efcode/sparcv9/lfc_upa_pci.so 755 root bin
f none usr/lib/efcode/sparcv9/lfc_gptwo.so 755 root bin
s none usr/lib/efcode/sparcv9/lfc_gptwo_gptwo.so=lfc_gptwo.so
s none usr/lib/efcode/sparcv9/lfc_gptwo_pci.so=lfc_upa_pci.so
+s none usr/lib/efcode/sparcv9/lfc_pciex_pciex.so=lfc_upa_pci.so
+s none usr/lib/efcode/sparcv9/lfc_pciex_pci.so=lfc_upa_pci.so
+s none usr/lib/efcode/sparcv9/lfc_pci_pciex.so=lfc_upa_pci.so
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index f347dc71a7..f2d155fd25 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -684,6 +684,8 @@ PCIHPNEXUS_OBJS += pcihp.o
PCIEHPCNEXUS_OBJS += pciehpc.o
+PCISHPC_OBJS += pcishpc.o
+
PCICFG_OBJS += pcicfg.o
OPENEEPR_OBJS += openprom.o
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 2e6586e4e2..3a214afab7 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -476,6 +476,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/hotplug/pciehpc/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/hotplug/pcishpc/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/hotplug/pcihp/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1196,6 +1200,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hotplug/pcicfg/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hotplug/pciehpc/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hotplug/pcishpc/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hotplug/pcihp/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c b/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c
index 329f053017..41435779fa 100644
--- a/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c
+++ b/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c
@@ -47,6 +47,9 @@
#include <sys/callb.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#if defined(__sparc)
+#include <sys/pcie_impl.h>
+#endif
#include <sys/hotplug/pci/pciehpc_impl.h>
/*
@@ -70,6 +73,12 @@ static char *pciehpc_led_state_text(hpc_led_state_t state);
static void pciehpc_attn_btn_handler(pciehpc_t *ctrl_p);
static void pciehpc_dev_info(pciehpc_t *ctrl_p);
+static int pciehpc_pcie_dev(dev_info_t *dip, ddi_acc_handle_t handle);
+#if defined(__sparc)
+static void pciehpc_disable_errors(pciehpc_t *ctrl_p);
+static void pciehpc_enable_errors(pciehpc_t *ctrl_p);
+#endif
+
#ifdef DEBUG
int pciehpc_debug = 0;
static void pciehpc_dump_hpregs(pciehpc_t *ctrl_p);
@@ -186,6 +195,8 @@ pciehpc_init(dev_info_t *dip, pciehpc_regops_t *regops)
goto cleanup;
}
+ PCIEHPC_DISABLE_ERRORS(ctrl_p);
+
/*
* Set the platform specific hot plug mode.
*/
@@ -245,6 +256,7 @@ cleanup2:
(void) (ctrl_p->ops.uninit_hpc_hw)(ctrl_p);
cleanup1:
+ PCIEHPC_ENABLE_ERRORS(ctrl_p);
pciehpc_regs_teardown(&ctrl_p->cfghdl);
cleanup:
@@ -285,6 +297,8 @@ pciehpc_uninit(dev_info_t *dip)
/* uninitialize hpc, remove interrupt handler, etc. */
(void) (ctrl_p->ops.uninit_hpc_hw)(ctrl_p);
+ PCIEHPC_ENABLE_ERRORS(ctrl_p);
+
/* free up the HPC register mapping */
pciehpc_regs_teardown(&ctrl_p->cfghdl);
@@ -1257,6 +1271,7 @@ pciehpc_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
/* if power to the slot is still on then set Power led to ON */
if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED)
pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_ON);
+ PCIEHPC_ENABLE_ERRORS(ctrl_p);
break;
case HPC_CTRL_ENABLE_AUTOCFG:
case HPC_CTRL_DISABLE_AUTOCFG:
@@ -1270,11 +1285,16 @@ pciehpc_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
case HPC_CTRL_DEV_CONFIG_START:
case HPC_CTRL_DEV_UNCONFIG_START:
+ PCIEHPC_DISABLE_ERRORS(ctrl_p);
/* no action is needed here */
break;
case HPC_CTRL_DEV_CONFIGURED:
case HPC_CTRL_DEV_UNCONFIGURED:
/* no action is needed here */
+ if (request == HPC_CTRL_DEV_CONFIGURED) {
+ /*EMPTY*/
+ PCIEHPC_ENABLE_ERRORS(ctrl_p);
+ }
break;
default:
PCIEHPC_DEBUG((CE_WARN,
@@ -1683,6 +1703,15 @@ pciehpc_dev_info(pciehpc_t *ctrl_p)
int reglen;
dev_info_t *dip = ctrl_p->dip;
+ /*
+ * Check if it is a PCIe fabric hotplug nexus. This is specially
+ * not so for Rootcomplex nodes supporting PCIe hotplug.
+ * We save this information so as to implement hardening for
+ * fabric nodes only via pcie services.
+ */
+ if (pciehpc_pcie_dev(dip, ctrl_p->cfghdl) == DDI_SUCCESS)
+ ctrl_p->soft_state |= PCIEHPC_SOFT_STATE_PCIE_DEV;
+
/* Get the device number. */
if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
"reg", (caddr_t)&regspec, &reglen) != DDI_SUCCESS) {
@@ -1757,3 +1786,52 @@ pciehpc_set_slot_name(pciehpc_t *ctrl_p)
p->slotNum);
}
}
+
+/*ARGSUSED*/
+static int
+pciehpc_pcie_dev(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+ /* get parent device's device_type property */
+ char *device_type;
+ int rc;
+ dev_info_t *pdip = ddi_get_parent(dip);
+
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+ DDI_PROP_DONTPASS, "device_type", &device_type)
+ != DDI_PROP_SUCCESS) {
+ PCIEHPC_DEBUG2((CE_NOTE, "device_type property missing for "
+ "%s#%d", ddi_get_name(pdip), ddi_get_instance(pdip)));
+ return (DDI_FAILURE);
+ }
+
+ PCIEHPC_DEBUG((CE_NOTE, "device_type=<%s>\n", device_type));
+ rc = DDI_FAILURE;
+ if (strcmp(device_type, "pciex") == 0)
+ rc = DDI_SUCCESS;
+ ddi_prop_free(device_type);
+ return (rc);
+}
+
+#if defined(__sparc)
+static void
+pciehpc_disable_errors(pciehpc_t *ctrl_p)
+{
+ if (ctrl_p->soft_state & PCIEHPC_SOFT_STATE_PCIE_DEV) {
+ pcie_disable_errors(ctrl_p->dip, ctrl_p->cfghdl);
+ PCIEHPC_DEBUG3((CE_NOTE, "%s%d: pciehpc_disable_errors\n",
+ ddi_driver_name(ctrl_p->dip),
+ ddi_get_instance(ctrl_p->dip)));
+ }
+}
+
+static void
+pciehpc_enable_errors(pciehpc_t *ctrl_p)
+{
+ if (ctrl_p->soft_state & PCIEHPC_SOFT_STATE_PCIE_DEV) {
+ pcie_enable_errors(ctrl_p->dip, ctrl_p->cfghdl);
+ PCIEHPC_DEBUG3((CE_NOTE, "%s%d: pciehpc_enable_errors\n",
+ ddi_driver_name(ctrl_p->dip),
+ ddi_get_instance(ctrl_p->dip)));
+ }
+}
+#endif
diff --git a/usr/src/uts/common/io/hotplug/pcishpc/pcishpc.c b/usr/src/uts/common/io/hotplug/pcishpc/pcishpc.c
new file mode 100644
index 0000000000..e5a19c8cf4
--- /dev/null
+++ b/usr/src/uts/common/io/hotplug/pcishpc/pcishpc.c
@@ -0,0 +1,2379 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * PCISHPC - The Standard PCI HotPlug Controller driver module. This driver
+ * can be used with PCI HotPlug controllers that are compatible
+ * with the PCI SHPC specification 1.x.
+ */
+
+#include <sys/note.h>
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/kstat.h>
+#include <sys/debug.h>
+#include <sys/vtrace.h>
+#include <sys/modctl.h>
+#include <sys/autoconf.h>
+#include <sys/varargs.h>
+#include <sys/hwconf.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/pci.h>
+#include <sys/callb.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/ndi_impldefs.h>
+#include <sys/hotplug/pci/pcishpc.h>
+#include <sys/hotplug/hpcsvc.h>
+
+/*
+ * SHPC controller registers accessed via the SHPC DWORD select and DATA
+ * registers in PCI configuration space relative to the SHPC capibility
+ * pointer.
+ */
+#define SHPC_BASE_OFFSET_REG 0x00
+#define SHPC_SLOTS_AVAIL_I_REG 0x01
+#define SHPC_SLOTS_AVAIL_II_REG 0x02
+#define SHPC_SLOT_CONFIGURATION_REG 0x03
+#define SHPC_PROF_IF_SBCR_REG 0x04
+#define SHPC_COMMAND_STATUS_REG 0x05
+#define SHPC_IRQ_LOCATOR_REG 0x06
+#define SHPC_SERR_LOCATOR_REG 0x07
+#define SHPC_CTRL_SERR_INT_REG 0x08
+#define SHPC_LOGICAL_SLOT_REGS 0x09
+#define SHPC_VENDOR_SPECIFIC 0x28
+
+
+/* General Register bit weights for the 32-bit SHPC registers */
+#define REG_BIT0 0x00000001
+#define REG_BIT1 0x00000002
+#define REG_BIT2 0x00000004
+#define REG_BIT3 0x00000008
+#define REG_BIT4 0x00000010
+#define REG_BIT5 0x00000020
+#define REG_BIT6 0x00000040
+#define REG_BIT7 0x00000080
+#define REG_BIT8 0x00000100
+#define REG_BIT9 0x00000200
+#define REG_BIT10 0x00000400
+#define REG_BIT11 0x00000800
+#define REG_BIT12 0x00001000
+#define REG_BIT13 0x00002000
+#define REG_BIT14 0x00004000
+#define REG_BIT15 0x00008000
+#define REG_BIT16 0x00010000
+#define REG_BIT17 0x00020000
+#define REG_BIT18 0x00040000
+#define REG_BIT19 0x00080000
+#define REG_BIT20 0x00100000
+#define REG_BIT21 0x00200000
+#define REG_BIT22 0x00400000
+#define REG_BIT23 0x00800000
+#define REG_BIT24 0x01000000
+#define REG_BIT25 0x02000000
+#define REG_BIT26 0x04000000
+#define REG_BIT27 0x08000000
+#define REG_BIT28 0x10000000
+#define REG_BIT29 0x20000000
+#define REG_BIT30 0x40000000
+#define REG_BIT31 0x80000000
+
+
+/* Register bits used with the SHPC SHPC_CTRL_SERR_INT_REG register */
+#define SHPC_SERR_INT_GLOBAL_IRQ_MASK REG_BIT0
+#define SHPC_SERR_INT_GLOBAL_SERR_MASK REG_BIT1
+#define SHPC_SERR_INT_CMD_COMPLETE_MASK REG_BIT2
+#define SHPC_SERR_INT_ARBITER_SERR_MASK REG_BIT3
+#define SHPC_SERR_INT_CMD_COMPLETE_IRQ REG_BIT16
+#define SHPC_SERR_INT_ARBITER_IRQ REG_BIT17
+#define SHPC_SERR_INT_MASK_ALL (REG_BIT0|REG_BIT1|REG_BIT2|REG_BIT3)
+
+/* Register bits used with the SHPC SHPC_LOGICAL_SLOT_REGS register */
+#define SHPC_SLOT_MRL_STATE_MASK REG_BIT8
+#define SHPC_SLOT_CARD_EMPTY_MASK (REG_BIT10 | REG_BIT11)
+#define SHPC_SLOT_PRESENCE_DETECTED REG_BIT16
+#define SHPC_SLOT_ISO_PWR_DETECTED REG_BIT17
+#define SHPC_SLOT_ATTN_DETECTED REG_BIT18
+#define SHPC_SLOT_MRL_DETECTED REG_BIT19
+#define SHPC_SLOT_POWER_DETECTED REG_BIT20
+#define SHPC_SLOT_PRESENCE_MASK REG_BIT24
+#define SHPC_SLOT_ISO_PWR_MASK REG_BIT25
+#define SHPC_SLOT_ATTN_MASK REG_BIT26
+#define SHPC_SLOT_MRL_MASK REG_BIT27
+#define SHPC_SLOT_POWER_MASK REG_BIT28
+#define SHPC_SLOT_MRL_SERR_MASK REG_BIT29
+#define SHPC_SLOT_POWER_SERR_MASK REG_BIT30
+#define SHPC_SLOT_MASK_ALL (REG_BIT24|REG_BIT25|REG_BIT26|\
+ REG_BIT27|REG_BIT28|REG_BIT29|REG_BIT30)
+
+/* Register bits used with the SHPC SHPC_IRQ_LOCATOR_REG register. */
+#define SHPC_IRQ_CMD_COMPLETE REG_BIT0
+#define SHPC_IRQ_SLOT_N_PENDING REG_BIT1
+
+/* Register bits used with the SHPC SHPC_SERR_LOCATOR_REG register. */
+#define SHPC_IRQ_SERR_ARBITER_PENDING REG_BIT0
+#define SHPC_IRQ_SERR_SLOT_N_PENDING REG_BIT1
+
+/* Register bits used with the SHPC SHPC_SLOT_CONFIGURATION_REG register */
+#define SHPC_SLOT_CONFIG_MRL_SENSOR REG_BIT30
+#define SHPC_SLOT_CONFIG_ATTN_BUTTON REG_BIT31
+#define SHPC_SLOT_CONFIG_PHY_SLOT_NUM_SHIFT 16
+#define SHPC_SLOT_CONFIG_PHY_SLOT_NUM_MASK 0x3FF
+#define SHPC_SLOT_CONFIG_PHY_SLOT_NUM(reg) (((reg) >> 16) & 0x3FF)
+
+/* Max PCISHPC controller slots */
+#define MAX_SHPC_SLOTS 31
+
+/* PCISHPC controller command complete delay in microseconds. */
+#define SHPC_COMMAND_WAIT_TIME 10000
+
+/* reset delay is 2^25 clock cycles as per PCI spec @33MHz. */
+static int pcishpc_reset_delay = 0x1000000;
+
+/* PCISHPC controller softstate structure */
+typedef struct pcishpc_ctrl {
+ dev_info_t *shpc_dip; /* DIP for SHPC Nexus */
+ ddi_acc_handle_t shpc_config_hdl; /* SHPC DDI cfg handle */
+ kmutex_t shpc_intr_mutex; /* Interrupt mutex lock */
+ boolean_t interrupt_installed; /* Interrupt installed */
+ boolean_t command_complete; /* Got a cmd complete IRQ */
+ kcondvar_t cmd_comp_cv;
+ boolean_t arbiter_timeout; /* Got a Arb timeout IRQ */
+ kmutex_t shpc_mutex; /* Mutex for this SHPC */
+ char nexus_path[MAXNAMELEN]; /* Pathname of Nexus */
+ uint32_t shpc_bus; /* SHPC bus */
+ uint32_t shpc_dev; /* SHPC device */
+ uint32_t shpc_func; /* SHPC function */
+ uint8_t shpc_dword_select; /* SHPC register offset */
+ uint8_t shpc_dword_data_reg; /* SHPC data register */
+ uint32_t numSlots; /* # of HotPlug Slots */
+ uint32_t deviceStart; /* 1st PCI Device # */
+ uint32_t physStart; /* 1st Phys Device # */
+ uint32_t deviceIncreases; /* Device # Increases */
+ struct pcishpc *slots[MAX_SHPC_SLOTS]; /* Slot pointers */
+ boolean_t has_attn; /* Do we have attn btn? */
+ boolean_t has_mrl; /* Do we have MRL? */
+ struct pcishpc_ctrl *nextp; /* Linked list pointer */
+} pcishpc_ctrl_t;
+
+/* PCISHPC slot softstate structure */
+typedef struct pcishpc {
+ pcishpc_ctrl_t *ctrl; /* SHPC ctrl for this slot */
+ hpc_slot_info_t slot_info; /* HPS framework slot info */
+ hpc_slot_t slot_handle; /* HPS framework handle */
+ hpc_slot_ops_t *slot_ops; /* HPS framework callbacks */
+ uint32_t fault_led_state; /* Fault LED state */
+ uint32_t power_led_state; /* Power LED state */
+ uint32_t attn_led_state; /* Attn LED state */
+ uint32_t active_led_state; /* Active LED state */
+ hpc_slot_state_t slot_state; /* Slot State */
+ uint32_t deviceNum; /* PCI device num for slot */
+ uint32_t slotNum; /* SHPC slot number */
+ uint32_t phy_slot_num; /* physical slot number */
+ uint32_t slot_events; /* Slot event(s) IRQ */
+ kcondvar_t attn_btn_cv; /* ATTN button pressed intr */
+ boolean_t attn_btn_pending;
+ kthread_t *attn_btn_threadp; /* ATTN button event thread */
+ boolean_t attn_btn_thread_exit;
+ struct pcishpc *nextp; /* Linked list pointer */
+} pcishpc_t;
+/* mutex to protect the shpc_head and shpc_ctrl_head linked lists */
+static kmutex_t pcishpc_list_mutex;
+
+/* Pointer to a linked list of shpc slot softstate structures */
+static pcishpc_t *pcishpc_head = NULL;
+
+/* Pointer to a linked list of shpc controller softstate structures */
+static pcishpc_ctrl_t *pcishpc_ctrl_head = NULL;
+
+/* mutex to protect access to the controller */
+static kmutex_t pcishpc_control_mutex;
+
+/* SHPC static function prototypes */
+static pcishpc_ctrl_t *pcishpc_create_controller(dev_info_t *dip);
+static int pcishpc_destroy_controller(dev_info_t *dip);
+static pcishpc_ctrl_t *pcishpc_get_controller(dev_info_t *dip);
+static pcishpc_t *pcishpc_create_slot(pcishpc_ctrl_t *ctrl_p);
+static int pcishpc_destroy_slots(pcishpc_ctrl_t *ctrl_p);
+static pcishpc_t *pcishpc_hpc_get_slot_state(hpc_slot_t slot);
+static int pcishpc_setup_controller(pcishpc_ctrl_t *ctrl_p);
+static int pcishpc_register_slot(pcishpc_ctrl_t *ctrl_p, int slot);
+static int pcishpc_connect(caddr_t ops_arg,
+ hpc_slot_t slot_hdl, void *data,
+ uint_t flags);
+static int pcishpc_disconnect(caddr_t ops_arg,
+ hpc_slot_t slot_hdl, void *data,
+ uint_t flags);
+static int pcishpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
+ int request, caddr_t arg);
+static int pcishpc_setled(pcishpc_t *pcishpc_p, hpc_led_t led,
+ hpc_led_state_t state);
+static int pcishpc_set_power_state(pcishpc_t *pcishpc_p,
+ hpc_slot_state_t state);
+static int pcishpc_probe_controller(pcishpc_ctrl_t *pcishpc_p);
+static int pcishpc_get_pci_info(pcishpc_ctrl_t *pcishpc_p);
+static void pcishpc_get_slot_state(pcishpc_t *pcishpc_p);
+static int pcishpc_process_intr(pcishpc_ctrl_t *ctrl_p);
+static int pcishpc_enable_irqs(pcishpc_ctrl_t *ctrl_p);
+static int pcishpc_disable_irqs(pcishpc_ctrl_t *ctrl_p);
+static void pcishpc_set_soft_int(pcishpc_ctrl_t *ctrl_p);
+static int pcishpc_wait_busy(pcishpc_t *pcishpc_p);
+static int pcishpc_issue_command(pcishpc_t *pcishpc_p, uint8_t cmd_code);
+static int pcishpc_led_shpc_to_hpc(int state);
+static int pcishpc_led_hpc_to_shpc(int state);
+static int pcishpc_slot_shpc_to_hpc(int state);
+static int pcishpc_slot_hpc_to_shpc(int state);
+static char *pcishpc_textledstate(hpc_led_state_t state);
+static char *pcishpc_textslotstate(hpc_slot_state_t state);
+static char *pcishpc_textrequest(int request);
+static int pcishpc_set_slot_state(pcishpc_t *pcishpc_p);
+static void pcishpc_dump_regs(pcishpc_ctrl_t *ctrl_p);
+static void pcishpc_write_reg(pcishpc_ctrl_t *ctrl_p, int reg,
+ uint32_t data);
+static uint32_t pcishpc_read_reg(pcishpc_ctrl_t *ctrl_p, int reg);
+static void pcishpc_debug(char *fmt, ...);
+
+static void pcishpc_attn_btn_handler(pcishpc_t *pcishpc_p);
+static void pcishpc_set_slot_name(pcishpc_ctrl_t *ctrl_p, int slot);
+
+static int pcishpc_debug_enabled = 0;
+
+/* Module operations information for the kernel */
+extern struct mod_ops mod_miscops;
+static struct modlmisc modlmisc = {
+ &mod_miscops,
+ "PCI SHPC hotplug module v1.12",
+};
+
+/* Module linkage information for the kernel */
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ &modlmisc,
+ NULL
+};
+
+int
+_init(void)
+{
+ int rc;
+
+ if ((rc = mod_install(&modlinkage)) != 0) {
+ pcishpc_debug("pcishpc: install error=%d", rc);
+ return (rc);
+ }
+
+ /* Init the shpc driver list mutex. */
+ mutex_init(&pcishpc_list_mutex, NULL, MUTEX_DRIVER, NULL);
+ /* Init the shpc control mutex. */
+ mutex_init(&pcishpc_control_mutex, NULL, MUTEX_DRIVER, NULL);
+
+ pcishpc_debug("pcishpc: installed");
+ return (rc);
+}
+
+int
+_fini(void)
+{
+ pcishpc_debug("pcishpc: _fini called()");
+ /* XXX - to be fixed later */
+ return (EBUSY);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ pcishpc_debug("pcishpc: _info called()");
+ return (mod_info(&modlinkage, modinfop));
+}
+
+
+/*
+ * pcishpc_create_controller()
+ *
+ * This function allocates and creates an SHPC controller state structure
+ * and adds it to the linked list of controllers.
+ */
+static pcishpc_ctrl_t *
+pcishpc_create_controller(dev_info_t *dip)
+{
+ pcishpc_ctrl_t *ctrl_p;
+
+ pcishpc_debug("pcishpc: create controller for %s#%d",
+ ddi_driver_name(dip), ddi_get_instance(dip));
+
+ ctrl_p = kmem_zalloc(sizeof (pcishpc_ctrl_t), KM_SLEEP);
+
+ ctrl_p->interrupt_installed = B_FALSE;
+ ctrl_p->shpc_dip = dip;
+
+ (void) ddi_pathname(dip, ctrl_p->nexus_path);
+
+ /* Get the PCI BUS,DEVICE,FUNCTION for this SHPC controller. */
+ if (pcishpc_get_pci_info(ctrl_p) != DDI_SUCCESS) {
+
+ pcishpc_debug("pcishpc_create_controller() "
+ "Error: pcishpc_get_pci_info() failed");
+ kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
+ return (NULL);
+ }
+
+ if (pci_config_setup(dip, &ctrl_p->shpc_config_hdl) != DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_create_controller() "
+ "Error: Unable to map SHPC PCI Config registers");
+ kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
+ return (NULL);
+ }
+
+ /* Make sure the SHPC is listed in the PCI capibilities list. */
+ if (pcishpc_probe_controller(ctrl_p) != DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_create_controller() "
+ "Error: Unable to find SHPC controller");
+ pci_config_teardown(&ctrl_p->shpc_config_hdl);
+ kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
+ return (NULL);
+ }
+
+ /* Init the interrupt mutex */
+ mutex_init(&ctrl_p->shpc_intr_mutex, NULL, MUTEX_DRIVER,
+ (void *)PCISHPC_INTR_PRI);
+
+ /* Interrupts are now enabled. */
+ ctrl_p->interrupt_installed = B_TRUE;
+
+ /* Init the shpc controller's mutex. */
+ mutex_init(&ctrl_p->shpc_mutex, NULL, MUTEX_DRIVER, NULL);
+
+ mutex_enter(&pcishpc_list_mutex);
+
+ /* Insert new softstate into linked list of current soft states. */
+ ctrl_p->nextp = pcishpc_ctrl_head;
+ pcishpc_ctrl_head = ctrl_p;
+
+ mutex_exit(&pcishpc_list_mutex);
+
+ pcishpc_debug("pcishpc_create_controller() success");
+
+ return (ctrl_p);
+}
+
+
+/*
+ * pcishpc_probe_controller()
+ *
+ * This function probes to make sure there is indeed an SHPC controller.
+ */
+static int
+pcishpc_probe_controller(pcishpc_ctrl_t *ctrl_p)
+{
+ uint8_t cap_ptr;
+ uint8_t cap_id;
+ uint16_t status;
+
+ status = pci_config_get16(ctrl_p->shpc_config_hdl, PCI_CONF_STAT);
+ if (!(status & PCI_STAT_CAP)) {
+ return (DDI_FAILURE);
+ }
+
+ /* Get a pointer to the PCI capabilities list. */
+ cap_ptr = pci_config_get8(ctrl_p->shpc_config_hdl, PCI_BCNF_CAP_PTR);
+
+ cap_ptr &= 0xFC;
+
+ /* Walk PCI capabilities list searching for the SHPC capability. */
+ while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
+ cap_id = pci_config_get8(ctrl_p->shpc_config_hdl, cap_ptr);
+
+ pcishpc_debug("pcishpc_probe_controller() capability @ "
+ "pointer=%02x (id=%02x)", cap_ptr, cap_id);
+
+ if (cap_id == PCI_CAP_ID_PCI_HOTPLUG) {
+ /* Save the SHPC register offset. */
+ ctrl_p->shpc_dword_select = cap_ptr+2;
+ /* Save the SHPC data register. */
+ ctrl_p->shpc_dword_data_reg = cap_ptr+4;
+ break;
+ }
+
+ /* Get the pointer to the next capability. */
+ cap_ptr = pci_config_get8(ctrl_p->shpc_config_hdl,
+ cap_ptr+1);
+
+ cap_ptr &= 0xFC;
+ }
+
+ if (cap_ptr == PCI_CAP_NEXT_PTR_NULL) {
+ return (DDI_FAILURE);
+ }
+
+ pcishpc_debug("pcishpc_probe_controller() Found SHPC capibility");
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_destroy_controller()
+ *
+ * This function deallocates all of the SHPC controller resources.
+ */
+static int
+pcishpc_destroy_controller(dev_info_t *dip)
+{
+ pcishpc_ctrl_t *ctrl_p;
+ pcishpc_ctrl_t **ctrl_pp;
+
+ pcishpc_debug("pcishpc_destroy_controller() called(dip=%p)", dip);
+
+ mutex_enter(&pcishpc_list_mutex);
+
+ ctrl_pp = &pcishpc_ctrl_head;
+
+ /* Walk the linked list of softstates. */
+ while ((ctrl_p = *ctrl_pp) != NULL) {
+ if (ctrl_p->shpc_dip == dip) {
+ /*
+ * Deallocate the slot state structures for
+ * this controller.
+ */
+ (void) pcishpc_destroy_slots(ctrl_p);
+
+ *ctrl_pp = ctrl_p->nextp;
+
+ pci_config_teardown(&ctrl_p->shpc_config_hdl);
+
+ cv_destroy(&ctrl_p->cmd_comp_cv);
+
+ mutex_destroy(&ctrl_p->shpc_mutex);
+ mutex_destroy(&ctrl_p->shpc_intr_mutex);
+ kmem_free(ctrl_p, sizeof (pcishpc_ctrl_t));
+ mutex_exit(&pcishpc_list_mutex);
+
+ pcishpc_debug("pcishpc_destroy_controller() success");
+ return (DDI_SUCCESS);
+ }
+ ctrl_pp = &(ctrl_p->nextp);
+ }
+
+ mutex_exit(&pcishpc_list_mutex);
+
+ pcishpc_debug("pcishpc_destroy_controller() not found");
+
+ return (DDI_FAILURE);
+}
+
+
+/*
+ * pcishpc_intr()
+ *
+ * This is the SHPC controller interrupt handler.
+ */
+int
+pcishpc_intr(dev_info_t *dip)
+{
+ pcishpc_ctrl_t *ctrl_p = pcishpc_get_controller(dip);
+ int slot;
+ uint32_t irq_locator, irq_serr_locator, reg;
+ boolean_t slot_event = B_FALSE;
+
+ pcishpc_debug("pcishpc_intr() called");
+
+ if (ctrl_p->interrupt_installed == B_TRUE) {
+ mutex_enter(&ctrl_p->shpc_intr_mutex);
+
+ pcishpc_debug("pcishpc_intr() interrupt received");
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
+
+ if (reg & SHPC_SERR_INT_CMD_COMPLETE_IRQ) {
+ pcishpc_debug("pcishpc_intr() "
+ "SHPC_SERR_INT_CMD_COMPLETE_IRQ detected");
+ ctrl_p->command_complete = B_TRUE;
+ cv_signal(&ctrl_p->cmd_comp_cv);
+ }
+
+ if (reg & SHPC_SERR_INT_ARBITER_IRQ) {
+ pcishpc_debug("pcishpc_intr() SHPC_SERR_INT_ARBITER_IRQ"
+ " detected");
+ ctrl_p->arbiter_timeout = B_TRUE;
+ }
+
+ /* Write back the SERR INT register to acknowledge the IRQs. */
+ pcishpc_write_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG, reg);
+
+ irq_locator = pcishpc_read_reg(ctrl_p, SHPC_IRQ_LOCATOR_REG);
+
+ irq_serr_locator = pcishpc_read_reg(ctrl_p,
+ SHPC_SERR_LOCATOR_REG);
+
+ /* Check for slot events that might have occured. */
+ for (slot = 0; slot < ctrl_p->numSlots; slot++) {
+ if ((irq_locator & (SHPC_IRQ_SLOT_N_PENDING<<slot)) ||
+ (irq_serr_locator &
+ (SHPC_IRQ_SERR_SLOT_N_PENDING<<slot))) {
+ pcishpc_debug("pcishpc_intr() slot %d and "
+ "pending IRQ", slot+1);
+
+ /*
+ * Note that we will need to generate a
+ * slot event interrupt.
+ */
+ slot_event = B_TRUE;
+
+ reg = pcishpc_read_reg(ctrl_p,
+ SHPC_LOGICAL_SLOT_REGS+slot);
+
+ /* Record any pending slot interrupts/events. */
+ ctrl_p->slots[slot]->slot_events |= reg;
+
+ /* Acknoledge any slot interrupts */
+ pcishpc_write_reg(ctrl_p,
+ SHPC_LOGICAL_SLOT_REGS+slot, reg);
+ }
+ }
+
+ if (slot_event == B_TRUE) {
+ pcishpc_debug("pcishpc_intr() slot(s) have event(s)");
+ (void) pcishpc_process_intr(ctrl_p);
+ } else {
+ pcishpc_debug("pcishpc_intr() No slot event(s)");
+ }
+
+ mutex_exit(&ctrl_p->shpc_intr_mutex);
+
+ pcishpc_debug("pcishpc_intr() claimed");
+
+ return (DDI_INTR_CLAIMED);
+ }
+
+ pcishpc_debug("pcishpc_intr() unclaimed");
+
+ return (DDI_INTR_UNCLAIMED);
+}
+
+/*
+ * pcishpc_process_intr()
+ *
+ * This is the SHPC soft interrupt handler.
+ */
+static int
+pcishpc_process_intr(pcishpc_ctrl_t *ctrl_p)
+{
+ int slot;
+
+ mutex_enter(&ctrl_p->shpc_mutex);
+
+ pcishpc_debug("pcishpc_process_intr() called");
+
+ /* XXX - add event handling code here */
+ for (slot = 0; slot < ctrl_p->numSlots; slot++) {
+ if (ctrl_p->slots[slot]->slot_events &
+ SHPC_SLOT_PRESENCE_DETECTED)
+ pcishpc_debug("slot %d: SHPC_SLOT_PRESENCE_DETECTED",
+ slot+1);
+
+ if (ctrl_p->slots[slot]->slot_events &
+ SHPC_SLOT_ISO_PWR_DETECTED)
+ pcishpc_debug("slot %d: SHPC_SLOT_ISO_PWR_DETECTED",
+ slot+1);
+
+ if (ctrl_p->slots[slot]->slot_events &
+ SHPC_SLOT_ATTN_DETECTED) {
+ pcishpc_debug("slot %d: SHPC_SLOT_ATTN_DETECTED",
+ slot+1);
+ /*
+ * if ATTN button event is still pending
+ * then cancel it
+ */
+ if (ctrl_p->slots[slot]->attn_btn_pending == B_TRUE)
+ ctrl_p->slots[slot]->attn_btn_pending = B_FALSE;
+
+ /* wake up the ATTN event handler */
+ cv_signal(&ctrl_p->slots[slot]->attn_btn_cv);
+ }
+
+ if (ctrl_p->slots[slot]->slot_events & SHPC_SLOT_MRL_DETECTED)
+ pcishpc_debug("slot %d: SHPC_SLOT_MRL_DETECTED",
+ slot+1);
+
+ if (ctrl_p->slots[slot]->slot_events & SHPC_SLOT_POWER_DETECTED)
+ pcishpc_debug("slot %d: SHPC_SLOT_POWER_DETECTED",
+ slot+1);
+
+ /* Clear the events now that we've processed all of them. */
+ ctrl_p->slots[slot]->slot_events = 0;
+ }
+
+ mutex_exit(&ctrl_p->shpc_mutex);
+
+ return (DDI_INTR_CLAIMED);
+}
+
+
+/*
+ * pcishpc_get_controller()
+ *
+ * This function retrieves the hot plug SHPC controller soft state.
+ */
+static pcishpc_ctrl_t *
+pcishpc_get_controller(dev_info_t *dip)
+{
+ pcishpc_ctrl_t *ctrl_p;
+
+ pcishpc_debug("pcishpc_get_controller() called (dip=%p)", dip);
+
+ mutex_enter(&pcishpc_list_mutex);
+
+ ctrl_p = pcishpc_ctrl_head;
+
+ while (ctrl_p) {
+ if (ctrl_p->shpc_dip == dip)
+ break;
+ ctrl_p = ctrl_p->nextp;
+ }
+
+ mutex_exit(&pcishpc_list_mutex);
+
+ pcishpc_debug("pcishpc_get_controller() (ctrl_p=%llx)", ctrl_p);
+
+ return (ctrl_p);
+}
+
+
+/*
+ * pcishpc_hpc_get_slot_state()
+ *
+ * This function retrieves the hot plug SHPC soft state from the
+ * the HPS framework slot handle.
+ */
+static pcishpc_t *
+pcishpc_hpc_get_slot_state(hpc_slot_t slot)
+{
+ pcishpc_t *pcishpc_p;
+
+ pcishpc_debug("pcishpc_hpc_get_slot_state() called (hpc_slot=%x)",
+ slot);
+
+ mutex_enter(&pcishpc_list_mutex);
+
+ pcishpc_p = pcishpc_head;
+
+ while (pcishpc_p) {
+ if (pcishpc_p->slot_handle == slot) {
+ pcishpc_debug("pcishpc_hpc_get_slot_state() found "
+ "(pcishpc=%x)", pcishpc_p);
+ mutex_exit(&pcishpc_list_mutex);
+ return (pcishpc_p);
+ }
+ pcishpc_p = pcishpc_p->nextp;
+ }
+
+ mutex_exit(&pcishpc_list_mutex);
+
+ pcishpc_debug("pcishpc_hpc_get_slot_state() failed (slot=%x)", slot);
+
+ return (NULL);
+}
+
+
+/*
+ * pcishpc_get_pci_info()
+ *
+ * Read the PCI Bus, PCI Device, and PCI function for the SHPC controller.
+ */
+static int
+pcishpc_get_pci_info(pcishpc_ctrl_t *pcishpc_p)
+{
+ pci_regspec_t *regspec;
+ int reglen;
+
+ pcishpc_debug("pcishpc_get_pci_info() called");
+
+ if (ddi_getlongprop(DDI_DEV_T_NONE, pcishpc_p->shpc_dip,
+ DDI_PROP_DONTPASS, "reg", (caddr_t)&regspec, &reglen)
+ != DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_get_pci_info() failed to get regspec.");
+ return (DDI_FAILURE);
+ }
+
+ pcishpc_p->shpc_bus = PCI_REG_BUS_G(regspec[0].pci_phys_hi);
+ pcishpc_p->shpc_dev = PCI_REG_DEV_G(regspec[0].pci_phys_hi);
+ pcishpc_p->shpc_func = PCI_REG_FUNC_G(regspec[0].pci_phys_hi);
+
+ kmem_free(regspec, reglen);
+
+ pcishpc_debug("pcishpc_get_pci_info() %s%d: bus=%d, dev=%d, func=%d",
+ ddi_driver_name(pcishpc_p->shpc_dip),
+ ddi_get_instance(pcishpc_p->shpc_dip),
+ pcishpc_p->shpc_bus, pcishpc_p->shpc_dev,
+ pcishpc_p->shpc_func);
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_init()
+ *
+ * Install and configure an SHPC controller and register the HotPlug slots
+ * with the Solaris HotPlug framework. This function is usually called by
+ * a PCI bridge Nexus driver that has a built in SHPC controller.
+ */
+int
+pcishpc_init(dev_info_t *dip)
+{
+ pcishpc_ctrl_t *ctrl_p;
+ int i;
+
+ pcishpc_debug("pcishpc_init() called from %s#%d",
+ ddi_driver_name(dip), ddi_get_instance(dip));
+
+ mutex_enter(&pcishpc_control_mutex);
+
+ if (pcishpc_get_controller(dip) != NULL) {
+ pcishpc_debug("pcishpc_init() shpc instance already "
+ "initialized!");
+ mutex_exit(&pcishpc_control_mutex);
+ return (DDI_SUCCESS);
+ }
+
+ /* Initialize soft state structure for the SHPC instance. */
+ ctrl_p = pcishpc_create_controller(dip);
+
+ if (ctrl_p == NULL) {
+ pcishpc_debug("pcishpc_init() failed to create shpc softstate");
+ mutex_exit(&pcishpc_control_mutex);
+ return (DDI_FAILURE);
+ }
+
+ if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_init() failed to setup controller");
+ (void) pcishpc_destroy_controller(dip);
+ mutex_exit(&pcishpc_control_mutex);
+ return (DDI_FAILURE);
+ }
+
+#if 0
+ pcishpc_debug("%s%d: P2P bridge register dump:",
+ ddi_driver_name(dip), ddi_get_instance(dip));
+
+ for (i = 0; i < 0x100; i += 4) {
+ pcishpc_debug("SHPC Cfg reg 0x%02x: %08x", i,
+ pci_config_get32(ctrl_p->shpc_config_hdl, i));
+ }
+#endif
+
+ /* Setup each HotPlug slot on this SHPC controller. */
+ for (i = 0; i < ctrl_p->numSlots; i++) {
+ if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_init() failed to register "
+ "slot %d", i);
+ (void) pcishpc_destroy_controller(dip);
+ mutex_exit(&pcishpc_control_mutex);
+ return (DDI_FAILURE);
+ }
+ }
+
+ (void) pcishpc_enable_irqs(ctrl_p);
+
+ if (pcishpc_debug_enabled) {
+ /* Dump out the SHPC registers. */
+ pcishpc_dump_regs(ctrl_p);
+ }
+
+ mutex_exit(&pcishpc_control_mutex);
+
+ pcishpc_debug("pcishpc_init() success(dip=%p)", dip);
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_enable_irqs()
+ *
+ * Enable/unmask the different IRQ's we support from the SHPC controller.
+ */
+static int
+pcishpc_enable_irqs(pcishpc_ctrl_t *ctrl_p)
+{
+ uint32_t reg;
+ int slot;
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
+
+ /* Enable all interrupts. */
+ reg &= ~SHPC_SERR_INT_MASK_ALL;
+
+ pcishpc_write_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG, reg);
+
+ /* Unmask the interrupts for each slot. */
+ for (slot = 0; slot < ctrl_p->numSlots; slot++) {
+ ctrl_p->slots[slot]->slot_events = 0;
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot);
+
+ /* Enable/Unmask all slot interrupts. */
+ reg &= (~SHPC_SLOT_MASK_ALL);
+
+ pcishpc_write_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot, reg);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_disable_irqs()
+ *
+ * Disable/Mask the different IRQ's we support from the SHPC controller.
+ */
+static int
+pcishpc_disable_irqs(pcishpc_ctrl_t *ctrl_p)
+{
+ uint32_t reg;
+ int slot;
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
+
+ /* Mask all interrupts. */
+ reg |= SHPC_SERR_INT_MASK_ALL;
+
+ pcishpc_write_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG, reg);
+
+ /* Unmask the interrupts for each slot. */
+ for (slot = 0; slot < ctrl_p->numSlots; slot++) {
+ reg = pcishpc_read_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot);
+
+ /* Disable/Mask all slot interrupts. */
+ reg |= SHPC_SLOT_MASK_ALL;
+
+ pcishpc_write_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot, reg);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_register_slot()
+ *
+ * Create and register a slot with the Solaris HotPlug framework.
+ */
+static int
+pcishpc_register_slot(pcishpc_ctrl_t *ctrl_p, int slot)
+{
+ pcishpc_t *pcishpc_p;
+
+ pcishpc_p = pcishpc_create_slot(ctrl_p);
+
+ ctrl_p->slots[slot] = pcishpc_p;
+
+ pcishpc_p->slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
+
+ pcishpc_p->slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
+
+ pcishpc_p->slotNum = slot;
+
+ /* Setup the PCI device # for this SHPC slot. */
+ if (ctrl_p->deviceIncreases)
+ pcishpc_p->deviceNum = ctrl_p->deviceStart + pcishpc_p->slotNum;
+ else
+ pcishpc_p->deviceNum = ctrl_p->deviceStart - pcishpc_p->slotNum;
+
+ /* Setup the HPS framework slot ops callbacks for the SHPC driver. */
+ pcishpc_p->slot_ops->hpc_op_connect = pcishpc_connect;
+ pcishpc_p->slot_ops->hpc_op_disconnect = pcishpc_disconnect;
+ pcishpc_p->slot_ops->hpc_op_control = pcishpc_pci_control;
+ /* PCI HPC drivers do not support the insert/remove callbacks. */
+ pcishpc_p->slot_ops->hpc_op_insert = NULL;
+ pcishpc_p->slot_ops->hpc_op_remove = NULL;
+
+ /* Setup the HPS framework slot information. */
+ pcishpc_p->slot_info.version = HPC_SLOT_OPS_VERSION;
+ pcishpc_p->slot_info.slot_type = HPC_SLOT_TYPE_PCI;
+ /* Do not auto enable the deivce in this slot. */
+ pcishpc_p->slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
+ HPC_SLOT_CREATE_DEVLINK;
+
+ pcishpc_p->slot_info.slot.pci.device_number = pcishpc_p->deviceNum;
+ pcishpc_p->slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
+
+ /* setup thread for handling ATTN button events */
+ if (ctrl_p->has_attn) {
+ pcishpc_debug("pcishpc_register_slot: "
+ "setting up ATTN button event "
+ "handler thread for slot %d\n", slot);
+ cv_init(&pcishpc_p->attn_btn_cv, NULL, CV_DRIVER, NULL);
+ pcishpc_p->attn_btn_pending = B_FALSE;
+ pcishpc_p->attn_btn_threadp = thread_create(NULL, 0,
+ pcishpc_attn_btn_handler,
+ (void *)pcishpc_p, 0, &p0, TS_RUN, minclsyspri);
+ pcishpc_p->attn_btn_thread_exit = B_FALSE;
+ }
+
+ /* setup the slot name (used for ap-id) */
+ pcishpc_set_slot_name(ctrl_p, slot);
+
+ pcishpc_get_slot_state(pcishpc_p);
+
+ /* Register this SHPC slot with the HPS framework. */
+ if (hpc_slot_register(ctrl_p->shpc_dip, ctrl_p->nexus_path,
+ &pcishpc_p->slot_info, &pcishpc_p->slot_handle,
+ pcishpc_p->slot_ops, (caddr_t)pcishpc_p, 0) != 0) {
+
+ pcishpc_debug("pcishpc_register_slot() faled to Register "
+ "slot");
+ return (DDI_FAILURE);
+ }
+
+ pcishpc_debug("pcishpc_register_slot() success for slot %d", slot);
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_create_slot()
+ *
+ * Allocate and add a new HotPlug slot state structure to the linked list.
+ */
+static pcishpc_t *
+pcishpc_create_slot(pcishpc_ctrl_t *ctrl_p)
+{
+ pcishpc_t *pcishpc_p;
+
+ pcishpc_debug("pcishpc_create_slot() called(ctrl_p=%x)", ctrl_p);
+
+ /* Allocate a new slot structure. */
+ pcishpc_p = kmem_zalloc(sizeof (pcishpc_t), KM_SLEEP);
+
+ pcishpc_p->ctrl = ctrl_p;
+
+ mutex_enter(&pcishpc_list_mutex);
+
+ /* Insert new slot into linked list of current slots. */
+ pcishpc_p->nextp = pcishpc_head;
+ pcishpc_head = pcishpc_p;
+
+ mutex_exit(&pcishpc_list_mutex);
+
+ pcishpc_debug("pcishpc_create_slot() success");
+ return (pcishpc_p);
+}
+
+/*
+ * pcishpc_setup_controller()
+ *
+ * Get the number of HotPlug Slots, and the PCI device information
+ * for this HotPlug controller.
+ */
+static int
+pcishpc_setup_controller(pcishpc_ctrl_t *ctrl_p)
+{
+ uint32_t config;
+ dev_info_t *ppdip;
+
+ config = pcishpc_read_reg(ctrl_p, SHPC_SLOT_CONFIGURATION_REG);
+
+ /* Get the number of HotPlug slots. */
+ ctrl_p->numSlots = ((config)&31);
+
+ /* Get the first PCI device Number used. */
+ /*
+ * PCI-X I/O boat workaround.
+ * The register doesn't set up the correct value.
+ */
+ ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->shpc_dip));
+ if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
+ "vendor-id", -1) == 0x108e) &&
+ (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
+ "device-id", -1) == 0x9010))
+ ctrl_p->deviceStart = 4;
+ else
+ ctrl_p->deviceStart = ((config>>8)&31);
+
+ /* Get the first Physical device number. */
+ ctrl_p->physStart = ((config>>16)&0x7ff);
+ /* Check if the device numbers increase or decrease. */
+ ctrl_p->deviceIncreases = ((config>>29)&0x1);
+
+ ctrl_p->has_attn =
+ (config & SHPC_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE;
+ ctrl_p->has_mrl =
+ (config & SHPC_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE;
+
+ cv_init(&ctrl_p->cmd_comp_cv, NULL, CV_DRIVER, NULL);
+ ctrl_p->command_complete = B_FALSE;
+ ctrl_p->arbiter_timeout = B_FALSE;
+
+ if (ctrl_p->numSlots > MAX_SHPC_SLOTS) {
+ pcishpc_debug("pcishpc_setup_controller() too many SHPC "
+ "slots error");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_uninit()
+ * Unload the HogPlug controller driver and deallocate all resources.
+ */
+int
+pcishpc_uninit(dev_info_t *dip)
+{
+ pcishpc_ctrl_t *ctrl_p;
+
+ pcishpc_debug("pcishpc_uninit() called(dip=%p)", dip);
+
+ mutex_enter(&pcishpc_control_mutex);
+
+ ctrl_p = pcishpc_get_controller(dip);
+
+ if (!ctrl_p) {
+ pcishpc_debug("pcishpc_uninit() Unable to find softstate");
+ mutex_exit(&pcishpc_control_mutex);
+ return (DDI_FAILURE);
+ }
+
+ (void) pcishpc_destroy_controller(dip);
+
+ mutex_exit(&pcishpc_control_mutex);
+
+ pcishpc_debug("pcishpc_uninit() success(dip=%p)", dip);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_destroy_slots()
+ *
+ * Free up all of the slot resources for this controller.
+ */
+static int
+pcishpc_destroy_slots(pcishpc_ctrl_t *ctrl_p)
+{
+ pcishpc_t *pcishpc_p, *prev_pcishpc_p;
+ pcishpc_t **pcishpc_pp;
+
+ pcishpc_debug("pcishpc_destroy_slots() called(ctrl_p=%p)", ctrl_p);
+
+ pcishpc_pp = &pcishpc_head;
+ prev_pcishpc_p = NULL;
+
+ while ((pcishpc_p = *pcishpc_pp) != NULL) {
+
+ pcishpc_pp = &(pcishpc_p->nextp);
+
+ if (pcishpc_p->ctrl == ctrl_p) {
+ if (pcishpc_p->attn_btn_threadp != NULL) {
+ mutex_enter(&ctrl_p->shpc_mutex);
+ pcishpc_p->attn_btn_thread_exit = B_TRUE;
+ cv_signal(&pcishpc_p->attn_btn_cv);
+ pcishpc_debug("pcishpc_destroy_slots: "
+ "waiting for ATTN thread exit\n");
+ cv_wait(&pcishpc_p->attn_btn_cv,
+ &ctrl_p->shpc_mutex);
+ pcishpc_debug("pcishpc_destroy_slots: "
+ "ATTN thread exit\n");
+ cv_destroy(&pcishpc_p->attn_btn_cv);
+ pcishpc_p->attn_btn_threadp = NULL;
+ mutex_exit(&ctrl_p->shpc_mutex);
+ }
+
+ if (prev_pcishpc_p == NULL)
+ pcishpc_head = pcishpc_p->nextp;
+ else
+ prev_pcishpc_p->nextp = pcishpc_p->nextp;
+
+ pcishpc_debug("pcishpc_destroy_slots() (shpc_p=%p) "
+ "destroyed", pcishpc_p);
+ kmem_free(pcishpc_p, sizeof (pcishpc_t));
+ } else
+ prev_pcishpc_p = pcishpc_p;
+ }
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * pcishpc_connect()
+ *
+ * Called by Hot Plug Services to connect a slot on the bus.
+ */
+/*ARGSUSED*/
+static int
+pcishpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
+{
+ pcishpc_t *pcishpc_p;
+ uint32_t status;
+
+ pcishpc_debug("pcishpc_connect called()");
+
+ pcishpc_p = pcishpc_hpc_get_slot_state(slot_hdl);
+
+ if (!pcishpc_p) {
+ pcishpc_debug("pcishpc_connect() "
+ "Failed to find soft state for slot_hdl %x", slot_hdl);
+ return (HPC_ERR_FAILED);
+ }
+
+ mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
+
+ /* make sure the MRL sensor is closed */
+ status = pcishpc_read_reg(pcishpc_p->ctrl,
+ SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
+
+ if (status & SHPC_SLOT_MRL_STATE_MASK) {
+ pcishpc_debug("pcishpc_connect() failed: MRL open");
+ goto cleanup;
+ }
+
+ if (pcishpc_set_power_state(pcishpc_p, HPC_SLOT_CONNECTED) !=
+ DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_connect() failed: set power state");
+ goto cleanup;
+ }
+
+ mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
+
+ pcishpc_debug("pcishpc_connect() success!");
+
+ return (HPC_SUCCESS);
+
+cleanup:
+ mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
+ return (HPC_ERR_FAILED);
+}
+
+
+/*
+ * pcishpc_set_power_state()
+ *
+ * Changed a slot's power state.
+ */
+static int
+pcishpc_set_power_state(pcishpc_t *pcishpc_p, hpc_slot_state_t state)
+{
+ pcishpc_get_slot_state(pcishpc_p);
+
+ /* Check to see if the slot is already in this state. */
+ if (pcishpc_p->slot_state == state) {
+ pcishpc_debug("pcishpc_set_power_state() slot already in "
+ "this state");
+ return (DDI_SUCCESS);
+ }
+
+ if ((pcishpc_p->slot_state == HPC_SLOT_EMPTY) &&
+ ((state == HPC_SLOT_CONNECTED) ||
+ (state == HPC_SLOT_DISCONNECTED))) {
+ pcishpc_debug("pcishpc_set_power_state() slot in "
+ "empty state");
+ return (DDI_FAILURE);
+ }
+
+ /* Set the Power LED to blink. */
+ (void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_BLINK);
+
+ /* Turn all other LEDS off. */
+ (void) pcishpc_setled(pcishpc_p, HPC_FAULT_LED, HPC_LED_OFF);
+ (void) pcishpc_setled(pcishpc_p, HPC_ATTN_LED, HPC_LED_OFF);
+ (void) pcishpc_setled(pcishpc_p, HPC_ACTIVE_LED, HPC_LED_OFF);
+
+ /* Set the slot state to the new slot state. */
+ pcishpc_p->slot_state = state;
+
+ /* Update the hardweare slot state. */
+ if (pcishpc_set_slot_state(pcishpc_p) != DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_set_power_state() failed");
+ (void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_OFF);
+ pcishpc_get_slot_state(pcishpc_p);
+ return (DDI_FAILURE);
+ }
+
+ /* Turn the Power LED ON for a connected slot. */
+ if (state == HPC_SLOT_CONNECTED) {
+ (void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_ON);
+ }
+
+ /* Turn the Power LED OFF for a disconnected slot. */
+ if (state == HPC_SLOT_DISCONNECTED) {
+ (void) pcishpc_setled(pcishpc_p, HPC_POWER_LED, HPC_LED_OFF);
+ }
+
+ /* Turn all other LEDS off. */
+ (void) pcishpc_setled(pcishpc_p, HPC_FAULT_LED, HPC_LED_OFF);
+ (void) pcishpc_setled(pcishpc_p, HPC_ATTN_LED, HPC_LED_OFF);
+ (void) pcishpc_setled(pcishpc_p, HPC_ACTIVE_LED, HPC_LED_OFF);
+
+ pcishpc_debug("pcishpc_set_power_state() success!");
+
+ pcishpc_get_slot_state(pcishpc_p);
+
+ /* delay after powerON to let the device initialize itself */
+ drv_usecwait(pcishpc_reset_delay);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * pcishpc_disconnect()
+ *
+ * Called by Hot Plug Services to disconnect a slot on the bus.
+ */
+/*ARGSUSED*/
+static int
+pcishpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data,
+ uint_t flags)
+{
+ pcishpc_t *pcishpc_p;
+
+ pcishpc_debug("pcishpc_disconnect called()");
+
+ pcishpc_p = pcishpc_hpc_get_slot_state(slot_hdl);
+
+ if (!pcishpc_p) {
+ pcishpc_debug("pcishpc_disconnect() "
+ "Failed to find soft state for slot_hdl %x", slot_hdl);
+ return (HPC_ERR_FAILED);
+ }
+
+ mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
+
+ if (pcishpc_set_power_state(pcishpc_p, HPC_SLOT_DISCONNECTED)
+ != DDI_SUCCESS) {
+ pcishpc_debug("pcishpc_disconnect() failed");
+ goto cleanup;
+ }
+
+ mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
+
+ pcishpc_debug("pcishpc_disconnect() success!");
+
+ return (HPC_SUCCESS);
+
+cleanup:
+ mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
+ return (HPC_ERR_FAILED);
+}
+
+
+/*
+ * pcishpc_pci_control()
+ *
+ * Called by Hot Plug Services to perform a attachment point specific
+ * operation on a Hot Pluggable Standard PCI Slot.
+ */
+/*ARGSUSED*/
+static int
+pcishpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
+ caddr_t arg)
+{
+ hpc_slot_state_t *hpc_slot_state;
+ hpc_board_type_t *hpc_board_type;
+ hpc_led_info_t *hpc_led_info;
+ pcishpc_t *pcishpc_p;
+ int ret = HPC_SUCCESS;
+
+ pcishpc_debug("pcishpc_pci_control called(Request %s)",
+ pcishpc_textrequest(request));
+
+ pcishpc_p = pcishpc_hpc_get_slot_state(slot_hdl);
+
+ if (!pcishpc_p) {
+ pcishpc_debug("pcishpc_pci_control() Error: "
+ "Failed to find soft state for slot_hdl %x", slot_hdl);
+ return (HPC_ERR_FAILED);
+ }
+
+ mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
+
+ switch (request) {
+ case HPC_CTRL_GET_SLOT_STATE:
+ hpc_slot_state = (hpc_slot_state_t *)arg;
+ pcishpc_get_slot_state(pcishpc_p);
+ *hpc_slot_state = pcishpc_p->slot_state;
+ pcishpc_debug("pcishpc_pci_control() - "
+ "HPC_CTRL_GET_SLOT_STATE (state=%s)",
+ pcishpc_textslotstate(pcishpc_p->slot_state));
+ break;
+
+ case HPC_CTRL_GET_BOARD_TYPE:
+ hpc_board_type = (hpc_board_type_t *)arg;
+ pcishpc_debug("pcishpc_pci_control() - "
+ "HPC_CTRL_GET_BOARD_TYPE");
+ pcishpc_get_slot_state(pcishpc_p);
+ /*
+ * The HPS framework does not know what board
+ * type is plugged in.
+ */
+ if (pcishpc_p->slot_state == HPC_SLOT_EMPTY)
+ *hpc_board_type = HPC_BOARD_UNKNOWN;
+ else
+ *hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
+ break;
+
+ case HPC_CTRL_GET_LED_STATE:
+ hpc_led_info = (hpc_led_info_t *)arg;
+
+ pcishpc_get_slot_state(pcishpc_p);
+
+ switch (hpc_led_info->led) {
+ case HPC_FAULT_LED:
+ hpc_led_info->state =
+ pcishpc_p->fault_led_state;
+ pcishpc_debug("pcishpc_pci_control() - "
+ "GET_LED FAULT (state=%s)",
+ pcishpc_textledstate(
+ hpc_led_info->state));
+ break;
+
+ case HPC_POWER_LED:
+ hpc_led_info->state =
+ pcishpc_p->power_led_state;
+ pcishpc_debug("pcishpc_pci_control() - "
+ "GET_LED POWER (state=%s)",
+ pcishpc_textledstate(
+ hpc_led_info->state));
+ break;
+
+ case HPC_ATTN_LED:
+ hpc_led_info->state =
+ pcishpc_p->attn_led_state;
+ pcishpc_debug("pcishpc_pci_control() - "
+ "GET_LED ATTN(state = %s)",
+ pcishpc_textledstate(
+ hpc_led_info->state));
+ break;
+
+ case HPC_ACTIVE_LED:
+ hpc_led_info->state =
+ pcishpc_p->active_led_state;
+ pcishpc_debug("pcishpc_pci_control() - "
+ "GET_LED ACTIVE(state = %s)",
+ pcishpc_textledstate(
+ hpc_led_info->state));
+ break;
+
+ default:
+ pcishpc_debug("pcishpc_pci_control() "
+ "Error: GET_LED - "
+ "Invalid LED %x",
+ hpc_led_info->led);
+ ret = HPC_ERR_NOTSUPPORTED;
+ break;
+ }
+ break;
+
+ case HPC_CTRL_SET_LED_STATE:
+ hpc_led_info = (hpc_led_info_t *)arg;
+ (void) pcishpc_setled(pcishpc_p, hpc_led_info->led,
+ hpc_led_info->state);
+ break;
+
+ case HPC_CTRL_DEV_UNCONFIG_FAILURE:
+ case HPC_CTRL_DEV_CONFIG_FAILURE:
+ pcishpc_debug("pcishpc_pci_control() Config/Unconfig "
+ "failed.");
+ (void) pcishpc_setled(pcishpc_p, HPC_ATTN_LED,
+ HPC_LED_BLINK);
+ break;
+
+ case HPC_CTRL_ENABLE_AUTOCFG:
+ case HPC_CTRL_DISABLE_AUTOCFG:
+ case HPC_CTRL_DISABLE_SLOT:
+ case HPC_CTRL_DEV_UNCONFIGURED:
+ case HPC_CTRL_ENABLE_SLOT:
+ case HPC_CTRL_DISABLE_ENUM:
+ case HPC_CTRL_DEV_UNCONFIG_START:
+ case HPC_CTRL_DEV_CONFIG_START:
+ case HPC_CTRL_DEV_CONFIGURED:
+ pcishpc_debug("pcishpc_pci_control() - %s",
+ pcishpc_textrequest(request));
+ break;
+
+ case HPC_CTRL_ENABLE_ENUM:
+ default:
+ pcishpc_debug("pcishpc_pci_control() - Error: "
+ "request (%d) NOT SUPPORTED", request);
+ ret = HPC_ERR_NOTSUPPORTED;
+ break;
+ }
+
+ mutex_exit(&pcishpc_p->ctrl->shpc_mutex);
+ return (ret);
+}
+
+
+/*
+ * pcishpc_setled()
+ *
+ * Change the state of a slot's LED.
+ */
+static int
+pcishpc_setled(pcishpc_t *pcishpc_p, hpc_led_t led, hpc_led_state_t state)
+{
+ switch (led) {
+ case HPC_FAULT_LED:
+ pcishpc_debug("pcishpc_setled() - HPC_FAULT_LED "
+ "(set %s)", pcishpc_textledstate(state));
+ pcishpc_p->fault_led_state = state;
+ break;
+
+ case HPC_POWER_LED:
+ pcishpc_debug("pcishpc_setled() - HPC_POWER_LED "
+ "(set %s)", pcishpc_textledstate(state));
+ pcishpc_p->power_led_state = state;
+ break;
+
+ case HPC_ATTN_LED:
+ pcishpc_debug("pcishpc_setled() - HPC_ATTN_LED "
+ "(set %s)", pcishpc_textledstate(state));
+ pcishpc_p->attn_led_state = state;
+ break;
+
+ case HPC_ACTIVE_LED:
+ pcishpc_debug("pcishpc_setled() - HPC_ACTIVE_LED "
+ "(set %s)", pcishpc_textledstate(state));
+ pcishpc_p->active_led_state = state;
+ break;
+ }
+
+ return (pcishpc_set_slot_state(pcishpc_p));
+}
+
+
+/*
+ * pcishpc_set_slot_state()
+ *
+ * Updates the slot's state and leds.
+ */
+static int
+pcishpc_set_slot_state(pcishpc_t *pcishpc_p)
+{
+ uint32_t reg;
+ uint8_t cmd_code;
+ hpc_slot_state_t slot_state;
+
+ reg = pcishpc_read_reg(pcishpc_p->ctrl,
+ SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
+
+ /* Default all states to unchanged. */
+ cmd_code = 0;
+
+ /* Has the slot state changed? */
+ if ((reg & SHPC_SLOT_CARD_EMPTY_MASK) == SHPC_SLOT_CARD_EMPTY_MASK)
+ slot_state = HPC_SLOT_EMPTY;
+ else
+ slot_state = pcishpc_slot_shpc_to_hpc(reg & 3);
+ if (pcishpc_p->slot_state != slot_state) {
+ pcishpc_debug("pcishpc_set_slot_state() Slot State changed");
+ /* Set the new slot state in the Slot operation command. */
+ cmd_code |= pcishpc_slot_hpc_to_shpc(pcishpc_p->slot_state);
+ }
+
+ /* Has the Power LED state changed? */
+ if (pcishpc_p->power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) {
+ pcishpc_debug("pcishpc_set_slot_state() Power LED State "
+ "changed");
+ /* Set the new power led state in the Slot operation command. */
+ cmd_code |=
+ (pcishpc_led_hpc_to_shpc(pcishpc_p->power_led_state)
+ << 2);
+ }
+
+ /* Has the Attn LED state changed? */
+ if (pcishpc_p->attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) {
+ pcishpc_debug("pcishpc_set_slot_state() Attn LED State "
+ "changed");
+ /* Set the new attn led state in the Slot operation command. */
+ cmd_code |= (pcishpc_led_hpc_to_shpc(pcishpc_p->attn_led_state)
+ << 4);
+ }
+
+ return (pcishpc_issue_command(pcishpc_p, cmd_code));
+}
+
+
+/*
+ * pcishpc_wait_busy()
+ *
+ * Wait until the SHPC controller is not busy.
+ */
+static int
+pcishpc_wait_busy(pcishpc_t *pcishpc_p)
+{
+ uint32_t status;
+
+ /* Wait until SHPC controller is NOT busy. */
+ /*CONSTCOND*/
+ while (1) {
+ status = pcishpc_read_reg(pcishpc_p->ctrl,
+ SHPC_COMMAND_STATUS_REG);
+
+ /* Is there an MRL Sensor error? */
+ if (((status>>17) & 1)) {
+ pcishpc_debug("pcishpc_wait_busy() ERROR: MRL Sensor "
+ "error");
+ break;
+ }
+
+ /* Is there an Invalid command error? */
+ if (((status>>18) & 1)) {
+ pcishpc_debug("pcishpc_wait_busy() ERROR: Invalid "
+ "command error");
+ break;
+ }
+
+ /* Is there an Invalid Speed/Mode error? */
+ if (((status>>19) & 1)) {
+ pcishpc_debug("pcishpc_wait_busy() ERROR: Invalid "
+ "Speed/Mode error");
+ break;
+ }
+
+ /* Is the SHPC controller not BUSY? */
+ if (((status>>16)&1) == 0) {
+ /* Return Success. */
+ return (DDI_SUCCESS);
+ }
+
+ pcishpc_debug("pcishpc_wait_busy() SHPC controller busy. "
+ "Waiting");
+
+ /* Wait before polling the status register again. */
+ delay(drv_usectohz(SHPC_COMMAND_WAIT_TIME));
+ }
+
+ return (DDI_FAILURE);
+}
+
+
+/*
+ * pcishpc_issue_command()
+ *
+ * Sends a command to the SHPC controller.
+ */
+static int
+pcishpc_issue_command(pcishpc_t *pcishpc_p, uint8_t cmd_code)
+{
+ uint32_t command;
+ int retCode;
+
+ pcishpc_debug("pcishpc_issue_command() cmd_code=%02x", cmd_code);
+
+ /* Setup the slot for this command. */
+ command = ((1+pcishpc_p->slotNum)<<8) | (uint32_t)cmd_code;
+
+ mutex_enter(&pcishpc_p->ctrl->shpc_intr_mutex);
+
+ pcishpc_p->ctrl->command_complete = B_FALSE;
+
+ /* Write the command to the SHPC controller. */
+ pcishpc_write_reg(pcishpc_p->ctrl, SHPC_COMMAND_STATUS_REG, command);
+
+ while (pcishpc_p->ctrl->command_complete == B_FALSE)
+ cv_wait(&pcishpc_p->ctrl->cmd_comp_cv,
+ &pcishpc_p->ctrl->shpc_intr_mutex);
+
+ /* Wait until the SHPC controller processes the command. */
+ retCode = pcishpc_wait_busy(pcishpc_p);
+
+ /* Make sure the command completed. */
+ if (retCode == DDI_SUCCESS) {
+
+ /* Did the command fail to generate the command complete IRQ? */
+ if (pcishpc_p->ctrl->command_complete != B_TRUE) {
+ pcishpc_debug("pcishpc_issue_command() Failed on "
+ "generate cmd complete IRQ");
+ retCode = DDI_FAILURE;
+ }
+
+ }
+
+ mutex_exit(&pcishpc_p->ctrl->shpc_intr_mutex);
+
+ if (retCode == DDI_FAILURE)
+ pcishpc_debug("pcishpc_issue_command() Failed on cmd_code=%02x",
+ cmd_code);
+ else
+ pcishpc_debug("pcishpc_issue_command() Success on "
+ "cmd_code=%02x", cmd_code);
+
+ return (retCode);
+}
+
+/*
+ * pcishpc_led_shpc_to_hpc()
+ *
+ * Convert from SHPC indicator status to HPC indicator status.
+ */
+static int
+pcishpc_led_shpc_to_hpc(int state)
+{
+ switch (state) {
+ case 1: /* SHPC On bits b01 */
+ return (HPC_LED_ON);
+ case 2: /* SHPC Blink bits b10 */
+ return (HPC_LED_BLINK);
+ case 3: /* SHPC Off bits b11 */
+ return (HPC_LED_OFF);
+ }
+
+ return (HPC_LED_OFF);
+}
+
+
+/*
+ * pcishpc_led_hpc_to_shpc()
+ *
+ * Convert from HPC indicator status to SHPC indicator status.
+ */
+static int
+pcishpc_led_hpc_to_shpc(int state)
+{
+ switch (state) {
+ case HPC_LED_ON:
+ return (1); /* SHPC On bits b01 */
+ case HPC_LED_BLINK:
+ return (2); /* SHPC Blink bits b10 */
+ case HPC_LED_OFF:
+ return (3); /* SHPC Off bits b11 */
+ }
+
+ return (3); /* SHPC Off bits b11 */
+}
+
+/*
+ * pcishpc_slot_shpc_to_hpc()
+ *
+ * Convert from SHPC slot state to HPC slot state.
+ */
+static int
+pcishpc_slot_shpc_to_hpc(int state)
+{
+ switch (state) {
+ case 0: /* SHPC Reserved */
+ return (HPC_SLOT_EMPTY);
+
+ case 1: /* SHPC Powered Only */
+ return (HPC_SLOT_UNKNOWN);
+
+ case 2: /* SHPC Enabled */
+ return (HPC_SLOT_CONNECTED);
+
+ case 3: /* SHPC Disabled */
+ return (HPC_SLOT_DISCONNECTED);
+ }
+
+ /* Unknown slot state. */
+ return (HPC_SLOT_UNKNOWN);
+}
+
+
+/*
+ * pcishpc_slot_hpc_to_shpc()
+ *
+ * Convert from HPC slot state to SHPC slot state.
+ */
+static int
+pcishpc_slot_hpc_to_shpc(int state)
+{
+ switch (state) {
+ case HPC_SLOT_EMPTY:
+ return (0); /* SHPC Reserved */
+
+ case HPC_SLOT_UNKNOWN:
+ return (1); /* SHPC Powered Only */
+
+ case HPC_SLOT_CONNECTED:
+ return (2); /* SHPC Enabled */
+
+ case HPC_SLOT_DISCONNECTED:
+ return (3); /* SHPC Disabled */
+ }
+
+ /* Known slot state is reserved. */
+ return (0);
+}
+
+
+/*
+ * pcishpc_get_slot_state()
+ *
+ * Get the state of the slot.
+ */
+static void
+pcishpc_get_slot_state(pcishpc_t *pcishpc_p)
+{
+ uint32_t reg;
+
+ /* Read the logical slot register for this Slot. */
+ reg = pcishpc_read_reg(pcishpc_p->ctrl,
+ SHPC_LOGICAL_SLOT_REGS+pcishpc_p->slotNum);
+
+ /* Convert from the SHPC slot state to the HPC slot state. */
+ if ((reg & SHPC_SLOT_CARD_EMPTY_MASK) == SHPC_SLOT_CARD_EMPTY_MASK)
+ pcishpc_p->slot_state = HPC_SLOT_EMPTY;
+ else
+ pcishpc_p->slot_state = pcishpc_slot_shpc_to_hpc(reg & 3);
+
+ /* Convert from the SHPC Power LED state to the HPC Power LED state. */
+ pcishpc_p->power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3);
+
+ /* Convert from the SHPC Attn LED state to the HPC Attn LED state. */
+ pcishpc_p->attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3);
+
+ /* We don't have a fault LED so just default it to OFF. */
+ pcishpc_p->fault_led_state = HPC_LED_OFF;
+
+ /* We don't have an active LED so just default it to OFF. */
+ pcishpc_p->active_led_state = HPC_LED_OFF;
+}
+
+/*
+ * pcishpc_textledstate()
+ *
+ * Convert the led state into a text message.
+ */
+static char *
+pcishpc_textledstate(hpc_led_state_t state)
+{
+ /* Convert an HPC led state into a textual string. */
+ switch (state) {
+ case HPC_LED_OFF:
+ return ("off");
+
+ case HPC_LED_ON:
+ return ("on");
+
+ case HPC_LED_BLINK:
+ return ("blink");
+ }
+ return ("unknown");
+}
+
+/*
+ * pcishpc_textrequest()
+ *
+ * Convert the request into a text message.
+ */
+static char *
+pcishpc_textrequest(int request)
+{
+ /* Convert an HPC request into a textual string. */
+ switch (request) {
+ case HPC_CTRL_GET_LED_STATE:
+ return ("HPC_CTRL_GET_LED_STATE");
+ case HPC_CTRL_SET_LED_STATE:
+ return ("HPC_CTRL_SET_LED_STATE");
+ case HPC_CTRL_GET_SLOT_STATE:
+ return ("HPC_CTRL_GET_SLOT_STATE");
+ case HPC_CTRL_DEV_CONFIGURED:
+ return ("HPC_CTRL_DEV_CONFIGURED");
+ case HPC_CTRL_DEV_UNCONFIGURED:
+ return ("HPC_CTRL_DEV_UNCONFIGURED");
+ case HPC_CTRL_GET_BOARD_TYPE:
+ return ("HPC_CTRL_GET_BOARD_TYPE");
+ case HPC_CTRL_DISABLE_AUTOCFG:
+ return ("HPC_CTRL_DISABLE_AUTOCFG");
+ case HPC_CTRL_ENABLE_AUTOCFG:
+ return ("HPC_CTRL_ENABLE_AUTOCFG");
+ case HPC_CTRL_DISABLE_SLOT:
+ return ("HPC_CTRL_DISABLE_SLOT");
+ case HPC_CTRL_ENABLE_SLOT:
+ return ("HPC_CTRL_ENABLE_SLOT");
+ case HPC_CTRL_DISABLE_ENUM:
+ return ("HPC_CTRL_DISABLE_ENUM");
+ case HPC_CTRL_ENABLE_ENUM:
+ return ("HPC_CTRL_ENABLE_ENUM");
+ case HPC_CTRL_DEV_CONFIG_FAILURE:
+ return ("HPC_CTRL_DEV_CONFIG_FAILURE");
+ case HPC_CTRL_DEV_UNCONFIG_FAILURE:
+ return ("HPC_CTRL_DEV_UNCONFIG_FAILURE");
+ case HPC_CTRL_DEV_CONFIG_START:
+ return ("HPC_CTRL_DEV_CONFIG_START");
+ case HPC_CTRL_DEV_UNCONFIG_START:
+ return ("HPC_CTRL_DEV_UNCONFIG_START");
+ }
+ return ("Unknown");
+}
+
+/*
+ * pcishpc_textslotstate()
+ *
+ * Convert the request into a text message.
+ */
+static char *
+pcishpc_textslotstate(hpc_slot_state_t state)
+{
+ /* Convert an HPC slot state into a textual string. */
+ switch (state) {
+ case HPC_SLOT_EMPTY:
+ return ("HPC_SLOT_EMPTY");
+ case HPC_SLOT_DISCONNECTED:
+ return ("HPC_SLOT_DISCONNECTED");
+ case HPC_SLOT_CONNECTED:
+ return ("HPC_SLOT_CONNECTED");
+ case HPC_SLOT_UNKNOWN:
+ return ("HPC_SLOT_UNKNOWN");
+ }
+ return ("Unknown");
+}
+
+
+/*
+ * pcishpc_write_reg()
+ *
+ * Write to a SHPC controller register.
+ */
+static void
+pcishpc_write_reg(pcishpc_ctrl_t *ctrl_p, int reg, uint32_t data)
+{
+ /* Setup the SHPC dword select register. */
+ pci_config_put8(ctrl_p->shpc_config_hdl,
+ ctrl_p->shpc_dword_select, (uint8_t)reg);
+
+ /* Read back the SHPC dword select register and verify. */
+ if (pci_config_get8(ctrl_p->shpc_config_hdl,
+ ctrl_p->shpc_dword_select) != (uint8_t)reg) {
+ pcishpc_debug("pcishpc_write_reg() - Failed writing "
+ "DWORD select reg");
+ return;
+ }
+
+ /* Write to the SHPC dword data register. */
+ pci_config_put32(ctrl_p->shpc_config_hdl,
+ ctrl_p->shpc_dword_data_reg, data);
+
+ /*
+ * Issue a read of the VendorID/DeviceID just to force the previous
+ * write to complete. This is probably not necessary, but it does
+ * help enforce ordering if there is an issue.
+ */
+ (void) pci_config_get16(ctrl_p->shpc_config_hdl, PCI_CONF_VENID);
+}
+
+
+/*
+ * pcishpc_read_reg()
+ *
+ * Read from a SHPC controller register.
+ */
+static uint32_t
+pcishpc_read_reg(pcishpc_ctrl_t *ctrl_p, int reg)
+{
+ /* Setup the SHPC dword select register. */
+ pci_config_put8(ctrl_p->shpc_config_hdl,
+ ctrl_p->shpc_dword_select, (uint8_t)reg);
+
+ /* Read back the SHPC dword select register and verify. */
+ if (pci_config_get8(ctrl_p->shpc_config_hdl,
+ ctrl_p->shpc_dword_select) != (uint8_t)reg) {
+ pcishpc_debug("pcishpc_read_reg() - Failed writing DWORD "
+ "select reg");
+ return (0xFFFFFFFF);
+ }
+
+ /* Read from the SHPC dword data register. */
+ return (pci_config_get32(ctrl_p->shpc_config_hdl,
+ ctrl_p->shpc_dword_data_reg));
+}
+
+
+/*
+ * pcishpc_debug()
+ *
+ * Controls debug output if enabled.
+ */
+static void
+pcishpc_debug(char *fmt, ...)
+{
+ va_list ap;
+
+ if (pcishpc_debug_enabled) {
+ va_start(ap, fmt);
+ vcmn_err(CE_WARN, fmt, ap);
+ va_end(ap);
+ }
+}
+
+
+/*
+ * pcishpc_dump_regs()
+ *
+ * Dumps all of the SHPC controller registers.
+ */
+static void
+pcishpc_dump_regs(pcishpc_ctrl_t *ctrl_p)
+{
+ int slot, numSlots;
+ uint32_t reg;
+ char *state;
+
+ cmn_err(CE_WARN, "pcishpc_dump_regs() called:");
+ cmn_err(CE_WARN, "================================================"
+ "==========");
+
+ cmn_err(CE_WARN, "SHPC Base Offset "
+ ": 0x%08x", pcishpc_read_reg(ctrl_p, SHPC_BASE_OFFSET_REG));
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_SLOTS_AVAIL_I_REG);
+
+ cmn_err(CE_WARN, "Number of PCIX slots avail (33 Mhz) : %d",
+ (reg & 31));
+
+ cmn_err(CE_WARN, "Number of PCIX slots avail (66 Mhz) : %d",
+ ((reg>>8) & 31));
+
+ cmn_err(CE_WARN, "Number of PCIX slots avail (100 Mhz) : %d",
+ ((reg>>16) & 31));
+
+ cmn_err(CE_WARN, "Number of PCIX slots avail (133 Mhz) : %d",
+ ((reg>>24) & 31));
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_SLOTS_AVAIL_II_REG);
+
+ cmn_err(CE_WARN, "Number of conventional PCI slots (66 Mhz) : %d",
+ (reg & 31));
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_SLOT_CONFIGURATION_REG);
+
+ numSlots = (reg & 31);
+
+ cmn_err(CE_WARN, "Number of Slots connected to this port : %d",
+ numSlots);
+
+ cmn_err(CE_WARN, "PCI Device # for First HotPlug Slot : %d",
+ ((reg>>8) & 31));
+
+ cmn_err(CE_WARN, "Physical Slot # for First PCI Device # : %d",
+ ((reg>>16) & 0x7ff));
+
+ cmn_err(CE_WARN, "Physical Slot Number Up/Down "
+ ": %d", ((reg>>29) & 0x1));
+
+ cmn_err(CE_WARN, "MRL Sensor Implemented "
+ ": %s", (reg & SHPC_SLOT_CONFIG_MRL_SENSOR) ? "Yes" :
+ "No");
+
+ cmn_err(CE_WARN, "Attention Button Implemented "
+ ": %s", (reg & SHPC_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" :
+ "No");
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_PROF_IF_SBCR_REG);
+
+ switch (reg & 7) {
+ case 0:
+ state = "33Mhz Conventional PCI";
+ break;
+ case 1:
+ state = "66Mhz Conventional PCI";
+ break;
+ case 2:
+ state = "66Mhz PCI-X";
+ break;
+ case 3:
+ state = "100Mhz PCI-X";
+ break;
+ case 4:
+ state = "133Mhz PCI-X";
+ break;
+ default:
+ state = "Reserved (Error)";
+ break;
+ }
+
+ cmn_err(CE_WARN, "Current Port Operation Mode "
+ ": %s", state);
+
+ cmn_err(CE_WARN, "SHPC Interrupt Message Number "
+ ": %d", ((reg>>16) &31));
+
+ cmn_err(CE_WARN, "SHPC Programming Interface "
+ ": %d", ((reg>>24) & 0xff));
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_COMMAND_STATUS_REG);
+
+ cmn_err(CE_WARN, "SHPC Command Code "
+ ": %d", (reg & 0xff));
+
+ cmn_err(CE_WARN, "SHPC Target Slot "
+ ": %d", ((reg>>8) & 31));
+
+ cmn_err(CE_WARN, "SHPC Controller Busy "
+ ": %s", ((reg>>16) & 1) ? "Yes" : "No");
+
+ cmn_err(CE_WARN, "SHPC Controller Err: MRL Sensor "
+ ": %s", ((reg>>17) & 1) ? "Yes" : "No");
+
+ cmn_err(CE_WARN, "SHPC Controller Err: Invalid Command : %s",
+ ((reg>>18) & 1) ? "Yes" : "No");
+
+ cmn_err(CE_WARN, "SHPC Controller Err: Invalid Speed/Mode : %s",
+ ((reg>>19) & 1) ? "Yes" : "No");
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_IRQ_LOCATOR_REG);
+
+ cmn_err(CE_WARN, "Command Completion Interrupt Pending : %s",
+ (reg & SHPC_IRQ_CMD_COMPLETE) ? "Yes" : "No");
+
+ for (slot = 0; slot < numSlots; slot++) {
+ cmn_err(CE_WARN, "Slot %d Interrupt Pending "
+ ": %s", slot+1,
+ (reg & (SHPC_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
+ }
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_SERR_LOCATOR_REG);
+
+ cmn_err(CE_WARN, "Arbiter SERR Pending "
+ ": %s", (reg & SHPC_IRQ_SERR_ARBITER_PENDING) ?
+ "Yes" : "No");
+
+ for (slot = 0; slot < numSlots; slot++) {
+ cmn_err(CE_WARN, "Slot %d SERR Pending "
+ ": %s", slot+1, (reg &
+ (SHPC_IRQ_SERR_SLOT_N_PENDING<<slot)) ?
+ "Yes" : "No");
+ }
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_CTRL_SERR_INT_REG);
+
+ cmn_err(CE_WARN, "Global Interrupt Mask "
+ ": %s", (reg & SHPC_SERR_INT_GLOBAL_IRQ_MASK) ?
+ "Yes" : "No");
+
+ cmn_err(CE_WARN, "Global SERR Mask "
+ ": %s", (reg & SHPC_SERR_INT_GLOBAL_SERR_MASK) ?
+ "Yes" : "No");
+
+ cmn_err(CE_WARN, "Command Completion Interrupt Mask "
+ ": %s", (reg & SHPC_SERR_INT_CMD_COMPLETE_MASK) ?
+ "Yes" : "No");
+
+ cmn_err(CE_WARN, "Arbiter SERR Mask "
+ ": %s", (reg & SHPC_SERR_INT_ARBITER_SERR_MASK) ?
+ "Yes" : "No");
+
+ cmn_err(CE_WARN, "Command Completion Detected "
+ ": %s", (reg & SHPC_SERR_INT_CMD_COMPLETE_IRQ) ?
+ "Yes" : "No");
+
+ cmn_err(CE_WARN, "Arbiter Timeout Detected "
+ ": %s", (reg & SHPC_SERR_INT_ARBITER_IRQ) ?
+ "Yes" : "No");
+
+
+ for (slot = 0; slot < numSlots; slot++) {
+ cmn_err(CE_WARN, "Logical Slot %d Registers:", slot+1);
+ cmn_err(CE_WARN, "------------------------------------");
+
+ reg = pcishpc_read_reg(ctrl_p, SHPC_LOGICAL_SLOT_REGS+slot);
+
+ cmn_err(CE_WARN, "Slot %d state "
+ ": %s", slot+1,
+ pcishpc_textslotstate(pcishpc_slot_shpc_to_hpc(
+ (reg & 3))));
+
+ cmn_err(CE_WARN, "Slot %d Power Indicator State "
+ ": %s", slot+1,
+ pcishpc_textledstate(pcishpc_led_shpc_to_hpc(
+ (reg>>2) &3)));
+
+ cmn_err(CE_WARN, "Slot %d Attention Indicator State "
+ ": %s", slot+1,
+ pcishpc_textledstate(pcishpc_led_shpc_to_hpc(
+ (reg>>4)&3)));
+
+ cmn_err(CE_WARN, "Slot %d Power Fault "
+ ": %s", slot+1, ((reg>>6)&1) ? "Fault Detected" :
+ "No Fault");
+ cmn_err(CE_WARN, "Slot %d Attention Button "
+ ": %s", slot+1, ((reg>>7)&1) ? "Depressed" :
+ "Not Depressed");
+ cmn_err(CE_WARN, "Slot %d MRL Sensor "
+ ": %s", slot+1, ((reg>>8)&1) ? "Not Closed" :
+ "Closed");
+ cmn_err(CE_WARN, "Slot %d 66mhz Capable "
+ ": %s", slot+1, ((reg>>9)&1) ? "66mhz" : "33mgz");
+
+ switch ((reg>>10)&3) {
+ case 0:
+ state = "Card Present 7.5W";
+ break;
+ case 1:
+ state = "Card Present 15W";
+ break;
+ case 2:
+ state = "Card Present 25W";
+ break;
+ case 3:
+ state = "Slot Empty";
+ break;
+ }
+
+ cmn_err(CE_WARN, "Slot %d PRSNT1#/PRSNT2# "
+ ": %s", slot+1, state);
+
+ switch ((reg>>12)&3) {
+ case 0:
+ state = "Non PCI-X";
+ break;
+ case 1:
+ state = "66mhz PCI-X";
+ break;
+ case 2:
+ state = "Reserved";
+ break;
+ case 3:
+ state = "133mhz PCI-X";
+ break;
+ }
+
+ cmn_err(CE_WARN, "Slot %d Card Presence Change Detected : %s",
+ slot+1, (reg & SHPC_SLOT_PRESENCE_DETECTED) ? "Yes" :
+ "No");
+ cmn_err(CE_WARN, "Slot %d Isolated Power Fault Detected : %s",
+ slot+1, (reg & SHPC_SLOT_ISO_PWR_DETECTED) ? "Yes" :
+ "No");
+ cmn_err(CE_WARN, "Slot %d Attention Button Press Detected"
+ ": %s", slot+1,
+ (reg & SHPC_SLOT_ATTN_DETECTED) ? "Yes" : "No");
+ cmn_err(CE_WARN, "Slot %d MRL Sensor Change Detected "
+ ": %s", slot+1,
+ (reg & SHPC_SLOT_MRL_DETECTED) ? "Yes" : "No");
+ cmn_err(CE_WARN, "Slot %d Connected Power Fault Detected"
+ ": %s", slot+1,
+ (reg & SHPC_SLOT_POWER_DETECTED) ? "Yes" : "No");
+
+ cmn_err(CE_WARN, "Slot %d Card Presence IRQ Masked "
+ ": %s", slot+1,
+ (reg & SHPC_SLOT_PRESENCE_MASK) ? "Yes" : "No");
+ cmn_err(CE_WARN, "Slot %d Isolated Power Fault IRQ Masked"
+ ": %s", slot+1,
+ (reg & SHPC_SLOT_ISO_PWR_MASK) ? "Yes" : "No");
+ cmn_err(CE_WARN, "Slot %d Attention Button IRQ Masked "
+ ": %s", slot+1, (reg & SHPC_SLOT_ATTN_MASK) ? "Yes" :
+ "No");
+ cmn_err(CE_WARN, "Slot %d MRL Sensor IRQ Masked "
+ ": %s", slot+1,
+ (reg & SHPC_SLOT_MRL_MASK) ? "Yes" : "No");
+ cmn_err(CE_WARN, "Slot %d Connected Power Fault IRQ Masked"
+ " : %s", slot+1,
+ (reg & SHPC_SLOT_POWER_MASK) ? "Yes" : "No");
+ cmn_err(CE_WARN, "Slot %d MRL Sensor SERR Masked "
+ ": %s", slot+1,
+ (reg & SHPC_SLOT_MRL_SERR_MASK) ? "Yes" : "No");
+ cmn_err(CE_WARN, "Slot %d Connected Power Fault SERR Masked :"
+ "%s", slot+1,
+ (reg & SHPC_SLOT_POWER_SERR_MASK) ? "Yes" : "No");
+ }
+}
+
+static void
+pcishpc_attn_btn_handler(pcishpc_t *pcishpc_p)
+{
+ hpc_led_state_t power_led_state;
+ callb_cpr_t cprinfo;
+
+ pcishpc_debug("pcishpc_attn_btn_handler: thread started\n");
+
+ CALLB_CPR_INIT(&cprinfo, &pcishpc_p->ctrl->shpc_mutex,
+ callb_generic_cpr, "pcishpc_attn_btn_handler");
+
+ mutex_enter(&pcishpc_p->ctrl->shpc_mutex);
+
+ /* wait for ATTN button event */
+ cv_wait(&pcishpc_p->attn_btn_cv, &pcishpc_p->ctrl->shpc_mutex);
+
+ while (pcishpc_p->attn_btn_thread_exit == B_FALSE) {
+ if (pcishpc_p->attn_btn_pending == B_TRUE) {
+ /* get the current state of power LED */
+ power_led_state = pcishpc_p->power_led_state;
+
+ /* Blink the Power LED while we wait for 5 seconds */
+ (void) pcishpc_setled(pcishpc_p, HPC_POWER_LED,
+ HPC_LED_BLINK);
+
+ /* wait for 5 seconds before taking any action */
+ if (cv_timedwait(&pcishpc_p->attn_btn_cv,
+ &pcishpc_p->ctrl->shpc_mutex,
+ ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
+ /*
+ * It is a time out;
+ * make sure the ATTN pending flag is
+ * still ON before sending the event
+ * to HPS framework.
+ */
+ if (pcishpc_p->attn_btn_pending == B_TRUE) {
+ /*
+ * send the ATTN button event
+ * to HPS framework
+ */
+ pcishpc_p->attn_btn_pending = B_FALSE;
+ (void) hpc_slot_event_notify(
+ pcishpc_p->slot_handle,
+ HPC_EVENT_SLOT_ATTN,
+ HPC_EVENT_NORMAL);
+ }
+ }
+
+ /* restore the power LED state ??? XXX */
+ (void) pcishpc_setled(pcishpc_p, HPC_POWER_LED,
+ power_led_state);
+ continue;
+ }
+
+ /* wait for another ATTN button event */
+ cv_wait(&pcishpc_p->attn_btn_cv, &pcishpc_p->ctrl->shpc_mutex);
+ }
+
+ pcishpc_debug("pcishpc_attn_btn_handler: thread exit\n");
+ cv_signal(&pcishpc_p->attn_btn_cv);
+ CALLB_CPR_EXIT(&cprinfo);
+ thread_exit();
+}
+
+/*
+ * setup slot name/slot-number info.
+ */
+static void
+pcishpc_set_slot_name(pcishpc_ctrl_t *ctrl_p, int slot)
+{
+ pcishpc_t *p = ctrl_p->slots[slot];
+ uchar_t *slotname_data;
+ int *slotnum;
+ uint_t count;
+ int len;
+ uchar_t *s;
+ uint32_t bit_mask;
+ int pci_id_cnt, pci_id_bit;
+ int slots_before, found;
+ int invalid_slotnum = 0;
+ uint32_t config;
+
+ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->shpc_dip,
+ DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
+ DDI_PROP_SUCCESS) {
+ p->phy_slot_num = slotnum[0];
+ ddi_prop_free(slotnum);
+ } else {
+ config = pcishpc_read_reg(ctrl_p, SHPC_SLOT_CONFIGURATION_REG);
+ p->phy_slot_num = SHPC_SLOT_CONFIG_PHY_SLOT_NUM(config);
+ }
+
+ if (!p->phy_slot_num) { /* platform may not have initialized it */
+ cmn_err(CE_WARN, "%s#%d: Invalid slot number! ",
+ ddi_driver_name(ctrl_p->shpc_dip),
+ ddi_get_instance(ctrl_p->shpc_dip));
+ p->phy_slot_num = pci_config_get8(ctrl_p->shpc_config_hdl,
+ PCI_BCNF_SECBUS);
+ invalid_slotnum = 1;
+ }
+
+ /*
+ * construct the slot_name:
+ * if "slot-names" property exists then use that name
+ * else if valid slot number exists then it is "pci<slot-num>".
+ * else it will be "pci<sec-bus-number>dev<dev-number>"
+ */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->shpc_dip, DDI_PROP_DONTPASS,
+ "slot-names", (caddr_t)&slotname_data,
+ &len) == DDI_PROP_SUCCESS) {
+
+ bit_mask = slotname_data[3] | (slotname_data[2] << 8) |
+ (slotname_data[1] << 16) | (slotname_data[0] << 24);
+
+ pci_id_bit = 1;
+ pci_id_cnt = slots_before = found = 0;
+
+ /*
+ * Walk the bit mask until we find the bit that corresponds
+ * to our slots device number. We count how many bits
+ * we find before we find our slot's bit.
+ */
+ while (!found && (pci_id_cnt < 32)) {
+
+ while (p->deviceNum != pci_id_cnt) {
+
+ /*
+ * Find the next bit set.
+ */
+ while (!(bit_mask & pci_id_bit) &&
+ (pci_id_cnt < 32)) {
+ pci_id_bit = pci_id_bit << 1;
+ pci_id_cnt++;
+ }
+
+ if (p->deviceNum != pci_id_cnt)
+ slots_before++;
+ else
+ found = 1;
+ }
+ }
+
+ if (pci_id_cnt < 32) {
+
+ /*
+ * Set ptr to first string.
+ */
+ s = slotname_data + 4;
+
+ /*
+ * Increment past all the strings for the slots
+ * before ours.
+ */
+ while (slots_before) {
+ while (*s != NULL)
+ s++;
+ s++;
+ slots_before--;
+ }
+
+ (void) sprintf(p->slot_info.pci_slot_name, (char *)s);
+
+ kmem_free(slotname_data, len);
+ return;
+ }
+
+ /* slot-names entry not found */
+ pcishpc_debug("pcishpc_set_slot_name(): "
+ "No slot-names entry found for slot #%d",
+ p->phy_slot_num);
+ kmem_free(slotname_data, len);
+ }
+
+ if (invalid_slotnum)
+ (void) sprintf(p->slot_info.pci_slot_name, "pci%ddev%d",
+ p->phy_slot_num, p->deviceNum);
+ else
+ (void) sprintf(p->slot_info.pci_slot_name, "pci%d",
+ p->phy_slot_num);
+}
diff --git a/usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h b/usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h
index 6afbf1e432..e11e57109e 100644
--- a/usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h
+++ b/usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h
@@ -21,7 +21,7 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -80,6 +80,7 @@ typedef uint32_t pciehpc_soft_state_t;
#define PCIEHPC_SOFT_STATE_INIT_ENABLE 0x20
#define PCIEHPC_SOFT_STATE_INIT_BLOCK 0x40
#define PCIEHPC_SOFT_STATE_INIT_FM 0x80
+#define PCIEHPC_SOFT_STATE_PCIE_DEV 0x10000
/*
* PCI Express Hotplug controller soft state structure
@@ -210,6 +211,14 @@ extern int pciehpc_debug;
/* default interrupt priority for Hot Plug interrupts */
#define PCIEHPC_INTR_PRI 1
+#if defined(__sparc)
+#define PCIEHPC_ENABLE_ERRORS(arg) pciehpc_enable_errors(arg)
+#define PCIEHPC_DISABLE_ERRORS(arg) pciehpc_disable_errors(arg)
+#else
+#define PCIEHPC_ENABLE_ERRORS(arg)
+#define PCIEHPC_DISABLE_ERRORS(arg)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/hotplug/pci/pcishpc.h b/usr/src/uts/common/sys/hotplug/pci/pcishpc.h
new file mode 100644
index 0000000000..f8c1fab1c0
--- /dev/null
+++ b/usr/src/uts/common/sys/hotplug/pci/pcishpc.h
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_PCISHPC_H
+#define _SYS_PCISHPC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interfaces exported by SHPC Nexus extension module
+ */
+
+int pcishpc_init(dev_info_t *);
+int pcishpc_uninit(dev_info_t *);
+int pcishpc_intr(dev_info_t *);
+
+#define PCISHPC_INTR_PRI (LOCK_LEVEL - 1)
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_PCISHPC_H */
diff --git a/usr/src/uts/sparc/Makefile.files b/usr/src/uts/sparc/Makefile.files
index c582f2a42b..a831f5a4ed 100644
--- a/usr/src/uts/sparc/Makefile.files
+++ b/usr/src/uts/sparc/Makefile.files
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -68,6 +68,7 @@ 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 px_debug.o pcie_pwr.o
+FCODE_OBJS += fcode.o
#
# file system modules
@@ -90,6 +91,9 @@ KRTLD_OBJS += \
kobj_reloc.o
SWAPGENERIC_OBJS += swapgeneric.o
+PCICFG_E_OBJS += pcicfg.e.o
+FCPCI_OBJS += fcpci.o
+FCODEM_OBJS += fc_ddi.o fc_physio.o fc_ops.o fc_subr.o
#
# special files
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 5bdb8df6b2..7933df65ed 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -264,6 +264,7 @@ DRV_KMODS += sbp2
DRV_KMODS += ib ibd
DRV_KMODS += pci_pci px_pci pcie
DRV_KMODS += i8042 kb8042 mouse8042
+DRV_KMODS += fcode
$(CLOSED_BUILD)CLOSED_DRV_KMODS += audioens
$(CLOSED_BUILD)CLOSED_DRV_KMODS += audiovia823x
@@ -352,7 +353,7 @@ MISC_KMODS += kmech_krb5
MISC_KMODS += fssnap_if
MISC_KMODS += hidparser kbtrans usba usba10 usbs49_fw
MISC_KMODS += s1394
-MISC_KMODS += hpcsvc pcicfg pcihp
+MISC_KMODS += hpcsvc pcihp pciehpc pcishpc
MISC_KMODS += rsmops
MISC_KMODS += kcf
MISC_KMODS += ibcm
@@ -364,6 +365,7 @@ MISC_KMODS += zmod
MISC_KMODS += mac dls
MISC_KMODS += cmlb
MISC_KMODS += tem
+MISC_KMODS += pcicfg.e fcodem fcpci
$(CLOSED_BUILD)CLOSED_MISC_KMODS += amsrc1
$(CLOSED_BUILD)CLOSED_MISC_KMODS += klmmod klmops
diff --git a/usr/src/uts/sun4u/fcode/Makefile b/usr/src/uts/sparc/fcode/Makefile
index 3e980a4cae..5f5eac7595 100644
--- a/usr/src/uts/sun4u/fcode/Makefile
+++ b/usr/src/uts/sparc/fcode/Makefile
@@ -20,15 +20,16 @@
# CDDL HEADER END
#
#
-# uts/sun4u/fcode/Makefile
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# uts/sparc/fcode/Makefile
+#
+# Copyright 2006 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 ebus driver kernel module
+# This makefile drives the production of the fcode driver kernel module
#
-# sun4u implementation architecture dependent
+# sparc implementation architecture dependent
#
#
@@ -42,14 +43,13 @@ UTSBASE = ../..
MODULE = fcode
OBJECTS = $(FCODE_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(FCODE_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE = $(ROOT_PSM_DRV_DIR)/$(MODULE)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
CONF_SRCDIR = $(UTSBASE)/sun4/io/efcode
-
#
# Include common rules.
#
-include $(UTSBASE)/sun4u/Makefile.sun4u
+include $(UTSBASE)/sparc/Makefile.sparc
#
# Define targets
@@ -58,6 +58,11 @@ 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
+
# Turn this on once compiler understands v9 in it's backend
#INLINES += $(UTSBASE)/sun4/io/fcode.il
@@ -95,4 +100,4 @@ install: $(INSTALL_DEPS)
#
# Include common targets.
#
-include $(UTSBASE)/sun4u/Makefile.targ
+include $(UTSBASE)/sparc/Makefile.targ
diff --git a/usr/src/uts/sun4u/fcodem/Makefile b/usr/src/uts/sparc/fcodem/Makefile
index adcdd91b6c..94141b4ba7 100644
--- a/usr/src/uts/sun4u/fcodem/Makefile
+++ b/usr/src/uts/sparc/fcodem/Makefile
@@ -20,15 +20,16 @@
# CDDL HEADER END
#
#
-# uts/sun4u/fcodem/Makefile
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# uts/sparc/fcodem/Makefile
+#
+# Copyright 2006 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 ebus driver kernel module
+# This makefile drives the production of the fcodem misc kernel module
#
-# sun4u implementation architecture dependent
+# sparc implementation architecture dependent
#
#
@@ -42,12 +43,12 @@ UTSBASE = ../..
MODULE = fcodem
OBJECTS = $(FCODEM_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(FCODEM_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
+ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
#
# Include common rules.
#
-include $(UTSBASE)/sun4u/Makefile.sun4u
+include $(UTSBASE)/sparc/Makefile.sparc
#
# Define targets
@@ -56,6 +57,11 @@ ALL_TARGET = $(BINARY)
LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+#
+# Include sun4 specific headers files
+#
+INC_PATH += -I$(UTSBASE)/sun4
+
# Turn this on once compiler understands v9 in it's backend
#INLINES += $(UTSBASE)/sun4/io/fcode.il
@@ -93,4 +99,4 @@ install: $(INSTALL_DEPS)
#
# Include common targets.
#
-include $(UTSBASE)/sun4u/Makefile.targ
+include $(UTSBASE)/sparc/Makefile.targ
diff --git a/usr/src/uts/sun4u/fcpci/Makefile b/usr/src/uts/sparc/fcpci/Makefile
index 101284b7bd..c11db6ad71 100644
--- a/usr/src/uts/sun4u/fcpci/Makefile
+++ b/usr/src/uts/sparc/fcpci/Makefile
@@ -20,17 +20,17 @@
# CDDL HEADER END
#
#
-# uts/sun4u/fcpci/Makefile
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# uts/sparc/fcpci/Makefile
+#
+# Copyright 2006 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 ebus driver kernel module
+# This makefile drives the production of the fcpci kernel misc module
#
-# sun4u implementation architecture dependent
+# sparc implementation architecture dependent
#
-
#
# Path to the base of the uts directory tree (usually /usr/src/uts).
#
@@ -42,12 +42,12 @@ UTSBASE = ../..
MODULE = fcpci
OBJECTS = $(FCPCI_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(FCPCI_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
+ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
#
# Include common rules.
#
-include $(UTSBASE)/sun4u/Makefile.sun4u
+include $(UTSBASE)/sparc/Makefile.sparc
#
# Define targets
@@ -56,6 +56,11 @@ ALL_TARGET = $(BINARY)
LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+#
+# Include sun4 specific headers files
+#
+INC_PATH += -I$(UTSBASE)/sun4
+
# Turn this on once compiler understands v9 in it's backend
#INLINES += $(UTSBASE)/sun4/io/fcode.il
@@ -93,4 +98,4 @@ install: $(INSTALL_DEPS)
#
# Include common targets.
#
-include $(UTSBASE)/sun4u/Makefile.targ
+include $(UTSBASE)/sparc/Makefile.targ
diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s
index 2f2bdb9508..97bff00380 100644
--- a/usr/src/uts/sparc/ml/modstubs.s
+++ b/usr/src/uts/sparc/ml/modstubs.s
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -982,13 +982,35 @@ stubs_base:
#endif
/*
- * Stubs for PCI configurator module (misc/pcicfg).
+ * Stubs for PCI configurator module (misc/pcicfg.e).
*/
-#ifndef PCICFG_MODULE
- MODULE(pcicfg,misc);
- STUB(pcicfg, pcicfg_configure, 0);
- STUB(pcicfg, pcicfg_unconfigure, 0);
- END_MODULE(pcicfg);
+#ifndef PCICFG_E_MODULE
+ MODULE(pcicfg.e,misc);
+ STUB(pcicfg.e, pcicfg_configure, 0);
+ STUB(pcicfg.e, pcicfg_unconfigure, 0);
+ END_MODULE(pcicfg.e);
+#endif
+
+/*
+ * Stubs for PCIEHPC (pci-ex hot plug support) module (misc/pciehpc).
+ */
+#ifndef PCIEHPC_MODULE
+ MODULE(pciehpc,misc);
+ STUB(pciehpc, pciehpc_init, 0);
+ STUB(pciehpc, pciehpc_uninit, 0);
+ WSTUB(pciehpc, pciehpc_intr, 0);
+ END_MODULE(pciehpc);
+#endif
+
+/*
+ * Stubs for PCISHPC (pci/pci-x shpc hot plug support) module (misc/pcishpc).
+ */
+#ifndef PCISHPC_MODULE
+ MODULE(pcishpc,misc);
+ STUB(pcishpc, pcishpc_init, 0);
+ STUB(pcishpc, pcishpc_uninit, 0);
+ WSTUB(pcishpc, pcishpc_intr, 0);
+ END_MODULE(pcishpc);
#endif
#ifndef PCIHP_MODULE
diff --git a/usr/src/uts/sun4u/pcicfg.e/Makefile b/usr/src/uts/sparc/pcicfg.e/Makefile
index c57597056a..9c48775d98 100644
--- a/usr/src/uts/sun4u/pcicfg.e/Makefile
+++ b/usr/src/uts/sparc/pcicfg.e/Makefile
@@ -20,8 +20,8 @@
# CDDL HEADER END
#
#
-# uts/sun4u/pcicfg.e/Makefile
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# uts/sparc/pcicfg.e/Makefile
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -29,7 +29,7 @@
# This makefile drives the production of the EFCode Enabled
# PCI Configurator.
#
-# sun4u implementation architecture dependent
+# sun4 implementation architecture dependent
#
#
@@ -43,12 +43,12 @@ UTSBASE = ../..
MODULE = pcicfg.e
OBJECTS = $(PCICFG_E_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(PCICFG_E_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
+ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
#
# Include common rules.
#
-include $(UTSBASE)/sun4u/Makefile.sun4u
+include $(UTSBASE)/sparc/Makefile.sparc
#
# Define targets
@@ -57,6 +57,11 @@ ALL_TARGET = $(BINARY)
LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+#
+# Include sun4 specific headers files
+#
+INC_PATH += -I$(UTSBASE)/sun4
+
# Turn this on once compiler understands v9 in it's backend
#INLINES += $(UTSBASE)/sun4u/io/pcicfg.il
@@ -73,8 +78,7 @@ CFLAGS += -dalign -DPCICFG_INTERPRET_FCODE
#
# Dependency
-LDFLAGS += -dy -Nmisc/busra -Nmisc/hpcsvc -Nmisc/fcpci -Nmisc/fcodem
-
+LDFLAGS += -dy -Nmisc/busra -Nmisc/fcpci -Nmisc/fcodem -Nmisc/pcie
#
# Default build targets.
@@ -100,4 +104,4 @@ install: $(INSTALL_DEPS)
#
# Include common targets.
#
-include $(UTSBASE)/sun4u/Makefile.targ
+include $(UTSBASE)/sparc/Makefile.targ
diff --git a/usr/src/uts/sparc/pciehpc/Makefile b/usr/src/uts/sparc/pciehpc/Makefile
new file mode 100644
index 0000000000..1f9d29c436
--- /dev/null
+++ b/usr/src/uts/sparc/pciehpc/Makefile
@@ -0,0 +1,87 @@
+#
+# 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
+#
+#
+# uts/sparc/pciehpc/Makefile
+# Copyright 2006 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 kernel/misc/pciehpc module
+# (PCIe hotplug controller module) for PCIe hotplug support in PCIe nexus
+# drivers.
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = pciehpc
+OBJECTS = $(PCIEHPCNEXUS_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(PCIEHPCNEXUS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Dependency
+LDFLAGS += -dy -Nmisc/hpcsvc -Nmisc/pcie
+
+#
+# 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/sparc/pcihp/Makefile b/usr/src/uts/sparc/pcihp/Makefile
index b410885379..8e7076c31e 100644
--- a/usr/src/uts/sparc/pcihp/Makefile
+++ b/usr/src/uts/sparc/pcihp/Makefile
@@ -21,7 +21,7 @@
#
#
# uts/sparc/pcihp/Makefile
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -71,7 +71,7 @@ CLEANFILES += $(MODSTUBS_O)
#
# Dependency
-LDFLAGS += -dy -Nmisc/busra -Nmisc/hpcsvc -Nmisc/pcicfg
+LDFLAGS += -dy -Nmisc/busra -Nmisc/hpcsvc -Nmisc/pcicfg.e
#
# Default build targets.
diff --git a/usr/src/uts/sparc/pcishpc/Makefile b/usr/src/uts/sparc/pcishpc/Makefile
new file mode 100644
index 0000000000..4052e0338f
--- /dev/null
+++ b/usr/src/uts/sparc/pcishpc/Makefile
@@ -0,0 +1,87 @@
+#
+# 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
+#
+#
+# uts/sparc/pcishpc/Makefile
+# Copyright 2006 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 kernel/misc/pcishpc module
+# (PCI SHPC hotplug controller module) for PCI hotplug support in PCI
+# nexus drivers.
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = pcishpc
+OBJECTS = $(PCISHPC_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(PCISHPC_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Dependency
+LDFLAGS += -dy -Nmisc/hpcsvc
+
+#
+# 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/sparc/px_pci/Makefile b/usr/src/uts/sparc/px_pci/Makefile
index fd148993ee..3d6b919e2f 100644
--- a/usr/src/uts/sparc/px_pci/Makefile
+++ b/usr/src/uts/sparc/px_pci/Makefile
@@ -22,7 +22,7 @@
#
# uts/sparc/px_pci/Makefile
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -75,7 +75,7 @@ CFLAGS += -dalign
#
# Dependency
#
-LDFLAGS += -dy -Nmisc/pcie
+LDFLAGS += -dy -Nmisc/pcie -Nmisc/pcishpc -Nmisc/pcihp -Nmisc/pciehpc
#
# Default build targets.
@@ -102,4 +102,3 @@ install: $(INSTALL_DEPS)
# Include common targets.
#
include $(UTSBASE)/sparc/Makefile.targ
-include $(UTSBASE)/sun4/Makefile.rules
diff --git a/usr/src/uts/sun4/Makefile.files b/usr/src/uts/sun4/Makefile.files
index 8ad679100e..2be0e9093f 100644
--- a/usr/src/uts/sun4/Makefile.files
+++ b/usr/src/uts/sun4/Makefile.files
@@ -80,9 +80,6 @@ PX_OBJS += px.o px_cb.o px_debug.o px_devctl.o px_dma.o \
FPC_OBJS += fpc.o fpc-impl.o fpc-kstats.o
VIS_OBJS += visinstr.o
TOD_OBJS += tod.o
-FCODE_OBJS += fcode.o
-FCODEM_OBJS += fc_ddi.o fc_physio.o fc_ops.o fc_subr.o
-FCPCI_OBJS += fcpci.o
EBUS_OBJS += ebus.o
SU_OBJS += su_driver.o
diff --git a/usr/src/uts/sun4u/io/pcicfg.e.c b/usr/src/uts/sun4/io/pcicfg.e.c
index 3fb3f38717..aa5fef244e 100644
--- a/usr/src/uts/sun4u/io/pcicfg.e.c
+++ b/usr/src/uts/sun4/io/pcicfg.e.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,21 +37,20 @@
#include <sys/debug.h>
#include <sys/modctl.h>
#include <sys/autoconf.h>
-
#include <sys/hwconf.h>
#include <sys/ddi_impldefs.h>
-
#include <sys/fcode.h>
-
-#include <sys/pci.h>
-
+#include <sys/pcie.h>
+#include <sys/pcie_impl.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/sunndi.h>
#include <sys/hotplug/pci/pcicfg.h>
-
#include <sys/ndi_impldefs.h>
+#define PCICFG_DEVICE_TYPE_PCI 1
+#define PCICFG_DEVICE_TYPE_PCIE 2
+
#define EFCODE21554 /* changes for supporting 21554 */
static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t);
@@ -100,6 +99,12 @@ static int pcicfg_start_devno = 0; /* for Debug only */
#define PCICFG_IO_MULT 4
#define PCICFG_RANGE_LEN 2 /* Number of range entries */
+static int pcicfg_slot_busnums = 8;
+static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
+static int pcicfg_slot_iosize = 64 * PCICFG_IOGRAN; /* 64K per slot */
+static int pcicfg_chassis_per_tree = 1;
+static int pcicfg_sec_reset_delay = 1000000;
+
/*
* The following typedef is used to represent a
* 1275 "bus-range" property of a PCI Bus node.
@@ -174,6 +179,14 @@ struct pcicfg_find_ctrl {
dev_info_t *dip;
};
+typedef struct pcicfg_err_regs {
+ uint16_t cmd;
+ uint16_t bcntl;
+ uint16_t pcie_dev;
+ uint16_t devctl;
+ int pcie_cap_off;
+} pcicfg_err_regs_t;
+
/*
* List of Indirect Config Map Devices. At least the intent of the
* design is to look for a device in this list during the configure
@@ -249,7 +262,8 @@ int pcicfg_dont_interpret = 1;
static int pcicfg_add_config_reg(dev_info_t *,
uint_t, uint_t, uint_t);
-static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t);
+static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
+ uint_t *);
#ifdef PCICFG_INTERPRET_FCODE
static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
@@ -275,10 +289,14 @@ static int pcicfg_bridge_assign(dev_info_t *, void *);
static int pcicfg_free_resources(dev_info_t *);
static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
+static void pcicfg_enable_bridge_probe_err(dev_info_t *dip,
+ ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
+static void pcicfg_disable_bridge_probe_err(dev_info_t *dip,
+ ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
static void pcicfg_device_on(ddi_acc_handle_t);
static void pcicfg_device_off(ddi_acc_handle_t);
-static int pcicfg_set_busnode_props(dev_info_t *);
+static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
static int pcicfg_free_bridge_resources(dev_info_t *);
static int pcicfg_free_device_resources(dev_info_t *);
static int pcicfg_teardown_device(dev_info_t *);
@@ -380,7 +398,7 @@ extern struct mod_ops mod_miscops;
static struct modlmisc modlmisc = {
&mod_miscops, /* Type of module */
- "PCI Config (EFCode Enabled) v%I%"
+ "PCIe/PCI Config (EFCode Enabled) v%I%"
};
static struct modlinkage modlinkage = {
@@ -539,6 +557,152 @@ struct modinfo *modinfop;
}
/*
+ * given a cap_id, return its cap_id location in config space
+ */
+static int
+pcicfg_get_cap(ddi_acc_handle_t config_handle, uint8_t cap_id)
+{
+ uint8_t curcap;
+ uint_t cap_id_loc;
+ uint16_t status;
+ int location = -1;
+
+ /*
+ * Need to check the Status register for ECP support first.
+ * Also please note that for type 1 devices, the
+ * offset could change. Should support type 1 next.
+ */
+ status = pci_config_get16(config_handle, PCI_CONF_STAT);
+ if (!(status & PCI_STAT_CAP)) {
+ return (-1);
+ }
+ cap_id_loc = pci_config_get8(config_handle, PCI_CONF_CAP_PTR);
+
+ /* Walk the list of capabilities */
+ while (cap_id_loc) {
+
+ curcap = pci_config_get8(config_handle, cap_id_loc);
+
+ if (curcap == cap_id) {
+ location = cap_id_loc;
+ break;
+ }
+ cap_id_loc = pci_config_get8(config_handle,
+ cap_id_loc + 1);
+ }
+ return (location);
+}
+
+/*ARGSUSED*/
+static uint8_t
+pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+ int cap_id_loc;
+ uint8_t num_slots = 0;
+
+ /* just depend on the pcie_cap for now. */
+ if ((cap_id_loc = pcicfg_get_cap(handle, PCI_CAP_ID_PCI_E))
+ > 0) {
+ if (pci_config_get16(handle, cap_id_loc +
+ PCIE_PCIECAP) &
+ PCIE_PCIECAP_SLOT_IMPL)
+ num_slots = 1;
+ } else /* not a PCIe switch/bridge. Must be a PCI-PCI[-X] bridge */
+ if ((cap_id_loc = pcicfg_get_cap(handle, PCI_CAP_ID_SLOT_ID))
+ > 0) {
+ uint8_t esr_reg = pci_config_get8(handle, cap_id_loc +
+ PCI_CAP_ID_REGS_OFF);
+ num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
+ }
+ /* XXX - need to cover PCI-PCIe bridge with n slots */
+ return (num_slots);
+}
+
+/*ARGSUSED*/
+static uint8_t
+pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+ int cap_id_loc;
+
+ if ((cap_id_loc = pcicfg_get_cap(handle, PCI_CAP_ID_SLOT_ID))
+ > 0) {
+ uint8_t esr_reg = pci_config_get8(handle, cap_id_loc + 2);
+ if (PCI_CAPSLOT_FIC(esr_reg))
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*ARGSUSED*/
+static int
+pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs)
+{
+ /* get parent device's device_type property */
+ char *device_type;
+ int rc = DDI_FAILURE;
+ dev_info_t *pdip = ddi_get_parent(dip);
+
+ regs->pcie_dev = 0;
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+ DDI_PROP_DONTPASS, "device_type", &device_type)
+ != DDI_PROP_SUCCESS) {
+ DEBUG2("device_type property missing for %s#%d",
+ ddi_get_name(pdip), ddi_get_instance(pdip));
+ return (DDI_FAILURE);
+ }
+ switch (bus_type) {
+ case PCICFG_DEVICE_TYPE_PCIE:
+ if (strcmp(device_type, "pciex") == 0) {
+ rc = DDI_SUCCESS;
+ regs->pcie_dev = 1;
+ }
+ break;
+ case PCICFG_DEVICE_TYPE_PCI:
+ if (strcmp(device_type, "pci") == 0)
+ rc = DDI_SUCCESS;
+ break;
+ default:
+ break;
+ }
+ ddi_prop_free(device_type);
+ return (rc);
+}
+
+/*ARGSUSED*/
+static int
+pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+ int port_type = -1;
+ int cap_loc;
+
+ if ((cap_loc = pcicfg_get_cap(handle, PCI_CAP_ID_PCI_E)) > 0)
+ port_type = pci_config_get16(handle,
+ cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
+
+ return (port_type);
+}
+
+static int
+pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
+{
+ int port_type = pcicfg_pcie_port_type(dip, handle);
+
+ DEBUG1("device port_type = %x\n", port_type);
+ /* No PCIe CAP regs, we are not PCIe device_type */
+ if (port_type < 0)
+ return (DDI_FAILURE);
+
+ /* check for all PCIe device_types */
+ if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
+ (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
+ return (DDI_SUCCESS);
+
+ return (DDI_FAILURE);
+
+}
+
+/*
* In the following functions ndi_devi_enter() without holding the
* parent dip is sufficient. This is because pci dr is driven through
* opens on the nexus which is in the device tree path above the node
@@ -597,6 +761,8 @@ pcicfg_configure(dev_info_t *devi, uint_t device)
DEBUG3("no device : bus "
"[0x%x] slot [0x%x] func [0x%x]\n",
bus, device, func);
+ if (func)
+ continue;
break;
default:
DEBUG3("configure: bus => [%d] "
@@ -632,7 +798,7 @@ cleanup:
if ((new_device = pcicfg_devi_find(devi,
device, func)) == NULL) {
DEBUG0("No more devices to clean up\n");
- break;
+ continue;
}
DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
@@ -667,6 +833,7 @@ pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
uint64_t next_bus;
uint64_t blen;
ndi_ra_request_t req;
+ uint8_t pcie_device_type = 0;
/*
* If we need to do indirect config, lets create a property here
@@ -675,15 +842,22 @@ pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
* mapped directly under the host.
*/
if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
- PCICFG_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
+ PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
!= DDI_SUCCESS) {
DEBUG0("Cannot create indirect conf map property.\n");
return ((int)PCICFG_FAILURE);
}
+ if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
+ return (PCICFG_FAILURE);
+ /* check if we are PCIe device */
+ if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS)
+ pcie_device_type = 1;
+ pci_config_teardown(&config_handle);
/* create Bus node properties for ntbridge. */
- if (pcicfg_set_busnode_props(new_device) != PCICFG_SUCCESS) {
+ if (pcicfg_set_busnode_props(new_device, pcie_device_type) !=
+ PCICFG_SUCCESS) {
DEBUG0("Failed to set busnode props\n");
return (rc);
}
@@ -1217,15 +1391,15 @@ pcicfg_indirect_map(dev_info_t *dip)
#if defined(__sparc)
int rc = DDI_FAILURE;
- if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), DDI_PROP_DONTPASS,
- PCICFG_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
+ if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
+ PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
rc = DDI_SUCCESS;
else
- if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
- DDI_PROP_DONTPASS, PCICFG_BUS_CONF_MAP_PROP,
- DDI_FAILURE) != DDI_FAILURE)
+ if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
+ 0, PCI_BUS_CONF_MAP_PROP,
+ DDI_FAILURE) != DDI_FAILURE)
rc = DDI_SUCCESS;
-
+ DEBUG1("pci conf map = %d", rc);
return (rc);
#else
return (DDI_SUCCESS);
@@ -1299,7 +1473,7 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device)
*/
for (func = 0; func < PCICFG_MAX_FUNCTION; func++) {
if ((child_dip = pcicfg_devi_find(devi, device, func)) == NULL)
- break;
+ continue;
if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
continue;
@@ -1311,12 +1485,12 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device)
DEBUG2("Device [0x%x] function [%x] is busy\n", device, func);
for (i = 0; i < func; i++) {
if ((child_dip = pcicfg_devi_find(devi, device, i))
- == NULL) {
+ == NULL) {
DEBUG0("No more devices to put back on line!!\n");
/*
* Made it through all functions
*/
- break;
+ continue;
}
if (ndi_devi_online(child_dip, NDI_CONFIG) != NDI_SUCCESS) {
DEBUG0("Failed to put back devices state\n");
@@ -1333,7 +1507,7 @@ pcicfg_unconfigure(dev_info_t *devi, uint_t device)
if ((child_dip = pcicfg_devi_find(devi,
device, func)) == NULL) {
DEBUG0("No more devices to tear down!\n");
- break;
+ continue;
}
DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
@@ -1561,17 +1735,15 @@ pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
- DEBUG1("bridge assign: assigning addresses to %s\n",
- ddi_get_name(dip));
-
- entry->error = PCICFG_SUCCESS;
+ DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
if (entry == NULL) {
DEBUG0("Failed to get entry\n");
- entry->error = PCICFG_FAILURE;
return (DDI_WALK_TERMINATE);
}
+ entry->error = PCICFG_SUCCESS;
+
if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
DEBUG0("Failed to map config space!\n");
entry->error = PCICFG_FAILURE;
@@ -1841,6 +2013,12 @@ pcicfg_device_assign(dev_info_t *dip)
reg[i].pci_phys_low = PCICFG_LOADDR(answer);
reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
+ /*
+ * currently support 32b address space
+ * assignments only.
+ */
+ reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^
+ PCI_ADDR_MEM32;
offset += 8;
break;
@@ -2345,11 +2523,22 @@ pcicfg_free_bridge_resources(dev_info_t *dip)
DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
&length) != DDI_PROP_SUCCESS) {
DEBUG0("Failed to read ranges property\n");
+ if (ddi_get_child(dip)) {
+ cmn_err(CE_WARN, "No ranges property found for %s",
+ ddi_get_name(dip));
+ /*
+ * strictly speaking, we can check for children with
+ * assigned-addresses but for now it is better to
+ * be conservative and assume that if there are child
+ * nodes, then they do consume PCI memory or IO
+ * resources, Hence return failure.
+ */
+ return (PCICFG_FAILURE);
+ }
+ length = 0;
+
+ }
-#if 0
- return (PCICFG_FAILURE);
-#endif
- } else {
for (i = 0; i < length / sizeof (pcicfg_range_t); i++) {
if (ranges[i].size_lo != 0 ||
ranges[i].size_hi != 0) {
@@ -2396,8 +2585,8 @@ pcicfg_free_bridge_resources(dev_info_t *dip)
}
}
- kmem_free(ranges, length);
- }
+ if (length)
+ kmem_free(ranges, length);
if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
@@ -2412,6 +2601,7 @@ pcicfg_free_bridge_resources(dev_info_t *dip)
if (ndi_ra_free(ddi_get_parent(dip),
(uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
+ /*EMPTY*/
DEBUG0("Failed to free a bus number\n");
}
/*
@@ -2785,16 +2975,17 @@ pcicfg_device_off(ddi_acc_handle_t config_handle)
* header of the PCI device
*/
static int
-pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
+pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
+ uint8_t pcie_dev)
{
- int ret;
+ int ret, cap_id_loc;
uint16_t val;
uint32_t wordval;
uint8_t byteval;
/* These two exists only for non-bridges */
- if ((pci_config_get8(config_handle,
- PCI_CONF_HEADER) & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) {
+ if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
+ & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
"min-grant", byteval)) != DDI_SUCCESS) {
@@ -2848,13 +3039,17 @@ pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
* present (but with no value other than its own existence) if the bit
* is set, non-existent otherwise
*/
- if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_FBBC) {
+ if ((!pcie_dev) &&
+ (pci_config_get16(config_handle, PCI_CONF_STAT) &
+ PCI_STAT_FBBC)) {
if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
"fast-back-to-back", 0)) != DDI_SUCCESS) {
return (ret);
}
}
- if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_66MHZ) {
+ if ((!pcie_dev) &&
+ (pci_config_get16(config_handle, PCI_CONF_STAT) &
+ PCI_STAT_66MHZ)) {
if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
"66mhz-capable", 0)) != DDI_SUCCESS) {
return (ret);
@@ -2909,15 +3104,38 @@ pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
return (ret);
}
}
+ if (pcie_dev && (cap_id_loc = pcicfg_get_cap(config_handle,
+ PCI_CAP_ID_PCI_E)) > 0) {
+ val = pci_config_get16(config_handle, cap_id_loc +
+ PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
+ /* if slot implemented, get physical slot number */
+ if (val) {
+ wordval = (pci_config_get32(config_handle, cap_id_loc +
+ PCIE_SLOTCAP) >>
+ PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) &
+ PCIE_SLOTCAP_PHY_SLOT_NUM_MASK;
+ if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE,
+ dip, "physical-slot#", wordval))
+ != DDI_SUCCESS) {
+ return (ret);
+ }
+ }
+ }
return (PCICFG_SUCCESS);
}
static int
-pcicfg_set_busnode_props(dev_info_t *dip)
+pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type)
{
int ret;
+ char device_type[8];
+
+ if (pcie_device_type)
+ (void) strcpy(device_type, "pciex");
+ else
+ (void) strcpy(device_type, "pci");
if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
- "device_type", "pci")) != DDI_SUCCESS) {
+ "device_type", device_type)) != DDI_SUCCESS) {
return (ret);
}
if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
@@ -2932,27 +3150,38 @@ pcicfg_set_busnode_props(dev_info_t *dip)
}
static int
-pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
+pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
+ uint8_t pcie_dev)
{
int ret;
-#ifndef _DONT_USE_1275_GENERIC_NAMES
- uint32_t wordval;
-#endif
char *name;
- char buffer[64];
- uint32_t classcode;
- char *compat[8];
+ char buffer[64], pprefix[8];
+ uint16_t classcode;
+ uint8_t revid, pif, pclass, psubclass;
+ char *compat[24];
int i;
int n;
- uint16_t sub_vid, sub_sid;
+ uint16_t sub_vid, sub_sid, vid, did;
+
+ /* set the property prefix based on the device type */
+ if (pcie_dev)
+ (void) sprintf(pprefix, "pciex");
+ else
+ (void) sprintf(pprefix, "pci");
+ sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID),
+ sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
+ vid = pci_config_get16(config_handle, PCI_CONF_VENID),
+ did = pci_config_get16(config_handle, PCI_CONF_DEVID);
+ revid = pci_config_get8(config_handle, PCI_CONF_REVID);
+ pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
+ classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
+ pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
+ psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
+
/*
* NOTE: These are for both a child and PCI-PCI bridge node
*/
-#ifndef _DONT_USE_1275_GENERIC_NAMES
- wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
- (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
-#endif
/*
* "name" property rule
@@ -2980,15 +3209,10 @@ pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
* ssid = subsystem id
*/
- sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID),
- sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
- if ((pci_config_get16(config_handle, PCI_CONF_SUBSYSID) != 0) ||
- (pci_config_get16(config_handle, PCI_CONF_SUBVENID) != 0)) {
- (void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
+ if ((sub_sid != 0) || (sub_vid != 0)) {
+ (void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid);
} else {
- (void) sprintf(buffer, "pci%x,%x",
- pci_config_get16(config_handle, PCI_CONF_VENID),
- pci_config_get16(config_handle, PCI_CONF_DEVID));
+ (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
}
/*
@@ -3000,7 +3224,7 @@ pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
#ifdef _DONT_USE_1275_GENERIC_NAMES
name = buffer;
#else
- if ((name = pcicfg_get_class_name(wordval>>8)) == NULL) {
+ if ((name = pcicfg_get_class_name(classcode)) == NULL) {
/*
* Set name to the above fabricated name
*/
@@ -3025,23 +3249,53 @@ pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle)
(void) strcpy(compat[n++], buffer);
/*
- * Add in the VendorID/DeviceID compatible name.
+ * Setup 'compatible' as per the PCI2.1 bindings document.
+ * pci[ex]VVVV,DDDD.SSSS.ssss.RR
+ * pci[ex]VVVV,DDDD.SSSS.ssss
+ * pciSSSS.ssss -> not created for PCIe as per PCIe bindings
+ * pci[ex]VVVV,DDDD.RR
+ * pci[ex]VVVV,DDDD
+ * pci[ex]class,CCSSPP
+ * pci[ex]class,CCSS
*/
- (void) sprintf(buffer, "pci%x,%x",
- pci_config_get16(config_handle, PCI_CONF_VENID),
- pci_config_get16(config_handle, PCI_CONF_DEVID));
+ /* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
+ (void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix, vid, did,
+ sub_vid, sub_sid, revid);
compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
(void) strcpy(compat[n++], buffer);
- classcode = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
- (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
+ /* pci[ex]VVVV,DDDD.SSSS.ssss */
+ (void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix, vid, did,
+ sub_vid, sub_sid);
+ compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+ (void) strcpy(compat[n++], buffer);
- /*
- * Add in the Classcode
- */
- (void) sprintf(buffer, "pciclass,%06x", classcode);
+ /* pciSSSS.ssss -> not created for PCIe as per PCIe bindings */
+ if (!pcie_dev) {
+ (void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
+ compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+ (void) strcpy(compat[n++], buffer);
+ }
+ /* pci[ex]VVVV,DDDD.RR */
+ (void) sprintf(buffer, "%s%x,%x.%x", pprefix, vid, did, revid);
+ compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+ (void) strcpy(compat[n++], buffer);
+
+ /* pci[ex]VVVV,DDDD */
+ (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
+ compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+ (void) strcpy(compat[n++], buffer);
+
+ /* pci[ex]class,CCSSPP */
+ (void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
+ pclass, psubclass, pif);
+ compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
+ (void) strcpy(compat[n++], buffer);
+
+ /* pci[ex]class,CCSS */
+ (void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
(void) strcpy(compat[n++], buffer);
@@ -3075,6 +3329,8 @@ static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
uint_t primary, uint_t secondary, uint_t subordinate)
{
+ DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
+ subordinate);
/*
* Primary bus#
*/
@@ -3151,7 +3407,7 @@ pcicfg_setup_bridge(pcicfg_phdl_t *entry,
* first Configuration access. The worst case is 33MHz, which
* is a 1 second wait.
*/
- drv_usecwait(1000000);
+ drv_usecwait(pcicfg_sec_reset_delay);
}
@@ -3211,30 +3467,80 @@ pcicfg_update_bridge(pcicfg_phdl_t *entry,
}
}
+/*ARGSUSED*/
+static void
+pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
+ pcicfg_err_regs_t *regs)
+{
+ uint16_t val;
+
+ /* disable SERR generated in the context of Master Aborts. */
+ regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM);
+ val &= ~PCI_COMM_SERR_ENABLE;
+ pci_config_put16(h, PCI_CONF_COMM, val);
+ regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL);
+ val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
+ pci_config_put16(h, PCI_BCNF_BCNTRL, val);
+ /* clear any current pending errors */
+ pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
+ PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+ pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
+ PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+ /* if we are a PCIe device, disable the generation of UR, CE and NFE */
+ if (regs->pcie_dev) {
+ uint16_t devctl;
+ int off = pcicfg_get_cap(h, PCI_CAP_ID_PCI_E);
+
+ regs->pcie_cap_off = off;
+ regs->devctl = devctl = pci_config_get16(h, off + PCIE_DEVCTL);
+ devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN |
+ PCIE_DEVCTL_CE_REPORTING_EN |
+ PCIE_DEVCTL_NFE_REPORTING_EN |
+ PCIE_DEVCTL_FE_REPORTING_EN);
+ pci_config_put16(h, off + PCIE_DEVCTL, devctl);
+ }
+}
+
+/*ARGSUSED*/
+static void
+pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
+ pcicfg_err_regs_t *regs)
+{
+ /* clear any pending errors */
+ pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
+ PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+ pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
+ PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
+
+ /* restore original settings */
+ if (regs->pcie_dev) {
+ pcie_clear_errors(dip, h);
+ pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
+ regs->devctl);
+ }
+
+ pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl);
+ pci_config_put16(h, PCI_CONF_COMM, regs->cmd);
+
+}
+
static int
pcicfg_probe_children(dev_info_t *parent, uint_t bus,
- uint_t device, uint_t func)
+ uint_t device, uint_t func, uint_t *highest_bus)
{
dev_info_t *new_child;
ddi_acc_handle_t config_handle;
- uint8_t header_type;
+ uint8_t header_type, pcie_dev = 0;
- int i, j;
- ndi_ra_request_t req;
- uint64_t next_bus;
- uint64_t blen;
+ int i;
uint32_t request;
- uint_t new_bus;
int ret;
- int circ;
-
+ pcicfg_err_regs_t regs;
/*
* This node will be put immediately below
* "parent". Allocate a blank device node. It will either
* be filled in or freed up based on further probing.
*/
-
- ndi_devi_enter(parent, &circ);
/*
* Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c
* ndi_devi_alloc() is called as ndi_devi_alloc_sleep()
@@ -3243,7 +3549,6 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus,
(pnode_t)DEVI_SID_NODEID, &new_child)
!= NDI_SUCCESS) {
DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n");
- ndi_devi_exit(parent, circ);
return (PCICFG_FAILURE);
}
@@ -3258,7 +3563,6 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus,
!= PCICFG_SUCCESS) {
if (ret == PCICFG_NODEVICE) {
(void) ndi_devi_free(new_child);
- ndi_devi_exit(parent, circ);
return (ret);
}
DEBUG0("pcicfg_probe_children():"
@@ -3273,12 +3577,18 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus,
*/
(void) pcicfg_device_off(config_handle);
+ /* check if we are PCIe device */
+ if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
+ == DDI_SUCCESS) {
+ DEBUG0("PCIe device detected\n");
+ pcie_dev = 1;
+ }
/*
* Set 1275 properties common to all devices
*/
- if (pcicfg_set_standard_props(new_child,
- config_handle) != PCICFG_SUCCESS) {
+ if (pcicfg_set_standard_props(new_child, config_handle,
+ pcie_dev) != PCICFG_SUCCESS) {
DEBUG0("Failed to set standard properties\n");
goto failedchild;
}
@@ -3286,8 +3596,8 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus,
/*
* Child node properties NOTE: Both for PCI-PCI bridge and child node
*/
- if (pcicfg_set_childnode_props(new_child,
- config_handle) != PCICFG_SUCCESS) {
+ if (pcicfg_set_childnode_props(new_child, config_handle,
+ pcie_dev) != PCICFG_SUCCESS) {
goto failedchild;
}
@@ -3296,11 +3606,10 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus,
/*
* If this is not a multi-function card only probe function zero.
*/
- if (!(header_type & PCI_HEADER_MULTI) && (func != 0)) {
+ if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
(void) pcicfg_config_teardown(&config_handle);
(void) ndi_devi_free(new_child);
- ndi_devi_exit(parent, circ);
return (PCICFG_NODEVICE);
}
@@ -3309,54 +3618,22 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus,
DEBUG1("---Device ID = [0x%x]\n",
pci_config_get16(config_handle, PCI_CONF_DEVID));
+ /*
+ * Attach the child to its parent
+ */
+ (void) i_ndi_config_node(new_child, DS_LINKED, 0);
+
if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
DEBUG3("--Bridge found bus [0x%x] device"
"[0x%x] func [0x%x]\n", bus, device, func);
- /*
- * Get next bus in sequence and program device.
- * XXX There might have to be slot specific
- * ranges taken care of here.
- */
- bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
- req.ra_len = 1;
- if (ndi_ra_alloc(ddi_get_parent(new_child), &req,
- &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
- NDI_RA_PASS) != NDI_SUCCESS) {
- DEBUG0("Failed to get a bus number\n");
- goto failedchild;
- }
- new_bus = next_bus;
-
- DEBUG1("NEW bus found ->[%d]\n", new_bus);
-
- (void) pcicfg_set_bus_numbers(config_handle,
- bus, new_bus, new_bus);
- /*
- * Set bus properties
- */
- if (pcicfg_set_busnode_props(new_child) != PCICFG_SUCCESS) {
- DEBUG0("Failed to set busnode props\n");
+ if (pcicfg_probe_bridge(new_child, config_handle,
+ bus, highest_bus) != PCICFG_SUCCESS) {
+ (void) pcicfg_free_bridge_resources(new_child);
goto failedchild;
}
- /*
- * Probe all children devices
- */
- for (i = 0; i < PCICFG_MAX_DEVICE; i++) {
- for (j = 0; j < PCICFG_MAX_FUNCTION; j++) {
- if (pcicfg_probe_children(new_child,
- new_bus, i, j) ==
- PCICFG_FAILURE) {
- DEBUG3("Failed to configure bus "
- "[0x%x] device [0x%x] func [0x%x]\n",
- new_bus, i, j);
- goto failedchild;
- }
- }
- }
-
} else {
DEBUG3("--Leaf device found bus [0x%x] device"
@@ -3430,16 +3707,16 @@ pcicfg_probe_children(dev_info_t *parent, uint_t bus,
goto failedchild;
}
}
- }
- /*
- * Attach the child to its parent
- */
- (void) ndi_devi_bind_driver(new_child, 0);
+ /* now allocate & program the resources */
+ if (pcicfg_device_assign(new_child) != PCICFG_SUCCESS) {
+ (void) pcicfg_free_device_resources(new_child);
+ goto failedchild;
+ }
+ (void) ndi_devi_bind_driver(new_child, 0);
+ }
(void) pcicfg_config_teardown(&config_handle);
- ndi_devi_exit(parent, circ);
-
return (PCICFG_SUCCESS);
failedchild:
@@ -3449,8 +3726,6 @@ failedchild:
failedconfig:
(void) ndi_devi_free(new_child);
- ndi_devi_exit(parent, circ);
-
return (PCICFG_FAILURE);
}
@@ -3461,10 +3736,10 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
dev_info_t *new_child;
int8_t header_type;
int ret;
- ddi_acc_handle_t h;
+ ddi_acc_handle_t h, ph;
int error = 0;
- int rval;
extern int pcicfg_dont_interpret;
+ pcicfg_err_regs_t parent_regs, regs;
#ifdef PCICFG_INTERPRET_FCODE
struct pci_ops_bus_args po;
fco_handle_t c;
@@ -3479,6 +3754,22 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
#endif
/*
+ * check if our parent is of type pciex.
+ * if so, program config space to disable error msgs during probe.
+ */
+ if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs)
+ == DDI_SUCCESS) {
+ DEBUG0("PCI/PCIe parent detected. Disable errors.\n");
+ /*
+ * disable parent generating URs or SERR#s during probing
+ * alone.
+ */
+ if (pci_config_setup(parent, &ph) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ pcicfg_disable_bridge_probe_err(parent, ph, &parent_regs);
+ }
+
+ /*
* This node will be put immediately below
* "parent". Allocate a blank device node. It will either
* be filled in or freed up based on further probing.
@@ -3488,7 +3779,9 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
(pnode_t)DEVI_SID_NODEID, &new_child)
!= NDI_SUCCESS) {
DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n");
- return (PCICFG_FAILURE);
+ /* return (PCICFG_FAILURE); */
+ ret = PCICFG_FAILURE;
+ goto failed2;
}
/*
@@ -3497,21 +3790,19 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
* produce one by hand.
*/
if (pcicfg_add_config_reg(new_child, bus,
- device, func) != DDI_SUCCESS) {
-
- (void) ndi_devi_free(new_child);
- return (PCICFG_FAILURE);
+ device, func) != DDI_SUCCESS) {
+ ret = PCICFG_FAILURE;
+ goto failed3;
}
#ifdef EFCODE21554
if ((ret = pcicfg_config_setup(new_child, &h))
!= PCICFG_SUCCESS) {
DEBUG0("pcicfg_fcode_probe():"
"Failed to setup config space\n");
- (void) ndi_devi_free(new_child);
- return (ret);
+ ret = PCICFG_NODEVICE;
+ goto failed3;
}
- DEBUG0("fcode_probe: conf space mapped.\n");
#else
p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
p.pci_phys_mid = p.pci_phys_low = 0;
@@ -3526,11 +3817,9 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) {
DEBUG0("pcicfg_fcode_probe():"
- "Failed to setup config space\n");
-
- (void) ndi_devi_free(new_child);
-
- return (PCICFG_FAILURE);
+ "Failed to setup config space\n");
+ ret = PCICFG_NODEVICE;
+ goto failed3;
}
/*
@@ -3541,10 +3830,11 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) {
DEBUG0("Can not read Vendor ID");
pcicfg_unmap_phys(&h, &p);
- (void) ndi_devi_free(new_child);
- return (PCICFG_NODEVICE);
+ ret = PCICFG_NODEVICE;
+ goto failed3;
}
#endif
+ DEBUG0("fcode_probe: conf space mapped.\n");
/*
* As soon as we have access to config space,
* turn off device. It will get turned on
@@ -3552,11 +3842,18 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
*/
(void) pcicfg_device_off(h);
+ /* check if we are PCIe device */
+ if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, &regs)
+ == DDI_SUCCESS) {
+ /*EMPTY*/
+ DEBUG0("PCI/PCIe device detected\n");
+ }
+
/*
* Set 1275 properties common to all devices
*/
if (pcicfg_set_standard_props(new_child,
- h) != PCICFG_SUCCESS) {
+ h, regs.pcie_dev) != PCICFG_SUCCESS) {
DEBUG0("Failed to set standard properties\n");
goto failed;
}
@@ -3565,7 +3862,8 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
* Child node properties NOTE: Both for PCI-PCI bridge and child node
*/
if (pcicfg_set_childnode_props(new_child,
- h) != PCICFG_SUCCESS) {
+ h, regs.pcie_dev) != PCICFG_SUCCESS) {
+ ret = PCICFG_FAILURE;
goto failed;
}
@@ -3576,13 +3874,8 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
*/
if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) {
-#ifdef EFCODE21554
- pcicfg_config_teardown(&h);
-#else
- pcicfg_unmap_phys(&h, &p);
-#endif
- (void) ndi_devi_free(new_child);
- return (PCICFG_NODEVICE);
+ ret = PCICFG_NODEVICE;
+ goto failed;
}
if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
@@ -3600,17 +3893,10 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
DEBUG3("--Bridge found bus [0x%x] device"
"[0x%x] func [0x%x]\n", bus, device, func);
- rval = pcicfg_probe_bridge(new_child, h, bus, highest_bus);
-
-#ifdef EFCODE21554
- pcicfg_config_teardown(&h);
-#else
- pcicfg_unmap_phys(&h, &p);
-#endif
- if (rval != PCICFG_SUCCESS)
- (void) ndi_devi_free(new_child);
-
- return (rval);
+ if ((ret = pcicfg_probe_bridge(new_child, h,
+ bus, highest_bus)) != PCICFG_SUCCESS)
+ (void) pcicfg_free_bridge_resources(new_child);
+ goto done;
} else {
DEBUG3("--Leaf device found bus [0x%x] device"
@@ -3660,6 +3946,7 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
!= PCICFG_SUCCESS) {
DEBUG0("Failed to assign addresses to "
"implemented BARs");
+ ret = PCICFG_FAILURE;
goto failed;
}
@@ -3695,8 +3982,8 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
!= DDI_SUCCESS) {
DEBUG0("Failed to create "
"fcode-rom-offset property\n");
- (void) ndi_devi_free(new_child);
- return (PCICFG_FAILURE);
+ ret = PCICFG_FAILURE;
+ goto failed;
}
} else {
DEBUG0("There is no Expansion ROM\n");
@@ -3769,32 +4056,24 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
*/
if (pcicfg_alloc_new_resources(new_child) ==
PCICFG_FAILURE) {
-#ifdef EFCODE21554
- pcicfg_config_teardown(&h);
-#else
- pcicfg_unmap_phys(&h, &p);
-#endif
- (void) ndi_devi_free(new_child);
- return (PCICFG_FAILURE);
+ ret = PCICFG_FAILURE;
+ goto failed;
}
-#ifdef EFCODE21554
- pcicfg_config_teardown(&h);
-#else
- pcicfg_unmap_phys(&h, &p);
-#endif
+ ret = PCICFG_SUCCESS;
/* no fcode, bind driver now */
(void) ndi_devi_bind_driver(new_child, 0);
- return (PCICFG_SUCCESS);
+ goto done;
} else if ((error != FC_NO_FCODE) &&
- (pcicfg_dont_interpret == 0)) {
+ (pcicfg_dont_interpret == 0)) {
/*
* The interpreter located fcode, but had an error in
* processing. Cleanup and fail the operation.
*/
DEBUG0("Interpreter detected fcode failure\n");
(void) pcicfg_free_resources(new_child);
+ ret = PCICFG_FAILURE;
goto failed;
} else {
/*
@@ -3822,11 +4101,12 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
DEBUG0("No Drop-in Probe device ourself\n");
- ret = pcicfg_probe_children(parent, bus, device, func);
+ ret = pcicfg_probe_children(parent, bus, device, func,
+ highest_bus);
if (ret != PCICFG_SUCCESS) {
DEBUG0("Could not self probe child\n");
- return (ret);
+ goto failed2;
}
/*
@@ -3836,13 +4116,8 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
parent, device, func)) == NULL) {
DEBUG0("Did'nt find device node "
"just created\n");
- return (PCICFG_FAILURE);
- }
- if (pcicfg_program_ap(new_child)
- == PCICFG_FAILURE) {
- DEBUG0("Failed to program devices\n");
- (void) ndi_devi_free(new_child);
- return (PCICFG_FAILURE);
+ ret = PCICFG_FAILURE;
+ goto failed2;
}
#ifdef EFCODE21554
/*
@@ -3883,19 +4158,26 @@ pcicfg_fcode_probe(dev_info_t *parent, uint_t bus,
(void) pcicfg_teardown_device(new_child);
}
#endif
-
- return (ret);
+ goto done2;
}
}
+done:
failed:
#ifdef EFCODE21554
pcicfg_config_teardown(&h);
#else
pcicfg_unmap_phys(&h, &p);
#endif
- (void) ndi_devi_free(new_child);
-
- return (PCICFG_FAILURE);
+failed3:
+ if (ret != PCICFG_SUCCESS)
+ (void) ndi_devi_free(new_child);
+done2:
+failed2:
+ if (parent_regs.pcie_dev) {
+ pcicfg_enable_bridge_probe_err(parent, ph, &parent_regs);
+ pci_config_teardown(&ph);
+ }
+ return (ret);
}
static int
@@ -3903,12 +4185,11 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
uint_t *highest_bus)
{
uint64_t next_bus;
- uint_t new_bus;
+ uint_t new_bus, num_slots;
ndi_ra_request_t req;
int rval, i, j;
- uint64_t mem_answer, io_answer, mem_base, io_base, mem_alen, io_alen;
- uint64_t mem_size, io_size;
- uint64_t mem_end, io_end;
+ uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end;
+ uint64_t io_answer, io_base, io_alen, io_size, io_end;
uint64_t round_answer, round_len;
pcicfg_range_t range[PCICFG_RANGE_LEN];
int bus_range[2];
@@ -3916,6 +4197,7 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
int count;
uint64_t pcibus_base, pcibus_alen;
uint64_t max_bus;
+ uint8_t pcie_device_type = 0;
bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
@@ -3929,6 +4211,7 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
if (rval != NDI_SUCCESS) {
if (rval == NDI_RA_PARTIAL_REQ) {
+ /*EMPTY*/
DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
} else {
DEBUG0(
@@ -3970,6 +4253,10 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
req.ra_boundbase = 0;
+ /*
+ * Note: To support a 32b system, boundlen and len need to be
+ * 32b quantities
+ */
req.ra_boundlen = PCICFG_4GIG_LIMIT + 1;
req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */
req.ra_align_mask =
@@ -3980,6 +4267,7 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
if (rval != NDI_SUCCESS) {
if (rval == NDI_RA_PARTIAL_REQ) {
+ /*EMPTY*/
DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
} else {
DEBUG0(
@@ -4021,28 +4309,33 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
if (rval != NDI_SUCCESS) {
if (rval == NDI_RA_PARTIAL_REQ) {
+ /*EMPTY*/
DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
} else {
DEBUG0("Failed to allocate io space for bridge\n");
- return (PCICFG_FAILURE);
+ io_base = io_answer = io_alen = 0;
+ /* return (PCICFG_FAILURE); */
}
}
- DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
- PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), io_alen);
+ if (io_alen) {
+ DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
+ PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer),
+ io_alen);
- if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
- DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
- return (PCICFG_FAILURE);
- }
-
- /*
- * Put available I/O into the pool.
- */
- (void) ndi_ra_free(new_child, io_answer, io_alen, NDI_RA_TYPE_IO,
- NDI_RA_PASS);
+ if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) ==
+ NDI_FAILURE) {
+ DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
+ return (PCICFG_FAILURE);
+ }
- io_base = io_answer;
+ /*
+ * Put available I/O into the pool.
+ */
+ (void) ndi_ra_free(new_child, io_answer, io_alen,
+ NDI_RA_TYPE_IO, NDI_RA_PASS);
+ io_base = io_answer;
+ }
(void) pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
@@ -4151,10 +4444,15 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
*/
pci_config_put8(h, PCI_CONF_ILINE, 0xf);
+ /* check our device_type as defined by Open Firmware */
+ if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
+ pcie_device_type = 1;
+
/*
* Set bus properties
*/
- if (pcicfg_set_busnode_props(new_child) != PCICFG_SUCCESS) {
+ if (pcicfg_set_busnode_props(new_child, pcie_device_type)
+ != PCICFG_SUCCESS) {
DEBUG0("Failed to set busnode props\n");
return (PCICFG_FAILURE);
}
@@ -4174,7 +4472,7 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
* first Configuration access. The worst case is 33MHz, which
* is a 1 second wait.
*/
- drv_usecwait(1000000);
+ drv_usecwait(pcicfg_sec_reset_delay);
/*
* Probe all children devices
@@ -4183,25 +4481,45 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
ndi_devi_enter(new_child, &count);
for (i = 0; i < PCICFG_MAX_DEVICE; i++) {
for (j = 0; j < PCICFG_MAX_FUNCTION; j++) {
- if (pcicfg_fcode_probe(new_child,
- new_bus, i, j, highest_bus) != PCICFG_SUCCESS) {
- DEBUG3("Failed to configure bus "
- "[0x%x] device [0x%x] func [0x%x]\n",
- new_bus, i, j);
+ if ((rval = pcicfg_fcode_probe(new_child,
+ new_bus, i, j, highest_bus))
+ != PCICFG_SUCCESS) {
+ if (rval == PCICFG_NODEVICE) {
+ DEBUG3("No Device at bus [0x%x]"
+ "device [0x%x] "
+ "func [0x%x]\n", new_bus, i, j);
+ if (j)
+ continue;
+ } else {
+ DEBUG3("Failed to configure bus "
+ "[0x%x] device [0x%x] "
+ "func [0x%x]\n", new_bus, i, j);
+ rval = PCICFG_FAILURE;
+ }
+
break;
}
}
+ /* if any function fails to be configured, no need to proceed */
+ if (rval != PCICFG_NODEVICE) {
+ break;
+ }
}
ndi_devi_exit(new_child, count);
+ /* if empty topology underneath, it is still a success. */
+ if (rval != PCICFG_FAILURE)
+ rval = PCICFG_SUCCESS;
+
/*
* Offline the bridge to allow reprogramming of resources.
*/
(void) ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG);
phdl.dip = new_child;
- phdl.memory_base = 0;
- phdl.io_base = 0;
+ phdl.memory_base = mem_answer;
+ phdl.io_base = (uint32_t)io_answer;
+ phdl.error = PCICFG_SUCCESS; /* in case of empty child tree */
ndi_devi_enter(ddi_get_parent(new_child), &count);
ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
@@ -4212,22 +4530,71 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
return (PCICFG_FAILURE);
}
+ num_slots = pcicfg_get_nslots(new_child, h);
mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
- DEBUG2("Start of Unallocated Bridge Resources Mem=0x%lx I/O=0x%lx\n",
- mem_end, io_end);
-
-
- if (mem_end == 0) {
- /*
- * Give back all memory space back to parent.
- */
- (void) ndi_ra_free(ddi_get_parent(new_child),
- mem_answer, mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
-
+ DEBUG3("Start of Unallocated Bridge(%d slots) Resources "
+ "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end);
+
+ /*
+ * if the bridge a slots, then preallocate. If not, assume static
+ * configuration. Also check for preallocation limits and spit
+ * warning messages appropriately (perhaps some can be in debug mode).
+ */
+ if (num_slots) {
+ uint64_t mem_reqd = mem_answer + (num_slots *
+ pcicfg_slot_memsize);
+ uint64_t io_reqd = io_answer + (num_slots *
+ pcicfg_slot_iosize);
+ uint8_t highest_bus_reqd = new_bus + (num_slots *
+ pcicfg_slot_busnums);
+
+ if (mem_end > mem_reqd)
+ cmn_err(CE_WARN, "Memory space consumed by bridge"
+ " more than planned for %d slot(s)(%lx, %lx)",
+ num_slots, mem_answer, mem_end);
+ if (io_end > io_reqd)
+ cmn_err(CE_WARN, "IO space consumed by bridge"
+ " more than planned for %d slot(s)(%lx, %lx)",
+ num_slots, io_answer, io_end);
+ if (*highest_bus > highest_bus_reqd)
+ cmn_err(CE_WARN, "Buses consumed by bridge"
+ " more than planned for %d slot(s)(%x, %x)",
+ num_slots, new_bus, *highest_bus);
+
+ if (mem_reqd > (mem_answer + mem_alen))
+ cmn_err(CE_WARN, "Memory space required by bridge"
+ " more than available for %d slot(s)(%lx, %lx)",
+ num_slots, mem_answer, mem_end);
+
+ if (io_reqd > (io_answer + io_alen))
+ cmn_err(CE_WARN, "IO space required by bridge"
+ " more than available for %d slot(s)(%lx, %lx)",
+ num_slots, io_answer, io_end);
+ if (highest_bus_reqd > max_bus)
+ cmn_err(CE_WARN, "Bus numbers required by bridge"
+ " more than available for %d slot(s)(%x, %x)",
+ num_slots, new_bus, *highest_bus);
+
+ mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
+ mem_end);
+ io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
+ *highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
+ *highest_bus);
+ DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n",
+ mem_end, io_end, *highest_bus);
+ }
+
+ /*
+ * Give back unused memory space to parent.
+ */
+ (void) ndi_ra_free(ddi_get_parent(new_child),
+ mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
+ NDI_RA_PASS);
+
+ if (mem_end == mem_answer) {
DEBUG0("No memory resources used\n");
-
/*
* To prevent the bridge from forwarding any Memory
* transactions, the Memory Limit will be programmed
@@ -4239,12 +4606,6 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
mem_size = 0;
} else {
/*
- * Give back the unused memory space to the parent.
- */
- (void) ndi_ra_free(ddi_get_parent(new_child),
- mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
- NDI_RA_PASS);
- /*
* Reprogram the end of the memory.
*/
pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
@@ -4252,14 +4613,14 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
mem_size = mem_end - mem_base;
}
+ /*
+ * Give back unused io space to parent.
+ */
+ (void) ndi_ra_free(ddi_get_parent(new_child),
+ io_end, (io_answer + io_alen) - io_end,
+ NDI_RA_TYPE_IO, NDI_RA_PASS);
- if (io_end == 0) {
- /*
- * Give back all io space back to parent.
- */
- (void) ndi_ra_free(ddi_get_parent(new_child),
- io_answer, io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
-
+ if (io_end == io_answer) {
DEBUG0("No IO Space resources used\n");
/*
@@ -4275,13 +4636,6 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
io_size = 0;
} else {
/*
- * Give back the unused io space to the parent.
- */
- (void) ndi_ra_free(ddi_get_parent(new_child),
- io_end, (io_answer + io_alen) - io_end,
- NDI_RA_TYPE_IO, NDI_RA_PASS);
-
- /*
* Reprogram the end of the io space.
*/
pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
@@ -4354,25 +4708,29 @@ pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
}
/*
* Remove the resource maps for the bridge since we no longer
- * need them.
+ * need them. Note that the failure is ignored since the
+ * ndi_devi_offline above may have already taken care of it via
+ * driver detach.
+ * It has been checked that there are no other reasons for
+ * failure other than map itself being non-existent. So we are Ok.
*/
if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
+ /*EMPTY*/
DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n");
- return (PCICFG_FAILURE);
}
if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
+ /*EMPTY*/
DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n");
- return (PCICFG_FAILURE);
}
if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM)
== NDI_FAILURE) {
+ /*EMPTY*/
DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
- return (PCICFG_FAILURE);
}
- return (PCICFG_SUCCESS);
+ return (rval);
}
/*
@@ -4395,6 +4753,7 @@ pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
* mapped, otherwise it is 0. "flags" is introduced in support of any
* non transparent bridges, where configuration space is indirectly
* mapped.
+ * Indirect mapping is always true on sun4v systems.
*/
int flags = 0;
@@ -4425,6 +4784,7 @@ pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
+ attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
#ifdef EFCODE21554
if (ddi_regs_map_setup(dip, 0, &virt,
@@ -4452,12 +4812,18 @@ pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
}
if (ret == DDI_SUCCESS) {
- if ((tmp == (int16_t)0xffff) || (tmp == -1)) {
+ if (tmp == -1) {
DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
ret = PCICFG_NODEVICE;
} else {
- DEBUG1("DEVICEFOUND, read %x\n", tmp);
- ret = PCICFG_SUCCESS;
+ /* XXX - Need to check why HV is returning 0 */
+ if (tmp == 0) {
+ DEBUG0("Device Not Ready yet ?");
+ ret = PCICFG_NODEVICE;
+ } else {
+ DEBUG1("DEVICEFOUND, read %x\n", tmp);
+ ret = PCICFG_SUCCESS;
+ }
}
} else {
DEBUG0("ddi_peek failed, must be NODEVICE\n");
diff --git a/usr/src/uts/sun4/io/px/px.c b/usr/src/uts/sun4/io/px/px.c
index d8337a931d..4ce07e4620 100644
--- a/usr/src/uts/sun4/io/px/px.c
+++ b/usr/src/uts/sun4/io/px/px.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,6 +42,8 @@
#include <sys/spl.h>
#include <sys/epm.h>
#include <sys/iommutsb.h>
+#include <sys/hotplug/pci/pcihp.h>
+#include <sys/hotplug/pci/pciehpc.h>
#include "px_obj.h"
#include <sys/pci_tools.h>
#include "px_tools_ext.h"
@@ -60,6 +62,12 @@ static int px_pwr_setup(dev_info_t *dip);
static void px_pwr_teardown(dev_info_t *dip);
/*
+ * function prototypes for hotplug routines:
+ */
+static uint_t px_init_hotplug(px_t *px_p);
+static uint_t px_uninit_hotplug(dev_info_t *dip);
+
+/*
* bus ops and dev ops structures:
*/
static struct bus_ops px_bus_ops = {
@@ -181,14 +189,12 @@ px_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
int instance = getminor((dev_t)arg);
px_t *px_p = INST_TO_STATE(instance);
-#ifdef HOTPLUG
/*
* Allow hotplug to deal with ones it manages
* Hot Plug will be done later.
*/
- if (px_p && (px_p->hotplug_capable == B_TRUE))
+ if (px_p && (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE))
return (pcihp_info(dip, infocmd, arg, result));
-#endif /* HOTPLUG */
/* non-hotplug or not attached */
switch (infocmd) {
@@ -239,6 +245,8 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
px_p->px_open_count = 0;
+ (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
+ "device_type", "pciex");
/*
* Get key properties of the pci bridge node and
* determine it's type (psycho, schizo, etc ...).
@@ -293,6 +301,8 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
if ((ret = px_err_add_intr(&px_p->px_fault)) != DDI_SUCCESS)
goto err_bad_pec_add_intr;
+ (void) px_init_hotplug(px_p);
+
/*
* Create the "devctl" node for hotplug and pcitool support.
* For non-hotplug bus, we still need ":devctl" to
@@ -420,17 +430,11 @@ px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
*/
px_cpr_rem_callb(px_p);
-#ifdef HOTPLUG
- /*
- * Hot plug will be done later.
- */
- if (px_p->hotplug_capable == B_TRUE) {
- if (pxhp_uninit(dip) == DDI_FAILURE) {
+ if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
+ if (px_uninit_hotplug(dip) != DDI_SUCCESS) {
mutex_exit(&px_p->px_mutex);
return (DDI_FAILURE);
}
- }
-#endif /* HOTPLUG */
/*
* things which used to be done in obj_destroy
@@ -530,6 +534,8 @@ px_pwr_setup(dev_info_t *dip)
DDI_INTR_PRI(px_pwr_pil));
cv_init(&px_p->px_l23ready_cv, NULL, CV_DRIVER, NULL);
+
+
/* Initilize handle */
hdl.ih_cb_arg1 = px_p;
hdl.ih_cb_arg2 = NULL;
@@ -1304,3 +1310,78 @@ px_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
return (ret);
}
+
+static uint_t
+px_init_hotplug(px_t *px_p)
+{
+ px_bus_range_t bus_range;
+ dev_info_t *dip;
+ pciehpc_regops_t regops;
+
+ dip = px_p->px_dip;
+
+ if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "hotplug-capable") == 0)
+ return (DDI_FAILURE);
+
+ /*
+ * Before initializing hotplug - open up bus range. The busra
+ * module will initialize its pool of bus numbers from this.
+ * "busra" will be the agent that keeps track of them during
+ * hotplug. Also, note, that busra will remove any bus numbers
+ * already in use from boot time.
+ */
+ if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "bus-range") == 0) {
+ cmn_err(CE_WARN, "%s%d: bus-range not found\n",
+ ddi_driver_name(dip), ddi_get_instance(dip));
+#ifdef DEBUG
+ bus_range.lo = 0x0;
+ bus_range.hi = 0xff;
+
+ if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
+ dip, "bus-range", (int *)&bus_range, 2)
+ != DDI_PROP_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+#else
+ return (DDI_FAILURE);
+#endif
+ }
+
+ if (px_lib_hotplug_init(dip, (void *)&regops) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
+ if (pciehpc_init(dip, &regops) != DDI_SUCCESS) {
+ px_lib_hotplug_uninit(dip);
+ return (DDI_FAILURE);
+ }
+
+ if (pcihp_init(dip) != DDI_SUCCESS) {
+ (void) pciehpc_uninit(dip);
+ px_lib_hotplug_uninit(dip);
+ return (DDI_FAILURE);
+ }
+
+ if (pcihp_get_cb_ops() != NULL) {
+ DBG(DBG_ATTACH, dip, "%s%d hotplug enabled",
+ ddi_driver_name(dip), ddi_get_instance(dip));
+ px_p->px_dev_caps |= PX_HOTPLUG_CAPABLE;
+ }
+
+ return (DDI_SUCCESS);
+}
+
+static uint_t
+px_uninit_hotplug(dev_info_t *dip)
+{
+ if (pcihp_uninit(dip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
+ if (pciehpc_uninit(dip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
+ px_lib_hotplug_uninit(dip);
+
+ return (DDI_SUCCESS);
+}
diff --git a/usr/src/uts/sun4/io/px/px_devctl.c b/usr/src/uts/sun4/io/px/px_devctl.c
index 1dbc054c8a..196d8d6e3a 100644
--- a/usr/src/uts/sun4/io/px/px_devctl.c
+++ b/usr/src/uts/sun4/io/px/px_devctl.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -82,6 +82,8 @@ static int
px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
{
px_t *px_p;
+ int rval;
+ uint_t orig_px_soft_state;
/*
* Make sure the open is for the right file type.
@@ -101,6 +103,7 @@ px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
*/
DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
mutex_enter(&px_p->px_mutex);
+ orig_px_soft_state = px_p->px_soft_state;
if (flags & FEXCL) {
if (px_p->px_soft_state != PX_SOFT_STATE_CLOSED) {
mutex_exit(&px_p->px_mutex);
@@ -116,6 +119,15 @@ px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
}
px_p->px_soft_state = PX_SOFT_STATE_OPEN;
}
+
+ if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
+ if (rval = (pcihp_get_cb_ops())->cb_open(devp, flags,
+ otyp, credp)) {
+ px_p->px_soft_state = orig_px_soft_state;
+ mutex_exit(&px_p->px_mutex);
+ return (rval);
+ }
+
px_p->px_open_count++;
mutex_exit(&px_p->px_mutex);
return (0);
@@ -127,6 +139,7 @@ static int
px_close(dev_t dev, int flags, int otyp, cred_t *credp)
{
px_t *px_p;
+ int rval;
if (otyp != OTYP_CHR)
return (EINVAL);
@@ -137,6 +150,14 @@ px_close(dev_t dev, int flags, int otyp, cred_t *credp)
DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
mutex_enter(&px_p->px_mutex);
+
+ if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
+ if (rval = (pcihp_get_cb_ops())->cb_close(dev, flags,
+ otyp, credp)) {
+ mutex_exit(&px_p->px_mutex);
+ return (rval);
+ }
+
px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
px_p->px_open_count = 0;
mutex_exit(&px_p->px_mutex);
@@ -230,6 +251,9 @@ px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
return (rv);
default:
+ if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
+ return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
+ arg, mode, credp, rvalp));
break;
}
diff --git a/usr/src/uts/sun4/io/px/px_dma.c b/usr/src/uts/sun4/io/px/px_dma.c
index 743b71c41c..58731d3277 100644
--- a/usr/src/uts/sun4/io/px/px_dma.c
+++ b/usr/src/uts/sun4/io/px/px_dma.c
@@ -228,7 +228,7 @@ px_dma_attach(px_t *px_p)
PCI_MAP_ATTR_WRITE|PCI_MAP_ATTR_READ,
&baddr) != DDI_ENOTSUP)
/* ignore all other errors */
- px_p->px_soft_state |= PX_BYPASS_DMA_ALLOWED;
+ px_p->px_dev_caps |= PX_BYPASS_DMA_ALLOWED;
return (DDI_SUCCESS);
}
@@ -276,7 +276,7 @@ px_dma_attr2hdl(px_t *px_p, ddi_dma_impl_t *mp)
* If Bypass DMA is not supported, return error so that
* target driver can fall back to dvma mode of operation
*/
- if (!(px_p->px_soft_state & PX_BYPASS_DMA_ALLOWED))
+ if (!(px_p->px_dev_caps & PX_BYPASS_DMA_ALLOWED))
return (DDI_DMA_BADATTR);
mp->dmai_flags |= PX_DMAI_FLAGS_BYPASSREQ;
if (nocross != UINT64_MAX)
diff --git a/usr/src/uts/sun4/io/px/px_fm.c b/usr/src/uts/sun4/io/px/px_fm.c
index 987649b781..3270dfc2d9 100644
--- a/usr/src/uts/sun4/io/px/px_fm.c
+++ b/usr/src/uts/sun4/io/px/px_fm.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -804,7 +804,9 @@ px_err_fabric_intr(px_t *px_p, msgcode_t msg_code,
*/
if ((err & (PX_FATAL_GOS | PX_FATAL_SW)) ||
(ret == DDI_FM_FATAL) || (fab_err == DDI_FM_FATAL))
- PX_FM_PANIC("Fatal PCIe Fabric Error has occurred\n");
+ PX_FM_PANIC("%s#%d: Fatal PCIe Fabric Error has occurred"
+ "(%x,%x,%x)\n", ddi_driver_name(rpdip),
+ ddi_get_instance(rpdip), err, fab_err, ret);
return (DDI_INTR_CLAIMED);
}
diff --git a/usr/src/uts/sun4/io/px/px_lib.h b/usr/src/uts/sun4/io/px/px_lib.h
index d4edf2702f..a32b084c63 100644
--- a/usr/src/uts/sun4/io/px/px_lib.h
+++ b/usr/src/uts/sun4/io/px/px_lib.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -210,6 +210,12 @@ extern void px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
extern void px_cpr_add_callb(px_t *);
extern void px_cpr_rem_callb(px_t *);
+/*
+ * Hotplug functions
+ */
+extern int px_lib_hotplug_init(dev_info_t *dip, void *regops);
+extern void px_lib_hotplug_uninit(dev_info_t *dip);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/sun4/io/px/px_pci.c b/usr/src/uts/sun4/io/px/px_pci.c
index d0761e6950..90da208323 100644
--- a/usr/src/uts/sun4/io/px/px_pci.c
+++ b/usr/src/uts/sun4/io/px/px_pci.c
@@ -37,11 +37,19 @@
#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/ddi.h>
#include <sys/sunndi.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>
@@ -49,12 +57,13 @@
#include "px_pci.h"
#include "px_debug.h"
+/* Tunables. Beware: Some are for debug purpose only. */
/*
* PXB MSI tunable:
*
* By default MSI is enabled on all supported platforms.
*/
-boolean_t pxb_enable_msi = B_TRUE;
+boolean_t pxb_enable_msi = B_TRUE; /* MSI enabled by default, otherwise INTX */
static int pxb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
off_t, off_t, caddr_t *);
@@ -73,6 +82,11 @@ static int pxb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
static int pxb_fm_err_callback(dev_info_t *dip, ddi_fm_error_t *derr,
const void *impl_data);
+static int ppb_pcie_device_type(pxb_devstate_t *pxb_p);
+#ifdef PRINT_PLX_SEEPROM_CRC
+static void pxb_print_plx_seeprom_crc_data(pxb_devstate_t *pxb_p);
+#endif
+
struct bus_ops pxb_bus_ops = {
BUSO_REV,
pxb_bus_map,
@@ -142,6 +156,17 @@ 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);
+static int pxb_get_cap(ddi_acc_handle_t config_handle, uint8_t cap_id);
+static uint16_t pxb_find_ext_cap_reg(ddi_acc_handle_t config_handle,
+ uint16_t cap_id);
+static int pxb_bad_func(pxb_devstate_t *pxb, int func);
+static int pxb_check_bad_devs(pxb_devstate_t *pxb, int vend);
+
+/* 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 void pxb_init_hotplug(pxb_devstate_t *pxb);
+
struct dev_ops pxb_ops = {
DEVO_REV, /* devo_rev */
0, /* refcnt */
@@ -162,7 +187,7 @@ struct dev_ops pxb_ops = {
static struct modldrv modldrv = {
&mod_driverops, /* Type of module */
- "PCIe/PCI nexus driver %I%",
+ "PCIe/PCI nexus driver 1.29",
&pxb_ops, /* driver ops */
};
@@ -188,11 +213,12 @@ int pxb_tlp_count = 64;
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 int pxb_get_port_type(dev_info_t *dip, ddi_acc_handle_t config_handle);
static void pxb_removechild(dev_info_t *);
static int pxb_initchild(dev_info_t *child);
static dev_info_t *get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip);
-static void pxb_init_hotplug(pxb_devstate_t *pxb);
static void pxb_create_ranges_prop(dev_info_t *, ddi_acc_handle_t);
int
@@ -262,7 +288,7 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
int instance;
pxb_devstate_t *pxb;
ddi_acc_handle_t config_handle;
- int intr_types;
+ char device_type[8];
instance = ddi_get_instance(devi);
@@ -326,6 +352,7 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
/* Save the vnedor 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);
/*
* This is a software workaround to fix the Broadcom PCIe-PCI bridge
@@ -356,13 +383,8 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
goto fail;
}
- 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;
-
pxb->pxb_port_type = pxb_get_port_type(devi, config_handle);
+
if ((pxb->pxb_port_type != PX_CAP_REG_DEV_TYPE_UP) &&
(pxb->pxb_port_type != PX_CAP_REG_DEV_TYPE_DOWN) &&
(pxb->pxb_port_type != PX_CAP_REG_DEV_TYPE_PCIE2PCI) &&
@@ -374,8 +396,12 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
/*
* Make sure the "device_type" property exists.
*/
+ if (ppb_pcie_device_type(pxb) == DDI_SUCCESS)
+ (void) strcpy(device_type, "pciex");
+ else
+ (void) strcpy(device_type, "pci");
(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
- "device_type", "pciex");
+ "device_type", device_type);
/*
* Check whether the "ranges" property is present.
@@ -388,32 +414,6 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
}
/*
- * 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");
- goto fail;
- }
-
- 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");
- goto fail;
- }
- }
-
- /*
* 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
@@ -421,7 +421,23 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
* slots and successfully initializes Hot Plug Framework.
*/
pxb->pxb_hotplug_capable = B_FALSE;
- pxb_init_hotplug(pxb);
+
+ if ((pxb->pxb_port_type == PX_CAP_REG_DEV_TYPE_DOWN) ||
+ (pxb->pxb_port_type == PX_CAP_REG_DEV_TYPE_PCIE2PCI) ||
+ (pxb->pxb_port_type == PX_CAP_REG_DEV_TYPE_PCI2PCIE)) {
+ pxb_init_hotplug(pxb);
+ }
+
+ /* attach interrupt only if hotplug functionality is required */
+ if (pxb->pxb_hotplug_capable != B_FALSE) {
+ if (pxb_intr_attach(pxb) != DDI_SUCCESS)
+ goto fail;
+ }
+#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
@@ -436,6 +452,12 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
"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;
+
ddi_report_dev(devi);
return (DDI_SUCCESS);
@@ -463,16 +485,22 @@ pxb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
pxb = (pxb_devstate_t *)
ddi_get_soft_state(pxb_state, ddi_get_instance(devi));
- if (pxb->pxb_hotplug_capable == B_TRUE)
+ 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);
+ }
else
ddi_remove_minor_node(devi, "devctl");
(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
- pxb_intr_fini(pxb);
-
+ if (pxb->pxb_hotplug_capable != B_FALSE)
+ pxb_intr_fini(pxb);
if (pxb->pxb_init_flags & PXB_INIT_FM)
pxb_fm_fini(pxb);
@@ -881,8 +909,13 @@ pxb_initchild(dev_info_t *child)
* optimized out.
*/
if ((!pxb_tlp_count) ||
- (pxb->pxb_vendor_id != PXB_VENDOR_PLX) ||
- ((pxb->pxb_device_id != PXB_DEVICE_PLX_8532) &&
+ ((pxb->pxb_vendor_id != PXB_VENDOR_SUN) &&
+ (pxb->pxb_vendor_id != PXB_VENDOR_PLX)) ||
+ ((pxb->pxb_vendor_id == PXB_VENDOR_SUN) &&
+ (pxb->pxb_device_id != PXB_DEVICE_PLX_PCIX) &&
+ (pxb->pxb_device_id != PXB_DEVICE_PLX_PCIE)) ||
+ ((pxb->pxb_vendor_id == PXB_VENDOR_PLX) &&
+ (pxb->pxb_device_id != PXB_DEVICE_PLX_8532) &&
(pxb->pxb_device_id != PXB_DEVICE_PLX_8516))) {
/* Workaround not needed return success */
result = DDI_SUCCESS;
@@ -906,6 +939,46 @@ done:
return (result);
}
+static int
+pxb_intr_attach(pxb_devstate_t *pxb)
+{
+ int intr_types;
+ dev_info_t *devi;
+ uint8_t bad_msi_dev = 0;
+
+ 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 (pxb_bad_func(pxb, PXB_MSI))
+ bad_msi_dev = 1;
+
+ if ((intr_types & DDI_INTR_TYPE_MSI) && pxb_enable_msi &&
+ !bad_msi_dev) {
+ 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
@@ -917,7 +990,8 @@ done:
* device might not ask for any interrupts.
*/
static int
-pxb_intr_init(pxb_devstate_t *pxb, int intr_type) {
+pxb_intr_init(pxb_devstate_t *pxb, int intr_type)
+{
dev_info_t *dip = pxb->pxb_dip;
int request, count, x;
int ret;
@@ -1055,8 +1129,9 @@ fail:
return (DDI_FAILURE);
}
-static
-void pxb_intr_fini(pxb_devstate_t *pxb) {
+static void
+pxb_intr_fini(pxb_devstate_t *pxb)
+{
int x;
int count = pxb->pxb_intr_count;
int flags = pxb->pxb_init_flags;
@@ -1093,21 +1168,30 @@ void pxb_intr_fini(pxb_devstate_t *pxb) {
*/
/*ARGSUSED*/
static uint_t
-pxb_intr(caddr_t arg1, caddr_t arg2) {
+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;
- cmn_err(CE_WARN,
- "%s%d: Received %s Interrupt\n",
- ddi_driver_name(dip),
- ddi_get_instance(dip),
- (pxb->pxb_intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx");
+ 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 (DDI_INTR_UNCLAIMED);
+ return (rval);
}
-static
-int pxb_get_port_type(dev_info_t *dip, ddi_acc_handle_t config_handle) {
+static int
+pxb_get_port_type(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
ushort_t caps_ptr, cap;
int port_type = PX_CAP_REG_DEV_TYPE_PCIE_DEV;
@@ -1168,10 +1252,41 @@ pxb_removechild(dev_info_t *dip)
static void
pxb_init_hotplug(pxb_devstate_t *pxb)
{
- /*
- * Hot plug support to be decided.
- */
+ int rv;
+
+ pxb->pxb_hpc_type = HPC_NONE;
+
+ if (((pxb->pxb_port_type == PX_CAP_REG_DEV_TYPE_DOWN) ||
+ (pxb->pxb_port_type == PX_CAP_REG_DEV_TYPE_PCI2PCIE)) &&
+ (pxb_pciehpc_probe(pxb->pxb_dip,
+ pxb->pxb_config_handle) == DDI_SUCCESS)) {
+ rv = pciehpc_init(pxb->pxb_dip, NULL);
+ if (rv == DDI_SUCCESS)
+ pxb->pxb_hpc_type = HPC_PCIE;
+ } else if ((pxb->pxb_port_type == PX_CAP_REG_DEV_TYPE_PCIE2PCI) &&
+ (pxb_pcishpc_probe(pxb->pxb_dip,
+ pxb->pxb_config_handle) == DDI_SUCCESS)) {
+ rv = pcishpc_init(pxb->pxb_dip);
+ if (rv == DDI_SUCCESS)
+ pxb->pxb_hpc_type = HPC_SHPC;
+ }
+ if (pxb->pxb_hpc_type != HPC_NONE) {
+ 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);
+
+ pxb->pxb_hpc_type = HPC_NONE;
+ cmn_err(CE_WARN,
+ "%s%d: Failed setting hotplug framework",
+ ddi_driver_name(pxb->pxb_dip),
+ ddi_get_instance(pxb->pxb_dip));
+ }
+ }
+
+ pxb->pxb_hotplug_capable = (pxb->pxb_hpc_type != HPC_NONE);
}
static void
@@ -1442,9 +1557,12 @@ pxb_pwr_setup(dev_info_t *dip)
* Due to PLX erratum #34, we can't allow the downstream device
* go to non-D0 state.
*/
- if ((pxb->pxb_vendor_id == PXB_VENDOR_PLX) &&
- ((pxb->pxb_device_id == PXB_DEVICE_PLX_8516) ||
- (pxb->pxb_device_id == PXB_DEVICE_PLX_8532))) {
+ if (((pxb->pxb_vendor_id == PXB_VENDOR_SUN) &&
+ ((pxb->pxb_device_id == PXB_DEVICE_PLX_PCIX) ||
+ (pxb->pxb_device_id == PXB_DEVICE_PLX_PCIE))) ||
+ ((pxb->pxb_vendor_id == PXB_VENDOR_PLX) &&
+ ((pxb->pxb_device_id == PXB_DEVICE_PLX_8516) ||
+ (pxb->pxb_device_id == PXB_DEVICE_PLX_8532)))) {
DBG(DBG_PWR, dip, "pxb_pwr_setup: PLX8532/PLX8516 found "
"disabling PM\n");
pwr_p->pwr_func_lvl = PM_LEVEL_D0;
@@ -1601,7 +1719,8 @@ pxb_fm_init(pxb_devstate_t *pxb_p)
/*
* Register error callback with our parent.
*/
- ddi_fm_handler_register(pxb_p->pxb_dip, pxb_fm_err_callback, NULL);
+ ddi_fm_handler_register(pxb_p->pxb_dip, pxb_fm_err_callback,
+ (void *)&pxb_p->pxb_config_handle);
return (DDI_SUCCESS);
}
@@ -1636,20 +1755,24 @@ pxb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
}
/*
- * Error callback handler.
+ * FMA Error callback handler.
+ * Need to revisit when pcie fm is supported.
*/
/*ARGSUSED*/
static int
pxb_fm_err_callback(dev_info_t *dip, ddi_fm_error_t *derr,
const void *impl_data)
{
- /* Need to revisit when pcie fm is supported */
uint16_t pci_cfg_stat, pci_cfg_sec_stat;
+ int ret;
+ ddi_acc_handle_t hdl = *(ddi_acc_handle_t *)impl_data;
pci_ereport_post(dip, derr, &pci_cfg_stat);
pci_bdg_ereport_post(dip, derr, &pci_cfg_sec_stat);
- return (pci_bdg_check_status(dip, derr, pci_cfg_stat,
- pci_cfg_sec_stat));
+ ret = pci_bdg_check_status(dip, derr, pci_cfg_stat, pci_cfg_sec_stat);
+ /* do this till Fabric FMA is in place. */
+ pcie_clear_errors(dip, hdl);
+ return (ret);
}
/*
@@ -1667,3 +1790,277 @@ pxb_pwr_teardown(dev_info_t *dip)
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 status;
+ uint8_t cap_ptr, cap_id;
+
+ status = pci_config_get16(config_handle, PCI_CONF_STAT);
+
+ if (!(status & PCI_STAT_CAP))
+ cap_ptr = PCI_CAP_NEXT_PTR_NULL;
+ else {
+ cap_ptr = pci_config_get8(config_handle, PCI_CONF_CAP_PTR);
+ cap_ptr &= 0xFC;
+ }
+
+ while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
+ cap_id = pci_config_get8(config_handle, cap_ptr);
+
+ if (cap_id == PCI_CAP_ID_PCI_E) {
+ uint16_t slotimpl;
+
+ slotimpl = pci_config_get16(config_handle, cap_ptr +
+ PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
+ if (slotimpl)
+ if (pci_config_get32(config_handle, cap_ptr +
+ PCIE_SLOTCAP) &
+ PCIE_SLOTCAP_HP_CAPABLE)
+ break;
+ }
+
+ cap_ptr = pci_config_get8(config_handle, cap_ptr +
+ PCI_CAP_NEXT_PTR);
+ cap_ptr &= 0xFC;
+ }
+
+ return ((cap_ptr != PCI_CAP_NEXT_PTR_NULL) ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int pxb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
+{
+ uint16_t status;
+ uint8_t cap_ptr, cap_id;
+
+ status = pci_config_get16(config_handle, PCI_CONF_STAT);
+
+ if (!(status & PCI_STAT_CAP))
+ cap_ptr = PCI_CAP_NEXT_PTR_NULL;
+ else {
+ cap_ptr = pci_config_get8(config_handle, PCI_CONF_CAP_PTR);
+ cap_ptr &= 0xFC;
+ }
+
+ while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
+ cap_id = pci_config_get8(config_handle, cap_ptr);
+
+ if (cap_id == PCI_CAP_ID_PCI_HOTPLUG)
+ break;
+
+ cap_ptr = pci_config_get8(config_handle, cap_ptr +
+ PCI_CAP_NEXT_PTR);
+ cap_ptr &= 0xFC;
+ }
+
+ return ((cap_ptr != PCI_CAP_NEXT_PTR_NULL) ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+/* check if this device has PCIe link underneath. */
+static int
+ppb_pcie_device_type(pxb_devstate_t *pxb_p)
+{
+ int port_type = pxb_p->pxb_port_type;
+
+ /* No PCIe CAP regs, we are not PCIe device_type */
+ if (port_type < 0)
+ return (DDI_FAILURE);
+
+ /* check for all PCIe device_types */
+ if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
+ (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
+ return (DDI_SUCCESS);
+
+ return (DDI_FAILURE);
+}
+
+#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
+
+/*
+ * given a cap_id, return its cap_id location in config space
+ */
+static int
+pxb_get_cap(ddi_acc_handle_t config_handle, uint8_t cap_id)
+{
+ uint8_t curcap;
+ uint_t cap_id_loc;
+ uint16_t status;
+ int location = -1;
+
+ /*
+ * Need to check the Status register for ECP support first.
+ * Also please note that for type 1 devices, the
+ * offset could change. Should support type 1 next.
+ */
+ status = pci_config_get16(config_handle, PCI_CONF_STAT);
+ if (!(status & PCI_STAT_CAP)) {
+ return (-1);
+ }
+ cap_id_loc = pci_config_get8(config_handle, PCI_CONF_CAP_PTR);
+
+ /* Walk the list of capabilities */
+ while (cap_id_loc) {
+
+ curcap = pci_config_get8(config_handle, cap_id_loc);
+
+ if (curcap == cap_id) {
+ location = cap_id_loc;
+ break;
+ }
+ cap_id_loc = pci_config_get8(config_handle,
+ cap_id_loc + 1);
+ }
+ return (location);
+}
+
+static uint16_t
+pxb_find_ext_cap_reg(ddi_acc_handle_t config_handle, uint16_t cap_id)
+{
+ uint32_t hdr, hdr_next_ptr, hdr_cap_id;
+ uint16_t offset = P2ALIGN(PCIE_EXT_CAP, 4);
+
+ hdr = pci_config_get32(config_handle, offset);
+ hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
+ PCIE_EXT_CAP_NEXT_PTR_MASK;
+ hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) &
+ PCIE_EXT_CAP_ID_MASK;
+
+ while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) &&
+ (hdr_cap_id != cap_id)) {
+ offset = P2ALIGN(hdr_next_ptr, 4);
+ hdr = pci_config_get32(config_handle, offset);
+ hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
+ PCIE_EXT_CAP_NEXT_PTR_MASK;
+ hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) &
+ PCIE_EXT_CAP_ID_MASK;
+ }
+
+ if (hdr_cap_id == cap_id)
+ return (P2ALIGN(offset, 4));
+
+ return (PCIE_EXT_CAP_NEXT_PTR_NULL);
+}
+
+/* check for known bad functionality in devices */
+static int
+pxb_bad_func(pxb_devstate_t *pxb, int func)
+{
+ int ret = B_FALSE;
+
+ switch (func) {
+ /* some devices do not render MSI well. */
+ case PXB_MSI:
+ if (pxb_check_bad_devs(pxb, PXB_VENDOR_SUN) ||
+ pxb_check_bad_devs(pxb, PXB_VENDOR_PLX)) {
+
+ if (pxb->pxb_rev_id <=
+ PXB_DEVICE_PLX_BAD_MSI_REV)
+ ret = B_TRUE;
+ }
+ break;
+
+ case PXB_LINK_INIT:
+ /*
+ * some devices require certain initialization sequence so
+ * as to not get wedged.
+ */
+
+ case PXB_HOTPLUG_MSGS:
+ /*
+ * disable UR for 1.0a implementations where
+ * hotplug messages sent downstream cause URs to be
+ * detected causing error messages to be sent to the fabric.
+ */
+ if (pxb_check_bad_devs(pxb, PXB_VENDOR_SUN) ||
+ pxb_check_bad_devs(pxb, PXB_VENDOR_PLX)) {
+
+ ret = B_TRUE;
+ }
+ if (func == PXB_HOTPLUG_MSGS)
+ ret = B_TRUE;
+ break;
+
+
+ default:
+ break;
+ }
+ return (ret);
+}
+
+/* check for known bad devices from a vendor */
+static int
+pxb_check_bad_devs(pxb_devstate_t *pxb, int vend)
+{
+ int ret = B_FALSE;
+
+ switch (vend) {
+ case PXB_VENDOR_SUN:
+ if ((pxb->pxb_vendor_id == PXB_VENDOR_SUN) &&
+ ((pxb->pxb_device_id ==
+ PXB_DEVICE_PLX_PCIX) ||
+ (pxb->pxb_device_id ==
+ PXB_DEVICE_PLX_PCIE))) {
+ ret = B_TRUE;
+ }
+ break;
+ case PXB_VENDOR_PLX:
+ if ((pxb->pxb_vendor_id == PXB_VENDOR_PLX) &&
+ ((pxb->pxb_device_id ==
+ PXB_DEVICE_PLX_8532) ||
+ (pxb->pxb_device_id ==
+ PXB_DEVICE_PLX_8516))) {
+ ret = B_TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ return (ret);
+}
diff --git a/usr/src/uts/sun4/io/px/px_pci.h b/usr/src/uts/sun4/io/px/px_pci.h
index 283c635b39..d3fbe16c7e 100644
--- a/usr/src/uts/sun4/io/px/px_pci.h
+++ b/usr/src/uts/sun4/io/px/px_pci.h
@@ -114,6 +114,8 @@ typedef struct {
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;
@@ -133,6 +135,7 @@ typedef struct {
* HP support
*/
boolean_t pxb_hotplug_capable;
+ pxb_hpc_type_t pxb_hpc_type;
kmutex_t pxb_mutex;
uint_t pxb_soft_state;
@@ -147,7 +150,7 @@ typedef struct {
/* Vendor Device Id */
uint16_t pxb_vendor_id;
uint16_t pxb_device_id;
-
+ uint8_t pxb_rev_id;
} pxb_devstate_t;
/*
@@ -184,6 +187,19 @@ extern void *pxb_state;
((pxb->pxb_vendor_id == PXB_VENDOR_BCM) && \
(pxb->pxb_device_id == PXB_DEVICE_BCM5714))
+#define PXB_DEVICE_PLX_BAD_MSI_REV 0xAA /* last known bad rev for MSI */
+
+#define PXB_VENDOR_SUN 0x108E
+#define PXB_DEVICE_PLX_PCIX 0x9010
+#define PXB_DEVICE_PLX_PCIE 0x9020
+
+#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 __cplusplus
}
#endif
diff --git a/usr/src/uts/sun4/io/px/px_var.h b/usr/src/uts/sun4/io/px/px_var.h
index 23d3355530..5b1fd8d898 100644
--- a/usr/src/uts/sun4/io/px/px_var.h
+++ b/usr/src/uts/sun4/io/px/px_var.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -132,6 +132,8 @@ struct px {
int px_fm_cap;
ddi_iblock_cookie_t px_fm_ibc;
+ uint32_t px_dev_caps;
+
/* Platform specific information */
void *px_plat_p;
@@ -152,7 +154,10 @@ struct px {
#define PX_SOFT_STATE_OPEN 0x01
#define PX_SOFT_STATE_OPEN_EXCL 0x02
#define PX_SOFT_STATE_CLOSED 0x04
-#define PX_BYPASS_DMA_ALLOWED 0x10
+
+/* px_dev_caps definition */
+#define PX_BYPASS_DMA_ALLOWED 0x00000001
+#define PX_HOTPLUG_CAPABLE 0x00000002
/* px_pm_flags definitions used with interrupts and FMA code */
#define PX_PMETOACK_RECVD 0x01 /* With PME_To_ACK interrupt */
diff --git a/usr/src/uts/sun4u/sys/fc_plat.h b/usr/src/uts/sun4/sys/fc_plat.h
index 77211e30f3..77211e30f3 100644
--- a/usr/src/uts/sun4u/sys/fc_plat.h
+++ b/usr/src/uts/sun4/sys/fc_plat.h
diff --git a/usr/src/uts/sun4u/Makefile.files b/usr/src/uts/sun4u/Makefile.files
index a35156f264..88169fb6b1 100644
--- a/usr/src/uts/sun4u/Makefile.files
+++ b/usr/src/uts/sun4u/Makefile.files
@@ -103,7 +103,6 @@ GRBEEP_OBJS += grbeep.o
ADM1031_OBJS += adm1031.o
ICS951601_OBJS += ics951601.o
PPM_OBJS += ppm_subr.o ppm.o
-PCICFG_E_OBJS += pcicfg.e.o
PCF8584_OBJS += pcf8584.o
PCA9556_OBJS += pca9556.o
ADM1026_OBJS += adm1026.o
diff --git a/usr/src/uts/sun4u/Makefile.sun4u.shared b/usr/src/uts/sun4u/Makefile.sun4u.shared
index 196e611b4b..b2b4b80914 100644
--- a/usr/src/uts/sun4u/Makefile.sun4u.shared
+++ b/usr/src/uts/sun4u/Makefile.sun4u.shared
@@ -367,7 +367,6 @@ DRV_KMODS += su
DRV_KMODS += tod
DRV_KMODS += power
DRV_KMODS += epic
-DRV_KMODS += fcode
DRV_KMODS += grbeep
DRV_KMODS += pcf8584 max1617 seeprom tda8444 pca9556
DRV_KMODS += ics951601 adm1031
@@ -434,7 +433,6 @@ SYS_KMODS +=
MISC_KMODS += obpsym bootdev vis cpr platmod md5 sha1 i2c_svc
MISC_KMODS += sbd
-MISC_KMODS += fcodem fcpci pcicfg.e
MISC_KMODS += kmech_krb5
MISC_KMODS += zuluvm
diff --git a/usr/src/uts/sun4u/daktari/Makefile b/usr/src/uts/sun4u/daktari/Makefile
index 73c5ce61b3..0febbbe020 100644
--- a/usr/src/uts/sun4u/daktari/Makefile
+++ b/usr/src/uts/sun4u/daktari/Makefile
@@ -21,9 +21,10 @@
#
#
# uts/sun4u/daktari/Makefile
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+#
#ident "%Z%%M% %I% %E% SMI"
#
# This makefile drives the production of all Daktari system
@@ -85,13 +86,7 @@ install: $(ROOT_DAKTARI_DIR) $(USR_DAKTARI_DIR) \
$(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/include) \
$(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/sbin) \
$(DAKTARI_CRYPTO_LINKS) \
- .WAIT $(DAKTARI_KMODS) \
- pcicfg
-
-pcicfg: $(ROOT_PSM_MISC_DIR_64)/pcicfg.e
- -@$(RM) $(ROOT_DAKTARI_MISC_DIR_64)/$@
- $(SYMLINK) ../../../../sun4u/kernel/misc/sparcv9/pcicfg.e \
- $(ROOT_DAKTARI_MISC_DIR_64)/$@
+ .WAIT $(DAKTARI_KMODS)
$(DAKTARI_CRYPTO_LINKS): $(ROOT_DAKTARI_CRYPTO_DIR_64)
-$(RM) $(ROOT_DAKTARI_CRYPTO_DIR_64)/$@;
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c
index e4d84fc9df..2ee179b796 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,6 +42,7 @@
#include <sys/cpuvar.h>
#include <sys/ivintr.h>
#include <sys/byteorder.h>
+#include <sys/hotplug/pci/pciehpc.h>
#include <px_obj.h>
#include <pcie_pwr.h>
#include <px_regs.h>
@@ -2025,3 +2026,16 @@ px_cpr_rem_callb(px_t *px_p)
{
(void) callb_delete(px_p->px_cprcb_id);
}
+
+/*ARGSUSED*/
+int
+px_lib_hotplug_init(dev_info_t *dip, void *arg)
+{
+ return (DDI_ENOTSUP);
+}
+
+/*ARGSUSED*/
+void
+px_lib_hotplug_uninit(dev_info_t *dip)
+{
+}
diff --git a/usr/src/uts/sun4u/montecarlo/Makefile b/usr/src/uts/sun4u/montecarlo/Makefile
index fca5358f84..cf62a50216 100644
--- a/usr/src/uts/sun4u/montecarlo/Makefile
+++ b/usr/src/uts/sun4u/montecarlo/Makefile
@@ -21,9 +21,10 @@
#
#
# uts/sun4u/montecarlo/Makefile
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+#
#ident "%Z%%M% %I% %E% SMI"
#
# This makefile drives the production of all MonteCarlo system
@@ -71,12 +72,7 @@ install: $(ROOT_MONTECARLO_DIR) $(USR_MONTECARLO_DIR) \
$(USR_MONTECARLO_SBIN_DIR) \
$(USR_MONTECARLO_LIB_DIR) \
.WAIT $(MONTECARLO_KMODS) $(CLOSED_MONTECARLO_KMODS) \
- pcicfg se.conf ttymux.conf
-
-pcicfg: $(ROOT_MONTECARLO_MISC_DIR_64)
- -@$(RM) $(ROOT_MONTECARLO_MISC_DIR_64)/$@
- $(SYMLINK) ../../../../sun4u/kernel/misc/sparcv9/pcicfg.e \
- $(ROOT_MONTECARLO_MISC_DIR_64)/$@
+ se.conf ttymux.conf
se.conf: $(ROOT_MONTECARLO_DRV_DIR)
-@$(RM) $(ROOT_MONTECARLO_DRV_DIR)/$@
diff --git a/usr/src/uts/sun4u/px/Makefile b/usr/src/uts/sun4u/px/Makefile
index 972b5a41fb..8364572ae6 100644
--- a/usr/src/uts/sun4u/px/Makefile
+++ b/usr/src/uts/sun4u/px/Makefile
@@ -22,7 +22,7 @@
#
# uts/sun4u/px/Makefile
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -76,7 +76,7 @@ CFLAGS += -dalign
#
# Dependency
#
-LDFLAGS += -dy -Nmisc/busra -Nmisc/pcie
+LDFLAGS += -dy -Nmisc/busra -Nmisc/pcie -Nmisc/pcihp -Nmisc/pciehpc
#
# Default build targets.
diff --git a/usr/src/uts/sun4u/serengeti/Makefile b/usr/src/uts/sun4u/serengeti/Makefile
index a6ccb23ab5..7f532317bc 100644
--- a/usr/src/uts/sun4u/serengeti/Makefile
+++ b/usr/src/uts/sun4u/serengeti/Makefile
@@ -21,9 +21,10 @@
#
#
# uts/sun4u/serengeti/Makefile
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 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 sun4u serengeti platform
@@ -86,13 +87,7 @@ install: $(ROOT_SERENGETI_DIR) $(USR_SERENGETI_DIR) \
$(USR_SERENGETI_LIB_DIR) \
$(SERENGETI_CRYPTO_LINKS) \
genassym unix .WAIT \
- $(SERENGETI_KMODS) $(CLOSED_SERENGETI_KMODS) \
- pcicfg
-
-pcicfg: $(ROOT_PSM_MISC_DIR_64)/pcicfg.e $(ROOT_SERENGETI_MISC_DIR_64)
- -@$(RM) $(ROOT_SERENGETI_MISC_DIR_64)/$@
- $(SYMLINK) ../../../../sun4u/kernel/misc/sparcv9/pcicfg.e \
- $(ROOT_SERENGETI_MISC_DIR_64)/$@
+ $(SERENGETI_KMODS) $(CLOSED_SERENGETI_KMODS)
genassym unix $(SERENGETI_KMODS): FRC
@cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET)
diff --git a/usr/src/uts/sun4u/starcat/Makefile b/usr/src/uts/sun4u/starcat/Makefile
index a22852614f..afdb3d7244 100644
--- a/usr/src/uts/sun4u/starcat/Makefile
+++ b/usr/src/uts/sun4u/starcat/Makefile
@@ -22,9 +22,10 @@
#
#pragma ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+#
# This makefile drives the production of the sun4u starcat platform
# module.
#
@@ -86,12 +87,7 @@ install: $(ROOT_STARCAT_DIR) $(USR_STARCAT_DIR) \
$(USR_STARCAT_LIB_DIR) \
$(STARCAT_CRYPTO_LINKS) \
genassym unix .WAIT $(STARCAT_CPU_KMODS) \
- $(STARCAT_KMODS) $(CLOSED_STARCAT_KMODS) pcicfg
-
-pcicfg: $(ROOT_PSM_MISC_DIR_64)/pcicfg.e $(ROOT_STARCAT_MISC_DIR_64)
- -@$(RM) $(ROOT_STARCAT_MISC_DIR_64)/$@
- $(SYMLINK) ../../../../sun4u/kernel/misc/sparcv9/pcicfg.e \
- $(ROOT_STARCAT_MISC_DIR_64)/$@
+ $(STARCAT_KMODS) $(CLOSED_STARCAT_KMODS)
genassym unix $(STARCAT_KMODS) $(STARCAT_CPU_KMODS): FRC
@cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET)
diff --git a/usr/src/uts/sun4u/sys/Makefile b/usr/src/uts/sun4u/sys/Makefile
index 21c7f3eca7..0de14065cc 100644
--- a/usr/src/uts/sun4u/sys/Makefile
+++ b/usr/src/uts/sun4u/sys/Makefile
@@ -50,6 +50,7 @@ SUN4_HDRS= \
eeprom.h \
errclassify.h \
fcode.h \
+ fc_plat.h \
idprom.h \
intr.h \
intreg.h \
@@ -80,7 +81,6 @@ HDRS= \
envctrl_ue250.h \
envctrl_ue450.h \
gpio_87317.h \
- fc_plat.h \
iocache.h \
iommu.h \
machasi.h \
diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.c b/usr/src/uts/sun4v/io/px/px_lib4v.c
index 298e832aed..ed5b463c84 100644
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -40,6 +40,7 @@
#include <sys/hypervisor_api.h>
#include <px_obj.h>
#include <sys/machsystm.h>
+#include <sys/hotplug/pci/pcihp.h>
#include "px_lib4v.h"
#include "px_err.h"
@@ -72,6 +73,14 @@ px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl)
ddi_prop_free(rp);
+ /*
+ * hotplug implementation requires this property to be associated with
+ * any indirect PCI config access services
+ */
+ (void) ddi_prop_update_int(makedevice(ddi_driver_major(dip),
+ PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), PCIHP_DEVCTL_MINOR)), dip,
+ PCI_BUS_CONF_MAP_PROP, 1);
+
DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl);
return (DDI_SUCCESS);
@@ -83,6 +92,10 @@ px_lib_dev_fini(dev_info_t *dip)
{
DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip);
+ (void) ddi_prop_remove(makedevice(ddi_driver_major(dip),
+ PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), PCIHP_DEVCTL_MINOR)), dip,
+ PCI_BUS_CONF_MAP_PROP);
+
return (DDI_SUCCESS);
}
@@ -1824,6 +1837,19 @@ px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
(bdf << PX_RA_BDF_SHIFT), offset, 4, wdata);
}
+/*ARGSUSED*/
+int
+px_lib_hotplug_init(dev_info_t *dip, void *arg)
+{
+ return (DDI_ENOTSUP);
+}
+
+/*ARGSUSED*/
+void
+px_lib_hotplug_uninit(dev_info_t *dip)
+{
+}
+
/* Dummy cpr add callback */
/*ARGSUSED*/
void
diff --git a/usr/src/uts/sun4v/px/Makefile b/usr/src/uts/sun4v/px/Makefile
index ee1eb57e5d..0ae8987576 100644
--- a/usr/src/uts/sun4v/px/Makefile
+++ b/usr/src/uts/sun4v/px/Makefile
@@ -22,7 +22,7 @@
#
# uts/sun4v/px/Makefile
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -78,7 +78,7 @@ CFLAGS += -dalign
# Dependency
#
-LDFLAGS += -dy -Nmisc/busra -Nmisc/pcie
+LDFLAGS += -dy -Nmisc/busra -Nmisc/pcie -Nmisc/pciehpc -Nmisc/pcihp
# Default build targets.
#