git: 915c628c4f49 - main - igb: Report 82580 memory ECC errors

Kevin Bowling <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a8a6bde.1c32e.170caa7__28464.0012470604$1787456495$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=915c628c4f49b267c8a713b79c4a8b157092d717

commit 915c628c4f49b267c8a713b79c4a8b157092d717
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-16 05:49:56 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-23 03:34:23 +0000

    igb: Report 82580 memory ECC errors
    
    82580 exposes clear-on-read, saturating corrected error counters for
    the receive and transmit packet buffers.  Its two PCIe command memories
    expose RW1C indications for uncorrectable ECC errors.
    
    Sample the packet buffer counters and PCIe indications from the regular
    hardware statistics update.  Fatal recovery samples the PCIe indications
    from the serialized admin path rather than the interrupt filter.  Thus,
    either the regular statistics pass or recovery reads and clears each
    indication, but they cannot both account it.  Also preserve indications
    observed while initialization is completing.
    
    Expose the exact packet buffer error total and observed PCIe command
    memory indications under the memory_errors sysctl node.  Multiple PCIe
    errors between samples can collapse into one indication per memory.
    
    Validated on an Intel I340-T2 (82580, revision 1).  A clean boot and
    three down/up cycles left the packet-buffer, PCIe, and region-specific
    counters at zero.  Synthetic ICS.FER events advanced fatal_unknown and
    fatal_resets exactly once on the targeted function without changing the
    sibling or ECC counters.
    
    The 82580 datasheet exposes no ECC or parity error injection register,
    so corrected packet buffer and PCIe ECC accounting could not be forced
    independently.
    
    MFC after:      2 weeks
    Sponsored by:   BBOX.io
---
 sys/dev/e1000/e1000_defines.h |  1 +
 sys/dev/e1000/if_em.c         | 68 +++++++++++++++++++++++++++++++++++--------
 sys/dev/e1000/if_em.h         |  1 +
 3 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index 56c9418b2419..371fee155dd0 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -553,6 +553,7 @@
 #define E1000_PCIEECCSTS_82580_ERROR_MASK	0x00000003
 #define E1000_LANPERRSTS_82580_ERROR_MASK	0x00007FFF
 #define E1000_PBECCSTS_82580_ECC_ENABLE		0x00010000
+#define E1000_PBECCSTS_82580_CORR_CNT_MASK	0x000000FF
 
 /* 82576 uses PEIND directly rather than the later four-region layout. */
 #define E1000_PEIND_82576_NONFATAL_MASK	0x00000007
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 95f50c6694a6..aeb38fd4fb10 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -462,6 +462,8 @@ static void	em_finish_fatal_error_reset(struct e1000_softc *);
 static void	em_configure_peind_memory_errors(struct e1000_softc *);
 static void	em_configure_82575_memory_errors(struct e1000_softc *);
 static void	em_configure_82580_memory_errors(struct e1000_softc *);
+static void	em_update_82580_ecc_stats(struct e1000_softc *, u32, u32,
+		    u32);
 static void	em_if_multi_set(if_ctx_t);
 static void	em_if_update_admin_status(if_ctx_t);
 static void	em_if_debug(if_ctx_t);
@@ -2303,10 +2305,11 @@ em_configure_82580_memory_errors(struct e1000_softc *sc)
 	em_clear_82580_memory_error_status(hw, E1000_DRPARS_82580);
 	em_clear_82580_memory_error_status(hw, E1000_DDPARS_82580);
 	em_clear_82580_memory_error_status(hw, E1000_PCIEERRSTS);
-	em_clear_82580_memory_error_status(hw, E1000_PCIEECCSTS);
 	(void)E1000_READ_REG(hw, E1000_LANPERRSTS);
