git: 5b4a7fd9378a - main - e1000: Handle I354 internal memory errors
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 29 Aug 2026 02:02:53 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=5b4a7fd9378abba882a87330af31351c6353aea7
commit 5b4a7fd9378abba882a87330af31351c6353aea7
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-28 12:37:35 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-29 02:01:59 +0000
e1000: Handle I354 internal memory errors
The Atom C2000 integrated GbE programming reference documents the I354
internal memory error architecture. It shares the I350 PEIND and
ICR.FER routing, DMA and packet-buffer status, LAN parity status, and
required reset recovery.
Extend the existing I350 recovery and corrected error accounting paths
to I354. Keep the PCIe corrected error mask family-specific. C2000
PCIEECCSTS ends at the transmit write-data indication in bit 4 and does
not implement the I350 retry buffer indication in bit 5. Do not expose
the corresponding retry counter on I354.
The PRM overview says a PCIe region failure requires a system reboot,
while the individual PCIEERRSTS fields prescribe CTRL.RST followed by
port reinitialization. Use the register specific recovery, matching the
existing I350 path; failed reinitialization still leaves the port down.
This follows sections 5.6 and 6.21 of the Intel Atom Processor C2000
Product Family Integrated GbE Controller Programmer's Reference Manual,
document 537426 revision 1.5.
MFC after: 2 weeks
Sponsored by: BBOX.io
---
sys/dev/e1000/e1000_defines.h | 18 ++++++-----
sys/dev/e1000/if_em.c | 75 +++++++++++++++++++++++--------------------
2 files changed, 50 insertions(+), 43 deletions(-)
diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index 371fee155dd0..21f54e15b9a7 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -535,7 +535,7 @@
#define E1000_ECC_82575_UNCORR_CNT_SHIFT 8
#define E1000_ECC_82575_ENABLE 0x00010000
-/* I350 and I210/I211 memory error status bits. */
+/* I350, I354, and I210/I211 memory error status bits. */
#define E1000_PEIND_LANPORT_PARITY_FATAL 0x00000001
#define E1000_PEIND_MNG_PARITY_FATAL 0x00000002
#define E1000_PEIND_PCIE_PARITY_FATAL 0x00000004
@@ -572,12 +572,14 @@
#define E1000_PBECCSTS_I210_CORR_ERR 0x00000004
#define E1000_PCIEERRSTS_I210_FATAL_MASK 0x00000078
-#define E1000_PCIEERRSTS_I350_FATAL_MASK 0x0000007C
+#define E1000_PCIEERRSTS_I350_I354_FATAL_MASK 0x0000007C
#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_I354_OTHER_MASK 0x0000000F
#define E1000_PCIEECCSTS_I350_CORR_MASK 0x0000003F
+/* I354 has no I350-style PCIe retry-buffer status bit. */
+#define E1000_PCIEECCSTS_I354_CORR_MASK 0x0000001F
#define E1000_DTPARS_CORR_MASK 0x0000005B
#define E1000_DTPARS_FATAL_MASK 0x00000020
@@ -585,13 +587,13 @@
#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_PBECCSTS_I350_I354_ENABLE_MASK 0x00030000
+#define E1000_PBECCSTS_I350_I354_CORR_MASK 0x14000000
#define E1000_LANPERRSTS_RETX_BUF 0x00000200
-#define E1000_LANPERRSTS_I350_NO_RESET_MASK 0x00008400
-#define E1000_LANPERRSTS_I350_RESET_MASK 0x00007BFE
-#define E1000_LANPERRSTS_I350_FATAL_MASK 0x0000FFFE
+#define E1000_LANPERRSTS_I350_I354_NO_RESET_MASK 0x00008400
+#define E1000_LANPERRSTS_I350_I354_RESET_MASK 0x00007BFE
+#define E1000_LANPERRSTS_I350_I354_FATAL_MASK 0x0000FFFE
#define IFS_MAX 80
#define IFS_MIN 40
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 082549767315..de1b513f1040 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -2360,10 +2360,11 @@ em_has_i210_memory_errors(const struct e1000_hw *hw)
}
static bool
-em_has_i350_memory_errors(const struct e1000_hw *hw)
+em_has_i350_i354_memory_errors(const struct e1000_hw *hw)
{
- return (hw->mac.type == e1000_i350);
+ return (hw->mac.type == e1000_i350 ||
+ hw->mac.type == e1000_i354);
}
static void
@@ -2373,7 +2374,7 @@ em_configure_peind_memory_errors(struct e1000_softc *sc)
u32 peindm;
hw = &sc->hw;
- if (!em_has_i350_memory_errors(hw) &&
+ if (!em_has_i350_i354_memory_errors(hw) &&
!em_has_i210_memory_errors(hw))
return;
@@ -2391,7 +2392,7 @@ em_has_peind_memory_errors(const struct e1000_hw *hw)
{
return (em_has_82580_memory_errors(hw) ||
- em_has_i350_memory_errors(hw) ||
+ em_has_i350_i354_memory_errors(hw) ||
em_has_i210_memory_errors(hw));
}
@@ -2401,8 +2402,8 @@ em_pcie_fatal_error_mask(const struct e1000_hw *hw)
if (em_has_82580_memory_errors(hw))
return (~0U);
- if (em_has_i350_memory_errors(hw))
- return (E1000_PCIEERRSTS_I350_FATAL_MASK);
+ if (em_has_i350_i354_memory_errors(hw))
+ return (E1000_PCIEERRSTS_I350_I354_FATAL_MASK);
if (em_has_i210_memory_errors(hw))
return (E1000_PCIEERRSTS_I210_FATAL_MASK);
return (0);
@@ -2589,10 +2590,10 @@ em_update_i210_ecc_stats(struct e1000_softc *sc)
}
static void
-em_update_i350_ecc_stats(struct e1000_softc *sc)
+em_update_i350_i354_ecc_stats(struct e1000_softc *sc)
{
struct e1000_hw *hw;
- u32 pbeccsts, status;
+ u32 pbeccsts, pcieecc_mask, status;
hw = &sc->hw;
status = E1000_READ_REG(hw, E1000_DTPARS) &
@@ -2615,31 +2616,33 @@ em_update_i350_ecc_stats(struct e1000_softc *sc)
}
pbeccsts = E1000_READ_REG(hw, E1000_RPBECCSTS);
- status = pbeccsts & E1000_PBECCSTS_I350_CORR_MASK;
+ status = pbeccsts & E1000_PBECCSTS_I350_I354_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_PBECCSTS_I350_I354_ENABLE_MASK |
+ E1000_PBECCSTS_I350_I354_CORR_MASK));
}
pbeccsts = E1000_READ_REG(hw, E1000_TPBECCSTS);
- status = pbeccsts & E1000_PBECCSTS_I350_CORR_MASK;
+ status = pbeccsts & E1000_PBECCSTS_I350_I354_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));
+ pbeccsts & (E1000_PBECCSTS_I350_I354_ENABLE_MASK |
+ E1000_PBECCSTS_I350_I354_CORR_MASK));
}
- status = E1000_READ_REG(hw, E1000_PCIEECCSTS) &
+ pcieecc_mask = hw->mac.type == e1000_i354 ?
+ E1000_PCIEECCSTS_I354_CORR_MASK :
E1000_PCIEECCSTS_I350_CORR_MASK;
+ status = E1000_READ_REG(hw, E1000_PCIEECCSTS) & pcieecc_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);
+ E1000_PCIEECCSTS_I350_I354_OTHER_MASK);
if (status != 0)
E1000_WRITE_REG(hw, E1000_PCIEECCSTS, status);
}
@@ -2698,13 +2701,13 @@ em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr)
E1000_DDPARS_82580);
lanerr = E1000_READ_REG(hw, E1000_LANPERRSTS) &
E1000_LANPERRSTS_82580_ERROR_MASK;
- } else if (em_has_i350_memory_errors(hw)) {
+ } else if (em_has_i350_i354_memory_errors(hw)) {
dma_tx = E1000_READ_REG(hw, E1000_DTPARS) &
E1000_DTPARS_FATAL_MASK;
dma_rx = E1000_READ_REG(hw, E1000_DRPARS) &
E1000_DRPARS_FATAL_MASK;
lanerr = E1000_READ_REG(hw, E1000_LANPERRSTS) &
- E1000_LANPERRSTS_I350_FATAL_MASK;
+ E1000_LANPERRSTS_I350_I354_FATAL_MASK;
} else {
dma_tx = 0;
dma_rx = 0;
@@ -2836,19 +2839,19 @@ em_handle_fatal_error_admin(struct e1000_softc *sc)
if (peind == 0)
reset_required = true;
if (peind & E1000_PEIND_LANPORT_PARITY_FATAL) {
- if (!em_has_i350_memory_errors(&sc->hw) ||
+ if (!em_has_i350_i354_memory_errors(&sc->hw) ||
sc->fatal_error_lan == 0 ||
(sc->fatal_error_lan &
- E1000_LANPERRSTS_I350_RESET_MASK) != 0)
+ E1000_LANPERRSTS_I350_I354_RESET_MASK) != 0)
reset_required = true;
}
/* Management-memory recovery belongs to management firmware. */
if (!reset_required) {
- if (em_has_i350_memory_errors(&sc->hw) &&
+ if (em_has_i350_i354_memory_errors(&sc->hw) &&
sc->fatal_error_lan != 0)
E1000_WRITE_REG(&sc->hw, E1000_LANPERRSTS,
sc->fatal_error_lan &
- E1000_LANPERRSTS_I350_NO_RESET_MASK);
+ E1000_LANPERRSTS_I350_I354_NO_RESET_MASK);
sc->fatal_error_peind = 0;
sc->fatal_error_pcie = 0;
sc->fatal_error_pcie_ecc = 0;
@@ -2874,11 +2877,11 @@ em_handle_fatal_error_admin(struct e1000_softc *sc)
}
/*
- * A PCIe-region parity failure stops PCIe and DMA traffic. I350, I210, and
- * I211 require a port reset before master disable in this case. 82580 stops
- * 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.
+ * A PCIe-region parity failure stops PCIe and DMA traffic. I350, I354,
+ * I210, and I211 require a port reset before master disable in this case.
+ * 82580 stops 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.
@@ -3004,7 +3007,7 @@ em_finish_fatal_error_reset(struct e1000_softc *sc)
em_pcie_fatal_error_mask(hw));
if (pcieerr != 0)
E1000_WRITE_REG(hw, E1000_PCIEERRSTS, pcieerr);
- if (em_has_i350_memory_errors(hw)) {
+ if (em_has_i350_i354_memory_errors(hw)) {
dma_tx = sc->fatal_error_dma_tx |
(E1000_READ_REG(hw, E1000_DTPARS) &
E1000_DTPARS_FATAL_MASK);
@@ -3017,7 +3020,7 @@ em_finish_fatal_error_reset(struct e1000_softc *sc)
E1000_WRITE_REG(hw, E1000_DRPARS, dma_rx);
lanerr = sc->fatal_error_lan |
(E1000_READ_REG(hw, E1000_LANPERRSTS) &
- E1000_LANPERRSTS_I350_FATAL_MASK);
+ E1000_LANPERRSTS_I350_I354_FATAL_MASK);
} else {
lanerr = sc->fatal_error_lan |
(E1000_READ_REG(hw, E1000_LANPERRSTS) &
@@ -6631,8 +6634,8 @@ em_update_stats_counters(struct e1000_softc *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_i350_i354_memory_errors(&sc->hw))
+ em_update_i350_i354_ecc_stats(sc);
else if (em_has_i210_memory_errors(&sc->hw))
em_update_i210_ecc_stats(sc);
}
@@ -7180,10 +7183,12 @@ em_add_hw_stats(struct e1000_softc *sc)
"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");
+ if (sc->hw.mac.type == e1000_i350)
+ 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,