Replace various netif_running() checks with an explicit WX_STATE_DOWN
state bit to track whether the device datapath and interrupt handling
are operational.
The previous logic relied on netif_running() to gate interrupt
reenablement, queue wakeups, statistics updates, and service task
execution. However, netif_running() only reflects the administrative
state of the netdevice and does not fully serialize against teardown
and reset paths. During device shutdown and reset flows, asynchronous
contexts such as interrupt handlers, NAPI poll, and service work could
still observe netif_running() as true while device resources were
already being disabled or freed.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Link: https://patch.msgid.link/20260525100543.27140-2-jiawenwu@trustnetic.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
mutex_init(&wx->reset_lock);
bitmap_zero(wx->state, WX_STATE_NBITS);
bitmap_zero(wx->flags, WX_PF_FLAGS_NBITS);
+ set_bit(WX_STATE_DOWN, wx->state);
wx->misc_irq_domain = false;
return 0;
u64 restart_queue = 0, tx_busy = 0;
u32 i;
- if (!netif_running(wx->netdev) ||
+ if (test_bit(WX_STATE_DOWN, wx->state) ||
test_bit(WX_STATE_RESETTING, wx->state))
return;
if (__netif_subqueue_stopped(tx_ring->netdev,
tx_ring->queue_index) &&
- netif_running(tx_ring->netdev)) {
+ !test_bit(WX_STATE_DOWN, wx->state)) {
netif_wake_subqueue(tx_ring->netdev,
tx_ring->queue_index);
++tx_ring->tx_stats.restart_queue;
if (likely(napi_complete_done(napi, work_done))) {
if (wx->adaptive_itr)
wx_update_dim_sample(q_vector);
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
wx_intr_enable(wx, WX_INTR_Q(q_vector->v_idx));
}
wx_cache_ring_rss(wx);
+ set_bit(WX_STATE_DOWN, wx->state);
+
return 0;
}
EXPORT_SYMBOL(wx_init_interrupt_scheme);
void wx_service_event_schedule(struct wx *wx)
{
- if (!test_and_set_bit(WX_STATE_SERVICE_SCHED, wx->state))
+ if (!test_bit(WX_STATE_DOWN, wx->state) &&
+ !test_and_set_bit(WX_STATE_SERVICE_SCHED, wx->state))
queue_work(system_power_efficient_wq, &wx->service_task);
}
EXPORT_SYMBOL(wx_service_event_schedule);
wx->vfinfo[vf].link_state = state;
switch (state) {
case IFLA_VF_LINK_STATE_AUTO:
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
wx->vfinfo[vf].link_enable = true;
else
wx->vfinfo[vf].link_enable = false;
};
enum wx_state {
+ WX_STATE_DOWN,
WX_STATE_RESETTING,
WX_STATE_SWFW_BUSY,
WX_STATE_PTP_RUNNING,
set_bit(WX_FLAG_NEED_UPDATE_LINK, wx->flags);
/* Clear the interrupt */
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
wr32(wx, WX_VXIMC, wx->eims_other);
return IRQ_HANDLED;
wx_configure_msix_vf(wx);
smp_mb__before_atomic();
+ clear_bit(WX_STATE_DOWN, wx->state);
wx_napi_enable_all(wx);
/* clear any pending interrupts, may auto mask */
{
struct net_device *netdev = wx->netdev;
+ if (test_and_set_bit(WX_STATE_DOWN, wx->state))
+ return;
+
timer_delete_sync(&wx->service_timer);
netif_tx_stop_all_queues(netdev);
netif_tx_disable(netdev);
rtnl_lock();
if (test_bit(WX_STATE_RESETTING, wx->state) ||
- !(netif_running(wx->netdev))) {
+ test_bit(WX_STATE_DOWN, wx->state)) {
rtnl_unlock();
return;
}
/* shared interrupt alert!
* the interrupt that we masked before the EICR read.
*/
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
ngbe_irq_enable(wx, true);
return IRQ_NONE; /* Not our interrupt */
}
/* would disable interrupts here but it is auto disabled */
napi_schedule_irqoff(&q_vector->napi);
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
ngbe_irq_enable(wx, false);
return IRQ_HANDLED;
wx_ptp_check_pps_event(wx);
/* re-enable the original interrupt state, no lsc, no queues */
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
ngbe_irq_enable(wx, false);
return IRQ_HANDLED;
/* queue */
q_vector = wx->q_vector[0];
napi_schedule_irqoff(&q_vector->napi);
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
ngbe_irq_enable(wx, true);
return IRQ_HANDLED;
}
struct net_device *netdev = wx->netdev;
u32 i;
+ if (test_and_set_bit(WX_STATE_DOWN, wx->state))
+ return;
+
if (wx->num_vfs) {
/* Clear EITR Select mapping */
wr32(wx, WX_PX_ITRSEL, 0);
/* make sure to complete pre-operations */
smp_mb__before_atomic();
+ clear_bit(WX_STATE_DOWN, wx->state);
wx_napi_enable_all(wx);
/* enable transmits */
netif_tx_start_all_queues(wx->netdev);
/* shared interrupt alert!
* the interrupt that we masked before the ICR read.
*/
- if (netif_running(wx->netdev))
+ if (!test_bit(WX_STATE_DOWN, wx->state))
txgbe_irq_enable(wx, true);
return IRQ_NONE; /* Not our interrupt */
}
/* make sure to complete pre-operations */
smp_mb__before_atomic();
+ clear_bit(WX_STATE_DOWN, wx->state);
wx_napi_enable_all(wx);
switch (wx->mac.type) {
struct net_device *netdev = wx->netdev;
u32 i;
+ if (test_and_set_bit(WX_STATE_DOWN, wx->state))
+ return;
+
wx_disable_pcie_master(wx);
/* disable receives */
wx_disable_rx(wx);