mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
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:
parent
fabcf8cad6
commit
7116ffb48a
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user