From nobody Sun Aug 16 09:00:17 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 4hN90K3Z0Pz6nkg1 for ; Sun, 16 Aug 2026 09:00:17 +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 4hN90K2Pm3z3L8Y for ; Sun, 16 Aug 2026 09:00:17 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786870817; 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=tqhjQRNT+IqllFLib9jlSr1D+3+F10M4uVIpamwiw1s=; b=IAROIj+hd48zG2GgS8dZTgraZgwW9jcEcLWnHItcDnwxZg725qhBwzKtsmH54Zp6fpODUM edp3OB9YZLjk8T8B8flZDYiwdsqI4seYDtyAmUh8+9xLk7N+XlqnBZolS/uRcekPVn0cfs 2IwzW6t79WbiyOlSSZLf5W3NJWXuF9+Q4qbADVU5AnLIe7LirvBtsxFVRaDrItmMROTJn2 uvpIIlfgHiZmQ8gUiWWSSbXtr+JWlqo61K0AHErMJEk0oJQYLQG9A5hz8SVob+5an8z12I 7A8KzGcwmtSKBaFe6DY2l9fF5jxphc589mqGA+0+K8CVAUv3mpza3ZVaKia4lA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786870817; a=rsa-sha256; cv=none; b=mLZmHw9aRfLGyIkoUW0yVOeMxlsSqC7DLhs6KYNjmLMZOlWZRubgjhk4RsTpDEZrqAVMP3 lkEWQn5FFSNDwJHtT7R4QyUomLgcRoG8T8KM71OEPi0RAYgs7bzqXPdlaSNzQu0f0LVAJk ftOTVWgxfCgn6gRcULGVlVOPdflZOizc7lb5S3S/saHlImckd7R0hJsEJultkvOSOOj7HW WUxc2nrV8TFi2Sp2x/W1DcBBbn2oh49TtCF1Z1BPvlIksS2+JZp+5dFcqUIWFCpTFIKr5A HRYjSF+QNGkpExQjyBbglW3ZPK/ihhticrKuqHmcll/f8v+eCyeP0MdSss/lCg== 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=1786870817; 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=tqhjQRNT+IqllFLib9jlSr1D+3+F10M4uVIpamwiw1s=; b=lHHA6A8FU1TzrnapArphKY0TIL565cgom/nEeC9Y/dtPTF/qidJZ0kpmWjVMsl6Dov768R dk89eaJ86917HY1B556IfJGmGhndumSANQ57bPOXP7+bjyfcyCAjfZTX6mLPmheh9VeQkB LwjB1V9DZhbgjrOZQ/jMXfhQtolb5sOhw5Fn4LMpxQDVQADSMT1jkmSp9QcqtYmwH3As7g b39kLxBRw8XrOzh5WHlFjxs525tyhYECwp9kQUbEqp7JDR4jfu+dWU7+s/iCb7B6A7byNO BNXlquo5725n7PcG28CIKTStvrjRrvEsGzF22dc/IY0xWm8yJmwxPX9n0ApiJw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hN90K1Bvwz5WR for ; Sun, 16 Aug 2026 09:00:17 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1d5b9 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 16 Aug 2026 09:00:17 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: 39762c840a15 - main - e1000: Recover from PCH packet buffer ECC 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: 39762c840a15e1b32b2e1acaca18d98c030f7c17 Auto-Submitted: auto-generated Date: Sun, 16 Aug 2026 09:00:17 +0000 Message-Id: <6a817c21.1d5b9.75e9b199@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=39762c840a15e1b32b2e1acaca18d98c030f7c17 commit 39762c840a15e1b32b2e1acaca18d98c030f7c17 Author: Kevin Bowling AuthorDate: 2026-08-12 18:29:28 +0000 Commit: Kevin Bowling CommitDate: 2026-08-16 09:00:11 +0000 e1000: Recover from PCH packet buffer ECC errors PCH LAN controllers beginning with I217 report uncorrectable packet buffer ECC errors through ICR.ECCER. Descriptor memory errors stop the MAC and require a reset before traffic can resume. Enable the interrupt on the PCH generations whose shared code setup enables packet buffer ECC. Capture the read-clear PBECCSTS value in the interrupt filter, mask ECCER while recovery is pending, and request an iflib reset from the admin task. Reenable the cause only after hardware initialization succeeds. Hardware validation used an I219-LM and the documented ICS.ECCER bit to generate the fatal interrupt. This synthesizes the interrupt cause but does not corrupt packet buffer memory or alter its ECC byte counters. Three injections in one boot each requested one reset and recovered traffic without a panic or watchdog. IMS.ECCER and PBECCSTS.ECC_ENABLE remained set after every reset. MFC after: 2 weeks Sponsored by: BBOX.io --- sys/dev/e1000/if_em.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++--- sys/dev/e1000/if_em.h | 3 ++ 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index 691531601b8a..ce59a12df0de 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -455,6 +455,9 @@ static int em_if_rx_queue_intr_enable(if_ctx_t, uint16_t); static int em_if_tx_queue_intr_enable(if_ctx_t, uint16_t); static int igb_if_rx_queue_intr_enable(if_ctx_t, uint16_t); static int igb_if_tx_queue_intr_enable(if_ctx_t, uint16_t); +static void em_handle_fatal_error_intr(struct e1000_softc *, u32); +static bool em_handle_fatal_error_admin(struct e1000_softc *); +static void em_finish_fatal_error_reset(struct e1000_softc *); 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); @@ -499,6 +502,13 @@ static void em_disable_aspm(struct e1000_softc *); int em_intr(void *); +enum em_fatal_error_state { + EM_FATAL_ERROR_NONE, + EM_FATAL_ERROR_CAPTURING, + EM_FATAL_ERROR_DETECTED, + EM_FATAL_ERROR_RESET_REQUESTED, +}; + /* MSI-X handlers */ static int em_if_msix_intr_assign(if_ctx_t, int); static int em_msix_link(void *); @@ -2158,6 +2168,80 @@ em_newitr(struct e1000_softc *sc, struct em_rx_queue *que, } } +static bool +em_has_pch_ecc(const struct e1000_hw *hw) +{ + + return (hw->mac.type >= e1000_pch_lpt && + hw->mac.type < e1000_82575); +} + +static u32 +em_fatal_error_intr_mask(struct e1000_softc *sc) +{ + + if (em_has_pch_ecc(&sc->hw) && + atomic_load_acq_32(&sc->fatal_error_state) == + EM_FATAL_ERROR_NONE) + return (E1000_IMS_ECCER); + return (0); +} + +/* + * Descriptor-memory ECC errors stop the PCH MAC. Capture the read-clear + * status before handing recovery to the iflib admin task. + */ +static void +em_handle_fatal_error_intr(struct e1000_softc *sc, u32 icr) +{ + struct e1000_hw *hw; + + if (!em_has_pch_ecc(&sc->hw) || (icr & E1000_ICR_ECCER) == 0) + return; + + hw = &sc->hw; + E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_ECCER); + if (!atomic_cmpset_32(&sc->fatal_error_state, + EM_FATAL_ERROR_NONE, EM_FATAL_ERROR_CAPTURING)) + return; + + sc->fatal_error_pbeccsts = E1000_READ_REG(hw, E1000_PBECCSTS); + atomic_store_rel_32(&sc->fatal_error_state, + EM_FATAL_ERROR_DETECTED); + iflib_admin_intr_deferred(sc->ctx); +} + +static bool +em_handle_fatal_error_admin(struct e1000_softc *sc) +{ + + if (!atomic_cmpset_acq_32(&sc->fatal_error_state, + EM_FATAL_ERROR_DETECTED, EM_FATAL_ERROR_RESET_REQUESTED)) + return (atomic_load_acq_32(&sc->fatal_error_state) != + EM_FATAL_ERROR_NONE); + + device_printf(sc->dev, + "uncorrectable packet-buffer ECC error: PBECCSTS %#x; " + "requesting reset\n", sc->fatal_error_pbeccsts); + sc->fatal_error_reset_count++; + iflib_request_reset(sc->ctx); + /* Re-enter the admin task so it observes the reset request. */ + iflib_admin_intr_deferred(sc->ctx); + return (true); +} + +static void +em_finish_fatal_error_reset(struct e1000_softc *sc) +{ + + if (atomic_load_acq_32(&sc->fatal_error_state) == + EM_FATAL_ERROR_NONE) + return; + + sc->fatal_error_pbeccsts = 0; + atomic_store_rel_32(&sc->fatal_error_state, EM_FATAL_ERROR_NONE); +} + /********************************************************************* * * Fast Legacy/MSI Combined Interrupt Service routine @@ -2206,6 +2290,8 @@ em_intr(void *arg) if (reg_icr & E1000_ICR_RXO) sc->rx_overruns++; + em_handle_fatal_error_intr(sc, reg_icr); + if (hw->mac.type >= e1000_82540) em_newitr(sc, que, rxr); @@ -2315,12 +2401,14 @@ em_msix_link(void *arg) igb_iov_mdd_event(sc); if (reg_icr & E1000_ICR_VMMB) iflib_admin_intr_deferred(sc->ctx); + em_handle_fatal_error_intr(sc, reg_icr); rearm: /* Re-arm unconditionally */ if (sc->hw.mac.type >= igb_mac_min) { E1000_WRITE_REG(&sc->hw, E1000_IMS, - E1000_IMS_LSC | igb_iov_intr_mask(sc)); + E1000_IMS_LSC | igb_iov_intr_mask(sc) | + em_fatal_error_intr_mask(sc)); E1000_WRITE_REG(&sc->hw, E1000_EIMS, sc->link_mask); } else if (sc->hw.mac.type == e1000_82574) { E1000_WRITE_REG(&sc->hw, E1000_IMS, @@ -2333,7 +2421,8 @@ rearm: if (reg_icr) E1000_WRITE_REG(&sc->hw, E1000_ICS, sc->ims); } else - E1000_WRITE_REG(&sc->hw, E1000_IMS, E1000_IMS_LSC); + E1000_WRITE_REG(&sc->hw, E1000_IMS, + E1000_IMS_LSC | em_fatal_error_intr_mask(sc)); return (FILTER_HANDLED); } @@ -2662,6 +2751,8 @@ em_if_update_admin_status(if_ctx_t ctx) bool reset_requested = false; KASSERT(!sc->vf_ifp, ("%s called for a VF", __func__)); + if (em_handle_fatal_error_admin(sc)) + return; if (atomic_readandclear_32(&sc->promisc_pending) != 0) (void)em_if_set_promisc_impl(ctx, @@ -3828,6 +3919,7 @@ em_reset(if_ctx_t ctx) device_printf(dev, "Hardware Initialization Failed\n"); return; } + em_finish_fatal_error_reset(sc); if (hw->mac.type >= igb_mac_min) igb_init_dmac(sc, pba); @@ -5010,7 +5102,7 @@ em_if_intr_enable(if_ctx_t ctx) { struct e1000_softc *sc = iflib_get_softc(ctx); struct e1000_hw *hw = &sc->hw; - u32 ims_mask = IMS_ENABLE_MASK; + u32 ims_mask = IMS_ENABLE_MASK | em_fatal_error_intr_mask(sc); if (sc->intr_type == IFLIB_INTR_MSIX) { E1000_WRITE_REG(hw, EM_EIAC, sc->ims); @@ -5053,9 +5145,11 @@ igb_if_intr_enable(if_ctx_t ctx) igb_iov_intr_drain_stale(sc); E1000_WRITE_REG(hw, E1000_EIMS, mask); E1000_WRITE_REG(hw, E1000_IMS, - E1000_IMS_LSC | igb_iov_intr_mask(sc)); + E1000_IMS_LSC | igb_iov_intr_mask(sc) | + em_fatal_error_intr_mask(sc)); } else - E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK); + E1000_WRITE_REG(hw, E1000_IMS, + IMS_ENABLE_MASK | em_fatal_error_intr_mask(sc)); E1000_WRITE_FLUSH(hw); } diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h index 7116ff11c371..0c6f59f3f576 100644 --- a/sys/dev/e1000/if_em.h +++ b/sys/dev/e1000/if_em.h @@ -624,6 +624,9 @@ struct e1000_softc { int tso_automasked; u32 promisc_pending; u32 stats_pending; + u32 fatal_error_state; + u32 fatal_error_pbeccsts; + u64 fatal_error_reset_count; #ifdef PCI_IOV struct igb_vf *vfs;