git: 61b2ea4b897c - stable/15 - e1000: Report 82571 packet buffer ECC errors

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Thu, 03 Sep 2026 00:53:36 UTC
The branch stable/15 has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=61b2ea4b897c03e15511afc277c498dde6874a55

commit 61b2ea4b897c03e15511afc277c498dde6874a55
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-16 07:11:57 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-03 00:53:13 +0000

    e1000: Report 82571 packet buffer ECC errors
    
    The 82571 PBA_ECC register contains a 12-bit count of packet buffer ECC
    detections.  The shared code enables single-bit correction, but neither
    FreeBSD nor the DPDK base driver consumes the counter.
    
    Sample it with the ordinary statistics timer, accumulate the value under
    dev.em.N.memory_errors.detected_packet_buffer, and clear the hardware
    counter while preserving correction and reserved register state.  Do not
    enable its shared interrupt: the register does not distinguish corrected
    from uncorrectable events and does not provide a safe fatal recovery
    policy.
    
    Validated on a dual port 82571EB.  Both functions reported zero after a
    clean boot, and a controlled link down/up cycle left the counter at zero
    while the management link recovered at 1 Gb/s without issue.
    
    Sponsored by:   BBOX.io
    
    (cherry picked from commit aec0f1b85b54d14819747ed3364f366d21e76d88)
---
 sys/dev/e1000/if_em.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 47 insertions(+), 7 deletions(-)

diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 99495e93d265..6d7e3a63c435 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -1901,6 +1901,13 @@ em_has_pch_ecc(const struct e1000_hw *hw)
 	    hw->mac.type < e1000_82575);
 }
 
+static bool
+em_has_82571_ecc_stats(const struct e1000_hw *hw)
+{
+
+	return (hw->mac.type == e1000_82571);
+}
+
 static bool
 em_has_82575_memory_errors(const struct e1000_hw *hw)
 {
@@ -2047,6 +2054,13 @@ em_has_memory_errors(const struct e1000_hw *hw)
 	return (em_memory_error_intr_mask(hw) != 0);
 }
 
+static bool
+em_has_memory_error_stats(const struct e1000_hw *hw)
+{
+
+	return (em_has_82571_ecc_stats(hw) || em_has_memory_errors(hw));
+}
+
 static u32
 em_fatal_error_intr_mask(struct e1000_softc *sc)
 {
@@ -2141,6 +2155,24 @@ em_update_pch_ecc_stats(struct e1000_softc *sc, u32 pbeccsts)
 	    E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
 }
 
+static void
+em_update_82571_ecc_stats(struct e1000_softc *sc)
+{
+	struct e1000_hw *hw;
+	u32 count, pba_ecc;
+
+	hw = &sc->hw;
+	pba_ecc = E1000_READ_REG(hw, E1000_PBA_ECC);
+	count = (pba_ecc & E1000_PBA_ECC_COUNTER_MASK) >>
+	    E1000_PBA_ECC_COUNTER_SHIFT;
+	if (count == 0)
+		return;
+	sc->corrected_error_packet_buffer_count += count;
+	/* Preserve correction and reserved state while clearing statistics. */
+	E1000_WRITE_REG(hw, E1000_PBA_ECC,
+	    pba_ecc | E1000_PBA_ECC_STAT_CLR);
+}
+
 static void
 em_update_i210_ecc_stats(struct e1000_softc *sc)
 {
@@ -5828,7 +5860,9 @@ em_update_stats_counters(struct e1000_softc *sc)
 		E1000_READ_REG(&sc->hw, E1000_TSCTFC);
 	}
 
-	if (em_has_pch_ecc(&sc->hw))
+	if (em_has_82571_ecc_stats(&sc->hw))
+		em_update_82571_ecc_stats(sc);
+	else if (em_has_pch_ecc(&sc->hw))
 		em_update_pch_ecc_stats(sc,
 		    E1000_READ_REG(&sc->hw, E1000_PBECCSTS));
 	else if (em_has_82575_memory_errors(&sc->hw))
@@ -6145,7 +6179,7 @@ em_add_hw_stats(struct e1000_softc *sc)
 		SYSCTL_ADD_UQUAD(ctx, eee_list, OID_AUTO, "rx_lpi_count",
 		    CTLFLAG_RD, &stats->rlpic, "RX LPI event count");
 	}
-	if (em_has_memory_errors(&sc->hw)) {
+	if (em_has_memory_error_stats(&sc->hw)) {
 		struct sysctl_oid *memerr_node;
 		struct sysctl_oid_list *memerr_list;
 
@@ -6153,11 +6187,17 @@ em_add_hw_stats(struct e1000_softc *sc)
 		    "memory_errors", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
 		    "Internal memory error indications");
 		memerr_list = SYSCTL_CHILDREN(memerr_node);
-		SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
-		    "fatal_resets", CTLFLAG_RD,
-		    &sc->fatal_error_reset_count,
-		    "Resets requested for fatal internal memory errors");
-		if (em_has_pch_ecc(&sc->hw)) {
+		if (em_has_memory_errors(&sc->hw))
+			SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+			    "fatal_resets", CTLFLAG_RD,
+			    &sc->fatal_error_reset_count,
+			    "Resets requested for fatal internal memory errors");
+		if (em_has_82571_ecc_stats(&sc->hw)) {
+			SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+			    "detected_packet_buffer", CTLFLAG_RD,
+			    &sc->corrected_error_packet_buffer_count,
+			    "Detected packet-buffer ECC errors");
+		} else if (em_has_pch_ecc(&sc->hw)) {
 			SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
 			    "corrected_packet_buffer", CTLFLAG_RD,
 			    &sc->corrected_error_packet_buffer_count,