git: 2b2cc52236f4 - main - iflib: Own queue quiescence during power transitions
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 11 Sep 2026 20:13:33 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=2b2cc52236f462f1ca2b86581c8115252fb1a834
commit 2b2cc52236f462f1ca2b86581c8115252fb1a834
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-26 09:21:55 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-11 19:57:50 +0000
iflib: Own queue quiescence during power transitions
Perform a terminal datapath stop before suspend and shutdown
callbacks, then drain the private configuration taskqueue before
entering low power. Track power state independently of queue
ownership and prevent built-in admin, IOV, LED, and media-status
callbacks from accessing a suspended device.
Restore driver-specific state while the datapath remains stopped.
Initialize it exactly once on resume when the interface is
administratively up, and keep an administratively-down interface
stopped. Roll back the driver when suspend or child suspension fails.
Add ifdi_power_prepare() for policy which must be established before
the terminal stop. Use it to snapshot ixgbe(4) wake policy and preserve
X550EM PHY ordering, and remove the duplicate stop from aq(4).
Reviewed by: iflib (gallatin)
MFC after: 2 weeks
Sponsored by: BBOX.io
Differential Revision: https://reviews.freebsd.org/D59329
---
share/man/man9/Makefile | 2 +
share/man/man9/iflibdd.9 | 42 +++++++++++-
sys/dev/aq/aq_main.c | 3 -
sys/dev/ice/if_ice_iflib.c | 4 +-
sys/dev/ixgbe/if_ix.c | 39 ++++++-----
sys/net/ifdi_if.m | 17 +++++
sys/net/iflib.c | 160 +++++++++++++++++++++++++++++++++++++++++----
sys/net/iflib.h | 7 ++
8 files changed, 237 insertions(+), 37 deletions(-)
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index b4181c1d0f06..414ff7c998e0 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1327,12 +1327,14 @@ MLINKS+=iflibdd.9 ifdi_attach_pre.9 \
iflibdd.9 ifdi_media_change.9 \
iflibdd.9 ifdi_mtu_set.9 \
iflibdd.9 ifdi_multi_set.9 \
+ iflibdd.9 ifdi_power_prepare.9 \
iflibdd.9 ifdi_promisc_set.9 \
iflibdd.9 ifdi_queues_alloc.9 \
iflibdd.9 ifdi_queues_free.9 \
iflibdd.9 ifdi_queue_intr_enable.9 \
iflibdd.9 ifdi_resume.9 \
iflibdd.9 ifdi_rxq_setup.9 \
+ iflibdd.9 ifdi_shutdown.9 \
iflibdd.9 ifdi_stop.9 \
iflibdd.9 ifdi_suspend.9 \
iflibdd.9 ifdi_sysctl_int_delay.9 \
diff --git a/share/man/man9/iflibdd.9 b/share/man/man9/iflibdd.9
index d42ad6d2872e..3706271352ae 100644
--- a/share/man/man9/iflibdd.9
+++ b/share/man/man9/iflibdd.9
@@ -1,4 +1,4 @@
-.Dd August 8, 2026
+.Dd September 11, 2026
.Dt IFLIBDD 9
.Os
.Sh NAME
@@ -65,10 +65,19 @@
.Fa "uint16_t vtag"
.Fc
.Ft int
+.Fo ifdi_power_prepare
+.Fa "if_ctx_t ctx"
+.Fa "enum iflib_power_event event"
+.Fc
+.Ft int
.Fo ifdi_suspend
.Fa "if_ctx_t ctx"
.Fc
.Ft int
+.Fo ifdi_shutdown
+.Fa "if_ctx_t ctx"
+.Fc
+.Ft int
.Fo ifdi_resume
.Fa "if_ctx_t ctx"
.Fc
@@ -235,10 +244,37 @@ Optional function called by the VLAN config eventhandler.
is the new VLAN tag.
.It Fn ifdi_vlan_unregister
Optional function called by the VLAN unconfig eventhandler.
+.It Fn ifdi_power_prepare
+Optional function called before iflib performs the terminal stop used for
+detach, suspend, or shutdown.
+The
+.Fa event
+argument is one of
+.Dv IFLIB_POWER_DETACH ,
+.Dv IFLIB_POWER_SUSPEND ,
+or
+.Dv IFLIB_POWER_SHUTDOWN .
+Drivers should use this hook only to establish policy which must precede the
+stop and must not start, stop, or alter queue DMA; the default implementation
+does nothing.
+If it returns an error, it must undo any partial policy change before
+returning.
.It Fn ifdi_suspend
-Optional function that suspends the driver.
+Optional function called after iflib has stopped queue DMA and drained its
+private configuration taskqueue.
+It performs suspend-specific firmware, wake, PHY, and low-power work.
+An error is returned to the bus, and iflib attempts to resume the stopped
+interface.
+.It Fn ifdi_shutdown
+Optional function called after the same terminal stop and taskqueue drain as
+.Fn ifdi_suspend .
+Shutdown errors are returned without attempting rollback.
.It Fn ifdi_resume
-Optional function that resumes a driver.
+Optional function that restores suspend-specific device state while the
+datapath remains stopped.
+After it succeeds, iflib initializes the datapath exactly once when the
+interface is administratively up and leaves an administratively-down interface
+stopped.
.El
.Ss Device Configuration Functions
.Bl -ohang -offset indent
diff --git a/sys/dev/aq/aq_main.c b/sys/dev/aq/aq_main.c
index 92a6cbde858a..819ab5fb7e5c 100644
--- a/sys/dev/aq/aq_main.c
+++ b/sys/dev/aq/aq_main.c
@@ -565,12 +565,9 @@ aq_if_suspend(if_ctx_t ctx)
AQ_DBG_ENTER();
- aq_if_stop(ctx);
if (aq_hw_deinit(&softc->hw) != 0)
device_printf(softc->dev,
"could not shut the hardware down for suspend\n");
- /* iflib_device_suspend() does not stop the interface for us. */
- if_setdrvflagbits(iflib_get_ifp(ctx), IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
AQ_DBG_EXIT(0);
return (0);
diff --git a/sys/dev/ice/if_ice_iflib.c b/sys/dev/ice/if_ice_iflib.c
index 5a267671e87d..2214be71f4de 100644
--- a/sys/dev/ice/if_ice_iflib.c
+++ b/sys/dev/ice/if_ice_iflib.c
@@ -3378,7 +3378,7 @@ ice_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req)
* Deinitializes the driver and clears HW resources in preparation for
* suspend or an FLR.
*
- * @returns 0; this return value is ignored
+ * @returns 0 on success, or an error code on failure
*/
static int
ice_if_suspend(if_ctx_t ctx)
@@ -3402,7 +3402,7 @@ ice_if_suspend(if_ctx_t ctx)
* Reinitializes the driver and the HW after PCI resume or after
* an FLR. An init is performed by iflib after this function is finished.
*
- * @returns 0; this return value is ignored
+ * @returns 0 on success, or an error code on failure
*/
static int
ice_if_resume(if_ctx_t ctx)
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index e7bcf150319a..f734db0f79f0 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -181,6 +181,7 @@ static void *ixgbe_register(device_t);
static int ixgbe_if_attach_pre(if_ctx_t);
static int ixgbe_if_attach_post(if_ctx_t);
static int ixgbe_if_detach(if_ctx_t);
+static int ixgbe_if_power_prepare(if_ctx_t, enum iflib_power_event);
static int ixgbe_if_shutdown(if_ctx_t);
static int ixgbe_if_suspend(if_ctx_t);
static int ixgbe_if_resume(if_ctx_t);
@@ -227,7 +228,7 @@ static void ixgbe_enable_queue(struct ixgbe_softc *, u32);
static void ixgbe_disable_queue(struct ixgbe_softc *, u32);
static void ixgbe_add_device_sysctls(if_ctx_t);
static int ixgbe_allocate_pci_resources(if_ctx_t);
-static int ixgbe_setup_low_power_mode(if_ctx_t, bool);
+static int ixgbe_setup_low_power_mode(if_ctx_t);
static void ixgbe_config_dmac(struct ixgbe_softc *);
static void ixgbe_configure_ivars(struct ixgbe_softc *);
@@ -362,6 +363,7 @@ static device_method_t ixgbe_if_methods[] = {
DEVMETHOD(ifdi_attach_pre, ixgbe_if_attach_pre),
DEVMETHOD(ifdi_attach_post, ixgbe_if_attach_post),
DEVMETHOD(ifdi_detach, ixgbe_if_detach),
+ DEVMETHOD(ifdi_power_prepare, ixgbe_if_power_prepare),
DEVMETHOD(ifdi_shutdown, ixgbe_if_shutdown),
DEVMETHOD(ifdi_suspend, ixgbe_if_suspend),
DEVMETHOD(ifdi_resume, ixgbe_if_resume),
@@ -3915,7 +3917,7 @@ ixgbe_if_detach(if_ctx_t ctx)
sc->iov_recovery_stop = true;
- ixgbe_setup_low_power_mode(ctx, false);
+ ixgbe_setup_low_power_mode(ctx);
/* let hardware know driver is unloading */
ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT);
@@ -3993,13 +3995,27 @@ ixgbe_configure_wakeup_mta(if_ctx_t ctx)
hw->mac.mc_filter_type);
}
+/************************************************************************
+ * ixgbe_if_power_prepare - Establish policy required before a terminal stop
+ *
+ * Snapshot the requested wake filters before iflib stops the interface.
+ * X550EM 10GBASE-T must also suppress its PHY reset during that stop.
+ ************************************************************************/
+static int
+ixgbe_if_power_prepare(if_ctx_t ctx, enum iflib_power_event event)
+{
+
+ ixgbe_prepare_wakeup(ctx, event != IFLIB_POWER_DETACH);
+ return (0);
+}
+
/************************************************************************
* ixgbe_setup_low_power_mode - LPLU/WoL preparation
*
- * Prepare the adapter/port for LPLU and/or WoL
+ * Prepare the adapter/port for LPLU and/or WoL after a terminal stop
************************************************************************/
static int
-ixgbe_setup_low_power_mode(if_ctx_t ctx, bool arm_wake)
+ixgbe_setup_low_power_mode(if_ctx_t ctx)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
struct ixgbe_hw *hw = &sc->hw;
@@ -4007,10 +4023,7 @@ ixgbe_setup_low_power_mode(if_ctx_t ctx, bool arm_wake)
u32 fctrl, grc, wufc;
s32 error = 0;
- /* Snapshot wake policy before the terminal stop clears hardware state. */
- ixgbe_prepare_wakeup(ctx, arm_wake);
wufc = sc->wol_filters;
- ixgbe_if_stop(ctx);
/* Limit power management flow to X550EM baseT */
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
@@ -4086,7 +4099,7 @@ ixgbe_if_shutdown(if_ctx_t ctx)
INIT_DEBUGOUT("ixgbe_shutdown: begin");
- error = ixgbe_setup_low_power_mode(ctx, true);
+ error = ixgbe_setup_low_power_mode(ctx);
if (error != 0)
device_printf(iflib_get_dev(ctx),
"Wake configuration failed during shutdown: %d\n", error);
@@ -4105,7 +4118,7 @@ ixgbe_if_suspend(if_ctx_t ctx)
INIT_DEBUGOUT("ixgbe_suspend: begin");
- error = ixgbe_setup_low_power_mode(ctx, true);
+ error = ixgbe_setup_low_power_mode(ctx);
return (error);
} /* ixgbe_if_suspend */
@@ -4120,7 +4133,6 @@ ixgbe_if_resume(if_ctx_t ctx)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
device_t dev = iflib_get_dev(ctx);
- if_t ifp = iflib_get_ifp(ctx);
struct ixgbe_hw *hw = &sc->hw;
u32 wus;
@@ -4143,13 +4155,6 @@ ixgbe_if_resume(if_ctx_t ctx)
hw->wol_enabled = false;
sc->wol_filters = 0;
- /*
- * Required after D3->D0 transition;
- * will re-advertise all previous advertised speeds
- */
- if (if_getflags(ifp) & IFF_UP)
- ixgbe_if_init(ctx);
-
return (0);
} /* ixgbe_if_resume */
diff --git a/sys/net/ifdi_if.m b/sys/net/ifdi_if.m
index fdec1b866746..b226a1c7b96b 100644
--- a/sys/net/ifdi_if.m
+++ b/sys/net/ifdi_if.m
@@ -61,6 +61,13 @@ CODE {
return (0);
}
+ static int
+ null_power_prepare(if_ctx_t _ctx __unused,
+ enum iflib_power_event _event __unused)
+ {
+ return (0);
+ }
+
static int
null_queue_intr_enable(if_ctx_t _ctx __unused, uint16_t _qid __unused)
{
@@ -163,6 +170,16 @@ METHOD int detach {
if_ctx_t _ctx;
};
+#
+# Prepare driver policy which must be established before a terminal stop used
+# for detach, suspend, or shutdown. This method must not start, stop, or alter
+# queue DMA. The ordinary lifecycle callback runs after the stop.
+#
+METHOD int power_prepare {
+ if_ctx_t _ctx;
+ enum iflib_power_event _event;
+} DEFAULT null_power_prepare;
+
METHOD int suspend {
if_ctx_t _ctx;
} DEFAULT null_int_op;
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index d4c6b02762fe..0015cbb34a27 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -163,6 +163,17 @@ enum iflib_datapath_state {
IFLIB_DP_STOPPING,
};
+/*
+ * Power-transition state is separate from datapath ownership. It gates
+ * configuration callbacks while the device is entering or remains in low
+ * power without making any claim about driver-owned firmware or admin DMA.
+ */
+enum iflib_pm_state {
+ IFLIB_PM_ACTIVE = 0,
+ IFLIB_PM_SUSPENDING,
+ IFLIB_PM_SUSPENDED,
+};
+
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);
@@ -198,6 +209,7 @@ struct iflib_ctx {
uint32_t ifc_if_flags;
uint32_t ifc_flags;
enum iflib_datapath_state ifc_datapath_state;
+ enum iflib_pm_state ifc_pm_state;
uint32_t ifc_max_fl_buf_size;
uint32_t ifc_rx_mbuf_sz;
@@ -2610,6 +2622,9 @@ iflib_init_locked(if_ctx_t ctx)
bool init_failed;
sx_assert(&ctx->ifc_ctx_sx, SA_XLOCKED);
+ /* Configuration changes made during suspend take effect on resume. */
+ if (ctx->ifc_pm_state != IFLIB_PM_ACTIVE)
+ return;
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;
@@ -2733,6 +2748,12 @@ iflib_media_status(if_t ifp, struct ifmediareq *ifmr)
STATE_UNLOCK(ctx);
CTX_LOCK(ctx);
+ if (ctx->ifc_pm_state != IFLIB_PM_ACTIVE) {
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER | IFM_NONE;
+ CTX_UNLOCK(ctx);
+ return;
+ }
/*
* There is no need to update the admin status when it is done regularly by
* _task_fn_admin(), so only do it if that's not running. That can be quite
@@ -4325,6 +4346,10 @@ _task_fn_admin(void *context, int pending)
iflib_admin_task_fail_device) == 0, FAIL_POINT_NONSLEEPABLE, {});
CTX_LOCK(ctx);
+ if (ctx->ifc_pm_state != IFLIB_PM_ACTIVE) {
+ CTX_UNLOCK(ctx);
+ return;
+ }
if (!do_reset && do_reset_if_up &&
(if_getflags(ctx->ifc_ifp) & IFF_UP) != 0)
do_reset = true;
@@ -4367,6 +4392,10 @@ _task_fn_iov(void *context, int pending)
return;
CTX_LOCK(ctx);
+ if (ctx->ifc_pm_state != IFLIB_PM_ACTIVE) {
+ CTX_UNLOCK(ctx);
+ return;
+ }
IFDI_VFLR_HANDLE(ctx);
CTX_UNLOCK(ctx);
}
@@ -4397,6 +4426,8 @@ iflib_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
static void
iflib_if_init_locked(if_ctx_t ctx)
{
+ if (ctx->ifc_pm_state != IFLIB_PM_ACTIVE)
+ return;
if (ctx->ifc_datapath_state != IFLIB_DP_STOPPED)
iflib_stop(ctx);
iflib_init_locked(ctx);
@@ -4890,7 +4921,8 @@ _task_fn_led(void *context, int pending __unused)
return;
CTX_LOCK(ctx);
- IFDI_LED_FUNC(ctx, onoff);
+ if (ctx->ifc_pm_state == IFLIB_PM_ACTIVE)
+ IFDI_LED_FUNC(ctx, onoff);
CTX_UNLOCK(ctx);
}
@@ -5362,6 +5394,7 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
queues_allocated = false;
ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK | M_ZERO);
ctx->ifc_datapath_state = IFLIB_DP_UNKNOWN;
+ ctx->ifc_pm_state = IFLIB_PM_ACTIVE;
if (sc == NULL) {
sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK | M_ZERO);
@@ -5733,9 +5766,7 @@ iflib_device_deregister(if_ctx_t ctx)
{
if_t ifp = ctx->ifc_ifp;
device_t dev = ctx->ifc_dev;
-
- sysctl_ctx_free(&ctx->ifc_sysctl_ctx);
- ctx->ifc_sysctl_node = NULL;
+ int error;
/* Make sure VLANS are not using driver */
if (if_vlantrunkinuse(ifp)) {
@@ -5749,9 +5780,26 @@ iflib_device_deregister(if_ctx_t ctx)
}
#endif
+ /*
+ * Establish any ordering required by the terminal stop while the
+ * interface is still intact. Once this succeeds, mark the context
+ * inactive before releasing the lock so configuration tasks cannot
+ * consume partially applied policy.
+ */
+ CTX_LOCK(ctx);
+ error = IFDI_POWER_PREPARE(ctx, IFLIB_POWER_DETACH);
+ if (error != 0) {
+ CTX_UNLOCK(ctx);
+ return (error);
+ }
STATE_LOCK(ctx);
ctx->ifc_flags |= IFC_IN_DETACH;
STATE_UNLOCK(ctx);
+ ctx->ifc_pm_state = IFLIB_PM_SUSPENDING;
+ CTX_UNLOCK(ctx);
+
+ sysctl_ctx_free(&ctx->ifc_sysctl_ctx);
+ ctx->ifc_sysctl_node = NULL;
/* Unregister VLAN handlers before calling iflib_stop() */
iflib_unregister_vlan_handlers(ctx);
@@ -5852,25 +5900,108 @@ iflib_device_detach(device_t dev)
return (iflib_device_deregister(ctx));
}
+static int
+iflib_device_resume_locked(if_ctx_t ctx)
+{
+ if_t ifp;
+ int error;
+
+ sx_assert(&ctx->ifc_ctx_sx, SA_XLOCKED);
+ KASSERT(ctx->ifc_datapath_state == IFLIB_DP_STOPPED,
+ ("iflib resume with active datapath state %d",
+ ctx->ifc_datapath_state));
+ KASSERT(ctx->ifc_pm_state == IFLIB_PM_SUSPENDING ||
+ ctx->ifc_pm_state == IFLIB_PM_SUSPENDED,
+ ("iflib resume from power state %d", ctx->ifc_pm_state));
+
+ ifp = ctx->ifc_ifp;
+ error = IFDI_RESUME(ctx);
+ if (error != 0)
+ return (error);
+ ctx->ifc_pm_state = IFLIB_PM_ACTIVE;
+
+ if ((if_getflags(ifp) & IFF_UP) == 0) {
+ if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
+ return (0);
+ }
+
+ iflib_init_locked(ctx);
+ return (0);
+}
+
int
iflib_device_suspend(device_t dev)
{
if_ctx_t ctx = device_get_softc(dev);
+ int error, resume_error;
CTX_LOCK(ctx);
- IFDI_SUSPEND(ctx);
+ error = IFDI_POWER_PREPARE(ctx, IFLIB_POWER_SUSPEND);
+ if (error == 0) {
+ iflib_stop(ctx);
+ ctx->ifc_pm_state = IFLIB_PM_SUSPENDING;
+ }
CTX_UNLOCK(ctx);
+ if (error != 0)
+ return (error);
- return (bus_generic_suspend(dev));
+ /* Driver configuration tasks must finish before entering low power. */
+ taskqueue_drain_all(ctx->ifc_tq);
+
+ CTX_LOCK(ctx);
+ error = IFDI_SUSPEND(ctx);
+ if (error == 0)
+ ctx->ifc_pm_state = IFLIB_PM_SUSPENDED;
+ else {
+ resume_error = iflib_device_resume_locked(ctx);
+ if (resume_error != 0)
+ device_printf(dev,
+ "failed to resume after suspend error: %d\n",
+ resume_error);
+ }
+ CTX_UNLOCK(ctx);
+ if (error != 0)
+ return (error);
+
+ error = bus_generic_suspend(dev);
+ if (error != 0) {
+ CTX_LOCK(ctx);
+ resume_error = iflib_device_resume_locked(ctx);
+ CTX_UNLOCK(ctx);
+ if (resume_error != 0)
+ device_printf(dev,
+ "failed to resume after child suspend error: %d\n",
+ resume_error);
+ }
+
+ return (error);
}
+
int
iflib_device_shutdown(device_t dev)
{
if_ctx_t ctx = device_get_softc(dev);
+ int error;
CTX_LOCK(ctx);
- IFDI_SHUTDOWN(ctx);
+ error = IFDI_POWER_PREPARE(ctx, IFLIB_POWER_SHUTDOWN);
+ if (error == 0) {
+ iflib_stop(ctx);
+ ctx->ifc_pm_state = IFLIB_PM_SUSPENDING;
+ }
CTX_UNLOCK(ctx);
+ if (error != 0)
+ return (error);
+
+ taskqueue_drain_all(ctx->ifc_tq);
+
+ CTX_LOCK(ctx);
+ error = IFDI_SHUTDOWN(ctx);
+ if (error == 0)
+ ctx->ifc_pm_state = IFLIB_PM_SUSPENDED;
+ CTX_UNLOCK(ctx);
+ if (error != 0)
+ return (error);
return (bus_generic_suspend(dev));
}
@@ -5880,15 +6011,20 @@ iflib_device_resume(device_t dev)
{
if_ctx_t ctx = device_get_softc(dev);
iflib_txq_t txq = ctx->ifc_txqs;
+ bool running;
+ int error, child_error;
CTX_LOCK(ctx);
- IFDI_RESUME(ctx);
- iflib_if_init_locked(ctx);
+ error = iflib_device_resume_locked(ctx);
+ running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) != 0;
CTX_UNLOCK(ctx);
- for (int i = 0; i < NTXQSETS(ctx); i++, txq++)
- iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
+ if (running) {
+ for (int i = 0; i < NTXQSETS(ctx); i++, txq++)
+ iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET);
+ }
- return (bus_generic_resume(dev));
+ child_error = bus_generic_resume(dev);
+ return (error != 0 ? error : child_error);
}
int
diff --git a/sys/net/iflib.h b/sys/net/iflib.h
index 84b1e8723737..cab5c6232f9c 100644
--- a/sys/net/iflib.h
+++ b/sys/net/iflib.h
@@ -411,6 +411,13 @@ typedef enum {
*/
#define IFLIB_FEATURE_SUB_INTERFACES 1500014
+/* Power transitions for ifdi_power_prepare(). */
+enum iflib_power_event {
+ IFLIB_POWER_DETACH,
+ IFLIB_POWER_SUSPEND,
+ IFLIB_POWER_SHUTDOWN,
+};
+
/*
* These enum values are used in iflib_needs_restart to indicate to iflib
* functions whether or not the interface needs restarting when certain events