Page MenuHomeFreeBSD

D59328.id185810.diff
No OneTemporary

D59328.id185810.diff

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

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)

Event Timeline