From nobody Sun Aug 16 10:02:32 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hNBNG18Lbz6nqHJ for ; Sun, 16 Aug 2026 10:02:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hNBNG0Dbfz3Ty9 for ; Sun, 16 Aug 2026 10:02:38 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786874558; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QhUzpCmm4pSvZkqx3XOpEa/a4x3IVj+xlFHCb/y6bp8=; b=YSzpxnwjU7HH+HzJrL/lJryg4OsMLHN6ocNs0+FvttUwT+S1as50AQwMRrXHL5oFegYCNq 3W+fBWryLMd0vjF13hblb3P8tdvagP80JoXZS3kiLunKEJCzOcLQBzJMkjgbajPHG1gazs zCfoiw84KYVK1DxyfVahVYkdPqpLY/vGXRm16YK5OmzXGX+PMHzKKEz5D4BPqQYcUbWvKk Jg12M3DIYhBSmhr0/c8yq08WQd9VImxdn39NGURlNXkMjpQEfKcv7tPaxzGoIv6TTPx+wi ByBy90qIHm8i9Rm3F9KhpXghkpqjygm9a5Q5QdzHeq4cv1Klj8IkHOZ5bM2BjA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786874558; a=rsa-sha256; cv=none; b=LlzjCofTdW89pkEx+j/A2W5cEQVqS7L5bXravIzo45bSVE5AdYpFKaTJgIvRdMbXgmOQrn p1XFQocNHFbG0GixVJWRkAh5+YFRvv/00zIADI7hVqDj1ubL/F4n4ikkUfbUkFp15/HP3O zZtATqTq5BASOdPGfw0fvowT/zJR8Q4/eGpFJmCWHIXgv06mdI5YShE20D+3pUo3rwmA81 PEeaiFwDa38XOf5LTioVoZhdxhWuFhBnLseN2og0djriibM/2rlMT2klf6Rr95JCPa9IKZ r/+Hl2pZNiZxpA/3UCxpenYK6B37ANI/tVVBfIJ/qpTePqsZUyRQ20RdsTkrpQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786874558; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QhUzpCmm4pSvZkqx3XOpEa/a4x3IVj+xlFHCb/y6bp8=; b=x4Oizr3txXlL1QX0Jc1Qdh6cBbLz4c1U9m7URtTFkGKYVPJykLhwqLtsHtdSTxp1sa3W5s kpX9n5eg5YrULaqDKltYadU5IJYTfPLM8MLZUSpuBp7a3ETcaFRfM2+28yxBmgavlBoL8Y lgHRjNyhQlPVJbRU7JUBGtlBnHZFtxI1SkAdiqSUoKBQ8v/VM6NmSFrI0xx53MFpHktLri qf5HYpEJFetf46pH0yKU38lo3hDW7mNlKgXzZx9p9PDHUA0SHEkkLFGqsktzoDua2I4GPg 94MFOuYt7xZaNBjtoYGNbr6BboBd/E8lBd+suqUR7oGJ6bzbvEm9mbBtdOoCwA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hNBNF69KPz7GH for ; Sun, 16 Aug 2026 10:02:37 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 24918 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 16 Aug 2026 10:02:32 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: 4c2dda4c70e2 - main - e1000: Recover from 82576 memory errors List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kbowling X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 4c2dda4c70e210be4efb4527fc32fbb79f23d452 Auto-Submitted: auto-generated Date: Sun, 16 Aug 2026 10:02:32 +0000 Message-Id: <6a818ab8.24918.52763d85@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=4c2dda4c70e210be4efb4527fc32fbb79f23d452 commit 4c2dda4c70e210be4efb4527fc32fbb79f23d452 Author: Kevin Bowling AuthorDate: 2026-08-13 23:10:47 +0000 Commit: Kevin Bowling CommitDate: 2026-08-16 10:01:33 +0000 e1000: Recover from 82576 memory errors 82576 reports fatal and non-fatal internal memory errors through ICR.FER and ICR.NFER and identifies the affected memory in its native PEIND layout. Fatal errors can stop transmit, receive, or both until software resets and reinitializes the port. Enable the controller-wide parity detector and implemented PEINDM reaction bits after hardware initialization, while preserving unrelated register state and omitting the absent IPsec memories on 82576NS. Enable both interrupt causes and capture the read-clear PEIND register in the interrupt filter. Keep the causes masked while the iflib admin task owns the event. Acknowledge non-fatal packet data errors without disrupting the port. Request normal port reinitialization for FER, a fatal PEIND source, or the memory hang indication. Do not apply the later I210/I350 register layout or their special PCIe parity reset order. Hardware validation used a dual-port 82576EB revision 1. Firmware left PEINDM at its 0x80000000 default; initialization explicitly programmed the parity-enable bit and produced 0xffffff07 on both ports. An NFER during two-stream TCP sustained line rate without a reset, watchdog, or carrier event. FER on the linked and disconnected ports each requested exactly one reset. The linked port resumed the existing TCP sessions after autonegotiation. PEINDM and both interrupt causes were restored after every reset. The injections set the ICR causes without corrupting SRAM, so their empty PEIND values deliberately exercised the unknown source path. MFC after: 2 weeks Sponsored by: BBOX.io --- sys/dev/e1000/e1000_defines.h | 10 ++++ sys/dev/e1000/if_em.c | 113 +++++++++++++++++++++++++++++++++++++----- sys/dev/e1000/if_em.h | 1 + 3 files changed, 112 insertions(+), 12 deletions(-) diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h index 761ce02d06af..cf23bbde846e 100644 --- a/sys/dev/e1000/e1000_defines.h +++ b/sys/dev/e1000/e1000_defines.h @@ -535,6 +535,14 @@ #define E1000_PEIND_DMA_PARITY_FATAL 0x00000008 #define E1000_PEIND_FATAL_MASK 0x0000000F +/* 82576 uses PEIND directly rather than the later four-region layout. */ +#define E1000_PEIND_82576_NONFATAL_MASK 0x00000007 +#define E1000_PEIND_82576_FATAL_MASK 0x7FFFFF00 +#define E1000_PEIND_82576_MEMORY_HANG 0x80000000 +#define E1000_PEINDM_82576_PARITY_ENABLE 0x80000000 +/* 82576NS omits the IPsec key, FIFO, and packet-buffer memories. */ +#define E1000_PEIND_82576_IPSEC_MASK 0x40700600 + #define E1000_PBECCSTS_I210_ECC_ENABLE 0x00000001 #define E1000_PBECCSTS_I210_CORR_ERR 0x00000004 @@ -591,6 +599,7 @@ #define E1000_ICR_TXD_LOW 0x00008000 #define E1000_ICR_MNG 0x00040000 /* Manageability event */ #define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */ +#define E1000_ICR_NFER 0x00800000 /* Non-Fatal Error (82576) */ #define E1000_ICR_TS 0x00080000 /* Time Sync Interrupt */ #define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */ /* If this bit asserted, the driver should claim the interrupt */ @@ -659,6 +668,7 @@ #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */ #define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW #define E1000_IMS_ECCER E1000_ICR_ECCER /* Uncorrectable ECC Error */ +#define E1000_IMS_NFER E1000_ICR_NFER /* Non-Fatal Error (82576) */ #define E1000_IMS_TS E1000_ICR_TS /* Time Sync Interrupt */ #define E1000_IMS_DRSTA E1000_ICR_DRSTA /* Device Reset Asserted */ #define E1000_IMS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */ diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index e29b34116b5d..6aa2a634bd24 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -2180,6 +2180,44 @@ em_has_pch_ecc(const struct e1000_hw *hw) hw->mac.type < e1000_82575); } +static bool +em_has_82576_memory_errors(const struct e1000_hw *hw) +{ + + return (hw->mac.type == e1000_82576); +} + +static bool +em_82576_has_ipsec(const struct e1000_hw *hw) +{ + + return (hw->device_id != E1000_DEV_ID_82576_NS && + hw->device_id != E1000_DEV_ID_82576_NS_SERDES); +} + +static void +em_configure_82576_memory_errors(struct e1000_softc *sc) +{ + struct e1000_hw *hw; + u32 peindm, reactions; + + hw = &sc->hw; + if (!em_has_82576_memory_errors(hw)) + return; + + reactions = E1000_PEIND_82576_NONFATAL_MASK | + E1000_PEIND_82576_FATAL_MASK | + E1000_PEINDM_82576_PARITY_ENABLE; + if (!em_82576_has_ipsec(hw)) + reactions &= ~E1000_PEIND_82576_IPSEC_MASK; + + /* Discard indications left by firmware before enabling reactions. */ + (void)E1000_READ_REG(hw, E1000_PEIND); + peindm = E1000_READ_REG(hw, E1000_PEINDM); + E1000_WRITE_REG(hw, E1000_PEINDM, peindm | reactions); + E1000_WRITE_FLUSH(hw); +} + static bool em_has_i210_memory_errors(const struct e1000_hw *hw) { @@ -2237,13 +2275,20 @@ em_pcie_fatal_error_mask(const struct e1000_hw *hw) static u32 em_fatal_error_intr_mask(struct e1000_softc *sc) { + u32 mask; - if ((em_has_pch_ecc(&sc->hw) || - em_has_i210_i350_memory_errors(&sc->hw)) && - atomic_load_acq_32(&sc->fatal_error_state) == + if (!em_has_pch_ecc(&sc->hw) && + !em_has_82576_memory_errors(&sc->hw) && + !em_has_i210_i350_memory_errors(&sc->hw)) + return (0); + if (atomic_load_acq_32(&sc->fatal_error_state) != EM_FATAL_ERROR_NONE) - return (E1000_IMS_FER); - return (0); + return (0); + + mask = E1000_IMS_FER; + if (em_has_82576_memory_errors(&sc->hw)) + mask |= E1000_IMS_NFER; + return (mask); } static void @@ -2340,29 +2385,36 @@ em_update_i350_ecc_stats(struct e1000_softc *sc) } /* - * Fatal internal-memory errors stop part or all of the MAC. Capture the - * read-clear indication before handing recovery to the iflib admin task. + * Internal-memory error causes are read-clear. Capture them before handing + * fatal recovery or 82576 non-fatal acknowledgement to the iflib admin task. */ static void em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr) { struct e1000_hw *hw; - u32 dma_rx, dma_tx, lanerr, pcieerr, peind; + u32 dma_rx, dma_tx, error_mask, lanerr, pcieerr, peind; + error_mask = E1000_ICR_FER; + if (em_has_82576_memory_errors(&sc->hw)) + error_mask |= E1000_ICR_NFER; if ((!em_has_pch_ecc(&sc->hw) && + !em_has_82576_memory_errors(&sc->hw) && !em_has_i210_i350_memory_errors(&sc->hw)) || - (icr & E1000_ICR_FER) == 0) + (icr & error_mask) == 0) return; hw = &sc->hw; - E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_FER); + E1000_WRITE_REG(hw, E1000_IMC, error_mask); if (!atomic_cmpset_32(&sc->fatal_error_state, EM_FATAL_ERROR_NONE, EM_FATAL_ERROR_CAPTURING)) return; + sc->fatal_error_icr = icr & error_mask; if (em_has_pch_ecc(hw)) { sc->fatal_error_pbeccsts = E1000_READ_REG(hw, E1000_PBECCSTS); + } else if (em_has_82576_memory_errors(hw)) { + sc->fatal_error_peind = E1000_READ_REG(hw, E1000_PEIND); } else { peind = E1000_READ_REG(hw, E1000_PEIND) & E1000_PEIND_FATAL_MASK; @@ -2401,7 +2453,7 @@ em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr) static bool em_handle_fatal_error_admin(struct e1000_softc *sc) { - u32 peind; + u32 error_mask, peind; bool reset_required; if (!atomic_cmpset_acq_32(&sc->fatal_error_state, @@ -2415,6 +2467,31 @@ em_handle_fatal_error_admin(struct e1000_softc *sc) "uncorrectable packet-buffer ECC error: " "PBECCSTS %#x; requesting reset\n", sc->fatal_error_pbeccsts); + } else if (em_has_82576_memory_errors(&sc->hw)) { + peind = sc->fatal_error_peind; + reset_required = + (sc->fatal_error_icr & E1000_ICR_FER) != 0 || + (peind & (E1000_PEIND_82576_FATAL_MASK | + E1000_PEIND_82576_MEMORY_HANG)) != 0; + if (!reset_required) { + device_printf(sc->dev, + "non-fatal internal memory error: PEIND %#x\n", + peind); + sc->fatal_error_icr = 0; + sc->fatal_error_peind = 0; + atomic_store_rel_32(&sc->fatal_error_state, + EM_FATAL_ERROR_NONE); + error_mask = E1000_IMS_FER | E1000_IMS_NFER; + E1000_WRITE_REG(&sc->hw, E1000_IMS, error_mask); + E1000_WRITE_FLUSH(&sc->hw); + return (true); + } + if ((peind & (E1000_PEIND_82576_FATAL_MASK | + E1000_PEIND_82576_MEMORY_HANG)) == 0) + sc->fatal_error_unknown_count++; + device_printf(sc->dev, + "fatal internal memory error: PEIND %#x; " + "requesting reset\n", peind); } else { peind = sc->fatal_error_peind; if (peind & E1000_PEIND_LANPORT_PARITY_FATAL) @@ -2542,7 +2619,11 @@ em_finish_fatal_error_reset(struct e1000_softc *sc) return; hw = &sc->hw; - if (em_has_i210_i350_memory_errors(hw)) { + if (em_has_82576_memory_errors(hw)) { + /* Drain any indication relatched while the port was resetting. */ + (void)E1000_READ_REG(hw, E1000_PEIND); + sc->fatal_error_peind = 0; + } else if (em_has_i210_i350_memory_errors(hw)) { pcieerr = sc->fatal_error_pcie | (E1000_READ_REG(hw, E1000_PCIEERRSTS) & em_pcie_fatal_error_mask(hw)); @@ -2581,6 +2662,7 @@ em_finish_fatal_error_reset(struct e1000_softc *sc) sc->fatal_error_dma_tx = 0; sc->fatal_error_dma_rx = 0; } + sc->fatal_error_icr = 0; sc->fatal_error_pbeccsts = 0; atomic_store_rel_32(&sc->fatal_error_state, EM_FATAL_ERROR_NONE); } @@ -4265,6 +4347,7 @@ em_reset(if_ctx_t ctx) device_printf(dev, "Hardware Initialization Failed\n"); return; } + em_configure_82576_memory_errors(sc); em_finish_fatal_error_reset(sc); if (hw->mac.type >= igb_mac_min) igb_init_dmac(sc, pba); @@ -6539,6 +6622,7 @@ em_add_hw_stats(struct e1000_softc *sc) CTLFLAG_RD, &stats->rlpic, "RX LPI event count"); } if (em_has_pch_ecc(&sc->hw) || + em_has_82576_memory_errors(&sc->hw) || em_has_i210_i350_memory_errors(&sc->hw)) { struct sysctl_oid *memerr_node; struct sysctl_oid_list *memerr_list; @@ -6560,6 +6644,11 @@ em_add_hw_stats(struct e1000_softc *sc) "uncorrected_packet_buffer", CTLFLAG_RD, &sc->uncorrected_error_packet_buffer_count, "Uncorrected packet-buffer ECC errors"); + } else if (em_has_82576_memory_errors(&sc->hw)) { + SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO, + "fatal_unknown", CTLFLAG_RD, + &sc->fatal_error_unknown_count, + "Fatal memory errors without a reported source"); } else { SYSCTL_ADD_UQUAD(ctx, memerr_list, OID_AUTO, "fatal_lan", CTLFLAG_RD, diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h index 3273d4c6b7fe..5515fcd3b4b2 100644 --- a/sys/dev/e1000/if_em.h +++ b/sys/dev/e1000/if_em.h @@ -625,6 +625,7 @@ struct e1000_softc { u32 promisc_pending; u32 stats_pending; u32 fatal_error_state; + u32 fatal_error_icr; u32 fatal_error_pbeccsts; u32 fatal_error_peind; u32 fatal_error_pcie;