]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bng_en: add per-PF workqueue, timer, and slow-path task
authorBhargava Marreddy <bhargava.marreddy@broadcom.com>
Mon, 6 Apr 2026 18:04:11 +0000 (23:34 +0530)
committerJakub Kicinski <kuba@kernel.org>
Sun, 12 Apr 2026 18:09:36 +0000 (11:09 -0700)
Add a dedicated single-thread workqueue and a timer for each PF
to drive deferred slow-path work such as link event handling and
stats collection. The timer is stopped via timer_delete_sync()
when interrupts are disabled and restarted on open.

While the close path stops the timer to prevent new tasks from
being scheduled, the sp_task and workqueue are preserved to
maintain state continuity. Final draining and destruction of
the workqueue are handled during PCI remove.

Signed-off-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
Reviewed-by: Vikas Gupta <vikas.gupta@broadcom.com>
Reviewed-by: Ajit Kumar Khaparde <ajit.khaparde@broadcom.com>
Link: https://patch.msgid.link/20260406180420.279470-2-bhargava.marreddy@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
drivers/net/ethernet/broadcom/bnge/bnge_netdev.h

index a20dc3ca640cdc9fdb5f6916c53398c5a51556b3..8d5d828e19a32f263532b183100f90193cda0fe7 100644 (file)
@@ -101,6 +101,36 @@ err_free_ring_stats:
        return rc;
 }
 
+static void bnge_timer(struct timer_list *t)
+{
+       struct bnge_net *bn = timer_container_of(bn, t, timer);
+       struct bnge_dev *bd = bn->bd;
+
+       if (!netif_running(bn->netdev) ||
+           !test_bit(BNGE_STATE_OPEN, &bd->state))
+               return;
+
+       /* Periodic work added by later patches */
+
+       mod_timer(&bn->timer, jiffies + bn->current_interval);
+}
+
+static void bnge_sp_task(struct work_struct *work)
+{
+       struct bnge_net *bn = container_of(work, struct bnge_net, sp_task);
+       struct bnge_dev *bd = bn->bd;
+
+       netdev_lock(bn->netdev);
+       if (!test_bit(BNGE_STATE_OPEN, &bd->state)) {
+               netdev_unlock(bn->netdev);
+               return;
+       }
+
+       /* Event handling work added by later patches */
+
+       netdev_unlock(bn->netdev);
+}
+
 static void bnge_free_nq_desc_arr(struct bnge_nq_ring_info *nqr)
 {
        struct bnge_ring_struct *ring = &nqr->ring_struct;
@@ -2507,6 +2537,9 @@ static int bnge_open_core(struct bnge_net *bn)
        bnge_enable_int(bn);
 
        bnge_tx_enable(bn);
+
+       mod_timer(&bn->timer, jiffies + bn->current_interval);
+
        return 0;
 
 err_free_irq:
@@ -2542,6 +2575,8 @@ static void bnge_close_core(struct bnge_net *bn)
        bnge_tx_disable(bn);
 
        clear_bit(BNGE_STATE_OPEN, &bd->state);
+
+       timer_delete_sync(&bn->timer);
        bnge_shutdown_nic(bn);
        bnge_disable_napi(bn);
        bnge_free_all_rings_bufs(bn);
@@ -2774,6 +2809,18 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs)
        if (bd->tso_max_segs)
                netif_set_tso_max_segs(netdev, bd->tso_max_segs);
 
+       INIT_WORK(&bn->sp_task, bnge_sp_task);
+       timer_setup(&bn->timer, bnge_timer, 0);
+       bn->current_interval = BNGE_TIMER_INTERVAL;
+
+       bn->bnge_pf_wq = alloc_ordered_workqueue("bnge_pf_wq-%s", 0,
+                                                dev_name(bd->dev));
+       if (!bn->bnge_pf_wq) {
+               netdev_err(netdev, "Unable to create workqueue.\n");
+               rc = -ENOMEM;
+               goto err_netdev;
+       }
+
        bn->rx_ring_size = BNGE_DEFAULT_RX_RING_SIZE;
        bn->tx_ring_size = BNGE_DEFAULT_TX_RING_SIZE;
        bn->rx_dir = DMA_FROM_DEVICE;
@@ -2789,11 +2836,13 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs)
        rc = register_netdev(netdev);
        if (rc) {
                dev_err(bd->dev, "Register netdev failed rc: %d\n", rc);
-               goto err_netdev;
+               goto err_free_workq;
        }
 
        return 0;
 
+err_free_workq:
+       destroy_workqueue(bn->bnge_pf_wq);
 err_netdev:
        free_netdev(netdev);
        return rc;
@@ -2802,8 +2851,16 @@ err_netdev:
 void bnge_netdev_free(struct bnge_dev *bd)
 {
        struct net_device *netdev = bd->netdev;
+       struct bnge_net *bn;
+
+       bn = netdev_priv(netdev);
 
        unregister_netdev(netdev);
+
+       timer_shutdown_sync(&bn->timer);
+       cancel_work_sync(&bn->sp_task);
+       destroy_workqueue(bn->bnge_pf_wq);
+
        free_netdev(netdev);
        bd->netdev = NULL;
 }
index 70f1a7c2481456c5a9fbb87123e66d2d5e24054b..d2ccee72545401fd5bbfec3baded53878e716604 100644 (file)
@@ -224,6 +224,12 @@ struct bnge_tpa_info {
 #define BNGE_NQ_HDL_TYPE(hdl)  (((hdl) & BNGE_NQ_HDL_TYPE_MASK) >>     \
                                 BNGE_NQ_HDL_TYPE_SHIFT)
 
+enum bnge_net_state {
+       BNGE_STATE_NAPI_DISABLED,
+};
+
+#define BNGE_TIMER_INTERVAL    HZ
+
 struct bnge_net {
        struct bnge_dev         *bd;
        struct net_device       *netdev;
@@ -281,13 +287,17 @@ struct bnge_net {
        u32                     stats_coal_ticks;
 
        unsigned long           state;
-#define BNGE_STATE_NAPI_DISABLED       0
 
        u32                     msg_enable;
        u16                     max_tpa;
        __be16                  vxlan_port;
        __be16                  nge_port;
        __be16                  vxlan_gpe_port;
+
+       unsigned int            current_interval;
+       struct timer_list       timer;
+       struct workqueue_struct *bnge_pf_wq;
+       struct work_struct      sp_task;
 };
 
 #define BNGE_DEFAULT_RX_RING_SIZE      511