git: c28f2c551daf - main - ixgbe: Defer ECC recovery to iflib
Kevin Bowling <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.cvs.src |
|---|---|
| Message-ID | <6a7bee39.3a3c5.d7658bb__46472.5539249898$1786507051$gmane$org@gitrepo.freebsd.org> |
The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=c28f2c551daf07345ac78b74459efe1014c49464 commit c28f2c551daf07345ac78b74459efe1014c49464 Author: Kevin Bowling <[email protected]> AuthorDate: 2026-08-12 02:33:20 +0000 Commit: Kevin Bowling <[email protected]> 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_ */