]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: wangxun: introduce WX_STATE_DOWN to serialize device shutdown state
authorJiawen Wu <jiawenwu@trustnetic.com>
Mon, 25 May 2026 10:05:41 +0000 (18:05 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 28 May 2026 09:51:51 +0000 (11:51 +0200)
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>
drivers/net/ethernet/wangxun/libwx/wx_hw.c
drivers/net/ethernet/wangxun/libwx/wx_lib.c
drivers/net/ethernet/wangxun/libwx/wx_sriov.c
drivers/net/ethernet/wangxun/libwx/wx_type.h
drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c

index 2451f6b20b111594b87c5ca56df7a01a7ba3a8b3..260e14d5d541212181224d4997ef3ee0c5343483 100644 (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;
 
index 746623fa59b40dc466ccc830908b1b8cc805aa29..d042567b81284b5d3bda5408bfbcbeee03e17f74 100644 (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);
index a360b06a086a698993670b4213c60fc0125fedea..0152004a2dd3d7a60e291618326d35f797f37e7e 100644 (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;
index 0da5565ee4ffa617cd0d3a16aeda44b02a59f36e..c7befe4cdfe908baa242e8b46ccd841a351a01bc 100644 (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,
index 94ff8f5f0b4c8f7bfa245b91e6328f3ac3dd65ff..0d2db8d38cd56c75ded20e7f427db5b4b6926057 100644 (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;
        }
index d51d8db95a7639ffee17b26cd787d0a1f6d7dc2f..f4a2dd6fa4930aa22b54dc2f58c026874e78ed6d 100644 (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);
index aa14958d439a2d0c5a4aebd080587d9d3a8a7047..8746318ad3bcb8ea10e91de8c76597533d1d2c33 100644 (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 */
        }
index 4c549c2644ab38fc32199fec22b5ccc18d975733..f9cd1caaf0a449a3a80278d79750bf518e8622e1 100644 (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);