Date: Sat, 08 Aug 2026 07:12:36 +0000 From: Kevin Bowling <kbowling@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 2b763a82f9f2 - main - ixgbe: Handle deferred link-status requests Message-ID: <6a76d6e4.3e3fb.535e3124@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=2b763a82f9f21b722b50830bc22af2b2acf36746 commit 2b763a82f9f21b722b50830bc22af2b2acf36746 Author: Kevin Bowling <kbowling@FreeBSD.org> AuthorDate: 2026-08-06 08:22:21 +0000 Commit: Kevin Bowling <kbowling@FreeBSD.org> CommitDate: 2026-08-08 07:07:31 +0000 ixgbe: Handle deferred link-status requests The iflib conversion records link-status interrupts in the administrative request mask, but the administrative task did not consume them. Timer polling usually hid the omission; frequent mailbox interrupts could continually rearm that timer and leave cached link state down after hardware recovered. Claim request batches atomically, process link-setup dependencies, and sample hardware before publishing link state. Bound each invocation to eight batches and requeue residual work so a continuous producer cannot monopolize the admin taskqueue. Queue every link-related request from the legacy interrupt path. Unlike MSI-X, its threaded continuation services RX and does not enqueue the admin task. This restores the event-driven behavior of ix-3.4.39. Fixes: b2c1e8e62049 ("ix(4): Run {mod,msf,mbx,fdir,phy}_task in if_update_admin_status") MFC after: 2 weeks --- sys/dev/ixgbe/if_ix.c | 133 +++++++++++++++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 50 deletions(-) diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c index e0e627b915d9..0c40feed48c9 100644 --- a/sys/dev/ixgbe/if_ix.c +++ b/sys/dev/ixgbe/if_ix.c @@ -51,6 +51,9 @@ ************************************************************************/ static const char ixgbe_driver_version[] = "5.0.1-k"; +/* Bound one admin-task invocation while still coalescing new requests. */ +#define IXGBE_ADMIN_TASK_BUDGET 8 + /************************************************************************ * PCI Device ID Table * @@ -280,9 +283,9 @@ static int ixgbe_sysctl_dump_debug_dump(SYSCTL_HANDLER_ARGS); /* Deferred interrupt tasklets */ static void ixgbe_handle_msf(void *); -static void ixgbe_handle_mod(void *); +static bool ixgbe_handle_mod(void *); static void ixgbe_handle_phy(void *); -static void ixgbe_handle_fw_event(void *); +static u32 ixgbe_handle_fw_event(void *); static int ixgbe_enable_lse(struct ixgbe_softc *sc); static int ixgbe_disable_lse(struct ixgbe_softc *sc); @@ -1838,7 +1841,7 @@ ixgbe_config_link(if_ctx_t ctx) if (sfp) { /* ixgbe_if_stop() disables it on every 82599 SFP port. */ ixgbe_enable_tx_laser(hw); - sc->task_requests |= IXGBE_REQUEST_TASK_MOD; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_MOD); iflib_admin_intr_deferred(ctx); } else { if (hw->mac.ops.check_link) @@ -3123,12 +3126,12 @@ ixgbe_msix_link(void *arg) /* Link status change */ if (eicr & IXGBE_EICR_LSC) { IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); - sc->task_requests |= IXGBE_REQUEST_TASK_LSC; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_LSC); } if (eicr & IXGBE_EICR_FW_EVENT) { IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FW_EVENT); - sc->task_requests |= IXGBE_REQUEST_TASK_FWEVENT; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_FWEVENT); } if (sc->hw.mac.type != ixgbe_mac_82598EB) { @@ -3139,7 +3142,7 @@ ixgbe_msix_link(void *arg) return (FILTER_HANDLED); /* Disable the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); - sc->task_requests |= IXGBE_REQUEST_TASK_FDIR; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_FDIR); } else if (eicr & IXGBE_EICR_ECC) { device_printf(iflib_get_dev(sc->ctx), @@ -3190,7 +3193,7 @@ ixgbe_msix_link(void *arg) /* Check for VF message */ if ((sc->feat_en & IXGBE_FEATURE_SRIOV) && (eicr & IXGBE_EICR_MAILBOX)) { - sc->task_requests |= IXGBE_REQUEST_TASK_MBX; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_MBX); } } @@ -3207,14 +3210,14 @@ ixgbe_msix_link(void *arg) if (eicr & eicr_mask) { IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask); - sc->task_requests |= IXGBE_REQUEST_TASK_MOD; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_MOD); } if ((hw->mac.type == ixgbe_mac_82599EB) && (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); - sc->task_requests |= IXGBE_REQUEST_TASK_MSF; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_MSF); } } @@ -3229,10 +3232,10 @@ ixgbe_msix_link(void *arg) if ((hw->phy.type == ixgbe_phy_x550em_ext_t) && (eicr & IXGBE_EICR_GPI_SDP0_X540)) { IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); - sc->task_requests |= IXGBE_REQUEST_TASK_PHY; + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_PHY); } - return (sc->task_requests != 0) ? + return (atomic_load_acq_32(&sc->task_requests) != 0) ? FILTER_SCHEDULE_THREAD : FILTER_HANDLED; } /* ixgbe_msix_link */ @@ -3986,10 +3989,9 @@ ixgbe_if_init(if_ctx_t ctx) ixgbe_initialize_receive_units(ctx); /* - * Initialize variable holding task enqueue requests - * from MSI-X interrupts + * Initialize the deferred administrative request mask. */ - sc->task_requests = 0; + atomic_store_rel_32(&sc->task_requests, 0); /* Enable SDP & MSI-X interrupts based on adapter */ ixgbe_config_gpie(sc); @@ -4548,7 +4550,7 @@ out: /************************************************************************ * ixgbe_handle_mod - Tasklet for SFP module interrupts ************************************************************************/ -static void +static bool ixgbe_handle_mod(void *context) { if_ctx_t ctx = context; @@ -4593,11 +4595,10 @@ ixgbe_handle_mod(void *context) "Setup failure - unsupported SFP+ module type.\n"); goto handle_mod_out; } - sc->task_requests |= IXGBE_REQUEST_TASK_MSF; - return; + return (true); handle_mod_out: - sc->task_requests &= ~(IXGBE_REQUEST_TASK_MSF); + return (false); } /* ixgbe_handle_mod */ @@ -4689,7 +4690,7 @@ s32 ixgbe_disable_lse(struct ixgbe_softc *sc) /************************************************************************ * ixgbe_handle_fw_event - Tasklet for MSI-X Link Status Event interrupts ************************************************************************/ -static void +static u32 ixgbe_handle_fw_event(void *context) { if_ctx_t ctx = context; @@ -4698,13 +4699,14 @@ ixgbe_handle_fw_event(void *context) struct ixgbe_aci_event event; bool pending = false; s32 error; + u32 requests = 0; event.buf_len = IXGBE_ACI_MAX_BUFFER_SIZE; event.msg_buf = malloc(event.buf_len, M_IXGBE, M_ZERO | M_NOWAIT); if (!event.msg_buf) { device_printf(sc->dev, "Can not allocate buffer for " "event message\n"); - return; + return (0); } do { @@ -4717,7 +4719,7 @@ ixgbe_handle_fw_event(void *context) switch (le16toh(event.desc.opcode)) { case ixgbe_aci_opc_get_link_status: - sc->task_requests |= IXGBE_REQUEST_TASK_LSC; + requests |= IXGBE_REQUEST_TASK_LSC; break; case ixgbe_aci_opc_fw_logs_event: @@ -4741,6 +4743,7 @@ ixgbe_handle_fw_event(void *context) } while (pending); free(event.msg_buf, M_IXGBE); + return (requests); } /* ixgbe_handle_fw_event */ /************************************************************************ @@ -4812,15 +4815,61 @@ ixgbe_link_speed_to_str(u32 link_speed) /************************************************************************ * ixgbe_update_link_status - Update OS on link state * - * Note: Only updates the OS on the cached link state. - * The real check of the hardware only happens with - * a link interrupt. + * Process deferred administrative requests and update the OS link state. ************************************************************************/ static void ixgbe_if_update_admin_status(if_ctx_t ctx) { struct ixgbe_softc *sc = iflib_get_softc(ctx); device_t dev = iflib_get_dev(ctx); + u32 requests; + u_int pass; + bool check_link = false; + + /* + * The interrupt filter and other producers can run concurrently with + * this task. Claim each batch atomically so a request posted while the + * task is running remains pending for this or the next invocation. + * + * MOD and firmware events can produce dependent requests. Fold those + * into the claimed batch so link state is sampled after any link setup. + */ + if ((if_getdrvflags(iflib_get_ifp(ctx)) & IFF_DRV_RUNNING) != 0 && + (sc->iov_mbx_cleanup_pending || ixgbe_mbx_pending(sc))) + atomic_set_32(&sc->task_requests, IXGBE_REQUEST_TASK_MBX); + for (pass = 0; pass < IXGBE_ADMIN_TASK_BUDGET; pass++) { + requests = atomic_readandclear_32(&sc->task_requests); + if (requests == 0) + break; + if (requests & IXGBE_REQUEST_TASK_FWEVENT) + requests |= ixgbe_handle_fw_event(ctx); + if (requests & IXGBE_REQUEST_TASK_MOD) { + if (ixgbe_handle_mod(ctx)) + requests |= IXGBE_REQUEST_TASK_MSF; + else + requests &= ~IXGBE_REQUEST_TASK_MSF; + } + if (requests & IXGBE_REQUEST_TASK_MSF) + ixgbe_handle_msf(ctx); + /* A reset request can re-enable VF traffic; skip it while stopped. */ + if ((requests & IXGBE_REQUEST_TASK_MBX) != 0 && + (if_getdrvflags(iflib_get_ifp(ctx)) & IFF_DRV_RUNNING) != 0) + ixgbe_handle_mbx(ctx); + if (requests & IXGBE_REQUEST_TASK_FDIR) + ixgbe_reinit_fdir(ctx); + if (requests & IXGBE_REQUEST_TASK_PHY) + ixgbe_handle_phy(ctx); + if (requests & IXGBE_REQUEST_TASK_LSC) + check_link = true; + } + + /* Do not let a continuous producer monopolize the admin taskqueue. */ + if (atomic_load_acq_32(&sc->task_requests) != 0) + iflib_admin_intr_deferred(ctx); + + if (check_link) + ixgbe_check_link(&sc->hw, &sc->link_speed, &sc->link_up, + false); if (sc->link_up) { if (sc->link_active == false) { @@ -4864,27 +4913,6 @@ ixgbe_if_update_admin_status(if_ctx_t ctx) } } - /* Handle task requests from msix_link() */ - if (sc->task_requests & IXGBE_REQUEST_TASK_FWEVENT) - ixgbe_handle_fw_event(ctx); - if (sc->task_requests & IXGBE_REQUEST_TASK_MOD) - ixgbe_handle_mod(ctx); - if (sc->task_requests & IXGBE_REQUEST_TASK_MSF) - ixgbe_handle_msf(ctx); - /* - * A reset request re-enables VF traffic, so do not service mailboxes - * while the PF is stopped. VFREQ, VFACK, and VFLR are hardware-latched - * and ixgbe_mbx_pending() resamples them after the PF is running again. - */ - if ((if_getdrvflags(iflib_get_ifp(ctx)) & IFF_DRV_RUNNING) != 0 && - ((sc->task_requests & IXGBE_REQUEST_TASK_MBX) != 0 || - sc->iov_mbx_cleanup_pending || ixgbe_mbx_pending(sc))) - ixgbe_handle_mbx(ctx); - if (sc->task_requests & IXGBE_REQUEST_TASK_FDIR) - ixgbe_reinit_fdir(ctx); - if (sc->task_requests & IXGBE_REQUEST_TASK_PHY) - ixgbe_handle_phy(ctx); - sc->task_requests = 0; ixgbe_schedule_iov_recovery(sc); ixgbe_update_stats_counters(sc); @@ -5109,9 +5137,10 @@ ixgbe_intr(void *arg) struct ix_rx_queue *que = sc->rx_queues; struct ixgbe_hw *hw = &sc->hw; if_ctx_t ctx = sc->ctx; - u32 eicr, eicr_mask; + u32 eicr, eicr_mask, requests; eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + requests = 0; ++que->irqs; if (eicr == 0) { @@ -5131,7 +5160,7 @@ ixgbe_intr(void *arg) /* Link status change */ if (eicr & IXGBE_EICR_LSC) { IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); - iflib_admin_intr_deferred(ctx); + requests |= IXGBE_REQUEST_TASK_LSC; } if (ixgbe_is_sfp(hw)) { @@ -5143,21 +5172,25 @@ ixgbe_intr(void *arg) if (eicr & eicr_mask) { IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask); - sc->task_requests |= IXGBE_REQUEST_TASK_MOD; + requests |= IXGBE_REQUEST_TASK_MOD; } if ((hw->mac.type == ixgbe_mac_82599EB) && (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); - sc->task_requests |= IXGBE_REQUEST_TASK_MSF; + requests |= IXGBE_REQUEST_TASK_MSF; } } /* External PHY interrupt */ if ((hw->phy.type == ixgbe_phy_x550em_ext_t) && (eicr & IXGBE_EICR_GPI_SDP0_X540)) { - sc->task_requests |= IXGBE_REQUEST_TASK_PHY; + requests |= IXGBE_REQUEST_TASK_PHY; + } + if (requests != 0) { + atomic_set_32(&sc->task_requests, requests); + iflib_admin_intr_deferred(ctx); } return (FILTER_SCHEDULE_THREAD);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a76d6e4.3e3fb.535e3124>
