git: c28f2c551daf - main - ixgbe: Defer ECC recovery to iflib
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 12 Aug 2026 03:53:29 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=c28f2c551daf07345ac78b74459efe1014c49464
commit c28f2c551daf07345ac78b74459efe1014c49464
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-12 02:33:20 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-12 03:39:39 +0000
ixgbe: Defer ECC recovery to iflib
The link interrupt filter performed a full hardware reset in interrupt
context. This bypassed iflib stop and initialization, including queue
quiescence and restoration of temporary LED state.
Record the ECC event in the administrative request mask and ask iflib
to perform the reset from its taskqueue. Keep the ECC cause masked
until reset so the intermediate admin pass cannot re-enable a sticky
condition. Handle ECC independently of Flow Director and in legacy
interrupt mode.
Remove the redundant EICR write; the filter has already cleared the
reported causes. Also remove the accompanying complement-mask update
of mac.flags. It set every flag except DOUBLE_RESET_REQUIRED and had
no place in ECC recovery.
MFC after: 2 weeks
---
sys/dev/ixgbe/if_ix.c | 54 ++++++++++++++++++++++++++++++++++------------
sys/dev/ixgbe/ixgbe.h | 1 +
sys/dev/ixgbe/ixgbe_type.h | 1 +
3 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index 8610bfad0d4c..c12956fb6e07 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -3149,6 +3149,25 @@ ixgbe_if_promisc_set(if_ctx_t ctx, int flags)
return (0);
} /* ixgbe_if_promisc_set */
+/************************************************************************
+ * ixgbe_handle_ecc - Defer recovery from an ECC interrupt
+ ************************************************************************/
+static bool
+ixgbe_handle_ecc(struct ixgbe_softc *sc, u32 eicr)
+{
+ struct ixgbe_hw *hw = &sc->hw;
+
+ if ((eicr & IXGBE_EICR_ECC) == 0)
+ return (false);
+
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_ECC);
+ if (!atomic_cmpset_int(&sc->ecc_reset_pending, 0, 1))
+ return (false);
+
+ device_printf(sc->dev, "Received ECC Err, initiating reset\n");
+ return (true);
+}
+
/************************************************************************
* ixgbe_msix_link - Link status change ISR (MSI/MSI-X)
************************************************************************/
@@ -3187,21 +3206,17 @@ ixgbe_msix_link(void *arg)
if ((sc->feat_en & IXGBE_FEATURE_FDIR) &&
(eicr & IXGBE_EICR_FLOW_DIR)) {
/* This is probably overkill :) */
- if (!atomic_cmpset_int(&sc->fdir_reinit, 0, 1))
- return (FILTER_HANDLED);
- /* Disable the interrupt */
- IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR);
- atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_FDIR);
- } else
- if (eicr & IXGBE_EICR_ECC) {
- device_printf(iflib_get_dev(sc->ctx),
- "Received ECC Err, initiating reset\n");
- hw->mac.flags |=
- ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
- ixgbe_reset_hw(hw);
- IXGBE_WRITE_REG(hw, IXGBE_EICR,
- IXGBE_EICR_ECC);
+ if (atomic_cmpset_int(&sc->fdir_reinit, 0, 1)) {
+ /* Disable the interrupt */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC,
+ IXGBE_EICR_FLOW_DIR);
+ atomic_set_32(&sc->task_requests,
+ IXGBE_REQUEST_TASK_FDIR);
}
+ }
+ if (ixgbe_handle_ecc(sc, eicr))
+ atomic_set_32(&sc->task_requests,
+ IXGBE_REQUEST_TASK_RESET);
/* Check for over temp condition */
if (sc->feat_en & IXGBE_FEATURE_TEMP_SENSOR) {
@@ -4829,6 +4844,7 @@ ixgbe_if_stop(if_ctx_t ctx)
ixgbe_quiesce_vfs(sc);
}
ixgbe_reset_hw(hw);
+ atomic_store_rel_int(&sc->ecc_reset_pending, 0);
hw->adapter_stopped = false;
ixgbe_stop_adapter(hw);
/* Turn off the laser - noop with no optics */
@@ -4975,6 +4991,11 @@ ixgbe_if_update_admin_status(if_ctx_t ctx)
ixgbe_handle_phy(ctx);
if (requests & IXGBE_REQUEST_TASK_LSC)
check_link = true;
+ if (requests & IXGBE_REQUEST_TASK_RESET) {
+ /* Re-enter the admin task so it observes IFC_DO_RESET. */
+ iflib_request_reset(ctx);
+ iflib_admin_intr_deferred(ctx);
+ }
}
/* Do not let a continuous producer monopolize the admin taskqueue. */
@@ -5120,6 +5141,8 @@ ixgbe_if_enable_intr(if_ctx_t ctx)
/* Enable Flow Director */
if (sc->feat_en & IXGBE_FEATURE_FDIR)
mask |= IXGBE_EIMS_FLOW_DIR;
+ if (atomic_load_acq_int(&sc->ecc_reset_pending))
+ mask &= ~IXGBE_EIMS_ECC;
IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
@@ -5302,6 +5325,9 @@ ixgbe_intr(void *arg)
(eicr & IXGBE_EICR_GPI_SDP0_X540)) {
requests |= IXGBE_REQUEST_TASK_PHY;
}
+ if (hw->mac.type != ixgbe_mac_82598EB &&
+ ixgbe_handle_ecc(sc, eicr))
+ requests |= IXGBE_REQUEST_TASK_RESET;
if (requests != 0) {
atomic_set_32(&sc->task_requests, requests);
iflib_admin_intr_deferred(ctx);
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index 85b8c3480edd..3f06d1ab8120 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -459,6 +459,7 @@ struct ixgbe_softc {
/* Flow Director */
int fdir_reinit;
+ u_int ecc_reset_pending;
u32 task_requests;
diff --git a/sys/dev/ixgbe/ixgbe_type.h b/sys/dev/ixgbe/ixgbe_type.h
index 9222d8d54fd0..3194666bd81c 100644
--- a/sys/dev/ixgbe/ixgbe_type.h
+++ b/sys/dev/ixgbe/ixgbe_type.h
@@ -4613,5 +4613,6 @@ struct ixgbe_bypass_eeprom {
#define IXGBE_REQUEST_TASK_PHY 0x10
#define IXGBE_REQUEST_TASK_LSC 0x20
#define IXGBE_REQUEST_TASK_FWEVENT 0x40
+#define IXGBE_REQUEST_TASK_RESET 0x80
#endif /* _IXGBE_TYPE_H_ */