git: 8367882d5313 - main - e1000: Report corrected I350 ECC errors
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 16 Aug 2026 09:44:50 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=8367882d531313eea68966b07ddf917e39690b77
commit 8367882d531313eea68966b07ddf917e39690b77
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-12 23:35:43 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-16 09:43:44 +0000
e1000: Report corrected I350 ECC errors
I350 does not interrupt for corrected internal ECC errors. Instead,
the PCIe, DMA, packet buffer, loopback, and management memories expose
sticky status bits in their region-specific status registers.
Sample those bits with the regular hardware statistics update, preserve
the RX and TX packet buffer ECC enable state while clearing RW1C
indications, and expose counters grouped by memory region. Each counter
records observed indication bits rather than exact error counts because
repeated corrections between samples collapse into one sticky bit.
On an I350 (8086:1521 revision 1), the ECC enables remained set. All
corrected-error status registers remained clear across boot, interface
down/up, three FER recovery resets, and bidirectional line-rate traffic.
The device has no documented corrected error injector. Therefore, the
per-region paths were validated against the register definitions rather
than an injected SRAM error.
MFC after: 2 weeks
Sponsored by: BBOX.io
---
sys/dev/e1000/e1000_defines.h | 8 +++++
sys/dev/e1000/e1000_regs.h | 3 ++
sys/dev/e1000/if_em.c | 79 +++++++++++++++++++++++++++++++++++++++++++
sys/dev/e1000/if_em.h | 1 +
4 files changed, 91 insertions(+)
diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index da06481be7de..761ce02d06af 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -543,9 +543,17 @@
#define E1000_PCIEECCSTS_TX_WR_DATA 0x00000010
#define E1000_PCIEECCSTS_RETRY_BUF 0x00000020
#define E1000_PCIEECCSTS_I210_CORR_MASK 0x00000030
+#define E1000_PCIEECCSTS_I350_OTHER_MASK 0x0000000F
+#define E1000_PCIEECCSTS_I350_CORR_MASK 0x0000003F
+#define E1000_DTPARS_CORR_MASK 0x0000005B
#define E1000_DTPARS_FATAL_MASK 0x00000020
+#define E1000_DRPARS_CORR_MASK 0x0000000D
#define E1000_DRPARS_FATAL_MASK 0x00000002
+#define E1000_DDECCS_CORR_MASK 0x0000000F
+
+#define E1000_PBECCSTS_I350_ENABLE_MASK 0x00030000
+#define E1000_PBECCSTS_I350_CORR_MASK 0x14000000
#define E1000_LANPERRSTS_RETX_BUF 0x00000200
#define E1000_LANPERRSTS_I350_NO_RESET_MASK 0x00008400
diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h
index d2ac267f0be9..ec5df9ad774d 100644
--- a/sys/dev/e1000/e1000_regs.h
+++ b/sys/dev/e1000/e1000_regs.h
@@ -695,8 +695,11 @@
#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
/* Memory error status registers */
+#define E1000_RPBECCSTS 0x0245C /* Rx Packet Buffer ECC Status - RW */
+#define E1000_TPBECCSTS 0x0345C /* Tx Packet Buffer ECC Status - RW */
#define E1000_DTPARS 0x03F10 /* DMA Tx Parity and ECC Status - RW1C */
#define E1000_DRPARS 0x03F14 /* DMA Rx Parity and ECC Status - RW1C */
+#define E1000_DDECCS 0x03F18 /* DMA Host ECC Status - RW1C */
#define E1000_PCIEERRSTS 0x05BA8 /* PCIe Parity Status - RW1C */
#define E1000_PCIEECCSTS 0x05BAC /* PCIe ECC Status - RW1C */
#define E1000_LANPERRSTS 0x05F58 /* LAN Port Parity Status - RW1C */
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 263bdd48a871..e29b34116b5d 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -2283,6 +2283,62 @@ em_update_i210_ecc_stats(struct e1000_softc *sc)
E1000_WRITE_REG(hw, E1000_PCIEECCSTS, pcieeccsts);
}
+static void
+em_update_i350_ecc_stats(struct e1000_softc *sc)
+{
+ struct e1000_hw *hw;
+ u32 pbeccsts, status;
+
+ hw = &sc->hw;
+ status = E1000_READ_REG(hw, E1000_DTPARS) &
+ E1000_DTPARS_CORR_MASK;
+ if (status != 0) {
+ sc->corrected_error_dma_count += bitcount32(status);
+ E1000_WRITE_REG(hw, E1000_DTPARS, status);
+ }
+ status = E1000_READ_REG(hw, E1000_DRPARS) &
+ E1000_DRPARS_CORR_MASK;
+ if (status != 0) {
+ sc->corrected_error_dma_count += bitcount32(status);
+ E1000_WRITE_REG(hw, E1000_DRPARS, status);
+ }
+ status = E1000_READ_REG(hw, E1000_DDECCS) &
+ E1000_DDECCS_CORR_MASK;
+ if (status != 0) {
+ sc->corrected_error_dma_count += bitcount32(status);
+ E1000_WRITE_REG(hw, E1000_DDECCS, status);
+ }
+
+ pbeccsts = E1000_READ_REG(hw, E1000_RPBECCSTS);
+ status = pbeccsts & E1000_PBECCSTS_I350_CORR_MASK;
+ if (status != 0) {
+ sc->corrected_error_packet_buffer_count += bitcount32(status);
+ /* Preserve the enable bits while clearing RW1C status. */
+ E1000_WRITE_REG(hw, E1000_RPBECCSTS,
+ pbeccsts & (E1000_PBECCSTS_I350_ENABLE_MASK |
+ E1000_PBECCSTS_I350_CORR_MASK));
+ }
+ pbeccsts = E1000_READ_REG(hw, E1000_TPBECCSTS);
+ status = pbeccsts & E1000_PBECCSTS_I350_CORR_MASK;
+ if (status != 0) {
+ sc->corrected_error_packet_buffer_count += bitcount32(status);
+ E1000_WRITE_REG(hw, E1000_TPBECCSTS,
+ pbeccsts & (E1000_PBECCSTS_I350_ENABLE_MASK |
+ E1000_PBECCSTS_I350_CORR_MASK));
+ }
+
+ status = E1000_READ_REG(hw, E1000_PCIEECCSTS) &
+ E1000_PCIEECCSTS_I350_CORR_MASK;
+ if (status & E1000_PCIEECCSTS_TX_WR_DATA)
+ sc->corrected_error_pcie_tx_data_count++;
+ if (status & E1000_PCIEECCSTS_RETRY_BUF)
+ sc->corrected_error_pcie_retry_count++;
+ sc->corrected_error_pcie_other_count += bitcount32(status &
+ E1000_PCIEECCSTS_I350_OTHER_MASK);
+ if (status != 0)
+ E1000_WRITE_REG(hw, E1000_PCIEECCSTS, status);
+}
+
/*
* Fatal internal-memory errors stop part or all of the MAC. Capture the
* read-clear indication before handing recovery to the iflib admin task.
@@ -6066,6 +6122,8 @@ em_update_stats_counters(struct e1000_softc *sc)
if (em_has_pch_ecc(&sc->hw))
em_update_pch_ecc_stats(sc,
E1000_READ_REG(&sc->hw, E1000_PBECCSTS));
+ else if (em_has_i350_memory_errors(&sc->hw))
+ em_update_i350_ecc_stats(sc);
else if (em_has_i210_memory_errors(&sc->hw))
em_update_i210_ecc_stats(sc);
}
@@ -6536,6 +6594,27 @@ em_add_hw_stats(struct e1000_softc *sc)
"corrected_pcie_retry", CTLFLAG_RD,
&sc->corrected_error_pcie_retry_count,
"Corrected PCIe retry-buffer memory indications");
+ } else {
+ SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+ "corrected_dma", CTLFLAG_RD,
+ &sc->corrected_error_dma_count,
+ "Corrected DMA memory indications");
+ SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+ "corrected_packet_buffer", CTLFLAG_RD,
+ &sc->corrected_error_packet_buffer_count,
+ "Corrected packet-buffer memory indications");
+ SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+ "corrected_pcie_tx_data", CTLFLAG_RD,
+ &sc->corrected_error_pcie_tx_data_count,
+ "Corrected PCIe transmit-data memory indications");
+ SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+ "corrected_pcie_retry", CTLFLAG_RD,
+ &sc->corrected_error_pcie_retry_count,
+ "Corrected PCIe retry-buffer memory indications");
+ SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO,
+ "corrected_pcie_other", CTLFLAG_RD,
+ &sc->corrected_error_pcie_other_count,
+ "Other corrected PCIe memory indications");
}
}
}
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
index ccb23afb48a2..3273d4c6b7fe 100644
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -640,6 +640,7 @@ struct e1000_softc {
u64 corrected_error_dma_count;
u64 corrected_error_pcie_tx_data_count;
u64 corrected_error_pcie_retry_count;
+ u64 corrected_error_pcie_other_count;
u64 corrected_error_packet_buffer_count;
u64 uncorrected_error_packet_buffer_count;