-	(void)E1000_READ_REG(hw, E1000_RPBECCSTS);
-	(void)E1000_READ_REG(hw, E1000_TPBECCSTS);
+	em_update_82580_ecc_stats(sc,
+	    E1000_READ_REG(hw, E1000_RPBECCSTS),
+	    E1000_READ_REG(hw, E1000_TPBECCSTS),
+	    E1000_READ_REG(hw, E1000_PCIEECCSTS));
 	E1000_WRITE_REG(hw, E1000_RPBECCSTS,
 	    E1000_PBECCSTS_82580_ECC_ENABLE);
 	E1000_WRITE_REG(hw, E1000_TPBECCSTS,
@@ -2434,6 +2437,21 @@ em_fatal_error_intr_mask(struct e1000_softc *sc)
 	return (em_memory_error_intr_mask(&sc->hw));
 }
 
+static void
+em_update_82580_ecc_stats(struct e1000_softc *sc, u32 rpbeccsts,
+    u32 tpbeccsts, u32 pcieeccsts)
+{
+	u32 status;
+
+	sc->corrected_error_packet_buffer_count +=
+	    (rpbeccsts & E1000_PBECCSTS_82580_CORR_CNT_MASK) +
+	    (tpbeccsts & E1000_PBECCSTS_82580_CORR_CNT_MASK);
+	status = pcieeccsts & E1000_PCIEECCSTS_82580_ERROR_MASK;
+	sc->uncorrected_error_pcie_count += bitcount32(status);
+	if (status != 0)
+		E1000_WRITE_REG(&sc->hw, E1000_PCIEECCSTS, status);
+}
+
 static void
 em_update_82575_ecc_stats(struct e1000_softc *sc, u32 pbeccsts,
     u32 rdhests, u32 tdhests)
@@ -2625,8 +2643,7 @@ static void
 em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr)
 {
 	struct e1000_hw *hw;
-	u32 dma_host, dma_rx, dma_tx, error_mask, lanerr, pcieecc;
-	u32 pcieerr, peind;
+	u32 dma_host, dma_rx, dma_tx, error_mask, lanerr, pcieerr, peind;
 
 	error_mask = em_memory_error_intr_mask(&sc->hw);
 	if (!em_has_memory_errors(&sc->hw) ||
@@ -2657,7 +2674,6 @@ em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr)
 		    E1000_PEIND_FATAL_MASK;
 		pcieerr = E1000_READ_REG(hw, E1000_PCIEERRSTS) &
 		    em_pcie_fatal_error_mask(hw);
-		pcieecc = 0;
 		dma_host = 0;
 		if (em_has_82580_memory_errors(hw)) {
 			/*
@@ -2667,8 +2683,6 @@ em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr)
 			 * status registers.
 			 */
 			peind &= E1000_PEIND_MNG_PARITY_FATAL;
-			pcieecc = E1000_READ_REG(hw, E1000_PCIEECCSTS) &
-			    E1000_PCIEECCSTS_82580_ERROR_MASK;
 			dma_tx = E1000_READ_REG(hw, E1000_DTPARS_82580);
 			dma_rx = E1000_READ_REG(hw, E1000_DRPARS_82580);
 			dma_host = E1000_READ_REG(hw,
@@ -2688,7 +2702,7 @@ em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr)
 			lanerr = E1000_READ_REG(hw, E1000_LANPERRSTS) &
 			    E1000_LANPERRSTS_RETX_BUF;
 		}
-		if (pcieerr != 0 || pcieecc != 0)
+		if (pcieerr != 0)
 			peind |= E1000_PEIND_PCIE_PARITY_FATAL;
 		if (lanerr != 0)
 			peind |= E1000_PEIND_LANPORT_PARITY_FATAL;
@@ -2696,7 +2710,6 @@ em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr)
 			peind |= E1000_PEIND_DMA_PARITY_FATAL;
 		sc->fatal_error_peind = peind;
 		sc->fatal_error_pcie = pcieerr;
-		sc->fatal_error_pcie_ecc = pcieecc;
 		sc->fatal_error_lan = lanerr;
 		sc->fatal_error_dma_tx = dma_tx;
 		sc->fatal_error_dma_rx = dma_rx;
