summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkrishnae <none@none>2008-03-28 12:11:52 -0700
committerkrishnae <none@none>2008-03-28 12:11:52 -0700
commiteae2e508a8e70b1ec407b10bd068c080651bbe5c (patch)
tree997c76ef99a46a31e13e027aae4085ea65f05e1d
parentc45cbb52ab3d9544ffb196de6b0a1c5f332c93a4 (diff)
downloadillumos-joyent-eae2e508a8e70b1ec407b10bd068c080651bbe5c.tar.gz
PSARC 2008/157 PCIe Fabric portfolio for SPARC and x86
6510830 SPARC and x86 PCIe IO error handling should be merged --HG-- rename : usr/src/uts/intel/io/pciex/pcie_error.c => deleted_files/usr/src/uts/intel/io/pciex/pcie_error.c rename : usr/src/uts/intel/io/pciex/pcie_error.h => deleted_files/usr/src/uts/intel/io/pciex/pcie_error.h rename : deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/Makefile => usr/src/cmd/fm/modules/common/fabric-xlate/Makefile rename : deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c => usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c rename : deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf => usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf
-rw-r--r--deleted_files/usr/src/uts/intel/io/pciex/pcie_error.c (renamed from usr/src/uts/intel/io/pciex/pcie_error.c)0
-rw-r--r--deleted_files/usr/src/uts/intel/io/pciex/pcie_error.h (renamed from usr/src/uts/intel/io/pciex/pcie_error.h)0
-rw-r--r--usr/src/cmd/fm/eversholt/files/common/pciex.esc13
-rw-r--r--usr/src/cmd/fm/eversholt/files/sparc/sun4/fire.esc168
-rw-r--r--usr/src/cmd/fm/eversholt/files/sparc/sun4v/n2piu.esc34
-rw-r--r--usr/src/cmd/fm/modules/common/Makefile5
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/Makefile (renamed from deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/Makefile)0
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c (renamed from deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c)0
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf (renamed from deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf)0
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_2xml.c23
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h1
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_parse.h1
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus/did_props.c26
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus/did_props.h3
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_com2
-rw-r--r--usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c11
-rw-r--r--usr/src/uts/common/io/pcie.c1008
-rw-r--r--usr/src/uts/common/io/pcie_fault.c3444
-rw-r--r--usr/src/uts/common/os/ddifm.c12
-rw-r--r--usr/src/uts/common/os/pcifm.c66
-rw-r--r--usr/src/uts/common/os/sunndi.c40
-rw-r--r--usr/src/uts/common/sys/ddi_impldefs.h21
-rw-r--r--usr/src/uts/common/sys/ddifm_impl.h4
-rw-r--r--usr/src/uts/common/sys/fm/io/pci.h5
-rw-r--r--usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h15
-rw-r--r--usr/src/uts/common/sys/pci.h3
-rw-r--r--usr/src/uts/common/sys/pcie.h6
-rw-r--r--usr/src/uts/common/sys/pcie_impl.h450
-rw-r--r--usr/src/uts/common/sys/sunddi.h3
-rw-r--r--usr/src/uts/common/sys/sunndi.h12
-rw-r--r--usr/src/uts/i86pc/Makefile.files4
-rw-r--r--usr/src/uts/i86pc/io/pci/pci.c9
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe.c139
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe_misc.c29
-rw-r--r--usr/src/uts/i86pc/os/ddi_impl.c12
-rw-r--r--usr/src/uts/i86xpv/Makefile.files4
-rw-r--r--usr/src/uts/intel/io/pci/pci_pci.c85
-rw-r--r--usr/src/uts/intel/io/pciex/pcie_pci.c129
-rw-r--r--usr/src/uts/intel/pci_pci/Makefile4
-rw-r--r--usr/src/uts/sun4/io/pcicfg.e.c2
-rw-r--r--usr/src/uts/sun4/io/px/pcie_pwr.c64
-rw-r--r--usr/src/uts/sun4/io/px/px.c93
-rw-r--r--usr/src/uts/sun4/io/px/px_fm.c624
-rw-r--r--usr/src/uts/sun4/io/px/px_fm.h19
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.c135
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.h6
-rw-r--r--usr/src/uts/sun4/io/px/px_space.c82
-rw-r--r--usr/src/uts/sun4/io/px/px_space.h19
-rw-r--r--usr/src/uts/sun4/io/px/px_util.c26
-rw-r--r--usr/src/uts/sun4/io/px/px_var.h10
-rw-r--r--usr/src/uts/sun4u/io/pci/pci_pci.c6
-rw-r--r--usr/src/uts/sun4u/io/px/px_err.c123
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c45
-rw-r--r--usr/src/uts/sun4v/io/px/px_err.c235
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.c52
55 files changed, 4478 insertions, 2854 deletions
diff --git a/usr/src/uts/intel/io/pciex/pcie_error.c b/deleted_files/usr/src/uts/intel/io/pciex/pcie_error.c
index dd68840476..dd68840476 100644
--- a/usr/src/uts/intel/io/pciex/pcie_error.c
+++ b/deleted_files/usr/src/uts/intel/io/pciex/pcie_error.c
diff --git a/usr/src/uts/intel/io/pciex/pcie_error.h b/deleted_files/usr/src/uts/intel/io/pciex/pcie_error.h
index 396aaab3a5..396aaab3a5 100644
--- a/usr/src/uts/intel/io/pciex/pcie_error.h
+++ b/deleted_files/usr/src/uts/intel/io/pciex/pcie_error.h
diff --git a/usr/src/cmd/fm/eversholt/files/common/pciex.esc b/usr/src/cmd/fm/eversholt/files/common/pciex.esc
index e9de09d32f..f68ba8e3de 100644
--- a/usr/src/cmd/fm/eversholt/files/common/pciex.esc
+++ b/usr/src/cmd/fm/eversholt/files/common/pciex.esc
@@ -151,7 +151,8 @@ event fault.io.pciex.device-invreq@pciexbus/pciexdev/pciexfn,
FITrate=PCIEX_DEV_INV_FIT, FRU=pciexbus/pciexdev,
ASRU=pciexbus/pciexdev/pciexfn;
-event upset.io.pciex.device-invreq@pciexrc;
+event fault.io.pciex.device-invreq@pciexrc,
+ FITrate=PCIEX_RC_FIT, FRU=pciexrc, ASRU=pciexrc;
event fault.io.pciex.device-noresp@pciexbus/pciexdev/pciexfn,
FITrate=PCIEX_DEV_NR_FIT, FRU=pciexbus/pciexdev,
@@ -373,7 +374,7 @@ event error.io.pciex.fatlink@pciexrc/pciexbus/pciexdev/pciexfn;
prop fault.io.pciex.device-noresp@pciexrc (1)->
error.io.pciex.nr-d@pciexrc/pciexbus<>/pciexdev<>/pciexfn<>;
-prop upset.io.pciex.device-invreq@pciexrc (1)->
+prop fault.io.pciex.device-invreq@pciexrc (1)->
error.io.pciex.badreq-d@pciexrc/pciexbus<>/pciexdev<>/pciexfn<>;
prop fault.io.pciex.device-interr@pciexrc (1)->
@@ -2127,13 +2128,15 @@ prop error.io.pci.perr-dr-u@pciexbus/pciexdev/pciexfn/pcibus/pcidev/pcifn (1)->
* If the bridge receives data with bad ecc/parity from pci/pci-x, it will
* propagate onto pci express as a poisoned tlp
*/
-prop error.io.pci.dpdata-dr-u@pciexbus/pciexdev/pciexfn/pcibus/pcidev/pcifn (3)->
+prop error.io.pci.dpdata-dr-u@pciexbus/pciexdev/pciexfn/pcibus/pcidev/pcifn (2)->
ereport.io.pci.sec-dpe@pciexbus/pciexdev/pciexfn,
- ereport.io.pci.sec-mdpe@pciexbus/pciexdev/pciexfn,
error.io.pciex.poiscomp-u@pciexbus/pciexdev/pciexfn;
prop error.io.pci.dpdata-dr-u@pciexbus/pciexdev/pciexfn/pcibus/pcidev/pcifn (0)->
- error.io.pciex.nonfatal@pciexbus/pciexdev/pciexfn,
+ error.io.pciex.nonfatal@pciexbus/pciexdev/pciexfn;
+
+prop error.io.pci.dpdata-dr-u@pciexbus/pciexdev/pciexfn/pcibus/pcidev/pcifn (1)->
+ ereport.io.pci.sec-mdpe@pciexbus/pciexdev/pciexfn,
ereport.io.pci.mdpe@pciexbus/pciexdev/pciexfn;
prop error.io.pci.dpdata-dw-u@pciexbus/pciexdev/pciexfn/pcibus/pcidev/pcifn (1)->
diff --git a/usr/src/cmd/fm/eversholt/files/sparc/sun4/fire.esc b/usr/src/cmd/fm/eversholt/files/sparc/sun4/fire.esc
index 134f279f04..63fb5e5db0 100644
--- a/usr/src/cmd/fm/eversholt/files/sparc/sun4/fire.esc
+++ b/usr/src/cmd/fm/eversholt/files/sparc/sun4/fire.esc
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -58,6 +58,11 @@
#define MATCH_CE ((payloadprop("severity") == PF_CE) || \
(payloadprop("severity") == (PF_CE | PF_NO_ERROR)))
+
+#define MATCH_UNRECOGNIZED ((payloadprop("sysino") == 0) && \
+ (payloadprop("ehdl") == 0) && \
+ (payloadprop("stick") == 0))
+
/*
* Test for primary or secondary ereports
*/
@@ -113,8 +118,6 @@ event ereport.io.fire.jbc.wr_dpe@hostbridge/pciexrc{within(5s)};
/***************
* DMC ereports
***************/
-event ereport.io.fire.dmc.byp_err@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.dmc.byp_oor@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.cor_not_en@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.eq_not_en@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.eq_over@hostbridge/pciexrc{within(5s)};
@@ -130,11 +133,8 @@ event ereport.io.fire.dmc.tbw_dpe@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.tbw_err@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.tbw_ude@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.trn_err@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.dmc.trn_oor@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.ttc_cae@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.dmc.ttc_dpe@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.dmc.tte_inv@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.dmc.tte_prt@hostbridge/pciexrc{within(5s)};
/***************
* TLU Other Event ereports
@@ -143,11 +143,7 @@ event ereport.io.fire.pec.crs@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.edp@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.ehp@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.eip@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.pec.emp@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.pec.epe@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.pec.ero@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.erp@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.pec.eru@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.ihb_pe@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.iip@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.ldn@hostbridge/pciexrc{within(5s)};
@@ -155,27 +151,6 @@ event ereport.io.fire.pec.lin@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.lrs@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.lup@hostbridge/pciexrc{within(5s)};
event ereport.io.fire.pec.mrc@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.pec.ruc@hostbridge/pciexrc{within(5s)};
-event ereport.io.fire.pec.wuc@hostbridge/pciexrc{within(5s)};
-
-/***************
- * TLU Uncorrectable and Correctable ereports
- ***************/
-event ereport.io.fire.pec.ur@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.uc@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.cto@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.rof@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.mfc@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.mfp@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.pois@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.fcp@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.dlp@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.te@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.re@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.bdp@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.btp@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.rnr@hostbridge/pciexrc {within(5s)};
-event ereport.io.fire.pec.rto@hostbridge/pciexrc {within(5s)};
/***************
* Fire Fabric ereport
@@ -252,7 +227,7 @@ event error.io.fire.dmc.bad_state@hostbridge/pciexrc;
prop fault.io.fire.sw-epkt@hostbridge/pciexrc,
fault.io.fire.fw-epkt@hostbridge/pciexrc,
fault.io.fire.sw-fw-mismatch@hostbridge/pciexrc->(A)
- ereport.io.fire.epkt@hostbridge/pciexrc;
+ ereport.io.fire.epkt@hostbridge/pciexrc { MATCH_UNRECOGNIZED };
prop fault.io.fire.hb.sw-config@hostbridge/pciexrc (0)->
error.io.fire.jbc.driver@hostbridge/pciexrc;
@@ -414,7 +389,6 @@ prop error.io.fire.dmc.driver@hostbridge/pciexrc (1)->
* The px driver should not have been in this state. Defect the px driver.
***************/
event error.io.fire.dmc.bad_state-mmu@hostbridge/pciexrc;
-event error.io.fire.dmc.bad_state-no_fab@hostbridge/pciexrc;
prop error.io.fire.dmc.bad_state@hostbridge/pciexrc (1)->
ereport.io.fire.dmc.cor_not_en@hostbridge/pciexrc,
@@ -423,14 +397,7 @@ prop error.io.fire.dmc.bad_state@hostbridge/pciexrc (1)->
ereport.io.fire.dmc.msi_not_en@hostbridge/pciexrc,
ereport.io.fire.dmc.nonfatal_not_en@hostbridge/pciexrc,
ereport.io.fire.dmc.pmeack_not_en@hostbridge/pciexrc,
- ereport.io.fire.dmc.pmpme_not_en@hostbridge/pciexrc,
- error.io.fire.dmc.bad_state-no_fab@hostbridge/pciexrc;
-
-prop error.io.fire.dmc.bad_state-no_fab@hostbridge/pciexrc (1)->
- error.io.fire.dmc.bad_state-mmu@hostbridge/pciexrc;
-
-prop error.io.fire.dmc.bad_state-no_fab@hostbridge/pciexrc (1)->
- error.io.fire.fabric-sib@hostbridge/pciexrc;
+ ereport.io.fire.dmc.pmpme_not_en@hostbridge/pciexrc;
prop error.io.fire.dmc.bad_state-mmu@hostbridge/pciexrc (1)->
ereport.io.fire.dmc.tbw_dme@hostbridge/pciexrc,
@@ -452,50 +419,16 @@ prop error.io.fire.dmc.asic@hostbridge/pciexrc (1)->
* -------------
* Fire asic error.
***************/
-event error.io.fire.dmc.bad_parity-no_fab@hostbridge/pciexrc;
event error.io.fire.dmc.bad_parity-mmu@hostbridge/pciexrc;
prop error.io.fire.dmc.bad_parity@hostbridge/pciexrc (1)->
- ereport.io.fire.dmc.msi_par_err@hostbridge/pciexrc,
- error.io.fire.dmc.bad_parity-no_fab@hostbridge/pciexrc;
-
-prop error.io.fire.dmc.bad_parity-no_fab@hostbridge/pciexrc (1)->
- error.io.fire.dmc.bad_parity-mmu@hostbridge/pciexrc;
-
-prop error.io.fire.dmc.bad_parity-no_fab@hostbridge/pciexrc (1)->
- error.io.fire.fabric-sib@hostbridge/pciexrc;
+ ereport.io.fire.dmc.msi_par_err@hostbridge/pciexrc;
prop error.io.fire.dmc.bad_parity-mmu@hostbridge/pciexrc (1)->
ereport.io.fire.dmc.tbw_dpe@hostbridge/pciexrc,
ereport.io.fire.dmc.tbw_ude@hostbridge/pciexrc,
ereport.io.fire.dmc.ttc_dpe@hostbridge/pciexrc;
-
-/***************
- * Bad DMA requests
- * -------------
- * Errors caused by bad leaf drivers, which will end up sending fire.fabric
- * ereport, which will be diagnosed in itself. Do not diagnose the bad DMA
- * requests and rely on the fire.fabric error being there. Propagate to a
- * fault.io.fire.pciex.device.
- *
- * Atleast 1 PCIe device will be faulted. PCI devices will also be if the
- * DMA came from a PCI device.
- ***************/
-event error.io.fire.dmc.fabric_diag@hostbridge/pciexrc;
-
-prop error.io.fire.dmc.fabric_diag@hostbridge/pciexrc(0) ->
- ereport.io.fire.dmc.byp_err@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.fire.dmc.byp_oor@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.fire.dmc.trn_oor@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.fire.dmc.tte_inv@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.fire.dmc.tte_prt@hostbridge/pciexrc{ IS_PRIMARY };
-
-prop error.io.fire.fabric@pciexbus/pciexdev/pciexfn (0) ->
- error.io.fire.dmc.fabric_diag@hostbridge/pciexrc {
- is_under(hostbridge/pciexrc, pciexbus/pciexdev/pciexfn)
- };
-
/***************
* Malformed MSI
* -------------
@@ -556,21 +489,14 @@ prop fault.io.fire.pci.device@pcibus[b]/pcidev[d]/pcifn[0] (0) ->
event error.io.fire.dmc.secondary@hostbridge/pciexrc;
prop error.io.fire.dmc.secondary@hostbridge/pciexrc (0) ->
- ereport.io.fire.dmc.byp_err@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.dmc.byp_oor@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.dmc.msi_mal_err@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.dmc.trn_oor@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.dmc.tte_inv@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.dmc.tte_prt@hostbridge/pciexrc{ IS_SECONDARY };
+ ereport.io.fire.dmc.msi_mal_err@hostbridge/pciexrc{ IS_SECONDARY };
/******************************
* PEC Rules Begin Here *
******************************/
event error.io.fire.pec.buffer-parity@hostbridge/pciexrc;
-event error.io.fire.pec.misc-egress@hostbridge/pciexrc ;
event error.io.fire.pec.adjacentnode@hostbridge/pciexrc ;
-event error.io.fire.pec.fabric_error@hostbridge/pciexrc ;
/***************
* Fire PX SW error
@@ -589,7 +515,6 @@ prop fault.io.fire.pec.sw-algorithm@hostbridge/pciexrc (0) ->
***************/
prop error.io.fire.pec.asic@hostbridge/pciexrc (1)->
error.io.fire.pec.buffer-parity@hostbridge/pciexrc,
- error.io.fire.pec.misc-egress@hostbridge/pciexrc,
error.io.fire.pec.adjacentnode@hostbridge/pciexrc;
prop error.io.fire.pec.buffer-parity@hostbridge/pciexrc (1) ->
@@ -600,37 +525,6 @@ prop error.io.fire.pec.buffer-parity@hostbridge/pciexrc (1) ->
ereport.io.fire.pec.ihb_pe@hostbridge/pciexrc,
ereport.io.fire.pec.iip@hostbridge/pciexrc;
-prop error.io.fire.pec.misc-egress@hostbridge/pciexrc (1) ->
- ereport.io.fire.pec.emp@hostbridge/pciexrc,
- ereport.io.fire.pec.epe@hostbridge/pciexrc,
- ereport.io.fire.pec.ero@hostbridge/pciexrc,
- ereport.io.fire.pec.eru@hostbridge/pciexrc;
-
-/***************
- * Bad IO requests
- * -------------
- * Errors caused by bad leaf drivers, which will end up sending fire.fabric
- * ereport, which will be diagnosed in itself. Do not diagnose the bad IO
- * requests and rely on the fire.fabric error being there. Propagate to a
- * fault.io.fire.pciex.device.
- *
- * Atleast 1 PCIe device will be fauled. PCI will be fault as well if the
- * DMA came from a PCI device.
- ***************/
-event error.io.fire.pec.fabric_diag@hostbridge/pciexrc;
-
-prop error.io.fire.pec.fabric_diag@hostbridge/pciexrc(1) ->
- ereport.io.fire.pec.wuc@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.fire.pec.ruc@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.fire.pec.pois@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.fire.pec.ur@hostbridge/pciexrc{ IS_PRIMARY };
-
-
-prop error.io.fire.fabric@pciexbus/pciexdev/pciexfn (0) ->
- error.io.fire.pec.fabric_diag@hostbridge/pciexrc {
- is_under(hostbridge/pciexrc, pciexbus/pciexdev/pciexfn)
- };
-
/***************
* Failed Links
* -------------
@@ -680,39 +574,6 @@ prop fault.io.fire.pciex.device@hostbridge/pciexrc/pciexbus/pciexdev/pciexfn
prop error.io.fire.pec.adjacentnode@hostbridge/pciexrc (0) ->
ereport.io.fire.link-events-trip@hostbridge/pciexrc;
-/***************
- * Undiagnosible Secondary Errors
- * -------------
- * Secondary errors of the ereport that the device is at fault.
- * Undiagnosed the secondary errors since the payload is invalid.
- ***************/
-event error.io.fire.pec.secondary@hostbridge/pciexrc;
-
-prop error.io.fire.pec.secondary@hostbridge/pciexrc (1) ->
- ereport.io.fire.pec.ruc@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.pec.wuc@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.pec.pois@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.fire.pec.ur@hostbridge/pciexrc{ IS_SECONDARY };
-
-/*
- * For logging purpose only.
- * The Fire nexus driver generates equivalent pciex ereports for the
- * common pciex rules to diagnose.
- */
-prop error.io.fire.pec.fabric_error@hostbridge/pciexrc (0) ->
- ereport.io.fire.pec.bdp@hostbridge/pciexrc,
- ereport.io.fire.pec.btp@hostbridge/pciexrc,
- ereport.io.fire.pec.cto@hostbridge/pciexrc,
- ereport.io.fire.pec.dlp@hostbridge/pciexrc,
- ereport.io.fire.pec.fcp@hostbridge/pciexrc,
- ereport.io.fire.pec.mfc@hostbridge/pciexrc,
- ereport.io.fire.pec.mfp@hostbridge/pciexrc,
- ereport.io.fire.pec.re@hostbridge/pciexrc,
- ereport.io.fire.pec.rnr@hostbridge/pciexrc,
- ereport.io.fire.pec.rof@hostbridge/pciexrc,
- ereport.io.fire.pec.rto@hostbridge/pciexrc,
- ereport.io.fire.pec.te@hostbridge/pciexrc,
- ereport.io.fire.pec.uc@hostbridge/pciexrc;
/******************************
* Fabric Rules Begin Here *
@@ -786,9 +647,6 @@ event error.io.fire.dmc.nodiag@hostbridge/pciexrc;
prop error.io.fire.dmc.nodiag@hostbridge/pciexrc (1)->
ereport.io.fire.dmc.tbw_err@hostbridge/pciexrc;
-prop error.io.fire.dmc.nodiag@hostbridge/pciexrc (1)->
- error.io.fire.fabric-sib@hostbridge/pciexrc;
-
prop upset.io.fire.nodiag@hostbridge/pciexrc (0)->
ereport.io.fire.jbc.ce_asyn@hostbridge/pciexrc, /* CPU */
ereport.io.fire.jbc.jbe@hostbridge/pciexrc, /* CPU */
@@ -798,8 +656,6 @@ prop upset.io.fire.nodiag@hostbridge/pciexrc (0)->
ereport.io.fire.jbc.unsol_rd@hostbridge/pciexrc, /* CPU */
ereport.io.fire.pec.lin@hostbridge/pciexrc,
ereport.io.fire.pec.lup@hostbridge/pciexrc,
- error.io.fire.pec.fabric_error@hostbridge/pciexrc,
- error.io.fire.pec.secondary@hostbridge/pciexrc,
error.io.fire.dmc.nodiag@hostbridge/pciexrc,
- error.io.fire.dmc.fabric_diag@hostbridge/pciexrc,
- error.io.fire.dmc.secondary@hostbridge/pciexrc;
+ error.io.fire.dmc.secondary@hostbridge/pciexrc,
+ ereport.io.fire.epkt@hostbridge/pciexrc { !MATCH_UNRECOGNIZED };
diff --git a/usr/src/cmd/fm/eversholt/files/sparc/sun4v/n2piu.esc b/usr/src/cmd/fm/eversholt/files/sparc/sun4v/n2piu.esc
index 8687385196..23fb08e460 100644
--- a/usr/src/cmd/fm/eversholt/files/sparc/sun4v/n2piu.esc
+++ b/usr/src/cmd/fm/eversholt/files/sparc/sun4v/n2piu.esc
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -87,16 +87,6 @@ event upset.io.fire.nodiag@hostbridge;
/*
* Additional "DMC" errors to fire.
- * Driver errors.
- */
-event ereport.io.n2.dmu.sun4v_va_oor@hostbridge/pciexrc{within(5s)};
-event ereport.io.n2.dmu.sun4v_adj_va_uf@hostbridge/pciexrc{within(5s)};
-event ereport.io.n2.dmu.sun4v_inv_pg_sz@hostbridge/pciexrc{within(5s)};
-event ereport.io.n2.dmu.sun4v_key_err@hostbridge/pciexrc{within(5s)};
-event ereport.io.n2.dmu.iotsbdesc_inv@hostbridge/pciexrc{within(5s)};
-
-/*
- * Additional "DMC" errors to fire.
* N2 asic parity error
*/
event ereport.io.n2.dmu.iotsbdesc_dpe@hostbridge/pciexrc{within(5s)};
@@ -161,28 +151,6 @@ event ereport.io.device.intern_corr@niu/niufn{within(5s)};
event ereport.io.device.intern_uncorr@niu/niufn{within(5s)};
event ereport.io.device.nf-device@niu/niufn;
-
-/*
- * Bad DMA requests
- */
-event error.io.fire.dmc.fabric_diag@hostbridge/pciexrc;
-
-prop error.io.fire.dmc.fabric_diag@hostbridge/pciexrc(0) ->
- ereport.io.n2.dmu.iotsbdesc_inv@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.n2.dmu.sun4v_adj_va_uf@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.n2.dmu.sun4v_inv_pg_sz@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.n2.dmu.sun4v_key_err@hostbridge/pciexrc{ IS_PRIMARY },
- ereport.io.n2.dmu.sun4v_va_oor@hostbridge/pciexrc{ IS_PRIMARY };
-
-event error.io.fire.dmc.secondary@hostbridge/pciexrc;
-
-prop error.io.fire.dmc.secondary@hostbridge/pciexrc (0) ->
- ereport.io.n2.dmu.iotsbdesc_inv@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.n2.dmu.sun4v_adj_va_uf@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.n2.dmu.sun4v_inv_pg_sz@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.n2.dmu.sun4v_key_err@hostbridge/pciexrc{ IS_SECONDARY },
- ereport.io.n2.dmu.sun4v_va_oor@hostbridge/pciexrc{ IS_SECONDARY };
-
/*
* Fault at the adjacent node which is right below the Fire ASIC
*/
diff --git a/usr/src/cmd/fm/modules/common/Makefile b/usr/src/cmd/fm/modules/common/Makefile
index 00d3798741..5daa88c01c 100644
--- a/usr/src/cmd/fm/modules/common/Makefile
+++ b/usr/src/cmd/fm/modules/common/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -35,6 +35,7 @@ SUBDIRS = cpumem-retire \
sp-monitor \
syslog-msgs \
zfs-diagnosis \
- zfs-retire
+ zfs-retire \
+ fabric-xlate
include ../../Makefile.subdirs
diff --git a/deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/Makefile b/usr/src/cmd/fm/modules/common/fabric-xlate/Makefile
index 8de8852eda..8de8852eda 100644
--- a/deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/Makefile
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/Makefile
diff --git a/deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c
index ed3c7e8d0f..ed3c7e8d0f 100644
--- a/deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c
diff --git a/deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf
index dfc492e237..dfc492e237 100644
--- a/deleted_files/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.conf
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c b/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c
index 088a290849..0f3e69ae70 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -107,7 +107,7 @@ txml_print_prop(topo_hdl_t *thp, FILE *fp, topo_propval_t *pv)
{
int err;
char *fmri = NULL;
- char vbuf[INT64BUFSZ], tbuf[10], *pval;
+ char vbuf[INT64BUFSZ], tbuf[10], *pval, *aval;
nvpair_t *nvp;
nvp = nvlist_next_nvpair(pv->tp_val, NULL);
@@ -169,6 +169,25 @@ txml_print_prop(topo_hdl_t *thp, FILE *fp, topo_propval_t *pv)
(void) snprintf(tbuf, 10, "%s", FMRI);
break;
}
+ case TOPO_TYPE_UINT32_ARRAY: {
+ uint32_t *val;
+ uint_t nelem, i;
+
+ (void) nvpair_value_uint32_array(nvp, &val, &nelem);
+
+ if (nelem > 0) {
+ aval = calloc((nelem*9-1), sizeof (uchar_t));
+
+ (void) sprintf(aval, "0x%x", val[0]);
+ for (i = 1; i < nelem; i++) {
+ (void) sprintf(vbuf, " 0x%x", val[i]);
+ (void) strcat(aval, vbuf);
+ }
+ (void) snprintf(tbuf, 10, "%s", UInt32_Arr);
+ pval = aval;
+ }
+ break;
+ }
}
begin_end_element(fp, Propval, Name, pv->tp_name, Type, tbuf,
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
index 83eeb991e8..ba49a8bbb0 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -91,6 +91,7 @@ extern "C" {
#define TOPO_PCI_EXCAP "extended-capabilities"
#define TOPO_PCI_BDF "BDF"
#define TOPO_PCI_CLASS "class-code"
+#define TOPO_PCI_AADDR "assigned-addresses"
#ifdef __cplusplus
}
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_parse.h b/usr/src/lib/fm/topo/libtopo/common/topo_parse.h
index f60bf6ec21..bed769dac0 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_parse.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_parse.h
@@ -155,6 +155,7 @@ typedef struct tf_info {
#define Topology "topology"
#define Type "type"
#define UInt32 "uint32"
+#define UInt32_Arr "uint32arr"
#define UInt64 "uint64"
#define Value "value"
#define Verify "verify"
diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/did_props.c b/usr/src/lib/fm/topo/modules/common/pcibus/did_props.c
index 1cd14cb709..07406fdb4e 100644
--- a/usr/src/lib/fm/topo/modules/common/pcibus/did_props.c
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/did_props.c
@@ -64,6 +64,8 @@ static int maybe_di_chars_copy(tnode_t *, did_t *,
const char *, const char *, const char *);
static int maybe_di_uint_to_str(tnode_t *, did_t *,
const char *, const char *, const char *);
+static int AADDR_set(tnode_t *, did_t *,
+ const char *, const char *, const char *);
/*
* Arrays of "property translation routines" to set the properties a
@@ -101,6 +103,7 @@ txprop_t Fn_common_props[] = {
{ NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set },
{ DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str },
{ DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str },
+ { DI_AADDRPROP, &pci_pgroup, TOPO_PCI_AADDR, AADDR_set },
{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
@@ -792,6 +795,29 @@ maybe_di_uint_to_str(tnode_t *tn, did_t *pd,
return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
}
+static int
+AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
+ const char *tpnm)
+{
+ topo_mod_t *mp;
+ uchar_t *typbuf;
+ int sz = -1;
+ int err, e;
+
+ if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
+ return (0);
+
+ mp = did_mod(pd);
+
+ e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE,
+ /*LINTED*/
+ (uint32_t *)typbuf, sz/4, &err);
+
+ if (e != 0)
+ return (topo_mod_seterrno(mp, err));
+ return (0);
+}
+
/*ARGSUSED*/
static int
BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h b/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h
index 8314bf0131..af2e2a5316 100644
--- a/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -69,6 +69,7 @@ typedef struct txprop {
#define DI_CCPROP "class-code"
#define DI_PHYSPROP "physical-slot#"
#define DI_SLOTPROP "slot-names"
+#define DI_AADDRPROP "assigned-addresses"
extern int did_props_set(tnode_t *, did_t *, txprop_t[], int);
diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_com b/usr/src/pkgdefs/SUNWfmd/prototype_com
index c88e791cfe..6f0c685505 100644
--- a/usr/src/pkgdefs/SUNWfmd/prototype_com
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_com
@@ -76,6 +76,8 @@ f none usr/lib/fm/fmd/plugins/disk-monitor.conf 644 root bin
f none usr/lib/fm/fmd/plugins/disk-monitor.so 555 root bin
f none usr/lib/fm/fmd/plugins/eft.conf 644 root bin
f none usr/lib/fm/fmd/plugins/eft.so 555 root bin
+f none usr/lib/fm/fmd/plugins/fabric-xlate.conf 644 root bin
+f none usr/lib/fm/fmd/plugins/fabric-xlate.so 555 root bin
f none usr/lib/fm/fmd/plugins/io-retire.conf 644 root bin
f none usr/lib/fm/fmd/plugins/io-retire.so 555 root bin
f none usr/lib/fm/fmd/plugins/ip-transport.so 555 root bin
diff --git a/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c b/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c
index c31a0e6a02..1d7deabfa6 100644
--- a/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c
+++ b/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -47,13 +47,8 @@
#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>
-#if defined(__i386) || defined(__amd64)
-#include <io/pciex/pcie_error.h>
-#endif
/*
* Local data/functions
@@ -1973,7 +1968,7 @@ 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);
+ PCIE_DISABLE_ERRORS(ctrl_p->dip);
PCIEHPC_DEBUG3((CE_NOTE, "%s%d: pciehpc_disable_errors\n",
ddi_driver_name(ctrl_p->dip),
ddi_get_instance(ctrl_p->dip)));
@@ -1984,7 +1979,7 @@ static void
pciehpc_enable_errors(pciehpc_t *ctrl_p)
{
if (ctrl_p->soft_state & PCIEHPC_SOFT_STATE_PCIE_DEV) {
- (void) PCIE_ENABLE_ERRORS(ctrl_p->dip, ctrl_p->cfghdl);
+ (void) PCIE_ENABLE_ERRORS(ctrl_p->dip);
PCIEHPC_DEBUG3((CE_NOTE, "%s%d: pciehpc_enable_errors\n",
ddi_driver_name(ctrl_p->dip),
ddi_get_instance(ctrl_p->dip)));
diff --git a/usr/src/uts/common/io/pcie.c b/usr/src/uts/common/io/pcie.c
index b5dda7dbf9..a536b55493 100644
--- a/usr/src/uts/common/io/pcie.c
+++ b/usr/src/uts/common/io/pcie.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -40,39 +40,127 @@
#include <sys/pci_cap.h>
#include <sys/pcie_impl.h>
-dev_info_t *pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip);
-uint32_t pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip);
+static void pcie_init_pfd(dev_info_t *);
+static void pcie_fini_pfd(dev_info_t *);
#ifdef DEBUG
uint_t pcie_debug_flags = 0;
+static void pcie_print_bus(pcie_bus_t *bus_p);
+
#define PCIE_DBG pcie_dbg
+/* Common Debugging shortcuts */
+#define PCIE_DBG_CFG(dip, bus_p, name, sz, off, org) \
+ PCIE_DBG("%s:%d:(0x%x) %s(0x%x) 0x%x -> 0x%x\n", ddi_node_name(dip), \
+ ddi_get_instance(dip), bus_p->bus_bdf, name, off, org, \
+ PCIE_GET(sz, bus_p, off))
+#define PCIE_DBG_CAP(dip, bus_p, name, sz, off, org) \
+ PCIE_DBG("%s:%d:(0x%x) %s(0x%x) 0x%x -> 0x%x\n", ddi_node_name(dip), \
+ ddi_get_instance(dip), bus_p->bus_bdf, name, off, org, \
+ PCIE_CAP_GET(sz, bus_p, off))
+#define PCIE_DBG_AER(dip, bus_p, name, sz, off, org) \
+ PCIE_DBG("%s:%d:(0x%x) %s(0x%x) 0x%x -> 0x%x\n", ddi_node_name(dip), \
+ ddi_get_instance(dip), bus_p->bus_bdf, name, off, org, \
+ PCIE_AER_GET(sz, bus_p, off))
+
static void pcie_dbg(char *fmt, ...);
#else /* DEBUG */
+#define PCIE_DBG_CFG 0 &&
#define PCIE_DBG 0 &&
+#define PCIE_DBG_CAP 0 &&
+#define PCIE_DBG_AER 0 &&
#endif /* DEBUG */
+int pcie_intel_error_disable = 1;
+
/* Variable to control default PCI-Express config settings */
-ushort_t pcie_command_default = PCI_COMM_SERR_ENABLE |
- PCI_COMM_WAIT_CYC_ENAB |
- PCI_COMM_PARITY_DETECT |
- PCI_COMM_ME |
- PCI_COMM_MAE |
- PCI_COMM_IO;
-ushort_t pcie_base_err_default = PCIE_DEVCTL_CE_REPORTING_EN |
- PCIE_DEVCTL_NFE_REPORTING_EN |
- PCIE_DEVCTL_FE_REPORTING_EN |
- PCIE_DEVCTL_UR_REPORTING_EN;
-
-uint32_t pcie_devctl_default = PCIE_DEVCTL_RO_EN |
- PCIE_DEVCTL_MAX_PAYLOAD_128 |
- PCIE_DEVCTL_MAX_READ_REQ_512;
-uint32_t pcie_aer_uce_mask = 0;
-uint32_t pcie_aer_ce_mask = 0;
-uint32_t pcie_aer_suce_mask = 0;
+ushort_t pcie_command_default =
+ PCI_COMM_SERR_ENABLE |
+ PCI_COMM_WAIT_CYC_ENAB |
+ PCI_COMM_PARITY_DETECT |
+ PCI_COMM_ME |
+ PCI_COMM_MAE |
+ PCI_COMM_IO;
+
+/* xxx_fw are bits that are controlled by FW and should not be modified */
+ushort_t pcie_command_default_fw =
+ PCI_COMM_SPEC_CYC |
+ PCI_COMM_MEMWR_INVAL |
+ PCI_COMM_PALETTE_SNOOP |
+ PCI_COMM_WAIT_CYC_ENAB |
+ 0xF800; /* Reserved Bits */
+
+ushort_t pcie_bdg_command_default_fw =
+ PCI_BCNF_BCNTRL_ISA_ENABLE |
+ PCI_BCNF_BCNTRL_VGA_ENABLE |
+ 0xF000; /* Reserved Bits */
+
+/* PCI-Express Base error defaults */
+ushort_t pcie_base_err_default =
+ PCIE_DEVCTL_CE_REPORTING_EN |
+ PCIE_DEVCTL_NFE_REPORTING_EN |
+ PCIE_DEVCTL_FE_REPORTING_EN |
+ PCIE_DEVCTL_UR_REPORTING_EN;
+
+/* PCI-Express Device Control Register */
+uint16_t pcie_devctl_default =
+ PCIE_DEVCTL_RO_EN |
+ PCIE_DEVCTL_MAX_PAYLOAD_128 |
+ PCIE_DEVCTL_MAX_READ_REQ_512;
+
+/* PCI-Express AER Root Control Register */
+#define PCIE_ROOT_SYS_ERR (PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \
+ PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN)
+
+#if defined(__xpv)
+ushort_t pcie_root_ctrl_default =
+ PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
+#else
+ushort_t pcie_root_ctrl_default =
+ PCIE_ROOTCTL_SYS_ERR_ON_CE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
+ PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
+#endif /* __xpv */
+
+/* PCI-Express Root Error Command Register */
+ushort_t pcie_root_error_cmd_default =
+ PCIE_AER_RE_CMD_CE_REP_EN |
+ PCIE_AER_RE_CMD_NFE_REP_EN |
+ PCIE_AER_RE_CMD_FE_REP_EN;
+
+/* ECRC settings in the PCIe AER Control Register */
+uint32_t pcie_ecrc_value =
+ PCIE_AER_CTL_ECRC_GEN_ENA |
+ PCIE_AER_CTL_ECRC_CHECK_ENA;
+
+/*
+ * If a particular platform wants to disable certain errors such as UR/MA,
+ * instead of using #defines have the platform's PCIe Root Complex driver set
+ * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For
+ * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the
+ * closest PCIe root complex driver is PX.
+ *
+ * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
+ * systems may want to disable SERR in general. For root ports, enabling SERR
+ * causes NMIs which are not handled and results in a watchdog timeout error.
+ */
+uint32_t pcie_aer_uce_mask = 0; /* AER UE Mask */
+uint32_t pcie_aer_ce_mask = 0; /* AER CE Mask */
+uint32_t pcie_aer_suce_mask = 0; /* AER Secondary UE Mask */
+uint32_t pcie_serr_disable_flag = 0; /* Disable SERR */
+
+/* Default severities needed for eversholt. Error handling doesn't care */
+uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \
+ PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \
+ PCIE_AER_UCE_TRAINING;
+uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
+ PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
+ PCIE_AER_SUCE_USC_MSG_DATA_ERR;
/*
* modload support
@@ -89,11 +177,24 @@ struct modlinkage modlinkage = {
NULL
};
+/*
+ * Global Variables needed for a non-atomic version of ddi_fm_ereport_post.
+ * Currently used to send the pci.fabric ereports whose payload depends on the
+ * type of PCI device it is being sent for.
+ */
+char *pcie_nv_buf;
+nv_alloc_t *pcie_nvap;
+nvlist_t *pcie_nvl;
+
int
_init(void)
{
int rval;
+ pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP);
+ pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ);
+ pcie_nvl = fm_nvlist_create(pcie_nvap);
+
rval = mod_install(&modlinkage);
return (rval);
}
@@ -103,6 +204,10 @@ _fini()
{
int rval;
+ fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
+ fm_nva_xdestroy(pcie_nvap);
+ kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
+
rval = mod_remove(&modlinkage);
return (rval);
}
@@ -126,157 +231,438 @@ _info(struct modinfo *modinfop)
int
pcie_initchild(dev_info_t *cdip)
{
- uint8_t header_type;
- uint8_t bcr;
- uint16_t command_reg, status_reg;
- pcie_ppd_t *ppd_p;
- ddi_acc_handle_t eh;
-
- ppd_p = pcie_init_ppd(cdip);
- if (ppd_p == NULL)
+ uint16_t tmp16, reg16;
+ pcie_bus_t *bus_p;
+
+ bus_p = PCIE_DIP2BUS(cdip);
+ if (bus_p == NULL) {
+ PCIE_DBG("%s: BUS not found.\n",
+ ddi_driver_name(cdip));
+
return (DDI_FAILURE);
+ }
- eh = ppd_p->ppd_cfg_hdl;
+ /* Clear the device's status register */
+ reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
+ PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
- /* setup the device's command register */
- header_type = ppd_p->ppd_hdr_type;
- status_reg = pci_config_get16(eh, PCI_CONF_STAT);
- pci_config_put16(eh, PCI_CONF_STAT, status_reg);
- command_reg = pci_config_get16(eh, PCI_CONF_COMM);
- command_reg |= pcie_command_default;
- pci_config_put16(eh, PCI_CONF_COMM, command_reg);
+ /* Setup the device's command register */
+ reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM);
+ tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default;
+ if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p))
+ tmp16 &= ~PCI_COMM_SERR_ENABLE;
- PCIE_DBG("pcie_initchild: %s(dip 0x%p), header_type=%x, "
- "command=%x\n", ddi_driver_name(cdip), (void *)cdip,
- header_type, pci_config_get16(eh, PCI_CONF_COMM));
+ PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16);
+ PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16);
/*
* If the device has a bus control register then program it
* based on the settings in the command register.
*/
- if (header_type == PCI_HEADER_ONE) {
- status_reg = pci_config_get16(eh,
- PCI_BCNF_SEC_STATUS);
- pci_config_put16(eh, PCI_BCNF_SEC_STATUS,
- status_reg);
- bcr = pci_config_get8(eh, PCI_BCNF_BCNTRL);
+ if (PCIE_IS_BDG(bus_p)) {
+ /* Clear the device's secondary status register */
+ reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
+ PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16);
+
+ /* Setup the device's secondary command register */
+ reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
+ tmp16 = (reg16 & pcie_bdg_command_default_fw);
if (pcie_command_default & PCI_COMM_PARITY_DETECT)
- bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
- if (pcie_command_default & PCI_COMM_SERR_ENABLE)
- bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
- bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
- pci_config_put8(eh, PCI_BCNF_BCNTRL, bcr);
+ tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
+ if (pcie_command_default & PCI_COMM_SERR_ENABLE) {
+ if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p) &&
+ PCIE_IS_ROOT(bus_p))
+ tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
+ else
+ tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE;
+ }
+
+ /*
+ * Enable Master Abort Mode only if URs have not been masked.
+ * For PCI and PCIe-PCI bridges, enabling this bit causes a
+ * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this
+ * bit is masked, posted requests are dropped and non-posted
+ * requests are returned with -1.
+ */
+ if (pcie_aer_uce_mask & PCIE_AER_UCE_UR)
+ tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
+ else
+ tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE;
+ PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16);
+ PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL,
+ reg16);
}
- if (ppd_p->ppd_pcie_off)
- pcie_enable_errors(cdip, eh);
+ if (PCIE_IS_PCIE(bus_p)) {
+ /* Setup PCIe device control register */
+ reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
+ tmp16 = pcie_devctl_default;
+ PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
+ PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
+
+ /* Enable PCIe errors */
+ pcie_enable_errors(cdip);
+ }
return (DDI_SUCCESS);
}
-/* Initialize PCIe Parent Private Data */
-pcie_ppd_t *
-pcie_init_ppd(dev_info_t *cdip)
+#define PCIE_ZALLOC(data) kmem_zalloc(sizeof (data), KM_SLEEP)
+static void
+pcie_init_pfd(dev_info_t *dip)
+{
+ pf_data_t *pfd_p = PCIE_ZALLOC(pf_data_t);
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+
+ PCIE_DIP2PFD(dip) = pfd_p;
+
+ pfd_p->pe_bus_p = bus_p;
+ pfd_p->pe_severity_flags = 0;
+ pfd_p->pe_lock = B_FALSE;
+ pfd_p->pe_valid = B_FALSE;
+
+ /* Allocate the root fault struct for both RC and RP */
+ if (PCIE_IS_ROOT(bus_p))
+ PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
+
+ PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
+
+ if (PCIE_IS_BDG(bus_p))
+ PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
+
+ if (PCIE_IS_PCIE(bus_p)) {
+ PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
+
+ if (PCIE_IS_RP(bus_p))
+ PCIE_RP_REG(pfd_p) =
+ PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
+
+ PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
+
+ if (PCIE_IS_RP(bus_p))
+ PCIE_ADV_RP_REG(pfd_p) =
+ PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
+ else if (PCIE_IS_PCIE_BDG(bus_p))
+ PCIE_ADV_BDG_REG(pfd_p) =
+ PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t);
+
+ if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
+ PCIX_BDG_ERR_REG(pfd_p) =
+ PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
+
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
+ PCIX_BDG_ECC_REG(pfd_p, 0) =
+ PCIE_ZALLOC(pf_pcix_ecc_regs_t);
+ PCIX_BDG_ECC_REG(pfd_p, 1) =
+ PCIE_ZALLOC(pf_pcix_ecc_regs_t);
+ }
+ }
+ } else if (PCIE_IS_PCIX(bus_p)) {
+ if (PCIE_IS_BDG(bus_p)) {
+ PCIX_BDG_ERR_REG(pfd_p) =
+ PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
+
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
+ PCIX_BDG_ECC_REG(pfd_p, 0) =
+ PCIE_ZALLOC(pf_pcix_ecc_regs_t);
+ PCIX_BDG_ECC_REG(pfd_p, 1) =
+ PCIE_ZALLOC(pf_pcix_ecc_regs_t);
+ }
+ } else {
+ PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t);
+
+ if (PCIX_ECC_VERSION_CHECK(bus_p))
+ PCIX_ECC_REG(pfd_p) =
+ PCIE_ZALLOC(pf_pcix_ecc_regs_t);
+ }
+ }
+}
+
+static void
+pcie_fini_pfd(dev_info_t *dip)
{
- pcie_ppd_t *ppd_p = 0;
- ddi_acc_handle_t eh;
+ pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+
+ if (PCIE_IS_PCIE(bus_p)) {
+ if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
+ kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
+ sizeof (pf_pcix_ecc_regs_t));
+ kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
+ sizeof (pf_pcix_ecc_regs_t));
+ }
+
+ kmem_free(PCIX_BDG_ERR_REG(pfd_p),
+ sizeof (pf_pcix_bdg_err_regs_t));
+ }
+
+ if (PCIE_IS_RP(bus_p))
+ kmem_free(PCIE_ADV_RP_REG(pfd_p),
+ sizeof (pf_pcie_adv_rp_err_regs_t));
+ else if (PCIE_IS_PCIE_BDG(bus_p))
+ kmem_free(PCIE_ADV_BDG_REG(pfd_p),
+ sizeof (pf_pcie_adv_bdg_err_regs_t));
+
+ kmem_free(PCIE_ADV_REG(pfd_p),
+ sizeof (pf_pcie_adv_err_regs_t));
+
+ if (PCIE_IS_RP(bus_p))
+ kmem_free(PCIE_RP_REG(pfd_p),
+ sizeof (pf_pcie_rp_err_regs_t));
+
+ kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
+ } else if (PCIE_IS_PCIX(bus_p)) {
+ if (PCIE_IS_BDG(bus_p)) {
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
+ kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
+ sizeof (pf_pcix_ecc_regs_t));
+ kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
+ sizeof (pf_pcix_ecc_regs_t));
+ }
+
+ kmem_free(PCIX_BDG_ERR_REG(pfd_p),
+ sizeof (pf_pcix_bdg_err_regs_t));
+ } else {
+ if (PCIX_ECC_VERSION_CHECK(bus_p))
+ kmem_free(PCIX_ECC_REG(pfd_p),
+ sizeof (pf_pcix_ecc_regs_t));
+
+ kmem_free(PCIX_ERR_REG(pfd_p),
+ sizeof (pf_pcix_err_regs_t));
+ }
+ }
+
+ if (PCIE_IS_BDG(bus_p))
+ kmem_free(PCI_BDG_ERR_REG(pfd_p),
+ sizeof (pf_pci_bdg_err_regs_t));
+
+ kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
+
+ if (PCIE_IS_ROOT(bus_p))
+ kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
+
+ kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t));
+
+ PCIE_DIP2PFD(dip) = NULL;
+}
+
+
+/*
+ * Special functions to allocate pf_data_t's for PCIe root complexes.
+ * Note: Root Complex not Root Port
+ */
+void
+pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p)
+{
+ pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip);
+ pfd_p->pe_severity_flags = 0;
+ pfd_p->pe_lock = B_FALSE;
+ pfd_p->pe_valid = B_FALSE;
+
+ PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
+ PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
+ PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
+ PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
+ PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
+ PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
+ PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
+
+ PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity;
+}
+
+void
+pcie_rc_fini_pfd(pf_data_t *pfd_p)
+{
+ kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t));
+ kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t));
+ kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t));
+ kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
+ kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
+ kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
+ kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
+}
+
+void
+pcie_rc_init_bus(dev_info_t *dip)
+{
+ pcie_bus_t *bus_p;
+
+ bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
+ bus_p->bus_dip = dip;
+ bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO;
+ bus_p->bus_hdr_type = PCI_HEADER_ONE;
+
+ /* Fake that there are AER logs */
+ bus_p->bus_aer_off = (uint16_t)-1;
+
+ /* Needed only for handle lookup */
+ bus_p->bus_fm_flags |= PF_FM_READY;
+
+ ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p);
+}
+
+void
+pcie_rc_fini_bus(dev_info_t *dip)
+{
+ pcie_bus_t *bus_p = (pcie_bus_t *)ndi_get_bus_private(dip, B_FALSE);
+ ndi_set_bus_private(dip, B_FALSE, NULL, NULL);
+ kmem_free(bus_p, sizeof (pcie_bus_t));
+}
+
+/*
+ * Initialize PCIe Bus Private Data
+ *
+ * PCIe Bus Private Data contains commonly used PCI/PCIe information and offsets
+ * to key registers.
+ */
+pcie_bus_t *
+pcie_init_bus(dev_info_t *cdip)
+{
+ pcie_bus_t *bus_p = 0;
+ ddi_acc_handle_t eh = NULL;
int range_size;
+ dev_info_t *pdip;
+
+ ASSERT(PCIE_DIP2UPBUS(cdip) == NULL);
+
+ /* allocate memory for pcie bus data */
+ bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
- /* allocate memory for pcie parent data */
- ppd_p = kmem_zalloc(sizeof (pcie_ppd_t), KM_SLEEP);
+
+ /* Set back pointer to dip */
+ bus_p->bus_dip = cdip;
/* Create an config access special to error handling */
if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
- kmem_free(ppd_p, sizeof (pcie_ppd_t));
- return (NULL);
+ goto fail;
}
- ppd_p->ppd_cfg_hdl = eh;
+ bus_p->bus_cfg_hdl = eh;
+ bus_p->bus_fm_flags = 0;
/* get device's bus/dev/function number */
- if (pcie_get_bdf_from_dip(cdip, &ppd_p->ppd_bdf) != DDI_SUCCESS)
+ if (pcie_get_bdf_from_dip(cdip, &bus_p->bus_bdf) != DDI_SUCCESS)
goto fail;
/* Save the Vendor Id Device Id */
- ppd_p->ppd_dev_ven_id = pci_config_get32(eh, PCI_CONF_VENID);
+ bus_p->bus_dev_ven_id = PCIE_GET(32, bus_p, PCI_CONF_VENID);
+ bus_p->bus_rev_id = PCIE_GET(8, bus_p, PCI_CONF_REVID);
/* Save the Header Type */
- ppd_p->ppd_hdr_type = pci_config_get8(eh, PCI_CONF_HEADER);
- ppd_p->ppd_hdr_type &= PCI_HEADER_TYPE_M;
- ppd_p->ppd_pcie2pci_secbus = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, 0,
+ bus_p->bus_hdr_type = PCIE_GET(8, bus_p, PCI_CONF_HEADER);
+ bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
+ bus_p->bus_pcie2pci_secbus = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, 0,
"pcie2pci-sec-bus", 0);
+ /* Figure out the device type and all the relavant capability offsets */
+ if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_E, &bus_p->bus_pcie_off))
+ != DDI_FAILURE) {
+ bus_p->bus_dev_type = PCI_CAP_GET16(eh, NULL,
+ bus_p->bus_pcie_off, PCIE_PCIECAP) &
+ PCIE_PCIECAP_DEV_TYPE_MASK;
+
+ if (PCI_CAP_LOCATE(eh, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_AER),
+ &bus_p->bus_aer_off) != DDI_SUCCESS)
+ bus_p->bus_aer_off = NULL;
+ } else {
+ bus_p->bus_pcie_off = NULL;
+ bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_DEV;
+ }
+
+ if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &bus_p->bus_pcix_off))
+ != DDI_FAILURE) {
+ if (PCIE_IS_BDG(bus_p))
+ bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p,
+ PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
+ else
+ bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p,
+ PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
+ } else {
+ bus_p->bus_pcix_off = NULL;
+ bus_p->bus_ecc_ver = NULL;
+ }
+
/* Save the Range information if device is a switch/bridge */
- if (ppd_p->ppd_hdr_type == PCI_HEADER_ONE) {
+ if (PCIE_IS_BDG(bus_p)) {
/* get "bus_range" property */
range_size = sizeof (pci_bus_range_t);
if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
- "bus-range", (caddr_t)&ppd_p->ppd_bus_range, &range_size)
+ "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
!= DDI_PROP_SUCCESS)
goto fail;
/* get secondary bus number */
- ppd_p->ppd_bdg_secbus = pci_config_get8(eh, PCI_BCNF_SECBUS);
+ bus_p->bus_bdg_secbus = PCIE_GET(8, bus_p, PCI_BCNF_SECBUS);
/* Get "ranges" property */
if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
- "ranges", (caddr_t)&ppd_p->ppd_addr_ranges,
- &ppd_p->ppd_addr_entries) != DDI_PROP_SUCCESS)
- ppd_p->ppd_addr_entries = 0;
- ppd_p->ppd_addr_entries /= sizeof (ppb_ranges_t);
+ "ranges", (caddr_t)&bus_p->bus_addr_ranges,
+ &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
+ bus_p->bus_addr_entries = 0;
+ bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
}
/* save "assigned-addresses" property array, ignore failues */
if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
- "assigned-addresses", (caddr_t)&ppd_p->ppd_assigned_addr,
- &ppd_p->ppd_assigned_entries) == DDI_PROP_SUCCESS)
- ppd_p->ppd_assigned_entries /= sizeof (pci_regspec_t);
+ "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
+ &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
+ bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
else
- ppd_p->ppd_assigned_entries = 0;
+ bus_p->bus_assigned_entries = 0;
- if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_E, &ppd_p->ppd_pcie_off))
- != DDI_FAILURE) {
- ppd_p->ppd_dev_type = PCI_CAP_GET16(eh, NULL,
- ppd_p->ppd_pcie_off, PCIE_PCIECAP) &
- PCIE_PCIECAP_DEV_TYPE_MASK;
-
- if (PCI_CAP_LOCATE(eh, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_AER),
- &ppd_p->ppd_aer_off) != DDI_SUCCESS)
- ppd_p->ppd_aer_off = NULL;
+ /* save RP dip and RP bdf */
+ if (PCIE_IS_RP(bus_p)) {
+ bus_p->bus_rp_dip = cdip;
+ bus_p->bus_rp_bdf = bus_p->bus_bdf;
} else {
- ppd_p->ppd_pcie_off = NULL;
- ppd_p->ppd_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_DEV;
+ for (pdip = ddi_get_parent(cdip); pdip;
+ pdip = ddi_get_parent(pdip)) {
+ pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
+
+ /*
+ * When debugging be aware that some NVIDIA x86
+ * architectures have 2 nodes for each RP, One at Bus
+ * 0x0 and one at Bus 0x80. The requester is from Bus
+ * 0x80
+ */
+ if (PCIE_IS_ROOT(parent_bus_p)) {
+ bus_p->bus_rp_dip = pdip;
+ bus_p->bus_rp_bdf = parent_bus_p->bus_bdf;
+ break;
+ }
+ }
}
- ppd_p->ppd_dip = cdip;
- ppd_p->ppd_fm_flags = 0;
- ddi_set_parent_data(cdip, (void *)ppd_p);
+ ndi_set_bus_private(cdip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
+
+ pcie_init_pfd(cdip);
PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
- ddi_driver_name(cdip), (void *)cdip, ppd_p->ppd_bdf,
- ppd_p->ppd_bdg_secbus);
+ ddi_driver_name(cdip), (void *)cdip, bus_p->bus_bdf,
+ bus_p->bus_bdg_secbus);
+#ifdef DEBUG
+ pcie_print_bus(bus_p);
+#endif
- return (ppd_p);
+ return (bus_p);
fail:
cmn_err(CE_WARN, "PCIE init err info failed BDF 0x%x\n",
- ppd_p->ppd_bdf);
- pci_config_teardown(&eh);
- kmem_free(ppd_p, sizeof (pcie_ppd_t));
+ bus_p->bus_bdf);
+ if (eh)
+ pci_config_teardown(&eh);
+ kmem_free(bus_p, sizeof (pcie_bus_t));
return (NULL);
}
int
-pcie_postattach_child(dev_info_t *dip)
+pcie_postattach_child(dev_info_t *cdip)
{
- ddi_acc_handle_t cfg_hdl;
- int rval = DDI_FAILURE;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
- if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS)
+ if (!bus_p)
return (DDI_FAILURE);
- rval = pcie_enable_ce(dip, cfg_hdl);
-
- pci_config_teardown(&cfg_hdl);
- return (rval);
+ return (pcie_enable_ce(cdip));
}
/*
@@ -287,161 +673,153 @@ pcie_postattach_child(dev_info_t *dip)
void
pcie_uninitchild(dev_info_t *cdip)
{
- pcie_ppd_t *ppd_p;
- ppd_p = pcie_get_ppd(cdip);
-
- pcie_disable_errors(cdip, ppd_p->ppd_cfg_hdl);
- pcie_uninit_ppd(cdip);
+ pcie_disable_errors(cdip);
+ pcie_fini_bus(cdip);
}
void
-pcie_uninit_ppd(dev_info_t *cdip)
+pcie_fini_bus(dev_info_t *cdip)
{
- pcie_ppd_t *ppd_p;
-
- ppd_p = pcie_get_ppd(cdip);
- ASSERT(ppd_p);
- pci_config_teardown(&ppd_p->ppd_cfg_hdl);
- kmem_free(ppd_p->ppd_assigned_addr,
- (sizeof (pci_regspec_t) * ppd_p->ppd_assigned_entries));
- kmem_free(ppd_p->ppd_addr_ranges,
- (sizeof (ppb_ranges_t) * ppd_p->ppd_addr_entries));
+ pcie_bus_t *bus_p;
- kmem_free(ppd_p, sizeof (pcie_ppd_t));
- ddi_set_parent_data(cdip, NULL);
-}
+ pcie_fini_pfd(cdip);
-/* ARGSUSED */
-void
-pcie_clear_errors(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
-{
- uint16_t cap_ptr, aer_ptr, dev_type, device_sts;
- int rval = DDI_FAILURE;
-
- /* 1. clear the Legacy PCI Errors */
- device_sts = pci_config_get16(cfg_hdl, PCI_CONF_STAT);
- pci_config_put16(cfg_hdl, PCI_CONF_STAT, device_sts);
-
- if ((PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
- DDI_FAILURE)
- return;
-
- rval = PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_XCFG_SPC
- (PCIE_EXT_CAP_ID_AER), &aer_ptr);
- dev_type = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr,
- PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
-
- /* 1.1 clear the Legacy PCI Secondary Bus Errors */
- if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
- device_sts = pci_config_get16(cfg_hdl,
- PCI_BCNF_SEC_STATUS);
- pci_config_put16(cfg_hdl, PCI_BCNF_SEC_STATUS,
- device_sts);
- }
-
- /*
- * Clear any pending errors
- */
- /* 2. clear the Advanced PCIe Errors */
- if (rval != DDI_FAILURE) {
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_CE_STS,
- -1);
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_UCE_STS,
- -1);
-
- if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE) {
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr,
- PCIE_AER_SUCE_STS, -1);
- }
- }
+ bus_p = PCIE_DIP2UPBUS(cdip);
+ ASSERT(bus_p);
+ pci_config_teardown(&bus_p->bus_cfg_hdl);
+ ndi_set_bus_private(cdip, B_TRUE, NULL, NULL);
+ kmem_free(bus_p->bus_assigned_addr,
+ (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
+ kmem_free(bus_p->bus_addr_ranges,
+ (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
- /* 3. clear the PCIe Errors */
- if ((device_sts = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr,
- PCIE_DEVSTS)) != PCI_CAP_EINVAL16)
- PCI_CAP_PUT16(cfg_hdl, PCI_CAP_ID_PCI_E, cap_ptr,
- PCIE_DEVSTS, device_sts);
+ kmem_free(bus_p, sizeof (pcie_bus_t));
}
void
-pcie_enable_errors(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
+pcie_enable_errors(dev_info_t *dip)
{
- uint16_t cap_ptr, aer_ptr, dev_type, device_ctl;
- uint32_t aer_reg;
- int rval = DDI_FAILURE;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ uint16_t reg16, tmp16;
+ uint32_t reg32, tmp32;
+
+ ASSERT(bus_p);
/*
* Clear any pending errors
*/
- pcie_clear_errors(dip, cfg_hdl);
+ pcie_clear_errors(dip);
- if ((PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_ID_PCI_E, &cap_ptr))
- == DDI_FAILURE)
+ if (!PCIE_IS_PCIE(bus_p))
return;
- rval = PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_XCFG_SPC
- (PCIE_EXT_CAP_ID_AER), &aer_ptr);
- dev_type = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr, PCIE_PCIECAP) &
- PCIE_PCIECAP_DEV_TYPE_MASK;
-
/*
* Enable Baseline Error Handling but leave CE reporting off (poweron
* default).
*/
- if ((device_ctl = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr,
- PCIE_DEVCTL)) != PCI_CAP_EINVAL16) {
- PCI_CAP_PUT16(cfg_hdl, NULL, cap_ptr, PCIE_DEVCTL,
- pcie_devctl_default | (pcie_base_err_default &
- (~PCIE_DEVCTL_CE_REPORTING_EN)));
- PCIE_DBG("%s%d: devctl 0x%x -> 0x%x\n", ddi_node_name(dip),
- ddi_get_instance(dip), device_ctl,
- PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr,
- PCIE_DEVCTL));
+ if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
+ PCI_CAP_EINVAL16) {
+ tmp16 = pcie_devctl_default | (pcie_base_err_default &
+ (~PCIE_DEVCTL_CE_REPORTING_EN));
+ PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
+ PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
+ }
+
+ /* Enable Root Port Baseline Error Receiving */
+ if (PCIE_IS_ROOT(bus_p) &&
+ (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) !=
+ PCI_CAP_EINVAL16) {
+
+#if defined(__xpv)
+ /*
+ * When we're booted under the hypervisor we won't receive
+ * MSI's, so to ensure that uncorrectable errors aren't ignored
+ * we set the SERR_FAT and SERR_NONFAT bits in the Root Control
+ * Register.
+ */
+ tmp16 = pcie_root_ctrl_default;
+#else
+ tmp16 = pcie_serr_disable_flag ?
+ (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) :
+ pcie_root_ctrl_default;
+#endif /* __xpv */
+ PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16);
+ PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL,
+ reg16);
}
/*
* Enable PCI-Express Advanced Error Handling if Exists
*/
- if (rval == DDI_FAILURE) {
+ if (!PCIE_HAS_AER(bus_p))
return;
+
+ /* Set Uncorrectable Severity */
+ if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) !=
+ PCI_CAP_EINVAL32) {
+ tmp32 = pcie_aer_uce_severity;
+
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32);
+ PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV,
+ reg32);
}
/* Enable Uncorrectable errors */
- if ((aer_reg = PCI_XCAP_GET32(cfg_hdl, NULL, aer_ptr,
- PCIE_AER_UCE_MASK)) != PCI_CAP_EINVAL32) {
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr,
- PCIE_AER_UCE_MASK, pcie_aer_uce_mask);
- PCIE_DBG("%s: AER UCE=0x%x->0x%x\n", ddi_driver_name(dip),
- aer_reg, PCI_XCAP_GET32(cfg_hdl, NULL, aer_ptr,
- PCIE_AER_UCE_MASK));
+ if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) !=
+ PCI_CAP_EINVAL32) {
+ tmp32 = pcie_aer_uce_mask;
+
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32);
+ PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK,
+ reg32);
}
+ /* x86 doesn't do this except for RC */
/* Enable ECRC generation and checking */
- if ((aer_reg = PCI_XCAP_GET32(cfg_hdl, NULL, aer_ptr,
- PCIE_AER_CTL)) != PCI_CAP_EINVAL32) {
- aer_reg |= (PCIE_AER_CTL_ECRC_GEN_ENA |
- PCIE_AER_CTL_ECRC_CHECK_ENA);
+ if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
+ PCI_CAP_EINVAL32) {
+ tmp32 = reg32 | pcie_ecrc_value;
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32);
+ PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32);
+ }
+
+ /* Enable Secondary Uncorrectable errors if this is a bridge */
+ if (!PCIE_IS_PCIE_BDG(bus_p))
+ goto root;
+
+ /* Set Uncorrectable Severity */
+ if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) !=
+ PCI_CAP_EINVAL32) {
+ tmp32 = pcie_aer_suce_severity;
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_CTL,
- aer_reg);
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32);
+ PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV,
+ reg32);
}
+ if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) !=
+ PCI_CAP_EINVAL32) {
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask);
+ PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32,
+ PCIE_AER_SUCE_MASK, reg32);
+ }
+
+root:
/*
- * Enable Secondary Uncorrectable errors if this is a bridge
+ * Enable Root Control this is a Root device
*/
- if (!(dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI))
+ if (!PCIE_IS_ROOT(bus_p))
return;
- /*
- * Enable secondary bus errors
- */
- if ((aer_reg = PCI_XCAP_GET32(cfg_hdl, NULL, aer_ptr,
- PCIE_AER_SUCE_MASK)) != PCI_CAP_EINVAL32) {
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_SUCE_MASK,
- pcie_aer_suce_mask);
- PCIE_DBG("%s: AER SUCE=0x%x->0x%x\n", ddi_driver_name(dip),
- aer_reg, PCI_XCAP_GET32(cfg_hdl,
- PCIE_EXT_CAP_ID_AER, aer_ptr, PCIE_AER_SUCE_MASK));
+#if !defined(__xpv)
+ if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
+ PCI_CAP_EINVAL16) {
+ PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD,
+ pcie_root_error_cmd_default);
+ PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16,
+ PCIE_AER_RE_CMD, reg16);
}
+#endif /* __xpv */
}
/*
@@ -450,14 +828,14 @@ pcie_enable_errors(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
* a call to pcie_enable_errors.
*/
int
-pcie_enable_ce(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
+pcie_enable_ce(dev_info_t *dip)
{
- uint16_t cap_ptr, aer_ptr, device_sts, device_ctl;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ uint16_t device_sts, device_ctl;
uint32_t tmp_pcie_aer_ce_mask;
- if ((PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_ID_PCI_E, &cap_ptr))
- == DDI_FAILURE)
- return (DDI_FAILURE);
+ if (!PCIE_IS_PCIE(bus_p))
+ return (DDI_SUCCESS);
/*
* The "pcie_ce_mask" property is used to control both the CE reporting
@@ -468,103 +846,105 @@ pcie_enable_ce(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask);
- if (tmp_pcie_aer_ce_mask == -1) {
+ if (tmp_pcie_aer_ce_mask == (uint32_t)-1) {
/*
* Nothing to do since CE reporting has already been disabled.
*/
return (DDI_SUCCESS);
}
- if (PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_XCFG_SPC
- (PCIE_EXT_CAP_ID_AER), &aer_ptr) != DDI_FAILURE) {
+ if (PCIE_HAS_AER(bus_p)) {
/* Enable AER CE */
- PCI_XCAP_PUT32(cfg_hdl, PCIE_EXT_CAP_ID_AER,
- aer_ptr, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
-
- PCIE_DBG("%s: AER CE set to 0x%x\n",
- ddi_driver_name(dip), PCI_XCAP_GET32(cfg_hdl, NULL,
- aer_ptr, PCIE_AER_CE_MASK));
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
+ PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK,
+ 0);
/* Clear any pending AER CE errors */
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_CE_STS,
- -1);
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1);
}
/* clear any pending CE errors */
- if ((device_sts = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr,
- PCIE_DEVSTS)) != PCI_CAP_EINVAL16)
- PCI_CAP_PUT16(cfg_hdl, PCI_CAP_ID_PCI_E, cap_ptr,
- PCIE_DEVSTS, device_sts & (~PCIE_DEVSTS_CE_DETECTED));
+ if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) !=
+ PCI_CAP_EINVAL16)
+ PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS,
+ device_sts & (~PCIE_DEVSTS_CE_DETECTED));
/* Enable CE reporting */
- device_ctl = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr, PCIE_DEVCTL);
- PCI_CAP_PUT16(cfg_hdl, NULL, cap_ptr, PCIE_DEVCTL,
- (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
- PCIE_DBG("%s%d: devctl 0x%x -> 0x%x\n", ddi_node_name(dip),
- ddi_get_instance(dip), device_ctl,
- PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr, PCIE_DEVCTL));
+ device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
+ PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL,
+ (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
+ PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl);
+
return (DDI_SUCCESS);
}
/* ARGSUSED */
void
-pcie_disable_errors(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
+pcie_disable_errors(dev_info_t *dip)
{
- uint16_t cap_ptr, aer_ptr, dev_type, device_ctl;
- uint32_t aer_reg;
- int rval = DDI_FAILURE;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ uint16_t device_ctl;
+ uint32_t aer_reg;
- if ((PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_ID_PCI_E, &cap_ptr))
- == DDI_FAILURE)
+ if (!PCIE_IS_PCIE(bus_p))
return;
- rval = PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_XCFG_SPC
- (PCIE_EXT_CAP_ID_AER), &aer_ptr);
- dev_type = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr,
- PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
-
/*
* Disable PCI-Express Baseline Error Handling
*/
- device_ctl = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr, PCIE_DEVCTL);
+ device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
device_ctl &= ~PCIE_DEVCTL_ERR_MASK;
- PCI_CAP_PUT16(cfg_hdl, NULL, cap_ptr, PCIE_DEVCTL, device_ctl);
+ PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl);
/*
* Disable PCI-Express Advanced Error Handling if Exists
*/
- if (rval == DDI_FAILURE) {
- return;
- }
+ if (!PCIE_HAS_AER(bus_p))
+ goto root;
/* Disable Uncorrectable errors */
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_UCE_MASK,
- PCIE_AER_UCE_BITS);
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS);
/* Disable Correctable errors */
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_CE_MASK,
- PCIE_AER_CE_BITS);
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS);
/* Disable ECRC generation and checking */
- if ((aer_reg = PCI_XCAP_GET32(cfg_hdl, NULL, aer_ptr,
- PCIE_AER_CTL)) != PCI_CAP_EINVAL32) {
+ if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
+ PCI_CAP_EINVAL32) {
aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA |
PCIE_AER_CTL_ECRC_CHECK_ENA);
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_CTL,
- aer_reg);
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg);
}
/*
* Disable Secondary Uncorrectable errors if this is a bridge
*/
- if (!(dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI))
- return;
+ if (!PCIE_IS_PCIE_BDG(bus_p))
+ goto root;
+
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS);
+root:
/*
- * Disable secondary bus errors
+ * disable Root Control this is a Root device
*/
- PCI_XCAP_PUT32(cfg_hdl, NULL, aer_ptr, PCIE_AER_SUCE_MASK,
- PCIE_AER_SUCE_BITS);
+ if (!PCIE_IS_ROOT(bus_p))
+ return;
+
+ if (!pcie_serr_disable_flag) {
+ device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL);
+ device_ctl &= ~PCIE_ROOT_SYS_ERR;
+ PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl);
+ }
+
+ if (!PCIE_HAS_AER(bus_p))
+ return;
+
+ if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
+ PCI_CAP_EINVAL16) {
+ device_ctl &= ~pcie_root_error_cmd_default;
+ PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl);
+ }
}
/*
@@ -630,14 +1010,46 @@ pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
return (PCI_GET_PCIE2PCI_SECBUS(cdip) ? 0 : PCI_GET_BDF(cdip));
}
-/*
- * Returns Parent Private Data for PCIe devices and PCI devices that are in PCIe
- * systems
- */
-pcie_ppd_t *
-pcie_get_ppd(dev_info_t *dip)
-{
- return ((pcie_ppd_t *)ddi_get_parent_data(dip));
+uint32_t
+pcie_get_aer_uce_mask() {
+ return (pcie_aer_uce_mask);
+}
+uint32_t
+pcie_get_aer_ce_mask() {
+ return (pcie_aer_ce_mask);
+}
+uint32_t
+pcie_get_aer_suce_mask() {
+ return (pcie_aer_suce_mask);
+}
+uint32_t
+pcie_get_serr_mask() {
+ return (pcie_serr_disable_flag);
+}
+
+void
+pcie_set_aer_uce_mask(uint32_t mask) {
+ pcie_aer_uce_mask = mask;
+ if (mask & PCIE_AER_UCE_UR)
+ pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN;
+ else
+ pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN;
+
+ if (mask & PCIE_AER_UCE_ECRC)
+ pcie_ecrc_value = 0;
+}
+
+void
+pcie_set_aer_ce_mask(uint32_t mask) {
+ pcie_aer_ce_mask = mask;
+}
+void
+pcie_set_aer_suce_mask(uint32_t mask) {
+ pcie_aer_suce_mask = mask;
+}
+void
+pcie_set_serr_mask(uint32_t mask) {
+ pcie_serr_disable_flag = mask;
}
/*
@@ -654,7 +1066,39 @@ pcie_is_child(dev_info_t *dip, dev_info_t *rdip)
return (cdip != NULL);
}
+boolean_t
+pcie_is_link_disabled(dev_info_t *dip)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+
+ if (PCIE_IS_PCIE(bus_p)) {
+ if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) &
+ PCIE_LINKCTL_LINK_DISABLE)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
#ifdef DEBUG
+
+static void
+pcie_print_bus(pcie_bus_t *bus_p)
+{
+ pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip);
+ pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags);
+
+ pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf);
+ pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id);
+ pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id);
+ pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type);
+ pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type);
+ pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus);
+ pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off);
+ pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off);
+ pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off);
+ pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver);
+}
+
/*
* For debugging purposes set pcie_dbg_print != 0 to see printf messages
* during interrupt.
diff --git a/usr/src/uts/common/io/pcie_fault.c b/usr/src/uts/common/io/pcie_fault.c
index 50065a3775..0271deee93 100644
--- a/usr/src/uts/common/io/pcie_fault.c
+++ b/usr/src/uts/common/io/pcie_fault.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,14 +34,20 @@
#include <sys/sunndi.h>
#include <sys/fm/protocol.h>
#include <sys/fm/util.h>
+#include <sys/fm/io/ddi.h>
+#include <sys/fm/io/pci.h>
#include <sys/promif.h>
#include <sys/disp.h>
+#include <sys/atomic.h>
#include <sys/pcie.h>
#include <sys/pci_cap.h>
#include <sys/pcie_impl.h>
-/* size of error queue */
-uint_t pf_dq_size = 32;
+#define PF_PCIE_BDG_ERR (PCIE_DEVSTS_FE_DETECTED | PCIE_DEVSTS_NFE_DETECTED | \
+ PCIE_DEVSTS_CE_DETECTED)
+
+#define PF_PCI_BDG_ERR (PCI_STAT_S_SYSERR | PCI_STAT_S_TARG_AB | \
+ PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | PCI_STAT_S_PERROR)
#define PF_AER_FATAL_ERR (PCIE_AER_UCE_DLP | PCIE_AER_UCE_SD |\
PCIE_AER_UCE_FCP | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP)
@@ -57,32 +63,28 @@ uint_t pf_dq_size = 32;
PCIE_AER_SUCE_UC_DATA_ERR | PCIE_AER_SUCE_TIMER_EXPIRED | \
PCIE_AER_SUCE_PERR_ASSERT | PCIE_AER_SUCE_INTERNAL_ERR)
-#define PF_PCIE_BDG_ERR (PCIE_DEVSTS_FE_DETECTED | PCIE_DEVSTS_NFE_DETECTED | \
- PCIE_DEVSTS_CE_DETECTED)
-
-#define PF_PCI_BDG_ERR (PCI_STAT_S_SYSERR | PCI_STAT_S_TARG_AB | \
- PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | PCI_STAT_S_PERROR)
-
+#define PF_PCI_PARITY_ERR (PCI_STAT_S_PERROR | PCI_STAT_PERROR)
-#define PF_DATA_NOT_FOUND -1
+#define PF_FIRST_AER_ERR(bit, adv) \
+ (bit & (1 << (adv->pcie_adv_ctl & PCIE_AER_CTL_FST_ERR_PTR_MASK)))
-#define HAS_AER_LOGS(pf_data_p, bit) \
- (pf_data_p->aer_off && (bit & (1 << (pf_data_p->aer_control & \
- PCIE_AER_CTL_FST_ERR_PTR_MASK))))
+#define HAS_AER_LOGS(pfd_p, bit) \
+ (PCIE_HAS_AER(pfd_p->pe_bus_p) && \
+ PF_FIRST_AER_ERR(bit, PCIE_ADV_REG(pfd_p)))
-#define HAS_SAER_LOGS(pf_data_p, bit) \
- (pf_data_p->aer_off && (bit & (1 << (pf_data_p->s_aer_control & \
- PCIE_AER_SCTL_FST_ERR_PTR_MASK))))
+#define PF_FIRST_SAER_ERR(bit, adv) \
+ (bit & (1 << (adv->pcie_sue_ctl & PCIE_AER_SCTL_FST_ERR_PTR_MASK)))
-#define GET_SAER_CMD(pf_data_p) \
- (pf_data_p->s_aer_h1 >> PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & \
- PCIE_AER_SUCE_HDR_CMD_LWR_MASK;
+#define HAS_SAER_LOGS(pfd_p, bit) \
+ (PCIE_HAS_AER(pfd_p->pe_bus_p) && \
+ PF_FIRST_SAER_ERR(bit, PCIE_ADV_BDG_REG(pfd_p)))
-#define CE_ADVISORY(pf_data_p) \
- (pf_data_p->aer_ce_status & PCIE_AER_CE_AD_NFE)
+#define GET_SAER_CMD(pfd_p) \
+ ((PCIE_ADV_BDG_HDR(pfd_p, 1) >> \
+ PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK)
-#define IS_RC(pf_data_p) \
- (pf_data_p->dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
+#define CE_ADVISORY(pfd_p) \
+ (PCIE_ADV_REG(pfd_p)->pcie_ce_status & PCIE_AER_CE_AD_NFE)
/* PCIe Fault Fabric Error analysis table */
typedef struct pf_fab_err_tbl {
@@ -90,169 +92,286 @@ typedef struct pf_fab_err_tbl {
int (*handler)(); /* Error handling fuction */
} pf_fab_err_tbl_t;
-/* DMA/PIO/CFG Handle Comparason Function Declaration */
-typedef int (*pf_hdl_compare_t)(struct i_ddi_fmhdl *, ddi_fm_error_t *,
- uint32_t, pcie_req_id_t);
-
-/* PCIe Fault Support Functions. */
-static int pf_find_in_q(pcie_req_id_t bdf, pf_data_t *dq_p, int dq_tail);
-static boolean_t pf_in_bus_range(pcie_ppd_t *ppd_p, pcie_req_id_t bdf);
-static boolean_t pf_in_addr_range(pcie_ppd_t *ppd_p, uint32_t addr);
-static int pf_pcie_dispatch(dev_info_t *pdip, pf_impl_t *impl);
-static int pf_pci_dispatch(dev_info_t *pdip, pf_impl_t *impl);
-static int pf_default_hdl(dev_info_t *dip, dev_info_t *pdip,
- pcie_ppd_t *ppd_p, pf_impl_t *impl);
+static pcie_bus_t *pf_is_ready(dev_info_t *);
+/* Functions for scanning errors */
+static int pf_default_hdl(dev_info_t *, pf_impl_t *);
+static int pf_dispatch(dev_info_t *, pf_impl_t *, boolean_t);
+static boolean_t pf_in_bus_range(pcie_bus_t *, pcie_req_id_t);
+static boolean_t pf_in_addr_range(pcie_bus_t *, uint64_t);
+
+static int pf_pci_decode(pf_data_t *, uint16_t *);
+
+/* Functions for gathering errors */
+static void pf_pcix_ecc_regs_gather(pf_pcix_ecc_regs_t *pcix_ecc_regs,
+ pcie_bus_t *bus_p, boolean_t bdg);
+static void pf_pcix_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p);
+static void pf_pcie_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p);
+static void pf_pci_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p);
+static int pf_dummy_cb(dev_info_t *, ddi_fm_error_t *, const void *);
+static void pf_en_dq(pf_data_t *pfd_p, pf_impl_t *impl_p);
+
+/* Functions for analysing errors */
+static int pf_analyse_error(ddi_fm_error_t *, pf_impl_t *);
+static void pf_adjust_for_no_aer(pf_data_t *);
+static void pf_adjust_for_no_saer(pf_data_t *);
+static pf_data_t *pf_get_pcie_bridge(pf_data_t *, pcie_req_id_t);
+static pf_data_t *pf_get_parent_pcie_bridge(pf_data_t *);
+static boolean_t pf_matched_in_rc(pf_data_t *, pf_data_t *,
+ uint32_t);
+static int pf_analyse_error_tbl(ddi_fm_error_t *, pf_impl_t *,
+ pf_data_t *, const pf_fab_err_tbl_t *, uint32_t);
+static int pf_analyse_ca_ur(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_ma_ta(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_pci(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_perr_assert(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_ptlp(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_sc(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_to(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_uc(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_analyse_uc_data(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_no_panic(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static int pf_panic(ddi_fm_error_t *, uint32_t,
+ pf_data_t *, pf_data_t *);
+static void pf_send_ereport(ddi_fm_error_t *, pf_impl_t *);
+static int pf_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr);
/* PCIe Fabric Handle Lookup Support Functions. */
-static int pf_hdl_child_lookup(dev_info_t *rpdip, dev_info_t *dip,
- ddi_fm_error_t *derr, uint32_t addr, pcie_req_id_t bdf,
- pf_hdl_compare_t cf);
-static int pf_cfg_hdl_check(struct i_ddi_fmhdl *fmhdl,
- ddi_fm_error_t *derr, uint32_t notused, pcie_req_id_t bdf);
-static int pf_pio_hdl_check(struct i_ddi_fmhdl *fmhdl,
- ddi_fm_error_t *derr, uint32_t addr, pcie_req_id_t bdf);
-static int pf_dma_hdl_check(struct i_ddi_fmhdl *fmhdl,
- ddi_fm_error_t *derr, uint32_t addr, pcie_req_id_t bdf);
-
-
-/* PCIe/PCI Fault Handling Support Functions. */
-static int pf_pci_decode(dev_info_t *rpdip, pf_data_t *pf_data_p, uint16_t *cmd,
- pcie_req_id_t *bdf, uint32_t *addr, uint32_t *trans_type);
-static int pf_analyse_error(dev_info_t *rpdip, ddi_fm_error_t *derr,
- pf_data_t *q, int last_index);
-static void pf_send_ereport(dev_info_t *rpdip, ddi_fm_error_t *derr,
- pf_data_t *dq_p, int dq_tail);
-static void pf_adjust_for_no_aer(pf_data_t *pf_data_p);
-static void pf_adjust_for_no_saer(pf_data_t *pf_data_p);
-static pf_data_t *pf_get_parent_pcie_bridge(pf_data_t *dq_p,
- pf_data_t *pf_data_p);
-static boolean_t pf_matched_in_rc(pf_data_t *dq_p, pf_data_t *pf_data_p,
- uint32_t abort_type);
-static int pf_analyse_error_tbl(dev_info_t *rpdip, ddi_fm_error_t *derr,
- pf_data_t *dq_p, pf_data_t *pf_data_p, const pf_fab_err_tbl_t *tbl,
- uint32_t err_reg);
-static int pf_analyse_ca_ur(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_ma_ta(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_pci(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_perr_assert(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_ptlp(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_sc(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_to(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_uc(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_analyse_uc_data(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_matched_device(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_no_panic(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static int pf_panic(dev_info_t *rpdip, ddi_fm_error_t *derr,
- uint32_t bit, pf_data_t *dq_p, pf_data_t *pf_data_p);
-static void pf_check_ce(pf_data_t *dq_p, int dq_tail);
-static void pf_set_parent_erpt(pf_data_t *dq_p, int index, int erpt_val);
+static int pf_hdl_child_lookup(dev_info_t *, ddi_fm_error_t *, uint32_t,
+ uint64_t, pcie_req_id_t);
+static int pf_hdl_compare(dev_info_t *, ddi_fm_error_t *, uint32_t, uint64_t,
+ pcie_req_id_t, ndi_fmc_t *);
+static int pf_log_hdl_lookup(dev_info_t *, ddi_fm_error_t *, pf_data_t *,
+ boolean_t);
-int
-pf_held(dev_info_t *dip)
-{
- pcie_ppd_t *ppd_p = pcie_get_ppd(dip);
- return (mutex_owned(&ppd_p->ppd_fm_lock));
-}
-
-boolean_t
-pf_enter(dev_info_t *dip)
-{
- pcie_ppd_t *ppd_p = pcie_get_ppd(dip);
- if (!(ppd_p->ppd_fm_flags & PF_FM_READY))
- return (B_FALSE);
- if (!pf_held(dip))
- mutex_enter(&ppd_p->ppd_fm_lock);
- return (B_TRUE);
-}
+static int pf_handler_enter(dev_info_t *, pf_impl_t *);
+static void pf_handler_exit(dev_info_t *);
-void
-pf_exit(dev_info_t *dip)
-{
- pcie_ppd_t *ppd_p = pcie_get_ppd(dip);
- mutex_exit(&ppd_p->ppd_fm_lock);
-}
+boolean_t pcie_full_scan = B_FALSE; /* Force to always do a full scan */
+int pcie_disable_scan = 0; /* Disable fabric scan */
/*
- * Default pci/pci-x/pci-e error handler callbacks for
- * SPARC PCI-E platforms
+ * Scan Fabric is the entry point for PCI/PCIe IO fabric errors. The
+ * caller may create a local pf_data_t with the "root fault"
+ * information populated to either do a precise or full scan. More
+ * than one pf_data_t maybe linked together if there are multiple
+ * errors. Only a PCIe compliant Root Port device may pass in NULL
+ * for the root_pfd_p.
+ *
+ * "Root Complexes" such as NPE and PX should call scan_fabric using itself as
+ * the rdip. PCIe Root ports should call pf_scan_fabric using it's parent as
+ * the rdip.
+ *
+ * Scan fabric initiated from RCs are likely due to a fabric message, traps or
+ * any RC detected errors that propagated to/from the fabric.
+ *
+ * This code assumes that by the time pf_scan_fabric is
+ * called, pf_handler_enter has NOT been called on the rdip.
*/
-
-/* Called during postattach to initalize FM lock */
-void
-pf_init(dev_info_t *dip, ddi_iblock_cookie_t ibc, ddi_attach_cmd_t cmd)
+int
+pf_scan_fabric(dev_info_t *rdip, ddi_fm_error_t *derr, pf_data_t *root_pfd_p)
{
- pcie_ppd_t *ppd_p = pcie_get_ppd(dip);
- struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
- int cap = DDI_FM_EREPORT_CAPABLE;
+ pf_impl_t impl;
+ pf_data_t *pfd_p, *pfd_head_p, *pfd_tail_p;
+ int scan_flag = PF_SCAN_SUCCESS;
+ int analyse_flag = PF_ERR_NO_ERROR;
+ boolean_t full_scan = pcie_full_scan;
+
+ if (pcie_disable_scan)
+ return (analyse_flag);
+
+ /* Find the head and tail of this link list */
+ pfd_head_p = root_pfd_p;
+ for (pfd_tail_p = root_pfd_p; pfd_tail_p && pfd_tail_p->pe_next;
+ pfd_tail_p = pfd_tail_p->pe_next)
+ ;
- if (fmhdl) {
- fmhdl->fh_cap |= cap;
- } else {
- ppd_p->ppd_fm_flags |= PF_IS_NH;
+ /* Save head/tail */
+ impl.pf_total = 0;
+ impl.pf_derr = derr;
+ impl.pf_dq_head_p = pfd_head_p;
+ impl.pf_dq_tail_p = pfd_tail_p;
+
+ /* If scan is initiated from RP then RP itself must be scanned. */
+ if (PCIE_IS_RP(PCIE_DIP2BUS(rdip)) && pf_is_ready(rdip) &&
+ !root_pfd_p) {
+ scan_flag = pf_handler_enter(rdip, &impl);
+ if (scan_flag & PF_SCAN_DEADLOCK)
+ goto done;
- if (cmd == DDI_ATTACH)
- ddi_fm_init(dip, &cap, &ibc);
+ scan_flag = pf_default_hdl(rdip, &impl);
+ if (scan_flag & PF_SCAN_NO_ERR_IN_CHILD)
+ goto done;
+ }
- fmhdl = DEVI(dip)->devi_fmhdl;
+ /*
+ * Scan the fabric using the fault_bdf and fault_addr in error q.
+ * fault_bdf will be valid in the following cases:
+ * - Fabric message
+ * - Poisoned TLP
+ * - Signaled UR/CA
+ * - Received UR/CA
+ * - PIO load failures
+ */
+ for (pfd_p = impl.pf_dq_head_p; pfd_p && PFD_IS_ROOT(pfd_p);
+ pfd_p = pfd_p->pe_next) {
+ impl.pf_fault = PCIE_ROOT_FAULT(pfd_p);
+
+ if (impl.pf_fault->full_scan)
+ full_scan = B_TRUE;
+
+ if (full_scan || impl.pf_fault->fault_bdf ||
+ impl.pf_fault->fault_addr)
+ scan_flag |= pf_dispatch(rdip, &impl, full_scan);
+
+ if (full_scan)
+ break;
}
- /* If ddi_fm_init fails for any reason RETURN */
- if (!fmhdl || !(cap & DDI_FM_EREPORT_CAPABLE)) {
- ppd_p->ppd_fm_flags = 0;
- return;
+done:
+ /*
+ * If this is due to safe access, don't analyze the errors and return
+ * success regardless of how scan fabric went.
+ */
+ if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) {
+ analyse_flag = PF_ERR_NO_PANIC;
+ } else {
+ analyse_flag = pf_analyse_error(derr, &impl);
}
- mutex_init(&ppd_p->ppd_fm_lock, NULL, MUTEX_DRIVER, (void *)ibc);
- ppd_p->ppd_fm_flags |= PF_FM_READY;
+ pf_send_ereport(derr, &impl);
+
+ /*
+ * Check if any hardened driver's callback reported a panic or scan
+ * fabric was unable to gather all the information needed. If so panic.
+ */
+ if (scan_flag & (PF_SCAN_CB_FAILURE | PF_SCAN_BAD_RESPONSE))
+ analyse_flag |= PF_ERR_PANIC;
+
+ /*
+ * If a deadlock was detected, panic the system as error analysis has
+ * been compromised.
+ */
+ if (scan_flag & PF_SCAN_DEADLOCK)
+ analyse_flag |= PF_ERR_PANIC_DEADLOCK;
+
+ derr->fme_status = PF_ERR2DDIFM_ERR(scan_flag);
+
+ return (analyse_flag);
}
-/* undo OPL FMA lock, called at predetach */
-void
-pf_fini(dev_info_t *dip, ddi_detach_cmd_t cmd)
+/*
+ * pf_dispatch walks the device tree and calls the pf_default_hdl if the device
+ * falls in the error path.
+ *
+ * Returns PF_SCAN_* flags
+ */
+static int
+pf_dispatch(dev_info_t *pdip, pf_impl_t *impl, boolean_t full_scan)
{
- pcie_ppd_t *ppd_p = pcie_get_ppd(dip);
+ dev_info_t *dip;
+ pcie_req_id_t rid = impl->pf_fault->fault_bdf;
+ pcie_bus_t *bus_p;
+ int scan_flag = PF_SCAN_SUCCESS;
- /* Don't fini anything if device isn't FM Ready */
- if (!(ppd_p->ppd_fm_flags & PF_FM_READY))
- return;
+ for (dip = ddi_get_child(pdip); dip; dip = ddi_get_next_sibling(dip)) {
+ /* Make sure dip is attached and ready */
+ if (!(bus_p = pf_is_ready(dip)))
+ continue;
- /* undo non-hardened drivers */
- if (ppd_p->ppd_fm_flags & PF_IS_NH) {
- if (cmd == DDI_DETACH) {
- ppd_p->ppd_fm_flags &= ~PF_IS_NH;
- ddi_fm_fini(dip);
+ scan_flag |= pf_handler_enter(dip, impl);
+ if (scan_flag & PF_SCAN_DEADLOCK)
+ break;
+
+ /*
+ * Handle this device if it is a:
+ * o Full Scan
+ * o PCI/PCI-X Device
+ * o Fault BDF = Device BDF
+ * o BDF/ADDR is in range of the Bridge/Switch
+ */
+ if (full_scan ||
+ (bus_p->bus_bdf == rid) ||
+ pf_in_bus_range(bus_p, rid) ||
+ pf_in_addr_range(bus_p, impl->pf_fault->fault_addr)) {
+ int hdl_flag = pf_default_hdl(dip, impl);
+ scan_flag |= hdl_flag;
+
+ /*
+ * If pf_default_hdl was not able gather error
+ * information, it means this device wasn't added to the
+ * error q list. In that case exit the lock now,
+ * otherwise it'll be locked forever.
+ */
+ if (hdl_flag & PF_SCAN_BAD_RESPONSE)
+ pf_handler_exit(dip);
+
+ /*
+ * A bridge may have detected no errors in which case
+ * there is no need to scan further down.
+ */
+ if (hdl_flag & PF_SCAN_NO_ERR_IN_CHILD)
+ continue;
+ } else {
+ pf_handler_exit(dip);
+ continue;
}
- }
- /* no other code should set the flag to false */
- ppd_p->ppd_fm_flags &= ~PF_FM_READY;
- while (pf_held(dip))
- ;
- mutex_destroy(&ppd_p->ppd_fm_lock);
+ /* match or in bridge bus-range */
+ switch (bus_p->bus_dev_type) {
+ case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
+ case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
+ scan_flag |= pf_dispatch(dip, impl, B_TRUE);
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_UP:
+ case PCIE_PCIECAP_DEV_TYPE_DOWN:
+ {
+ pf_data_t *pfd_p = PCIE_BUS2PFD(bus_p);
+ pf_pci_err_regs_t *err_p = PCI_ERR_REG(pfd_p);
+ pf_pci_bdg_err_regs_t *serr_p = PCI_BDG_ERR_REG(pfd_p);
+ /*
+ * Continue if the fault BDF != the switch or there is a
+ * parity error
+ */
+ if ((bus_p->bus_bdf != rid) ||
+ (err_p->pci_err_status & PF_PCI_PARITY_ERR) ||
+ (serr_p->pci_bdg_sec_stat & PF_PCI_PARITY_ERR))
+ scan_flag |= pf_dispatch(dip, impl, full_scan);
+ break;
+ }
+ case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_PCI_DEV:
+ if (PCIE_IS_BDG(bus_p))
+ scan_flag |= pf_dispatch(dip, impl, B_TRUE);
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_ROOT:
+ default:
+ ASSERT(B_FALSE);
+ }
+ }
+ return (scan_flag);
}
/* Returns whether the "bdf" is in the bus range of a switch/bridge */
static boolean_t
-pf_in_bus_range(pcie_ppd_t *ppd_p, pcie_req_id_t bdf)
+pf_in_bus_range(pcie_bus_t *bus_p, pcie_req_id_t bdf)
{
- pci_bus_range_t *br_p = &ppd_p->ppd_bus_range;
- uint16_t hdr_type = ppd_p->ppd_hdr_type;
+ pci_bus_range_t *br_p = &bus_p->bus_bus_range;
uint8_t bus_no = (bdf & PCIE_REQ_ID_BUS_MASK) >>
PCIE_REQ_ID_BUS_SHIFT;
/* check if given bdf falls within bridge's bus range */
- if ((hdr_type == PCI_HEADER_ONE) &&
+ if (PCIE_IS_BDG(bus_p) &&
((bus_no >= br_p->lo) && (bus_no <= br_p->hi)))
return (B_TRUE);
else
@@ -264,14 +383,15 @@ pf_in_bus_range(pcie_ppd_t *ppd_p, pcie_req_id_t bdf)
* "addr" is in the assigned addr of a device.
*/
static boolean_t
-pf_in_addr_range(pcie_ppd_t *ppd_p, uint32_t addr)
+pf_in_addr_range(pcie_bus_t *bus_p, uint64_t addr)
{
- uint_t i, low, hi;
- ppb_ranges_t *ranges_p = ppd_p->ppd_addr_ranges;
- pci_regspec_t *assign_p = ppd_p->ppd_assigned_addr;
+ uint_t i;
+ uint64_t low, hi;
+ ppb_ranges_t *ranges_p = bus_p->bus_addr_ranges;
+ pci_regspec_t *assign_p = bus_p->bus_assigned_addr;
/* check if given address belongs to this device */
- for (i = 0; i < ppd_p->ppd_assigned_entries; i++, assign_p++) {
+ for (i = 0; i < bus_p->bus_assigned_entries; i++, assign_p++) {
low = assign_p->pci_phys_low;
hi = low + assign_p->pci_size_low;
if ((addr < hi) && (addr >= low))
@@ -279,1103 +399,690 @@ pf_in_addr_range(pcie_ppd_t *ppd_p, uint32_t addr)
}
/* check if given address belongs to a child below this device */
- if (ppd_p->ppd_hdr_type == PCI_HEADER_ONE) {
- for (i = 0; i < ppd_p->ppd_addr_entries; i++, ranges_p++) {
- if (ranges_p->child_high & PCI_ADDR_MEM32) {
- low = ranges_p->child_low;
- hi = low + ranges_p->size_low;
- if ((addr < hi) && (addr >= low))
- return (B_TRUE);
- break;
- }
+ if (!PCIE_IS_BDG(bus_p))
+ return (B_FALSE);
+
+ for (i = 0; i < bus_p->bus_addr_entries; i++, ranges_p++) {
+ switch (ranges_p->child_high & PCI_ADDR_MASK) {
+ case PCI_ADDR_MEM32:
+ low = ranges_p->child_low;
+ hi = ranges_p->size_low + low;
+ if ((addr < hi) && (addr >= low))
+ return (B_TRUE);
+ break;
+ case PCI_ADDR_MEM64:
+ low = ((uint64_t)ranges_p->child_mid << 32) |
+ (uint64_t)ranges_p->child_low;
+ hi = (((uint64_t)ranges_p->size_high << 32) |
+ (uint64_t)ranges_p->size_low) + low;
+ if ((addr < hi) && (addr >= low))
+ return (B_TRUE);
+ break;
}
}
-
return (B_FALSE);
}
-int
-pf_pci_dispatch(dev_info_t *pdip, pf_impl_t *impl)
+static pcie_bus_t *
+pf_is_ready(dev_info_t *dip)
{
- dev_info_t *dip;
- pcie_ppd_t *ppd_p;
- int sts = 0, ret = 0;
-
- /* for bridge, check all downstream */
- dip = ddi_get_child(pdip);
- for (; dip; dip = ddi_get_next_sibling(dip)) {
- /* make sure dip is attached, ie. fm_ready */
- if (!(ppd_p = pcie_get_ppd(dip)) ||
- !pf_enter(dip))
- continue;
-
- sts = pf_default_hdl(dip, pdip, ppd_p, impl);
- ret |= (sts & PF_FAILURE) ? DDI_FAILURE : DDI_SUCCESS;
-
- if (sts & PF_DO_NOT_SCAN)
- continue;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ if (!bus_p)
+ return (NULL);
- if (ppd_p->ppd_hdr_type == PCI_HEADER_ONE)
- ret |= pf_pci_dispatch(dip, impl);
- }
- return (ret);
+ if (!(bus_p->bus_fm_flags & PF_FM_READY))
+ return (NULL);
+ return (bus_p);
}
-int
-pf_pcie_dispatch(dev_info_t *pdip, pf_impl_t *impl)
+static void
+pf_pcix_ecc_regs_gather(pf_pcix_ecc_regs_t *pcix_ecc_regs,
+ pcie_bus_t *bus_p, boolean_t bdg)
{
- dev_info_t *dip;
- pcie_req_id_t rid = impl->pf_fbdf;
- pcie_ppd_t *ppd_p;
- int sts, ret = DDI_SUCCESS;
-
- dip = ddi_get_child(pdip);
- for (; dip; dip = ddi_get_next_sibling(dip)) {
- /* Make sure dip is attached and fm_ready */
- if (!(ppd_p = pcie_get_ppd(dip)) ||
- !pf_enter(dip))
- continue;
-
- if ((ppd_p->ppd_bdf == rid) ||
- pf_in_bus_range(ppd_p, rid) ||
- pf_in_addr_range(ppd_p, impl->pf_faddr)) {
- sts = pf_default_hdl(dip, pdip, ppd_p, impl);
-
- ret |= (sts & PF_FAILURE) ? DDI_FAILURE : DDI_SUCCESS;
-
- if (sts & PF_DO_NOT_SCAN)
- continue;
- } else {
- pf_exit(dip);
- continue;
- }
-
- /* match or in bridge bus-range */
- switch (ppd_p->ppd_dev_type) {
- case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
- ret |= pf_pci_dispatch(dip, impl);
- return (ret);
- case PCIE_PCIECAP_DEV_TYPE_UP:
- case PCIE_PCIECAP_DEV_TYPE_DOWN:
- if (ppd_p->ppd_bdf != rid)
- ret |= pf_pcie_dispatch(dip, impl);
- /* FALLTHROUGH */
- case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
- return (ret);
- case PCIE_PCIECAP_DEV_TYPE_ROOT:
- default:
- ASSERT(B_FALSE);
- }
+ if (bdg) {
+ pcix_ecc_regs->pcix_ecc_ctlstat = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_BDG_ECC_STATUS);
+ pcix_ecc_regs->pcix_ecc_fstaddr = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_BDG_ECC_FST_AD);
+ pcix_ecc_regs->pcix_ecc_secaddr = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_BDG_ECC_SEC_AD);
+ pcix_ecc_regs->pcix_ecc_attr = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_BDG_ECC_ATTR);
+ } else {
+ pcix_ecc_regs->pcix_ecc_ctlstat = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_ECC_STATUS);
+ pcix_ecc_regs->pcix_ecc_fstaddr = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_ECC_FST_AD);
+ pcix_ecc_regs->pcix_ecc_secaddr = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_ECC_SEC_AD);
+ pcix_ecc_regs->pcix_ecc_attr = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_ECC_ATTR);
}
- return (ret);
}
-/*
- * Called by the RC to scan the fabric.
- *
- * After all the necessary fabric devices are scanned, the error queue will be
- * analyzed for error severity and ereports will be sent.
- */
-int
-pf_scan_fabric(dev_info_t *rpdip, ddi_fm_error_t *derr,
- pf_data_t *dq_p, int *dq_tail_p)
-{
- pf_impl_t impl;
- pf_data_t *rc_pf_data_p;
- int i, sts, ret = DDI_SUCCESS;
- int last_rc_index = *dq_tail_p;
-
- impl.pf_rpdip = rpdip;
- impl.pf_derr = derr;
- impl.pf_dq_p = dq_p;
- impl.pf_dq_tail_p = dq_tail_p;
-
- i = 0;
+static void
+pf_pcix_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p)
+{
/*
- * Scan the fabric using the fault_bdf and fault_addr in error q.
- * fault_bdf will be valid in the following cases:
- * - Fabric message
- * - Poisoned TLP
- * - Signaled UR/CA
- * - Received UR/CA
- * - PIO load failures
+ * For PCI-X device PCI-X Capability only exists for Type 0 Headers.
+ * PCI-X Bridge Capability only exists for Type 1 Headers.
+ * Both capabilities do not exist at the same time.
*/
- for (rc_pf_data_p = dq_p; IS_RC(rc_pf_data_p) && i <= last_rc_index;
- rc_pf_data_p++, i++) {
- impl.pf_fbdf = rc_pf_data_p->fault_bdf;
- impl.pf_faddr = rc_pf_data_p->fault_addr;
-
- if ((impl.pf_fbdf && pf_find_in_q(impl.pf_fbdf, dq_p,
- *dq_tail_p) == PF_DATA_NOT_FOUND) ||
- (!impl.pf_fbdf && impl.pf_faddr))
- ret |= pf_pcie_dispatch(rpdip, &impl);
- }
+ if (PCIE_IS_BDG(bus_p)) {
+ pf_pcix_bdg_err_regs_t *pcix_bdg_regs;
- /* If this is due to safe access, don't analyse the errors and return */
- if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) {
- ret = DDI_SUCCESS;
- sts = PF_NO_PANIC;
- } else {
- sts = pf_analyse_error(rpdip, derr, dq_p, *dq_tail_p);
- pf_check_ce(dq_p, *dq_tail_p);
- }
+ pcix_bdg_regs = PCIX_BDG_ERR_REG(pfd_p);
- pf_send_ereport(rpdip, derr, dq_p, *dq_tail_p);
- *dq_tail_p = -1;
+ pcix_bdg_regs->pcix_bdg_sec_stat = PCIX_CAP_GET(16, bus_p,
+ PCI_PCIX_SEC_STATUS);
+ pcix_bdg_regs->pcix_bdg_stat = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_BDG_STATUS);
- /*
- * If ret is not SUCCESS that means we were not able to add 1 or more
- * devices to the fault q. Since that device could have have been the
- * one which had a error, be conservative and panic here.
- */
- if (ret != DDI_SUCCESS)
- return (PF_PANIC | sts);
- else
- return (sts);
-}
-
-/*
- * For each device in the fault queue ensure that no ereport is sent if that
- * device was scanned as a result of a CE in one of its children.
- */
-void
-pf_check_ce(pf_data_t *dq_p, int dq_tail) {
- int i = dq_tail;
- pf_data_t *pf_data_p;
-
- for (pf_data_p = &dq_p[dq_tail]; i >= 0; pf_data_p = &dq_p[--i]) {
- if (pf_data_p->send_erpt == PF_SEND_ERPT_UNKNOWN) {
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
/*
- * Always send ereport for the last device in a
- * particular scan path.
+ * PCI Express to PCI-X bridges only implement the
+ * secondary side of the PCI-X ECC registers, bit one is
+ * read-only so we make sure we do not write to it.
*/
- pf_data_p->send_erpt = PF_SEND_ERPT_YES;
-
- if (pf_data_p->severity_flags == (PF_CE |
- PF_NO_ERROR)) {
- /*
- * Since this device had a CE don't send ereport
- * for parents.
- */
- pf_set_parent_erpt(dq_p,
- pf_data_p->parent_index, PF_SEND_ERPT_NO);
- } else {
- /* Send ereports for all parents */
- pf_set_parent_erpt(dq_p,
- pf_data_p->parent_index, PF_SEND_ERPT_YES);
+ if (!PCIE_IS_PCIE_BDG(bus_p)) {
+ PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
+ 0);
+ pf_pcix_ecc_regs_gather(
+ PCIX_BDG_ECC_REG(pfd_p, 0), bus_p, B_TRUE);
+ PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
+ 1);
}
+ pf_pcix_ecc_regs_gather(PCIX_BDG_ECC_REG(pfd_p, 0),
+ bus_p, B_TRUE);
}
+ } else {
+ pf_pcix_err_regs_t *pcix_regs = PCIX_ERR_REG(pfd_p);
+
+ pcix_regs->pcix_command = PCIX_CAP_GET(16, bus_p,
+ PCI_PCIX_COMMAND);
+ pcix_regs->pcix_status = PCIX_CAP_GET(32, bus_p,
+ PCI_PCIX_STATUS);
+ if (PCIX_ECC_VERSION_CHECK(bus_p))
+ pf_pcix_ecc_regs_gather(PCIX_ECC_REG(pfd_p), bus_p,
+ B_TRUE);
}
-
-}
-
-void
-pf_set_parent_erpt(pf_data_t *dq_p, int index, int erpt_val) {
- int i;
- pf_data_t *pf_data_p;
-
- for (i = index; i != PF_DATA_NOT_FOUND; i = pf_data_p->parent_index) {
- pf_data_p = &dq_p[i];
-
- if (pf_data_p->send_erpt != PF_SEND_ERPT_YES)
- pf_data_p->send_erpt = erpt_val;
-
- }
-}
-
-/*
- * Returns the index of the bdf if found in the PCIe Fault Data Queue
- * Returns PF_DATA_NOT_FOUND of the index if the bdf is not found.
- * This function should not be called by RC.
- */
-static int
-pf_find_in_q(pcie_req_id_t bdf, pf_data_t *dq_p, int dq_tail)
-{
- int i;
-
- /* Check if this is the first item in queue */
- if (dq_tail == -1)
- return (PF_DATA_NOT_FOUND);
-
- for (i = dq_tail; i >= 0; i--) {
- if (dq_p[i].bdf == bdf)
- return (i);
- }
-
- return (PF_DATA_NOT_FOUND);
-}
-
-int
-pf_get_dq_size()
-{
- return (pf_dq_size);
-}
-
-/*
- * Add PFD to queue.
- * Return true if successfully added.
- * Return false if out of space or already in queue.
- * Pass in pbdf = -1 if pfd is from RC.
- */
-int
-pf_en_dq(pf_data_t *pf_data_p, pf_data_t *dq_p, int *dq_tail_p,
- pcie_req_id_t pbdf)
-{
- int parent_index = PF_DATA_NOT_FOUND;
-
- if (*dq_tail_p >= (int)pf_dq_size)
- return (DDI_FAILURE);
-
- /* Look for parent BDF if pfd is not from RC and save rp_bdf */
- if (pbdf != (uint16_t)0xFFFF) {
- parent_index = pf_find_in_q(pbdf, dq_p, *dq_tail_p);
- pf_data_p->rp_bdf = dq_p[0].rp_bdf;
- }
-
- *dq_tail_p += 1;
- dq_p[*dq_tail_p] = *pf_data_p;
- dq_p[*dq_tail_p].parent_index = parent_index;
- return (DDI_SUCCESS);
}
-/* Load PCIe Fault Data for PCI/PCIe devices into PCIe Fault Data Queue */
-static int
-pf_default_hdl(dev_info_t *dip, dev_info_t *pdip,
- pcie_ppd_t *ppd_p, pf_impl_t *impl)
+static void
+pf_pcie_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p)
{
- ddi_acc_handle_t h = ppd_p->ppd_cfg_hdl;
- pf_data_t pf_data = {0};
- pcie_req_id_t pbdf;
- uint16_t pcie_off, aer_off, pcix_off;
- uint8_t hdr_type, dev_type;
- int cb_sts, sts = PF_SUCCESS;
+ pf_pcie_err_regs_t *pcie_regs = PCIE_ERR_REG(pfd_p);
+ pf_pcie_adv_err_regs_t *pcie_adv_regs = PCIE_ADV_REG(pfd_p);
- pbdf = PCI_GET_BDF(pdip);
- pf_data.bdf = PCI_GET_BDF(dip);
+ pcie_regs->pcie_err_status = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS);
+ pcie_regs->pcie_err_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
+ pcie_regs->pcie_dev_cap = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP);
- /* Make sure this device hasn't already been snapshotted and cleared */
- if (pf_find_in_q(pf_data.bdf, impl->pf_dq_p, *impl->pf_dq_tail_p) !=
- PF_DATA_NOT_FOUND)
- return (PF_SUCCESS);
+ if (PCIE_IS_BDG(bus_p) && PCIE_IS_PCIX(bus_p))
+ pf_pcix_regs_gather(pfd_p, bus_p);
- pf_data.dip = dip;
- pf_data.bdg_secbus = ppd_p->ppd_bdg_secbus << 8;
- pf_data.vendor_id = ppd_p->ppd_dev_ven_id & 0xFFFF;
- pf_data.device_id = ppd_p->ppd_dev_ven_id >> 16;
- pf_data.send_erpt = PF_SEND_ERPT_UNKNOWN;
+ if (PCIE_IS_ROOT(bus_p)) {
+ pf_pcie_rp_err_regs_t *pcie_rp_regs = PCIE_RP_REG(pfd_p);
- /*
- * Read vendor/device ID and check with cached data, if it doesn't match
- * could very well be a device that isn't responding anymore. Just
- * stop. Save the basic info in the error q for post mortem debugging
- * purposes.
- */
- if (pci_config_get32(h, PCI_CONF_VENID) != ppd_p->ppd_dev_ven_id) {
- (void) pf_en_dq(&pf_data, impl->pf_dq_p, impl->pf_dq_tail_p,
- pbdf);
- return (DDI_FAILURE);
- }
-
- hdr_type = ppd_p->ppd_hdr_type;
- dev_type = ppd_p->ppd_dev_type;
-
- pf_data.hdr_type = hdr_type;
- pf_data.command = pci_config_get16(h, PCI_CONF_COMM);
- pf_data.status = pci_config_get16(h, PCI_CONF_STAT);
- pf_data.rev_id = pci_config_get8(h, PCI_CONF_REVID);
- pcie_off = ppd_p->ppd_pcie_off;
- aer_off = ppd_p->ppd_aer_off;
-
- if (hdr_type == PCI_HEADER_ONE) {
- pf_data.s_status = pci_config_get16(h, PCI_BCNF_SEC_STATUS);
- }
-
- pf_data.dev_type = dev_type;
- if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI_DEV) {
- if (pci_lcap_locate(h, PCI_CAP_ID_PCIX, &pcix_off)
- != DDI_FAILURE) {
- pf_data.pcix_s_status = pci_config_get16(h,
- pcix_off + PCI_PCIX_SEC_STATUS);
- pf_data.pcix_bdg_status = pci_config_get32(h,
- pcix_off + PCI_PCIX_BDG_STATUS);
- }
- goto clear;
- }
-
- if (!pcie_off)
- goto clear;
-
- pf_data.dev_status = PCI_CAP_GET16(h, NULL, pcie_off, PCIE_DEVSTS);
- pf_data.pcie_off = pcie_off;
-
- /*
- * If a bridge does not have any error no need to scan any further down.
- * For PCIe devices, check the PCIe device status and PCI secondary
- * status.
- * - Some non-compliant PCIe devices do not utilize PCIe
- * error registers. If so rely on legacy PCI error registers.
- * For PCI devices, check the PCI secondary status.
- */
- if (hdr_type == PCI_HEADER_ONE) {
- if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
- !(pf_data.dev_status & PF_PCIE_BDG_ERR) &&
- !(pf_data.s_status & PF_PCI_BDG_ERR))
- sts |= PF_DO_NOT_SCAN;
-
- if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCI_DEV) &&
- !(pf_data.s_status & PF_PCI_BDG_ERR))
- sts |= PF_DO_NOT_SCAN;
+ pcie_rp_regs->pcie_rp_status = PCIE_CAP_GET(32, bus_p,
+ PCIE_ROOTSTS);
+ pcie_rp_regs->pcie_rp_ctl = PCIE_CAP_GET(16, bus_p,
+ PCIE_ROOTCTL);
}
- if (!aer_off)
- goto clear;
+ if (!PCIE_HAS_AER(bus_p))
+ return;
- pf_data.aer_off = aer_off;
- pf_data.aer_ce_status = PCI_XCAP_GET32(h, NULL, aer_off,
- PCIE_AER_CE_STS);
- pf_data.aer_ue_status = PCI_XCAP_GET32(h, NULL, aer_off,
+ /* Gather UE AERs */
+ pcie_adv_regs->pcie_adv_ctl = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_CTL);
+ pcie_adv_regs->pcie_ue_status = PCIE_AER_GET(32, bus_p,
PCIE_AER_UCE_STS);
- pf_data.aer_severity = PCI_XCAP_GET32(h, NULL, aer_off,
+ pcie_adv_regs->pcie_ue_mask = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_UCE_MASK);
+ pcie_adv_regs->pcie_ue_sev = PCIE_AER_GET(32, bus_p,
PCIE_AER_UCE_SERV);
- pf_data.aer_control = PCI_XCAP_GET32(h, NULL, aer_off, PCIE_AER_CTL);
- pf_data.aer_h0 = PCI_XCAP_GET32(h, NULL, aer_off,
- PCIE_AER_HDR_LOG + 0x0);
- pf_data.aer_h1 = PCI_XCAP_GET32(h, NULL, aer_off,
+ PCIE_ADV_HDR(pfd_p, 0) = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_HDR_LOG);
+ PCIE_ADV_HDR(pfd_p, 1) = PCIE_AER_GET(32, bus_p,
PCIE_AER_HDR_LOG + 0x4);
- pf_data.aer_h2 = PCI_XCAP_GET32(h, NULL, aer_off,
+ PCIE_ADV_HDR(pfd_p, 2) = PCIE_AER_GET(32, bus_p,
PCIE_AER_HDR_LOG + 0x8);
- pf_data.aer_h3 = PCI_XCAP_GET32(h, NULL, aer_off,
+ PCIE_ADV_HDR(pfd_p, 3) = PCIE_AER_GET(32, bus_p,
PCIE_AER_HDR_LOG + 0xc);
- if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
- pf_data.s_aer_ue_status = PCI_XCAP_GET32(h, NULL, aer_off,
+ /* Gather CE AERs */
+ pcie_adv_regs->pcie_ce_status = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_CE_STS);
+ pcie_adv_regs->pcie_ce_mask = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_CE_MASK);
+
+ /*
+ * If pci express to pci bridge then grab the bridge
+ * error registers.
+ */
+ if (PCIE_IS_PCIE_BDG(bus_p)) {
+ pf_pcie_adv_bdg_err_regs_t *pcie_bdg_regs =
+ PCIE_ADV_BDG_REG(pfd_p);
+
+ pcie_bdg_regs->pcie_sue_ctl = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_SCTL);
+ pcie_bdg_regs->pcie_sue_status = PCIE_AER_GET(32, bus_p,
PCIE_AER_SUCE_STS);
- pf_data.s_aer_severity = PCI_XCAP_GET32(h, NULL, aer_off,
+ pcie_bdg_regs->pcie_sue_mask = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_SUCE_MASK);
+ pcie_bdg_regs->pcie_sue_sev = PCIE_AER_GET(32, bus_p,
PCIE_AER_SUCE_SERV);
- pf_data.s_aer_control = PCI_XCAP_GET32(h, NULL, aer_off,
- PCIE_AER_SCTL);
- pf_data.s_aer_h0 = PCI_XCAP_GET32(h, NULL, aer_off,
- PCIE_AER_SHDR_LOG + 0x0);
- pf_data.s_aer_h1 = PCI_XCAP_GET32(h, NULL, aer_off,
+ PCIE_ADV_BDG_HDR(pfd_p, 0) = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_SHDR_LOG);
+ PCIE_ADV_BDG_HDR(pfd_p, 1) = PCIE_AER_GET(32, bus_p,
PCIE_AER_SHDR_LOG + 0x4);
- pf_data.s_aer_h2 = PCI_XCAP_GET32(h, NULL, aer_off,
+ PCIE_ADV_BDG_HDR(pfd_p, 2) = PCIE_AER_GET(32, bus_p,
PCIE_AER_SHDR_LOG + 0x8);
- pf_data.s_aer_h3 = PCI_XCAP_GET32(h, NULL, aer_off,
+ PCIE_ADV_BDG_HDR(pfd_p, 3) = PCIE_AER_GET(32, bus_p,
PCIE_AER_SHDR_LOG + 0xc);
}
-clear:
- /* Clear the Legacy PCI Errors */
- pci_config_put16(h, PCI_CONF_STAT, pf_data.status);
-
- if (hdr_type == PCI_HEADER_ONE)
- pci_config_put16(h, PCI_BCNF_SEC_STATUS, pf_data.s_status);
-
- if (!pcie_off)
- goto queue;
-
- /* Clear the Advanced PCIe Errors */
- if (aer_off) {
- PCI_XCAP_PUT32(h, NULL, aer_off, PCIE_AER_CE_STS,
- pf_data.aer_ce_status);
- PCI_XCAP_PUT32(h, NULL, aer_off, PCIE_AER_UCE_STS,
- pf_data.aer_ue_status);
-
- if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI)
- PCI_XCAP_PUT32(h, NULL, aer_off,
- PCIE_AER_SUCE_STS, pf_data.s_aer_ue_status);
- }
-
- /* Clear the PCIe Errors */
- PCI_CAP_PUT16(h, PCI_CAP_ID_PCI_E, pcie_off, PCIE_DEVSTS,
- pf_data.dev_status);
-
-queue:
/*
- * If the driver is FMA hardened and callback capable, call it's
- * callback function
+ * If PCI Express root port then grab the root port
+ * error registers.
*/
- if (DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
- cb_sts = ndi_fm_handler_dispatch(pdip, dip, impl->pf_derr);
- if (cb_sts == DDI_FM_FATAL || cb_sts == DDI_FM_UNKNOWN)
- sts |= PF_FAILURE;
- else
- sts |= PF_SUCCESS;
+ if (PCIE_IS_ROOT(bus_p)) {
+ pf_pcie_adv_rp_err_regs_t *pcie_rp_regs =
+ PCIE_ADV_RP_REG(pfd_p);
+
+ pcie_rp_regs->pcie_rp_err_cmd = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_RE_CMD);
+ pcie_rp_regs->pcie_rp_err_status = PCIE_AER_GET(32, bus_p,
+ PCIE_AER_RE_STS);
+ pcie_rp_regs->pcie_rp_ce_src_id = PCIE_AER_GET(16, bus_p,
+ PCIE_AER_CE_SRC_ID);
+ pcie_rp_regs->pcie_rp_ue_src_id = PCIE_AER_GET(16, bus_p,
+ PCIE_AER_ERR_SRC_ID);
}
-
- /* Add the snapshot to the error q */
- if (pf_en_dq(&pf_data, impl->pf_dq_p, impl->pf_dq_tail_p, pbdf) ==
- DDI_FAILURE)
- sts |= PF_FAILURE;
-
- return (sts);
}
-/*
- * Function used by PCI error handlers to check if captured address is stored
- * in the DMA or ACC handle caches.
- * return: PF_HDL_NOTFOUND if a handle is not found
- * PF_HDL_FOUND if a handle is found
- */
-int
-pf_hdl_lookup(dev_info_t *dip, uint64_t ena, uint32_t flag, uint32_t addr,
- pcie_req_id_t bdf)
+static void
+pf_pci_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p)
{
- ddi_fm_error_t derr;
- int found = 0;
+ pf_pci_err_regs_t *pci_regs = PCI_ERR_REG(pfd_p);
- /* If we don't know the addr or rid just return with UNKNOWN */
- if (addr == NULL && bdf == NULL)
- return (PF_HDL_NOTFOUND);
+ /*
+ * Start by reading all the error registers that are available for
+ * pci and pci express and for leaf devices and bridges/switches
+ */
+ pci_regs->pci_err_status = PCIE_GET(16, bus_p, PCI_CONF_STAT);
+ pci_regs->pci_cfg_comm = PCIE_GET(16, bus_p, PCI_CONF_COMM);
- if (!(flag & (PF_DMA_ADDR | PF_PIO_ADDR | PF_CFG_ADDR))) {
- return (PF_HDL_NOTFOUND);
+ /*
+ * If pci-pci bridge grab PCI bridge specific error registers.
+ */
+ if (PCIE_IS_BDG(bus_p)) {
+ pf_pci_bdg_err_regs_t *pci_bdg_regs = PCI_BDG_ERR_REG(pfd_p);
+ pci_bdg_regs->pci_bdg_sec_stat =
+ PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
+ pci_bdg_regs->pci_bdg_ctrl =
+ PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
}
- bzero(&derr, sizeof (ddi_fm_error_t));
- derr.fme_version = DDI_FME_VERSION;
- derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
- derr.fme_ena = ena;
-
- /* If we know the addr or bdf mark the handle as failed */
- if (flag & PF_DMA_ADDR) {
- if (pf_hdl_child_lookup(dip, dip, &derr, addr, bdf,
- pf_dma_hdl_check) != PF_HDL_NOTFOUND)
- found++;
- }
- if (flag & PF_PIO_ADDR) {
- if (pf_hdl_child_lookup(dip, dip, &derr, addr, bdf,
- pf_pio_hdl_check) != PF_HDL_NOTFOUND)
- found++;
- }
- if (flag & PF_CFG_ADDR) {
- if (pf_hdl_child_lookup(dip, dip, &derr, addr, bdf,
- pf_cfg_hdl_check) != PF_HDL_NOTFOUND)
- found++;
- }
+ /*
+ * If pci express device grab pci express error registers and
+ * check for advanced error reporting features and grab them if
+ * available.
+ */
+ if (PCIE_IS_PCIE(bus_p))
+ pf_pcie_regs_gather(pfd_p, bus_p);
+ else if (PCIE_IS_PCIX(bus_p))
+ pf_pcix_regs_gather(pfd_p, bus_p);
- return (found ? PF_HDL_FOUND : PF_HDL_NOTFOUND);
}
-/*
- * Recursively search the tree for the handler that matches the given address.
- * If the BDF is known, only check the handlers that are associated with the
- * given BDF, otherwise search the entire tree.
- */
-static int
-pf_hdl_child_lookup(dev_info_t *rpdip, dev_info_t *dip,
- ddi_fm_error_t *derr, uint32_t addr, pcie_req_id_t bdf,
- pf_hdl_compare_t cf)
+static void
+pf_pcix_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p)
{
- int status = PF_HDL_NOTFOUND;
- struct i_ddi_fmhdl *fmhdl;
- struct i_ddi_fmtgt *tgt;
- pcie_req_id_t child_bdf;
+ if (PCIE_IS_BDG(bus_p)) {
+ pf_pcix_bdg_err_regs_t *pcix_bdg_regs;
- child_bdf = PCI_GET_BDF(dip);
+ pcix_bdg_regs = PCIX_BDG_ERR_REG(pfd_p);
- i_ddi_fm_handler_enter(dip);
- fmhdl = DEVI(dip)->devi_fmhdl;
- ASSERT(fmhdl);
-
- /* Check if dip and BDF match, if not recurse to it's children. */
- if (bdf == NULL || child_bdf == bdf) {
- /* If we found the handler stop the search */
- if ((status = cf(fmhdl, derr, addr, bdf)) != PF_HDL_NOTFOUND)
- goto done;
- }
-
- /* If we can't find the handler check it's children */
- for (tgt = fmhdl->fh_tgts; tgt != NULL; tgt = tgt->ft_next) {
- if ((status = pf_hdl_child_lookup(rpdip, tgt->ft_dip, derr,
- addr, bdf, cf)) != PF_HDL_NOTFOUND)
- goto done;
- }
+ PCIX_CAP_PUT(16, bus_p, PCI_PCIX_SEC_STATUS,
+ pcix_bdg_regs->pcix_bdg_sec_stat);
-done:
- i_ddi_fm_handler_exit(dip);
+ PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_STATUS,
+ pcix_bdg_regs->pcix_bdg_stat);
- return (status);
-}
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
+ pf_pcix_ecc_regs_t *pcix_bdg_ecc_regs;
+ /*
+ * PCI Express to PCI-X bridges only implement the
+ * secondary side of the PCI-X ECC registers. For
+ * clearing, there is no need to "select" the ECC
+ * register, just write what was originally read.
+ */
+ if (!PCIE_IS_PCIE_BDG(bus_p)) {
+ pcix_bdg_ecc_regs = PCIX_BDG_ECC_REG(pfd_p, 0);
+ PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
+ pcix_bdg_ecc_regs->pcix_ecc_ctlstat);
-/*
- * Find and Mark CFG Handles as failed associated with the given BDF. We should
- * always know the BDF for CFG accesses, since it is encoded in the address of
- * the TLP. Since there can be multiple cfg handles, mark them all as failed.
- */
-/* ARGSUSED */
-static int
-pf_cfg_hdl_check(struct i_ddi_fmhdl *fmhdl, ddi_fm_error_t *derr,
- uint32_t notused, pcie_req_id_t bdf)
-{
- ndi_fmc_t *fcp;
- ndi_fmcentry_t *fep;
- ddi_acc_handle_t ap;
- ddi_acc_hdl_t *hp;
- int status = PF_HDL_NOTFOUND;
+ }
+ pcix_bdg_ecc_regs = PCIX_BDG_ECC_REG(pfd_p, 1);
+ PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
+ pcix_bdg_ecc_regs->pcix_ecc_ctlstat);
+ }
+ } else {
+ pf_pcix_err_regs_t *pcix_regs = PCIX_ERR_REG(pfd_p);
- ASSERT(bdf);
+ PCIX_CAP_PUT(32, bus_p, PCI_PCIX_STATUS,
+ pcix_regs->pcix_status);
- /* Return NOTFOUND if this driver doesn't support ACC flagerr */
- if (!DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap) ||
- ((fcp = fmhdl->fh_acc_cache) == NULL))
- return (PF_HDL_NOTFOUND);
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
+ pf_pcix_ecc_regs_t *pcix_ecc_regs = PCIX_ECC_REG(pfd_p);
- mutex_enter(&fcp->fc_lock);
- for (fep = fcp->fc_active->fce_next; fep; fep = fep->fce_next) {
- ap = fep->fce_resource;
- hp = impl_acc_hdl_get(ap);
-
- /* CFG space is always reg 0 */
- if (hp->ah_rnumber == 0) {
- i_ddi_fm_acc_err_set(ap, derr->fme_ena, DDI_FM_NONFATAL,
- DDI_FM_ERR_UNEXPECTED);
- ddi_fm_acc_err_get(ap, derr, DDI_FME_VERSION);
- derr->fme_acc_handle = ap;
- status = PF_HDL_FOUND;
+ PCIX_CAP_PUT(32, bus_p, PCI_PCIX_ECC_STATUS,
+ pcix_ecc_regs->pcix_ecc_ctlstat);
}
}
- mutex_exit(&fcp->fc_lock);
-
- return (status);
}
-/*
- * Find and Mark all ACC Handles associated with a give address and BDF as
- * failed. If the BDF != NULL, then check to see if the device has a ACC Handle
- * associated with ADDR. If the handle is not found, mark all the handles as
- * failed. If the BDF == NULL, mark the handle as failed if it is associated
- * with ADDR.
- */
-static int
-pf_pio_hdl_check(struct i_ddi_fmhdl *fmhdl, ddi_fm_error_t *derr,
- uint32_t addr, pcie_req_id_t bdf)
+static void
+pf_pcie_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p)
{
- ndi_fmc_t *fcp;
- ndi_fmcentry_t *fep;
- ddi_acc_handle_t ap;
- ddi_acc_hdl_t *hp;
- uint32_t base_addr;
- uint_t size;
- int status = PF_HDL_NOTFOUND;
+ pf_pcie_err_regs_t *pcie_regs = PCIE_ERR_REG(pfd_p);
+ pf_pcie_adv_err_regs_t *pcie_adv_regs = PCIE_ADV_REG(pfd_p);
- if (!DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap) ||
- ((fcp = fmhdl->fh_acc_cache) == NULL))
- return (PF_HDL_NOTFOUND);
+ PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS, pcie_regs->pcie_err_status);
- mutex_enter(&fcp->fc_lock);
- for (fep = fcp->fc_active->fce_next; fep; fep = fep->fce_next) {
- ap = fep->fce_resource;
- hp = impl_acc_hdl_get(ap);
+ if (PCIE_IS_BDG(bus_p) && PCIE_IS_PCIX(bus_p))
+ pf_pcix_regs_clear(pfd_p, bus_p);
- /* CFG space is always reg 0, don't mark config handlers. */
- if (hp->ah_rnumber == 0)
- continue;
+ if (!PCIE_HAS_AER(bus_p))
+ return;
- /*
- * Normalize the base addr to the addr and strip off the
- * HB info. All PIOs are 32 bit access only.
- */
- base_addr = (uint32_t)(hp->ah_pfn << MMU_PAGESHIFT) +
- hp->ah_offset;
- size = hp->ah_len;
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_STS,
+ pcie_adv_regs->pcie_ue_status);
- if (((addr >= base_addr) && (addr < (base_addr + size))) ||
- ((addr == NULL) && (bdf != NULL))) {
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS,
+ pcie_adv_regs->pcie_ce_status);
- status = PF_HDL_FOUND;
+ if (PCIE_IS_PCIE_BDG(bus_p)) {
+ pf_pcie_adv_bdg_err_regs_t *pcie_bdg_regs =
+ PCIE_ADV_BDG_REG(pfd_p);
- i_ddi_fm_acc_err_set(ap, derr->fme_ena, DDI_FM_NONFATAL,
- DDI_FM_ERR_UNEXPECTED);
- ddi_fm_acc_err_get(ap, derr, DDI_FME_VERSION);
- derr->fme_acc_handle = ap;
- }
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_STS,
+ pcie_bdg_regs->pcie_sue_status);
}
- mutex_exit(&fcp->fc_lock);
/*
- * If no handles found and we know this is the right device mark
- * all the handles as failed.
+ * If PCI Express root complex then clear the root complex
+ * error registers.
*/
- if (addr && bdf != NULL && status == PF_HDL_NOTFOUND)
- status = pf_pio_hdl_check(fmhdl, derr, NULL, bdf);
+ if (PCIE_IS_ROOT(bus_p)) {
+ pf_pcie_adv_rp_err_regs_t *pcie_rp_regs;
- return (status);
+ pcie_rp_regs = PCIE_ADV_RP_REG(pfd_p);
+
+ PCIE_AER_PUT(32, bus_p, PCIE_AER_RE_STS,
+ pcie_rp_regs->pcie_rp_err_status);
+ }
}
-/*
- * Find and Mark all DNA Handles associated with a give address and BDF as
- * failed. If the BDF != NULL, then check to see if the device has a DMA Handle
- * associated with ADDR. If the handle is not found, mark all the handles as
- * failed. If the BDF == NULL, mark the handle as failed if it is associated
- * with ADDR.
- */
-static int
-pf_dma_hdl_check(struct i_ddi_fmhdl *fmhdl, ddi_fm_error_t *derr,
- uint32_t addr, pcie_req_id_t bdf)
+static void
+pf_pci_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p)
{
- ndi_fmc_t *fcp;
- ndi_fmcentry_t *fep;
- ddi_dma_impl_t *pcie_dp;
- ddi_dma_handle_t dp;
- int status = PF_HDL_NOTFOUND;
- uint32_t base_addr;
- uint_t size;
+ if (PCIE_IS_PCIE(bus_p))
+ pf_pcie_regs_clear(pfd_p, bus_p);
+ else if (PCIE_IS_PCIX(bus_p))
+ pf_pcix_regs_clear(pfd_p, bus_p);
- if (!DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap) ||
- ((fcp = fmhdl->fh_dma_cache) == NULL))
- return (PF_HDL_NOTFOUND);
+ PCIE_PUT(16, bus_p, PCI_CONF_STAT, pfd_p->pe_pci_regs->pci_err_status);
- mutex_enter(&fcp->fc_lock);
- for (fep = fcp->fc_active->fce_next; fep; fep = fep->fce_next) {
- pcie_dp = (ddi_dma_impl_t *)fep->fce_resource;
- dp = (ddi_dma_handle_t)fep->fce_resource;
- base_addr = (uint32_t)pcie_dp->dmai_mapping;
- size = pcie_dp->dmai_size;
-
- /*
- * Mark the handle as failed if the ADDR is mapped, or if we
- * know the BDF and ADDR == 0.
- */
- if (((addr >= base_addr) && (addr < (base_addr + size))) ||
- ((addr == NULL) && (bdf != NULL))) {
-
- status = PF_HDL_FOUND;
-
- i_ddi_fm_dma_err_set(dp, derr->fme_ena, DDI_FM_NONFATAL,
- DDI_FM_ERR_UNEXPECTED);
- ddi_fm_dma_err_get(dp, derr, DDI_FME_VERSION);
- derr->fme_dma_handle = dp;
- }
+ if (PCIE_IS_BDG(bus_p)) {
+ pf_pci_bdg_err_regs_t *pci_bdg_regs = PCI_BDG_ERR_REG(pfd_p);
+ PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS,
+ pci_bdg_regs->pci_bdg_sec_stat);
}
- mutex_exit(&fcp->fc_lock);
+}
- /*
- * If no handles found and we know this is the right device mark
- * all the handles as failed.
- */
- if (addr && bdf != NULL && status == PF_HDL_NOTFOUND)
- status = pf_dma_hdl_check(fmhdl, derr, NULL, bdf);
+/* ARGSUSED */
+void
+pcie_clear_errors(dev_info_t *dip)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
- return (status);
+ ASSERT(bus_p);
+
+ pf_pci_regs_gather(pfd_p, bus_p);
+ pf_pci_regs_clear(pfd_p, bus_p);
}
-/*
- * If a PCIe device does not support AER, assume all AER statuses have been set,
- * unless other registers do not indicate a certain error occuring.
- */
+/* Find the fault BDF, fault Addr or full scan on a PCIe Root Port. */
static void
-pf_adjust_for_no_aer(pf_data_t *pf_data_p)
+pf_pci_find_rp_fault(pf_data_t *pfd_p, pcie_bus_t *bus_p)
{
- uint32_t aer_ue = 0;
-
- if (pf_data_p->aer_off)
+ pf_root_fault_t *root_fault = PCIE_ROOT_FAULT(pfd_p);
+ pf_pcie_adv_rp_err_regs_t *rp_regs = PCIE_ADV_RP_REG(pfd_p);
+ uint32_t root_err = rp_regs->pcie_rp_err_status;
+ uint32_t ue_err = PCIE_ADV_REG(pfd_p)->pcie_ue_status;
+ int num_faults = 0;
+
+ /* Since this data structure is reused, make sure to reset it */
+ root_fault->full_scan = B_FALSE;
+ root_fault->fault_bdf = 0;
+ root_fault->fault_addr = 0;
+
+ if (!PCIE_HAS_AER(bus_p) &&
+ (PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR)) {
+ PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
return;
+ }
- if (pf_data_p->dev_status & PCIE_DEVSTS_FE_DETECTED) {
- aer_ue = PF_AER_FATAL_ERR;
- } else if (pf_data_p->dev_status & PCIE_DEVSTS_NFE_DETECTED) {
- aer_ue = PF_AER_NON_FATAL_ERR;
- /* Check if the device received a PTLP */
- if (!(pf_data_p->status & PCI_STAT_PERROR))
- aer_ue &= ~PCIE_AER_UCE_PTLP;
+ /*
+ * Check to see if an error has been received that
+ * requires a scan of the fabric. Count the number of
+ * faults seen. If MUL CE/FE_NFE that counts for
+ * atleast 2 faults, so just return with full_scan.
+ */
+ if ((root_err & PCIE_AER_RE_STS_MUL_CE_RCVD) ||
+ (root_err & PCIE_AER_RE_STS_MUL_FE_NFE_RCVD)) {
+ PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
+ return;
+ }
- /* Check if the device signaled a CA */
- if (!(pf_data_p->status & PCI_STAT_S_TARG_AB))
- aer_ue &= ~PCIE_AER_UCE_CA;
+ if (root_err & PCIE_AER_RE_STS_CE_RCVD)
+ num_faults++;
- /* Check if the device sent a UR */
- if ((!pf_data_p->dev_status & PCIE_DEVSTS_UR_DETECTED))
- aer_ue &= ~PCIE_AER_UCE_UR;
+ if (root_err & PCIE_AER_RE_STS_FE_NFE_RCVD)
+ num_faults++;
- /*
- * Ignore ECRCs as it is optional and will manefest itself as
- * another error like PTLP and MFP
- */
- aer_ue &= ~PCIE_AER_UCE_ECRC;
- }
+ if (ue_err & PCIE_AER_UCE_CA)
+ num_faults++;
- if (pf_data_p->dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
- aer_ue &= ~PCIE_AER_UCE_TRAINING;
- aer_ue &= ~PCIE_AER_UCE_SD;
- }
- pf_data_p->aer_ue_status = aer_ue;
-}
+ if (ue_err & PCIE_AER_UCE_UR)
+ num_faults++;
-static void
-pf_adjust_for_no_saer(pf_data_t *pf_data_p)
-{
- uint32_t s_aer_ue = 0;
+ /* If no faults just return */
+ if (num_faults == 0)
+ return;
- if (pf_data_p->aer_off)
+ /* If faults > 1 do full scan */
+ if (num_faults > 1) {
+ PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
return;
+ }
- if (pf_data_p->dev_status & PCIE_DEVSTS_FE_DETECTED) {
- s_aer_ue = PF_SAER_FATAL_ERR;
- } else if (pf_data_p->dev_status & PCIE_DEVSTS_NFE_DETECTED) {
- s_aer_ue = PF_SAER_NON_FATAL_ERR;
- /* Check if the device received a UC_DATA */
- if (!(pf_data_p->s_status & PCI_STAT_PERROR))
- s_aer_ue &= ~PCIE_AER_SUCE_UC_DATA_ERR;
+ /* By this point, there is only 1 fault detected */
+ if ((root_err & PCIE_AER_RE_STS_CE_RCVD) &&
+ rp_regs->pcie_rp_ce_src_id) {
+ PCIE_ROOT_FAULT(pfd_p)->fault_bdf = rp_regs->pcie_rp_ce_src_id;
+ num_faults--;
+ } else if ((root_err & PCIE_AER_RE_STS_FE_NFE_RCVD) &&
+ rp_regs->pcie_rp_ue_src_id) {
+ PCIE_ROOT_FAULT(pfd_p)->fault_bdf = rp_regs->pcie_rp_ue_src_id;
+ num_faults--;
+ } else if ((HAS_AER_LOGS(pfd_p, PCIE_AER_UCE_CA) ||
+ HAS_AER_LOGS(pfd_p, PCIE_AER_UCE_UR)) &&
+ (pf_tlp_decode(PCIE_PFD2BUS(pfd_p), PCIE_ADV_REG(pfd_p)) ==
+ DDI_SUCCESS)) {
+ PCIE_ROOT_FAULT(pfd_p)->fault_bdf =
+ PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr;
+ num_faults--;
+ }
- /* Check if the device received a RCVD_MA/MA_ON_SC */
- if (!(pf_data_p->s_status & (PCI_STAT_R_MAST_AB))) {
- s_aer_ue &= ~PCIE_AER_SUCE_RCVD_MA;
- s_aer_ue &= ~PCIE_AER_SUCE_MA_ON_SC;
- }
+ /*
+ * This means an error did occur, but we couldn't extract the fault BDF
+ */
+ if (num_faults > 0)
+ PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
- /* Check if the device received a RCVD_TA/TA_ON_SC */
- if (!(pf_data_p->s_status & (PCI_STAT_R_TARG_AB))) {
- s_aer_ue &= ~PCIE_AER_SUCE_RCVD_TA;
- s_aer_ue &= ~PCIE_AER_SUCE_TA_ON_SC;
- }
- }
- pf_data_p->s_aer_ue_status = s_aer_ue;
}
-/* Find the PCIe-PCI bridge of a PCI device */
-static pf_data_t *
-pf_get_parent_pcie_bridge(pf_data_t *dq_p, pf_data_t *pf_data_p)
+
+/*
+ * Load PCIe Fault Data for PCI/PCIe devices into PCIe Fault Data Queue
+ *
+ * Returns a scan flag.
+ * o PF_SCAN_SUCCESS - Error gathered and cleared sucessfuly, data added to
+ * Fault Q
+ * o PF_SCAN_BAD_RESPONSE - Unable to talk to device, item not added to fault Q
+ * o PF_SCAN_CB_FAILURE - A hardened device deemed that the error was fatal.
+ * o PF_SCAN_NO_ERR_IN_CHILD - Only applies to bridge to prevent further
+ * unnecessary scanning
+ * o PF_SCAN_IN_DQ - This device has already been scanned; it was skipped this
+ * time.
+ */
+static int
+pf_default_hdl(dev_info_t *dip, pf_impl_t *impl)
{
- pf_data_t *bdg_pf_data_p;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
+ int cb_sts, scan_flag = PF_SCAN_SUCCESS;
- if (pf_data_p->dev_type != PCIE_PCIECAP_DEV_TYPE_PCI_DEV)
- return (NULL);
+ /* Make sure this device hasn't already been snapshotted and cleared */
+ if (pfd_p->pe_valid == B_TRUE) {
+ scan_flag |= PF_SCAN_IN_DQ;
+ goto done;
+ }
- if (pf_data_p->parent_index == PF_DATA_NOT_FOUND)
- return (NULL);
+ /*
+ * Read vendor/device ID and check with cached data, if it doesn't match
+ * could very well be a device that isn't responding anymore. Just
+ * stop. Save the basic info in the error q for post mortem debugging
+ * purposes.
+ */
+ if (PCIE_GET(32, bus_p, PCI_CONF_VENID) != bus_p->bus_dev_ven_id) {
+ char buf[FM_MAX_CLASS];
+
+ (void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
+ PCI_ERROR_SUBCLASS, PCI_NR);
+ ddi_fm_ereport_post(dip, buf, fm_ena_generate(0, FM_ENA_FMT1),
+ DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL);
- for (bdg_pf_data_p = &dq_p[pf_data_p->parent_index];
- bdg_pf_data_p->dev_type != PCIE_PCIECAP_DEV_TYPE_PCIE2PCI;
- bdg_pf_data_p = &dq_p[bdg_pf_data_p->parent_index]) {
- if (!bdg_pf_data_p || (bdg_pf_data_p->parent_index ==
- PF_DATA_NOT_FOUND))
- return (NULL);
+ return (PF_SCAN_BAD_RESPONSE);
}
- return (bdg_pf_data_p);
-}
+ pf_pci_regs_gather(pfd_p, bus_p);
+ pf_pci_regs_clear(pfd_p, bus_p);
+ if (PCIE_IS_RP(bus_p))
+ pf_pci_find_rp_fault(pfd_p, bus_p);
-/*
- * See if a leaf error was bubbled up to the RC and handled.
- * Check if the RC logged an error with the appropriate status type/abort type.
- * Ex: Parity Error, Received Master/Target Abort
- * Check if either the fault address found in the rc matches the device's
- * assigned address range (PIO's only) or the fault BDF in the rc matches the
- * device's BDF or Secondary Bus.
- */
-static boolean_t
-pf_matched_in_rc(pf_data_t *dq_p, pf_data_t *pf_data_p, uint32_t abort_type)
-{
- pf_data_t *rc_pf_data_p;
- pcie_ppd_t *ppd_p;
+ cb_sts = pf_fm_callback(dip, impl->pf_derr);
- ppd_p = pcie_get_ppd(pf_data_p->dip);
- for (rc_pf_data_p = dq_p; IS_RC(rc_pf_data_p); rc_pf_data_p++) {
- /* If device and rc abort type does not match continue */
- if (!(rc_pf_data_p->s_status & abort_type))
- continue;
+ if (cb_sts == DDI_FM_FATAL || cb_sts == DDI_FM_UNKNOWN)
+ scan_flag |= PF_SCAN_CB_FAILURE;
- /* The Fault BDF = Device's BDF */
- if (rc_pf_data_p->fault_bdf == pf_data_p->bdf)
- return (B_TRUE);
+ /* Add the snapshot to the error q */
+ pf_en_dq(pfd_p, impl);
- /* The Fault Addr is in device's address range */
- if (pf_in_addr_range(ppd_p, rc_pf_data_p->fault_addr))
- return (B_TRUE);
+done:
+ /*
+ * If a bridge does not have any error no need to scan any further down.
+ * For PCIe devices, check the PCIe device status and PCI secondary
+ * status.
+ * - Some non-compliant PCIe devices do not utilize PCIe
+ * error registers. If so rely on legacy PCI error registers.
+ * For PCI devices, check the PCI secondary status.
+ */
+ if (PCIE_IS_PCIE_BDG(bus_p) &&
+ !(PCIE_ERR_REG(pfd_p)->pcie_err_status & PF_PCIE_BDG_ERR) &&
+ !(PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR))
+ scan_flag |= PF_SCAN_NO_ERR_IN_CHILD;
- /* The Fault BDF is from PCIe-PCI Bridge's secondary bus */
- if ((pf_data_p->dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
- ((rc_pf_data_p->fault_bdf & PCIE_REQ_ID_BUS_MASK) ==
- pf_data_p->bdg_secbus))
- return (B_TRUE);
- }
+ if (PCIE_IS_PCI_BDG(bus_p) &&
+ !(PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR))
+ scan_flag |= PF_SCAN_NO_ERR_IN_CHILD;
- return (B_FALSE);
+ pfd_p->pe_valid = B_TRUE;
+ return (scan_flag);
}
/*
- * Decodes the TLP and returns the BDF of the handler, address and transaction
- * type if known.
- *
- * Types of TLP logs seen in RC, and what to extract:
- *
- * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR
- * Memory(PIO) - address, PF_PIO_ADDR
- * CFG - Should not occur and result in UR
- * Completion(DMA) - Requester BDF, PF_DMA_ADDR
- * Completion(PIO) - Requester BDF, PF_PIO_ADDR
- *
- * Types of TLP logs seen in SW/Leaf, and what to extract:
+ * Called during postattach to initialize a device's error handling
+ * capabilities. If the devices has already been hardened, then there isn't
+ * much needed. Otherwise initialize the device's default FMA capabilities.
*
- * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR
- * Memory(PIO) - address, PF_PIO_ADDR
- * CFG - Destined BDF, address, PF_CFG_ADDR
- * Completion(DMA) - Requester BDF, PF_DMA_ADDR
- * Completion(PIO) - Requester BDF, PF_PIO_ADDR
- *
- * If the TLP can be decoded the *bdf, *addr, and *trans_type will be populated
- * with the TLP information. The caller may pass in NULL for any of the
- * mentioned variables, if they are not interested in them.
+ * In a future project where PCIe support is removed from pcifm, several
+ * "properties" that are setup in ddi_fm_init and pci_ereport_setup need to be
+ * created here so that the PCI/PCIe eversholt rules will work properly.
*/
-/* ARGSUSED */
-int
-pf_tlp_decode(dev_info_t *rpdip, pf_data_t *pf_data_p, pcie_req_id_t *bdf,
- uint32_t *addr, uint32_t *trans_type)
+void
+pf_init(dev_info_t *dip, ddi_iblock_cookie_t ibc, ddi_attach_cmd_t cmd)
{
- pcie_tlp_hdr_t *tlp_hdr = (pcie_tlp_hdr_t *)&pf_data_p->aer_h0;
- pcie_req_id_t rp_bdf, rid_bdf, tlp_bdf;
- uint32_t tlp_addr, tlp_trans_type;
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
+ boolean_t need_cb_register = B_FALSE;
- rp_bdf = pf_data_p->rp_bdf;
+ if (!bus_p) {
+ cmn_err(CE_WARN, "devi_bus information is not set for %s%d.\n",
+ ddi_driver_name(dip), ddi_get_instance(dip));
+ return;
+ }
- switch (tlp_hdr->type) {
- case PCIE_TLP_TYPE_IO:
- case PCIE_TLP_TYPE_MEM:
- case PCIE_TLP_TYPE_MEMLK:
+ if (fmhdl) {
/*
- * Obtain IO/Memory address based on whether TLP
- * Header has a 4DW (four doublewords) or 3DW layout.
+ * If device is only ereport capable and not callback capable
+ * make it callback capable. The only downside is that the
+ * "fm-errcb-capable" property is not created for this device
+ * which should be ok since it's not used anywhere.
*/
- if ((tlp_hdr->fmt & 0x1) != 0) {
- /* then TLP Header contains a 64-bit addr */
+ if (!(fmhdl->fh_cap & DDI_FM_ERRCB_CAPABLE))
+ need_cb_register = B_TRUE;
+ } else {
+ int cap;
+ /*
+ * fm-capable in driver.conf can be used to set fm_capabilities.
+ * If fm-capable is not defined, set the default
+ * DDI_FM_EREPORT_CAPABLE and DDI_FM_ERRCB_CAPABLE.
+ */
+ cap = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "fm-capable",
+ DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE);
+ cap &= (DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE);
- /*
- * Use a dummy value for now, as 64-bit addrs
- * are not fully supported. This unique,
- * well-known value will assist in debugging.
- */
- tlp_addr = 0;
- } else {
- /* TLP Header has the 3DW layout. */
- pcie_memio32_t *h;
+ bus_p->bus_fm_flags |= PF_FM_IS_NH;
- h = (pcie_memio32_t *)&pf_data_p->aer_h1;
- tlp_addr = h->addr0 << 2;
+ if (cmd == DDI_ATTACH) {
+ ddi_fm_init(dip, &cap, &ibc);
+ pci_ereport_setup(dip);
}
- /* If the RID_BDF == RP_BDF, PIO, otherwise DMA */
- rid_bdf = (pcie_req_id_t)(pf_data_p->aer_h1 >> 16);
- if (rid_bdf == rp_bdf) {
- tlp_trans_type = PF_PIO_ADDR;
- tlp_bdf = NULL;
- } else {
- tlp_trans_type = PF_DMA_ADDR;
- tlp_bdf = rid_bdf;
- }
- break;
- case PCIE_TLP_TYPE_CFG0:
- case PCIE_TLP_TYPE_CFG1:
- tlp_addr = 0;
- tlp_bdf = (pcie_req_id_t)(pf_data_p->aer_h2 >> 16);
- tlp_trans_type = PF_CFG_ADDR;
- break;
- case PCIE_TLP_TYPE_CPL:
- case PCIE_TLP_TYPE_CPLLK:
- tlp_addr = NULL;
- /*
- * If the completer bdf == RP_BDF, DMA, otherwise PIO or a CFG
- * completion.
- */
- tlp_bdf = (pcie_req_id_t)(pf_data_p->aer_h1 >> 16);
- if (tlp_bdf == rp_bdf)
- tlp_trans_type = PF_DMA_ADDR;
- else
- tlp_trans_type = PF_PIO_ADDR | PF_CFG_ADDR;
- break;
- default:
- return (DDI_FAILURE);
+ if (cap & DDI_FM_ERRCB_CAPABLE)
+ need_cb_register = B_TRUE;
+
+ fmhdl = DEVI(dip)->devi_fmhdl;
}
- if (addr)
- *addr = tlp_addr;
- if (trans_type)
- *trans_type = tlp_trans_type;
- if (bdf)
- *bdf = tlp_bdf;
+ /* If ddi_fm_init fails for any reason RETURN */
+ if (!fmhdl) {
+ bus_p->bus_fm_flags = 0;
+ return;
+ }
- return (DDI_SUCCESS);
+ fmhdl->fh_cap |= DDI_FM_ERRCB_CAPABLE;
+ if (cmd == DDI_ATTACH) {
+ if (need_cb_register)
+ ddi_fm_handler_register(dip, pf_dummy_cb, NULL);
+ }
+
+ bus_p->bus_fm_flags |= PF_FM_READY;
}
-/*
- * pf_pci_decode function decodes the secondary aer transaction logs in
- * PCIe-PCI bridges.
- *
- * The log is 128 bits long and arranged in this manner.
- * [0:35] Transaction Attribute (s_aer_h0-saer_h1)
- * [36:39] Transaction lower command (saer_h1)
- * [40:43] Transaction upper command (saer_h1)
- * [44:63] Reserved
- * [64:127] Address (saer_h2-saer_h3)
- */
-/* ARGSUSED */
-static int
-pf_pci_decode(dev_info_t *rpdip, pf_data_t *pf_data_p, uint16_t *cmd,
- pcie_req_id_t *bdf, uint32_t *addr, uint32_t *trans_type) {
- pcix_attr_t *attr;
- pcie_req_id_t rp_bdf;
+/* undo FMA lock, called at predetach */
+void
+pf_fini(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
- rp_bdf = pf_data_p->rp_bdf;
+ if (!bus_p)
+ return;
- *cmd = GET_SAER_CMD(pf_data_p);
+ /* Don't fini anything if device isn't FM Ready */
+ if (!(bus_p->bus_fm_flags & PF_FM_READY))
+ return;
- switch (*cmd) {
- case PCI_PCIX_CMD_MEMRD_DW:
- case PCI_PCIX_CMD_MEMRD_BL:
- case PCI_PCIX_CMD_MEMRDBL:
- case PCI_PCIX_CMD_MEMWR:
- case PCI_PCIX_CMD_MEMWR_BL:
- case PCI_PCIX_CMD_MEMWRBL:
- *addr = pf_data_p->s_aer_h2;
- attr = (pcix_attr_t *)&pf_data_p->s_aer_h0;
+ /* no other code should set the flag to false */
+ bus_p->bus_fm_flags &= ~PF_FM_READY;
- /*
- * Could be DMA or PIO. Find out by look at requesting bdf.
- * If the requester is the RC, then it's a PIO, otherwise, DMA
- */
- *bdf = attr->rid;
- if (*bdf == rp_bdf) {
- *trans_type = PF_PIO_ADDR;
- *bdf = 0;
- } else {
- *trans_type = PF_DMA_ADDR;
+ /*
+ * Grab the mutex to make sure device isn't in the middle of
+ * error handling. Setting the bus_fm_flag to ~PF_FM_READY
+ * should prevent this device from being error handled after
+ * the mutex has been released.
+ */
+ (void) pf_handler_enter(dip, NULL);
+ pf_handler_exit(dip);
+
+ /* undo non-hardened drivers */
+ if (bus_p->bus_fm_flags & PF_FM_IS_NH) {
+ if (cmd == DDI_DETACH) {
+ bus_p->bus_fm_flags &= ~PF_FM_IS_NH;
+ pci_ereport_teardown(dip);
+ /*
+ * ddi_fini itself calls ddi_handler_unregister,
+ * so no need to explicitly call unregister.
+ */
+ ddi_fm_fini(dip);
}
- break;
- case PCI_PCIX_CMD_CFRD:
- case PCI_PCIX_CMD_CFWR:
- /*
- * CFG Access should always be down stream. Match the BDF in
- * the address phase.
- */
- *addr = 0;
- attr = (pcix_attr_t *)&pf_data_p->s_aer_h2;
- *bdf = attr->rid;
- *trans_type = PF_CFG_ADDR;
- break;
- case PCI_PCIX_CMD_SPL:
- /*
- * Check for DMA read completions. The requesting BDF is in the
- * Address phase.
- */
- *addr = 0;
- attr = (pcix_attr_t *)&pf_data_p->s_aer_h0;
- *bdf = attr->rid;
- *trans_type = PF_DMA_ADDR;
- break;
- default:
- *addr = 0;
- *bdf = 0;
- *trans_type = 0;
- return (DDI_FAILURE);
}
- return (DDI_SUCCESS);
}
-/*
- * For this function only the Primary AER Header Logs need to be valid in the
- * pfd (PCIe Fault Data) arg.
- */
-int
-pf_tlp_hdl_lookup(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *pf_data_p)
+/*ARGSUSED*/
+static int
+pf_dummy_cb(dev_info_t *dip, ddi_fm_error_t *derr, const void *not_used)
{
- uint32_t addr;
- int err = PF_HDL_NOTFOUND;
- pcie_req_id_t hdl_bdf;
- uint32_t trans_type;
-
- if (pf_tlp_decode(rpdip, pf_data_p, &hdl_bdf, &addr, &trans_type) ==
- DDI_SUCCESS) {
- err = pf_hdl_lookup(rpdip, derr->fme_ena, trans_type, addr,
- hdl_bdf);
- }
-
- return (err);
+ return (DDI_FM_OK);
}
/*
- * Last function called for PF Scan Fabric.
- * Sends ereports for all devices that are not dev_type = RC.
- * Will also unlock all the mutexes grabbed during fabric scan.
+ * Add PFD to queue. If it is an RC add it to the beginning,
+ * otherwise add it to the end.
*/
-/* ARGSUSED */
static void
-pf_send_ereport(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *dq_p,
- int dq_tail)
+pf_en_dq(pf_data_t *pfd_p, pf_impl_t *impl)
{
- char buf[FM_MAX_CLASS];
- pf_data_t *pfd_p;
- int i, total = dq_tail;
- boolean_t hasError = B_FALSE;
+ pf_data_t *head_p = impl->pf_dq_head_p;
+ pf_data_t *tail_p = impl->pf_dq_tail_p;
- i = 0;
- /*
- * Search through the error queue and look for the number of pf_data
- * from the RC and if the queue contains any errors. All the pf_data's
- * from the RC will only be at the top of the queue.
- */
- for (pfd_p = dq_p; i <= dq_tail; pfd_p++, i++) {
- if (IS_RC(pfd_p)) {
- total--;
- if (pfd_p->s_status)
- hasError = B_TRUE;
- } else {
- if (hasError)
- break;
- if (pfd_p->severity_flags != PF_NO_ERROR) {
- hasError = B_TRUE;
- break;
- }
- }
+ impl->pf_total++;
+
+ if (!head_p) {
+ ASSERT(PFD_IS_ROOT(pfd_p));
+ impl->pf_dq_head_p = pfd_p;
+ impl->pf_dq_tail_p = pfd_p;
+ pfd_p->pe_prev = NULL;
+ pfd_p->pe_next = NULL;
+ return;
}
- i = dq_tail;
- for (pfd_p = &dq_p[dq_tail]; i >= 0; pfd_p--, i--) {
- if (IS_RC(pfd_p))
- continue;
+ /* Check if this is a Root Port eprt */
+ if (PFD_IS_ROOT(pfd_p)) {
+ pf_data_t *root_p, *last_p = NULL;
- if ((!hasError) || (pfd_p->send_erpt == PF_SEND_ERPT_NO) ||
- (derr->fme_flag != DDI_FM_ERR_UNEXPECTED))
- goto unlock;
-
- (void) snprintf(buf, FM_MAX_CLASS, "%s", "fire.fabric");
- ddi_fm_ereport_post(pfd_p->dip, buf, derr->fme_ena,
- DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
- "req_id", DATA_TYPE_UINT16, pfd_p->bdf,
- "device_id", DATA_TYPE_UINT16, pfd_p->device_id,
- "vendor_id", DATA_TYPE_UINT16, pfd_p->vendor_id,
- "rev_id", DATA_TYPE_UINT8, pfd_p->rev_id,
- "dev_type", DATA_TYPE_UINT16, pfd_p->dev_type,
- "cap_off", DATA_TYPE_UINT16, pfd_p->pcie_off,
- "aer_off", DATA_TYPE_UINT16, pfd_p->aer_off,
- "sts_reg", DATA_TYPE_UINT16, pfd_p->status,
- "sts_sreg", DATA_TYPE_UINT16, pfd_p->s_status,
- "pcix_sts_reg", DATA_TYPE_UINT16, pfd_p->pcix_s_status,
- "pcix_bdg_sts_reg", DATA_TYPE_UINT32,
- pfd_p->pcix_bdg_status,
- "dev_sts_reg", DATA_TYPE_UINT16, pfd_p->dev_status,
- "aer_ce", DATA_TYPE_UINT32, pfd_p->aer_ce_status,
- "aer_ue", DATA_TYPE_UINT32, pfd_p->aer_ue_status,
- "aer_sev", DATA_TYPE_UINT32, pfd_p->aer_severity,
- "aer_ctr", DATA_TYPE_UINT32, pfd_p->aer_control,
- "aer_h1", DATA_TYPE_UINT32, pfd_p->aer_h0,
- "aer_h2", DATA_TYPE_UINT32, pfd_p->aer_h1,
- "aer_h3", DATA_TYPE_UINT32, pfd_p->aer_h2,
- "aer_h4", DATA_TYPE_UINT32, pfd_p->aer_h3,
- "saer_ue", DATA_TYPE_UINT32, pfd_p->s_aer_ue_status,
- "saer_sev", DATA_TYPE_UINT32, pfd_p->s_aer_severity,
- "saer_ctr", DATA_TYPE_UINT32, pfd_p->s_aer_control,
- "saer_h1", DATA_TYPE_UINT32, pfd_p->s_aer_h0,
- "saer_h2", DATA_TYPE_UINT32, pfd_p->s_aer_h1,
- "saer_h3", DATA_TYPE_UINT32, pfd_p->s_aer_h2,
- "saer_h4", DATA_TYPE_UINT32, pfd_p->s_aer_h3,
- "remainder", DATA_TYPE_UINT32, total--,
- "severity", DATA_TYPE_UINT32, pfd_p->severity_flags,
- NULL);
+ /* The first item must be a RP */
+ root_p = head_p;
+ for (last_p = head_p; last_p && PFD_IS_ROOT(last_p);
+ last_p = last_p->pe_next)
+ root_p = last_p;
+
+ /* root_p is the last RP pfd. last_p is the first non-RP pfd. */
+ root_p->pe_next = pfd_p;
+ pfd_p->pe_prev = root_p;
+ pfd_p->pe_next = last_p;
-unlock:
- pf_exit(pfd_p->dip);
+ if (last_p)
+ last_p->pe_prev = pfd_p;
+ else
+ tail_p = pfd_p;
+ } else {
+ tail_p->pe_next = pfd_p;
+ pfd_p->pe_prev = tail_p;
+ pfd_p->pe_next = NULL;
+ tail_p = pfd_p;
}
+
+ impl->pf_dq_head_p = head_p;
+ impl->pf_dq_tail_p = tail_p;
}
/*
@@ -1397,6 +1104,22 @@ const pf_fab_err_tbl_t pcie_pcie_tbl[] = {
NULL, NULL
};
+const pf_fab_err_tbl_t pcie_rp_tbl[] = {
+ PCIE_AER_UCE_TRAINING, pf_no_panic,
+ PCIE_AER_UCE_DLP, pf_panic,
+ PCIE_AER_UCE_SD, pf_no_panic,
+ PCIE_AER_UCE_PTLP, pf_analyse_ptlp,
+ PCIE_AER_UCE_FCP, pf_panic,
+ PCIE_AER_UCE_TO, pf_panic,
+ PCIE_AER_UCE_CA, pf_no_panic,
+ PCIE_AER_UCE_UC, pf_analyse_uc,
+ PCIE_AER_UCE_RO, pf_panic,
+ PCIE_AER_UCE_MTLP, pf_panic,
+ PCIE_AER_UCE_ECRC, pf_panic,
+ PCIE_AER_UCE_UR, pf_no_panic,
+ NULL, NULL
+};
+
const pf_fab_err_tbl_t pcie_sw_tbl[] = {
PCIE_AER_UCE_TRAINING, pf_no_panic,
PCIE_AER_UCE_DLP, pf_panic,
@@ -1451,95 +1174,108 @@ const pf_fab_err_tbl_t pcie_pci_tbl[] = {
};
/*
- * Analyse all the PCIe Fault Data (pfd) gathered during dispatch in the pfd
+ * Analyse all the PCIe Fault Data (erpt) gathered during dispatch in the erpt
* Queue.
*/
static int
-pf_analyse_error(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *dq_p,
- int dq_tail)
+pf_analyse_error(ddi_fm_error_t *derr, pf_impl_t *impl)
{
- int i = 0, pfd_err, err = 0;
- pf_data_t *pf_data_p;
+ int sts_flags, error_flags = 0;
+ pf_data_t *pfd_p;
- for (pf_data_p = &dq_p[i]; i <= dq_tail; pf_data_p = &dq_p[++i]) {
- pfd_err = 0;
- switch (pf_data_p->dev_type) {
- case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
- if (PCIE_DEVSTS_CE_DETECTED & pf_data_p->dev_status)
- pfd_err |= PF_CE;
+ for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) {
+ sts_flags = 0;
- pf_adjust_for_no_aer(pf_data_p);
- pfd_err |= pf_analyse_error_tbl(rpdip, derr, dq_p,
- pf_data_p, pcie_pcie_tbl, pf_data_p->aer_ue_status);
+ switch (PCIE_PFD2BUS(pfd_p)->bus_dev_type) {
+ case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
+ if (PCIE_DEVSTS_CE_DETECTED &
+ PCIE_ERR_REG(pfd_p)->pcie_err_status)
+ sts_flags |= PF_ERR_CE;
+
+ pf_adjust_for_no_aer(pfd_p);
+ sts_flags |= pf_analyse_error_tbl(derr, impl,
+ pfd_p, pcie_pcie_tbl,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_status);
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_ROOT:
+ pf_adjust_for_no_aer(pfd_p);
+ sts_flags |= pf_analyse_error_tbl(derr, impl,
+ pfd_p, pcie_rp_tbl,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_status);
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO:
+ /* no adjust_for_aer for pseudo RC */
+ (void) pf_analyse_error_tbl(derr, impl, pfd_p,
+ pcie_rp_tbl, PCIE_ADV_REG(pfd_p)->pcie_ue_status);
break;
case PCIE_PCIECAP_DEV_TYPE_UP:
case PCIE_PCIECAP_DEV_TYPE_DOWN:
- if (PCIE_DEVSTS_CE_DETECTED & pf_data_p->dev_status)
- pfd_err |= PF_CE;
-
- pf_adjust_for_no_aer(pf_data_p);
- pfd_err |= pf_analyse_error_tbl(rpdip, derr, dq_p,
- pf_data_p, pcie_sw_tbl, pf_data_p->aer_ue_status);
- break;
- case PCIE_PCIECAP_DEV_TYPE_ROOT:
- /* Do not analyse RC info as it has already been done */
- pfd_err |= PF_NO_ERROR;
+ if (PCIE_DEVSTS_CE_DETECTED &
+ PCIE_ERR_REG(pfd_p)->pcie_err_status)
+ sts_flags |= PF_ERR_CE;
+
+ pf_adjust_for_no_aer(pfd_p);
+ sts_flags |= pf_analyse_error_tbl(derr, impl,
+ pfd_p, pcie_sw_tbl,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_status);
break;
case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
- if (PCIE_DEVSTS_CE_DETECTED & pf_data_p->dev_status)
- pfd_err |= PF_CE;
-
- if ((PCIE_DEVSTS_NFE_DETECTED |
- PCIE_DEVSTS_FE_DETECTED)
- & pf_data_p->dev_status) {
- pf_adjust_for_no_aer(pf_data_p);
- pf_adjust_for_no_saer(pf_data_p);
- pfd_err |= pf_analyse_error_tbl(rpdip, derr,
- dq_p, pf_data_p, pcie_pcie_tbl,
- pf_data_p->aer_ue_status);
- pfd_err |= pf_analyse_error_tbl(rpdip, derr,
- dq_p, pf_data_p, pcie_pcie_bdg_tbl,
- pf_data_p->s_aer_ue_status);
- break;
- }
+ if (PCIE_DEVSTS_CE_DETECTED &
+ PCIE_ERR_REG(pfd_p)->pcie_err_status)
+ sts_flags |= PF_ERR_CE;
+
+ pf_adjust_for_no_aer(pfd_p);
+ pf_adjust_for_no_saer(pfd_p);
+ sts_flags |= pf_analyse_error_tbl(derr,
+ impl, pfd_p, pcie_pcie_tbl,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_status);
+ sts_flags |= pf_analyse_error_tbl(derr,
+ impl, pfd_p, pcie_pcie_bdg_tbl,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status);
/*
* Some non-compliant PCIe devices do not utilize PCIe
* error registers. So fallthrough and rely on legacy
* PCI error registers.
*/
+ if ((PCIE_DEVSTS_NFE_DETECTED | PCIE_DEVSTS_FE_DETECTED)
+ & PCIE_ERR_REG(pfd_p)->pcie_err_status)
+ break;
/* FALLTHROUGH */
case PCIE_PCIECAP_DEV_TYPE_PCI_DEV:
- pfd_err |= pf_analyse_error_tbl(rpdip, derr, dq_p,
- pf_data_p, pcie_pci_tbl, pf_data_p->status);
- if (pf_data_p->hdr_type == PCI_HEADER_ONE)
- pfd_err |= pf_analyse_error_tbl(rpdip, derr,
- dq_p, pf_data_p, pcie_pci_bdg_tbl,
- pf_data_p->s_status);
- break;
+ sts_flags |= pf_analyse_error_tbl(derr, impl,
+ pfd_p, pcie_pci_tbl,
+ PCI_ERR_REG(pfd_p)->pci_err_status);
+
+ if (!PCIE_IS_BDG(PCIE_PFD2BUS(pfd_p)))
+ break;
+
+ sts_flags |= pf_analyse_error_tbl(derr,
+ impl, pfd_p, pcie_pci_bdg_tbl,
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat);
}
- err |= pfd_err;
- pf_data_p->severity_flags = pfd_err;
+ pfd_p->pe_severity_flags = sts_flags;
+ error_flags |= pfd_p->pe_severity_flags;
}
- return (err);
+ return (error_flags);
}
static int
-pf_analyse_error_tbl(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *dq_p,
- pf_data_t *pf_data_p, const pf_fab_err_tbl_t *tbl, uint32_t err_reg) {
+pf_analyse_error_tbl(ddi_fm_error_t *derr, pf_impl_t *impl,
+ pf_data_t *pfd_p, const pf_fab_err_tbl_t *tbl, uint32_t err_reg) {
const pf_fab_err_tbl_t *row;
int err = 0;
- for (row = tbl; err_reg && (row->bit != NULL) && !(err & PF_PANIC);
+ for (row = tbl; err_reg && (row->bit != NULL) && !(err & PF_ERR_PANIC);
row++) {
if (err_reg & row->bit)
- err |= row->handler(rpdip, derr, row->bit, dq_p,
- pf_data_p);
+ err |= row->handler(derr, row->bit, impl->pf_dq_head_p,
+ pfd_p);
}
if (!err)
- err = PF_NO_ERROR;
+ err = PF_ERR_NO_ERROR;
return (err);
}
@@ -1553,28 +1289,38 @@ pf_analyse_error_tbl(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *dq_p,
*/
/* ARGSUSED */
static int
-pf_analyse_ca_ur(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_ca_ur(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
uint32_t abort_type;
+ dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
+
+ /* If UR's are masked forgive this error */
+ if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) &&
+ (bit == PCIE_AER_UCE_UR))
+ return (PF_ERR_NO_PANIC);
+
+ /*
+ * If a RP has an CA/UR it means a leaf sent a bad request to the RP
+ * such as a config read or a bad DMA address.
+ */
+ if (PCIE_IS_RP(PCIE_PFD2BUS(pfd_p)))
+ goto handle_lookup;
if (bit == PCIE_AER_UCE_UR)
abort_type = PCI_STAT_R_MAST_AB;
else
abort_type = PCI_STAT_R_TARG_AB;
- if (pf_matched_in_rc(dq_p, pf_data_p, abort_type))
- return (PF_MATCHED_RC);
-
- if (HAS_AER_LOGS(pf_data_p, bit)) {
- if (pf_tlp_hdl_lookup(rpdip, derr, pf_data_p) ==
- PF_HDL_NOTFOUND)
- return (PF_PANIC);
+ if (pf_matched_in_rc(dq_head_p, pfd_p, abort_type))
+ return (PF_ERR_MATCHED_RC);
- return (PF_MATCHED_DEVICE);
- }
+handle_lookup:
+ if (HAS_AER_LOGS(pfd_p, bit) &&
+ pf_log_hdl_lookup(rpdip, derr, pfd_p, B_TRUE) == PF_HDL_FOUND)
+ return (PF_ERR_MATCHED_DEVICE);
- return (PF_PANIC);
+ return (PF_ERR_PANIC);
}
/*
@@ -1586,34 +1332,32 @@ pf_analyse_ca_ur(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
*/
/* ARGSUSED */
static int
-pf_analyse_ma_ta(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_ma_ta(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
- uint16_t cmd;
- uint32_t addr;
- pcie_req_id_t bdf;
- uint32_t abort_type, trans_type;
+ dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
+ uint32_t abort_type;
+
+ /* If UR's are masked forgive this error */
+ if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) &&
+ (bit == PCIE_AER_SUCE_RCVD_MA))
+ return (PF_ERR_NO_PANIC);
if (bit == PCIE_AER_SUCE_RCVD_MA)
abort_type = PCI_STAT_R_MAST_AB;
else
abort_type = PCI_STAT_R_TARG_AB;
- if (pf_matched_in_rc(dq_p, pf_data_p, abort_type))
- return (PF_MATCHED_RC);
+ if (pf_matched_in_rc(dq_head_p, pfd_p, abort_type))
+ return (PF_ERR_MATCHED_RC);
- if (!HAS_SAER_LOGS(pf_data_p, bit))
- return (PF_PANIC);
+ if (!HAS_SAER_LOGS(pfd_p, bit))
+ return (PF_ERR_PANIC);
- if (pf_pci_decode(rpdip, pf_data_p, &cmd, &bdf, &addr, &trans_type) !=
- DDI_SUCCESS)
- return (PF_PANIC);
+ if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE) == PF_HDL_FOUND)
+ return (PF_ERR_MATCHED_DEVICE);
- if (pf_hdl_lookup(rpdip, derr->fme_ena, trans_type, addr, bdf) ==
- PF_HDL_NOTFOUND)
- return (PF_PANIC);
-
- return (PF_MATCHED_DEVICE);
+ return (PF_ERR_PANIC);
}
/*
@@ -1626,18 +1370,23 @@ pf_analyse_ma_ta(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
*/
/* ARGSUSED */
static int
-pf_analyse_pci(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_pci(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
pf_data_t *parent_pfd_p;
uint16_t cmd;
- uint32_t addr;
- pcie_req_id_t bdf;
- uint32_t trans_type, aer_ue_status;
- pcie_ppd_t *ppd_p;
+ uint32_t aer_ue_status;
+ pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p);
+ pf_pcie_adv_bdg_err_regs_t *parent_saer_p;
+
+ if (PCI_ERR_REG(pfd_p)->pci_err_status & PCI_STAT_S_SYSERR)
+ return (PF_ERR_PANIC);
+
+ /* If UR's are masked forgive this error */
+ if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) &&
+ (bit == PCI_STAT_R_MAST_AB))
+ return (PF_ERR_NO_PANIC);
- if (pf_data_p->status & PCI_STAT_S_SYSERR)
- return (PF_PANIC);
if (bit & (PCI_STAT_PERROR | PCI_STAT_S_PERROR)) {
aer_ue_status = PCIE_AER_SUCE_PERR_ASSERT;
@@ -1647,26 +1396,27 @@ pf_analyse_pci(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
PCIE_AER_SUCE_RCVD_MA);
}
- parent_pfd_p = pf_get_parent_pcie_bridge(dq_p, pf_data_p);
+ parent_pfd_p = pf_get_parent_pcie_bridge(pfd_p);
if (parent_pfd_p == NULL)
- return (PF_PANIC);
+ return (PF_ERR_PANIC);
- if (!(parent_pfd_p->s_aer_ue_status & aer_ue_status) ||
+ /* Check if parent bridge has seen this error */
+ parent_saer_p = PCIE_ADV_BDG_REG(parent_pfd_p);
+ if (!(parent_saer_p->pcie_sue_status & aer_ue_status) ||
!HAS_SAER_LOGS(parent_pfd_p, aer_ue_status))
- return (PF_PANIC);
-
- if (pf_pci_decode(rpdip, parent_pfd_p, &cmd, &bdf, &addr, &trans_type)
- != DDI_SUCCESS)
- return (PF_PANIC);
+ return (PF_ERR_PANIC);
/*
* If the addr or bdf from the parent PCIe bridge logs belong to this
* PCI device, assume the PCIe bridge's error handling has already taken
* care of this PCI device's error.
*/
- ppd_p = pcie_get_ppd(pf_data_p->dip);
- if ((bdf == pf_data_p->bdf) || pf_in_addr_range(ppd_p, addr))
- return (PF_MATCHED_PARENT);
+ if (pf_pci_decode(parent_pfd_p, &cmd) != DDI_SUCCESS)
+ return (PF_ERR_PANIC);
+
+ if ((parent_saer_p->pcie_sue_tgt_bdf == bus_p->bus_bdf) ||
+ pf_in_addr_range(bus_p, parent_saer_p->pcie_sue_tgt_addr))
+ return (PF_ERR_MATCHED_PARENT);
/*
* If this device is a PCI-PCI bridge, check if the bdf in the parent
@@ -1674,11 +1424,11 @@ pf_analyse_pci(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
* If they are, then assume the PCIe bridge's error handling has already
* taken care of this PCI-PCI bridge device's error.
*/
- if ((pf_data_p->hdr_type == PCI_HEADER_ONE) &&
- pf_in_bus_range(ppd_p, bdf))
- return (PF_MATCHED_PARENT);
+ if (PCIE_IS_BDG(bus_p) &&
+ pf_in_bus_range(bus_p, parent_saer_p->pcie_sue_tgt_bdf))
+ return (PF_ERR_MATCHED_PARENT);
- return (PF_PANIC);
+ return (PF_ERR_PANIC);
}
/*
@@ -1694,82 +1444,96 @@ pf_analyse_pci(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
*/
/* ARGSUSED */
static int
-pf_analyse_perr_assert(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_perr_assert(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
+ dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
uint16_t cmd;
- uint32_t addr;
- pcie_req_id_t bdf;
- uint32_t trans_type;
- int sts;
- int err = PF_NO_ERROR;
+ int hdl_sts = PF_HDL_NOTFOUND;
+ int err = PF_ERR_NO_ERROR;
+ pf_pcie_adv_bdg_err_regs_t *saer_p;
+
- if (HAS_SAER_LOGS(pf_data_p, bit)) {
- if (pf_pci_decode(rpdip, pf_data_p, &cmd, &bdf, &addr,
- &trans_type) != DDI_SUCCESS)
- return (PF_PANIC);
+ if (HAS_SAER_LOGS(pfd_p, bit)) {
+ saer_p = PCIE_ADV_BDG_REG(pfd_p);
+ if (pf_pci_decode(pfd_p, &cmd) != DDI_SUCCESS)
+ return (PF_ERR_PANIC);
+cmd_switch:
switch (cmd) {
+ case PCI_PCIX_CMD_IOWR:
case PCI_PCIX_CMD_MEMWR:
case PCI_PCIX_CMD_MEMWR_BL:
case PCI_PCIX_CMD_MEMWRBL:
/* Posted Writes Transactions */
- if (trans_type == PF_PIO_ADDR)
- sts = pf_hdl_lookup(rpdip, derr->fme_ena,
- trans_type, addr, bdf);
+ if (saer_p->pcie_sue_tgt_trans == PF_ADDR_PIO)
+ hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p,
+ B_FALSE);
break;
case PCI_PCIX_CMD_CFWR:
/*
* Check to see if it is a non-posted write. If so, a
* UR Completion would have been sent.
*/
- if (pf_matched_in_rc(dq_p, pf_data_p,
+ if (pf_matched_in_rc(dq_head_p, pfd_p,
PCI_STAT_R_MAST_AB)) {
- sts = PF_HDL_FOUND;
- err = PF_MATCHED_RC;
- break;
+ hdl_sts = PF_HDL_FOUND;
+ err = PF_ERR_MATCHED_RC;
+ goto done;
}
- sts = pf_hdl_lookup(rpdip, derr->fme_ena,
- trans_type, addr, bdf);
+ hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p,
+ B_FALSE);
break;
case PCI_PCIX_CMD_SPL:
- sts = pf_hdl_lookup(rpdip, derr->fme_ena,
- trans_type, addr, bdf);
+ hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p,
+ B_FALSE);
break;
+ case PCI_PCIX_CMD_DADR:
+ cmd = (PCIE_ADV_BDG_HDR(pfd_p, 1) >>
+ PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) &
+ PCIE_AER_SUCE_HDR_CMD_UP_MASK;
+ if (cmd != PCI_PCIX_CMD_DADR)
+ goto cmd_switch;
+ /* FALLTHROUGH */
default:
/* Unexpected situation, panic */
- sts = PF_HDL_NOTFOUND;
+ hdl_sts = PF_HDL_NOTFOUND;
}
- if (sts == PF_HDL_NOTFOUND)
- err = PF_PANIC;
+ if (hdl_sts == PF_HDL_FOUND)
+ err = PF_ERR_MATCHED_DEVICE;
+ else
+ err = PF_ERR_PANIC;
} else {
/*
* Check to see if it is a non-posted write. If so, a UR
* Completion would have been sent.
*/
- if ((pf_data_p->dev_status & PCIE_DEVCTL_UR_REPORTING_EN) &&
- pf_matched_in_rc(dq_p, pf_data_p, PCI_STAT_R_MAST_AB))
- err = PF_MATCHED_RC;
+ if ((PCIE_ERR_REG(pfd_p)->pcie_err_status &
+ PCIE_DEVSTS_UR_DETECTED) &&
+ pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_R_MAST_AB))
+ err = PF_ERR_MATCHED_RC;
/* Check for posted writes. Transaction is lost. */
- if (pf_data_p->s_status & PCI_STAT_S_PERROR) {
- err = PF_PANIC;
- }
+ if (PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat &
+ PCI_STAT_S_PERROR)
+ err = PF_ERR_PANIC;
/*
* All other scenarios are due to read completions. Check for
* PERR on the primary side. If found the primary side error
* handling will take care of this error.
*/
- if (err == PF_NO_ERROR) {
- if (pf_data_p->status & PCI_STAT_PERROR)
- err = PF_MATCHED_PARENT;
+ if (err == PF_ERR_NO_ERROR) {
+ if (PCI_ERR_REG(pfd_p)->pci_err_status &
+ PCI_STAT_PERROR)
+ err = PF_ERR_MATCHED_PARENT;
else
- err = PF_PANIC;
+ err = PF_ERR_PANIC;
}
}
+done:
return (err);
}
@@ -1780,37 +1544,89 @@ pf_analyse_perr_assert(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
*/
/* ARGSUSED */
static int
-pf_analyse_ptlp(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_ptlp(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
- pf_data_t *parent_pfd_p;
+ dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
/*
* If AERs are supported find the logs in this device, otherwise look in
* it's parent's logs.
*/
- if (HAS_AER_LOGS(pf_data_p, bit)) {
- pcie_tlp_hdr_t *hdr = (pcie_tlp_hdr_t *)&pf_data_p->aer_h0;
+ if (HAS_AER_LOGS(pfd_p, bit)) {
+ pcie_tlp_hdr_t *hdr = (pcie_tlp_hdr_t *)&PCIE_ADV_HDR(pfd_p, 0);
/*
* Double check that the log contains a poisoned TLP.
* Some devices like PLX switch do not log poison TLP headers.
*/
if (hdr->ep) {
- if (pf_tlp_hdl_lookup(rpdip, derr, pf_data_p) ==
+ if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_TRUE) ==
PF_HDL_FOUND)
- return (PF_MATCHED_DEVICE);
+ return (PF_ERR_MATCHED_DEVICE);
}
- return (PF_PANIC);
+
+ /*
+ * If an address is found and hdl lookup failed panic.
+ * Otherwise check parents to see if there was enough
+ * information recover.
+ */
+ if (PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr)
+ return (PF_ERR_PANIC);
}
- if (pf_data_p->parent_index != PF_DATA_NOT_FOUND) {
- parent_pfd_p = &dq_p[pf_data_p->parent_index];
+ /*
+ * Check to see if the rc has already handled this error or a parent has
+ * already handled this error.
+ *
+ * If the error info in the RC wasn't enough to find the fault device,
+ * such as if the faulting device lies behind a PCIe-PCI bridge from a
+ * poisoned completion, check to see if the PCIe-PCI bridge has enough
+ * info to recover. For completion TLP's, the AER header logs only
+ * contain the faulting BDF in the Root Port. For PCIe device the fault
+ * BDF is the fault device. But if the fault device is behind a
+ * PCIe-PCI bridge the fault BDF could turn out just to be a PCIe-PCI
+ * bridge's secondary bus number.
+ */
+ if (!PFD_IS_ROOT(pfd_p)) {
+ dev_info_t *pdip = ddi_get_parent(PCIE_PFD2DIP(pfd_p));
+ pf_data_t *parent_pfd_p;
+
+ if (PCIE_PFD2BUS(pfd_p)->bus_rp_dip == pdip) {
+ if (pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_PERROR))
+ return (PF_ERR_MATCHED_RC);
+ }
+
+ parent_pfd_p = PCIE_DIP2PFD(pdip);
+
if (HAS_AER_LOGS(parent_pfd_p, bit))
- return (PF_MATCHED_PARENT);
- }
+ return (PF_ERR_MATCHED_PARENT);
+ } else {
+ pf_data_t *bdg_pfd_p;
+ pcie_req_id_t secbus;
+
+ /*
+ * Looking for a pcie bridge only makes sense if the BDF
+ * Dev/Func = 0/0
+ */
+ if (!PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p)))
+ goto done;
+
+ secbus = PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf;
+
+ if (secbus & 0xFF)
+ goto done;
- return (PF_PANIC);
+ bdg_pfd_p = pf_get_pcie_bridge(pfd_p, secbus);
+
+ if (bdg_pfd_p && HAS_SAER_LOGS(bdg_pfd_p,
+ PCIE_AER_SUCE_PERR_ASSERT)) {
+ return pf_analyse_perr_assert(derr,
+ PCIE_AER_SUCE_PERR_ASSERT, dq_head_p, pfd_p);
+ }
+ }
+done:
+ return (PF_ERR_PANIC);
}
/*
@@ -1820,30 +1636,26 @@ pf_analyse_ptlp(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
*/
/* ARGSUSED */
static int
-pf_analyse_sc(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_sc(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
+ dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
uint16_t cmd;
- uint32_t addr;
- pcie_req_id_t bdf;
- uint32_t trans_type;
int sts = PF_HDL_NOTFOUND;
- if (!HAS_SAER_LOGS(pf_data_p, bit))
- return (PF_PANIC);
+ if (!HAS_SAER_LOGS(pfd_p, bit))
+ return (PF_ERR_PANIC);
- if (pf_pci_decode(rpdip, pf_data_p, &cmd, &bdf, &addr, &trans_type) !=
- DDI_SUCCESS)
- return (PF_PANIC);
+ if (pf_pci_decode(pfd_p, &cmd) != DDI_SUCCESS)
+ return (PF_ERR_PANIC);
if (cmd == PCI_PCIX_CMD_SPL)
- sts = pf_hdl_lookup(rpdip, derr->fme_ena, trans_type,
- addr, bdf);
+ sts = pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE);
- if (sts == PF_HDL_NOTFOUND)
- return (PF_PANIC);
+ if (sts == PF_HDL_FOUND)
+ return (PF_ERR_MATCHED_DEVICE);
- return (PF_MATCHED_DEVICE);
+ return (PF_ERR_PANIC);
}
/*
@@ -1853,42 +1665,34 @@ pf_analyse_sc(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
*/
/* ARGSUSED */
static int
-pf_analyse_to(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_to(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
- /*
- * If the Advisory Non-Fatal is set, that means HW will automatically
- * retry the failed transaction.
- */
- if (HAS_AER_LOGS(pf_data_p, bit) && CE_ADVISORY(pf_data_p))
- return (PF_NO_PANIC);
+ if (HAS_AER_LOGS(pfd_p, bit) && CE_ADVISORY(pfd_p))
+ return (PF_ERR_NO_PANIC);
- return (PF_PANIC);
+ return (PF_ERR_PANIC);
}
/*
- * PCIe Unexpected Completion. This error can be forgiven if it is marked as
- * CE Advisory. If it is marked as advisory, this means the HW can recover
- * and/or retry the transaction automatically.
+ * PCIe Unexpected Completion. Check to see if this TLP was misrouted by
+ * matching the device BDF with the TLP Log. If misrouting panic, otherwise
+ * don't panic.
*/
/* ARGSUSED */
static int
-pf_analyse_uc(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_uc(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
- /*
- * Check to see if this TLP was misrouted by matching the device BDF
- * with the TLP Log. If misrouting panic, otherwise don't panic.
- */
- if (HAS_AER_LOGS(pf_data_p, bit) &&
- (pf_data_p->bdf == (pf_data_p->aer_h2 >> 16)))
- return (PF_NO_PANIC);
+ if (HAS_AER_LOGS(pfd_p, bit) &&
+ (PCIE_PFD2BUS(pfd_p)->bus_bdf == (PCIE_ADV_HDR(pfd_p, 2) >> 16)))
+ return (PF_ERR_NO_PANIC);
- return (PF_PANIC);
+ return (PF_ERR_PANIC);
}
/*
- * PCIe-PCI Bridge Uncorrectable Data error anlyser. All Uncorrectable Data
+ * PCIe-PCI Bridge Uncorrectable Data error analyser. All Uncorrectable Data
* errors should have resulted in a PCIe Poisoned TLP to the RC, except for
* Posted Writes. Check the logs for Posted Writes and if the RC did not see a
* Poisoned TLP.
@@ -1898,51 +1702,1063 @@ pf_analyse_uc(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
*/
/* ARGSUSED */
static int
-pf_analyse_uc_data(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_analyse_uc_data(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
{
- uint16_t cmd;
- uint32_t addr;
- pcie_req_id_t bdf;
- uint32_t trans_type;
+ dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
- if (!HAS_SAER_LOGS(pf_data_p, bit))
- return (PF_PANIC);
+ if (!HAS_SAER_LOGS(pfd_p, bit))
+ return (PF_ERR_PANIC);
- if (pf_matched_in_rc(dq_p, pf_data_p, PCI_STAT_PERROR))
- return (PF_MATCHED_RC);
+ if (pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_PERROR))
+ return (PF_ERR_MATCHED_RC);
- if (pf_pci_decode(rpdip, pf_data_p, &cmd, &bdf, &addr, &trans_type) !=
- DDI_SUCCESS)
- return (PF_PANIC);
+ if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE) == PF_HDL_FOUND)
+ return (PF_ERR_MATCHED_DEVICE);
- if (pf_hdl_lookup(rpdip, derr->fme_ena, trans_type, addr, bdf) ==
- PF_HDL_NOTFOUND)
- return (PF_PANIC);
+ return (PF_ERR_PANIC);
+}
- return (PF_MATCHED_DEVICE);
+/* ARGSUSED */
+static int
+pf_no_panic(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
+{
+ return (PF_ERR_NO_PANIC);
}
/* ARGSUSED */
static int
-pf_no_panic(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_panic(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
+ pf_data_t *pfd_p)
+{
+ return (PF_ERR_PANIC);
+}
+
+/*
+ * If a PCIe device does not support AER, assume all AER statuses have been set,
+ * unless other registers do not indicate a certain error occuring.
+ */
+static void
+pf_adjust_for_no_aer(pf_data_t *pfd_p)
{
- return (PF_NO_PANIC);
+ uint32_t aer_ue = 0;
+ uint16_t status;
+
+ if (PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p)))
+ return;
+
+ if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_FE_DETECTED)
+ aer_ue = PF_AER_FATAL_ERR;
+
+ if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) {
+ aer_ue = PF_AER_NON_FATAL_ERR;
+ status = PCI_ERR_REG(pfd_p)->pci_err_status;
+
+ /* Check if the device received a PTLP */
+ if (!(status & PCI_STAT_PERROR))
+ aer_ue &= ~PCIE_AER_UCE_PTLP;
+
+ /* Check if the device signaled a CA */
+ if (!(status & PCI_STAT_S_TARG_AB))
+ aer_ue &= ~PCIE_AER_UCE_CA;
+
+ /* Check if the device sent a UR */
+ if (!(status & PCIE_DEVSTS_UR_DETECTED))
+ aer_ue &= ~PCIE_AER_UCE_UR;
+
+ /*
+ * Ignore ECRCs as it is optional and will manefest itself as
+ * another error like PTLP and MFP
+ */
+ aer_ue &= ~PCIE_AER_UCE_ECRC;
+ }
+
+ if (!PCIE_IS_BDG(PCIE_PFD2BUS(pfd_p))) {
+ aer_ue &= ~PCIE_AER_UCE_TRAINING;
+ aer_ue &= ~PCIE_AER_UCE_SD;
+ }
+
+ PCIE_ADV_REG(pfd_p)->pcie_ue_status = aer_ue;
}
+static void
+pf_adjust_for_no_saer(pf_data_t *pfd_p)
+{
+ uint32_t s_aer_ue = 0;
+ uint16_t status;
+
+ if (PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p)))
+ return;
+
+ if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_FE_DETECTED)
+ s_aer_ue = PF_SAER_FATAL_ERR;
+
+ if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) {
+ s_aer_ue = PF_SAER_NON_FATAL_ERR;
+ status = PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat;
+
+ /* Check if the device received a UC_DATA */
+ if (!(status & PCI_STAT_PERROR))
+ s_aer_ue &= ~PCIE_AER_SUCE_UC_DATA_ERR;
+
+ /* Check if the device received a RCVD_MA/MA_ON_SC */
+ if (!(status & (PCI_STAT_R_MAST_AB))) {
+ s_aer_ue &= ~PCIE_AER_SUCE_RCVD_MA;
+ s_aer_ue &= ~PCIE_AER_SUCE_MA_ON_SC;
+ }
+
+ /* Check if the device received a RCVD_TA/TA_ON_SC */
+ if (!(status & (PCI_STAT_R_TARG_AB))) {
+ s_aer_ue &= ~PCIE_AER_SUCE_RCVD_TA;
+ s_aer_ue &= ~PCIE_AER_SUCE_TA_ON_SC;
+ }
+ }
+
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status = s_aer_ue;
+}
+
+/* Find the PCIe-PCI bridge based on secondary bus number */
+static pf_data_t *
+pf_get_pcie_bridge(pf_data_t *pfd_p, pcie_req_id_t secbus)
+{
+ pf_data_t *bdg_pfd_p;
+
+ /* Search down for the PCIe-PCI device. */
+ for (bdg_pfd_p = pfd_p->pe_next; bdg_pfd_p;
+ bdg_pfd_p = bdg_pfd_p->pe_next) {
+ if (PCIE_IS_PCIE_BDG(PCIE_PFD2BUS(bdg_pfd_p)) &&
+ PCIE_PFD2BUS(bdg_pfd_p)->bus_pcie2pci_secbus == secbus)
+ return (bdg_pfd_p);
+ }
+
+ return (NULL);
+}
+
+/* Find the PCIe-PCI bridge of a PCI device */
+static pf_data_t *
+pf_get_parent_pcie_bridge(pf_data_t *pfd_p)
+{
+ dev_info_t *dip, *rp_dip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
+
+ /* This only makes sense if the device is a PCI device */
+ if (!PCIE_IS_PCI(PCIE_PFD2BUS(pfd_p)))
+ return (NULL);
+
+ /*
+ * Search up for the PCIe-PCI device. Watchout for x86 where pci
+ * devices hang directly off of NPE.
+ */
+ for (dip = PCIE_PFD2DIP(pfd_p); dip; dip = ddi_get_parent(dip)) {
+ if (dip == rp_dip)
+ dip = NULL;
+
+ if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(dip)))
+ return (PCIE_DIP2PFD(dip));
+ }
+
+ return (NULL);
+}
+
+/*
+ * See if a leaf error was bubbled up to the Root Complex (RC) and handled.
+ * As of right now only RC's have enough information to have errors found in the
+ * fabric to be matched to the RC. Note that Root Port's (RP) do not carry
+ * enough information. Currently known RC's are SPARC Fire architecture and
+ * it's equivalents, and x86's NPE.
+ * SPARC Fire architectures have a plethora of error registers, while currently
+ * NPE only have the address of a failed load.
+ *
+ * Check if the RC logged an error with the appropriate status type/abort type.
+ * Ex: Parity Error, Received Master/Target Abort
+ * Check if either the fault address found in the rc matches the device's
+ * assigned address range (PIO's only) or the fault BDF in the rc matches the
+ * device's BDF or Secondary Bus/Bus Range.
+ */
+static boolean_t
+pf_matched_in_rc(pf_data_t *dq_head_p, pf_data_t *pfd_p,
+ uint32_t abort_type)
+{
+ pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p);
+ pf_data_t *rc_pfd_p;
+ pcie_req_id_t fault_bdf;
+
+ for (rc_pfd_p = dq_head_p; PFD_IS_ROOT(rc_pfd_p);
+ rc_pfd_p = rc_pfd_p->pe_next) {
+ /* Only root complex's have enough information to match */
+ if (!PCIE_IS_RC(PCIE_PFD2BUS(rc_pfd_p)))
+ continue;
+
+ /* If device and rc abort type does not match continue */
+ if (!(PCI_BDG_ERR_REG(rc_pfd_p)->pci_bdg_sec_stat & abort_type))
+ continue;
+
+ fault_bdf = PCIE_ROOT_FAULT(rc_pfd_p)->fault_bdf;
+
+ /* The Fault BDF = Device's BDF */
+ if (fault_bdf == bus_p->bus_bdf)
+ return (B_TRUE);
+
+ /* The Fault Addr is in device's address range */
+ if (pf_in_addr_range(bus_p,
+ PCIE_ROOT_FAULT(rc_pfd_p)->fault_addr))
+ return (B_TRUE);
+
+ /* The Fault BDF is from PCIe-PCI Bridge's secondary bus */
+ if (PCIE_IS_PCIE_BDG(bus_p) &&
+ pf_in_bus_range(bus_p, fault_bdf))
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Check the RP and see if the error is PIO/DMA. If the RP also has a PERR then
+ * it is a DMA, otherwise it's a PIO
+ */
+static void
+pf_pci_find_trans_type(pf_data_t *pfd_p, uint64_t *addr, uint32_t *trans_type,
+ pcie_req_id_t *bdf) {
+ pf_data_t *rc_pfd_p;
+
+ /* Could be DMA or PIO. Find out by look at error type. */
+ switch (PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status) {
+ case PCIE_AER_SUCE_TA_ON_SC:
+ case PCIE_AER_SUCE_MA_ON_SC:
+ *trans_type = PF_ADDR_DMA;
+ return;
+ case PCIE_AER_SUCE_RCVD_TA:
+ case PCIE_AER_SUCE_RCVD_MA:
+ *bdf = 0;
+ *trans_type = PF_ADDR_PIO;
+ return;
+ case PCIE_AER_SUCE_USC_ERR:
+ case PCIE_AER_SUCE_UC_DATA_ERR:
+ case PCIE_AER_SUCE_PERR_ASSERT:
+ break;
+ default:
+ *addr = 0;
+ *bdf = 0;
+ *trans_type = 0;
+ return;
+ }
+
+ *bdf = 0;
+ *trans_type = PF_ADDR_PIO;
+ for (rc_pfd_p = pfd_p->pe_prev; rc_pfd_p;
+ rc_pfd_p = rc_pfd_p->pe_prev) {
+ if (PFD_IS_ROOT(rc_pfd_p) &&
+ (PCI_BDG_ERR_REG(rc_pfd_p)->pci_bdg_sec_stat &
+ PCI_STAT_PERROR)) {
+ *trans_type = PF_ADDR_DMA;
+ return;
+ }
+ }
+}
+
+/*
+ * pf_pci_decode function decodes the secondary aer transaction logs in
+ * PCIe-PCI bridges.
+ *
+ * The log is 128 bits long and arranged in this manner.
+ * [0:35] Transaction Attribute (s_aer_h0-saer_h1)
+ * [36:39] Transaction lower command (saer_h1)
+ * [40:43] Transaction upper command (saer_h1)
+ * [44:63] Reserved
+ * [64:127] Address (saer_h2-saer_h3)
+ */
/* ARGSUSED */
static int
-pf_matched_device(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_pci_decode(pf_data_t *pfd_p, uint16_t *cmd) {
+ pcix_attr_t *attr;
+ uint64_t addr;
+ uint32_t trans_type;
+ pcie_req_id_t bdf;
+
+ attr = (pcix_attr_t *)&PCIE_ADV_BDG_HDR(pfd_p, 0);
+ *cmd = GET_SAER_CMD(pfd_p);
+
+cmd_switch:
+ switch (*cmd) {
+ case PCI_PCIX_CMD_IORD:
+ case PCI_PCIX_CMD_IOWR:
+ /* IO Access should always be down stream */
+ addr = PCIE_ADV_BDG_HDR(pfd_p, 2);
+ bdf = attr->rid;
+ trans_type = PF_ADDR_PIO;
+ break;
+ case PCI_PCIX_CMD_MEMRD_DW:
+ case PCI_PCIX_CMD_MEMRD_BL:
+ case PCI_PCIX_CMD_MEMRDBL:
+ case PCI_PCIX_CMD_MEMWR:
+ case PCI_PCIX_CMD_MEMWR_BL:
+ case PCI_PCIX_CMD_MEMWRBL:
+ addr = ((uint64_t)PCIE_ADV_BDG_HDR(pfd_p, 3) <<
+ PCIE_AER_SUCE_HDR_ADDR_SHIFT) | PCIE_ADV_BDG_HDR(pfd_p, 2);
+ bdf = attr->rid;
+
+ pf_pci_find_trans_type(pfd_p, &addr, &trans_type, &bdf);
+ break;
+ case PCI_PCIX_CMD_CFRD:
+ case PCI_PCIX_CMD_CFWR:
+ /*
+ * CFG Access should always be down stream. Match the BDF in
+ * the address phase.
+ */
+ addr = 0;
+ bdf = attr->rid;
+ trans_type = PF_ADDR_CFG;
+ break;
+ case PCI_PCIX_CMD_SPL:
+ /*
+ * Check for DMA read completions. The requesting BDF is in the
+ * Address phase.
+ */
+ addr = 0;
+ bdf = attr->rid;
+ trans_type = PF_ADDR_DMA;
+ break;
+ case PCI_PCIX_CMD_DADR:
+ /*
+ * For Dual Address Cycles the transaction command is in the 2nd
+ * address phase.
+ */
+ *cmd = (PCIE_ADV_BDG_HDR(pfd_p, 1) >>
+ PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) &
+ PCIE_AER_SUCE_HDR_CMD_UP_MASK;
+ if (*cmd != PCI_PCIX_CMD_DADR)
+ goto cmd_switch;
+ /* FALLTHROUGH */
+ default:
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = 0;
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = 0;
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = 0;
+ return (DDI_FAILURE);
+ }
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = trans_type;
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = bdf;
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = addr;
+ return (DDI_SUCCESS);
+}
+
+/*
+ * Based on either the BDF/ADDR find and mark the faulting DMA/ACC handler.
+ * Returns either PF_HDL_NOTFOUND or PF_HDL_FOUND.
+ */
+int
+pf_hdl_lookup(dev_info_t *dip, uint64_t ena, uint32_t flag, uint64_t addr,
+ pcie_req_id_t bdf)
{
- return (PF_MATCHED_DEVICE);
+ ddi_fm_error_t derr;
+
+ /* If we don't know the addr or rid just return with NOTFOUND */
+ if (addr == NULL && bdf == NULL)
+ return (PF_HDL_NOTFOUND);
+
+ if (!(flag & (PF_ADDR_DMA | PF_ADDR_PIO | PF_ADDR_CFG))) {
+ return (PF_HDL_NOTFOUND);
+ }
+
+ bzero(&derr, sizeof (ddi_fm_error_t));
+ derr.fme_version = DDI_FME_VERSION;
+ derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
+ derr.fme_ena = ena;
+
+ return (pf_hdl_child_lookup(dip, &derr, flag, addr, bdf));
+}
+
+static int
+pf_hdl_child_lookup(dev_info_t *dip, ddi_fm_error_t *derr, uint32_t flag,
+ uint64_t addr, pcie_req_id_t bdf)
+{
+ int status = PF_HDL_NOTFOUND;
+ ndi_fmc_t *fcp = NULL;
+ struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
+ pcie_req_id_t dip_bdf;
+ boolean_t have_lock = B_FALSE;
+ pcie_bus_t *bus_p;
+ dev_info_t *cdip;
+
+ if (!(bus_p = pf_is_ready(dip))) {
+ return (status);
+ }
+
+ ASSERT(fmhdl);
+ if (!i_ddi_fm_handler_owned(dip)) {
+ /*
+ * pf_handler_enter always returns SUCCESS if the 'impl' arg is
+ * NULL.
+ */
+ (void) pf_handler_enter(dip, NULL);
+ have_lock = B_TRUE;
+ }
+
+ dip_bdf = PCI_GET_BDF(dip);
+
+ /* Check if dip and BDF match, if not recurse to it's children. */
+ if (!PCIE_IS_RC(bus_p) && (bdf == NULL || dip_bdf == bdf)) {
+ if ((flag & PF_ADDR_DMA) && DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap))
+ fcp = fmhdl->fh_dma_cache;
+ else
+ fcp = NULL;
+
+ if (fcp)
+ status = pf_hdl_compare(dip, derr, DMA_HANDLE, addr,
+ bdf, fcp);
+
+
+ if (((flag & PF_ADDR_PIO) || (flag & PF_ADDR_CFG)) &&
+ DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap))
+ fcp = fmhdl->fh_acc_cache;
+ else
+ fcp = NULL;
+
+ if (fcp)
+ status = pf_hdl_compare(dip, derr, ACC_HANDLE, addr,
+ bdf, fcp);
+ }
+
+ /* If we found the handler or know it's this device, we're done */
+ if (!PCIE_IS_RC(bus_p) && ((dip_bdf == bdf) ||
+ (status == PF_HDL_FOUND)))
+ goto done;
+
+ /*
+ * If the current devuce us a PCIe-PCI bridge need to check for special
+ * cases:
+ *
+ * If it is a PIO and we don't have an address or this is a DMA, check
+ * to see if the BDF = secondary bus. If so stop. The BDF isn't a real
+ * BDF and the fault device could have come from any device in the PCI
+ * bus.
+ */
+ if (PCIE_IS_PCIE_BDG(bus_p) &&
+ ((flag & PF_ADDR_DMA || flag & PF_ADDR_PIO)) &&
+ ((bus_p->bus_bdg_secbus << PCIE_REQ_ID_BUS_SHIFT) == bdf))
+ goto done;
+
+
+ /* If we can't find the handler check it's children */
+ for (cdip = ddi_get_child(dip); cdip;
+ cdip = ddi_get_next_sibling(cdip)) {
+ if ((bus_p = PCIE_DIP2BUS(cdip)) == NULL)
+ continue;
+
+ if (pf_in_bus_range(bus_p, bdf) ||
+ pf_in_addr_range(bus_p, addr))
+ status = pf_hdl_child_lookup(cdip, derr, flag, addr,
+ bdf);
+
+ if (status == PF_HDL_FOUND)
+ goto done;
+ }
+
+done:
+ if (have_lock == B_TRUE)
+ pf_handler_exit(dip);
+
+ return (status);
+}
+
+static int
+pf_hdl_compare(dev_info_t *dip, ddi_fm_error_t *derr, uint32_t flag,
+ uint64_t addr, pcie_req_id_t bdf, ndi_fmc_t *fcp) {
+ ndi_fmcentry_t *fep;
+ int found = 0;
+ int status;
+
+ mutex_enter(&fcp->fc_lock);
+ for (fep = fcp->fc_active->fce_next; fep != NULL;
+ fep = fep->fce_next) {
+ ddi_fmcompare_t compare_func;
+
+ /*
+ * Compare captured error state with handle
+ * resources. During the comparison and
+ * subsequent error handling, we block
+ * attempts to free the cache entry.
+ */
+ compare_func = (flag == ACC_HANDLE) ?
+ i_ddi_fm_acc_err_cf_get((ddi_acc_handle_t)
+ fep->fce_resource) :
+ i_ddi_fm_dma_err_cf_get((ddi_dma_handle_t)
+ fep->fce_resource);
+
+ status = compare_func(dip, fep->fce_resource,
+ (void *)&addr, (void *)&bdf);
+
+ if (status == DDI_FM_NONFATAL) {
+ found++;
+
+ /* Set the error for this resource handle */
+ if (flag == ACC_HANDLE) {
+ ddi_acc_handle_t ap = fep->fce_resource;
+
+ i_ddi_fm_acc_err_set(ap, derr->fme_ena, status,
+ DDI_FM_ERR_UNEXPECTED);
+ ddi_fm_acc_err_get(ap, derr, DDI_FME_VERSION);
+ derr->fme_acc_handle = ap;
+ } else {
+ ddi_dma_handle_t dp = fep->fce_resource;
+
+ i_ddi_fm_dma_err_set(dp, derr->fme_ena, status,
+ DDI_FM_ERR_UNEXPECTED);
+ ddi_fm_dma_err_get(dp, derr, DDI_FME_VERSION);
+ derr->fme_dma_handle = dp;
+ }
+ }
+ }
+ mutex_exit(&fcp->fc_lock);
+
+ /*
+ * If a handler isn't found and we know this is the right device mark
+ * them all failed.
+ */
+ if ((addr != NULL) && (bdf != NULL) && (found == 0)) {
+ status = pf_hdl_compare(dip, derr, flag, addr, bdf, fcp);
+ if (status == PF_HDL_FOUND)
+ found++;
+ }
+
+ return ((found) ? PF_HDL_FOUND : PF_HDL_NOTFOUND);
+}
+
+/*
+ * Automatically decode AER header logs and does a handling look up based on the
+ * AER header decoding.
+ *
+ * For this function only the Primary/Secondary AER Header Logs need to be valid
+ * in the pfd (PCIe Fault Data) arg.
+ *
+ * Returns either PF_HDL_NOTFOUND or PF_HDL_FOUND.
+ */
+static int
+pf_log_hdl_lookup(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *pfd_p,
+ boolean_t is_primary)
+{
+ int lookup = PF_HDL_NOTFOUND;
+
+ if (is_primary) {
+ pf_pcie_adv_err_regs_t *reg_p = PCIE_ADV_REG(pfd_p);
+ if (pf_tlp_decode(PCIE_PFD2BUS(pfd_p), reg_p) == DDI_SUCCESS) {
+ lookup = pf_hdl_lookup(rpdip, derr->fme_ena,
+ reg_p->pcie_ue_tgt_trans,
+ reg_p->pcie_ue_tgt_addr,
+ reg_p->pcie_ue_tgt_bdf);
+ }
+ } else {
+ pf_pcie_adv_bdg_err_regs_t *reg_p = PCIE_ADV_BDG_REG(pfd_p);
+ uint16_t cmd;
+ if (pf_pci_decode(pfd_p, &cmd) == DDI_SUCCESS) {
+ lookup = pf_hdl_lookup(rpdip, derr->fme_ena,
+ reg_p->pcie_sue_tgt_trans,
+ reg_p->pcie_sue_tgt_addr,
+ reg_p->pcie_sue_tgt_bdf);
+ }
+ }
+
+ return (lookup);
+}
+
+/*
+ * Decodes the TLP and returns the BDF of the handler, address and transaction
+ * type if known.
+ *
+ * Types of TLP logs seen in RC, and what to extract:
+ *
+ * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR
+ * Memory(PIO) - address, PF_PIO_ADDR
+ * CFG - Should not occur and result in UR
+ * Completion(DMA) - Requester BDF, PF_DMA_ADDR
+ * Completion(PIO) - Requester BDF, PF_PIO_ADDR
+ *
+ * Types of TLP logs seen in SW/Leaf, and what to extract:
+ *
+ * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR
+ * Memory(PIO) - address, PF_PIO_ADDR
+ * CFG - Destined BDF, address, PF_CFG_ADDR
+ * Completion(DMA) - Requester BDF, PF_DMA_ADDR
+ * Completion(PIO) - Requester BDF, PF_PIO_ADDR
+ *
+ * The adv_reg_p must be passed in separately for use with SPARC RPs. A
+ * SPARC RP could have multiple AER header logs which cannot be directly
+ * accessed via the bus_p.
+ */
+int
+pf_tlp_decode(pcie_bus_t *bus_p, pf_pcie_adv_err_regs_t *adv_reg_p) {
+ pcie_tlp_hdr_t *tlp_hdr = (pcie_tlp_hdr_t *)adv_reg_p->pcie_ue_hdr;
+ pcie_req_id_t my_bdf, tlp_bdf, flt_bdf = 0xFFFF;
+ uint64_t flt_addr = 0;
+ uint32_t flt_trans_type = 0;
+
+ adv_reg_p->pcie_ue_tgt_addr = 0;
+ adv_reg_p->pcie_ue_tgt_bdf = 0;
+ adv_reg_p->pcie_ue_tgt_trans = 0;
+
+ my_bdf = bus_p->bus_bdf;
+ switch (tlp_hdr->type) {
+ case PCIE_TLP_TYPE_IO:
+ case PCIE_TLP_TYPE_MEM:
+ case PCIE_TLP_TYPE_MEMLK:
+ /* Grab the 32/64bit fault address */
+ if (tlp_hdr->fmt & 0x1) {
+ flt_addr = ((uint64_t)adv_reg_p->pcie_ue_hdr[2] << 32);
+ flt_addr |= adv_reg_p->pcie_ue_hdr[3];
+ } else {
+ flt_addr = adv_reg_p->pcie_ue_hdr[2];
+ }
+
+ tlp_bdf = (pcie_req_id_t)(adv_reg_p->pcie_ue_hdr[1] >> 16);
+
+ /*
+ * If the req bdf >= this.bdf, then it means the request is this
+ * device or came from a device below it. Unless this device is
+ * a PCIe root port then it means is a DMA, otherwise PIO.
+ */
+ if ((tlp_bdf >= my_bdf) && !PCIE_IS_ROOT(bus_p)) {
+ flt_trans_type = PF_ADDR_DMA;
+ flt_bdf = tlp_bdf;
+ } else if (PCIE_IS_ROOT(bus_p) &&
+ (PF_FIRST_AER_ERR(PCIE_AER_UCE_PTLP, adv_reg_p) ||
+ (PF_FIRST_AER_ERR(PCIE_AER_UCE_CA, adv_reg_p)))) {
+ flt_trans_type = PF_ADDR_DMA;
+ flt_bdf = tlp_bdf;
+ } else {
+ flt_trans_type = PF_ADDR_PIO;
+ flt_bdf = 0;
+ }
+ break;
+ case PCIE_TLP_TYPE_CFG0:
+ case PCIE_TLP_TYPE_CFG1:
+ flt_addr = 0;
+ flt_bdf = (pcie_req_id_t)(adv_reg_p->pcie_ue_hdr[2] >> 16);
+ flt_trans_type = PF_ADDR_CFG;
+ break;
+ case PCIE_TLP_TYPE_CPL:
+ case PCIE_TLP_TYPE_CPLLK:
+ {
+ pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)adv_reg_p->pcie_ue_hdr;
+
+ flt_addr = NULL;
+ flt_bdf = cpl_tlp->rid;
+
+ /*
+ * If the cpl bdf < this.bdf, then it means the request is this
+ * device or came from a device below it. Unless this device is
+ * a PCIe root port then it means is a DMA, otherwise PIO.
+ */
+ if (cpl_tlp->rid > cpl_tlp->cid) {
+ flt_trans_type = PF_ADDR_DMA;
+ } else {
+ flt_trans_type = PF_ADDR_PIO | PF_ADDR_CFG;
+ }
+ break;
+ }
+ default:
+ return (DDI_FAILURE);
+ }
+
+ adv_reg_p->pcie_ue_tgt_addr = flt_addr;
+ adv_reg_p->pcie_ue_tgt_bdf = flt_bdf;
+ adv_reg_p->pcie_ue_tgt_trans = flt_trans_type;
+
+ return (DDI_SUCCESS);
+}
+
+#define PCIE_EREPORT DDI_IO_CLASS "." PCI_ERROR_SUBCLASS "." PCIEX_FABRIC
+static void
+pf_ereport_setup(dev_info_t *dip, uint64_t ena, nvlist_t **ereport,
+ nvlist_t **detector, errorq_elem_t **eqep)
+{
+ struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
+ char device_path[MAXPATHLEN];
+ nv_alloc_t *nva;
+
+ *eqep = errorq_reserve(fmhdl->fh_errorq);
+ if (*eqep == NULL) {
+ atomic_add_64(&fmhdl->fh_kstat.fek_erpt_dropped.value.ui64, 1);
+ return;
+ }
+
+ *ereport = errorq_elem_nvl(fmhdl->fh_errorq, *eqep);
+ nva = errorq_elem_nva(fmhdl->fh_errorq, *eqep);
+
+ ASSERT(*ereport);
+ ASSERT(nva);
+
+ /*
+ * Use the dev_path/devid for this device instance.
+ */
+ *detector = fm_nvlist_create(nva);
+ if (dip == ddi_root_node()) {
+ device_path[0] = '/';
+ device_path[1] = '\0';
+ } else {
+ (void) ddi_pathname(dip, device_path);
+ }
+
+ fm_fmri_dev_set(*detector, FM_DEV_SCHEME_VERSION, NULL,
+ device_path, NULL);
+
+ if (ena == 0)
+ ena = fm_ena_generate(0, FM_ENA_FMT1);
+
+ fm_ereport_set(*ereport, 0, PCIE_EREPORT, ena, *detector, NULL);
}
/* ARGSUSED */
+static void
+pf_ereport_post(dev_info_t *dip, nvlist_t **ereport, nvlist_t **detector,
+ errorq_elem_t **eqep)
+{
+ struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
+
+ errorq_commit(fmhdl->fh_errorq, *eqep, ERRORQ_ASYNC);
+}
+
+static void
+pf_send_ereport(ddi_fm_error_t *derr, pf_impl_t *impl)
+{
+ nvlist_t *ereport;
+ nvlist_t *detector;
+ errorq_elem_t *eqep;
+ pcie_bus_t *bus_p;
+ pf_data_t *pfd_p;
+ uint32_t total = impl->pf_total;
+
+ /*
+ * Ereports need to be sent in a top down fashion. The fabric translator
+ * expects the ereports from the Root first. This is needed to tell if
+ * the system contains a PCIe complaint RC/RP.
+ */
+ for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) {
+ bus_p = PCIE_PFD2BUS(pfd_p);
+ pfd_p->pe_valid = B_FALSE;
+
+ if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED ||
+ PFD_IS_RC(pfd_p) ||
+ !DDI_FM_EREPORT_CAP(ddi_fm_capable(PCIE_PFD2DIP(pfd_p))))
+ continue;
+
+ pf_ereport_setup(PCIE_BUS2DIP(bus_p), derr->fme_ena, &ereport,
+ &detector, &eqep);
+
+ /* Generic PCI device information */
+ fm_payload_set(ereport,
+ "bdf", DATA_TYPE_UINT16, bus_p->bus_bdf,
+ "device_id", DATA_TYPE_UINT16,
+ (bus_p->bus_dev_ven_id >> 16),
+ "vendor_id", DATA_TYPE_UINT16,
+ (bus_p->bus_dev_ven_id & 0xFFFF),
+ "rev_id", DATA_TYPE_UINT8, bus_p->bus_rev_id,
+ "dev_type", DATA_TYPE_UINT16, bus_p->bus_dev_type,
+ "pcie_off", DATA_TYPE_UINT16, bus_p->bus_pcie_off,
+ "pcix_off", DATA_TYPE_UINT16, bus_p->bus_pcix_off,
+ "aer_off", DATA_TYPE_UINT16, bus_p->bus_aer_off,
+ "ecc_ver", DATA_TYPE_UINT16, bus_p->bus_ecc_ver,
+ NULL);
+
+ /* PCI registers */
+ fm_payload_set(ereport,
+ "pci_status", DATA_TYPE_UINT16,
+ PCI_ERR_REG(pfd_p)->pci_err_status,
+ "pci_command", DATA_TYPE_UINT16,
+ PCI_ERR_REG(pfd_p)->pci_cfg_comm,
+ NULL);
+
+ /* PCI bridge registers */
+ if (PCIE_IS_BDG(bus_p)) {
+ fm_payload_set(ereport,
+ "pci_bdg_sec_status", DATA_TYPE_UINT16,
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat,
+ "pci_bdg_ctrl", DATA_TYPE_UINT16,
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_ctrl,
+ NULL);
+ }
+
+ /* PCIx registers */
+ if (PCIE_IS_PCIX(bus_p)) {
+ fm_payload_set(ereport,
+ "pcix_status", DATA_TYPE_UINT32,
+ PCIX_ERR_REG(pfd_p)->pcix_status,
+ "pcix_command", DATA_TYPE_UINT16,
+ PCIX_ERR_REG(pfd_p)->pcix_command,
+ NULL);
+ }
+
+ /* PCIx ECC Registers */
+ if (PCIX_ECC_VERSION_CHECK(bus_p)) {
+ pf_pcix_ecc_regs_t *ecc_bdg_reg;
+ pf_pcix_ecc_regs_t *ecc_reg;
+
+ ecc_bdg_reg = PCIX_BDG_ECC_REG(pfd_p, 0);
+ ecc_reg = PCIX_ECC_REG(pfd_p);
+ fm_payload_set(ereport,
+ "pcix_ecc_control_0", DATA_TYPE_UINT16,
+ PCIE_IS_BDG(bus_p) ?
+ (ecc_bdg_reg->pcix_ecc_ctlstat >> 16) :
+ (ecc_reg->pcix_ecc_ctlstat >> 16),
+ "pcix_ecc_status_0", DATA_TYPE_UINT16,
+ PCIE_IS_BDG(bus_p) ?
+ (ecc_bdg_reg->pcix_ecc_ctlstat & 0xFFFF) :
+ (ecc_reg->pcix_ecc_ctlstat & 0xFFFF),
+ "pcix_ecc_fst_addr_0", DATA_TYPE_UINT32,
+ PCIE_IS_BDG(bus_p) ?
+ ecc_bdg_reg->pcix_ecc_fstaddr :
+ ecc_reg->pcix_ecc_fstaddr,
+ "pcix_ecc_sec_addr_0", DATA_TYPE_UINT32,
+ PCIE_IS_BDG(bus_p) ?
+ ecc_bdg_reg->pcix_ecc_secaddr :
+ ecc_reg->pcix_ecc_secaddr,
+ "pcix_ecc_attr_0", DATA_TYPE_UINT32,
+ PCIE_IS_BDG(bus_p) ?
+ ecc_bdg_reg->pcix_ecc_attr :
+ ecc_reg->pcix_ecc_attr,
+ NULL);
+ }
+
+ /* PCIx ECC Bridge Registers */
+ if (PCIX_ECC_VERSION_CHECK(bus_p) && PCIE_IS_BDG(bus_p)) {
+ pf_pcix_ecc_regs_t *ecc_bdg_reg;
+
+ ecc_bdg_reg = PCIX_BDG_ECC_REG(pfd_p, 1);
+ fm_payload_set(ereport,
+ "pcix_ecc_control_1", DATA_TYPE_UINT16,
+ (ecc_bdg_reg->pcix_ecc_ctlstat >> 16),
+ "pcix_ecc_status_1", DATA_TYPE_UINT16,
+ (ecc_bdg_reg->pcix_ecc_ctlstat & 0xFFFF),
+ "pcix_ecc_fst_addr_1", DATA_TYPE_UINT32,
+ ecc_bdg_reg->pcix_ecc_fstaddr,
+ "pcix_ecc_sec_addr_1", DATA_TYPE_UINT32,
+ ecc_bdg_reg->pcix_ecc_secaddr,
+ "pcix_ecc_attr_1", DATA_TYPE_UINT32,
+ ecc_bdg_reg->pcix_ecc_attr,
+ NULL);
+ }
+
+ /* PCIx Bridge */
+ if (PCIE_IS_PCIX(bus_p) && PCIE_IS_BDG(bus_p)) {
+ fm_payload_set(ereport,
+ "pcix_bdg_status", DATA_TYPE_UINT32,
+ PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_stat,
+ "pcix_bdg_sec_status", DATA_TYPE_UINT16,
+ PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_sec_stat,
+ NULL);
+ }
+
+ /* PCIe registers */
+ if (PCIE_IS_PCIE(bus_p)) {
+ fm_payload_set(ereport,
+ "pcie_status", DATA_TYPE_UINT16,
+ PCIE_ERR_REG(pfd_p)->pcie_err_status,
+ "pcie_command", DATA_TYPE_UINT16,
+ PCIE_ERR_REG(pfd_p)->pcie_err_ctl,
+ "pcie_dev_cap", DATA_TYPE_UINT32,
+ PCIE_ERR_REG(pfd_p)->pcie_dev_cap,
+ NULL);
+ }
+
+ /* PCIe AER registers */
+ if (PCIE_HAS_AER(bus_p)) {
+ fm_payload_set(ereport,
+ "pcie_adv_ctl", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_adv_ctl,
+ "pcie_ue_status", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_status,
+ "pcie_ue_mask", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_mask,
+ "pcie_ue_sev", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_sev,
+ "pcie_ue_hdr0", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[0],
+ "pcie_ue_hdr1", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[1],
+ "pcie_ue_hdr2", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[2],
+ "pcie_ue_hdr3", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[3],
+ "pcie_ce_status", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ce_status,
+ "pcie_ce_mask", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ce_mask,
+ NULL);
+ }
+
+ /* PCIe AER decoded header */
+ if (HAS_AER_LOGS(pfd_p, PCIE_ADV_REG(pfd_p)->pcie_ue_status)) {
+ fm_payload_set(ereport,
+ "pcie_ue_tgt_trans", DATA_TYPE_UINT32,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_trans,
+ "pcie_ue_tgt_addr", DATA_TYPE_UINT64,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr,
+ "pcie_ue_tgt_bdf", DATA_TYPE_UINT16,
+ PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf,
+ NULL);
+ /* Clear these values as they no longer valid */
+ PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_trans = 0;
+ PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr = 0;
+ PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = 0;
+ }
+
+ /* PCIe BDG AER registers */
+ if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_HAS_AER(bus_p)) {
+ fm_payload_set(ereport,
+ "pcie_sue_adv_ctl", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_ctl,
+ "pcie_sue_status", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status,
+ "pcie_sue_mask", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_mask,
+ "pcie_sue_sev", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_sev,
+ "pcie_sue_hdr0", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[0],
+ "pcie_sue_hdr1", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[1],
+ "pcie_sue_hdr2", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[2],
+ "pcie_sue_hdr3", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[3],
+ NULL);
+ }
+
+ /* PCIe BDG AER decoded header */
+ if (PCIE_IS_PCIE_BDG(bus_p) && HAS_SAER_LOGS(pfd_p,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status)) {
+ fm_payload_set(ereport,
+ "pcie_sue_tgt_trans", DATA_TYPE_UINT32,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans,
+ "pcie_sue_tgt_addr", DATA_TYPE_UINT64,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr,
+ "pcie_sue_tgt_bdf", DATA_TYPE_UINT16,
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf,
+ NULL);
+ /* Clear these values as they no longer valid */
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = 0;
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = 0;
+ PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = 0;
+ }
+
+ /* PCIe RP registers */
+ if (PCIE_IS_RP(bus_p)) {
+ fm_payload_set(ereport,
+ "pcie_rp_status", DATA_TYPE_UINT32,
+ PCIE_RP_REG(pfd_p)->pcie_rp_status,
+ "pcie_rp_control", DATA_TYPE_UINT16,
+ PCIE_RP_REG(pfd_p)->pcie_rp_ctl,
+ NULL);
+ }
+
+ /* PCIe RP AER registers */
+ if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p)) {
+ fm_payload_set(ereport,
+ "pcie_adv_rp_status", DATA_TYPE_UINT32,
+ PCIE_ADV_RP_REG(pfd_p)->pcie_rp_err_status,
+ "pcie_adv_rp_command", DATA_TYPE_UINT32,
+ PCIE_ADV_RP_REG(pfd_p)->pcie_rp_err_cmd,
+ "pcie_adv_rp_ce_src_id", DATA_TYPE_UINT16,
+ PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id,
+ "pcie_adv_rp_ue_src_id", DATA_TYPE_UINT16,
+ PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id,
+ NULL);
+ }
+
+ /* Misc ereport information */
+ fm_payload_set(ereport,
+ "remainder", DATA_TYPE_UINT32, total--,
+ "severity", DATA_TYPE_UINT32, pfd_p->pe_severity_flags,
+ NULL);
+
+ pf_ereport_post(PCIE_BUS2DIP(bus_p), &ereport, &detector,
+ &eqep);
+ }
+
+ /* Unlock all the devices in the queue */
+ for (pfd_p = impl->pf_dq_tail_p; pfd_p; pfd_p = pfd_p->pe_prev) {
+ if (pfd_p->pe_lock) {
+ pf_handler_exit(PCIE_PFD2DIP(pfd_p));
+ }
+ }
+}
+
+/*
+ * pf_handler_enter must be called to serial access to each device's pf_data_t.
+ * Once error handling is finished with the device call pf_handler_exit to allow
+ * other threads to access it. The same thread may call pf_handler_enter
+ * several times without any consequences.
+ *
+ * The "impl" variable is passed in during scan fabric to double check that
+ * there is not a recursive algorithm and to ensure only one thread is doing a
+ * fabric scan at all times.
+ *
+ * In some cases "impl" is not available, such as "child lookup" being called
+ * from outside of scan fabric, just pass in NULL for this variable and this
+ * extra check will be skipped.
+ */
static int
-pf_panic(dev_info_t *rpdip, ddi_fm_error_t *derr, uint32_t bit,
- pf_data_t *dq_p, pf_data_t *pf_data_p)
+pf_handler_enter(dev_info_t *dip, pf_impl_t *impl)
{
- return (PF_PANIC);
+ pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
+
+ ASSERT(pfd_p);
+
+ /*
+ * Check to see if the lock has already been taken by this
+ * thread. If so just return and don't take lock again.
+ */
+ if (!pfd_p->pe_lock || !impl) {
+ i_ddi_fm_handler_enter(dip);
+ pfd_p->pe_lock = B_TRUE;
+ return (PF_SCAN_SUCCESS);
+ }
+
+ /* Check to see that this dip is already in the "impl" error queue */
+ for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) {
+ if (PCIE_PFD2DIP(pfd_p) == dip) {
+ return (PF_SCAN_SUCCESS);
+ }
+ }
+
+ return (PF_SCAN_DEADLOCK);
+}
+
+static void
+pf_handler_exit(dev_info_t *dip)
+{
+ pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
+
+ ASSERT(pfd_p);
+
+ ASSERT(pfd_p->pe_lock == B_TRUE);
+ i_ddi_fm_handler_exit(dip);
+ pfd_p->pe_lock = B_FALSE;
+}
+
+/*
+ * This function calls the driver's callback function (if it's FMA hardened
+ * and callback capable). This function relies on the current thread already
+ * owning the driver's fmhdl lock.
+ */
+static int
+pf_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr)
+{
+ int cb_sts = DDI_FM_OK;
+
+ if (DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
+ dev_info_t *pdip = ddi_get_parent(dip);
+ struct i_ddi_fmhdl *hdl = DEVI(pdip)->devi_fmhdl;
+ struct i_ddi_fmtgt *tgt = hdl->fh_tgts;
+ struct i_ddi_errhdl *errhdl;
+ while (tgt != NULL) {
+ if (dip == tgt->ft_dip) {
+ errhdl = tgt->ft_errhdl;
+ cb_sts = errhdl->eh_func(dip, derr,
+ errhdl->eh_impl);
+ break;
+ }
+ tgt = tgt->ft_next;
+ }
+ }
+ return (cb_sts);
}
diff --git a/usr/src/uts/common/os/ddifm.c b/usr/src/uts/common/os/ddifm.c
index 71dcab5b61..a111620eae 100644
--- a/usr/src/uts/common/os/ddifm.c
+++ b/usr/src/uts/common/os/ddifm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -467,6 +467,7 @@ i_ddi_fm_handler_enter(dev_info_t *dip)
struct i_ddi_fmhdl *hdl = DEVI(dip)->devi_fmhdl;
mutex_enter(&hdl->fh_lock);
+ hdl->fh_lock_owner = curthread;
}
/*
@@ -480,9 +481,18 @@ i_ddi_fm_handler_exit(dev_info_t *dip)
{
struct i_ddi_fmhdl *hdl = DEVI(dip)->devi_fmhdl;
+ hdl->fh_lock_owner = NULL;
mutex_exit(&hdl->fh_lock);
}
+boolean_t
+i_ddi_fm_handler_owned(dev_info_t *dip)
+{
+ struct i_ddi_fmhdl *hdl = DEVI(dip)->devi_fmhdl;
+
+ return (hdl->fh_lock_owner == curthread);
+}
+
/*
* Register a fault manager error handler for this device instance
*
diff --git a/usr/src/uts/common/os/pcifm.c b/usr/src/uts/common/os/pcifm.c
index f266e5cc1d..6dd300d401 100644
--- a/usr/src/uts/common/os/pcifm.c
+++ b/usr/src/uts/common/os/pcifm.c
@@ -45,21 +45,15 @@
/*
* Expected PCI Express error mask values
+ *
+ * !!NOTE!! All PCI Express functionality including PCIe initialization, PCIe
+ * error handling has been moved to the common pcie misc module. All functions
+ * and variables dealting with PCIe in this file have been deprecated and will
+ * be eventually removed. All Legacy PCI and PCI-X related code should remain
+ * as is.
*/
-uint32_t pcie_expected_ce_mask = 0x0;
-uint32_t pcie_expected_ue_mask = PCIE_AER_UCE_UC;
-#if defined(__sparc)
-uint32_t pcie_expected_sue_mask = 0x0;
-#else
-uint32_t pcie_expected_sue_mask = PCIE_AER_SUCE_RCVD_MA;
-#endif
uint32_t pcie_aer_uce_log_bits = PCIE_AER_UCE_LOG_BITS;
-#if defined(__sparc)
uint32_t pcie_aer_suce_log_bits = PCIE_AER_SUCE_LOG_BITS;
-#else
-uint32_t pcie_aer_suce_log_bits = \
- PCIE_AER_SUCE_LOG_BITS & ~PCIE_AER_SUCE_RCVD_MA;
-#endif
errorq_t *pci_target_queue = NULL;
@@ -709,7 +703,6 @@ pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
uint8_t pcie_cap_ptr;
uint16_t pcie_ecap_ptr;
uint16_t dev_type = 0;
- uint32_t mask = pcie_expected_ue_mask;
/*
* The following sparc specific code should be removed once the pci_cap
@@ -883,37 +876,6 @@ pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
if (erpt_p->pe_dflags & PCIEX_RC_DEV)
pcie_adv_regs->pcie_adv_rc_regs = kmem_zalloc(
sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP);
-
- /*
- * Check that mask values are as expected, if not
- * change them to what we desire.
- */
- pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED);
- pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
- if (pcie_regs->pcie_adv_regs->pcie_ce_mask != pcie_expected_ce_mask) {
- pci_config_put32(erpt_p->pe_hdl,
- pcie_ecap_ptr + PCIE_AER_CE_MASK, pcie_expected_ce_mask);
- }
-
- /* Disable PTLP/ECRC (or mask these two) for Switches */
- if (dev_type == PCIE_PCIECAP_DEV_TYPE_UP ||
- dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) {
- erpt_p->pe_dflags |= PCIEX_SWITCH_DEV;
- mask |= PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC;
- }
-
- if (pcie_regs->pcie_adv_regs->pcie_ue_mask != mask) {
- pci_config_put32(erpt_p->pe_hdl,
- pcie_ecap_ptr + PCIE_AER_UCE_MASK, mask);
- }
- if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
- if (pcie_regs->pcie_adv_regs->pcie_adv_bdg_regs->pcie_sue_mask
- != pcie_expected_sue_mask) {
- pci_config_put32(erpt_p->pe_hdl,
- pcie_ecap_ptr + PCIE_AER_SUCE_MASK,
- pcie_expected_sue_mask);
- }
- }
}
/*
@@ -986,7 +948,6 @@ pci_ereport_setup(dev_info_t *dip)
PCI_REG_FUNC_SHIFT);
}
-
if (!(pci_status & PCI_STAT_CAP)) {
goto done;
}
@@ -1118,6 +1079,7 @@ pci_ereport_teardown(dev_info_t *dip)
kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
kmem_free(erpt_p, sizeof (pci_erpt_t));
fmhdl->fh_bus_specific = NULL;
+
/*
* The following sparc specific code should be removed once the pci_cap
* interfaces create the necessary properties for us.
@@ -2283,6 +2245,20 @@ pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status)
ddi_fm_error_t de;
pci_fme_bus_specific_t pci_fme_bs;
+ /*
+ * On PCI Express systems, all error handling and ereport are done via
+ * the PCIe misc module. This function is a no-op for PCIe Systems. In
+ * order to tell if a system is a PCI or PCIe system, check that the
+ * bus_private_data exists. If it exists, this is a PCIe system.
+ */
+ if (ndi_get_bus_private(dip, B_TRUE)) {
+ derr->fme_status = DDI_FM_OK;
+ if (xx_status != NULL)
+ *xx_status = 0x0;
+
+ return;
+ }
+
fmhdl = DEVI(dip)->devi_fmhdl;
if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
!DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
diff --git a/usr/src/uts/common/os/sunndi.c b/usr/src/uts/common/os/sunndi.c
index 627f8fe6c6..cab88ecfe3 100644
--- a/usr/src/uts/common/os/sunndi.c
+++ b/usr/src/uts/common/os/sunndi.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2469,3 +2469,41 @@ i_ddi_rootnex_post_event(dev_info_t *dip, dev_info_t *rdip,
return (ndi_event_run_callbacks(rootnex_event_hdl, rdip,
eventid, impl_data));
}
+
+/*
+ * ndi_set_bus_private/ndi_get_bus_private:
+ * Get/set device bus private data in devinfo.
+ */
+void
+ndi_set_bus_private(dev_info_t *dip, boolean_t up, uint32_t port_type,
+ void *data)
+{
+ if (up) {
+ DEVI(dip)->devi_bus.port_up.info.port.type = port_type;
+ DEVI(dip)->devi_bus.port_up.priv_p = data;
+ } else {
+ DEVI(dip)->devi_bus.port_down.info.port.type = port_type;
+ DEVI(dip)->devi_bus.port_down.priv_p = data;
+ }
+}
+
+void *
+ndi_get_bus_private(dev_info_t *dip, boolean_t up)
+{
+ if (up)
+ return (DEVI(dip)->devi_bus.port_up.priv_p);
+ else
+ return (DEVI(dip)->devi_bus.port_down.priv_p);
+}
+
+boolean_t
+ndi_port_type(dev_info_t *dip, boolean_t up, uint32_t port_type)
+{
+ if (up) {
+ return ((DEVI(dip)->devi_bus.port_up.info.port.type) ==
+ port_type);
+ } else {
+ return ((DEVI(dip)->devi_bus.port_down.info.port.type) ==
+ port_type);
+ }
+}
diff --git a/usr/src/uts/common/sys/ddi_impldefs.h b/usr/src/uts/common/sys/ddi_impldefs.h
index f5c227e5aa..2cc473236c 100644
--- a/usr/src/uts/common/sys/ddi_impldefs.h
+++ b/usr/src/uts/common/sys/ddi_impldefs.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -74,6 +74,22 @@ typedef enum {
*/
struct devinfo_audit;
+typedef struct devi_port {
+ union {
+ struct {
+ uint32_t type;
+ uint32_t pad;
+ } port;
+ uint64_t type64;
+ } info;
+ void *priv_p;
+} devi_port_t;
+
+typedef struct devi_bus_priv {
+ devi_port_t port_up;
+ devi_port_t port_down;
+} devi_bus_priv_t;
+
struct dev_info {
struct dev_info *devi_parent; /* my parent node in tree */
@@ -200,6 +216,9 @@ struct dev_info {
int devi_ct_count; /* # of outstanding responses */
int devi_ct_neg; /* neg. occurred on dip */
list_t devi_ct;
+
+ /* owned by bus framework */
+ devi_bus_priv_t devi_bus; /* bus private data */
};
#define DEVI(dev_info_type) ((struct dev_info *)(dev_info_type))
diff --git a/usr/src/uts/common/sys/ddifm_impl.h b/usr/src/uts/common/sys/ddifm_impl.h
index a8dd18cce5..07cf1f05d1 100644
--- a/usr/src/uts/common/sys/ddifm_impl.h
+++ b/usr/src/uts/common/sys/ddifm_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -82,6 +82,7 @@ struct i_ddi_fmtgt {
struct i_ddi_fmhdl {
kmutex_t fh_lock; /* error handler lock */
+ kthread_t *fh_lock_owner;
struct i_ddi_fmc *fh_dma_cache; /* fm dma handle cache */
struct i_ddi_fmc *fh_acc_cache; /* fm access handle cache */
dev_info_t *fh_dip;
@@ -114,6 +115,7 @@ void i_ddi_drv_ereport_post(dev_info_t *, const char *, nvlist_t *, int);
/* target error handler add/remove/dispatch */
extern void i_ddi_fm_handler_enter(dev_info_t *);
extern void i_ddi_fm_handler_exit(dev_info_t *);
+extern boolean_t i_ddi_fm_handler_owned(dev_info_t *);
/* access and dma handle protection support */
extern void i_ddi_fm_acc_err_set(ddi_acc_handle_t, uint64_t, int, int);
diff --git a/usr/src/uts/common/sys/fm/io/pci.h b/usr/src/uts/common/sys/fm/io/pci.h
index 9529d96e52..b54b92b03a 100644
--- a/usr/src/uts/common/sys/fm/io/pci.h
+++ b/usr/src/uts/common/sys/fm/io/pci.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -156,6 +156,9 @@ extern "C" {
#define PCIEX_SUE_HDR2 "sue_hdr2"
#define PCIEX_SUE_HDR3 "sue_hdr3"
+/* Common fabric class names */
+#define PCIEX_FABRIC "fabric"
+
#ifdef __cplusplus
}
#endif
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 7227dac0d1..b2915d15e9 100644
--- a/usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h
+++ b/usr/src/uts/common/sys/hotplug/pci/pciehpc_impl.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -221,15 +221,10 @@ extern int pciehpc_debug;
/* default interrupt priority for Hot Plug interrupts */
#define PCIEHPC_INTR_PRI 1
-#if defined(__sparc)
-#define PCIE_ENABLE_ERRORS(arg1, arg2) \
- pcie_enable_errors(arg1, arg2); \
- (void) pcie_enable_ce(arg1, arg2)
-#define PCIE_DISABLE_ERRORS(arg1, arg2) pcie_disable_errors(arg1, arg2)
-#else
-#define PCIE_ENABLE_ERRORS(arg1, arg2) pcie_error_enable(arg1, arg2)
-#define PCIE_DISABLE_ERRORS(arg1, arg2) pcie_error_disable(arg1, arg2)
-#endif
+#define PCIE_ENABLE_ERRORS(arg1) \
+ pcie_enable_errors(arg1); \
+ (void) pcie_enable_ce(arg1)
+#define PCIE_DISABLE_ERRORS(arg1) pcie_disable_errors(arg1)
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/pci.h b/usr/src/uts/common/sys/pci.h
index 647a2060e3..cab6441560 100644
--- a/usr/src/uts/common/sys/pci.h
+++ b/usr/src/uts/common/sys/pci.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -98,6 +98,7 @@ extern "C" {
*/
#define PCI_BCNF_BCNTRL_PARITY_ENABLE 0x1
#define PCI_BCNF_BCNTRL_SERR_ENABLE 0x2
+#define PCI_BCNF_BCNTRL_ISA_ENABLE 0x4
#define PCI_BCNF_BCNTRL_VGA_ENABLE 0x8
#define PCI_BCNF_BCNTRL_MAST_AB_MODE 0x20
#define PCI_BCNF_BCNTRL_DTO_STAT 0x400
diff --git a/usr/src/uts/common/sys/pcie.h b/usr/src/uts/common/sys/pcie.h
index 624d3f9468..d840e1358b 100644
--- a/usr/src/uts/common/sys/pcie.h
+++ b/usr/src/uts/common/sys/pcie.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -70,6 +70,8 @@ extern "C" {
#define PCIE_PCIECAP_DEV_TYPE_DOWN 0x60 /* Downstream Port of Switch */
#define PCIE_PCIECAP_DEV_TYPE_PCIE2PCI 0x70 /* PCI-E to PCI Bridge */
#define PCIE_PCIECAP_DEV_TYPE_PCI2PCIE 0x80 /* PCI to PCI-E Bridge */
+#define PCIE_PCIECAP_DEV_TYPE_RC_IEP 0x90 /* RootComplex Integrated Dev */
+#define PCIE_PCIECAP_DEV_TYPE_RC_EC 0xA0 /* RootComplex Evt Collector */
#define PCIE_PCIECAP_DEV_TYPE_MASK 0xF0 /* Device/Port Type Mask */
#define PCIE_PCIECAP_SLOT_IMPL 0x100 /* Slot Impl vs Integrated */
#define PCIE_PCIECAP_INT_MSG_NUM 0x3700 /* Interrupt Message Number */
@@ -480,7 +482,7 @@ extern "C" {
#define PCIE_AER_ERR_SRC_ID_CE_SHIFT 0 /* ERR_COR Source ID */
#define PCIE_AER_ERR_SRC_ID_CE_MASK 0xFFFF
#define PCIE_AER_ERR_SRC_ID_UE_SHIFT 16 /* ERR_FATAL/NONFATAL Src ID */
-#define PCIE_AER_ERR_SRC_ID_UE_MASK 0xFFF
+#define PCIE_AER_ERR_SRC_ID_UE_MASK 0xFFFF
/*
* AER Secondary Uncorrectable Error Register
diff --git a/usr/src/uts/common/sys/pcie_impl.h b/usr/src/uts/common/sys/pcie_impl.h
index cc533d78cb..7e3ec25479 100644
--- a/usr/src/uts/common/sys/pcie_impl.h
+++ b/usr/src/uts/common/sys/pcie_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,98 +34,93 @@ extern "C" {
#include <sys/pcie.h>
-/* PCI-E config space data for error handling and ereport */
-typedef struct pf_data {
- dev_info_t *dip;
- pcie_req_id_t bdf;
- pcie_req_id_t rp_bdf;
- uint32_t severity_flags;
- int parent_index;
- pcie_req_id_t fault_bdf;
- uint32_t fault_addr;
- int send_erpt;
-
- /* 0-3Fh. PCI */
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t hdr_type;
- uint16_t command; /* command */
- uint16_t status; /* status */
- uint8_t rev_id;
- uint16_t s_status; /* Bridge secondary status */
- pcie_req_id_t bdg_secbus; /* Bridge secondary bus num */
-
- /* 40h-FFh. PCI-X Capability */
- uint16_t pcix_s_status; /* PCI-X Secondary status */
- uint32_t pcix_bdg_status; /* PCI-X Bridge status */
-
- /* 40h-FFh. PCI-E Capability */
- uint16_t pcie_off; /* PCI-E capability offset */
- uint8_t dev_type; /* device/port type */
- uint16_t dev_status; /* device status */
-
- /* 100h-FFFh. Extended PCI-E */
- uint16_t aer_off; /* AER offset */
-
- uint32_t aer_ce_status; /* AER Correctable Errors */
-
- uint32_t aer_ue_status; /* AER Uncorrectable Errors */
- uint32_t aer_severity;
- uint32_t aer_control;
- uint32_t aer_h0;
- uint32_t aer_h1;
- uint32_t aer_h2;
- uint32_t aer_h3;
-
- uint32_t s_aer_ue_status; /* Secondary AER UEs */
- uint32_t s_aer_control;
- uint32_t s_aer_severity;
- uint32_t s_aer_h0;
- uint32_t s_aer_h1;
- uint32_t s_aer_h2;
- uint32_t s_aer_h3;
-} pf_data_t;
+#define PCI_GET_BDF(dip) \
+ PCIE_DIP2BUS(dip)->bus_bdf
+#define PCI_GET_SEC_BUS(dip) \
+ PCIE_DIP2BUS(dip)->bus_bdg_secbus
+#define PCI_GET_PCIE2PCI_SECBUS(dip) \
+ PCIE_DIP2BUS(dip)->bus_pcie2pci_secbus
-/* Information used while handling errors in the fabric. */
-typedef struct pf_impl {
- dev_info_t *pf_rpdip;
- pcie_req_id_t pf_fbdf; /* captured fault bdf to scan */
- uint32_t pf_faddr; /* captured fault addr to scan */
- ddi_fm_error_t *pf_derr;
- pf_data_t *pf_dq_p; /* ptr to pcie fault data queue */
- int *pf_dq_tail_p; /* last valid index of fault data q */
-} pf_impl_t;
+#define DEVI_PORT_TYPE_PCI \
+ ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8) | \
+ PCI_BRIDGE_PCI_IF_PCI2PCI)
-/* Parent Private data of PCI/PCIe devices in a PCIe system */
-typedef struct pcie_ppd {
- dev_info_t *ppd_dip;
- ddi_acc_handle_t ppd_cfg_hdl; /* error handling acc handle */
- kmutex_t ppd_fm_lock; /* error handling lock */
- uint_t ppd_fm_flags;
+#define PCIE_DIP2BUS(dip) \
+ (ndi_port_type(dip, B_TRUE, DEVI_PORT_TYPE_PCI) ? \
+ PCIE_DIP2UPBUS(dip) : \
+ ndi_port_type(dip, B_FALSE, DEVI_PORT_TYPE_PCI) ? \
+ PCIE_DIP2DOWNBUS(dip) : NULL)
- /* Static PCI/PCIe information */
- pcie_req_id_t ppd_bdf;
- uint32_t ppd_dev_ven_id; /* device/vendor ID */
- uint8_t ppd_hdr_type; /* pci header type, see pci.h */
- uint8_t ppd_dev_type; /* PCI-E dev type, see pcie.h */
- uint8_t ppd_bdg_secbus; /* Bridge secondary bus num */
- pcie_req_id_t ppd_pcie2pci_secbus; /* PCIe2PCI Bridge secbus num */
- uint16_t ppd_pcie_off; /* PCIe Capability Offset */
- uint16_t ppd_aer_off; /* PCIe Advanced Error Offset */
- uint16_t ppd_pcix_off; /* PCIx Capability Offset */
- pci_bus_range_t ppd_bus_range; /* pci bus-range property */
- ppb_ranges_t *ppd_addr_ranges; /* pci range property */
- int ppd_addr_entries; /* number of range prop */
- pci_regspec_t *ppd_assigned_addr; /* "assigned-address" prop */
- int ppd_assigned_entries; /* number of prop entries */
-} pcie_ppd_t;
+#define PCIE_DIP2UPBUS(dip) \
+ ((pcie_bus_t *)ndi_get_bus_private(dip, B_TRUE))
+#define PCIE_DIP2DOWNBUS(dip) \
+ ((pcie_bus_t *)ndi_get_bus_private(dip, B_FALSE))
+#define PCIE_DIP2PFD(dip) (PCIE_DIP2BUS(dip))->bus_pfd
+#define PCIE_PFD2BUS(pfd_p) pfd_p->pe_bus_p
+#define PCIE_PFD2DIP(pfd_p) PCIE_PFD2BUS(pfd_p)->bus_dip
+#define PCIE_BUS2DIP(bus_p) bus_p->bus_dip
+#define PCIE_BUS2PFD(bus_p) PCIE_DIP2PFD(PCIE_BUS2DIP(bus_p))
-#define PCI_GET_BDF(dip) \
- ((pcie_ppd_t *)pcie_get_ppd(dip))->ppd_bdf
-#define PCI_GET_BDG_SECBUS(dip) \
- ((pcie_ppd_t *)pcie_get_ppd(dip))->ppd_bdg_secbus
-#define PCI_GET_PCIE2PCI_SECBUS(dip) \
- ((pcie_ppd_t *)pcie_get_ppd(dip))->ppd_pcie2pci_secbus
+#define PCIE_IS_PCIE(bus_p) (bus_p->bus_pcie_off)
+#define PCIE_IS_PCIX(bus_p) (bus_p->bus_pcix_off)
+#define PCIE_IS_PCI(bus_p) \
+ (bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_PCI_DEV)
+#define PCIE_HAS_AER(bus_p) (bus_p->bus_aer_off)
+/* IS_ROOT = is RC or RP */
+#define PCIE_IS_ROOT(bus_p) (PCIE_IS_RC(bus_p) || PCIE_IS_RP(bus_p))
+/*
+ * This is a pseudo pcie "device type", but it's needed to explain describe
+ * nodes such as PX and NPE, which aren't really PCI devices but do control or
+ * interaction with PCI error handling.
+ */
+#define PCIE_IS_RC(bus_p) \
+ (bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO)
+#define PCIE_IS_RP(bus_p) \
+ ((bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) && \
+ PCIE_IS_PCIE(bus_p))
+#define PCIE_IS_SW(bus_p) \
+ ((bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_UP) || \
+ (bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN))
+#define PCIE_IS_BDG(bus_p) (bus_p->bus_hdr_type == PCI_HEADER_ONE)
+#define PCIE_IS_PCI_BDG(bus_p) \
+ ((bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_PCI_DEV) && \
+ PCIE_IS_BDG(bus_p))
+#define PCIE_IS_PCIE_BDG(bus_p) \
+ (bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI)
+#define PCIE_IS_PCIE_SEC(bus_p) \
+ (PCIE_IS_PCIE(bus_p) && PCIE_IS_BDG(bus_p) && !PCIE_IS_PCIE_BDG(bus_p))
+#define PCIX_ECC_VERSION_CHECK(bus_p) \
+ ((bus_p->bus_ecc_ver == PCI_PCIX_VER_1) || \
+ (bus_p->bus_ecc_ver == PCI_PCIX_VER_2))
+
+#define PCIE_VENID(bus_p) (bus_p->bus_dev_ven_id & 0xffff)
+#define PCIE_DEVID(bus_p) ((bus_p->bus_dev_ven_id >> 16) & 0xffff)
+
+/* PCIE Cap/AER shortcuts */
+#define PCIE_GET(sz, bus_p, off) \
+ pci_config_get ## sz(bus_p->bus_cfg_hdl, off)
+#define PCIE_PUT(sz, bus_p, off, val) \
+ pci_config_put ## sz(bus_p->bus_cfg_hdl, off, val)
+#define PCIE_CAP_GET(sz, bus_p, off) \
+ PCI_CAP_GET ## sz(bus_p->bus_cfg_hdl, NULL, bus_p->bus_pcie_off, off)
+#define PCIE_CAP_PUT(sz, bus_p, off, val) \
+ PCI_CAP_PUT ## sz(bus_p->bus_cfg_hdl, NULL, bus_p->bus_pcie_off, off, \
+ val)
+#define PCIE_AER_GET(sz, bus_p, off) \
+ PCI_XCAP_GET ## sz(bus_p->bus_cfg_hdl, NULL, bus_p->bus_aer_off, off)
+#define PCIE_AER_PUT(sz, bus_p, off, val) \
+ PCI_XCAP_PUT ## sz(bus_p->bus_cfg_hdl, NULL, bus_p->bus_aer_off, off, \
+ val)
+#define PCIX_CAP_GET(sz, bus_p, off) \
+ PCI_CAP_GET ## sz(bus_p->bus_cfg_hdl, NULL, bus_p->bus_pcix_off, off)
+#define PCIX_CAP_PUT(sz, bus_p, off, val) \
+ PCI_CAP_PUT ## sz(bus_p->bus_cfg_hdl, NULL, bus_p->bus_pcix_off, off, \
+ val)
+
+/* Translate PF error return values to DDI_FM values */
+#define PF_ERR2DDIFM_ERR(sts) \
+ (sts & PF_ERR_FATAL_FLAGS ? DDI_FM_FATAL : \
+ (sts == PF_ERR_NO_ERROR ? DDI_FM_OK : DDI_FM_NONFATAL))
/*
* The following flag is used for Broadcom 5714/5715 bridge prefetch issue.
@@ -133,73 +128,250 @@ typedef struct pcie_ppd {
*/
#define PX_DMAI_FLAGS_MAP_BUFZONE 0x40000
-/* ppd_fm_flags field */
-#define PF_FM_READY (1 << 0) /* ppd_fm_lock initialized */
-#define PF_IS_NH (1 << 1) /* known as non-hardened */
+/*
+ * PCI(e/-X) structures used to to gather and report errors detected by
+ * PCI(e/-X) compliant devices. These registers only contain "dynamic" data.
+ * Static data such as Capability Offsets and Version #s is saved in the parent
+ * private data.
+ */
+#define PCI_ERR_REG(pfd_p) pfd_p->pe_pci_regs
+#define PCI_BDG_ERR_REG(pfd_p) PCI_ERR_REG(pfd_p)->pci_bdg_regs
+#define PCIX_ERR_REG(pfd_p) pfd_p->pe_ext.pe_pcix_regs
+#define PCIX_ECC_REG(pfd_p) PCIX_ERR_REG(pfd_p)->pcix_ecc_regs
+#define PCIX_BDG_ERR_REG(pfd_p) pfd_p->pe_pcix_bdg_regs
+#define PCIX_BDG_ECC_REG(pfd_p, n) PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_ecc_regs[n]
+#define PCIE_ERR_REG(pfd_p) pfd_p->pe_ext.pe_pcie_regs
+#define PCIE_RP_REG(pfd_p) PCIE_ERR_REG(pfd_p)->pcie_rp_regs
+#define PCIE_ROOT_FAULT(pfd_p) pfd_p->pe_root_fault
+#define PCIE_ADV_REG(pfd_p) PCIE_ERR_REG(pfd_p)->pcie_adv_regs
+#define PCIE_ADV_HDR(pfd_p, n) PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[n]
+#define PCIE_ADV_BDG_REG(pfd_p) \
+ PCIE_ADV_REG(pfd_p)->pcie_ext.pcie_adv_bdg_regs
+#define PCIE_ADV_BDG_HDR(pfd_p, n) PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[n]
+#define PCIE_ADV_RP_REG(pfd_p) \
+ PCIE_ADV_REG(pfd_p)->pcie_ext.pcie_adv_rp_regs
+#define PFD_IS_ROOT(pfd_p) PCIE_IS_ROOT(PCIE_PFD2BUS(pfd_p))
+#define PFD_IS_RC(pfd_p) PCIE_IS_RC(PCIE_PFD2BUS(pfd_p))
+#define PFD_IS_RP(pfd_p) PCIE_IS_RP(PCIE_PFD2BUS(pfd_p))
+
+typedef struct pf_pci_bdg_err_regs {
+ uint16_t pci_bdg_sec_stat; /* PCI secondary status reg */
+ uint16_t pci_bdg_ctrl; /* PCI bridge control reg */
+} pf_pci_bdg_err_regs_t;
+
+typedef struct pf_pci_err_regs {
+ uint16_t pci_err_status; /* pci status register */
+ uint16_t pci_cfg_comm; /* pci command register */
+ pf_pci_bdg_err_regs_t *pci_bdg_regs;
+} pf_pci_err_regs_t;
+
+typedef struct pf_pcix_ecc_regs {
+ uint32_t pcix_ecc_ctlstat; /* pcix ecc control status reg */
+ uint32_t pcix_ecc_fstaddr; /* pcix ecc first address reg */
+ uint32_t pcix_ecc_secaddr; /* pcix ecc second address reg */
+ uint32_t pcix_ecc_attr; /* pcix ecc attributes reg */
+} pf_pcix_ecc_regs_t;
+
+typedef struct pf_pcix_err_regs {
+ uint16_t pcix_command; /* pcix command register */
+ uint32_t pcix_status; /* pcix status register */
+ pf_pcix_ecc_regs_t *pcix_ecc_regs; /* pcix ecc registers */
+} pf_pcix_err_regs_t;
-/* PCIe fabric error handling return codes */
-#define PF_NO_ERROR (1 << 0) /* No error seen */
-#define PF_CE (1 << 1) /* Correctable Error */
-#define PF_NO_PANIC (1 << 2) /* Error should not panic sys */
-#define PF_MATCHED_DEVICE (1 << 3) /* Error Handled By Device */
-#define PF_MATCHED_RC (1 << 4) /* Error Handled By RC */
-#define PF_MATCHED_PARENT (1 << 5) /* Error Handled By Parent */
-#define PF_PANIC (1 << 6) /* Error should panic system */
+typedef struct pf_pcix_bdg_err_regs {
+ uint16_t pcix_bdg_sec_stat; /* pcix bridge secondary status reg */
+ uint32_t pcix_bdg_stat; /* pcix bridge status reg */
+ pf_pcix_ecc_regs_t *pcix_bdg_ecc_regs[2]; /* pcix ecc registers */
+} pf_pcix_bdg_err_regs_t;
-/* PCIe fabric handle lookup return codes */
-#define PF_HDL_FOUND 0
-#define PF_HDL_NOTFOUND 1
+typedef struct pf_pcie_adv_bdg_err_regs {
+ uint32_t pcie_sue_ctl; /* pcie bridge secondary ue control */
+ uint32_t pcie_sue_status; /* pcie bridge secondary ue status */
+ uint32_t pcie_sue_mask; /* pcie bridge secondary ue mask */
+ uint32_t pcie_sue_sev; /* pcie bridge secondary ue severity */
+ uint32_t pcie_sue_hdr[4]; /* pcie bridge secondary ue hdr log */
+ uint32_t pcie_sue_tgt_trans; /* Fault trans type from SAER Logs */
+ uint64_t pcie_sue_tgt_addr; /* Fault addr from SAER Logs */
+ pcie_req_id_t pcie_sue_tgt_bdf; /* Fault bdf from SAER Logs */
+} pf_pcie_adv_bdg_err_regs_t;
-/* PCIe fabric handle lookup address flags */
-#define PF_DMA_ADDR (1 << 0)
-#define PF_PIO_ADDR (1 << 1)
-#define PF_CFG_ADDR (1 << 2)
-#define PF_IO_ADDR (1 << 3)
+typedef struct pf_pcie_adv_rp_err_regs {
+ uint32_t pcie_rp_err_status; /* pcie root complex error status reg */
+ uint32_t pcie_rp_err_cmd; /* pcie root complex error cmd reg */
+ uint16_t pcie_rp_ce_src_id; /* pcie root complex ce sourpe id */
+ uint16_t pcie_rp_ue_src_id; /* pcie root complex ue sourpe id */
+} pf_pcie_adv_rp_err_regs_t;
-#define PF_SEND_ERPT_YES 1
-#define PF_SEND_ERPT_UNKNOWN 0
-#define PF_SEND_ERPT_NO -1
+typedef struct pf_pcie_adv_err_regs {
+ uint32_t pcie_adv_ctl; /* pcie advanced control reg */
+ uint32_t pcie_ue_status; /* pcie ue error status reg */
+ uint32_t pcie_ue_mask; /* pcie ue error mask reg */
+ uint32_t pcie_ue_sev; /* pcie ue error severity reg */
+ uint32_t pcie_ue_hdr[4]; /* pcie ue header log */
+ uint32_t pcie_ce_status; /* pcie ce error status reg */
+ uint32_t pcie_ce_mask; /* pcie ce error mask reg */
+ union {
+ pf_pcie_adv_bdg_err_regs_t *pcie_adv_bdg_regs; /* bdg regs */
+ pf_pcie_adv_rp_err_regs_t *pcie_adv_rp_regs; /* rp regs */
+ } pcie_ext;
+ uint32_t pcie_ue_tgt_trans; /* Fault trans type from AER Logs */
+ uint64_t pcie_ue_tgt_addr; /* Fault addr from AER Logs */
+ pcie_req_id_t pcie_ue_tgt_bdf; /* Fault bdf from SAER Logs */
+} pf_pcie_adv_err_regs_t;
-#define PF_SUCCESS (1 << 0)
-#define PF_FAILURE (1 << 1)
-#define PF_DO_NOT_SCAN (1 << 2)
+typedef struct pf_pcie_rp_err_regs {
+ uint32_t pcie_rp_status; /* root complex status register */
+ uint16_t pcie_rp_ctl; /* root complex control register */
+} pf_pcie_rp_err_regs_t;
-/* PCIe helper functions */
-extern pcie_ppd_t *pcie_get_ppd(dev_info_t *dip);
+typedef struct pf_pcie_err_regs {
+ uint16_t pcie_err_status; /* pcie device status register */
+ uint16_t pcie_err_ctl; /* pcie error control register */
+ uint32_t pcie_dev_cap; /* pcie device capabilities register */
+ pf_pcie_rp_err_regs_t *pcie_rp_regs; /* pcie root complex regs */
+ pf_pcie_adv_err_regs_t *pcie_adv_regs; /* pcie aer regs */
+} pf_pcie_err_regs_t;
+
+typedef struct pf_root_fault {
+ pcie_req_id_t fault_bdf; /* Fault BDF of error */
+ uint64_t fault_addr; /* Fault Addr of error */
+ boolean_t full_scan; /* Option to do a full scan */
+} pf_root_fault_t;
+
+typedef struct pf_data pf_data_t;
+
+typedef struct pcie_bus {
+ /* Needed for PCI/PCIe fabric error handling */
+ dev_info_t *bus_dip;
+ dev_info_t *bus_rp_dip;
+ ddi_acc_handle_t bus_cfg_hdl; /* error handling acc handle */
+ uint_t bus_fm_flags;
+
+ /* Static PCI/PCIe information */
+ pcie_req_id_t bus_bdf;
+ pcie_req_id_t bus_rp_bdf; /* BDF of device's Root Port */
+ uint32_t bus_dev_ven_id; /* device/vendor ID */
+ uint8_t bus_rev_id; /* revision ID */
+ uint8_t bus_hdr_type; /* pci header type, see pci.h */
+ pcie_req_id_t bus_pcie2pci_secbus; /* PCIe2PCI Bridge secbus num */
+ uint16_t bus_dev_type; /* PCI-E dev type, see pcie.h */
+ uint8_t bus_bdg_secbus; /* Bridge secondary bus num */
+ uint16_t bus_pcie_off; /* PCIe Capability Offset */
+ uint16_t bus_aer_off; /* PCIe Advanced Error Offset */
+ uint16_t bus_pcix_off; /* PCIx Capability Offset */
+ uint16_t bus_ecc_ver; /* PCIX ecc version */
+ pci_bus_range_t bus_bus_range; /* pci bus-range property */
+ ppb_ranges_t *bus_addr_ranges; /* pci range property */
+ int bus_addr_entries; /* number of range prop */
+ pci_regspec_t *bus_assigned_addr; /* "assigned-address" prop */
+ int bus_assigned_entries; /* number of prop entries */
+
+ /* Cache of last fault data */
+ pf_data_t *bus_pfd;
+} pcie_bus_t;
+
+struct pf_data {
+ boolean_t pe_lock;
+ boolean_t pe_valid;
+ uint32_t pe_severity_flags; /* Severity of error */
+ pcie_bus_t *pe_bus_p;
+ pf_root_fault_t *pe_root_fault; /* Only valid for RC and RP */
+ pf_pci_err_regs_t *pe_pci_regs; /* PCI error reg */
+ union {
+ pf_pcix_err_regs_t *pe_pcix_regs; /* PCI-X error reg */
+ pf_pcie_err_regs_t *pe_pcie_regs; /* PCIe error reg */
+ } pe_ext;
+ pf_pcix_bdg_err_regs_t *pe_pcix_bdg_regs; /* PCI-X bridge regs */
+ pf_data_t *pe_prev; /* Next error in queue */
+ pf_data_t *pe_next; /* Next error in queue */
+};
+
+/* Information used while handling errors in the fabric. */
+typedef struct pf_impl {
+ ddi_fm_error_t *pf_derr;
+ pf_root_fault_t *pf_fault; /* captured fault bdf/addr to scan */
+ pf_data_t *pf_dq_head_p; /* ptr to fault data queue */
+ pf_data_t *pf_dq_tail_p; /* ptr pt last fault data q */
+ uint32_t pf_total; /* total non RC pf_datas */
+} pf_impl_t;
+
+/* bus_fm_flags field */
+#define PF_FM_READY (1 << 0) /* bus_fm_lock initialized */
+#define PF_FM_IS_NH (1 << 1) /* known as non-hardened */
+
+/*
+ * PCIe fabric handle lookup address flags. Used to define what type of
+ * transaction the address is for. These same value are defined again in
+ * fabric-xlate FM module. Do not modify these variables, without modifying
+ * those.
+ */
+#define PF_ADDR_DMA (1 << 0)
+#define PF_ADDR_PIO (1 << 1)
+#define PF_ADDR_CFG (1 << 2)
+
+/* PCIe fabric error scanning status flags */
+#define PF_SCAN_SUCCESS (1 << 0)
+#define PF_SCAN_CB_FAILURE (1 << 1) /* hardened device callback failure */
+#define PF_SCAN_NO_ERR_IN_CHILD (1 << 2) /* no errors in bridge sec stat reg */
+#define PF_SCAN_IN_DQ (1 << 3) /* already present in the faultq */
+#define PF_SCAN_DEADLOCK (1 << 4) /* deadlock detected */
+#define PF_SCAN_BAD_RESPONSE (1 << 5) /* Incorrect device response */
+
+/* PCIe fabric error handling severity return flags */
+#define PF_ERR_NO_ERROR (1 << 0) /* No error seen */
+#define PF_ERR_CE (1 << 1) /* Correctable Error */
+#define PF_ERR_NO_PANIC (1 << 2) /* Error should not panic sys */
+#define PF_ERR_MATCHED_DEVICE (1 << 3) /* Error Handled By Device */
+#define PF_ERR_MATCHED_RC (1 << 4) /* Error Handled By RC */
+#define PF_ERR_MATCHED_PARENT (1 << 5) /* Error Handled By Parent */
+#define PF_ERR_PANIC (1 << 6) /* Error should panic system */
+#define PF_ERR_PANIC_DEADLOCK (1 << 7) /* deadlock detected */
+
+#define PF_ERR_FATAL_FLAGS (PF_ERR_PANIC | PF_ERR_PANIC_DEADLOCK)
+
+#define PF_HDL_FOUND 1
+#define PF_HDL_NOTFOUND 2
+
+#define PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO 0x100
/* PCIe Friendly Functions */
extern int pcie_initchild(dev_info_t *dip);
extern void pcie_uninitchild(dev_info_t *dip);
-extern void pcie_clear_errors(dev_info_t *dip, ddi_acc_handle_t cfg_hdl);
+extern void pcie_clear_errors(dev_info_t *dip);
extern int pcie_postattach_child(dev_info_t *dip);
-extern void pcie_enable_errors(dev_info_t *dip, ddi_acc_handle_t cfg_hdl);
-extern void pcie_disable_errors(dev_info_t *dip, ddi_acc_handle_t cfg_hdl);
-extern int pcie_enable_ce(dev_info_t *dip, ddi_acc_handle_t cfg_hdl);
-extern dev_info_t *pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip);
-extern uint32_t pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip);
+extern void pcie_enable_errors(dev_info_t *dip);
+extern void pcie_disable_errors(dev_info_t *dip);
+extern int pcie_enable_ce(dev_info_t *dip);
+extern boolean_t pcie_bridge_is_link_disabled(dev_info_t *);
-extern pcie_ppd_t *pcie_init_ppd(dev_info_t *cdip);
-extern void pcie_uninit_ppd(dev_info_t *cdip);
+extern pcie_bus_t *pcie_init_bus(dev_info_t *cdip);
+extern void pcie_fini_bus(dev_info_t *cdip);
+extern void pcie_rc_init_bus(dev_info_t *dip);
+extern void pcie_rc_fini_bus(dev_info_t *dip);
+extern void pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd);
+extern void pcie_rc_fini_pfd(pf_data_t *pfd);
extern boolean_t pcie_is_child(dev_info_t *dip, dev_info_t *rdip);
extern int pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf);
+extern dev_info_t *pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip);
+extern uint32_t pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip);
+
+extern uint32_t pcie_get_aer_uce_mask();
+extern uint32_t pcie_get_aer_ce_mask();
+extern uint32_t pcie_get_aer_suce_mask();
+extern uint32_t pcie_get_serr_mask();
+extern void pcie_set_aer_uce_mask(uint32_t mask);
+extern void pcie_set_aer_ce_mask(uint32_t mask);
+extern void pcie_set_aer_suce_mask(uint32_t mask);
+extern void pcie_set_serr_mask(uint32_t mask);
/* PCIe error handling functions */
-extern int pf_en_dq(pf_data_t *pf_data_p, pf_data_t *dq_p, int *dq_tail_p,
- pcie_req_id_t pbdf);
-extern int pf_get_dq_size(void);
-extern int pf_tlp_decode(dev_info_t *rpdip, pf_data_t *pf_data_p,
- pcie_req_id_t *bdf, uint32_t *addr, uint32_t *trans_type);
-extern int pf_tlp_hdl_lookup(dev_info_t *rpdip, ddi_fm_error_t *derr,
- pf_data_t *pf_data_p);
-extern int pf_hdl_lookup(dev_info_t *rpdip, uint64_t ena,
- uint32_t flag, uint32_t addr, pcie_req_id_t bdf);
extern int pf_scan_fabric(dev_info_t *rpdip, ddi_fm_error_t *derr,
- pf_data_t *dq_p, int *dq_tail_p);
-extern void pf_init(dev_info_t *dip, ddi_iblock_cookie_t ibc,
- ddi_attach_cmd_t cmd);
-extern void pf_fini(dev_info_t *dip, ddi_detach_cmd_t cmd);
-extern boolean_t pf_ready(dev_info_t *dip);
-
+ pf_data_t *root_pfd_p);
+extern void pf_init(dev_info_t *, ddi_iblock_cookie_t, ddi_attach_cmd_t);
+extern void pf_fini(dev_info_t *, ddi_detach_cmd_t);
+extern int pf_hdl_lookup(dev_info_t *, uint64_t, uint32_t, uint64_t,
+ pcie_req_id_t);
+extern int pf_tlp_decode(pcie_bus_t *, pf_pcie_adv_err_regs_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h
index 3289ab566c..081c624335 100644
--- a/usr/src/uts/common/sys/sunddi.h
+++ b/usr/src/uts/common/sys/sunddi.h
@@ -1913,7 +1913,8 @@ pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *status);
int
pci_peekpoke_check(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *,
int (*handler)(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
- void *), kmutex_t *, kmutex_t *);
+ void *), kmutex_t *, kmutex_t *,
+ void (*scan)(dev_info_t *, ddi_fm_error_t *));
#endif
void
diff --git a/usr/src/uts/common/sys/sunndi.h b/usr/src/uts/common/sys/sunndi.h
index dede7d8f10..3d392fbd4f 100644
--- a/usr/src/uts/common/sys/sunndi.h
+++ b/usr/src/uts/common/sys/sunndi.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -268,6 +268,16 @@ ndi_devi_unconfig_one(dev_info_t *dip, char *devnm, dev_info_t **dipp,
int
ndi_devi_unconfig_driver(dev_info_t *dip, int flags, major_t major);
+void
+ndi_set_bus_private(dev_info_t *dip, boolean_t up, uint32_t port_type,
+ void *data);
+
+void *
+ndi_get_bus_private(dev_info_t *dip, boolean_t up);
+
+boolean_t
+ndi_port_type(dev_info_t *dip, boolean_t up, uint32_t port_type);
+
/*
* Take a device node "Offline".
*
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index 2bad82b0af..4ee16c525d 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -20,7 +20,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -162,7 +162,7 @@ DBOOT_OBJS += \
GFX_PRIVATE_OBJS += gfx_private.o gfxp_pci.o gfxp_segmap.o \
gfxp_devmap.o gfxp_vgatext.o gfxp_vm.o vgasubr.o
ISANEXUS_OBJS += isa.o dma_engine.o i8237A.o
-PCI_E_MISC_OBJS += pcie_error.o
+PCI_E_MISC_OBJS += pcie.o pcie_fault.o
PCI_E_NEXUS_OBJS += npe.o npe_misc.o
PCI_E_NEXUS_OBJS += pci_common.o pci_kstats.o pci_tools.o
PCINEXUS_OBJS += pci.o pci_common.o pci_kstats.o pci_tools.o
diff --git a/usr/src/uts/i86pc/io/pci/pci.c b/usr/src/uts/i86pc/io/pci/pci.c
index 7cd0b38d4e..4c34aa4db2 100644
--- a/usr/src/uts/i86pc/io/pci/pci.c
+++ b/usr/src/uts/i86pc/io/pci/pci.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -102,6 +102,7 @@ static int pci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
static int pci_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
caddr_t, int *);
static int pci_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static void pci_peekpoke_cb(dev_info_t *, ddi_fm_error_t *);
struct cb_ops pci_cb_ops = {
pci_open, /* open */
@@ -594,7 +595,7 @@ pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip));
return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
pci_common_peekpoke, &pcip->pci_err_mutex,
- &pcip->pci_peek_poke_mutex));
+ &pcip->pci_peek_poke_mutex, pci_peekpoke_cb));
/* for now only X86 systems support PME wakeup from suspended state */
case DDI_CTLOPS_ATTACH:
@@ -792,6 +793,10 @@ pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
return (pcihp_info(dip, cmd, arg, result));
}
+void pci_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
+ (void) pci_ereport_post(dip, derr, NULL);
+}
+
/*ARGSUSED*/
static int
pci_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
diff --git a/usr/src/uts/i86pc/io/pciex/npe.c b/usr/src/uts/i86pc/io/pciex/npe.c
index fde4276cc7..3ca09deb31 100644
--- a/usr/src/uts/i86pc/io/pciex/npe.c
+++ b/usr/src/uts/i86pc/io/pciex/npe.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,8 +32,8 @@
#include <sys/conf.h>
#include <sys/modctl.h>
-#include <sys/pcie.h>
#include <sys/pci_impl.h>
+#include <sys/pcie_impl.h>
#include <sys/sysmacros.h>
#include <sys/ddi_intr.h>
#include <sys/sunndi.h>
@@ -42,9 +42,9 @@
#include <sys/ndifm.h>
#include <sys/fm/util.h>
#include <sys/hotplug/pci/pcihp.h>
-#include <io/pci/pci_common.h>
#include <io/pci/pci_tools_ext.h>
-#include <io/pciex/pcie_error.h>
+#include <io/pci/pci_common.h>
+#include <io/pciex/pcie_nvidia.h>
/*
* Bus Operation functions
@@ -60,6 +60,16 @@ static int npe_fm_init(dev_info_t *, dev_info_t *, int,
static int npe_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *);
+/*
+ * Disable URs and Received MA for all PCIe devices. Until x86 SW is changed so
+ * that random drivers do not do PIO accesses on devices that it does not own,
+ * these error bits must be disabled. SERR must also be disabled if URs have
+ * been masked.
+ */
+uint32_t npe_aer_uce_mask = PCIE_AER_UCE_UR;
+uint32_t npe_aer_ce_mask = 0;
+uint32_t npe_aer_suce_mask = PCIE_AER_SUCE_RCVD_MA;
+
struct bus_ops npe_bus_ops = {
BUSO_REV,
npe_bus_map,
@@ -158,6 +168,7 @@ static int npe_initchild(dev_info_t *child);
extern void npe_query_acpi_mcfg(dev_info_t *dip);
extern void npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
extern int npe_disable_empty_bridges_workaround(dev_info_t *child);
+extern void npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl);
/*
* Module linkage information for the kernel.
@@ -177,7 +188,6 @@ static struct modlinkage modlinkage = {
/* Save minimal state. */
void *npe_statep;
-
int
_init(void)
{
@@ -244,6 +254,8 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
pcip->pci_dip = devi;
+ pcie_rc_init_bus(devi);
+
/*
* Initialize hotplug support on this bus. At minimum
* (for non hotplug bus) this would create ":devctl" minor
@@ -262,12 +274,17 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
ddi_soft_state_free(npe_statep, instance);
return (DDI_FAILURE);
}
+
pcip->pci_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc);
- if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
+ if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) {
ddi_fm_handler_register(devi, npe_fm_callback, NULL);
+ }
+
+ PCIE_DIP2PFD(devi) = kmem_zalloc(sizeof (pf_data_t), KM_SLEEP);
+ pcie_rc_init_pfd(devi, PCIE_DIP2PFD(devi));
npe_query_acpi_mcfg(devi);
ddi_report_dev(devi);
@@ -275,7 +292,6 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
}
-
/*ARGSUSED*/
static int
npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
@@ -299,6 +315,10 @@ npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
ddi_fm_handler_unregister(devi);
+ pcie_rc_fini_bus(devi);
+ pcie_rc_fini_pfd(PCIE_DIP2PFD(devi));
+ kmem_free(PCIE_DIP2PFD(devi), sizeof (pf_data_t));
+
ddi_fm_fini(devi);
ddi_soft_state_free(npe_statep, instance);
return (DDI_SUCCESS);
@@ -610,7 +630,10 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
int totreg;
uint_t reglen;
pci_regspec_t *drv_regp;
- struct attachspec *asp;
+ struct attachspec *asp;
+ struct detachspec *dsp;
+ pci_state_t *pci_p = ddi_get_soft_state(npe_statep,
+ ddi_get_instance(dip));
switch (ctlop) {
case DDI_CTLOPS_REPORTDEV:
@@ -677,7 +700,15 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
/* X86 systems support PME wakeup from suspended state */
case DDI_CTLOPS_ATTACH:
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
asp = (struct attachspec *)arg;
+ if ((asp->when == DDI_POST) && (asp->result == DDI_SUCCESS)) {
+ pf_init(rdip, (void *)pci_p->pci_fm_ibc, asp->cmd);
+ (void) pcie_postattach_child(rdip);
+ }
+
/* only do this for immediate children */
if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE &&
ddi_get_parent(rdip) == dip)
@@ -688,16 +719,25 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
(void *) dip);
/* NOTREACHED */
}
- return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
+ return (DDI_SUCCESS);
case DDI_CTLOPS_DETACH:
- asp = (struct attachspec *)arg;
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
+ dsp = (struct detachspec *)arg;
+
+ if (dsp->when == DDI_PRE)
+ pf_fini(rdip, dsp->cmd);
+
/* only do this for immediate children */
- if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST &&
+ if (dsp->cmd == DDI_SUSPEND && dsp->when == DDI_POST &&
ddi_get_parent(rdip) == dip)
if (pci_post_suspend(rdip) != DDI_SUCCESS)
return (DDI_FAILURE);
- return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
+ return (DDI_SUCCESS);
default:
break;
@@ -722,7 +762,9 @@ npe_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
static int
npe_initchild(dev_info_t *child)
{
- char name[80];
+ char name[80];
+ pcie_bus_t *bus_p;
+ uint32_t regs;
ddi_acc_handle_t cfg_hdl;
/*
@@ -797,15 +839,55 @@ npe_initchild(dev_info_t *child)
else
ddi_set_parent_data(child, NULL);
+ /* Disable certain errors on PCIe drivers for x86 platforms */
+ regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask;
+ pcie_set_aer_uce_mask(regs);
+ regs = pcie_get_aer_ce_mask() | npe_aer_ce_mask;
+ pcie_set_aer_ce_mask(regs);
+ regs = pcie_get_aer_suce_mask() | npe_aer_suce_mask;
+ pcie_set_aer_suce_mask(regs);
+
/*
- * Enable AER next pointer being displayed and PCIe Error initilization
+ * If URs are disabled, mask SERRs as well, otherwise the system will
+ * still be notified of URs
*/
+ if (npe_aer_uce_mask & PCIE_AER_UCE_UR)
+ pcie_set_serr_mask(1);
+
if (pci_config_setup(child, &cfg_hdl) == DDI_SUCCESS) {
npe_ck804_fix_aer_ptr(cfg_hdl);
- (void) pcie_error_enable(child, cfg_hdl);
+ npe_nvidia_error_mask(cfg_hdl);
pci_config_teardown(&cfg_hdl);
}
+ bus_p = pcie_init_bus(child);
+ if (bus_p) {
+ uint16_t device_id = (uint16_t)(bus_p->bus_dev_ven_id >> 16);
+ uint16_t vendor_id = (uint16_t)(bus_p->bus_dev_ven_id & 0xFFFF);
+ uint16_t rev_id = bus_p->bus_rev_id;
+
+ /* Disable AER for certain NVIDIA Chipsets */
+ if ((vendor_id == NVIDIA_VENDOR_ID) &&
+ (device_id == NVIDIA_CK804_DEVICE_ID) &&
+ (rev_id < NVIDIA_CK804_AER_VALID_REVID))
+ bus_p->bus_aer_off = 0;
+
+ (void) pcie_initchild(child);
+
+ /* If device is an NVIDIA RC do device specific error setup */
+ if ((vendor_id == NVIDIA_VENDOR_ID) &&
+ NVIDIA_PCIE_RC_DEV_ID(device_id)) {
+ ddi_acc_handle_t cfg_hdl = bus_p->bus_cfg_hdl;
+ uint16_t rc_ctl;
+
+ rc_ctl = pci_config_get16(cfg_hdl, NVIDIA_INTR_BCR_OFF +
+ 0x2);
+ pci_config_put16(cfg_hdl, NVIDIA_INTR_BCR_OFF + 0x2,
+ rc_ctl | NVIDIA_INTR_BCR_SERR_FORWARD_BIT);
+ }
+
+ }
+
return (DDI_SUCCESS);
}
@@ -813,22 +895,8 @@ npe_initchild(dev_info_t *child)
static int
npe_removechild(dev_info_t *dip)
{
- ddi_acc_handle_t cfg_hdl;
- struct ddi_parent_private_data *pdptr;
+ pcie_uninitchild(dip);
- /*
- * Do it way early.
- * Otherwise ddi_map() call form pcie_error_fini crashes
- */
- if (pci_config_setup(dip, &cfg_hdl) == DDI_SUCCESS) {
- pcie_error_disable(dip, cfg_hdl);
- pci_config_teardown(&cfg_hdl);
- }
-
- if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
- kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
- ddi_set_parent_data(dip, NULL);
- }
ddi_set_name_addr(dip, NULL);
/*
@@ -872,6 +940,7 @@ npe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
return (ENXIO);
dip = pci_p->pci_dip;
+
return (pci_common_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
}
@@ -907,5 +976,13 @@ npe_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
static int
npe_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
{
- return (ndi_fm_handler_dispatch(dip, NULL, derr));
+ /*
+ * On current x86 systems, npe's callback does not get called for failed
+ * loads. If in the future this feature is used, the fault PA should be
+ * logged in the derr->fme_bus_specific field. The appropriate PCIe
+ * error handling code should be called and needs to be coordinated with
+ * safe access handling.
+ */
+
+ return (DDI_FM_OK);
}
diff --git a/usr/src/uts/i86pc/io/pciex/npe_misc.c b/usr/src/uts/i86pc/io/pciex/npe_misc.c
index 892bfbb09e..24e6096f7d 100644
--- a/usr/src/uts/i86pc/io/pciex/npe_misc.c
+++ b/usr/src/uts/i86pc/io/pciex/npe_misc.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,6 +36,8 @@
#include <sys/acpi/acpi.h>
#include <sys/acpi/acpi_pci.h>
#include <sys/acpica.h>
+#include <sys/pci_cap.h>
+#include <sys/pcie_impl.h>
#include <io/pciex/pcie_nvidia.h>
/*
@@ -44,12 +46,16 @@
void npe_query_acpi_mcfg(dev_info_t *dip);
void npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
int npe_disable_empty_bridges_workaround(dev_info_t *child);
+void npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl);
/*
* Default ecfga base address
*/
int64_t npe_default_ecfga_base = 0xE0000000;
+extern uint32_t npe_aer_uce_mask;
+extern boolean_t pcie_full_scan;
+
/*
* Query the MCFG table using ACPI. If MCFG is found, setup the
* 'ecfga-base-address' (Enhanced Configuration Access base address)
@@ -118,7 +124,6 @@ npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
}
}
-
/*
* If the bridge is empty, disable it
*/
@@ -137,3 +142,23 @@ npe_disable_empty_bridges_workaround(dev_info_t *child)
return (0);
}
+
+void
+npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl) {
+ uint32_t regs;
+ uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
+ uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
+
+ if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
+ /* Disable ECRC for all devices */
+ regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
+ PCIE_AER_UCE_ECRC;
+ pcie_set_aer_uce_mask(regs);
+
+ /*
+ * Turn full scan on since the Error Source ID register may not
+ * have the correct ID.
+ */
+ pcie_full_scan = B_TRUE;
+ }
+}
diff --git a/usr/src/uts/i86pc/os/ddi_impl.c b/usr/src/uts/i86pc/os/ddi_impl.c
index e001a30f78..9a6fbc4689 100644
--- a/usr/src/uts/i86pc/os/ddi_impl.c
+++ b/usr/src/uts/i86pc/os/ddi_impl.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2319,7 +2319,8 @@ peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args)
* calling pci_ereport_post() on all puts and for any gets that return -1
*/
static int
-pci_peekpoke_check_fma(dev_info_t *dip, void *arg, ddi_ctl_enum_t ctlop)
+pci_peekpoke_check_fma(dev_info_t *dip, void *arg, ddi_ctl_enum_t ctlop,
+ void (*scan)(dev_info_t *, ddi_fm_error_t *))
{
int rval = DDI_SUCCESS;
peekpoke_ctlops_t *in_args = (peekpoke_ctlops_t *)arg;
@@ -2389,7 +2390,7 @@ pci_peekpoke_check_fma(dev_info_t *dip, void *arg, ddi_ctl_enum_t ctlop)
*/
de.fme_flag = DDI_FM_ERR_UNEXPECTED;
}
- pci_ereport_post(dip, &de, NULL);
+ (void) scan(dip, &de);
if (hdlp->ah_acc.devacc_attr_access != DDI_DEFAULT_ACC &&
de.fme_status != DDI_FM_OK) {
ndi_err_t *errp = (ndi_err_t *)hp->ahi_err;
@@ -2453,7 +2454,8 @@ int
pci_peekpoke_check(dev_info_t *dip, dev_info_t *rdip,
ddi_ctl_enum_t ctlop, void *arg, void *result,
int (*handler)(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
- void *), kmutex_t *err_mutexp, kmutex_t *peek_poke_mutexp)
+ void *), kmutex_t *err_mutexp, kmutex_t *peek_poke_mutexp,
+ void (*scan)(dev_info_t *, ddi_fm_error_t *))
{
int rval;
peekpoke_ctlops_t *in_args = (peekpoke_ctlops_t *)arg;
@@ -2494,7 +2496,7 @@ pci_peekpoke_check(dev_info_t *dip, dev_info_t *rdip,
rval = handler(dip, rdip, ctlop, arg, result);
if (rval == DDI_SUCCESS) {
mutex_enter(err_mutexp);
- rval = pci_peekpoke_check_fma(dip, arg, ctlop);
+ rval = pci_peekpoke_check_fma(dip, arg, ctlop, scan);
mutex_exit(err_mutexp);
}
mutex_exit(peek_poke_mutexp);
diff --git a/usr/src/uts/i86xpv/Makefile.files b/usr/src/uts/i86xpv/Makefile.files
index 927414c3e8..541dac2efa 100644
--- a/usr/src/uts/i86xpv/Makefile.files
+++ b/usr/src/uts/i86xpv/Makefile.files
@@ -20,7 +20,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -185,7 +185,7 @@ BALLOON_OBJS += balloon_drv.o
EVTCHN_OBJS += evtchn_dev.o
GFX_PRIVATE_OBJS += gfx_private.o gfxp_pci.o gfxp_segmap.o \
gfxp_devmap.o gfxp_vgatext.o gfxp_vm.o vgasubr.o
-PCI_E_MISC_OBJS += pcie_error.o
+PCI_E_MISC_OBJS += pcie.o pcie_fault.o
PCI_E_NEXUS_OBJS += npe.o npe_misc.o
PCI_E_NEXUS_OBJS += pci_common.o pci_kstats.o pci_tools.o
PCINEXUS_OBJS += pci.o pci_common.o pci_kstats.o pci_tools.o
diff --git a/usr/src/uts/intel/io/pci/pci_pci.c b/usr/src/uts/intel/io/pci/pci_pci.c
index 753c04d8f8..48e49703b4 100644
--- a/usr/src/uts/intel/io/pci/pci_pci.c
+++ b/usr/src/uts/intel/io/pci/pci_pci.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,6 +36,7 @@
#include <sys/autoconf.h>
#include <sys/ddi_impldefs.h>
#include <sys/pci.h>
+#include <sys/pcie_impl.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/sunndi.h>
@@ -135,6 +136,7 @@ static int ppb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
static int ppb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
caddr_t, int *);
static int ppb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static void ppb_peekpoke_cb(dev_info_t *, ddi_fm_error_t *);
struct cb_ops ppb_cb_ops = {
ppb_open, /* open */
@@ -216,6 +218,8 @@ typedef struct {
uchar_t sec_latency_timer;
ushort_t bridge_control;
} config_state[PCI_MAX_CHILDREN];
+
+ uint8_t parent_bus;
} ppb_devstate_t;
@@ -276,9 +280,12 @@ ppb_probe(dev_info_t *devi)
static int
ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
+ dev_info_t *root = ddi_root_node();
int instance;
ppb_devstate_t *ppb;
+ dev_info_t *pdip;
ddi_acc_handle_t config_handle;
+ char *bus;
switch (cmd) {
case DDI_ATTACH:
@@ -332,6 +339,22 @@ ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
return (DDI_FAILURE);
}
+ ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_DEV;
+ for (pdip = ddi_get_parent(devi); pdip && (pdip != root) &&
+ (ppb->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV);
+ pdip = ddi_get_parent(pdip)) {
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
+ DDI_PROP_DONTPASS, "device_type", &bus) !=
+ DDI_PROP_SUCCESS)
+ break;
+
+ if (strcmp(bus, "pciex") == 0)
+ ppb->parent_bus =
+ PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;
+
+ ddi_prop_free(bus);
+ }
+
if (ppb_support_ht_msimap == 1)
(void) ppb_ht_msimap_set(config_handle,
HT_MSIMAP_ENABLE);
@@ -432,7 +455,9 @@ ppb_ctlops(dev_info_t *dip, dev_info_t *rdip,
int reglen;
int rn;
int totreg;
- ppb_devstate_t *ppb;
+ ppb_devstate_t *ppb = ddi_get_soft_state(ppb_state,
+ ddi_get_instance(dip));
+ struct detachspec *dsp;
struct attachspec *asp;
switch (ctlop) {
@@ -463,28 +488,42 @@ ppb_ctlops(dev_info_t *dip, dev_info_t *rdip,
/* X86 systems support PME wakeup from suspend */
case DDI_CTLOPS_ATTACH:
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
asp = (struct attachspec *)arg;
+ if ((ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
+ (asp->when == DDI_POST) && (asp->result == DDI_SUCCESS))
+ pf_init(rdip, (void *)ppb->ppb_fm_ibc, asp->cmd);
+
if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE)
if (pci_pre_resume(rdip) != DDI_SUCCESS)
return (DDI_FAILURE);
- return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+ return (DDI_SUCCESS);
case DDI_CTLOPS_DETACH:
- asp = (struct attachspec *)arg;
- if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST)
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
+ dsp = (struct detachspec *)arg;
+ if ((ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
+ (dsp->when == DDI_PRE))
+ pf_fini(rdip, dsp->cmd);
+
+ if (dsp->cmd == DDI_SUSPEND && dsp->when == DDI_POST)
if (pci_post_suspend(rdip) != DDI_SUCCESS)
return (DDI_FAILURE);
- return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
+ return (DDI_SUCCESS);
case DDI_CTLOPS_PEEK:
case DDI_CTLOPS_POKE:
- ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(dip));
if (strcmp(ddi_driver_name(ddi_get_parent(dip)), "npe") != 0)
return (ddi_ctlops(dip, rdip, ctlop, arg, result));
return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
ddi_ctlops, &ppb->ppb_err_mutex,
- &ppb->ppb_peek_poke_mutex));
+ &ppb->ppb_peek_poke_mutex, ppb_peekpoke_cb));
default:
return (ddi_ctlops(dip, rdip, ctlop, arg, result));
@@ -566,10 +605,14 @@ static int
ppb_initchild(dev_info_t *child)
{
struct ddi_parent_private_data *pdptr;
+ ppb_devstate_t *ppb;
char name[MAXNAMELEN];
ddi_acc_handle_t config_handle;
ushort_t command_preserve, command;
+ ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
+ ddi_get_instance(ddi_get_parent(child)));
+
if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
return (DDI_FAILURE);
ddi_set_name_addr(child, name);
@@ -613,6 +656,20 @@ ppb_initchild(dev_info_t *child)
return (DDI_NOT_WELL_FORMED);
}
+ ddi_set_parent_data(child, NULL);
+
+ /*
+ * PCIe FMA specific
+ *
+ * Note: parent_data for parent is created only if this is PCI-E
+ * platform, for which, SG take a different route to handle device
+ * errors.
+ */
+ if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
+ if (pcie_init_bus(child) == NULL)
+ return (DDI_FAILURE);
+ }
+
/* transfer select properties from PROM to kernel */
if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
"interrupts", -1) != -1) {
@@ -645,8 +702,14 @@ static void
ppb_removechild(dev_info_t *dip)
{
struct ddi_parent_private_data *pdptr;
+ ppb_devstate_t *ppb;
+
+ ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
+ ddi_get_instance(ddi_get_parent(dip)));
- if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
+ if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
+ pcie_fini_bus(dip);
+ else if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
ddi_set_parent_data(dip, NULL);
}
@@ -905,6 +968,10 @@ ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
return (pcihp_info(dip, cmd, arg, result));
}
+void ppb_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
+ (void) pci_ereport_post(dip, derr, NULL);
+}
+
/*ARGSUSED*/
static int
ppb_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
diff --git a/usr/src/uts/intel/io/pciex/pcie_pci.c b/usr/src/uts/intel/io/pciex/pcie_pci.c
index cf73c743be..8f0b5f451f 100644
--- a/usr/src/uts/intel/io/pciex/pcie_pci.c
+++ b/usr/src/uts/intel/io/pciex/pcie_pci.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -48,11 +48,10 @@
#include <sys/pcie_impl.h>
#include <sys/hotplug/pci/pcihp.h>
#include <sys/hotplug/pci/pciehpc.h>
-#include <io/pciex/pcie_error.h>
#include <io/pciex/pcie_nvidia.h>
#include <io/pciex/pcie_nb5000.h>
-#ifdef DEBUG
+#ifdef DEBUG
static int pepb_debug = 0;
#define PEPB_DEBUG(args) if (pepb_debug) cmn_err args
#else
@@ -69,8 +68,6 @@ static int pepb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
static int pepb_fm_init(dev_info_t *, dev_info_t *, int,
ddi_iblock_cookie_t *);
-static int pepb_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *);
-
struct bus_ops pepb_bus_ops = {
BUSO_REV,
pepb_bus_map,
@@ -113,6 +110,7 @@ static int pepb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
static int pepb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
caddr_t, int *);
static int pepb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static void pepb_peekpoke_cb(dev_info_t *, ddi_fm_error_t *);
struct cb_ops pepb_cb_ops = {
pepb_open, /* open */
@@ -176,7 +174,7 @@ static struct modlinkage modlinkage = {
static void *pepb_state;
typedef struct {
- dev_info_t *dip;
+ dev_info_t *dip;
/*
* cpr support:
@@ -223,13 +221,13 @@ typedef struct {
#define PEPB_SOFT_STATE_INIT_MUTEX 0x20 /* mutex initialized */
/* default interrupt priority for all interrupts (hotplug or non-hotplug */
-#define PEPB_INTR_PRI 1
+#define PEPB_INTR_PRI 1
/* flag to turn on MSI support */
static int pepb_enable_msi = 1;
-/* panic on unknown flag, defaulted to on */
-int pepb_panic_unknown = 1;
-int pepb_panic_fatal = 1;
+
+/* panic on PF_PANIC flag */
+static int pepb_die = PF_ERR_FATAL_FLAGS;
extern errorq_t *pci_target_queue;
@@ -242,12 +240,11 @@ static void pepb_save_config_regs(pepb_devstate_t *pepb_p);
static void pepb_restore_config_regs(pepb_devstate_t *pepb_p);
static int pepb_pcie_device_type(dev_info_t *dip, int *port_type);
static int pepb_pcie_port_type(dev_info_t *dip,
- ddi_acc_handle_t config_handle);
-
+ ddi_acc_handle_t config_handle);
/* interrupt related declarations */
-static uint_t pepb_intx_intr(caddr_t arg, caddr_t arg2);
-static uint_t pepb_pwr_msi_intr(caddr_t arg, caddr_t arg2);
-static uint_t pepb_err_msi_intr(caddr_t arg, caddr_t arg2);
+static uint_t pepb_intx_intr(caddr_t arg, caddr_t arg2);
+static uint_t pepb_pwr_msi_intr(caddr_t arg, caddr_t arg2);
+static uint_t pepb_err_msi_intr(caddr_t arg, caddr_t arg2);
static int pepb_intr_on_root_port(dev_info_t *);
static int pepb_intr_init(pepb_devstate_t *pepb_p, int intr_type);
static void pepb_intr_fini(pepb_devstate_t *pepb_p);
@@ -333,15 +330,16 @@ pepb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
instance = ddi_get_instance(devi);
if (ddi_soft_state_zalloc(pepb_state, instance) != DDI_SUCCESS)
return (DDI_FAILURE);
+
pepb = ddi_get_soft_state(pepb_state, instance);
pepb->dip = devi;
/*
- * initalise fma support before we start accessing config space
+ * initialize fma support before we start accessing config space
*/
pci_targetq_init();
- pepb->pepb_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
- DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
+ pepb->pepb_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
+ DDI_FM_DMACHK_CAPABLE;
ddi_fm_init(devi, &pepb->pepb_fmcap, &pepb->pepb_fm_ibc);
mutex_init(&pepb->pepb_err_mutex, NULL, MUTEX_DRIVER,
@@ -349,12 +347,6 @@ pepb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
mutex_init(&pepb->pepb_peek_poke_mutex, NULL, MUTEX_DRIVER,
(void *)pepb->pepb_fm_ibc);
- if (pepb->pepb_fmcap & (DDI_FM_ERRCB_CAPABLE|DDI_FM_EREPORT_CAPABLE))
- pci_ereport_setup(devi);
-
- if (pepb->pepb_fmcap & DDI_FM_ERRCB_CAPABLE)
- ddi_fm_handler_register(devi, pepb_fm_callback, NULL);
-
/*
* Make sure the "device_type" property exists.
*/
@@ -468,11 +460,6 @@ pepb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
* Uninitialize hotplug support on this bus.
*/
(void) pcihp_uninit(devi);
- if (pepb->pepb_fmcap & DDI_FM_ERRCB_CAPABLE)
- ddi_fm_handler_unregister(devi);
-
- if (pepb->pepb_fmcap & (DDI_FM_ERRCB_CAPABLE|DDI_FM_EREPORT_CAPABLE))
- pci_ereport_teardown(devi);
mutex_destroy(&pepb->pepb_err_mutex);
mutex_destroy(&pepb->pepb_peek_poke_mutex);
@@ -505,7 +492,10 @@ pepb_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
int reglen;
int rn;
int totreg;
- pepb_devstate_t *pepb;
+ pepb_devstate_t *pepb = ddi_get_soft_state(pepb_state,
+ ddi_get_instance(dip));
+ struct detachspec *ds;
+ struct attachspec *as;
switch (ctlop) {
case DDI_CTLOPS_REPORTDEV:
@@ -535,13 +525,32 @@ pepb_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
case DDI_CTLOPS_PEEK:
case DDI_CTLOPS_POKE:
- pepb = ddi_get_soft_state(pepb_state, ddi_get_instance(dip));
if (pepb->port_type != PCIE_PCIECAP_DEV_TYPE_ROOT)
return (ddi_ctlops(dip, rdip, ctlop, arg, result));
return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
ddi_ctlops, &pepb->pepb_err_mutex,
- &pepb->pepb_peek_poke_mutex));
+ &pepb->pepb_peek_poke_mutex,
+ pepb_peekpoke_cb));
+ case DDI_CTLOPS_ATTACH:
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
+ as = (struct attachspec *)arg;
+ if ((as->when == DDI_POST) && (as->result == DDI_SUCCESS)) {
+ pf_init(rdip, (void *)pepb->pepb_fm_ibc, as->cmd);
+ (void) pcie_postattach_child(rdip);
+ }
+
+ return (DDI_SUCCESS);
+ case DDI_CTLOPS_DETACH:
+ if (!pcie_is_child(dip, rdip))
+ return (DDI_SUCCESS);
+
+ ds = (struct detachspec *)arg;
+ if (ds->when == DDI_PRE)
+ pf_fini(rdip, ds->cmd);
+ return (DDI_SUCCESS);
default:
return (ddi_ctlops(dip, rdip, ctlop, arg, result));
}
@@ -622,7 +631,7 @@ static int
pepb_initchild(dev_info_t *child)
{
struct ddi_parent_private_data *pdptr;
- ddi_acc_handle_t cfg_hdl;
+ struct pcie_bus *bus_p;
char name[MAXNAMELEN];
if (pepb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
@@ -678,10 +687,9 @@ pepb_initchild(dev_info_t *child)
} else
ddi_set_parent_data(child, NULL);
- if (pci_config_setup(child, &cfg_hdl) == DDI_SUCCESS) {
- (void) pcie_error_enable(child, cfg_hdl);
- pci_config_teardown(&cfg_hdl);
- }
+ bus_p = pcie_init_bus(child);
+ if (!bus_p || pcie_initchild(child) != DDI_SUCCESS)
+ return (DDI_FAILURE);
return (DDI_SUCCESS);
}
@@ -689,22 +697,15 @@ pepb_initchild(dev_info_t *child)
static void
pepb_uninitchild(dev_info_t *dip)
{
- ddi_acc_handle_t cfg_hdl;
struct ddi_parent_private_data *pdptr;
- /*
- * Do it way early.
- * Otherwise ddi_map() call form pcie_error_fini crashes
- */
- if (pci_config_setup(dip, &cfg_hdl) == DDI_SUCCESS) {
- pcie_error_disable(dip, cfg_hdl);
- pci_config_teardown(&cfg_hdl);
- }
+ pcie_uninitchild(dip);
if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
ddi_set_parent_data(dip, NULL);
}
+
ddi_set_name_addr(dip, NULL);
/*
@@ -975,7 +976,6 @@ pepb_intr_init(pepb_devstate_t *pepb_p, int intr_type)
pepb_p->intr_type = intr_type;
return (DDI_SUCCESS);
-
fail:
pepb_intr_fini(pepb_p);
@@ -1132,24 +1132,13 @@ pepb_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
}
/*ARGSUSED*/
-int
-pepb_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
-{
- pepb_devstate_t *pepb_p = (pepb_devstate_t *)
- ddi_get_soft_state(pepb_state, ddi_get_instance(dip));
-
- mutex_enter(&pepb_p->pepb_err_mutex);
- pci_ereport_post(dip, derr, NULL);
- mutex_exit(&pepb_p->pepb_err_mutex);
- return (derr->fme_status);
-}
-
-/*ARGSUSED*/
static uint_t
pepb_err_msi_intr(caddr_t arg, caddr_t arg2)
{
pepb_devstate_t *pepb_p = (pepb_devstate_t *)arg;
- ddi_fm_error_t derr;
+ dev_info_t *dip = pepb_p->dip;
+ ddi_fm_error_t derr;
+ int sts;
bzero(&derr, sizeof (ddi_fm_error_t));
derr.fme_version = DDI_FME_VERSION;
@@ -1162,19 +1151,16 @@ pepb_err_msi_intr(caddr_t arg, caddr_t arg2)
PEPB_DEBUG((CE_NOTE, "pepb_err_msi_intr: received intr number %d\n",
(int)(uintptr_t)arg2));
- /* if HPC is initialized then call the interrupt handler */
if (pepb_p->pepb_fmcap & DDI_FM_EREPORT_CAPABLE)
- pci_ereport_post(pepb_p->dip, &derr, NULL);
-
- if ((pepb_panic_fatal && derr.fme_status == DDI_FM_FATAL) ||
- (pepb_panic_unknown && derr.fme_status == DDI_FM_UNKNOWN))
- fm_panic("%s-%d: PCI(-X) Express Fatal Error",
- ddi_driver_name(pepb_p->dip),
- ddi_get_instance(pepb_p->dip));
+ sts = pf_scan_fabric(dip, &derr, NULL);
mutex_exit(&pepb_p->pepb_err_mutex);
mutex_exit(&pepb_p->pepb_peek_poke_mutex);
+ if (pepb_die & sts)
+ fm_panic("%s-%d: PCI(-X) Express Fatal Error",
+ ddi_driver_name(dip), ddi_get_instance(dip));
+
return (DDI_INTR_CLAIMED);
}
@@ -1234,3 +1220,8 @@ pepb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
{
return (pcihp_info(dip, cmd, arg, result));
}
+
+void
+pepb_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
+ (void) pf_scan_fabric(dip, derr, NULL);
+}
diff --git a/usr/src/uts/intel/pci_pci/Makefile b/usr/src/uts/intel/pci_pci/Makefile
index b278711141..e8f47ecbc1 100644
--- a/usr/src/uts/intel/pci_pci/Makefile
+++ b/usr/src/uts/intel/pci_pci/Makefile
@@ -21,7 +21,7 @@
#
# uts/intel/pci_pci/Makefile
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -59,7 +59,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
# depends on misc/pcihp
#
-LDFLAGS += -dy -Nmisc/pcihp
+LDFLAGS += -dy -Nmisc/pcihp -Nmisc/pcie
#
# Override defaults to build a unique, local modstubs.o.
diff --git a/usr/src/uts/sun4/io/pcicfg.e.c b/usr/src/uts/sun4/io/pcicfg.e.c
index 8575829b7a..5d7e161af2 100644
--- a/usr/src/uts/sun4/io/pcicfg.e.c
+++ b/usr/src/uts/sun4/io/pcicfg.e.c
@@ -3634,7 +3634,7 @@ pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
/* restore original settings */
if (regs->pcie_dev) {
- pcie_clear_errors(dip, h);
+ pcie_clear_errors(dip);
pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
regs->devctl);
}
diff --git a/usr/src/uts/sun4/io/px/pcie_pwr.c b/usr/src/uts/sun4/io/px/pcie_pwr.c
index 0b8e47b150..fe96966b3a 100644
--- a/usr/src/uts/sun4/io/px/pcie_pwr.c
+++ b/usr/src/uts/sun4/io/px/pcie_pwr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -103,7 +103,7 @@ static void pcie_add_comps(dev_info_t *dip, dev_info_t *cdip,
static void pcie_remove_comps(dev_info_t *dip, dev_info_t *cdip,
pcie_pwr_t *pwr_p);
static void pcie_pm_subrelease(dev_info_t *dip, pcie_pwr_t *pwr_p);
-static boolean_t pcie_is_pcie(ddi_acc_handle_t config_handle);
+static boolean_t pcie_is_pcie(dev_info_t *dip);
#ifdef DEBUG
static char *pcie_decode_pwr_op(pm_bus_power_op_t op);
#else
@@ -528,7 +528,7 @@ pcie_add_comps(dev_info_t *dip, dev_info_t *cdip, pcie_pwr_t *pwr_p)
PCIE_SET_PMINFO(cdip, pcie_pm_p);
}
cpwr_p = (pcie_pwr_child_t *)kmem_zalloc(sizeof (pcie_pwr_child_t),
- KM_SLEEP);
+ KM_SLEEP);
pcie_pm_p->pcie_par_pminfo = cpwr_p;
(cpwr_p->pwr_child_counters)[PCIE_UNKNOWN_INDEX] += comps;
}
@@ -631,7 +631,7 @@ pwr_common_teardown(dev_info_t *dip)
return;
(void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
- "pm-want-child-notification?");
+ "pm-want-child-notification?");
mutex_destroy(&pwr_p->pwr_lock);
pcie_pm_p->pcie_pwr_p = NULL;
kmem_free(pwr_p, sizeof (pcie_pwr_t));
@@ -794,8 +794,8 @@ pcie_pm_remove_child(dev_info_t *dip, dev_info_t *cdip)
return (DDI_SUCCESS);
}
total = (counters[PCIE_D0_INDEX] + counters[PCIE_UNKNOWN_INDEX] +
- counters[PCIE_D1_INDEX] + counters[PCIE_D2_INDEX] +
- counters[PCIE_D3_INDEX]);
+ counters[PCIE_D1_INDEX] + counters[PCIE_D2_INDEX] +
+ counters[PCIE_D3_INDEX]);
/*
* Mark idle if either there are no children or our lowest
* possible level is less than the current level. Mark idle
@@ -814,19 +814,11 @@ pcie_pm_remove_child(dev_info_t *dip, dev_info_t *cdip)
}
boolean_t
-pcie_is_pcie(ddi_acc_handle_t config_handle)
+pcie_is_pcie(dev_info_t *dip)
{
- uint8_t cap_ptr, cap_id;
-
- cap_ptr = pci_config_get8(config_handle, PCI_BCNF_CAP_PTR);
- while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
- cap_id = pci_config_get8(config_handle, cap_ptr + PCI_CAP_ID);
- if (cap_id == PCI_CAP_ID_PCI_E)
- return (B_TRUE);
- cap_ptr = pci_config_get8(config_handle,
- cap_ptr + PCI_CAP_NEXT_PTR);
- }
- return (B_FALSE);
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ ASSERT(bus_p);
+ return (bus_p->bus_pcie_off != 0);
}
/*
@@ -837,7 +829,6 @@ pcie_pwr_resume(dev_info_t *dip)
{
dev_info_t *cdip;
pcie_pwr_t *pwr_p = NULL;
- ddi_acc_handle_t config_handle;
if (PCIE_PMINFO(dip))
pwr_p = PCIE_NEXUS_PMINFO(dip);
@@ -884,25 +875,17 @@ pcie_pwr_resume(dev_info_t *dip)
"DDI_RESUME: nexus restoring %s%d config regs\n",
ddi_driver_name(cdip), ddi_get_instance(cdip));
- if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) {
- DBG(dip, "DDI_RESUME: "
- "pci_config_setup for %s%d failed\n",
- ddi_driver_name(cdip), ddi_get_instance(cdip));
- continue;
- }
-
/* clear errors left by OBP scrubbing */
- pcie_clear_errors(cdip, config_handle);
+ pcie_clear_errors(cdip);
/* PCIe workaround: disable errors during 4K config resore */
- if (is_pcie = pcie_is_pcie(config_handle))
- pcie_disable_errors(cdip, config_handle);
+ if (is_pcie = pcie_is_pcie(cdip))
+ pcie_disable_errors(cdip);
(void) pci_restore_config_regs(cdip);
if (is_pcie) {
- pcie_enable_errors(cdip, config_handle);
- (void) pcie_enable_ce(cdip, config_handle);
+ pcie_enable_errors(cdip);
+ (void) pcie_enable_ce(cdip);
}
- pci_config_teardown(&config_handle);
if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
"nexus-saved-config-regs") != DDI_PROP_SUCCESS) {
@@ -921,7 +904,6 @@ int
pcie_pwr_suspend(dev_info_t *dip)
{
dev_info_t *cdip;
- ddi_acc_handle_t config_handle;
int i, *counters; /* per nexus counters */
int *child_counters = NULL; /* per child dip counters */
pcie_pwr_t *pwr_p = NULL;
@@ -1020,21 +1002,13 @@ pcie_pwr_suspend(dev_info_t *dip)
" %s%d\n", ddi_driver_name(cdip), ddi_get_instance(cdip));
/* PCIe workaround: disable errors during 4K config save */
- if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) {
- DBG(dip, "DDI_SUSPEND: pci_config_setup "
- "for %s%d failed\n",
- ddi_driver_name(cdip), ddi_get_instance(cdip));
- continue;
- }
-
- if (is_pcie = pcie_is_pcie(config_handle))
- pcie_disable_errors(cdip, config_handle);
+ if (is_pcie = pcie_is_pcie(cdip))
+ pcie_disable_errors(cdip);
(void) pci_save_config_regs(cdip);
if (is_pcie) {
- pcie_enable_errors(cdip, config_handle);
- (void) pcie_enable_ce(cdip, config_handle);
+ pcie_enable_errors(cdip);
+ (void) pcie_enable_ce(cdip);
}
- pci_config_teardown(&config_handle);
}
return (DDI_SUCCESS);
}
diff --git a/usr/src/uts/sun4/io/px/px.c b/usr/src/uts/sun4/io/px/px.c
index 0f790b052e..707fecb753 100644
--- a/usr/src/uts/sun4/io/px/px.c
+++ b/usr/src/uts/sun4/io/px/px.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -245,7 +245,7 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
if (ddi_soft_state_zalloc(px_state_p, instance)
!= DDI_SUCCESS) {
cmn_err(CE_WARN, "%s%d: can't allocate px state",
- ddi_driver_name(dip), instance);
+ ddi_driver_name(dip), instance);
goto err_bad_px_softstate;
}
px_p = INST_TO_STATE(instance);
@@ -255,7 +255,7 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
px_p->px_open_count = 0;
(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
- "device_type", "pciex");
+ "device_type", "pciex");
/* Initialize px_dbg for high pil printing */
px_dbg_attach(dip, &px_p->px_dbg_hdl);
@@ -276,12 +276,6 @@ px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
/* Cache the BDF of the root port nexus */
px_p->px_bdf = px_lib_get_bdf(px_p);
- px_p->px_dq_p = (pf_data_t *)
- kmem_zalloc(sizeof (pf_data_t) * pf_get_dq_size(),
- KM_SLEEP);
-
- px_p->px_dq_tail = -1;
-
/*
* Initialize interrupt block. Note that this
* initialize error handling for the PEC as well.
@@ -482,9 +476,6 @@ px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
px_ib_detach(px_p);
(void) px_lib_dev_fini(dip);
- kmem_free(px_p->px_dq_p, sizeof (pf_data_t) *
- pf_get_dq_size());
-
/*
* Free the px soft state structure and the rest of the
* resources it's using.
@@ -494,7 +485,8 @@ px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
mutex_exit(&px_p->px_mutex);
mutex_destroy(&px_p->px_mutex);
- /* Free the interrupt-priorities prop if we created it. */ {
+ /* Free the interrupt-priorities prop if we created it. */
+ {
int len;
if (ddi_getproplen(DDI_DEV_T_ANY, dip,
@@ -683,7 +675,7 @@ px_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
pci_regspec_t reloc_reg, *rp = &reloc_reg;
DBG(DBG_MAP, dip, "rdip=%s%d:",
- ddi_driver_name(rdip), ddi_get_instance(rdip));
+ ddi_driver_name(rdip), ddi_get_instance(rdip));
if (mp->map_flags & DDI_MF_USER_MAPPING)
return (DDI_ME_UNIMPLEMENTED);
@@ -698,8 +690,8 @@ px_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
DBG(DBG_MAP | DBG_CONT, dip, " r#=%x", r_no);
if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
- "reg", (caddr_t)&rp, &reglen) != DDI_SUCCESS)
- return (DDI_ME_RNUMBER_RANGE);
+ "reg", (caddr_t)&rp, &reglen) != DDI_SUCCESS)
+ return (DDI_ME_RNUMBER_RANGE);
if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) {
kmem_free(rp, reglen);
@@ -721,8 +713,8 @@ px_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
* px_pci bridge nexus driver.
*/
if ((off >= PCIE_CONF_HDR_SIZE) ||
- (len > PCIE_CONF_HDR_SIZE) ||
- (off + len > PCIE_CONF_HDR_SIZE))
+ (len > PCIE_CONF_HDR_SIZE) ||
+ (off + len > PCIE_CONF_HDR_SIZE))
return (DDI_ME_INVAL);
/*
* the following function returning a DDI_FAILURE assumes
@@ -763,10 +755,8 @@ px_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
/*
* Set-up access functions for FM access error capable drivers.
*/
- if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
- mp->map_handlep->ah_acc.devacc_attr_access !=
- DDI_DEFAULT_ACC)
- px_fm_acc_setup(mp, rdip);
+ if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)))
+ px_fm_acc_setup(mp, rdip, rp);
}
done:
@@ -796,8 +786,8 @@ px_dma_setup(dev_info_t *dip, dev_info_t *rdip, ddi_dma_req_t *dmareq,
int ret;
DBG(DBG_DMA_MAP, dip, "mapping - rdip=%s%d type=%s\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip),
- handlep ? "alloc" : "advisory");
+ ddi_driver_name(rdip), ddi_get_instance(rdip),
+ handlep ? "alloc" : "advisory");
if (!(mp = px_dma_lmts2hdl(dip, rdip, mmu_p, dmareq)))
return (DDI_DMA_NORESOURCES);
@@ -831,8 +821,8 @@ px_dma_setup(dev_info_t *dip, dev_info_t *rdip, ddi_dma_req_t *dmareq,
case PX_DMAI_FLAGS_BYPASS:
default:
cmn_err(CE_PANIC, "%s%d: px_dma_setup: bad dma type 0x%x",
- ddi_driver_name(rdip), ddi_get_instance(rdip),
- PX_DMA_TYPE(mp));
+ ddi_driver_name(rdip), ddi_get_instance(rdip),
+ PX_DMA_TYPE(mp));
/*NOTREACHED*/
}
*handlep = (ddi_dma_handle_t)mp;
@@ -861,7 +851,7 @@ px_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp,
int rval;
DBG(DBG_DMA_ALLOCH, dip, "rdip=%s%d\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip));
+ ddi_driver_name(rdip), ddi_get_instance(rdip));
if (attrp->dma_attr_version != DMA_ATTR_V0)
return (DDI_DMA_BADATTR);
@@ -895,7 +885,7 @@ int
px_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
{
DBG(DBG_DMA_FREEH, dip, "rdip=%s%d mp=%p\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
+ ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
px_dma_freemp((ddi_dma_impl_t *)handle);
if (px_kmem_clid) {
@@ -920,7 +910,7 @@ px_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
int ret;
DBG(DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip), mp, dmareq);
+ ddi_driver_name(rdip), ddi_get_instance(rdip), mp, dmareq);
if (mp->dmai_flags & PX_DMAI_FLAGS_INUSE)
return (DDI_DMA_INUSE);
@@ -961,17 +951,17 @@ mapped:
break;
default:
cmn_err(CE_PANIC, "%s%d: px_dma_bindhdl(%p): bad dma type",
- ddi_driver_name(rdip), ddi_get_instance(rdip), mp);
+ ddi_driver_name(rdip), ddi_get_instance(rdip), mp);
/*NOTREACHED*/
}
DBG(DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x\n",
- cookiep->dmac_address, cookiep->dmac_size);
+ cookiep->dmac_address, cookiep->dmac_size);
px_dump_dma_handle(DBG_DMA_MAP, dip, mp);
/* insert dma handle into FMA cache */
if (mp->dmai_attr.dma_attr_flags & DDI_DMA_FLAGERR) {
(void) ndi_fmc_insert(rdip, DMA_HANDLE, mp, NULL);
- mp->dmai_error.err_cf = impl_dma_check;
+ mp->dmai_error.err_cf = px_err_dma_hdl_check;
}
return (mp->dmai_nwin == 1 ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP);
@@ -995,7 +985,7 @@ px_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
px_mmu_t *mmu_p = px_p->px_mmu_p;
DBG(DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
+ ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
if ((mp->dmai_flags & PX_DMAI_FLAGS_INUSE) == 0) {
DBG(DBG_DMA_UNBINDH, dip, "handle not inuse\n");
return (DDI_FAILURE);
@@ -1025,7 +1015,7 @@ px_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
break;
default:
cmn_err(CE_PANIC, "%s%d: px_dma_unbindhdl:bad dma type %p",
- ddi_driver_name(rdip), ddi_get_instance(rdip), mp);
+ ddi_driver_name(rdip), ddi_get_instance(rdip), mp);
/*NOTREACHED*/
}
if (mmu_p->mmu_dvma_clid != 0) {
@@ -1053,7 +1043,7 @@ px_dma_win(dev_info_t *dip, dev_info_t *rdip,
int ret;
DBG(DBG_DMA_WIN, dip, "rdip=%s%d\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip));
+ ddi_driver_name(rdip), ddi_get_instance(rdip));
px_dump_dma_handle(DBG_DMA_WIN, dip, mp);
if (win >= mp->dmai_nwin) {
@@ -1076,7 +1066,7 @@ px_dma_win(dev_info_t *dip, dev_info_t *rdip,
}
if (cookiep)
MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping,
- mp->dmai_size);
+ mp->dmai_size);
if (ccountp)
*ccountp = 1;
break;
@@ -1086,7 +1076,7 @@ px_dma_win(dev_info_t *dip, dev_info_t *rdip,
ddi_dma_cookie_t *ck_p;
px_dma_win_t *win_p = mp->dmai_winlst;
- for (i = 0; i < win; win_p = win_p->win_next, i++);
+ for (i = 0; i < win; win_p = win_p->win_next, i++) {};
ck_p = (ddi_dma_cookie_t *)(win_p + 1);
*cookiep = *ck_p;
mp->dmai_offset = win_p->win_offset;
@@ -1100,14 +1090,14 @@ px_dma_win(dev_info_t *dip, dev_info_t *rdip,
break;
default:
cmn_err(CE_WARN, "%s%d: px_dma_win:bad dma type 0x%x",
- ddi_driver_name(rdip), ddi_get_instance(rdip),
- PX_DMA_TYPE(mp));
+ ddi_driver_name(rdip), ddi_get_instance(rdip),
+ PX_DMA_TYPE(mp));
return (DDI_FAILURE);
}
if (cookiep)
DBG(DBG_DMA_WIN, dip,
- "cookie - dmac_address=%x dmac_size=%x\n",
- cookiep->dmac_address, cookiep->dmac_size);
+ "cookie - dmac_address=%x dmac_size=%x\n",
+ cookiep->dmac_address, cookiep->dmac_size);
if (offp)
*offp = (off_t)mp->dmai_offset;
if (lenp)
@@ -1153,7 +1143,7 @@ px_dma_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
#ifdef DEBUG
DBG(DBG_DMA_CTL, dip, "%s: rdip=%s%d\n", px_dmactl_str[cmd],
- ddi_driver_name(rdip), ddi_get_instance(rdip));
+ ddi_driver_name(rdip), ddi_get_instance(rdip));
#endif /* DEBUG */
switch (cmd) {
@@ -1164,7 +1154,7 @@ px_dma_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
case DDI_DMA_RESERVE: {
px_t *px_p = DIP_TO_STATE(dip);
return (px_fdvma_reserve(dip, rdip, px_p,
- (ddi_dma_req_t *)offp, (ddi_dma_handle_t *)objp));
+ (ddi_dma_req_t *)offp, (ddi_dma_handle_t *)objp));
}
case DDI_DMA_RELEASE: {
px_t *px_p = DIP_TO_STATE(dip);
@@ -1177,15 +1167,15 @@ px_dma_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
switch (PX_DMA_TYPE(mp)) {
case PX_DMAI_FLAGS_DVMA:
return (px_dvma_ctl(dip, rdip, mp, cmd, offp, lenp, objp,
- cache_flags));
+ cache_flags));
case PX_DMAI_FLAGS_PTP:
case PX_DMAI_FLAGS_BYPASS:
return (px_dma_ctl(dip, rdip, mp, cmd, offp, lenp, objp,
- cache_flags));
+ cache_flags));
default:
cmn_err(CE_PANIC, "%s%d: px_dma_ctlops(%x):bad dma type %x",
- ddi_driver_name(rdip), ddi_get_instance(rdip), cmd,
- mp->dmai_flags);
+ ddi_driver_name(rdip), ddi_get_instance(rdip), cmd,
+ mp->dmai_flags);
/*NOTREACHED*/
}
return (0);
@@ -1236,16 +1226,11 @@ px_ctlops(dev_info_t *dip, dev_info_t *rdip,
return (pcie_pm_hold(dip));
}
if (as->cmd == DDI_RESUME) {
- ddi_acc_handle_t config_handle;
DBG(DBG_PWR, dip, "PRE_RESUME for %s@%d\n",
ddi_driver_name(rdip),
ddi_get_instance(rdip));
- if (pci_config_setup(rdip, &config_handle) ==
- DDI_SUCCESS) {
- pcie_clear_errors(rdip, config_handle);
- pci_config_teardown(&config_handle);
- }
+ pcie_clear_errors(rdip);
}
return (DDI_SUCCESS);
@@ -1324,7 +1309,7 @@ px_ctlops(dev_info_t *dip, dev_info_t *rdip,
* Now pass the request up to our parent.
*/
DBG(DBG_CTLOPS, dip, "passing request to parent: rdip=%s%d\n",
- ddi_driver_name(rdip), ddi_get_instance(rdip));
+ ddi_driver_name(rdip), ddi_get_instance(rdip));
return (ddi_ctlops(dip, rdip, op, arg, result));
}
diff --git a/usr/src/uts/sun4/io/px/px_fm.c b/usr/src/uts/sun4/io/px/px_fm.c
index 727d0351a6..65c1d78d29 100644
--- a/usr/src/uts/sun4/io/px/px_fm.c
+++ b/usr/src/uts/sun4/io/px/px_fm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,6 +33,7 @@
#include <sys/sunddi.h>
#include <sys/fm/protocol.h>
#include <sys/fm/util.h>
+#include <sys/fm/io/pci.h>
#include <sys/membar.h>
#include "px_obj.h"
@@ -43,26 +44,35 @@
(PCIE_AER_UCE_TRAINING | PCIE_AER_UCE_SD | PCIE_AER_UCE_CA | \
PCIE_AER_UCE_UC | PCIE_AER_UCE_UR)
-static void px_err_fill_pfd(dev_info_t *rpdip, px_err_pcie_t *regs);
+/*
+ * Global panicing state variabled used to control if further error handling
+ * should occur. If the system is already panic'ing or if PX itself has
+ * recommended panic'ing the system, no further error handling should occur to
+ * prevent the system from hanging.
+ */
+boolean_t px_panicing = B_FALSE;
+
+static pf_data_t *px_get_pfd(px_t *px_p);
+
static int px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr,
px_err_pcie_t *regs);
#if defined(DEBUG)
-static void px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs, int severity);
+static void px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs);
#else /* DEBUG */
#define px_pcie_log 0 &&
#endif /* DEBUG */
-/* external functions */
-extern int pci_xcap_locate(ddi_acc_handle_t h, uint16_t id, uint16_t *base_p);
-extern int pci_lcap_locate(ddi_acc_handle_t h, uint8_t id, uint16_t *base_p);
-
/*
* Initialize px FMA support
*/
int
px_fm_attach(px_t *px_p)
{
+ int i;
+ dev_info_t *dip = px_p->px_dip;
+ pcie_bus_t *bus_p;
+
px_p->px_fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
@@ -75,7 +85,7 @@ px_fm_attach(px_t *px_p)
/*
* check parents' capability
*/
- ddi_fm_init(px_p->px_dip, &px_p->px_fm_cap, &px_p->px_fm_ibc);
+ ddi_fm_init(dip, &px_p->px_fm_cap, &px_p->px_fm_ibc);
/*
* parents need to be ereport and error handling capable
@@ -89,10 +99,22 @@ px_fm_attach(px_t *px_p)
mutex_init(&px_p->px_fm_mutex, NULL, MUTEX_DRIVER,
(void *)px_p->px_fm_ibc);
+
+ pcie_rc_init_bus(dip);
+
+ px_p->px_pfd_idx = 0;
+ for (i = 0; i < 5; i++)
+ pcie_rc_init_pfd(dip, &px_p->px_pfd_arr[i]);
+ PCIE_DIP2PFD(dip) = px_p->px_pfd_arr;
+
+ bus_p = PCIE_DIP2BUS(dip);
+ bus_p->bus_rp_bdf = px_p->px_bdf;
+ bus_p->bus_rp_dip = dip;
+
/*
* register error callback in parent
*/
- ddi_fm_handler_register(px_p->px_dip, px_fm_callback, px_p);
+ ddi_fm_handler_register(dip, px_fm_callback, px_p);
return (DDI_SUCCESS);
}
@@ -103,9 +125,14 @@ px_fm_attach(px_t *px_p)
void
px_fm_detach(px_t *px_p)
{
+ int i;
+
ddi_fm_handler_unregister(px_p->px_dip);
mutex_destroy(&px_p->px_fm_mutex);
ddi_fm_fini(px_p->px_dip);
+ for (i = 0; i < 5; i++)
+ pcie_rc_fini_pfd(&px_p->px_pfd_arr[i]);
+ pcie_rc_fini_bus(px_p->px_dip);
}
/*
@@ -113,9 +140,10 @@ px_fm_detach(px_t *px_p)
* protection.
*/
void
-px_fm_acc_setup(ddi_map_req_t *mp, dev_info_t *rdip)
+px_fm_acc_setup(ddi_map_req_t *mp, dev_info_t *rdip, pci_regspec_t *rp)
{
uchar_t fflag;
+ ndi_err_t *errp;
ddi_acc_hdl_t *hp;
ddi_acc_impl_t *ap;
@@ -143,6 +171,13 @@ px_fm_acc_setup(ddi_map_req_t *mp, dev_info_t *rdip)
ap->ahi_rep_put16 = i_ddi_prot_rep_put16;
ap->ahi_rep_put32 = i_ddi_prot_rep_put32;
ap->ahi_rep_put64 = i_ddi_prot_rep_put64;
+ impl_acc_err_init(hp);
+ errp = ((ddi_acc_impl_t *)hp)->ahi_err;
+ if ((rp->pci_phys_hi & PCI_REG_ADDR_M) ==
+ PCI_ADDR_CONFIG)
+ errp->err_cf = px_err_cfg_hdl_check;
+ else
+ errp->err_cf = px_err_pio_hdl_check;
break;
case DDI_CAUTIOUS_ACC :
ap->ahi_get8 = i_ddi_caut_get8;
@@ -161,6 +196,13 @@ px_fm_acc_setup(ddi_map_req_t *mp, dev_info_t *rdip)
ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
+ impl_acc_err_init(hp);
+ errp = ((ddi_acc_impl_t *)hp)->ahi_err;
+ if ((rp->pci_phys_hi & PCI_REG_ADDR_M) ==
+ PCI_ADDR_CONFIG)
+ errp->err_cf = px_err_cfg_hdl_check;
+ else
+ errp->err_cf = px_err_pio_hdl_check;
break;
default:
break;
@@ -221,6 +263,24 @@ px_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle)
mutex_exit(&pec_p->pec_pokefault_mutex);
}
+static uint64_t
+px_in_addr_range(dev_info_t *dip, px_ranges_t *ranges_p, uint64_t addr)
+{
+ uint64_t addr_low, addr_high;
+
+ addr_low = ((uint64_t)ranges_p->parent_high << 32) |
+ (uint64_t)ranges_p->parent_low;
+ addr_high = addr_low + ((uint64_t)ranges_p->size_high << 32) +
+ (uint64_t)ranges_p->size_low;
+
+ DBG(DBG_ERR_INTR, dip, "Addr: 0x%llx high: 0x%llx low: 0x%llx\n",
+ addr, addr_high, addr_low);
+
+ if ((addr < addr_high) && (addr >= addr_low))
+ return (addr_low);
+
+ return (0);
+}
/*
* PCI error callback which is registered with our parent to call
@@ -234,8 +294,9 @@ px_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
dev_info_t *pdip = ddi_get_parent(dip);
px_t *px_p = (px_t *)impl_data;
int i, acc_type = 0;
- int lookup, rc_err, fab_err = PF_NO_PANIC;
- uint32_t addr, addr_high, addr_low;
+ int lookup, rc_err, fab_err;
+ uint64_t addr, base_addr;
+ uint64_t fault_addr = (uint64_t)derr->fme_bus_specific;
pcie_req_id_t bdf;
px_ranges_t *ranges_p;
int range_len;
@@ -250,11 +311,10 @@ px_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
return (DDI_FM_FATAL);
i_ddi_fm_handler_exit(pdip);
- mutex_enter(&px_p->px_fm_mutex);
- px_p->px_fm_mutex_owner = curthread;
-
- addr_high = (uint32_t)((uint64_t)derr->fme_bus_specific >> 32);
- addr_low = (uint32_t)((uint64_t)derr->fme_bus_specific);
+ if (px_fm_enter(px_p) != DDI_SUCCESS) {
+ i_ddi_fm_handler_enter(pdip);
+ return (DDI_FM_FATAL);
+ }
/*
* Make sure this failed load came from this PCIe port. Check by
@@ -263,21 +323,20 @@ px_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
range_len = px_p->px_ranges_length / sizeof (px_ranges_t);
i = 0;
for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
- if (ranges_p->parent_high == addr_high) {
+ base_addr = px_in_addr_range(dip, ranges_p, fault_addr);
+ if (base_addr) {
switch (ranges_p->child_high & PCI_ADDR_MASK) {
case PCI_ADDR_CONFIG:
- acc_type = PF_CFG_ADDR;
+ acc_type = PF_ADDR_CFG;
addr = NULL;
- bdf = (pcie_req_id_t)(addr_low >> 12);
+ bdf = (pcie_req_id_t)((fault_addr >> 12) &
+ 0xFFFF);
break;
case PCI_ADDR_IO:
- acc_type = PF_IO_ADDR;
- addr = addr_low;
- bdf = NULL;
- break;
+ case PCI_ADDR_MEM64:
case PCI_ADDR_MEM32:
- acc_type = PF_DMA_ADDR;
- addr = addr_low;
+ acc_type = PF_ADDR_PIO;
+ addr = fault_addr - base_addr;
bdf = NULL;
break;
}
@@ -287,39 +346,31 @@ px_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
/* This address doesn't belong to this leaf, just return with OK */
if (!acc_type) {
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
+ px_fm_exit(px_p);
i_ddi_fm_handler_enter(pdip);
return (DDI_FM_OK);
- } else if (acc_type == PF_IO_ADDR) {
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
- i_ddi_fm_handler_enter(pdip);
- return (DDI_FM_FATAL);
}
rc_err = px_err_cmn_intr(px_p, derr, PX_TRAP_CALL, PX_FM_BLOCK_ALL);
- lookup = pf_hdl_lookup(dip, derr->fme_ena, acc_type, addr, bdf);
+ lookup = pf_hdl_lookup(dip, derr->fme_ena, acc_type, (uint64_t)addr,
+ bdf);
- if (!px_lib_is_in_drain_state(px_p)) {
- /*
- * This is to ensure that device corresponding to the addr of
- * the failed PIO/CFG load gets scanned.
- */
- px_rp_en_q(px_p, bdf, addr,
- (PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB));
- fab_err = pf_scan_fabric(dip, derr, px_p->px_dq_p,
- &px_p->px_dq_tail);
- }
+ px_rp_en_q(px_p, bdf, addr,
+ (PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB));
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
+ fab_err = px_scan_fabric(px_p, dip, derr);
+
+ px_fm_exit(px_p);
i_ddi_fm_handler_enter(pdip);
- if ((rc_err & (PX_PANIC | PX_PROTECTED)) || (fab_err & PF_PANIC) ||
+ if (!px_die)
+ return (DDI_FM_OK);
+
+ if ((rc_err & (PX_PANIC | PX_PROTECTED)) ||
+ (fab_err & PF_ERR_FATAL_FLAGS) ||
(lookup == PF_HDL_NOTFOUND))
return (DDI_FM_FATAL);
- else if ((rc_err == PX_NO_ERROR) && (fab_err == PF_NO_ERROR))
+ else if ((rc_err == PX_NO_ERROR) && (fab_err == PF_ERR_NO_ERROR))
return (DDI_FM_OK);
return (DDI_FM_NONFATAL);
@@ -341,11 +392,13 @@ uint_t
px_err_fabric_intr(px_t *px_p, msgcode_t msg_code, pcie_req_id_t rid)
{
dev_info_t *rpdip = px_p->px_dip;
- int rc_err, fab_err = PF_NO_PANIC;
+ int rc_err, fab_err;
ddi_fm_error_t derr;
+ uint32_t rp_status;
+ uint16_t ce_source, ue_source;
- mutex_enter(&px_p->px_fm_mutex);
- px_p->px_fm_mutex_owner = curthread;
+ if (px_fm_enter(px_p) != DDI_SUCCESS)
+ goto done;
/* Create the derr */
bzero(&derr, sizeof (ddi_fm_error_t));
@@ -353,26 +406,72 @@ px_err_fabric_intr(px_t *px_p, msgcode_t msg_code, pcie_req_id_t rid)
derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
+ px_err_safeacc_check(px_p, &derr);
+
+ if (msg_code == PCIE_MSG_CODE_ERR_COR) {
+ rp_status = PCIE_AER_RE_STS_CE_RCVD;
+ ce_source = rid;
+ ue_source = 0;
+ } else {
+ rp_status = PCIE_AER_RE_STS_FE_NFE_RCVD;
+ ce_source = 0;
+ ue_source = rid;
+ if (msg_code == PCIE_MSG_CODE_ERR_NONFATAL)
+ rp_status |= PCIE_AER_RE_STS_NFE_MSGS_RCVD;
+ else {
+ rp_status |= PCIE_AER_RE_STS_FE_MSGS_RCVD;
+ rp_status |= PCIE_AER_RE_STS_FIRST_UC_FATAL;
+ }
+ }
+
+ if (derr.fme_flag == DDI_FM_ERR_UNEXPECTED) {
+ ddi_fm_ereport_post(rpdip, PCI_ERROR_SUBCLASS "." PCIEX_FABRIC,
+ derr.fme_ena,
+ DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
+ FIRE_PRIMARY, DATA_TYPE_BOOLEAN_VALUE, B_TRUE,
+ "pcie_adv_rp_status", DATA_TYPE_UINT32, rp_status,
+ "pcie_adv_rp_command", DATA_TYPE_UINT32, 0,
+ "pcie_adv_rp_ce_src_id", DATA_TYPE_UINT16, ce_source,
+ "pcie_adv_rp_ue_src_id", DATA_TYPE_UINT16, ue_source,
+ NULL);
+ }
+
/* Ensure that the rid of the fabric message will get scanned. */
px_rp_en_q(px_p, rid, NULL, NULL);
rc_err = px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_PCIE);
/* call rootport dispatch */
- if (!px_lib_is_in_drain_state(px_p)) {
- fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p,
- &px_p->px_dq_tail);
- }
-
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
+ fab_err = px_scan_fabric(px_p, rpdip, &derr);
- px_err_panic(rc_err, PX_RC, fab_err);
+ px_err_panic(rc_err, PX_RC, fab_err, B_TRUE);
+ px_fm_exit(px_p);
+ px_err_panic(rc_err, PX_RC, fab_err, B_FALSE);
+done:
return (DDI_INTR_CLAIMED);
}
/*
+ * px_scan_fabric:
+ *
+ * Check for drain state and if there is anything to scan.
+ */
+int
+px_scan_fabric(px_t *px_p, dev_info_t *rpdip, ddi_fm_error_t *derr) {
+ int fab_err = 0;
+
+ ASSERT(MUTEX_HELD(&px_p->px_fm_mutex));
+
+ if (!px_lib_is_in_drain_state(px_p) && px_p->px_pfd_idx) {
+ fab_err = pf_scan_fabric(rpdip, derr, px_p->px_pfd_arr);
+ px_p->px_pfd_idx = 0;
+ }
+
+ return (fab_err);
+}
+
+/*
* px_err_safeacc_check:
* Check to see if a peek/poke and cautious access is currently being
* done on a particular leaf.
@@ -456,103 +555,79 @@ px_err_check_eq(dev_info_t *dip)
return (PX_NO_PANIC);
}
-static void
-px_err_fill_pfd(dev_info_t *rpdip, px_err_pcie_t *regs)
+/* ARGSUSED */
+int
+px_err_check_pcie(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs)
{
- px_t *px_p = DIP_TO_STATE(rpdip);
- pf_data_t pf_data = {0};
- pcie_req_id_t fault_bdf = 0;
- uint32_t fault_addr = 0;
- uint16_t s_status = 0;
-
- pf_data.rp_bdf = px_p->px_bdf;
+ px_t *px_p = DIP_TO_STATE(dip);
+ pf_data_t *pfd_p = px_get_pfd(px_p);
+ int i;
+ pf_pcie_adv_err_regs_t *adv_reg = PCIE_ADV_REG(pfd_p);
/*
* set RC s_status in PCI term to coordinate with downstream fabric
* errors ananlysis.
*/
if (regs->primary_ue & PCIE_AER_UCE_UR)
- s_status = PCI_STAT_R_MAST_AB;
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_R_MAST_AB;
if (regs->primary_ue & PCIE_AER_UCE_CA)
- s_status = PCI_STAT_R_TARG_AB;
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_R_TARG_AB;
if (regs->primary_ue & (PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC))
- s_status = PCI_STAT_PERROR;
-
- if (regs->primary_ue & (PCIE_AER_UCE_UR | PCIE_AER_UCE_CA)) {
- pf_data.aer_h0 = regs->rx_hdr1;
- pf_data.aer_h1 = regs->rx_hdr2;
- pf_data.aer_h2 = regs->rx_hdr3;
- pf_data.aer_h3 = regs->rx_hdr4;
-
- pf_tlp_decode(rpdip, &pf_data, &fault_bdf, NULL, NULL);
- } else if (regs->primary_ue & PCIE_AER_UCE_PTLP) {
- pcie_tlp_hdr_t *tlp_p;
-
- pf_data.aer_h0 = regs->rx_hdr1;
- pf_data.aer_h1 = regs->rx_hdr2;
- pf_data.aer_h2 = regs->rx_hdr3;
- pf_data.aer_h3 = regs->rx_hdr4;
-
- tlp_p = (pcie_tlp_hdr_t *)&pf_data.aer_h0;
- if (tlp_p->type == PCIE_TLP_TYPE_CPL)
- pf_tlp_decode(rpdip, &pf_data, &fault_bdf, NULL, NULL);
-
- pf_data.aer_h0 = regs->tx_hdr1;
- pf_data.aer_h1 = regs->tx_hdr2;
- pf_data.aer_h2 = regs->tx_hdr3;
- pf_data.aer_h3 = regs->tx_hdr4;
-
- pf_tlp_decode(rpdip, &pf_data, NULL, &fault_addr, NULL);
- }
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_PERROR;
- px_rp_en_q(px_p, fault_bdf, fault_addr, s_status);
-}
-
-int
-px_err_check_pcie(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs)
-{
- uint32_t ce_reg, ue_reg;
- int err = PX_NO_ERROR;
-
- ce_reg = regs->ce_reg;
- if (ce_reg)
- err |= (ce_reg & px_fabric_die_rc_ce) ? PX_PANIC : PX_NO_ERROR;
-
- ue_reg = regs->ue_reg;
- if (!ue_reg)
+ if (!regs->primary_ue)
goto done;
- if (ue_reg & PCIE_AER_UCE_PTLP)
- err |= px_pcie_ptlp(dip, derr, regs);
+ adv_reg->pcie_ce_status = regs->ce_reg;
+ adv_reg->pcie_ue_status = regs->ue_reg | regs->primary_ue;
+ PCIE_ADV_HDR(pfd_p, 0) = regs->rx_hdr1;
+ PCIE_ADV_HDR(pfd_p, 1) = regs->rx_hdr2;
+ PCIE_ADV_HDR(pfd_p, 2) = regs->rx_hdr3;
+ PCIE_ADV_HDR(pfd_p, 3) = regs->rx_hdr4;
+ for (i = regs->primary_ue; i != 1; i = i >> 1)
+ adv_reg->pcie_adv_ctl++;
- if (ue_reg & PX_PCIE_PANIC_BITS)
- err |= PX_PANIC;
+ if (regs->primary_ue & (PCIE_AER_UCE_UR | PCIE_AER_UCE_CA)) {
+ if (pf_tlp_decode(PCIE_DIP2BUS(dip), adv_reg) == DDI_SUCCESS)
+ PCIE_ROOT_FAULT(pfd_p)->fault_bdf =
+ adv_reg->pcie_ue_tgt_bdf;
+ } else if (regs->primary_ue & PCIE_AER_UCE_PTLP) {
+ if (pf_tlp_decode(PCIE_DIP2BUS(dip), adv_reg) == DDI_SUCCESS) {
+ PCIE_ROOT_FAULT(pfd_p)->fault_bdf =
+ adv_reg->pcie_ue_tgt_bdf;
+ if (adv_reg->pcie_ue_tgt_trans ==
+ PF_ADDR_PIO)
+ PCIE_ROOT_FAULT(pfd_p)->fault_addr =
+ adv_reg->pcie_ue_tgt_addr;
+ }
- if (ue_reg & PX_PCIE_NO_PANIC_BITS)
- err |= PX_NO_PANIC;
+ /*
+ * Normally for Poisoned Completion TLPs we can look at the
+ * transmit log header for the original request and the original
+ * address, however this doesn't seem to be working. HW BUG.
+ */
+ }
- /* Scan the fabric to clean up error bits, for the following errors. */
- if (ue_reg & (PCIE_AER_UCE_PTLP | PCIE_AER_UCE_CA | PCIE_AER_UCE_UR))
- px_err_fill_pfd(dip, regs);
done:
- px_pcie_log(dip, regs, err);
- return (err);
+ px_pcie_log(dip, regs);
+
+ /* Return No Error here and let the pcie misc module analyse it */
+ return (PX_NO_ERROR);
}
#if defined(DEBUG)
static void
-px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs, int severity)
+px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs)
{
DBG(DBG_ERR_INTR, dip,
- "A PCIe RC error has occured with a severity of \"%s\"\n"
+ "A PCIe RC error has occured\n"
"\tCE: 0x%x UE: 0x%x Primary UE: 0x%x\n"
"\tTX Hdr: 0x%x 0x%x 0x%x 0x%x\n\tRX Hdr: 0x%x 0x%x 0x%x 0x%x\n",
- (severity & PX_PANIC) ? "PANIC" : "NO PANIC", regs->ce_reg,
- regs->ue_reg, regs->primary_ue, regs->tx_hdr1, regs->tx_hdr2,
- regs->tx_hdr3, regs->tx_hdr4, regs->rx_hdr1, regs->rx_hdr2,
- regs->rx_hdr3, regs->rx_hdr4);
+ regs->ce_reg, regs->ue_reg, regs->primary_ue,
+ regs->tx_hdr1, regs->tx_hdr2, regs->tx_hdr3, regs->tx_hdr4,
+ regs->rx_hdr1, regs->rx_hdr2, regs->rx_hdr3, regs->rx_hdr4);
}
-#endif /* DEBUG */
+#endif
/*
* look through poisoned TLP cases and suggest panic/no panic depend on
@@ -561,12 +636,12 @@ px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs, int severity)
static int
px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs)
{
- px_t *px_p = DIP_TO_STATE(dip);
- pf_data_t pf_data;
+ pf_pcie_adv_err_regs_t adv_reg;
pcie_req_id_t bdf;
- uint32_t addr, trans_type;
+ uint64_t addr;
+ uint32_t trans_type;
int tlp_sts, tlp_cmd;
- int sts = PF_HDL_NOTFOUND;
+ int lookup = PF_HDL_NOTFOUND;
if (regs->primary_ue != PCIE_AER_UCE_PTLP)
return (PX_PANIC);
@@ -574,18 +649,21 @@ px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs)
if (!regs->rx_hdr1)
goto done;
- pf_data.rp_bdf = px_p->px_bdf;
- pf_data.aer_h0 = regs->rx_hdr1;
- pf_data.aer_h1 = regs->rx_hdr2;
- pf_data.aer_h2 = regs->rx_hdr3;
- pf_data.aer_h3 = regs->rx_hdr4;
+ adv_reg.pcie_ue_hdr[0] = regs->rx_hdr1;
+ adv_reg.pcie_ue_hdr[1] = regs->rx_hdr2;
+ adv_reg.pcie_ue_hdr[2] = regs->rx_hdr3;
+ adv_reg.pcie_ue_hdr[3] = regs->rx_hdr4;
- tlp_sts = pf_tlp_decode(dip, &pf_data, &bdf, &addr, &trans_type);
- tlp_cmd = ((pcie_tlp_hdr_t *)(&pf_data.aer_h0))->type;
+ tlp_sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
+ tlp_cmd = ((pcie_tlp_hdr_t *)(adv_reg.pcie_ue_hdr))->type;
if (tlp_sts == DDI_FAILURE)
goto done;
+ bdf = adv_reg.pcie_ue_tgt_bdf;
+ addr = adv_reg.pcie_ue_tgt_addr;
+ trans_type = adv_reg.pcie_ue_tgt_trans;
+
switch (tlp_cmd) {
case PCIE_TLP_TYPE_CPL:
case PCIE_TLP_TYPE_CPLLK:
@@ -594,24 +672,58 @@ px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs)
* from the RX TLP, and the original address from the TX TLP.
*/
if (regs->tx_hdr1) {
- pf_data.aer_h0 = regs->tx_hdr1;
- pf_data.aer_h1 = regs->tx_hdr2;
- pf_data.aer_h2 = regs->tx_hdr3;
- pf_data.aer_h3 = regs->tx_hdr4;
+ adv_reg.pcie_ue_hdr[0] = regs->tx_hdr1;
+ adv_reg.pcie_ue_hdr[1] = regs->tx_hdr2;
+ adv_reg.pcie_ue_hdr[2] = regs->tx_hdr3;
+ adv_reg.pcie_ue_hdr[3] = regs->tx_hdr4;
- sts = pf_tlp_decode(dip, &pf_data, NULL, &addr,
- &trans_type);
+ lookup = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
+ if (lookup != DDI_SUCCESS)
+ break;
+ addr = adv_reg.pcie_ue_tgt_addr;
+ trans_type = adv_reg.pcie_ue_tgt_trans;
} /* FALLTHRU */
case PCIE_TLP_TYPE_IO:
case PCIE_TLP_TYPE_MEM:
case PCIE_TLP_TYPE_MEMLK:
- sts = pf_hdl_lookup(dip, derr->fme_ena, trans_type, addr, bdf);
+ lookup = pf_hdl_lookup(dip, derr->fme_ena, trans_type, addr,
+ bdf);
break;
default:
- sts = PF_HDL_NOTFOUND;
+ lookup = PF_HDL_NOTFOUND;
}
done:
- return (sts == PF_HDL_NOTFOUND ? PX_PANIC : PX_NO_PANIC);
+ return (lookup == PF_HDL_FOUND ? PX_NO_PANIC : PX_PANIC);
+}
+
+/*
+ * px_get_pdf automatically allocates a RC pf_data_t and returns a pointer to
+ * it. This function should be used when an error requires a fabric scan.
+ */
+static pf_data_t *
+px_get_pfd(px_t *px_p) {
+ int idx = px_p->px_pfd_idx++;
+ pf_data_t *pfd_p = &px_p->px_pfd_arr[idx];
+
+ /* Clear Old Data */
+ PCIE_ROOT_FAULT(pfd_p)->fault_bdf = 0;
+ PCIE_ROOT_FAULT(pfd_p)->fault_addr = 0;
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = 0;
+ PCIE_ADV_REG(pfd_p)->pcie_ce_status = 0;
+ PCIE_ADV_REG(pfd_p)->pcie_ue_status = 0;
+
+ pfd_p->pe_next = NULL;
+
+ if (idx > 0) {
+ px_p->px_pfd_arr[idx - 1].pe_next = pfd_p;
+ pfd_p->pe_prev = &px_p->px_pfd_arr[idx - 1];
+ } else {
+ pfd_p->pe_prev = NULL;
+ }
+
+ pfd_p->pe_valid = B_TRUE;
+
+ return (pfd_p);
}
/*
@@ -627,47 +739,208 @@ done:
* (ie S-TA/MA, R-TA)
* Either the fault bdf or addr may be NULL, but not both.
*/
-int px_foo = 0;
void
px_rp_en_q(px_t *px_p, pcie_req_id_t fault_bdf, uint32_t fault_addr,
uint16_t s_status)
{
- pf_data_t pf_data = {0};
+ pf_data_t *pfd_p;
if (!fault_bdf && !fault_addr)
return;
- pf_data.dev_type = PCIE_PCIECAP_DEV_TYPE_ROOT;
- if (px_foo) {
- pf_data.fault_bdf = px_foo;
- px_foo = 0;
- } else
- pf_data.fault_bdf = fault_bdf;
+ pfd_p = px_get_pfd(px_p);
+
+ PCIE_ROOT_FAULT(pfd_p)->fault_bdf = fault_bdf;
+ PCIE_ROOT_FAULT(pfd_p)->fault_addr = (uint64_t)fault_addr;
+ PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
+}
+
+
+/*
+ * Find and Mark CFG Handles as failed associated with the given BDF. We should
+ * always know the BDF for CFG accesses, since it is encoded in the address of
+ * the TLP. Since there can be multiple cfg handles, mark them all as failed.
+ */
+/* ARGSUSED */
+int
+px_err_cfg_hdl_check(dev_info_t *dip, const void *handle, const void *arg1,
+ const void *arg2)
+{
+ int status = DDI_FM_FATAL;
+ uint32_t addr = *(uint32_t *)arg1;
+ uint16_t bdf = *(uint16_t *)arg2;
+ pcie_bus_t *bus_p;
+
+ DBG(DBG_ERR_INTR, dip, "Check CFG Hdl: dip 0x%p addr 0x%x bdf=0x%x\n",
+ dip, addr, bdf);
- pf_data.bdf = px_p->px_bdf;
- pf_data.rp_bdf = px_p->px_bdf;
- pf_data.fault_addr = fault_addr;
- pf_data.s_status = s_status;
- pf_data.send_erpt = PF_SEND_ERPT_NO;
+ bus_p = PCIE_DIP2BUS(dip);
- (void) pf_en_dq(&pf_data, px_p->px_dq_p, &px_p->px_dq_tail, -1);
+ /*
+ * Because CFG and IO Acc Handlers are on the same cache list and both
+ * types of hdls gets called for both types of errors. For this checker
+ * only mark the device as "Non-Fatal" if the addr == NULL and bdf !=
+ * NULL.
+ */
+ status = (!addr && (bus_p->bus_bdf == bdf)) ? DDI_FM_NONFATAL :
+ DDI_FM_FATAL;
+
+ return (status);
+}
+
+/*
+ * Find and Mark all ACC Handles associated with a give address and BDF as
+ * failed. If the BDF != NULL, then check to see if the device has a ACC Handle
+ * associated with ADDR. If the handle is not found, mark all the handles as
+ * failed. If the BDF == NULL, mark the handle as failed if it is associated
+ * with ADDR.
+ */
+int
+px_err_pio_hdl_check(dev_info_t *dip, const void *handle, const void *arg1,
+ const void *arg2)
+{
+ dev_info_t *px_dip = PCIE_DIP2BUS(dip)->bus_rp_dip;
+ px_t *px_p = INST_TO_STATE(ddi_get_instance(px_dip));
+ px_ranges_t *ranges_p;
+ int range_len;
+ ddi_acc_handle_t ap = (ddi_acc_handle_t)handle;
+ ddi_acc_hdl_t *hp = impl_acc_hdl_get(ap);
+ int i, status = DDI_FM_FATAL;
+ uint64_t fault_addr = *(uint64_t *)arg1;
+ uint16_t bdf = *(uint16_t *)arg2;
+ uint64_t base_addr, range_addr;
+ uint_t size;
+
+ DBG(DBG_ERR_INTR, dip, "Check PIO Hdl: dip 0x%x addr 0x%x bdf=0x%x\n",
+ dip, fault_addr, bdf);
+
+ /* Normalize the base addr to the addr and strip off the HB info. */
+ base_addr = (hp->ah_pfn << MMU_PAGESHIFT) + hp->ah_offset;
+ range_len = px_p->px_ranges_length / sizeof (px_ranges_t);
+ i = 0;
+ for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
+ range_addr = px_in_addr_range(dip, ranges_p, base_addr);
+ if (range_addr) {
+ switch (ranges_p->child_high & PCI_ADDR_MASK) {
+ case PCI_ADDR_IO:
+ case PCI_ADDR_MEM64:
+ case PCI_ADDR_MEM32:
+ base_addr = base_addr - range_addr;
+ break;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Mark the handle as failed if the ADDR is mapped, or if we
+ * know the BDF and ADDR == 0.
+ */
+ size = hp->ah_len;
+ if (((fault_addr >= base_addr) && (fault_addr < (base_addr + size))) ||
+ ((fault_addr == NULL) && (bdf == PCIE_DIP2BUS(dip)->bus_bdf)))
+ status = DDI_FM_NONFATAL;
+
+ return (status);
+}
+
+/*
+ * Find and Mark all DNA Handles associated with a give address and BDF as
+ * failed. If the BDF != NULL, then check to see if the device has a DMA Handle
+ * associated with ADDR. If the handle is not found, mark all the handles as
+ * failed. If the BDF == NULL, mark the handle as failed if it is associated
+ * with ADDR.
+ */
+int
+px_err_dma_hdl_check(dev_info_t *dip, const void *handle, const void *arg1,
+ const void *arg2)
+{
+ ddi_dma_impl_t *pcie_dp;
+ int status = DDI_FM_FATAL;
+ uint32_t addr = *(uint32_t *)arg1;
+ uint16_t bdf = *(uint16_t *)arg2;
+ uint32_t base_addr;
+ uint_t size;
+
+ DBG(DBG_ERR_INTR, dip, "Check PIO Hdl: dip 0x%x addr 0x%x bdf=0x%x\n",
+ dip, addr, bdf);
+
+ pcie_dp = (ddi_dma_impl_t *)handle;
+ base_addr = (uint32_t)pcie_dp->dmai_mapping;
+ size = pcie_dp->dmai_size;
+
+ /*
+ * Mark the handle as failed if the ADDR is mapped, or if we
+ * know the BDF and ADDR == 0.
+ */
+ if (((addr >= base_addr) && (addr < (base_addr + size))) ||
+ ((addr == NULL) && (bdf != NULL)))
+ status = DDI_FM_NONFATAL;
+
+ return (status);
+}
+
+int
+px_fm_enter(px_t *px_p) {
+ if (px_panicing || (px_p->px_fm_mutex_owner == curthread))
+ return (DDI_FAILURE);
+
+ mutex_enter(&px_p->px_fm_mutex);
+ /*
+ * In rare cases when trap occurs and in the middle of scanning the
+ * fabric, a PIO will fail in the scan fabric. The CPU error handling
+ * code will correctly panic the system, while a mondo for the failed
+ * PIO may also show up. Normally the mondo will try to grab the mutex
+ * and wait until the callback finishes. But in this rare case,
+ * mutex_enter actually suceeds also continues to scan the fabric.
+ *
+ * This code below is designed specifically to check for this case. If
+ * we successfully grab the px_fm_mutex, the px_fm_mutex_owner better be
+ * NULL. If it isn't that means we are in the rare corner case. Return
+ * DDI_FAILURE, this should prevent PX from doing anymore error
+ * handling.
+ */
+ if (px_p->px_fm_mutex_owner) {
+ return (DDI_FAILURE);
+ }
+
+ px_p->px_fm_mutex_owner = curthread;
+
+ if (px_panicing) {
+ px_fm_exit(px_p);
+ return (DDI_FAILURE);
+ }
+ return (DDI_SUCCESS);
+}
+
+void
+px_fm_exit(px_t *px_p) {
+ px_p->px_fm_mutex_owner = NULL;
+ mutex_exit(&px_p->px_fm_mutex);
}
/*
* Panic if the err tunable is set and that we are not already in the middle
* of panic'ing.
+ *
+ * rc_err = Error severity of PX specific errors
+ * msg = Where the error was detected
+ * fabric_err = Error severity of PCIe Fabric errors
+ * isTest = Test if error severity causes panic
*/
#define MSZ (sizeof (fm_msg) -strlen(fm_msg) - 1)
void
-px_err_panic(int err, int msg, int fab_err)
+px_err_panic(int rc_err, int msg, int fabric_err, boolean_t isTest)
{
char fm_msg[96] = "";
int ferr = PX_NO_ERROR;
- if (panicstr)
+ if (panicstr) {
+ px_panicing = B_TRUE;
return;
+ }
- if (!(err & px_die))
+ if (!(rc_err & px_die))
goto fabric;
if (msg & PX_RC)
(void) strncat(fm_msg, px_panic_rc_msg, MSZ);
@@ -677,17 +950,22 @@ px_err_panic(int err, int msg, int fab_err)
(void) strncat(fm_msg, px_panic_hb_msg, MSZ);
fabric:
- if (fab_err & PF_PANIC)
+ if (fabric_err & PF_ERR_FATAL_FLAGS)
ferr = PX_PANIC;
- else if (fab_err & ~(PF_PANIC | PF_NO_ERROR))
+ else if (fabric_err & ~(PF_ERR_FATAL_FLAGS | PF_ERR_NO_ERROR))
ferr = PX_NO_PANIC;
if (ferr & px_die) {
- if (strlen(fm_msg))
+ if (strlen(fm_msg)) {
(void) strncat(fm_msg, " and", MSZ);
+ }
(void) strncat(fm_msg, px_panic_fab_msg, MSZ);
}
- if (strlen(fm_msg))
- fm_panic("Fatal error has occured in:%s.", fm_msg);
+ if (strlen(fm_msg)) {
+ px_panicing = B_TRUE;
+ if (!isTest)
+ fm_panic("Fatal error has occured in:%s.(0x%x)(0x%x)",
+ fm_msg, rc_err, fabric_err);
+ }
}
diff --git a/usr/src/uts/sun4/io/px/px_fm.h b/usr/src/uts/sun4/io/px/px_fm.h
index df98ee552a..e1b40d3582 100644
--- a/usr/src/uts/sun4/io/px/px_fm.h
+++ b/usr/src/uts/sun4/io/px/px_fm.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -103,7 +103,7 @@ extern int px_fm_attach(px_t *px_p);
extern void px_fm_detach(px_t *px_p);
extern int px_fm_init_child(dev_info_t *, dev_info_t *, int,
ddi_iblock_cookie_t *);
-extern void px_fm_acc_setup(ddi_map_req_t *, dev_info_t *);
+extern void px_fm_acc_setup(ddi_map_req_t *, dev_info_t *, pci_regspec_t *rp);
extern int px_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *);
extern int px_err_cmn_intr(px_t *, ddi_fm_error_t *, int, int);
@@ -118,14 +118,27 @@ extern uint_t px_err_fabric_intr(px_t *px_p, msgcode_t msg_code,
/*
* Common error handling functions
*/
+extern int px_scan_fabric(px_t *px_p, dev_info_t *rdip, ddi_fm_error_t *derr);
extern void px_err_safeacc_check(px_t *px_p, ddi_fm_error_t *derr);
extern int px_err_check_eq(dev_info_t *dip);
extern int px_err_check_pcie(dev_info_t *dip, ddi_fm_error_t *derr,
px_err_pcie_t *regs);
-extern void px_err_panic(int err, int msg, int fab_err);
+extern int px_fm_enter(px_t *px_p);
+extern void px_fm_exit(px_t *px_p);
+extern void px_err_panic(int err, int msg, int fab_err, boolean_t isTest);
extern void px_rp_en_q(px_t *px_p, pcie_req_id_t fault_bdf,
uint32_t fault_addr, uint16_t s_status);
+/*
+ * Sparc specific cfg, pio and dma handle lookup/check functions
+ */
+extern int px_err_cfg_hdl_check(dev_info_t *dip, const void *handle,
+ const void *addr, const void *not_used);
+extern int px_err_pio_hdl_check(dev_info_t *dip, const void *handle,
+ const void *addr, const void *not_used);
+extern int px_err_dma_hdl_check(dev_info_t *dip, const void *handle,
+ const void *addr, const void *not_used);
+
#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 b2af17fba6..286feee297 100644
--- a/usr/src/uts/sun4/io/px/px_pci.c
+++ b/usr/src/uts/sun4/io/px/px_pci.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -111,10 +111,7 @@ static int pxb_fm_init(pxb_devstate_t *pxb_p);
static void pxb_fm_fini(pxb_devstate_t *pxb_p);
static int pxb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
ddi_iblock_cookie_t *ibc_p);
-static int pxb_fm_err_callback(dev_info_t *dip, ddi_fm_error_t *derr,
- const void *impl_data);
-static int pxb_pcie_device_type(pxb_devstate_t *pxb_p);
static void pxb_set_pci_perf_parameters(dev_info_t *dip,
ddi_acc_handle_t config_handle);
#ifdef PRINT_PLX_SEEPROM_CRC
@@ -319,11 +316,12 @@ pxb_probe(register dev_info_t *devi)
static int
pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
+ pcie_bus_t *bus_p = PCIE_DIP2BUS(devi);
int instance;
pxb_devstate_t *pxb;
ddi_acc_handle_t config_handle;
char device_type[8];
- uint16_t cap_ptr;
+ uint8_t dev_type = bus_p->bus_dev_type;
#ifdef PX_PLX
uint_t bus_num, primary, secondary;
#endif /* PX_PLX */
@@ -336,8 +334,7 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
/*
* Get the soft state structure for the bridge.
*/
- pxb = (pxb_devstate_t *)
- ddi_get_soft_state(pxb_state, instance);
+ pxb = (pxb_devstate_t *)ddi_get_soft_state(pxb_state, instance);
(void) pcie_pwr_resume(devi);
return (DDI_SUCCESS);
@@ -402,18 +399,7 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
goto fail;
}
- if ((PCI_CAP_LOCATE(pxb->pxb_config_handle, PCI_CAP_ID_PCI_E,
- &cap_ptr)) != DDI_FAILURE)
- pxb->pxb_port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
- PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
- else
- pxb->pxb_port_type = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;
-
- if ((pxb->pxb_port_type != PCIE_PCIECAP_DEV_TYPE_UP) &&
- (pxb->pxb_port_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
- (pxb->pxb_port_type != PCIE_PCIECAP_DEV_TYPE_ROOT) &&
- (pxb->pxb_port_type != PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
- (pxb->pxb_port_type != PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
+ if (!(PCIE_IS_BDG(bus_p))) {
DBG(DBG_ATTACH, devi, "This is not a switch or bridge\n");
goto fail;
}
@@ -421,10 +407,13 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
/*
* Make sure the "device_type" property exists.
*/
- if (pxb_pcie_device_type(pxb) == DDI_SUCCESS)
+ if ((bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
+ (bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (bus_p->bus_dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
(void) strcpy(device_type, "pciex");
else
(void) strcpy(device_type, "pci");
+
(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
"device_type", device_type);
@@ -444,7 +433,7 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
* PCI and PCI-X device driver's parent private data structure
* as part of their init child function.
*/
- if (pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
+ if (PCIE_IS_PCI_BDG(bus_p)) {
if (ndi_prop_update_int(DDI_DEV_T_NONE, pxb->pxb_dip,
"pcie2pci-sec-bus", pci_config_get8(config_handle,
PCI_BCNF_SECBUS)) != DDI_PROP_SUCCESS) {
@@ -498,10 +487,10 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
goto hotplug_done;
#endif /* PX_PLX */
- if ((pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
- (pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
- (pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
- (pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
+ if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
#ifdef PX_PLX
/*
* Workaround for a race condition between hotplug
@@ -692,22 +681,15 @@ pxb_ctlops(dev_info_t *dip, dev_info_t *rdip,
return (pcie_pm_hold(dip));
}
if (as->cmd == DDI_RESUME) {
- ddi_acc_handle_t config_handle;
DBG(DBG_PWR, dip, "PRE_RESUME for %s@%d\n",
ddi_driver_name(rdip),
ddi_get_instance(rdip));
-
- if (pci_config_setup(rdip, &config_handle) ==
- DDI_SUCCESS) {
- pcie_clear_errors(rdip, config_handle);
- pci_config_teardown(&config_handle);
- }
+ pcie_clear_errors(rdip);
}
return (DDI_SUCCESS);
case DDI_POST: {
- ddi_acc_handle_t config_handle;
DBG(DBG_PWR, dip, "POST_ATTACH for %s@%d\n",
ddi_driver_name(rdip), ddi_get_instance(rdip));
if (as->cmd == DDI_ATTACH && as->result != DDI_SUCCESS)
@@ -729,11 +711,7 @@ pxb_ctlops(dev_info_t *dip, dev_info_t *rdip,
return (DDI_SUCCESS);
}
- if (pci_config_setup(rdip, &config_handle) ==
- DDI_SUCCESS) {
- pcie_disable_errors(rdip, config_handle);
- pci_config_teardown(&config_handle);
- }
+ pcie_disable_errors(rdip);
return (DDI_SUCCESS);
}
@@ -1007,7 +985,7 @@ pxb_initchild(dev_info_t *child)
"INITCHILD: config regs setup for %s@%s\n",
ddi_node_name(child), ddi_get_name_addr(child));
- if (pcie_initchild(child) != DDI_SUCCESS) {
+ if (!pcie_init_bus(child) || pcie_initchild(child) != DDI_SUCCESS) {
result = DDI_FAILURE;
goto cleanup;
}
@@ -1038,7 +1016,7 @@ pxb_initchild(dev_info_t *child)
for (i = 0; i < pxb_tlp_count; i += 1)
reg |= pci_config_get16(config_handle, PCI_CONF_VENID);
- if (pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI)
+ if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(pxb->pxb_dip)))
pxb_set_pci_perf_parameters(child, config_handle);
pci_config_teardown(&config_handle);
@@ -1288,8 +1266,8 @@ pxb_intr(caddr_t arg1, caddr_t arg2)
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))
+ 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));
@@ -1321,14 +1299,15 @@ static int
pxb_init_hotplug(pxb_devstate_t *pxb)
{
int rv = DDI_FAILURE;
+ uint8_t dev_type = PCIE_DIP2BUS(pxb->pxb_dip)->bus_dev_type;
- if (((pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
- (pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
- (pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) &&
+ if (((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE) ||
+ (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT)) &&
(pxb_pciehpc_probe(pxb->pxb_dip,
pxb->pxb_config_handle) == DDI_SUCCESS)) {
pxb->pxb_hpc_type = HPC_PCIE;
- } else if ((pxb->pxb_port_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
+ } else if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
(pxb_pcishpc_probe(pxb->pxb_dip,
pxb->pxb_config_handle) == DDI_SUCCESS)) {
pxb->pxb_hpc_type = HPC_SHPC;
@@ -1393,8 +1372,7 @@ pxb_create_ranges_prop(dev_info_t *dip,
* Create ranges for IO space
*/
ranges[i].size_low = ranges[i].size_high = 0;
- ranges[i].parent_mid = ranges[i].child_mid =
- ranges[i].parent_high = 0;
+ ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
ranges[i].child_high = ranges[i].parent_high |=
(PCI_REG_REL_M | PCI_ADDR_IO);
base = PXB_16bit_IOADDR(io_base_lo);
@@ -1418,8 +1396,7 @@ pxb_create_ranges_prop(dev_info_t *dip,
base = PXB_32bit_MEMADDR(mem_base);
limit = PXB_32bit_MEMADDR(mem_limit);
ranges[i].size_low = ranges[i].size_high = 0;
- ranges[i].parent_mid = ranges[i].child_mid =
- ranges[i].parent_high = 0;
+ ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
ranges[i].child_high = ranges[i].parent_high |=
(PCI_REG_REL_M | PCI_ADDR_MEM32);
ranges[i].child_low = ranges[i].parent_low = base;
@@ -1663,8 +1640,8 @@ pxb_pwr_setup(dev_info_t *dip)
/*
* Walk the capabilities searching for a PM entry.
*/
- if ((PCI_CAP_LOCATE(conf_hdl, PCI_CAP_ID_PM, &cap_ptr))
- == DDI_FAILURE) {
+ if ((PCI_CAP_LOCATE(conf_hdl, PCI_CAP_ID_PM, &cap_ptr)) ==
+ DDI_FAILURE) {
DBG(DBG_PWR, dip, "switch/bridge does not support PM. PCI"
" PM data structure not found in config header\n");
pci_config_teardown(&conf_hdl);
@@ -1768,23 +1745,17 @@ static int
pxb_fm_init(pxb_devstate_t *pxb_p)
{
dev_info_t *dip = pxb_p->pxb_dip;
-
- pxb_p->pxb_fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
+ int fm_cap = DDI_FM_EREPORT_CAPABLE |
DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
/*
* Request our capability level and get our parents capability
* and ibc.
*/
- ddi_fm_init(dip, &pxb_p->pxb_fm_cap, &pxb_p->pxb_fm_ibc);
+ ddi_fm_init(dip, &fm_cap, &pxb_p->pxb_fm_ibc);
pci_ereport_setup(dip);
- /*
- * Register error callback with our parent.
- */
- ddi_fm_handler_register(pxb_p->pxb_dip, pxb_fm_err_callback,
- (void *)&pxb_p->pxb_config_handle);
return (DDI_SUCCESS);
}
@@ -1798,8 +1769,6 @@ pxb_fm_fini(pxb_devstate_t *pxb_p)
/*
* Clean up allocated fm structures
*/
- ddi_fm_handler_unregister(dip);
- pci_ereport_teardown(dip);
ddi_fm_fini(dip);
}
@@ -1815,19 +1784,7 @@ pxb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
pxb_devstate_t *pxb_p = (pxb_devstate_t *)
ddi_get_soft_state(pxb_state, ddi_get_instance(dip));
*ibc_p = pxb_p->pxb_fm_ibc;
- return (pxb_p->pxb_fm_cap | DDI_FM_DMACHK_CAPABLE);
-}
-
-/*
- * 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)
-{
- return (DDI_FM_OK);
+ return (DEVI(dip)->devi_fmhdl->fh_cap | DDI_FM_DMACHK_CAPABLE);
}
/*
@@ -1851,8 +1808,8 @@ static int pxb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
{
uint16_t cap_ptr;
- if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr))
- != DDI_FAILURE) {
+ if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
+ DDI_FAILURE) {
uint16_t slotimpl = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
if (slotimpl)
@@ -1870,8 +1827,8 @@ static int pxb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
{
uint16_t cap_ptr;
- if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_HOTPLUG, &cap_ptr))
- != DDI_FAILURE) {
+ if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_HOTPLUG, &cap_ptr)) !=
+ DDI_FAILURE) {
return (DDI_SUCCESS);
}
@@ -1879,26 +1836,6 @@ static int pxb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
}
-/* check if this device has PCIe link underneath. */
-static int
-pxb_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_ROOT) ||
- (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
- return (DDI_SUCCESS);
-
- return (DDI_FAILURE);
-}
-
/*
* For PCI and PCI-X devices including PCIe2PCI bridge, initialize
* cache-line-size and latency timer configuration registers.
diff --git a/usr/src/uts/sun4/io/px/px_pci.h b/usr/src/uts/sun4/io/px/px_pci.h
index 13cc4cc1f8..1303de878b 100644
--- a/usr/src/uts/sun4/io/px/px_pci.h
+++ b/usr/src/uts/sun4/io/px/px_pci.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -100,9 +100,6 @@ typedef struct {
ddi_acc_handle_t pxb_config_handle;
- /* Bridge or Switch, upstream or downstream */
- int pxb_port_type;
-
/* Interrupt */
ddi_intr_handle_t *pxb_htable; /* Intr Handlers */
int pxb_htable_size; /* htable size */
@@ -123,7 +120,6 @@ typedef struct {
int pxb_init_flags;
/* FMA */
- int pxb_fm_cap;
ddi_iblock_cookie_t pxb_fm_ibc;
/* Vendor Device Id */
diff --git a/usr/src/uts/sun4/io/px/px_space.c b/usr/src/uts/sun4/io/px/px_space.c
index 838fc9ffe0..a153c2b233 100644
--- a/usr/src/uts/sun4/io/px/px_space.c
+++ b/usr/src/uts/sun4/io/px/px_space.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -164,83 +164,3 @@ uint32_t px_log = PX_PANIC | PX_NO_PANIC | PX_PROTECTED | PX_HW_RESET;
uint32_t px_log = PX_PANIC;
#endif
uint32_t px_die = PX_PANIC | PX_PROTECTED | PX_HW_RESET;
-
-/* Fire PCIe Error that should cause panics */
-boolean_t px_fabric_die = B_TRUE;
-
-/* Root Complex PCIe Error bit flags that should cause panics */
-uint32_t px_fabric_die_rc_ce = 0;
-uint32_t px_fabric_die_rc_ue = 0;
-
-/* Root Complex PCIe Error bit flags that should cause forgiven */
-uint32_t px_fabric_forgive_rc_ce = 0;
-uint32_t px_fabric_forgive_rc_ue = 0;
-
-/* Fabric Error that should cause panics */
-uint32_t px_fabric_die_ce = 0;
-uint32_t px_fabric_die_ue = PCIE_AER_UCE_UR |
- PCIE_AER_UCE_UC |
- PCIE_AER_UCE_TO |
- PCIE_AER_UCE_RO |
- PCIE_AER_UCE_FCP |
- PCIE_AER_UCE_DLP |
- PCIE_AER_UCE_TRAINING;
-
-/* Fabric Error that should cause panics even under protected access */
-uint32_t px_fabric_die_ce_gos = 0;
-uint32_t px_fabric_die_ue_gos = PCIE_AER_UCE_UC |
- PCIE_AER_UCE_TO |
- PCIE_AER_UCE_RO |
- PCIE_AER_UCE_FCP |
- PCIE_AER_UCE_DLP |
- PCIE_AER_UCE_TRAINING;
-
-/* Fabric Bridge Sec. Error that should cause panics */
-uint16_t px_fabric_die_bdg_sts = PCI_STAT_S_PERROR |
- PCI_STAT_R_TARG_AB |
- PCI_STAT_R_MAST_AB |
- PCI_STAT_S_SYSERR |
- PCI_STAT_PERROR;
-
-/*
- * Fabric Bridge Sec. Error that should cause panics even under
- * protected access
- */
-uint16_t px_fabric_die_bdg_sts_gos = PCI_STAT_S_PERROR |
- PCI_STAT_PERROR;
-
-/* Fabric Switch Sec. Error that should cause panics */
-uint16_t px_fabric_die_sw_sts = PCI_STAT_R_TARG_AB |
- PCI_STAT_R_MAST_AB;
-
-/*
- * Fabric Switch Sec. Error that should cause panics even under
- * protected access
- */
-uint16_t px_fabric_die_sw_sts_gos = 0;
-
-uint32_t px_fabric_die_sue = PCIE_AER_SUCE_TA_ON_SC |
- PCIE_AER_SUCE_MA_ON_SC |
- PCIE_AER_SUCE_RCVD_TA |
- PCIE_AER_SUCE_RCVD_MA |
- PCIE_AER_SUCE_USC_ERR |
- PCIE_AER_SUCE_USC_MSG_DATA_ERR |
- PCIE_AER_SUCE_UC_DATA_ERR |
- PCIE_AER_SUCE_UC_ATTR_ERR |
- PCIE_AER_SUCE_UC_ADDR_ERR |
- PCIE_AER_SUCE_TIMER_EXPIRED |
- PCIE_AER_SUCE_PERR_ASSERT |
- PCIE_AER_SUCE_SERR_ASSERT |
- PCIE_AER_SUCE_INTERNAL_ERR;
-
-uint32_t px_fabric_die_sue_gos = PCIE_AER_SUCE_TA_ON_SC |
- PCIE_AER_SUCE_MA_ON_SC |
- PCIE_AER_SUCE_USC_ERR |
- PCIE_AER_SUCE_USC_MSG_DATA_ERR |
- PCIE_AER_SUCE_UC_DATA_ERR |
- PCIE_AER_SUCE_UC_ATTR_ERR |
- PCIE_AER_SUCE_UC_ADDR_ERR |
- PCIE_AER_SUCE_TIMER_EXPIRED |
- PCIE_AER_SUCE_PERR_ASSERT |
- PCIE_AER_SUCE_SERR_ASSERT |
- PCIE_AER_SUCE_INTERNAL_ERR;
diff --git a/usr/src/uts/sun4/io/px/px_space.h b/usr/src/uts/sun4/io/px/px_space.h
index e49e2adb84..2551175510 100644
--- a/usr/src/uts/sun4/io/px/px_space.h
+++ b/usr/src/uts/sun4/io/px/px_space.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -114,23 +114,6 @@ extern uint32_t px_max_l1_tries;
extern uint32_t px_log;
extern uint32_t px_die;
-/* Fabric Error that should cause panics */
-extern boolean_t px_fabric_die;
-extern uint32_t px_fabric_die_rc_ce;
-extern uint32_t px_fabric_die_rc_ue;
-extern uint32_t px_fabric_forgive_rc_ce;
-extern uint32_t px_fabric_forgive_rc_ue;
-extern uint32_t px_fabric_die_ce;
-extern uint32_t px_fabric_die_ue;
-extern uint32_t px_fabric_die_ce_gos;
-extern uint32_t px_fabric_die_ue_gos;
-extern uint16_t px_fabric_die_bdg_sts;
-extern uint16_t px_fabric_die_bdg_sts_gos;
-extern uint16_t px_fabric_die_sw_sts;
-extern uint16_t px_fabric_die_sw_sts_gos;
-extern uint32_t px_fabric_die_sue;
-extern uint32_t px_fabric_die_sue_gos;
-
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/sun4/io/px/px_util.c b/usr/src/uts/sun4/io/px/px_util.c
index af466b5d19..ef2b2c8ea5 100644
--- a/usr/src/uts/sun4/io/px/px_util.c
+++ b/usr/src/uts/sun4/io/px/px_util.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -71,17 +71,17 @@ px_get_props(px_t *px_p, dev_info_t *dip)
return (DDI_FAILURE);
}
DBG(DBG_ATTACH, dip, "get_px_properties: bus-range (%x,%x)\n",
- px_p->px_bus_range.lo, px_p->px_bus_range.hi);
+ px_p->px_bus_range.lo, px_p->px_bus_range.hi);
/*
* Get the interrupts property.
*/
if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "interrupts", (caddr_t)&px_p->px_inos,
- &px_p->px_inos_len) != DDI_SUCCESS) {
+ "interrupts", (caddr_t)&px_p->px_inos,
+ &px_p->px_inos_len) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s%d: no interrupts property\n",
- ddi_driver_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip), ddi_get_instance(dip));
return (DDI_FAILURE);
}
@@ -99,11 +99,11 @@ px_get_props(px_t *px_p, dev_info_t *dip)
* Get the ranges property.
*/
if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
- (caddr_t)&px_p->px_ranges_p, &px_p->px_ranges_length) !=
- DDI_SUCCESS) {
+ (caddr_t)&px_p->px_ranges_p, &px_p->px_ranges_length) !=
+ DDI_SUCCESS) {
cmn_err(CE_WARN, "%s%d: no ranges property\n",
- ddi_driver_name(dip), ddi_get_instance(dip));
+ ddi_driver_name(dip), ddi_get_instance(dip));
kmem_free(px_p->px_inos, px_p->px_inos_len);
return (DDI_FAILURE);
}
@@ -151,8 +151,8 @@ px_reloc_reg(dev_info_t *dip, dev_info_t *rdip, px_t *px_p,
uint32_t space_type = phys_hi & PCI_REG_ADDR_M; /* 28-bit */
DBG(DBG_MAP | DBG_CONT, dip, "\tpx_reloc_reg fr: %x.%x.%x %x.%x\n",
- rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
- rp->pci_size_hi, rp->pci_size_low);
+ rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
+ rp->pci_size_hi, rp->pci_size_low);
if (space_type == PCI_ADDR_CONFIG || phys_hi & PCI_RELOCAT_B)
return (DDI_SUCCESS);
@@ -508,7 +508,9 @@ px_init_child(px_t *px_p, dev_info_t *child)
"INITCHILD: config regs setup for %s@%s\n",
ddi_node_name(child), ddi_get_name_addr(child));
- pcie_initchild(child);
+ ddi_set_parent_data(child, NULL);
+ if (pcie_init_bus(child))
+ (void) pcie_initchild(child);
/*
* Handle chip specific init-child tasks.
@@ -549,7 +551,7 @@ px_get_reg_set_size(dev_info_t *child, int rnumber)
goto done;
size = pci_rp[rnumber].pci_size_low |
- ((uint64_t)pci_rp[rnumber].pci_size_hi << 32);
+ ((uint64_t)pci_rp[rnumber].pci_size_hi << 32);
done:
kmem_free(pci_rp, i);
return (size);
diff --git a/usr/src/uts/sun4/io/px/px_var.h b/usr/src/uts/sun4/io/px/px_var.h
index 048a10c65b..ba395d8b9d 100644
--- a/usr/src/uts/sun4/io/px/px_var.h
+++ b/usr/src/uts/sun4/io/px/px_var.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -130,11 +130,13 @@ struct px {
kmutex_t px_fm_mutex;
kthread_t *px_fm_mutex_owner;
ddi_iblock_cookie_t px_fm_ibc;
+ pf_data_t px_pfd_arr[5];
+ int px_pfd_idx;
uint32_t px_dev_caps;
/* Platform specific information */
- void *px_plat_p;
+ void *px_plat_p;
/* Power Management fields */
kmutex_t px_l23ready_lock; /* used in PME_To_ACK interrupt */
@@ -150,10 +152,6 @@ struct px {
/* Handle for soft intr */
ddi_softint_handle_t px_dbg_hdl; /* HDL for dbg printing */
-
- /* array to keep track of register snapshots during error handling */
- int px_dq_tail; /* last valid index in cs array */
- pf_data_t *px_dq_p;
};
/* px soft state flag */
diff --git a/usr/src/uts/sun4u/io/pci/pci_pci.c b/usr/src/uts/sun4u/io/pci/pci_pci.c
index b694903116..6b9b710173 100644
--- a/usr/src/uts/sun4u/io/pci/pci_pci.c
+++ b/usr/src/uts/sun4u/io/pci/pci_pci.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -953,7 +953,7 @@ ppb_initchild(dev_info_t *child)
* errors.
*/
if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
- if (pcie_init_ppd(child) == NULL) {
+ if (pcie_init_bus(child) == NULL) {
pci_config_teardown(&config_handle);
return (DDI_FAILURE);
}
@@ -987,7 +987,7 @@ ppb_uninitchild(dev_info_t *child)
* SG OPL FMA specific
*/
if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
- pcie_uninit_ppd(child);
+ pcie_fini_bus(child);
ppb_removechild(child);
}
diff --git a/usr/src/uts/sun4u/io/px/px_err.c b/usr/src/uts/sun4u/io/px/px_err.c
index fb0d8cb053..58778ac9da 100644
--- a/usr/src/uts/sun4u/io/px/px_err.c
+++ b/usr/src/uts/sun4u/io/px/px_err.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#include <sys/sunndi.h>
#include <sys/fm/protocol.h>
#include <sys/fm/util.h>
#include <sys/pcie.h>
@@ -661,18 +662,18 @@ px_err_cb_intr(caddr_t arg)
derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
- mutex_enter(&px_p->px_fm_mutex);
- px_p->px_fm_mutex_owner = curthread;
+ if (px_fm_enter(px_p) != DDI_SUCCESS)
+ goto done;
err = px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_HOST);
(void) px_lib_intr_setstate(rpdip, px_fault_p->px_fh_sysino,
INTR_IDLE_STATE);
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
-
- px_err_panic(err, PX_HB, PX_NO_ERROR);
+ px_err_panic(err, PX_HB, PX_NO_ERROR, B_TRUE);
+ px_fm_exit(px_p);
+ px_err_panic(err, PX_HB, PX_NO_ERROR, B_FALSE);
+done:
return (DDI_INTR_CLAIMED);
}
@@ -692,7 +693,7 @@ px_err_dmc_pec_intr(caddr_t arg)
px_fault_t *px_fault_p = (px_fault_t *)arg;
dev_info_t *rpdip = px_fault_p->px_fh_dip;
px_t *px_p = DIP_TO_STATE(rpdip);
- int rc_err, fab_err = PF_NO_PANIC;
+ int rc_err, fab_err;
ddi_fm_error_t derr;
/* Create the derr */
@@ -701,27 +702,24 @@ px_err_dmc_pec_intr(caddr_t arg)
derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
- mutex_enter(&px_p->px_fm_mutex);
- px_p->px_fm_mutex_owner = curthread;
+ if (px_fm_enter(px_p) != DDI_SUCCESS)
+ goto done;
/* send ereport/handle/clear fire registers */
rc_err = px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_PCIE);
/* Check all child devices for errors */
- if (!px_lib_is_in_drain_state(px_p)) {
- fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p,
- &px_p->px_dq_tail);
- }
+ fab_err = px_scan_fabric(px_p, rpdip, &derr);
/* Set the interrupt state to idle */
(void) px_lib_intr_setstate(rpdip, px_fault_p->px_fh_sysino,
INTR_IDLE_STATE);
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
-
- px_err_panic(rc_err, PX_RC, fab_err);
+ px_err_panic(rc_err, PX_RC, fab_err, B_TRUE);
+ px_fm_exit(px_p);
+ px_err_panic(rc_err, PX_RC, fab_err, B_FALSE);
+done:
return (DDI_INTR_CLAIMED);
}
@@ -1797,7 +1795,7 @@ px_err_mmu_rbne_handle(dev_info_t *rpdip, caddr_t csr_base,
goto done;
bdf = (pcie_req_id_t)CSR_FR(csr_base, MMU_TRANSLATION_FAULT_STATUS, ID);
- (void) pf_hdl_lookup(rpdip, derr->fme_ena, PF_DMA_ADDR, NULL,
+ (void) pf_hdl_lookup(rpdip, derr->fme_ena, PF_ADDR_DMA, NULL,
bdf);
done:
@@ -1828,7 +1826,7 @@ px_err_mmu_tfa_handle(dev_info_t *rpdip, caddr_t csr_base,
goto done;
bdf = (pcie_req_id_t)CSR_FR(csr_base, MMU_TRANSLATION_FAULT_STATUS, ID);
- (void) pf_hdl_lookup(rpdip, derr->fme_ena, PF_DMA_ADDR, NULL,
+ (void) pf_hdl_lookup(rpdip, derr->fme_ena, PF_ADDR_DMA, NULL,
bdf);
done:
@@ -1860,7 +1858,7 @@ px_err_mmu_parity_handle(dev_info_t *rpdip, caddr_t csr_base,
mmu_tfa = CSR_XR(csr_base, MMU_TRANSLATION_FAULT_ADDRESS);
bdf = (pcie_req_id_t)CSR_FR(csr_base, MMU_TRANSLATION_FAULT_STATUS, ID);
- status = pf_hdl_lookup(rpdip, derr->fme_ena, PF_DMA_ADDR,
+ status = pf_hdl_lookup(rpdip, derr->fme_ena, PF_ADDR_DMA,
(uint32_t)mmu_tfa, bdf);
done:
@@ -1884,33 +1882,22 @@ px_err_wuc_ruc_handle(dev_info_t *rpdip, caddr_t csr_base,
px_t *px_p = DIP_TO_STATE(rpdip);
pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p;
uint64_t data;
- uint32_t addr, hdr;
- pcie_tlp_hdr_t *tlp;
- int sts = PF_HDL_NOTFOUND;
+ pf_pcie_adv_err_regs_t adv_reg;
+ int sts;
if (!PX_ERR_IS_PRI(err_bit_descr->bit))
goto done;
data = CSR_XR(csr_base, TLU_TRANSMIT_OTHER_EVENT_HEADER1_LOG);
- hdr = (uint32_t)(data >> 32);
- tlp = (pcie_tlp_hdr_t *)&hdr;
+ adv_reg.pcie_ue_hdr[0] = (uint32_t)(data >> 32);
+ adv_reg.pcie_ue_hdr[1] = (uint32_t)(data & 0xFFFFFFFF);
data = CSR_XR(csr_base, TLU_TRANSMIT_OTHER_EVENT_HEADER2_LOG);
- addr = (uint32_t)(data >> 32);
-
- switch (tlp->type) {
- case PCIE_TLP_TYPE_IO:
- case PCIE_TLP_TYPE_MEM:
- case PCIE_TLP_TYPE_MEMLK:
- sts = pf_hdl_lookup(rpdip, derr->fme_ena, PF_PIO_ADDR,
- addr, NULL);
- break;
- case PCIE_TLP_TYPE_CFG0:
- case PCIE_TLP_TYPE_CFG1:
- sts = pf_hdl_lookup(rpdip, derr->fme_ena, PF_CFG_ADDR,
- addr, (addr >> 16));
- break;
- }
+ adv_reg.pcie_ue_hdr[2] = (uint32_t)(data >> 32);
+ adv_reg.pcie_ue_hdr[3] = (uint32_t)(data & 0xFFFFFFFF);
+ pf_tlp_decode(PCIE_DIP2BUS(rpdip), &adv_reg);
+ sts = pf_hdl_lookup(rpdip, derr->fme_ena, adv_reg.pcie_ue_tgt_trans,
+ adv_reg.pcie_ue_tgt_addr, adv_reg.pcie_ue_tgt_bdf);
done:
if ((sts == PF_HDL_NOTFOUND) && (pxu_p->cpr_flag == PX_NOT_CPR))
return (px_err_protected_handle(rpdip, csr_base, derr,
@@ -1998,32 +1985,19 @@ px_err_pciex_ue_handle(dev_info_t *rpdip, caddr_t csr_base,
regs.primary_ue = err_bit;
/*
- * Log the Received Log for PTLP and UR. The PTLP most likely
- * is a poisoned completion. The original transaction will be
- * logged inthe Transmit Log.
+ * Log the Received Log for PTLP, UR and UC.
*/
- if (err_bit & (PCIE_AER_UCE_PTLP | PCIE_AER_UCE_UR)) {
+ if ((PCIE_AER_UCE_PTLP | PCIE_AER_UCE_UR | PCIE_AER_UCE_UC) &
+ err_bit) {
log = CSR_XR(csr_base,
TLU_RECEIVE_UNCORRECTABLE_ERROR_HEADER1_LOG);
regs.rx_hdr1 = (uint32_t)(log >> 32);
- regs.rx_hdr2 = (uint32_t)(log && 0xFFFFFFFF);
+ regs.rx_hdr2 = (uint32_t)(log & 0xFFFFFFFF);
log = CSR_XR(csr_base,
TLU_RECEIVE_UNCORRECTABLE_ERROR_HEADER2_LOG);
regs.rx_hdr3 = (uint32_t)(log >> 32);
- regs.rx_hdr4 = (uint32_t)(log && 0xFFFFFFFF);
- }
-
- if (err_bit & (PCIE_AER_UCE_PTLP)) {
- log = CSR_XR(csr_base,
- TLU_TRANSMIT_UNCORRECTABLE_ERROR_HEADER1_LOG);
- regs.tx_hdr1 = (uint32_t)(log >> 32);
- regs.tx_hdr2 = (uint32_t)(log && 0xFFFFFFFF);
-
- log = CSR_XR(csr_base,
- TLU_TRANSMIT_UNCORRECTABLE_ERROR_HEADER2_LOG);
- regs.tx_hdr3 = (uint32_t)(log >> 32);
- regs.tx_hdr4 = (uint32_t)(log && 0xFFFFFFFF);
+ regs.rx_hdr4 = (uint32_t)(log & 0xFFFFFFFF);
}
} else {
regs.ue_reg = (uint32_t)BITMASK(err_bit_descr->bit - 32);
@@ -2230,13 +2204,11 @@ PX_ERPT_SEND_DEC(pciex_rx_tx_oe)
char buf[FM_MAX_CLASS];
boolean_t pri = PX_ERR_IS_PRI(bit);
px_t *px_p = DIP_TO_STATE(rpdip);
- uint32_t trans_type, fault_addr = 0;
uint64_t rx_h1, rx_h2, tx_h1, tx_h2;
uint16_t s_status;
int sts;
- pcie_req_id_t fault_bdf = 0;
pcie_cpl_t *cpl;
- pf_data_t pf_data = {0};
+ pf_pcie_adv_err_regs_t adv_reg;
rx_h1 = CSR_XR(csr_base, TLU_RECEIVE_OTHER_EVENT_HEADER1_LOG);
rx_h2 = CSR_XR(csr_base, TLU_RECEIVE_OTHER_EVENT_HEADER2_LOG);
@@ -2245,14 +2217,13 @@ PX_ERPT_SEND_DEC(pciex_rx_tx_oe)
if ((bit == TLU_OTHER_EVENT_STATUS_SET_RUC_P) ||
(bit == TLU_OTHER_EVENT_STATUS_SET_WUC_P)) {
- pf_data.aer_h0 = (uint32_t)(rx_h1 >> 32);
- pf_data.aer_h1 = (uint32_t)rx_h1;
- pf_data.aer_h2 = (uint32_t)(rx_h2 >> 32);
- pf_data.aer_h3 = (uint32_t)rx_h2;
+ adv_reg.pcie_ue_hdr[0] = (uint32_t)(rx_h1 >> 32);
+ adv_reg.pcie_ue_hdr[1] = (uint32_t)rx_h1;
+ adv_reg.pcie_ue_hdr[2] = (uint32_t)(rx_h2 >> 32);
+ adv_reg.pcie_ue_hdr[3] = (uint32_t)rx_h2;
/* get completer bdf (fault bdf) from rx logs */
- cpl = (pcie_cpl_t *)&pf_data.aer_h1;
- fault_bdf = cpl->cid;
+ cpl = (pcie_cpl_t *)&adv_reg.pcie_ue_hdr[1];
/* Figure out if UR/CA from rx logs */
if (cpl->status == PCIE_CPL_STS_UR)
@@ -2260,19 +2231,17 @@ PX_ERPT_SEND_DEC(pciex_rx_tx_oe)
else if (cpl->status == PCIE_CPL_STS_CA)
s_status = PCI_STAT_R_TARG_AB;
-
- pf_data.aer_h0 = (uint32_t)(tx_h1 >> 32);
- pf_data.aer_h1 = (uint32_t)tx_h1;
- pf_data.aer_h2 = (uint32_t)(tx_h2 >> 32);
- pf_data.aer_h3 = (uint32_t)tx_h2;
+ adv_reg.pcie_ue_hdr[0] = (uint32_t)(tx_h1 >> 32);
+ adv_reg.pcie_ue_hdr[1] = (uint32_t)tx_h1;
+ adv_reg.pcie_ue_hdr[2] = (uint32_t)(tx_h2 >> 32);
+ adv_reg.pcie_ue_hdr[3] = (uint32_t)tx_h2;
/* get fault addr from tx logs */
- sts = pf_tlp_decode(rpdip, &pf_data, 0, &fault_addr,
- &trans_type);
+ sts = pf_tlp_decode(PCIE_DIP2BUS(rpdip), &adv_reg);
if (sts == DDI_SUCCESS)
- (void) px_rp_en_q(px_p, fault_bdf, fault_addr,
- s_status);
+ (void) px_rp_en_q(px_p, adv_reg.pcie_ue_tgt_bdf,
+ adv_reg.pcie_ue_tgt_addr, s_status);
}
(void) snprintf(buf, FM_MAX_CLASS, "%s", class_name);
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c
index b587d5336e..11c65abcd4 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,6 +30,7 @@
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#include <sys/sunndi.h>
#include <sys/fm/protocol.h>
#include <sys/fm/util.h>
#include <sys/modctl.h>
@@ -86,7 +87,7 @@ px_lib_map_regs(pxu_t *pxu_p, dev_info_t *dip)
px_reg_bank_t reg_bank = PX_REG_CSR;
DBG(DBG_ATTACH, dip, "px_lib_map_regs: pxu_p:0x%p, dip 0x%p\n",
- pxu_p, dip);
+ pxu_p, dip);
attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
@@ -241,7 +242,6 @@ px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl)
ILU_ERROR_LOG_ENABLE_SPARE3);
px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE);
- px_fabric_die_rc_ue |= PCIE_AER_UCE_UC;
break;
case PX_CHIP_FIRE:
@@ -1452,7 +1452,8 @@ px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr)
ndi_fm_acc_err_set(pec_p->pec_acc_hdl, &derr);
}
- mutex_enter(&px_p->px_fm_mutex);
+ if (px_fm_enter(px_p) != DDI_SUCCESS)
+ return;
/* send ereport/handle/clear fire registers */
rc_err = px_err_cmn_intr(px_p, &derr, PX_LIB_CALL, PX_FM_BLOCK_ALL);
@@ -1471,8 +1472,7 @@ px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr)
break;
case PCI_ADDR_MEM32:
if (rdip)
- (void) pcie_get_bdf_from_dip(rdip,
- &bdf);
+ bdf = PCI_GET_BDF(rdip);
else
bdf = NULL;
break;
@@ -1487,12 +1487,11 @@ px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr)
* XXX - Current code scans the fabric for all px_tool accesses.
* In future, do not scan fabric for px_tool access to IO Root Nexus
*/
- fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p,
- &px_p->px_dq_tail);
-
- mutex_exit(&px_p->px_fm_mutex);
+ fab_err = px_scan_fabric(px_p, rpdip, &derr);
- px_err_panic(rc_err, PX_RC, fab_err);
+ px_err_panic(rc_err, PX_RC, fab_err, B_TRUE);
+ px_fm_exit(px_p);
+ px_err_panic(rc_err, PX_RC, fab_err, B_FALSE);
}
#ifdef DEBUG
@@ -1641,9 +1640,10 @@ px_lib_do_peek(dev_info_t *dip, peekpoke_ctlops_t *in_args)
on_trap_data_t otd;
mutex_enter(&pec_p->pec_pokefault_mutex);
- mutex_enter(&px_p->px_fm_mutex);
+ if (px_fm_enter(px_p) != DDI_SUCCESS)
+ return (DDI_FAILURE);
pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;
- mutex_exit(&px_p->px_fm_mutex);
+ px_fm_exit(px_p);
if (!on_trap(&otd, OT_DATA_ACCESS)) {
uintptr_t tramp = otd.ot_trampoline;
@@ -2038,7 +2038,7 @@ px_err_rem_intr(px_fault_t *px_fault_p)
px_t *px_p = DIP_TO_STATE(dip);
px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino,
- IB_INTR_WAIT);
+ IB_INTR_WAIT);
VERIFY(rem_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
}
@@ -2120,7 +2120,7 @@ px_cb_add_intr(px_fault_t *fault_p)
/* px_lib_dev_init allows only FIRE and OBERON */
px_err_reg_enable(
(pxu_p->chip_type == PX_CHIP_FIRE) ?
- PX_ERR_JBC : PX_ERR_UBC,
+ PX_ERR_JBC : PX_ERR_UBC,
pxu_p->px_address[PX_REG_XBC]);
} else
pxu_p->px_cb_p = cb_p;
@@ -2146,7 +2146,7 @@ px_cb_add_intr(px_fault_t *fault_p)
* both.
*/
pxl = cb_p->pxl;
- for (; !(pxl->pxp == px_p) && pxl->next; pxl = pxl->next);
+ for (; !(pxl->pxp == px_p) && pxl->next; pxl = pxl->next) {};
ASSERT(pxl->pxp != px_p);
/* add to linked list */
@@ -2193,7 +2193,8 @@ px_cb_rem_intr(px_fault_t *fault_p)
} else {
prev = pxl;
pxl = pxl->next;
- for (; pxl && (pxl->pxp != px_p); prev = pxl, pxl = pxl->next);
+ for (; pxl && (pxl->pxp != px_p); prev = pxl, pxl = pxl->next) {
+ };
if (!pxl) {
cmn_err(CE_WARN, "px_cb_rem_intr: can't find px_p 0x%p "
"in registered CB list.", (void *)px_p);
@@ -2455,7 +2456,7 @@ px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank)
mask = px_get_rng_parent_hi_mask(px_p);
range_prop = (((uint64_t)(rp[bank].parent_high & mask)) << 32) |
- rp[bank].parent_low;
+ rp[bank].parent_low;
return (range_prop);
}
@@ -2467,7 +2468,7 @@ void
px_cpr_add_callb(px_t *px_p)
{
px_p->px_cprcb_id = callb_add(px_cpr_callb, (void *)px_p,
- CB_CL_CPR_POST_USER, "px_cpr");
+ CB_CL_CPR_POST_USER, "px_cpr");
}
/*
@@ -2491,9 +2492,9 @@ px_hp_intr(caddr_t arg1, caddr_t arg2)
#ifdef DEBUG
if (rval == DDI_INTR_UNCLAIMED)
- cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n",
- ddi_driver_name(px_p->px_dip),
- ddi_get_instance(px_p->px_dip));
+ cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n",
+ ddi_driver_name(px_p->px_dip),
+ ddi_get_instance(px_p->px_dip));
#endif
/* Set the interrupt state to idle */
diff --git a/usr/src/uts/sun4v/io/px/px_err.c b/usr/src/uts/sun4v/io/px/px_err.c
index dce8c76f07..77a2c4f2de 100644
--- a/usr/src/uts/sun4v/io/px/px_err.c
+++ b/usr/src/uts/sun4v/io/px/px_err.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#include <sys/sunndi.h>
#include <sys/fm/protocol.h>
#include <sys/fm/util.h>
#include <sys/membar.h>
@@ -45,6 +46,9 @@ static int px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr,
static void px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt,
boolean_t is_block_pci, char *msg);
+static void px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
+ boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
+ boolean_t is_valid_epkt);
static int px_cb_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
px_rc_err_t *epkt);
static int px_mmu_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
@@ -133,10 +137,10 @@ px_err_cmn_intr(px_t *px_p, ddi_fm_error_t *derr, int caller, int block)
*/
static void
px_err_fill_pfd(dev_info_t *dip, px_t *px_p, px_rc_err_t *epkt) {
- pf_data_t pf_data = {0};
+ pf_pcie_adv_err_regs_t adv_reg;
int sts = DDI_SUCCESS;
pcie_req_id_t fault_bdf = 0;
- uint32_t fault_addr = 0;
+ uint64_t fault_addr = 0;
uint16_t s_status = 0;
/* Add an PCIE PF_DATA Entry */
@@ -151,14 +155,12 @@ px_err_fill_pfd(dev_info_t *dip, px_t *px_p, px_rc_err_t *epkt) {
sts = DDI_FAILURE;
} else {
px_pec_err_t *pec_p = (px_pec_err_t *)epkt;
- uint32_t trans_type;
uint32_t dir = pec_p->pec_descr.dir;
- pf_data.rp_bdf = px_p->px_bdf;
- pf_data.aer_h0 = (uint32_t)(pec_p->hdr[0]);
- pf_data.aer_h1 = (uint32_t)(pec_p->hdr[0] >> 32);
- pf_data.aer_h2 = (uint32_t)(pec_p->hdr[1]);
- pf_data.aer_h3 = (uint32_t)(pec_p->hdr[1] >> 32);
+ adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0]);
+ adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0] >> 32);
+ adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1]);
+ adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1] >> 32);
/* translate RC UR/CA to legacy secondary errors */
if ((dir == DIR_READ || dir == DIR_WRITE) &&
@@ -175,8 +177,9 @@ px_err_fill_pfd(dev_info_t *dip, px_t *px_p, px_rc_err_t *epkt) {
if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
s_status |= PCI_STAT_S_TARG_AB;
- sts = pf_tlp_decode(dip, &pf_data, &fault_bdf, &fault_addr,
- &trans_type);
+ sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
+ fault_bdf = adv_reg.pcie_ue_tgt_bdf;
+ fault_addr = adv_reg.pcie_ue_tgt_bdf;
}
if (sts == DDI_SUCCESS)
@@ -200,11 +203,11 @@ px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
{
px_t *px_p = DIP_TO_STATE(fault_p->px_fh_dip);
dev_info_t *rpdip = px_p->px_dip;
- int rc_err, fab_err = PF_NO_PANIC, msg;
+ int rc_err, fab_err, msg;
ddi_fm_error_t derr;
- mutex_enter(&px_p->px_fm_mutex);
- px_p->px_fm_mutex_owner = curthread;
+ if (px_fm_enter(px_p) != DDI_SUCCESS)
+ goto done;
/* Create the derr */
bzero(&derr, sizeof (ddi_fm_error_t));
@@ -219,21 +222,15 @@ px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
rc_err = px_err_epkt_severity(px_p, &derr, epkt, PX_INTR_CALL);
/* Scan the fabric if the root port is not in drain state. */
- if (!px_lib_is_in_drain_state(px_p))
- fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p,
- &px_p->px_dq_tail);
+ fab_err = px_scan_fabric(px_p, rpdip, &derr);
/* Set the intr state to idle for the leaf that received the mondo */
if (px_lib_intr_setstate(rpdip, fault_p->px_fh_sysino,
INTR_IDLE_STATE) != DDI_SUCCESS) {
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
+ px_fm_exit(px_p);
return (DDI_INTR_UNCLAIMED);
}
- px_p->px_fm_mutex_owner = NULL;
- mutex_exit(&px_p->px_fm_mutex);
-
switch (epkt->rc_descr.block) {
case BLOCK_MMU: /* FALLTHROUGH */
case BLOCK_INTR:
@@ -248,8 +245,11 @@ px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
break;
}
- px_err_panic(rc_err, msg, fab_err);
+ px_err_panic(rc_err, msg, fab_err, B_TRUE);
+ px_fm_exit(px_p);
+ px_err_panic(rc_err, msg, fab_err, B_FALSE);
+done:
return (DDI_INTR_CLAIMED);
}
@@ -269,7 +269,7 @@ px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
dev_info_t *dip = px_p->px_dip;
boolean_t is_safeacc = B_FALSE;
boolean_t is_block_pci = B_FALSE;
- char buf[FM_MAX_CLASS], descr_buf[1024];
+ boolean_t is_valid_epkt = B_FALSE;
int err = 0;
/* Cautious access error handling */
@@ -334,75 +334,30 @@ px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
if ((err & PX_HW_RESET) || (err & PX_PANIC)) {
if (px_log & PX_PANIC)
px_err_log_handle(dip, epkt, is_block_pci, "PANIC");
+ is_valid_epkt = B_TRUE;
} else if (err & PX_PROTECTED) {
if (px_log & PX_PROTECTED)
px_err_log_handle(dip, epkt, is_block_pci, "PROTECTED");
+ is_valid_epkt = B_TRUE;
} else if (err & PX_NO_PANIC) {
if (px_log & PX_NO_PANIC)
px_err_log_handle(dip, epkt, is_block_pci, "NO PANIC");
+ is_valid_epkt = B_TRUE;
} else if (err & PX_NO_ERROR) {
if (px_log & PX_NO_ERROR)
px_err_log_handle(dip, epkt, is_block_pci, "NO ERROR");
+ is_valid_epkt = B_TRUE;
} else if (err == 0) {
px_err_log_handle(dip, epkt, is_block_pci, "UNRECOGNIZED");
+ is_valid_epkt = B_FALSE;
- /* Unrecognized epkt. send ereport */
- (void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG);
-
- if (is_block_pci) {
- px_pec_err_t *pec = (px_pec_err_t *)epkt;
-
- (void) snprintf(descr_buf, sizeof (descr_buf),
- "Epkt contents:\n"
- "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n"
- "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n"
- "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n"
- "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n"
- "HDR1: 0x%lx, HDR2: 0x%lx\n"
- "Err Src Reg: 0x%x, Root Err Status: 0x%x\n",
- pec->pec_descr.block, pec->pec_descr.dir,
- pec->pec_descr.Z, pec->pec_descr.S,
- pec->pec_descr.R, pec->pec_descr.I,
- pec->pec_descr.H, pec->pec_descr.C,
- pec->pec_descr.U, pec->pec_descr.E,
- pec->pec_descr.P, pec->pci_err_status,
- pec->pcie_err_status, pec->ce_reg_status,
- pec->ue_reg_status, pec->hdr[0],
- pec->hdr[1], pec->err_src_reg,
- pec->root_err_status);
-
- ddi_fm_ereport_post(dip, buf, derr->fme_ena,
- DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
- EPKT_SYSINO, DATA_TYPE_UINT64, pec->sysino,
- EPKT_EHDL, DATA_TYPE_UINT64, pec->ehdl,
- EPKT_STICK, DATA_TYPE_UINT64, pec->stick,
- EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf);
- } else {
- (void) snprintf(descr_buf, sizeof (descr_buf),
- "Epkt contents:\n"
- "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
- "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n"
- "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n"
- "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n",
- epkt->rc_descr.block, epkt->rc_descr.op,
- epkt->rc_descr.phase, epkt->rc_descr.cond,
- epkt->rc_descr.dir, epkt->rc_descr.STOP,
- epkt->rc_descr.H, epkt->rc_descr.R,
- epkt->rc_descr.D, epkt->rc_descr.M,
- epkt->rc_descr.S, epkt->size, epkt->addr,
- epkt->hdr[0], epkt->hdr[1], epkt->reserved);
-
- ddi_fm_ereport_post(dip, buf, derr->fme_ena,
- DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
- EPKT_SYSINO, DATA_TYPE_UINT64, epkt->sysino,
- EPKT_EHDL, DATA_TYPE_UINT64, epkt->ehdl,
- EPKT_STICK, DATA_TYPE_UINT64, epkt->stick,
- EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf);
- }
-
+ /* Panic on a unrecognized epkt */
err = PX_PANIC;
}
+ px_err_send_epkt_erpt(dip, epkt, is_block_pci, err, derr,
+ is_valid_epkt);
+
/* Readjust the severity as a result of safe access */
if (is_safeacc && !(err & PX_PANIC) && !(px_die & PX_PROTECTED))
err = PX_NO_PANIC;
@@ -411,6 +366,78 @@ px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
}
static void
+px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
+ boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
+ boolean_t is_valid_epkt)
+{
+ char buf[FM_MAX_CLASS], descr_buf[1024];
+
+ /* send ereport for debug purposes */
+ (void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG);
+
+ if (is_block_pci) {
+ px_pec_err_t *pec = (px_pec_err_t *)epkt;
+ (void) snprintf(descr_buf, sizeof (descr_buf),
+ "%s Epkt contents:\n"
+ "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n"
+ "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n"
+ "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n"
+ "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n"
+ "HDR1: 0x%lx, HDR2: 0x%lx\n"
+ "Err Src Reg: 0x%x, Root Err Status: 0x%x\n"
+ "Err Severity: 0x%x\n",
+ is_valid_epkt ? "Valid" : "Invalid",
+ pec->pec_descr.block, pec->pec_descr.dir,
+ pec->pec_descr.Z, pec->pec_descr.S,
+ pec->pec_descr.R, pec->pec_descr.I,
+ pec->pec_descr.H, pec->pec_descr.C,
+ pec->pec_descr.U, pec->pec_descr.E,
+ pec->pec_descr.P, pec->pci_err_status,
+ pec->pcie_err_status, pec->ce_reg_status,
+ pec->ue_reg_status, pec->hdr[0],
+ pec->hdr[1], pec->err_src_reg,
+ pec->root_err_status, err);
+
+ ddi_fm_ereport_post(dip, buf, derr->fme_ena,
+ DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
+ EPKT_SYSINO, DATA_TYPE_UINT64,
+ is_valid_epkt ? pec->sysino : 0,
+ EPKT_EHDL, DATA_TYPE_UINT64,
+ is_valid_epkt ? pec->ehdl : 0,
+ EPKT_STICK, DATA_TYPE_UINT64,
+ is_valid_epkt ? pec->stick : 0,
+ EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf);
+ } else {
+ (void) snprintf(descr_buf, sizeof (descr_buf),
+ "%s Epkt contents:\n"
+ "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
+ "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n"
+ "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n"
+ "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n"
+ "Err Severity: 0x%x\n",
+ is_valid_epkt ? "Valid" : "Invalid",
+ epkt->rc_descr.block, epkt->rc_descr.op,
+ epkt->rc_descr.phase, epkt->rc_descr.cond,
+ epkt->rc_descr.dir, epkt->rc_descr.STOP,
+ epkt->rc_descr.H, epkt->rc_descr.R,
+ epkt->rc_descr.D, epkt->rc_descr.M,
+ epkt->rc_descr.S, epkt->size, epkt->addr,
+ epkt->hdr[0], epkt->hdr[1], epkt->reserved,
+ err);
+
+ ddi_fm_ereport_post(dip, buf, derr->fme_ena,
+ DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
+ EPKT_SYSINO, DATA_TYPE_UINT64,
+ is_valid_epkt ? epkt->sysino : 0,
+ EPKT_EHDL, DATA_TYPE_UINT64,
+ is_valid_epkt ? epkt->ehdl : 0,
+ EPKT_STICK, DATA_TYPE_UINT64,
+ is_valid_epkt ? epkt->stick : 0,
+ EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf);
+ }
+}
+
+static void
px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, boolean_t is_block_pci,
char *msg)
{
@@ -559,40 +586,45 @@ px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
static int
px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
{
- px_t *px_p = DIP_TO_STATE(dip);
- px_pec_err_t *pec = (px_pec_err_t *)epkt;
+ px_pec_err_t *pec_p = (px_pec_err_t *)epkt;
px_err_pcie_t *pcie = (px_err_pcie_t *)epkt;
- pf_data_t pf_data;
- int x;
+ pf_pcie_adv_err_regs_t adv_reg;
+ int sts;
uint32_t temp;
/*
* Check for failed PIO Read/Writes, which are errors that are not
* defined in the PCIe spec.
*/
- pf_data.rp_bdf = px_p->px_bdf;
temp = PCIE_AER_UCE_UR | PCIE_AER_UCE_CA;
- if (((pec->pec_descr.dir == DIR_READ) || (pec->pec_descr.dir ==
- DIR_WRITE)) && pec->pec_descr.U && (pec->ue_reg_status & temp)) {
- pf_data.aer_h0 = (uint32_t)(pec->hdr[0]);
- pf_data.aer_h1 = (uint32_t)(pec->hdr[0] >> 32);
- pf_data.aer_h2 = (uint32_t)(pec->hdr[1]);
- pf_data.aer_h3 = (uint32_t)(pec->hdr[1] >> 32);
-
- if (pf_tlp_hdl_lookup(dip, derr, &pf_data) == PF_HDL_FOUND)
+ if (((pec_p->pec_descr.dir == DIR_READ) ||
+ (pec_p->pec_descr.dir == DIR_WRITE)) &&
+ pec_p->pec_descr.U && (pec_p->ue_reg_status & temp)) {
+ adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0]);
+ adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0] >> 32);
+ adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1]);
+ adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1] >> 32);
+
+ sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
+
+ if (sts == DDI_SUCCESS &&
+ pf_hdl_lookup(dip, derr->fme_ena,
+ adv_reg.pcie_ue_tgt_trans,
+ adv_reg.pcie_ue_tgt_addr,
+ adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
return (PX_NO_PANIC);
else
return (PX_PANIC);
}
- if (!pec->pec_descr.C)
- pec->ce_reg_status = 0;
- if (!pec->pec_descr.U)
- pec->ue_reg_status = 0;
- if (!pec->pec_descr.H)
- pec->hdr[0] = 0;
- if (!pec->pec_descr.I)
- pec->hdr[1] = 0;
+ if (!pec_p->pec_descr.C)
+ pec_p->ce_reg_status = 0;
+ if (!pec_p->pec_descr.U)
+ pec_p->ue_reg_status = 0;
+ if (!pec_p->pec_descr.H)
+ pec_p->hdr[0] = 0;
+ if (!pec_p->pec_descr.I)
+ pec_p->hdr[1] = 0;
/*
* According to the PCIe spec, there is a first error pointer. If there
@@ -606,6 +638,7 @@ px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
*/
temp = pcie->ue_reg;
if (temp) {
+ int x;
for (x = 0; !(temp & 0x1); x++) {
temp = temp >> 1;
}
@@ -637,13 +670,13 @@ px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
static int
px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
{
- uint32_t addr = (uint32_t)epkt->addr;
+ uint64_t addr = (uint64_t)epkt->addr;
pcie_req_id_t bdf = NULL;
if (epkt->rc_descr.H) {
bdf = (uint32_t)((epkt->hdr[0] >> 16) && 0xFFFF);
}
- return (pf_hdl_lookup(dip, derr->fme_ena, PF_DMA_ADDR, addr,
+ return (pf_hdl_lookup(dip, derr->fme_ena, PF_ADDR_DMA, addr,
bdf));
}
diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.c b/usr/src/uts/sun4v/io/px/px_lib4v.c
index f6d66e26c7..8ab8f6906b 100644
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1131,15 +1131,15 @@ px_lib_config_put(dev_info_t *dip, pci_device_t bdf, pci_config_offset_t off,
static uint32_t
px_pci_config_get(ddi_acc_impl_t *handle, uint32_t *addr, int size)
{
- px_config_acc_pvt_t *px_pvt = (px_config_acc_pvt_t *)
- handle->ahi_common.ah_bus_private;
+ px_config_acc_pvt_t *px_pvt = (px_config_acc_pvt_t *)
+ handle->ahi_common.ah_bus_private;
uint32_t pci_dev_addr = px_pvt->raddr;
uint32_t vaddr = px_pvt->vaddr;
uint16_t off = (uint16_t)(uintptr_t)(addr - vaddr) & 0xfff;
uint32_t rdata = 0;
if (px_lib_config_get(px_pvt->dip, pci_dev_addr, off,
- size, (pci_cfg_data_t *)&rdata) != DDI_SUCCESS)
+ size, (pci_cfg_data_t *)&rdata) != DDI_SUCCESS)
/* XXX update error kstats */
return (0xffffffff);
return (rdata);
@@ -1149,14 +1149,14 @@ static void
px_pci_config_put(ddi_acc_impl_t *handle, uint32_t *addr,
int size, pci_cfg_data_t wdata)
{
- px_config_acc_pvt_t *px_pvt = (px_config_acc_pvt_t *)
- handle->ahi_common.ah_bus_private;
+ px_config_acc_pvt_t *px_pvt = (px_config_acc_pvt_t *)
+ handle->ahi_common.ah_bus_private;
uint32_t pci_dev_addr = px_pvt->raddr;
uint32_t vaddr = px_pvt->vaddr;
uint16_t off = (uint16_t)(uintptr_t)(addr - vaddr) & 0xfff;
if (px_lib_config_put(px_pvt->dip, pci_dev_addr, off,
- size, wdata) != DDI_SUCCESS) {
+ size, wdata) != DDI_SUCCESS) {
/*EMPTY*/
/* XXX update error kstats */
}
@@ -1187,7 +1187,7 @@ px_pci_config_get64(ddi_acc_impl_t *handle, uint64_t *addr)
rdatal = (uint32_t)px_pci_config_get(handle, (uint32_t *)addr, 4);
rdatah = (uint32_t)px_pci_config_get(handle,
- (uint32_t *)((char *)addr+4), 4);
+ (uint32_t *)((char *)addr+4), 4);
return (((uint64_t)rdatah << 32) | rdatal);
}
@@ -1367,6 +1367,9 @@ px_lib_map_vconfig(dev_info_t *dip,
ddi_map_req_t *mp, pci_config_offset_t off,
pci_regspec_t *rp, caddr_t *addrp)
{
+ int fmcap;
+ ndi_err_t *errp;
+ on_trap_data_t *otp;
ddi_acc_hdl_t *hp;
ddi_acc_impl_t *ap;
uchar_t busnum; /* bus number */
@@ -1379,7 +1382,7 @@ px_lib_map_vconfig(dev_info_t *dip,
/* Check for mapping teardown operation */
if ((mp->map_op == DDI_MO_UNMAP) ||
- (mp->map_op == DDI_MO_UNLOCK)) {
+ (mp->map_op == DDI_MO_UNLOCK)) {
/* free up memory allocated for the private access handle. */
px_pvt = (px_config_acc_pvt_t *)hp->ah_bus_private;
kmem_free((void *)px_pvt, sizeof (px_config_acc_pvt_t));
@@ -1388,6 +1391,17 @@ px_lib_map_vconfig(dev_info_t *dip,
return (DDI_SUCCESS);
}
+ fmcap = ddi_fm_capable(dip);
+ if (DDI_FM_ACC_ERR_CAP(fmcap)) {
+ errp = ((ddi_acc_impl_t *)hp)->ahi_err;
+ otp = (on_trap_data_t *)errp->err_ontrap;
+ otp->ot_handle = (void *)(hp);
+ otp->ot_prot = OT_DATA_ACCESS;
+ errp->err_status = DDI_FM_OK;
+ errp->err_expected = DDI_FM_ERR_UNEXPECTED;
+ errp->err_cf = px_err_cfg_hdl_check;
+ }
+
ap->ahi_get8 = px_pci_config_get8;
ap->ahi_get16 = px_pci_config_get16;
ap->ahi_get32 = px_pci_config_get32;
@@ -1412,7 +1426,7 @@ px_lib_map_vconfig(dev_info_t *dip,
/* allocate memory for our private handle */
px_pvt = (px_config_acc_pvt_t *)
- kmem_zalloc(sizeof (px_config_acc_pvt_t), KM_SLEEP);
+ kmem_zalloc(sizeof (px_config_acc_pvt_t), KM_SLEEP);
hp->ah_bus_private = (void *)px_pvt;
busnum = PCI_REG_BUS_G(rp->pci_phys_hi);
@@ -1436,7 +1450,7 @@ px_lib_map_vconfig(dev_info_t *dip,
px_pvt->dip = dip;
DBG(DBG_LIB_CFG, dip, "px_config_setup: raddr 0x%x, vaddr 0x%x\n",
- px_pvt->raddr, px_pvt->vaddr);
+ px_pvt->raddr, px_pvt->vaddr);
*addrp = (caddr_t)(uintptr_t)px_pvt->vaddr;
return (DDI_SUCCESS);
}
@@ -1494,20 +1508,12 @@ px_lib_log_safeacc_err(px_t *px_p, ddi_acc_handle_t handle, int fme_flag,
}
}
- mutex_enter(&px_p->px_fm_mutex);
+ px_rp_en_q(px_p, bdf, addr, NULL);
- if (!px_lib_is_in_drain_state(px_p)) {
- /*
- * This is to ensure that device corresponding to the addr of
- * the failed PIO/CFG load gets scanned.
- */
- px_rp_en_q(px_p, bdf, addr,
- (PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB));
- (void) pf_scan_fabric(px_p->px_dip, &derr,
- px_p->px_dq_p, &px_p->px_dq_tail);
+ if (px_fm_enter(px_p) == DDI_SUCCESS) {
+ (void) px_scan_fabric(px_p, px_p->px_dip, &derr);
+ px_fm_exit(px_p);
}
-
- mutex_exit(&px_p->px_fm_mutex);
}