From nobody Thu Oct 29 04:55:26 2026 X-Original-To: dev-commits-src-branches@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 4jFX3g0xMsz6xmHM for ; Thu, 29 Oct 2026 04:55:27 +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) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jFX3g0MM1z4bHZ for ; Thu, 29 Oct 2026 04:55:27 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793249727; 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=WRyMdU8A1XMN4nSgD5O+WVEwgFPsGjNA21ew0D32+o8=; b=TQiqpMogrfQUzkBqbJSOrWJapiyjp5h0fnSYDoFu0fUWNdYymeZ5hNp0BeFbnoBeztWVY3 oTj2lhwHFPEQxcd28Ua+/H1tnU8szCECpSjIC7mxXqmxGPxG2brvG5yuwYGFrhgbPWZhZP meDSKSV64lwaeqHghjGIxL3DKsxaF2L0AiJvjVqTrbdrLE1DdrOPOYoRYFJmJsD3BO0rvL h3dHKci8gbpFq7J6+TDPEZNjQBqrdAcqktjQMoMOtxqXQg0+nc07RMHzLSy11TUVVu5jt2 xoPyccOUZQb4+Ry4GOP/x/XVLEX+nVvcQ09OwLHcaVtHIYp/aWMktHQLqMEl8Q== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1793249727; b=Eu8FIS/6ETrneiftQKGDKuwlKxKkIWTh84Zk/W2jfOrcHOWiFaAXyJf2k9JrmUrnnSFLIR WrcboqkAf8Y2YQkVKdeYlARyy0r7ysL3zi/Eqc4Z6Q/IHaDvRvotLU6A8fGtghIiCMPQQw 8ZrXw6Q4lkVn5vvOeIyI5oLyObHcvfBBobTWKfjSOaRwSYXOtTqi+BAqDM6ALEoYjXIgYT 89mYI4GQa0bJXwYEZ92rnClkABuzQSr5Dao+XfYx6p6FgkEpSxBOK7aCFeLEMubKqOh95X Wwc4EDG7cs6aW9FAlQi91KDf24bpYtl0MlKcbMotgq6l3h3H62tRm2ZVyRHaOw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793249727; 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=WRyMdU8A1XMN4nSgD5O+WVEwgFPsGjNA21ew0D32+o8=; b=r+TRMSVlUyT1EG0i/3yS2pJy42pP3T0v0fu4f7umrbJnmio5E8xXrZ9EAAnqBaIdR5Od+6 77V0T0W/82hXVo4f2kEmQCMSKY3iAlVof3FZJykktWB5l/jhgunkDgMvf39Ula756mEKYq XBCIARrGPtslkCG1sY1nJSJrsmXps82VsMElKVK4l2CKgCk9Ipq/rsNeKx0xLEOau0ZTnM rzkV4ZTBroRShUmV/YK20Cfg/4beePm+t8jSNEnuN+/BravL3+mhuuLvKA3nGyPTqB3AyD gOxTh/HIU1TEGdksNSvMy3Jl2PT7lYOzOGilN67LDI4hrN4WeFpO4ScjVeB45A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jFX3f6sZGzNjD for ; Thu, 29 Oct 2026 04:55:26 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 32a12 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 29 Oct 2026 04:55:26 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kevin Bowling Subject: git: 3f61381f4a19 - stable/15 - iflib: Track queue datapath lifecycle List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: Commits to the stable branches of the FreeBSD src repository 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/stable/15 X-Git-Reftype: branch X-Git-Commit: 3f61381f4a19affb870f4d13d6bedd9f0dc126d5 Auto-Submitted: auto-generated Date: Thu, 29 Oct 2026 04:55:26 +0000 Message-Id: <6ae2d1be.32a12.ef8aad4@gitrepo.freebsd.org> The branch stable/15 has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=3f61381f4a19affb870f4d13d6bedd9f0dc126d5 commit 3f61381f4a19affb870f4d13d6bedd9f0dc126d5 Author: Kevin Bowling AuthorDate: 2026-08-26 09:21:55 +0000 Commit: Kevin Bowling CommitDate: 2026-10-29 04:55:12 +0000 iflib: Track queue datapath lifecycle Track whether iflib queue mappings may still be accessed by the device. Keep the state private to iflib and conservative: an unknown or failed device must pass through IFDI_STOP() before mappings are reused or released, while a device known to be stopped need not receive another hardware stop. Enter the starting state before IFDI_INIT(), publish running only after receive buffers and framework state are ready, and stop hardware if receive-buffer setup fails after driver initialization. Do not initialize an administratively-down interface merely because its MTU, capabilities, VLAN configuration, or media changed. Preserve successful retries for an administratively-up interface whose previous initialization failed. This state describes ownership of iflib datapath mappings only. It deliberately makes no claim about firmware queues, administrative DMA, PCI power state, or whether a driver can safely elide a hardware reset. Reviewed by: iflib (gallatin) Sponsored by: BBOX.io Differential Revision: https://reviews.freebsd.org/D59328 (cherry picked from commit fb8fcd4bff36d620d00fc20903379fb9ee844c57) --- share/man/man9/iflibdd.9 | 14 ++++-- sys/net/iflib.c | 127 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 106 insertions(+), 35 deletions(-) diff --git a/share/man/man9/iflibdd.9 b/share/man/man9/iflibdd.9 index 7777cbaa0022..d42ad6d2872e 100644 --- a/share/man/man9/iflibdd.9 +++ b/share/man/man9/iflibdd.9 @@ -248,12 +248,20 @@ For example, it will reset the chip and enable the receiver unit. 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 +or in a state in which +.Fn ifdi_stop +can safely quiesce it, and call .Fn iflib_init_failed before returning. +Iflib treats this report conservatively and invokes the driver stop method +before retrying initialization or releasing queue mappings. .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. +Mandatory function that performs a terminal stop and disables all traffic on +the interface. +The driver must stop DMA before returning; iflib releases the TX and RX +buffers after the callback. +The method commonly issues a global reset and may also put the PHY or device +into its administratively-down state. .It Fn ifdi_multi_set Programs the interfaces multicast addresses .It Fn ifdi_media_status diff --git a/sys/net/iflib.c b/sys/net/iflib.c index 850e966bd3b9..8f1e8c30e374 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -141,6 +141,27 @@ typedef struct iflib_fl *iflib_fl_t; struct iflib_ctx; +/* + * This state describes access to queue mappings owned by iflib. It does not + * describe driver-owned administrative DMA or the PCI function's power state. + * Normal transitions are serialized by ifc_ctx_sx. + * + * Only STOPPED establishes that the device can no longer access the mappings; + * a failed initialization can leave queues active. IFF_UP separately records + * administrative intent. Existing datapath users still use IFF_DRV_RUNNING, + * but clearing that flag does not establish quiescence: the watchdog clears + * it before the admin task stops the hardware. Use this state for lifecycle + * decisions under ifc_ctx_sx, not as an unlocked datapath admission check. + */ +enum iflib_datapath_state { + IFLIB_DP_UNKNOWN = 0, + IFLIB_DP_STOPPED, + IFLIB_DP_FAILED, + IFLIB_DP_STARTING, + IFLIB_DP_RUNNING, + IFLIB_DP_STOPPING, +}; + static void iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid); static void iflib_timer(void *arg); static void iflib_tqg_detach(if_ctx_t ctx); @@ -173,6 +194,7 @@ struct iflib_ctx { iflib_rxq_t ifc_rxqs; uint32_t ifc_if_flags; uint32_t ifc_flags; + enum iflib_datapath_state ifc_datapath_state; uint32_t ifc_max_fl_buf_size; uint32_t ifc_rx_mbuf_sz; @@ -2464,6 +2486,11 @@ iflib_init_locked(if_ctx_t ctx) int i, j, tx_ip_csum_flags, tx_ip6_csum_flags; bool init_failed; + sx_assert(&ctx->ifc_ctx_sx, SA_XLOCKED); + KASSERT(ctx->ifc_datapath_state == IFLIB_DP_STOPPED, + ("iflib init from datapath state %d", ctx->ifc_datapath_state)); + ctx->ifc_datapath_state = IFLIB_DP_STARTING; + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); IFDI_INTR_DISABLE(ctx); @@ -2514,8 +2541,15 @@ iflib_init_locked(if_ctx_t ctx) STATE_LOCK(ctx); init_failed = (ctx->ifc_flags & IFC_INIT_FAILED) != 0; STATE_UNLOCK(ctx); - if (init_failed) + if (init_failed) { + /* + * IFDI_INIT failed, but that alone does not prove that the + * driver stopped every queue or fenced DMA. Force the next + * lifecycle transition through the driver's stop method. + */ + ctx->ifc_datapath_state = IFLIB_DP_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. */ @@ -2526,11 +2560,16 @@ iflib_init_locked(if_ctx_t ctx) device_printf(ctx->ifc_dev, "setting up free list %d failed - " "check cluster settings\n", j); - goto done; + /* + * IFDI_INIT has started the hardware. Stop it before + * releasing partially populated receive mappings. + */ + iflib_init_failed(ctx); + iflib_stop(ctx); + return; } } } -done: if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); IFDI_INTR_ENABLE(ctx); txq = ctx->ifc_txqs; @@ -2540,16 +2579,20 @@ done: /* Re-enable txsync/rxsync. */ netmap_enable_all_rings(ifp); + ctx->ifc_datapath_state = IFLIB_DP_RUNNING; } static int iflib_media_change(if_t ifp) { if_ctx_t ctx = if_getsoftc(ifp); + bool restart; int err; CTX_LOCK(ctx); - if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0) + restart = (if_getflags(ifp) & IFF_UP) != 0 || + ctx->ifc_datapath_state == IFLIB_DP_RUNNING; + if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0 && restart) iflib_if_init_locked(ctx); CTX_UNLOCK(ctx); return (err); @@ -2575,15 +2618,25 @@ iflib_stop(if_ctx_t ctx) if_shared_ctx_t sctx = ctx->ifc_sctx; iflib_dma_info_t di; iflib_fl_t fl; + bool stop_hardware; int i, j; + sx_assert(&ctx->ifc_ctx_sx, SA_XLOCKED); + KASSERT(ctx->ifc_datapath_state != IFLIB_DP_STOPPING, + ("recursive iflib stop")); + stop_hardware = ctx->ifc_datapath_state != IFLIB_DP_STOPPED; + /* Tell the stack that the interface is no longer active */ if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); - IFDI_INTR_DISABLE(ctx); - DELAY(1000); - IFDI_STOP(ctx); - DELAY(1000); + if (stop_hardware) { + ctx->ifc_datapath_state = IFLIB_DP_STOPPING; + IFDI_INTR_DISABLE(ctx); + DELAY(1000); + IFDI_STOP(ctx); + DELAY(1000); + ctx->ifc_datapath_state = IFLIB_DP_STOPPED; + } /* * Stop any pending txsync/rxsync and prevent new ones @@ -4195,7 +4248,8 @@ iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS) static void iflib_if_init_locked(if_ctx_t ctx) { - iflib_stop(ctx); + if (ctx->ifc_datapath_state != IFLIB_DP_STOPPED) + iflib_stop(ctx); iflib_init_locked(ctx); } @@ -4400,8 +4454,8 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) #if defined(INET) || defined(INET6) struct ifaddr *ifa = (struct ifaddr *)data; #endif - bool avoid_reset = false; - int err = 0, reinit = 0, bits; + bool avoid_reset = false, restart; + int err = 0, reinit = 0; switch (command) { case SIOCSIFADDR: @@ -4434,9 +4488,11 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) CTX_UNLOCK(ctx); break; } - bits = if_getdrvflags(ifp); - /* stop the driver and free any clusters before proceeding */ - iflib_stop(ctx); + restart = ctx->ifc_datapath_state == IFLIB_DP_RUNNING || + (if_getflags(ifp) & IFF_UP) != 0; + /* Quiesce a datapath whose stopped state is not established. */ + if (ctx->ifc_datapath_state != IFLIB_DP_STOPPED) + iflib_stop(ctx); if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) { STATE_LOCK(ctx); @@ -4447,12 +4503,8 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) STATE_UNLOCK(ctx); err = if_setmtu(ifp, ifr->ifr_mtu); } - iflib_init_locked(ctx); - STATE_LOCK(ctx); - /* Preserve the stopped state reported by iflib_init_failed(). */ - if ((ctx->ifc_flags & IFC_INIT_FAILED) == 0) - if_setdrvflags(ifp, bits); - STATE_UNLOCK(ctx); + if (restart) + iflib_init_locked(ctx); CTX_UNLOCK(ctx); break; case SIOCSIFFLAGS: @@ -4467,7 +4519,8 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) } } else reinit = 1; - } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { + } else if (ctx->ifc_datapath_state != IFLIB_DP_STOPPED) { + /* Stop partially initialized hardware as well as running queues. */ iflib_stop(ctx); } ctx->ifc_if_flags = if_getflags(ifp); @@ -4541,19 +4594,17 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) */ if (setmask) { CTX_LOCK(ctx); - bits = if_getdrvflags(ifp); - if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL) + restart = (setmask & ~IFCAP_WOL) != 0 && + (ctx->ifc_datapath_state == IFLIB_DP_RUNNING || + (if_getflags(ifp) & IFF_UP) != 0); + if (restart) iflib_stop(ctx); STATE_LOCK(ctx); if_togglecapenable(ifp, setmask); ctx->ifc_softc_ctx.isc_capenable ^= setmask; STATE_UNLOCK(ctx); - if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL) + if (restart) iflib_init_locked(ctx); - STATE_LOCK(ctx); - if ((ctx->ifc_flags & IFC_INIT_FAILED) == 0) - if_setdrvflags(ifp, bits); - STATE_UNLOCK(ctx); CTX_UNLOCK(ctx); } if_vlancap(ifp); @@ -4593,6 +4644,7 @@ static void iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag) { if_ctx_t ctx = if_getsoftc(ifp); + bool restart; if ((void *)ctx != arg) return; @@ -4604,12 +4656,15 @@ iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag) return; CTX_LOCK(ctx); + restart = IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG) && + ((if_getflags(ifp) & IFF_UP) != 0 || + ctx->ifc_datapath_state == IFLIB_DP_RUNNING); /* Driver may need all untagged packets to be flushed */ - if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG)) + if (restart) iflib_stop(ctx); IFDI_VLAN_REGISTER(ctx, vtag); /* Re-init to load the changes, if required */ - if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG)) + if (restart) iflib_init_locked(ctx); CTX_UNLOCK(ctx); } @@ -4618,6 +4673,7 @@ static void iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag) { if_ctx_t ctx = if_getsoftc(ifp); + bool restart; if ((void *)ctx != arg) return; @@ -4626,12 +4682,15 @@ iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag) return; CTX_LOCK(ctx); + restart = IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG) && + ((if_getflags(ifp) & IFF_UP) != 0 || + ctx->ifc_datapath_state == IFLIB_DP_RUNNING); /* Driver may need all tagged packets to be flushed */ - if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG)) + if (restart) iflib_stop(ctx); IFDI_VLAN_UNREGISTER(ctx, vtag); /* Re-init to load the changes, if required */ - if (IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG)) + if (restart) iflib_init_locked(ctx); CTX_UNLOCK(ctx); } @@ -5122,6 +5181,7 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct intr_allocated = false; queues_allocated = false; ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK | M_ZERO); + ctx->ifc_datapath_state = IFLIB_DP_UNKNOWN; if (sc == NULL) { sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK | M_ZERO); @@ -7150,6 +7210,9 @@ iflib_init_failed(if_ctx_t ctx) { sx_assert(&ctx->ifc_ctx_sx, SA_XLOCKED); + KASSERT(ctx->ifc_datapath_state == IFLIB_DP_STARTING, + ("iflib_init_failed outside IFDI_INIT, state %d", + ctx->ifc_datapath_state)); STATE_LOCK(ctx); ctx->ifc_flags |= IFC_INIT_FAILED; STATE_UNLOCK(ctx);