diff options
author | krishnae <none@none> | 2008-03-28 12:11:52 -0700 |
---|---|---|
committer | krishnae <none@none> | 2008-03-28 12:11:52 -0700 |
commit | eae2e508a8e70b1ec407b10bd068c080651bbe5c (patch) | |
tree | 997c76ef99a46a31e13e027aae4085ea65f05e1d | |
parent | c45cbb52ab3d9544ffb196de6b0a1c5f332c93a4 (diff) | |
download | illumos-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
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, ®len) != DDI_SUCCESS) - return (DDI_ME_RNUMBER_RANGE); + "reg", (caddr_t)&rp, ®len) != 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); } |