Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F170734152
D59328.id185810.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D59328.id185810.diff
View Options
diff --git a/share/man/man9/iflibdd.9 b/share/man/man9/iflibdd.9
--- a/share/man/man9/iflibdd.9
+++ b/share/man/man9/iflibdd.9
@@ -1,4 +1,4 @@
-.Dd August 8, 2026
+.Dd August 25, 2026
.Dt IFLIBDD 9
.Os
.Sh NAME
@@ -248,12 +248,20 @@
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
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -142,6 +142,20 @@
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.
+ */
+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);
@@ -176,6 +190,7 @@
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;
@@ -2587,6 +2602,11 @@
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);
@@ -2637,8 +2657,15 @@
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. */
@@ -2649,11 +2676,16 @@
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;
@@ -2663,16 +2695,20 @@
/* 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 ||
+ (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0;
+ if ((err = IFDI_MEDIA_CHANGE(ctx)) == 0 && restart)
iflib_if_init_locked(ctx);
CTX_UNLOCK(ctx);
return (err);
@@ -2712,15 +2748,25 @@
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
@@ -4381,7 +4427,8 @@
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);
}
@@ -4590,7 +4637,7 @@
#if defined(INET) || defined(INET6)
struct ifaddr *ifa = (struct ifaddr *)data;
#endif
- bool avoid_reset = false;
+ bool avoid_reset = false, restart, was_running;
int err = 0, reinit = 0, bits;
switch (command) {
@@ -4625,8 +4672,11 @@
break;
}
bits = if_getdrvflags(ifp);
- /* stop the driver and free any clusters before proceeding */
- iflib_stop(ctx);
+ was_running = (bits & IFF_DRV_RUNNING) != 0;
+ restart = was_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);
@@ -4637,12 +4687,19 @@
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);
+ STATE_LOCK(ctx);
+ /*
+ * Preserve a previously running driver's flags, but allow a
+ * successful retry of an administratively-up failed device to
+ * publish its new running state.
+ */
+ if (was_running &&
+ (ctx->ifc_flags & IFC_INIT_FAILED) == 0)
+ if_setdrvflags(ifp, bits);
+ STATE_UNLOCK(ctx);
+ }
CTX_UNLOCK(ctx);
break;
case SIOCSIFFLAGS:
@@ -4657,7 +4714,8 @@
}
} 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);
@@ -4741,16 +4799,20 @@
if (setmask) {
CTX_LOCK(ctx);
bits = if_getdrvflags(ifp);
- if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
+ was_running = (bits & IFF_DRV_RUNNING) != 0;
+ restart = (setmask & ~IFCAP_WOL) != 0 &&
+ (was_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 (was_running &&
+ (ctx->ifc_flags & IFC_INIT_FAILED) == 0)
if_setdrvflags(ifp, bits);
STATE_UNLOCK(ctx);
CTX_UNLOCK(ctx);
@@ -4810,6 +4872,7 @@
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;
@@ -4821,12 +4884,15 @@
return;
CTX_LOCK(ctx);
+ restart = IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG) &&
+ ((if_getflags(ifp) & IFF_UP) != 0 ||
+ (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0);
/* 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);
}
@@ -4835,6 +4901,7 @@
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;
@@ -4843,12 +4910,15 @@
return;
CTX_LOCK(ctx);
+ restart = IFDI_NEEDS_RESTART(ctx, IFLIB_RESTART_VLAN_CONFIG) &&
+ ((if_getflags(ifp) & IFF_UP) != 0 ||
+ (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0);
/* 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);
}
@@ -5339,6 +5409,7 @@
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);
@@ -7482,6 +7553,9 @@
{
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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Sep 7, 7:22 AM (10 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38413351
Default Alt Text
D59328.id185810.diff (9 KB)
Attached To
Mode
D59328: iflib: Track queue datapath lifecycle
Attached
Detach File
Event Timeline
Log In to Comment