net: wangxun: introduce WX_STATE_DOWN to serialize device shutdown state

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>
This commit is contained in:
Jiawen Wu 2026-05-25 18:05:41 +08:00 committed by Paolo Abeni
parent fabcf8cad6
commit 7116ffb48a
8 changed files with 29 additions and 12 deletions

View File

@ -2520,6 +2520,7 @@ int wx_sw_init(struct wx *wx)
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;
@ -2875,7 +2876,7 @@ void wx_update_stats(struct wx *wx)
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;

View File

@ -876,7 +876,7 @@ static bool wx_clean_tx_irq(struct wx_q_vector *q_vector,
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;
@ -964,7 +964,7 @@ static int wx_poll(struct napi_struct *napi, int budget)
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));
}
@ -2341,6 +2341,8 @@ int wx_init_interrupt_scheme(struct wx *wx)
wx_cache_ring_rss(wx);
set_bit(WX_STATE_DOWN, wx->state);
return 0;
}
EXPORT_SYMBOL(wx_init_interrupt_scheme);
@ -3314,7 +3316,8 @@ EXPORT_SYMBOL(wx_set_ring);
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);

View File

@ -898,7 +898,7 @@ static void wx_set_vf_link_state(struct wx *wx, int vf, int state)
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;

View File

@ -1202,6 +1202,7 @@ struct wx_last_stats {
};
enum wx_state {
WX_STATE_DOWN,
WX_STATE_RESETTING,
WX_STATE_SWFW_BUSY,
WX_STATE_PTP_RUNNING,

View File

@ -68,7 +68,7 @@ static irqreturn_t wx_msix_misc_vf(int __always_unused irq, void *data)
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;
@ -278,6 +278,7 @@ static void wxvf_up_complete(struct wx *wx)
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 */
@ -327,6 +328,9 @@ static void wxvf_down(struct wx *wx)
{
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);
@ -360,7 +364,7 @@ static void wxvf_reset_subtask(struct wx *wx)
rtnl_lock();
if (test_bit(WX_STATE_RESETTING, wx->state) ||
!(netif_running(wx->netdev))) {
test_bit(WX_STATE_DOWN, wx->state)) {
rtnl_unlock();
return;
}

View File

@ -204,7 +204,7 @@ static irqreturn_t ngbe_intr(int __always_unused irq, void *data)
/* 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 */
}
@ -220,7 +220,7 @@ static irqreturn_t ngbe_intr(int __always_unused irq, void *data)
/* 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;
@ -235,7 +235,7 @@ static irqreturn_t __ngbe_msix_misc(struct wx *wx, u32 eicr)
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;
@ -262,7 +262,7 @@ static irqreturn_t ngbe_misc_and_queue(int __always_unused irq, void *data)
/* 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;
}
@ -363,6 +363,9 @@ static void ngbe_disable_device(struct wx *wx)
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);
@ -428,6 +431,7 @@ void ngbe_up(struct wx *wx)
/* 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);

View File

@ -141,7 +141,7 @@ static irqreturn_t txgbe_misc_irq_handle(int irq, void *data)
/* 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 */
}

View File

@ -151,6 +151,7 @@ static void txgbe_up_complete(struct wx *wx)
/* 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) {
@ -213,6 +214,9 @@ static void txgbe_disable_device(struct wx *wx)
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);