@@ -2710,7 +2723,7 @@ em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr)
 static bool
 em_handle_fatal_error_admin(struct e1000_softc *sc)
 {
-	u32 error_mask, peind;
+	u32 error_mask, pcieecc, peind;
 	bool reset_required;
 
 	if (!atomic_cmpset_acq_32(&sc->fatal_error_state,
@@ -2761,6 +2774,20 @@ em_handle_fatal_error_admin(struct e1000_softc *sc)
 		    "requesting reset\n", peind);
 	} else {
 		peind = sc->fatal_error_peind;
+		if (em_has_82580_memory_errors(&sc->hw)) {
+			pcieecc = E1000_READ_REG(&sc->hw,
+			    E1000_PCIEECCSTS) &
+			    E1000_PCIEECCSTS_82580_ERROR_MASK;
+			sc->fatal_error_pcie_ecc |= pcieecc;
+			if (pcieecc != 0) {
+				peind |= E1000_PEIND_PCIE_PARITY_FATAL;
+				sc->fatal_error_peind = peind;
+			}
+			em_update_82580_ecc_stats(sc,
+			    E1000_READ_REG(&sc->hw, E1000_RPBECCSTS),
+			    E1000_READ_REG(&sc->hw, E1000_TPBECCSTS),
+			    pcieecc);
+		}
 		if (peind & E1000_PEIND_LANPORT_PARITY_FATAL)
 			sc->fatal_error_lan_count++;
 		if (peind & E1000_PEIND_MNG_PARITY_FATAL)
@@ -2843,6 +2870,9 @@ em_handle_fatal_error_admin(struct e1000_softc *sc)
  * PCIe traffic for a fatal error in any host-owned region, so use the same
  * order for every 82580 recovery.  This differs from the normal reset path,
  * which disables the bus master first.
+ *
+ * Indications that relatch after admin accounting are discarded during
+ * reset; sticky bits cannot distinguish them from the saved event.
  */
 static void
 em_prepare_fatal_error_reset(struct e1000_softc *sc)
@@ -6587,6 +6617,11 @@ em_update_stats_counters(struct e1000_softc *sc)
 		    E1000_READ_REG(&sc->hw, E1000_TDHESTS_82575));
 	else if (em_has_82576_memory_errors(&sc->hw))
 		em_update_82576_ecc_stats(sc);
+	else if (em_has_82580_memory_errors(&sc->hw))
+		em_update_82580_ecc_stats(sc,
+		    E1000_READ_REG(&sc->hw, E1000_RPBECCSTS),
+		    E1000_READ_REG(&sc->hw, E1000_TPBECCSTS),
+		    E1000_READ_REG(&sc->hw, E1000_PCIEECCSTS));
 	else if (em_has_i350_memory_errors(&sc->hw))
 		em_update_i350_ecc_stats(sc);
 	else if (em_has_i210_memory_errors(&sc->hw))
@@ -7101,7 +7136,16 @@ em_add_hw_stats(struct e1000_softc *sc)
 			    "fatal_unknown", CTLFLAG_RD,
 			    &sc->fatal_error_unknown_count,
 			    "Fatal memory errors without a reported region");
-			if (em_has_i210_memory_errors(&sc->hw)) {
+			if (em_has_82580_memory_errors(&sc->hw)) {
+				SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+				    "corrected_packet_buffer", CTLFLAG_RD,
+				    &sc->corrected_error_packet_buffer_count,
+				    "Corrected packet-buffer ECC errors");
+				SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+				    "uncorrected_pcie", CTLFLAG_RD,
+				    &sc->uncorrected_error_pcie_count,
+				    "Uncorrected PCIe command-memory ECC indications");
+			} else if (em_has_i210_memory_errors(&sc->hw)) {
 				SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
 				    "corrected_dma", CTLFLAG_RD,
 				    &sc->corrected_error_dma_count,
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
index 0901c1ce5780..d4d2b3db9457 100644
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -648,6 +648,7 @@ struct e1000_softc {
 	u64			corrected_error_packet_buffer_count;
 	u64			uncorrected_error_packet_buffer_count;
 	u64			uncorrected_error_dma_count;
+	u64			uncorrected_error_pcie_count;
 
 #ifdef PCI_IOV
 	struct igb_vf		*vfs;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.