git: 926bb8bbdee2 - stable/15 - iflib: Support recoverable initialization failure
Kevin Bowling <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.cvs.src,gmane.os.freebsd.devel.stable.scm |
|---|---|
| Message-ID | <[email protected]> |
The branch stable/15 has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=926bb8bbdee2ca3ed8b499cbd5dd2b04ab127a33 commit 926bb8bbdee2ca3ed8b499cbd5dd2b04ab127a33 Author: Kevin Bowling <[email protected]> AuthorDate: 2026-08-09 07:16:56 +0000 Commit: Kevin Bowling <[email protected]> CommitDate: 2026-08-23 00:23:47 +0000 iflib: Support recoverable initialization failure The ifdi_init method cannot report an error, so iflib always marks an interface running and enables its interrupts after the callback returns. Drivers whose hardware initialization depends on an unavailable peer can only return early and leave a falsely running interface. Add iflib_init_failed() so a callback can leave the interface stopped. Also add a conditional reset request for asynchronous recovery: it is discarded if the interface is administratively down when the admin task runs, preventing a queued retry from resurrecting a stopped interface. Do not restore saved driver flags after an MTU or capability change when initialization failed. Restoring the pre-init flags would overwrite the stopped result with stale RUNNING state. Document that reset requests require the caller to schedule the admin task, that output remains blocked during recovery, and that iflib rather than the driver owns the driver flags. (cherry picked from commit 9328a7eedba115040312bd1ea368371a0dbd0cac) --- share/man/man9/Makefile | 3 +++ share/man/man9/iflibdd.9 | 11 +++++++---- share/man/man9/iflibdi.9 | 35 ++++++++++++++++++++++++++++++++++ sys/net/iflib.c | 49 ++++++++++++++++++++++++++++++++++++++++++------ sys/net/iflib.h | 5 +++++ 5 files changed, 93 insertions(+), 10 deletions(-) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 9cf35e798b51..676e82c75a5b 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1343,8 +1343,11 @@ MLINKS+=iflibdi.9 iflib_add_int_delay_sysctl.9 \ iflibdi.9 iflib_led_create.9 \ iflibdi.9 iflib_irq_alloc.9 \ iflibdi.9 iflib_irq_alloc_generic.9 \ + iflibdi.9 iflib_init_failed.9 \ iflibdi.9 iflib_link_intr_deferred.9 \ iflibdi.9 iflib_link_state_change.9 \ + iflibdi.9 iflib_request_reset.9 \ + iflibdi.9 iflib_request_reset_if_up.9 \ iflibdi.9 iflib_rx_intr_deferred.9 \ iflibdi.9 iflib_tx_intr_deferred.9 MLINKS+=iflibtxrx.9 isc_rxd_available.9 \ diff --git a/share/man/man9/iflibdd.9 b/share/man/man9/iflibdd.9 index 67645fe5c87a..7777cbaa0022 100644 --- a/share/man/man9/iflibdd.9 +++ b/share/man/man9/iflibdd.9 @@ -1,4 +1,4 @@ -.Dd May 3, 2018 +.Dd August 8, 2026 .Dt IFLIBDD 9 .Os .Sh NAME @@ -245,9 +245,12 @@ Optional function that resumes a driver. .It Fn ifdi_init Mandatory function that will initialize and bring up the hardware. For example, it will reset the chip and enable the receiver unit. -It should mark the interface running, but not active ( -.Dv IFF_DRV_RUNNING , -.Dv ~IIF_DRV_OACTIVE ). +Iflib marks the interface running after the callback returns successfully; +the driver must not modify the driver flags itself. +If initialization cannot complete, the driver must leave the hardware stopped +and call +.Fn iflib_init_failed +before returning. .It Fn ifdi_stop Mandatory function that should disable all traffic on the interface by issuing a global reset on the MAC and deallocating the TX and RX buffers. diff --git a/share/man/man9/iflibdi.9 b/share/man/man9/iflibdi.9 index 57fa02c60b25..197cc037f04e 100644 --- a/share/man/man9/iflibdi.9 +++ b/share/man/man9/iflibdi.9 @@ -6,6 +6,7 @@ .Nd Device Independent Configuration Functions .Sh SYNOPSIS .In "ifdi_if.h" +.In "net/iflib.h" .Ss "Device Independent Functions" .Ft int .Fo iflib_device_attach @@ -80,6 +81,18 @@ .Fa "int linkstate" .Fc .Ft void +.Fo iflib_request_reset +.Fa "if_ctx_t ctx" +.Fc +.Ft void +.Fo iflib_request_reset_if_up +.Fa "if_ctx_t ctx" +.Fc +.Ft void +.Fo iflib_init_failed +.Fa "if_ctx_t ctx" +.Fc +.Ft void .Fo iflib_add_int_delay_sysctl .Fa "if_ctx_t ctx" .Fa "const char *" @@ -225,6 +238,28 @@ The following link states are currently defined: The link is up. .It Dv LINK_STATE_DOWN The link is down. +.It Fn iflib_request_reset +Request that the admin task stop and reinitialize the interface. +.It Fn iflib_request_reset_if_up +Request that the admin task stop and reinitialize the interface only if it +remains administratively up when the task runs. +This form is suitable for asynchronous recovery work that must not restart an +interface after an intervening administrative down operation. +Like +.Fn iflib_request_reset , +this function only records the request; the caller must schedule the admin +task, normally with +.Fn iflib_admin_intr_deferred . +.It Fn iflib_init_failed +Report that the current +.Fn ifdi_init +callback could not initialize the hardware. +The driver must leave the hardware stopped and call this function while the +callback holds the iflib context lock. +Iflib then leaves +.Dv IFF_DRV_RUNNING +clear and does not enable interrupts or periodic timers. +Output remains blocked so explicitly scheduled admin recovery work can run. .It Fn iflib_add_int_delay_sysctl Modifies settings to user defined values for a given set of variables. .El diff --git a/sys/net/iflib.c b/sys/net/iflib.c index 3ea5296fd2ae..57f6e568c951 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -318,13 +318,13 @@ typedef struct iflib_sw_tx_desc_array { #define IFC_LEGACY 0x001 #define IFC_QFLUSH 0x002 #define IFC_MULTISEG 0x004 -#define IFC_SPARE1 0x008 +#define IFC_INIT_FAILED 0x008 #define IFC_SC_ALLOCATED 0x010 #define IFC_INIT_DONE 0x020 #define IFC_PREFETCH 0x040 #define IFC_DO_RESET 0x080 #define IFC_DO_WATCHDOG 0x100 -#define IFC_SPARE0 0x200 +#define IFC_DO_RESET_IF_UP 0x200 #define IFC_SPARE2 0x400 #define IFC_IN_DETACH 0x800 @@ -2442,6 +2442,7 @@ iflib_init_locked(if_ctx_t ctx) iflib_txq_t txq; iflib_rxq_t rxq; int i, j, tx_ip_csum_flags, tx_ip6_csum_flags; + bool init_failed; if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); IFDI_INTR_DISABLE(ctx); @@ -2485,8 +2486,16 @@ iflib_init_locked(if_ctx_t ctx) #ifdef INVARIANTS i = if_getdrvflags(ifp); #endif + STATE_LOCK(ctx); + ctx->ifc_flags &= ~IFC_INIT_FAILED; + STATE_UNLOCK(ctx); IFDI_INIT(ctx); MPASS(if_getdrvflags(ifp) == i); + STATE_LOCK(ctx); + init_failed = (ctx->ifc_flags & IFC_INIT_FAILED) != 0; + STATE_UNLOCK(ctx); + if (init_failed) + return; for (i = 0, rxq = ctx->ifc_rxqs; i < scctx->isc_nrxqsets; i++, rxq++) { if (iflib_netmap_rxq_init(ctx, rxq) > 0) { /* This rxq is in netmap mode. Skip normal init. */ @@ -4057,15 +4066,18 @@ _task_fn_admin(void *context, int pending) if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; iflib_txq_t txq; int i; - bool oactive, running, do_reset, do_watchdog, in_detach; + bool oactive, running, do_reset, do_reset_if_up, do_watchdog; + bool in_detach; STATE_LOCK(ctx); running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING); oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE); do_reset = (ctx->ifc_flags & IFC_DO_RESET); + do_reset_if_up = (ctx->ifc_flags & IFC_DO_RESET_IF_UP); do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG); in_detach = (ctx->ifc_flags & IFC_IN_DETACH); - ctx->ifc_flags &= ~(IFC_DO_RESET | IFC_DO_WATCHDOG); + ctx->ifc_flags &= ~(IFC_DO_RESET | IFC_DO_RESET_IF_UP | + IFC_DO_WATCHDOG); STATE_UNLOCK(ctx); if ((!running && !oactive) && !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN)) @@ -4074,6 +4086,9 @@ _task_fn_admin(void *context, int pending) return; CTX_LOCK(ctx); + if (!do_reset && do_reset_if_up && + (if_getflags(ctx->ifc_ifp) & IFF_UP) != 0) + do_reset = true; for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) { CALLOUT_LOCK(txq); callout_stop(&txq->ift_timer); @@ -4395,7 +4410,9 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) } iflib_init_locked(ctx); STATE_LOCK(ctx); - if_setdrvflags(ifp, bits); + /* Preserve the stopped state reported by iflib_init_failed(). */ + if ((ctx->ifc_flags & IFC_INIT_FAILED) == 0) + if_setdrvflags(ifp, bits); STATE_UNLOCK(ctx); CTX_UNLOCK(ctx); break; @@ -4495,7 +4512,8 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL) iflib_init_locked(ctx); STATE_LOCK(ctx); - if_setdrvflags(ifp, bits); + if ((ctx->ifc_flags & IFC_INIT_FAILED) == 0) + if_setdrvflags(ifp, bits); STATE_UNLOCK(ctx); CTX_UNLOCK(ctx); } @@ -6922,6 +6940,25 @@ iflib_request_reset(if_ctx_t ctx) STATE_UNLOCK(ctx); } +void +iflib_request_reset_if_up(if_ctx_t ctx) +{ + + STATE_LOCK(ctx); + ctx->ifc_flags |= IFC_DO_RESET_IF_UP; + STATE_UNLOCK(ctx); +} + +void +iflib_init_failed(if_ctx_t ctx) +{ + + sx_assert(&ctx->ifc_ctx_sx, SA_XLOCKED); + STATE_LOCK(ctx); + ctx->ifc_flags |= IFC_INIT_FAILED; + STATE_UNLOCK(ctx); +} + #ifndef __NO_STRICT_ALIGNMENT static struct mbuf * iflib_fixup_rx(struct mbuf *m) diff --git a/sys/net/iflib.h b/sys/net/iflib.h index ed97796b550c..a8ab179aea21 100644 --- a/sys/net/iflib.h +++ b/sys/net/iflib.h @@ -425,6 +425,11 @@ if_shared_ctx_t iflib_get_sctx(if_ctx_t ctx); void iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN]); void iflib_request_reset(if_ctx_t ctx); +/* Defer a reset, but discard it if the interface is administratively down. */ +void iflib_request_reset_if_up(if_ctx_t ctx); + +/* Report an error from the otherwise void ifdi_init method while it runs. */ +void iflib_init_failed(if_ctx_t ctx); uint8_t iflib_in_detach(if_ctx_t ctx); uint32_t iflib_get_rx_mbuf_sz(if_ctx_t ctx);