Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'ethernet-convert-from-tasklet-to-bh-workqueue'

Allen Pais says:

====================
ethernet: Convert from tasklet to BH workqueue [part]

The only generic interface to execute asynchronously in the BH context is
tasklet; however, it's marked deprecated and has some design flaws. To
replace tasklets, BH workqueue support was recently added. A BH workqueue
behaves similarly to regular workqueues except that the queued work items
are executed in the BH context.

This patch converts a few drivers in drivers/ethernet/* from tasklet
to BH workqueue. The next set will be sent out after the next -rc is
out.

v2: https://lore.kernel.org/20240621183947.4105278-1-allen.lkml@gmail.com
v1: https://lore.kernel.org/20240507190111.16710-2-apais@linux.microsoft.com
====================

Link: https://patch.msgid.link/20240730183403.4176544-1-allen.lkml@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+73 -71
+13 -13
drivers/net/ethernet/alteon/acenic.c
··· 1560 1560 } 1561 1561 1562 1562 1563 - static void ace_tasklet(struct tasklet_struct *t) 1563 + static void ace_bh_work(struct work_struct *work) 1564 1564 { 1565 - struct ace_private *ap = from_tasklet(ap, t, ace_tasklet); 1565 + struct ace_private *ap = from_work(ap, work, ace_bh_work); 1566 1566 struct net_device *dev = ap->ndev; 1567 1567 int cur_size; 1568 1568 ··· 1595 1595 #endif 1596 1596 ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE - cur_size); 1597 1597 } 1598 - ap->tasklet_pending = 0; 1598 + ap->bh_work_pending = 0; 1599 1599 } 1600 1600 1601 1601 ··· 1617 1617 * 1618 1618 * Loading rings is safe without holding the spin lock since this is 1619 1619 * done only before the device is enabled, thus no interrupts are 1620 - * generated and by the interrupt handler/tasklet handler. 1620 + * generated and by the interrupt handler/bh handler. 1621 1621 */ 1622 1622 static void ace_load_std_rx_ring(struct net_device *dev, int nr_bufs) 1623 1623 { ··· 2160 2160 */ 2161 2161 if (netif_running(dev)) { 2162 2162 int cur_size; 2163 - int run_tasklet = 0; 2163 + int run_bh_work = 0; 2164 2164 2165 2165 cur_size = atomic_read(&ap->cur_rx_bufs); 2166 2166 if (cur_size < RX_LOW_STD_THRES) { ··· 2172 2172 ace_load_std_rx_ring(dev, 2173 2173 RX_RING_SIZE - cur_size); 2174 2174 } else 2175 - run_tasklet = 1; 2175 + run_bh_work = 1; 2176 2176 } 2177 2177 2178 2178 if (!ACE_IS_TIGON_I(ap)) { ··· 2188 2188 ace_load_mini_rx_ring(dev, 2189 2189 RX_MINI_SIZE - cur_size); 2190 2190 } else 2191 - run_tasklet = 1; 2191 + run_bh_work = 1; 2192 2192 } 2193 2193 } 2194 2194 ··· 2205 2205 ace_load_jumbo_rx_ring(dev, 2206 2206 RX_JUMBO_SIZE - cur_size); 2207 2207 } else 2208 - run_tasklet = 1; 2208 + run_bh_work = 1; 2209 2209 } 2210 2210 } 2211 - if (run_tasklet && !ap->tasklet_pending) { 2212 - ap->tasklet_pending = 1; 2213 - tasklet_schedule(&ap->ace_tasklet); 2211 + if (run_bh_work && !ap->bh_work_pending) { 2212 + ap->bh_work_pending = 1; 2213 + queue_work(system_bh_wq, &ap->ace_bh_work); 2214 2214 } 2215 2215 } 2216 2216 ··· 2267 2267 /* 2268 2268 * Setup the bottom half rx ring refill handler 2269 2269 */ 2270 - tasklet_setup(&ap->ace_tasklet, ace_tasklet); 2270 + INIT_WORK(&ap->ace_bh_work, ace_bh_work); 2271 2271 return 0; 2272 2272 } 2273 2273 ··· 2301 2301 cmd.idx = 0; 2302 2302 ace_issue_cmd(regs, &cmd); 2303 2303 2304 - tasklet_kill(&ap->ace_tasklet); 2304 + cancel_work_sync(&ap->ace_bh_work); 2305 2305 2306 2306 /* 2307 2307 * Make sure one CPU is not processing packets while
+4 -4
drivers/net/ethernet/alteon/acenic.h
··· 2 2 #ifndef _ACENIC_H_ 3 3 #define _ACENIC_H_ 4 4 #include <linux/interrupt.h> 5 - 5 + #include <linux/workqueue.h> 6 6 7 7 /* 8 8 * Generate TX index update each time, when TX ring is closed. ··· 667 667 struct rx_desc *rx_mini_ring; 668 668 struct rx_desc *rx_return_ring; 669 669 670 - int tasklet_pending, jumbo; 671 - struct tasklet_struct ace_tasklet; 670 + int bh_work_pending, jumbo; 671 + struct work_struct ace_bh_work; 672 672 673 673 struct event *evt_ring; 674 674 ··· 776 776 static netdev_tx_t ace_start_xmit(struct sk_buff *skb, 777 777 struct net_device *dev); 778 778 static int ace_close(struct net_device *dev); 779 - static void ace_tasklet(struct tasklet_struct *t); 779 + static void ace_bh_work(struct work_struct *work); 780 780 static void ace_dump_trace(struct ace_private *ap); 781 781 static void ace_set_multicast_list(struct net_device *dev); 782 782 static int ace_change_mtu(struct net_device *dev, int new_mtu);
+15 -15
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
··· 403 403 return false; 404 404 } 405 405 406 - static void xgbe_ecc_isr_task(struct tasklet_struct *t) 406 + static void xgbe_ecc_isr_bh_work(struct work_struct *work) 407 407 { 408 - struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_ecc); 408 + struct xgbe_prv_data *pdata = from_work(pdata, work, ecc_bh_work); 409 409 unsigned int ecc_isr; 410 410 bool stop = false; 411 411 ··· 465 465 { 466 466 struct xgbe_prv_data *pdata = data; 467 467 468 - if (pdata->isr_as_tasklet) 469 - tasklet_schedule(&pdata->tasklet_ecc); 468 + if (pdata->isr_as_bh_work) 469 + queue_work(system_bh_wq, &pdata->ecc_bh_work); 470 470 else 471 - xgbe_ecc_isr_task(&pdata->tasklet_ecc); 471 + xgbe_ecc_isr_bh_work(&pdata->ecc_bh_work); 472 472 473 473 return IRQ_HANDLED; 474 474 } 475 475 476 - static void xgbe_isr_task(struct tasklet_struct *t) 476 + static void xgbe_isr_bh_work(struct work_struct *work) 477 477 { 478 - struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_dev); 478 + struct xgbe_prv_data *pdata = from_work(pdata, work, dev_bh_work); 479 479 struct xgbe_hw_if *hw_if = &pdata->hw_if; 480 480 struct xgbe_channel *channel; 481 481 unsigned int dma_isr, dma_ch_isr; ··· 582 582 583 583 /* If there is not a separate ECC irq, handle it here */ 584 584 if (pdata->vdata->ecc_support && (pdata->dev_irq == pdata->ecc_irq)) 585 - xgbe_ecc_isr_task(&pdata->tasklet_ecc); 585 + xgbe_ecc_isr_bh_work(&pdata->ecc_bh_work); 586 586 587 587 /* If there is not a separate I2C irq, handle it here */ 588 588 if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq)) ··· 604 604 { 605 605 struct xgbe_prv_data *pdata = data; 606 606 607 - if (pdata->isr_as_tasklet) 608 - tasklet_schedule(&pdata->tasklet_dev); 607 + if (pdata->isr_as_bh_work) 608 + queue_work(system_bh_wq, &pdata->dev_bh_work); 609 609 else 610 - xgbe_isr_task(&pdata->tasklet_dev); 610 + xgbe_isr_bh_work(&pdata->dev_bh_work); 611 611 612 612 return IRQ_HANDLED; 613 613 } ··· 1007 1007 unsigned int i; 1008 1008 int ret; 1009 1009 1010 - tasklet_setup(&pdata->tasklet_dev, xgbe_isr_task); 1011 - tasklet_setup(&pdata->tasklet_ecc, xgbe_ecc_isr_task); 1010 + INIT_WORK(&pdata->dev_bh_work, xgbe_isr_bh_work); 1011 + INIT_WORK(&pdata->ecc_bh_work, xgbe_ecc_isr_bh_work); 1012 1012 1013 1013 ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0, 1014 1014 netdev_name(netdev), pdata); ··· 1078 1078 1079 1079 devm_free_irq(pdata->dev, pdata->dev_irq, pdata); 1080 1080 1081 - tasklet_kill(&pdata->tasklet_dev); 1082 - tasklet_kill(&pdata->tasklet_ecc); 1081 + cancel_work_sync(&pdata->dev_bh_work); 1082 + cancel_work_sync(&pdata->ecc_bh_work); 1083 1083 1084 1084 if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) 1085 1085 devm_free_irq(pdata->dev, pdata->ecc_irq, pdata);
+8 -8
drivers/net/ethernet/amd/xgbe/xgbe-i2c.c
··· 274 274 XI2C_IOREAD(pdata, IC_CLR_STOP_DET); 275 275 } 276 276 277 - static void xgbe_i2c_isr_task(struct tasklet_struct *t) 277 + static void xgbe_i2c_isr_bh_work(struct work_struct *work) 278 278 { 279 - struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_i2c); 279 + struct xgbe_prv_data *pdata = from_work(pdata, work, i2c_bh_work); 280 280 struct xgbe_i2c_op_state *state = &pdata->i2c.op_state; 281 281 unsigned int isr; 282 282 ··· 321 321 { 322 322 struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; 323 323 324 - if (pdata->isr_as_tasklet) 325 - tasklet_schedule(&pdata->tasklet_i2c); 324 + if (pdata->isr_as_bh_work) 325 + queue_work(system_bh_wq, &pdata->i2c_bh_work); 326 326 else 327 - xgbe_i2c_isr_task(&pdata->tasklet_i2c); 327 + xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work); 328 328 329 329 return IRQ_HANDLED; 330 330 } ··· 369 369 370 370 static irqreturn_t xgbe_i2c_combined_isr(struct xgbe_prv_data *pdata) 371 371 { 372 - xgbe_i2c_isr_task(&pdata->tasklet_i2c); 372 + xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work); 373 373 374 374 return IRQ_HANDLED; 375 375 } ··· 449 449 450 450 if (pdata->dev_irq != pdata->i2c_irq) { 451 451 devm_free_irq(pdata->dev, pdata->i2c_irq, pdata); 452 - tasklet_kill(&pdata->tasklet_i2c); 452 + cancel_work_sync(&pdata->i2c_bh_work); 453 453 } 454 454 } 455 455 ··· 464 464 465 465 /* If we have a separate I2C irq, enable it */ 466 466 if (pdata->dev_irq != pdata->i2c_irq) { 467 - tasklet_setup(&pdata->tasklet_i2c, xgbe_i2c_isr_task); 467 + INIT_WORK(&pdata->i2c_bh_work, xgbe_i2c_isr_bh_work); 468 468 469 469 ret = devm_request_irq(pdata->dev, pdata->i2c_irq, 470 470 xgbe_i2c_isr, 0, pdata->i2c_name,
+8 -8
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
··· 703 703 } 704 704 } 705 705 706 - static void xgbe_an_isr_task(struct tasklet_struct *t) 706 + static void xgbe_an_isr_bh_work(struct work_struct *work) 707 707 { 708 - struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_an); 708 + struct xgbe_prv_data *pdata = from_work(pdata, work, an_bh_work); 709 709 710 710 netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n"); 711 711 ··· 727 727 { 728 728 struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; 729 729 730 - if (pdata->isr_as_tasklet) 731 - tasklet_schedule(&pdata->tasklet_an); 730 + if (pdata->isr_as_bh_work) 731 + queue_work(system_bh_wq, &pdata->an_bh_work); 732 732 else 733 - xgbe_an_isr_task(&pdata->tasklet_an); 733 + xgbe_an_isr_bh_work(&pdata->an_bh_work); 734 734 735 735 return IRQ_HANDLED; 736 736 } 737 737 738 738 static irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata) 739 739 { 740 - xgbe_an_isr_task(&pdata->tasklet_an); 740 + xgbe_an_isr_bh_work(&pdata->an_bh_work); 741 741 742 742 return IRQ_HANDLED; 743 743 } ··· 1454 1454 1455 1455 if (pdata->dev_irq != pdata->an_irq) { 1456 1456 devm_free_irq(pdata->dev, pdata->an_irq, pdata); 1457 - tasklet_kill(&pdata->tasklet_an); 1457 + cancel_work_sync(&pdata->an_bh_work); 1458 1458 } 1459 1459 1460 1460 pdata->phy_if.phy_impl.stop(pdata); ··· 1477 1477 1478 1478 /* If we have a separate AN irq, enable it */ 1479 1479 if (pdata->dev_irq != pdata->an_irq) { 1480 - tasklet_setup(&pdata->tasklet_an, xgbe_an_isr_task); 1480 + INIT_WORK(&pdata->an_bh_work, xgbe_an_isr_bh_work); 1481 1481 1482 1482 ret = devm_request_irq(pdata->dev, pdata->an_irq, 1483 1483 xgbe_an_isr, 0, pdata->an_name,
+2 -2
drivers/net/ethernet/amd/xgbe/xgbe-pci.c
··· 139 139 return ret; 140 140 } 141 141 142 - pdata->isr_as_tasklet = 1; 142 + pdata->isr_as_bh_work = 1; 143 143 pdata->irq_count = ret; 144 144 145 145 pdata->dev_irq = pci_irq_vector(pdata->pcidev, 0); ··· 176 176 return ret; 177 177 } 178 178 179 - pdata->isr_as_tasklet = pdata->pcidev->msi_enabled ? 1 : 0; 179 + pdata->isr_as_bh_work = pdata->pcidev->msi_enabled ? 1 : 0; 180 180 pdata->irq_count = 1; 181 181 pdata->channel_irq_count = 1; 182 182
+5 -5
drivers/net/ethernet/amd/xgbe/xgbe.h
··· 1298 1298 1299 1299 unsigned int lpm_ctrl; /* CTRL1 for resume */ 1300 1300 1301 - unsigned int isr_as_tasklet; 1302 - struct tasklet_struct tasklet_dev; 1303 - struct tasklet_struct tasklet_ecc; 1304 - struct tasklet_struct tasklet_i2c; 1305 - struct tasklet_struct tasklet_an; 1301 + unsigned int isr_as_bh_work; 1302 + struct work_struct dev_bh_work; 1303 + struct work_struct ecc_bh_work; 1304 + struct work_struct i2c_bh_work; 1305 + struct work_struct an_bh_work; 1306 1306 1307 1307 struct dentry *xgbe_debugfs; 1308 1308
+10 -9
drivers/net/ethernet/broadcom/cnic.c
··· 31 31 #include <linux/if_vlan.h> 32 32 #include <linux/prefetch.h> 33 33 #include <linux/random.h> 34 + #include <linux/workqueue.h> 34 35 #if IS_ENABLED(CONFIG_VLAN_8021Q) 35 36 #define BCM_VLAN 1 36 37 #endif ··· 3016 3015 return cnic_service_bnx2_queues(dev); 3017 3016 } 3018 3017 3019 - static void cnic_service_bnx2_msix(struct tasklet_struct *t) 3018 + static void cnic_service_bnx2_msix(struct work_struct *work) 3020 3019 { 3021 - struct cnic_local *cp = from_tasklet(cp, t, cnic_irq_task); 3020 + struct cnic_local *cp = from_work(cp, work, cnic_irq_bh_work); 3022 3021 struct cnic_dev *dev = cp->dev; 3023 3022 3024 3023 cp->last_status_idx = cnic_service_bnx2_queues(dev); ··· 3037 3036 prefetch(cp->status_blk.gen); 3038 3037 prefetch(&cp->kcq1.kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); 3039 3038 3040 - tasklet_schedule(&cp->cnic_irq_task); 3039 + queue_work(system_bh_wq, &cp->cnic_irq_bh_work); 3041 3040 } 3042 3041 } 3043 3042 ··· 3141 3140 return last_status; 3142 3141 } 3143 3142 3144 - static void cnic_service_bnx2x_bh(struct tasklet_struct *t) 3143 + static void cnic_service_bnx2x_bh_work(struct work_struct *work) 3145 3144 { 3146 - struct cnic_local *cp = from_tasklet(cp, t, cnic_irq_task); 3145 + struct cnic_local *cp = from_work(cp, work, cnic_irq_bh_work); 3147 3146 struct cnic_dev *dev = cp->dev; 3148 3147 struct bnx2x *bp = netdev_priv(dev->netdev); 3149 3148 u32 status_idx, new_status_idx; ··· 4429 4428 4430 4429 if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { 4431 4430 cp->disable_int_sync(dev); 4432 - tasklet_kill(&cp->cnic_irq_task); 4431 + cancel_work_sync(&cp->cnic_irq_bh_work); 4433 4432 free_irq(ethdev->irq_arr[0].vector, dev); 4434 4433 } 4435 4434 } ··· 4442 4441 4443 4442 err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, "cnic", dev); 4444 4443 if (err) 4445 - tasklet_disable(&cp->cnic_irq_task); 4444 + disable_work_sync(&cp->cnic_irq_bh_work); 4446 4445 4447 4446 return err; 4448 4447 } ··· 4465 4464 CNIC_WR(dev, base + BNX2_HC_CMD_TICKS_OFF, (64 << 16) | 220); 4466 4465 4467 4466 cp->last_status_idx = cp->status_blk.bnx2->status_idx; 4468 - tasklet_setup(&cp->cnic_irq_task, cnic_service_bnx2_msix); 4467 + INIT_WORK(&cp->cnic_irq_bh_work, cnic_service_bnx2_msix); 4469 4468 err = cnic_request_irq(dev); 4470 4469 if (err) 4471 4470 return err; ··· 4874 4873 struct cnic_eth_dev *ethdev = cp->ethdev; 4875 4874 int err = 0; 4876 4875 4877 - tasklet_setup(&cp->cnic_irq_task, cnic_service_bnx2x_bh); 4876 + INIT_WORK(&cp->cnic_irq_bh_work, cnic_service_bnx2x_bh_work); 4878 4877 if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) 4879 4878 err = cnic_request_irq(dev); 4880 4879
+1 -1
drivers/net/ethernet/broadcom/cnic.h
··· 268 268 u32 bnx2x_igu_sb_id; 269 269 u32 int_num; 270 270 u32 last_status_idx; 271 - struct tasklet_struct cnic_irq_task; 271 + struct work_struct cnic_irq_bh_work; 272 272 273 273 struct kcqe *completed_kcq[MAX_COMPLETED_KCQE]; 274 274
+2 -1
drivers/net/ethernet/cadence/macb.h
··· 13 13 #include <linux/net_tstamp.h> 14 14 #include <linux/interrupt.h> 15 15 #include <linux/phy/phy.h> 16 + #include <linux/workqueue.h> 16 17 17 18 #if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP) 18 19 #define MACB_EXT_DESC ··· 1331 1330 spinlock_t rx_fs_lock; 1332 1331 unsigned int max_tuples; 1333 1332 1334 - struct tasklet_struct hresp_err_tasklet; 1333 + struct work_struct hresp_err_bh_work; 1335 1334 1336 1335 int rx_bd_rd_prefetch; 1337 1336 int tx_bd_rd_prefetch;
+5 -5
drivers/net/ethernet/cadence/macb_main.c
··· 1792 1792 return work_done; 1793 1793 } 1794 1794 1795 - static void macb_hresp_error_task(struct tasklet_struct *t) 1795 + static void macb_hresp_error_task(struct work_struct *work) 1796 1796 { 1797 - struct macb *bp = from_tasklet(bp, t, hresp_err_tasklet); 1797 + struct macb *bp = from_work(bp, work, hresp_err_bh_work); 1798 1798 struct net_device *dev = bp->dev; 1799 1799 struct macb_queue *queue; 1800 1800 unsigned int q; ··· 1994 1994 } 1995 1995 1996 1996 if (status & MACB_BIT(HRESP)) { 1997 - tasklet_schedule(&bp->hresp_err_tasklet); 1997 + queue_work(system_bh_wq, &bp->hresp_err_bh_work); 1998 1998 netdev_err(dev, "DMA bus error: HRESP not OK\n"); 1999 1999 2000 2000 if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) ··· 5172 5172 goto err_out_unregister_mdio; 5173 5173 } 5174 5174 5175 - tasklet_setup(&bp->hresp_err_tasklet, macb_hresp_error_task); 5175 + INIT_WORK(&bp->hresp_err_bh_work, macb_hresp_error_task); 5176 5176 5177 5177 netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", 5178 5178 macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), ··· 5216 5216 mdiobus_free(bp->mii_bus); 5217 5217 5218 5218 unregister_netdev(dev); 5219 - tasklet_kill(&bp->hresp_err_tasklet); 5219 + cancel_work_sync(&bp->hresp_err_bh_work); 5220 5220 pm_runtime_disable(&pdev->dev); 5221 5221 pm_runtime_dont_use_autosuspend(&pdev->dev); 5222 5222 if (!pm_runtime_suspended(&pdev->dev)) {