Commit 8e0c0ec9 authored by Jakub Kicinski's avatar Jakub Kicinski

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.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 9bb3ec18 c5092ba3
...@@ -1560,9 +1560,9 @@ static void ace_watchdog(struct net_device *data, unsigned int txqueue) ...@@ -1560,9 +1560,9 @@ static void ace_watchdog(struct net_device *data, unsigned int txqueue)
} }
static void ace_tasklet(struct tasklet_struct *t) static void ace_bh_work(struct work_struct *work)
{ {
struct ace_private *ap = from_tasklet(ap, t, ace_tasklet); struct ace_private *ap = from_work(ap, work, ace_bh_work);
struct net_device *dev = ap->ndev; struct net_device *dev = ap->ndev;
int cur_size; int cur_size;
...@@ -1595,7 +1595,7 @@ static void ace_tasklet(struct tasklet_struct *t) ...@@ -1595,7 +1595,7 @@ static void ace_tasklet(struct tasklet_struct *t)
#endif #endif
ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE - cur_size); ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE - cur_size);
} }
ap->tasklet_pending = 0; ap->bh_work_pending = 0;
} }
...@@ -1617,7 +1617,7 @@ static void ace_dump_trace(struct ace_private *ap) ...@@ -1617,7 +1617,7 @@ static void ace_dump_trace(struct ace_private *ap)
* *
* Loading rings is safe without holding the spin lock since this is * Loading rings is safe without holding the spin lock since this is
* done only before the device is enabled, thus no interrupts are * done only before the device is enabled, thus no interrupts are
* generated and by the interrupt handler/tasklet handler. * generated and by the interrupt handler/bh handler.
*/ */
static void ace_load_std_rx_ring(struct net_device *dev, int nr_bufs) static void ace_load_std_rx_ring(struct net_device *dev, int nr_bufs)
{ {
...@@ -2160,7 +2160,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id) ...@@ -2160,7 +2160,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
*/ */
if (netif_running(dev)) { if (netif_running(dev)) {
int cur_size; int cur_size;
int run_tasklet = 0; int run_bh_work = 0;
cur_size = atomic_read(&ap->cur_rx_bufs); cur_size = atomic_read(&ap->cur_rx_bufs);
if (cur_size < RX_LOW_STD_THRES) { if (cur_size < RX_LOW_STD_THRES) {
...@@ -2172,7 +2172,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id) ...@@ -2172,7 +2172,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
ace_load_std_rx_ring(dev, ace_load_std_rx_ring(dev,
RX_RING_SIZE - cur_size); RX_RING_SIZE - cur_size);
} else } else
run_tasklet = 1; run_bh_work = 1;
} }
if (!ACE_IS_TIGON_I(ap)) { if (!ACE_IS_TIGON_I(ap)) {
...@@ -2188,7 +2188,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id) ...@@ -2188,7 +2188,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
ace_load_mini_rx_ring(dev, ace_load_mini_rx_ring(dev,
RX_MINI_SIZE - cur_size); RX_MINI_SIZE - cur_size);
} else } else
run_tasklet = 1; run_bh_work = 1;
} }
} }
...@@ -2205,12 +2205,12 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id) ...@@ -2205,12 +2205,12 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
ace_load_jumbo_rx_ring(dev, ace_load_jumbo_rx_ring(dev,
RX_JUMBO_SIZE - cur_size); RX_JUMBO_SIZE - cur_size);
} else } else
run_tasklet = 1; run_bh_work = 1;
} }
} }
if (run_tasklet && !ap->tasklet_pending) { if (run_bh_work && !ap->bh_work_pending) {
ap->tasklet_pending = 1; ap->bh_work_pending = 1;
tasklet_schedule(&ap->ace_tasklet); queue_work(system_bh_wq, &ap->ace_bh_work);
} }
} }
...@@ -2267,7 +2267,7 @@ static int ace_open(struct net_device *dev) ...@@ -2267,7 +2267,7 @@ static int ace_open(struct net_device *dev)
/* /*
* Setup the bottom half rx ring refill handler * Setup the bottom half rx ring refill handler
*/ */
tasklet_setup(&ap->ace_tasklet, ace_tasklet); INIT_WORK(&ap->ace_bh_work, ace_bh_work);
return 0; return 0;
} }
...@@ -2301,7 +2301,7 @@ static int ace_close(struct net_device *dev) ...@@ -2301,7 +2301,7 @@ static int ace_close(struct net_device *dev)
cmd.idx = 0; cmd.idx = 0;
ace_issue_cmd(regs, &cmd); ace_issue_cmd(regs, &cmd);
tasklet_kill(&ap->ace_tasklet); cancel_work_sync(&ap->ace_bh_work);
/* /*
* Make sure one CPU is not processing packets while * Make sure one CPU is not processing packets while
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#ifndef _ACENIC_H_ #ifndef _ACENIC_H_
#define _ACENIC_H_ #define _ACENIC_H_
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/workqueue.h>
/* /*
* Generate TX index update each time, when TX ring is closed. * Generate TX index update each time, when TX ring is closed.
...@@ -667,8 +667,8 @@ struct ace_private ...@@ -667,8 +667,8 @@ struct ace_private
struct rx_desc *rx_mini_ring; struct rx_desc *rx_mini_ring;
struct rx_desc *rx_return_ring; struct rx_desc *rx_return_ring;
int tasklet_pending, jumbo; int bh_work_pending, jumbo;
struct tasklet_struct ace_tasklet; struct work_struct ace_bh_work;
struct event *evt_ring; struct event *evt_ring;
...@@ -776,7 +776,7 @@ static int ace_open(struct net_device *dev); ...@@ -776,7 +776,7 @@ static int ace_open(struct net_device *dev);
static netdev_tx_t ace_start_xmit(struct sk_buff *skb, static netdev_tx_t ace_start_xmit(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
static int ace_close(struct net_device *dev); static int ace_close(struct net_device *dev);
static void ace_tasklet(struct tasklet_struct *t); static void ace_bh_work(struct work_struct *work);
static void ace_dump_trace(struct ace_private *ap); static void ace_dump_trace(struct ace_private *ap);
static void ace_set_multicast_list(struct net_device *dev); static void ace_set_multicast_list(struct net_device *dev);
static int ace_change_mtu(struct net_device *dev, int new_mtu); static int ace_change_mtu(struct net_device *dev, int new_mtu);
......
...@@ -403,9 +403,9 @@ static bool xgbe_ecc_ded(struct xgbe_prv_data *pdata, unsigned long *period, ...@@ -403,9 +403,9 @@ static bool xgbe_ecc_ded(struct xgbe_prv_data *pdata, unsigned long *period,
return false; return false;
} }
static void xgbe_ecc_isr_task(struct tasklet_struct *t) static void xgbe_ecc_isr_bh_work(struct work_struct *work)
{ {
struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_ecc); struct xgbe_prv_data *pdata = from_work(pdata, work, ecc_bh_work);
unsigned int ecc_isr; unsigned int ecc_isr;
bool stop = false; bool stop = false;
...@@ -465,17 +465,17 @@ static irqreturn_t xgbe_ecc_isr(int irq, void *data) ...@@ -465,17 +465,17 @@ static irqreturn_t xgbe_ecc_isr(int irq, void *data)
{ {
struct xgbe_prv_data *pdata = data; struct xgbe_prv_data *pdata = data;
if (pdata->isr_as_tasklet) if (pdata->isr_as_bh_work)
tasklet_schedule(&pdata->tasklet_ecc); queue_work(system_bh_wq, &pdata->ecc_bh_work);
else else
xgbe_ecc_isr_task(&pdata->tasklet_ecc); xgbe_ecc_isr_bh_work(&pdata->ecc_bh_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void xgbe_isr_task(struct tasklet_struct *t) static void xgbe_isr_bh_work(struct work_struct *work)
{ {
struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_dev); struct xgbe_prv_data *pdata = from_work(pdata, work, dev_bh_work);
struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_channel *channel; struct xgbe_channel *channel;
unsigned int dma_isr, dma_ch_isr; unsigned int dma_isr, dma_ch_isr;
...@@ -582,7 +582,7 @@ static void xgbe_isr_task(struct tasklet_struct *t) ...@@ -582,7 +582,7 @@ static void xgbe_isr_task(struct tasklet_struct *t)
/* If there is not a separate ECC irq, handle it here */ /* If there is not a separate ECC irq, handle it here */
if (pdata->vdata->ecc_support && (pdata->dev_irq == pdata->ecc_irq)) if (pdata->vdata->ecc_support && (pdata->dev_irq == pdata->ecc_irq))
xgbe_ecc_isr_task(&pdata->tasklet_ecc); xgbe_ecc_isr_bh_work(&pdata->ecc_bh_work);
/* If there is not a separate I2C irq, handle it here */ /* If there is not a separate I2C irq, handle it here */
if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq)) if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq))
...@@ -604,10 +604,10 @@ static irqreturn_t xgbe_isr(int irq, void *data) ...@@ -604,10 +604,10 @@ static irqreturn_t xgbe_isr(int irq, void *data)
{ {
struct xgbe_prv_data *pdata = data; struct xgbe_prv_data *pdata = data;
if (pdata->isr_as_tasklet) if (pdata->isr_as_bh_work)
tasklet_schedule(&pdata->tasklet_dev); queue_work(system_bh_wq, &pdata->dev_bh_work);
else else
xgbe_isr_task(&pdata->tasklet_dev); xgbe_isr_bh_work(&pdata->dev_bh_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1007,8 +1007,8 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) ...@@ -1007,8 +1007,8 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata)
unsigned int i; unsigned int i;
int ret; int ret;
tasklet_setup(&pdata->tasklet_dev, xgbe_isr_task); INIT_WORK(&pdata->dev_bh_work, xgbe_isr_bh_work);
tasklet_setup(&pdata->tasklet_ecc, xgbe_ecc_isr_task); INIT_WORK(&pdata->ecc_bh_work, xgbe_ecc_isr_bh_work);
ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0, ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
netdev_name(netdev), pdata); netdev_name(netdev), pdata);
...@@ -1078,8 +1078,8 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata) ...@@ -1078,8 +1078,8 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata)
devm_free_irq(pdata->dev, pdata->dev_irq, pdata); devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
tasklet_kill(&pdata->tasklet_dev); cancel_work_sync(&pdata->dev_bh_work);
tasklet_kill(&pdata->tasklet_ecc); cancel_work_sync(&pdata->ecc_bh_work);
if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq))
devm_free_irq(pdata->dev, pdata->ecc_irq, pdata); devm_free_irq(pdata->dev, pdata->ecc_irq, pdata);
......
...@@ -274,9 +274,9 @@ static void xgbe_i2c_clear_isr_interrupts(struct xgbe_prv_data *pdata, ...@@ -274,9 +274,9 @@ static void xgbe_i2c_clear_isr_interrupts(struct xgbe_prv_data *pdata,
XI2C_IOREAD(pdata, IC_CLR_STOP_DET); XI2C_IOREAD(pdata, IC_CLR_STOP_DET);
} }
static void xgbe_i2c_isr_task(struct tasklet_struct *t) static void xgbe_i2c_isr_bh_work(struct work_struct *work)
{ {
struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_i2c); struct xgbe_prv_data *pdata = from_work(pdata, work, i2c_bh_work);
struct xgbe_i2c_op_state *state = &pdata->i2c.op_state; struct xgbe_i2c_op_state *state = &pdata->i2c.op_state;
unsigned int isr; unsigned int isr;
...@@ -321,10 +321,10 @@ static irqreturn_t xgbe_i2c_isr(int irq, void *data) ...@@ -321,10 +321,10 @@ static irqreturn_t xgbe_i2c_isr(int irq, void *data)
{ {
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
if (pdata->isr_as_tasklet) if (pdata->isr_as_bh_work)
tasklet_schedule(&pdata->tasklet_i2c); queue_work(system_bh_wq, &pdata->i2c_bh_work);
else else
xgbe_i2c_isr_task(&pdata->tasklet_i2c); xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -369,7 +369,7 @@ static void xgbe_i2c_set_target(struct xgbe_prv_data *pdata, unsigned int addr) ...@@ -369,7 +369,7 @@ static void xgbe_i2c_set_target(struct xgbe_prv_data *pdata, unsigned int addr)
static irqreturn_t xgbe_i2c_combined_isr(struct xgbe_prv_data *pdata) static irqreturn_t xgbe_i2c_combined_isr(struct xgbe_prv_data *pdata)
{ {
xgbe_i2c_isr_task(&pdata->tasklet_i2c); xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -449,7 +449,7 @@ static void xgbe_i2c_stop(struct xgbe_prv_data *pdata) ...@@ -449,7 +449,7 @@ static void xgbe_i2c_stop(struct xgbe_prv_data *pdata)
if (pdata->dev_irq != pdata->i2c_irq) { if (pdata->dev_irq != pdata->i2c_irq) {
devm_free_irq(pdata->dev, pdata->i2c_irq, pdata); devm_free_irq(pdata->dev, pdata->i2c_irq, pdata);
tasklet_kill(&pdata->tasklet_i2c); cancel_work_sync(&pdata->i2c_bh_work);
} }
} }
...@@ -464,7 +464,7 @@ static int xgbe_i2c_start(struct xgbe_prv_data *pdata) ...@@ -464,7 +464,7 @@ static int xgbe_i2c_start(struct xgbe_prv_data *pdata)
/* If we have a separate I2C irq, enable it */ /* If we have a separate I2C irq, enable it */
if (pdata->dev_irq != pdata->i2c_irq) { if (pdata->dev_irq != pdata->i2c_irq) {
tasklet_setup(&pdata->tasklet_i2c, xgbe_i2c_isr_task); INIT_WORK(&pdata->i2c_bh_work, xgbe_i2c_isr_bh_work);
ret = devm_request_irq(pdata->dev, pdata->i2c_irq, ret = devm_request_irq(pdata->dev, pdata->i2c_irq,
xgbe_i2c_isr, 0, pdata->i2c_name, xgbe_i2c_isr, 0, pdata->i2c_name,
......
...@@ -703,9 +703,9 @@ static void xgbe_an73_isr(struct xgbe_prv_data *pdata) ...@@ -703,9 +703,9 @@ static void xgbe_an73_isr(struct xgbe_prv_data *pdata)
} }
} }
static void xgbe_an_isr_task(struct tasklet_struct *t) static void xgbe_an_isr_bh_work(struct work_struct *work)
{ {
struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_an); struct xgbe_prv_data *pdata = from_work(pdata, work, an_bh_work);
netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n"); netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n");
...@@ -727,17 +727,17 @@ static irqreturn_t xgbe_an_isr(int irq, void *data) ...@@ -727,17 +727,17 @@ static irqreturn_t xgbe_an_isr(int irq, void *data)
{ {
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
if (pdata->isr_as_tasklet) if (pdata->isr_as_bh_work)
tasklet_schedule(&pdata->tasklet_an); queue_work(system_bh_wq, &pdata->an_bh_work);
else else
xgbe_an_isr_task(&pdata->tasklet_an); xgbe_an_isr_bh_work(&pdata->an_bh_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata) static irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata)
{ {
xgbe_an_isr_task(&pdata->tasklet_an); xgbe_an_isr_bh_work(&pdata->an_bh_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1454,7 +1454,7 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata) ...@@ -1454,7 +1454,7 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
if (pdata->dev_irq != pdata->an_irq) { if (pdata->dev_irq != pdata->an_irq) {
devm_free_irq(pdata->dev, pdata->an_irq, pdata); devm_free_irq(pdata->dev, pdata->an_irq, pdata);
tasklet_kill(&pdata->tasklet_an); cancel_work_sync(&pdata->an_bh_work);
} }
pdata->phy_if.phy_impl.stop(pdata); pdata->phy_if.phy_impl.stop(pdata);
...@@ -1477,7 +1477,7 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata) ...@@ -1477,7 +1477,7 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
/* If we have a separate AN irq, enable it */ /* If we have a separate AN irq, enable it */
if (pdata->dev_irq != pdata->an_irq) { if (pdata->dev_irq != pdata->an_irq) {
tasklet_setup(&pdata->tasklet_an, xgbe_an_isr_task); INIT_WORK(&pdata->an_bh_work, xgbe_an_isr_bh_work);
ret = devm_request_irq(pdata->dev, pdata->an_irq, ret = devm_request_irq(pdata->dev, pdata->an_irq,
xgbe_an_isr, 0, pdata->an_name, xgbe_an_isr, 0, pdata->an_name,
......
...@@ -139,7 +139,7 @@ static int xgbe_config_multi_msi(struct xgbe_prv_data *pdata) ...@@ -139,7 +139,7 @@ static int xgbe_config_multi_msi(struct xgbe_prv_data *pdata)
return ret; return ret;
} }
pdata->isr_as_tasklet = 1; pdata->isr_as_bh_work = 1;
pdata->irq_count = ret; pdata->irq_count = ret;
pdata->dev_irq = pci_irq_vector(pdata->pcidev, 0); pdata->dev_irq = pci_irq_vector(pdata->pcidev, 0);
...@@ -176,7 +176,7 @@ static int xgbe_config_irqs(struct xgbe_prv_data *pdata) ...@@ -176,7 +176,7 @@ static int xgbe_config_irqs(struct xgbe_prv_data *pdata)
return ret; return ret;
} }
pdata->isr_as_tasklet = pdata->pcidev->msi_enabled ? 1 : 0; pdata->isr_as_bh_work = pdata->pcidev->msi_enabled ? 1 : 0;
pdata->irq_count = 1; pdata->irq_count = 1;
pdata->channel_irq_count = 1; pdata->channel_irq_count = 1;
......
...@@ -1298,11 +1298,11 @@ struct xgbe_prv_data { ...@@ -1298,11 +1298,11 @@ struct xgbe_prv_data {
unsigned int lpm_ctrl; /* CTRL1 for resume */ unsigned int lpm_ctrl; /* CTRL1 for resume */
unsigned int isr_as_tasklet; unsigned int isr_as_bh_work;
struct tasklet_struct tasklet_dev; struct work_struct dev_bh_work;
struct tasklet_struct tasklet_ecc; struct work_struct ecc_bh_work;
struct tasklet_struct tasklet_i2c; struct work_struct i2c_bh_work;
struct tasklet_struct tasklet_an; struct work_struct an_bh_work;
struct dentry *xgbe_debugfs; struct dentry *xgbe_debugfs;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/workqueue.h>
#if IS_ENABLED(CONFIG_VLAN_8021Q) #if IS_ENABLED(CONFIG_VLAN_8021Q)
#define BCM_VLAN 1 #define BCM_VLAN 1
#endif #endif
...@@ -3015,9 +3016,9 @@ static int cnic_service_bnx2(void *data, void *status_blk) ...@@ -3015,9 +3016,9 @@ static int cnic_service_bnx2(void *data, void *status_blk)
return cnic_service_bnx2_queues(dev); return cnic_service_bnx2_queues(dev);
} }
static void cnic_service_bnx2_msix(struct tasklet_struct *t) static void cnic_service_bnx2_msix(struct work_struct *work)
{ {
struct cnic_local *cp = from_tasklet(cp, t, cnic_irq_task); struct cnic_local *cp = from_work(cp, work, cnic_irq_bh_work);
struct cnic_dev *dev = cp->dev; struct cnic_dev *dev = cp->dev;
cp->last_status_idx = cnic_service_bnx2_queues(dev); cp->last_status_idx = cnic_service_bnx2_queues(dev);
...@@ -3036,7 +3037,7 @@ static void cnic_doirq(struct cnic_dev *dev) ...@@ -3036,7 +3037,7 @@ static void cnic_doirq(struct cnic_dev *dev)
prefetch(cp->status_blk.gen); prefetch(cp->status_blk.gen);
prefetch(&cp->kcq1.kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); prefetch(&cp->kcq1.kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
tasklet_schedule(&cp->cnic_irq_task); queue_work(system_bh_wq, &cp->cnic_irq_bh_work);
} }
} }
...@@ -3140,9 +3141,9 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info) ...@@ -3140,9 +3141,9 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
return last_status; return last_status;
} }
static void cnic_service_bnx2x_bh(struct tasklet_struct *t) static void cnic_service_bnx2x_bh_work(struct work_struct *work)
{ {
struct cnic_local *cp = from_tasklet(cp, t, cnic_irq_task); struct cnic_local *cp = from_work(cp, work, cnic_irq_bh_work);
struct cnic_dev *dev = cp->dev; struct cnic_dev *dev = cp->dev;
struct bnx2x *bp = netdev_priv(dev->netdev); struct bnx2x *bp = netdev_priv(dev->netdev);
u32 status_idx, new_status_idx; u32 status_idx, new_status_idx;
...@@ -4428,7 +4429,7 @@ static void cnic_free_irq(struct cnic_dev *dev) ...@@ -4428,7 +4429,7 @@ static void cnic_free_irq(struct cnic_dev *dev)
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
cp->disable_int_sync(dev); cp->disable_int_sync(dev);
tasklet_kill(&cp->cnic_irq_task); cancel_work_sync(&cp->cnic_irq_bh_work);
free_irq(ethdev->irq_arr[0].vector, dev); free_irq(ethdev->irq_arr[0].vector, dev);
} }
} }
...@@ -4441,7 +4442,7 @@ static int cnic_request_irq(struct cnic_dev *dev) ...@@ -4441,7 +4442,7 @@ static int cnic_request_irq(struct cnic_dev *dev)
err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, "cnic", dev); err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, "cnic", dev);
if (err) if (err)
tasklet_disable(&cp->cnic_irq_task); disable_work_sync(&cp->cnic_irq_bh_work);
return err; return err;
} }
...@@ -4464,7 +4465,7 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev) ...@@ -4464,7 +4465,7 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev)
CNIC_WR(dev, base + BNX2_HC_CMD_TICKS_OFF, (64 << 16) | 220); CNIC_WR(dev, base + BNX2_HC_CMD_TICKS_OFF, (64 << 16) | 220);
cp->last_status_idx = cp->status_blk.bnx2->status_idx; cp->last_status_idx = cp->status_blk.bnx2->status_idx;
tasklet_setup(&cp->cnic_irq_task, cnic_service_bnx2_msix); INIT_WORK(&cp->cnic_irq_bh_work, cnic_service_bnx2_msix);
err = cnic_request_irq(dev); err = cnic_request_irq(dev);
if (err) if (err)
return err; return err;
...@@ -4873,7 +4874,7 @@ static int cnic_init_bnx2x_irq(struct cnic_dev *dev) ...@@ -4873,7 +4874,7 @@ static int cnic_init_bnx2x_irq(struct cnic_dev *dev)
struct cnic_eth_dev *ethdev = cp->ethdev; struct cnic_eth_dev *ethdev = cp->ethdev;
int err = 0; int err = 0;
tasklet_setup(&cp->cnic_irq_task, cnic_service_bnx2x_bh); INIT_WORK(&cp->cnic_irq_bh_work, cnic_service_bnx2x_bh_work);
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
err = cnic_request_irq(dev); err = cnic_request_irq(dev);
......
...@@ -268,7 +268,7 @@ struct cnic_local { ...@@ -268,7 +268,7 @@ struct cnic_local {
u32 bnx2x_igu_sb_id; u32 bnx2x_igu_sb_id;
u32 int_num; u32 int_num;
u32 last_status_idx; u32 last_status_idx;
struct tasklet_struct cnic_irq_task; struct work_struct cnic_irq_bh_work;
struct kcqe *completed_kcq[MAX_COMPLETED_KCQE]; struct kcqe *completed_kcq[MAX_COMPLETED_KCQE];
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/workqueue.h>
#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP) #if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP)
#define MACB_EXT_DESC #define MACB_EXT_DESC
...@@ -1330,7 +1331,7 @@ struct macb { ...@@ -1330,7 +1331,7 @@ struct macb {
spinlock_t rx_fs_lock; spinlock_t rx_fs_lock;
unsigned int max_tuples; unsigned int max_tuples;
struct tasklet_struct hresp_err_tasklet; struct work_struct hresp_err_bh_work;
int rx_bd_rd_prefetch; int rx_bd_rd_prefetch;
int tx_bd_rd_prefetch; int tx_bd_rd_prefetch;
......
...@@ -1792,9 +1792,9 @@ static int macb_tx_poll(struct napi_struct *napi, int budget) ...@@ -1792,9 +1792,9 @@ static int macb_tx_poll(struct napi_struct *napi, int budget)
return work_done; return work_done;
} }
static void macb_hresp_error_task(struct tasklet_struct *t) static void macb_hresp_error_task(struct work_struct *work)
{ {
struct macb *bp = from_tasklet(bp, t, hresp_err_tasklet); struct macb *bp = from_work(bp, work, hresp_err_bh_work);
struct net_device *dev = bp->dev; struct net_device *dev = bp->dev;
struct macb_queue *queue; struct macb_queue *queue;
unsigned int q; unsigned int q;
...@@ -1994,7 +1994,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) ...@@ -1994,7 +1994,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
} }
if (status & MACB_BIT(HRESP)) { if (status & MACB_BIT(HRESP)) {
tasklet_schedule(&bp->hresp_err_tasklet); queue_work(system_bh_wq, &bp->hresp_err_bh_work);
netdev_err(dev, "DMA bus error: HRESP not OK\n"); netdev_err(dev, "DMA bus error: HRESP not OK\n");
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
...@@ -5172,7 +5172,7 @@ static int macb_probe(struct platform_device *pdev) ...@@ -5172,7 +5172,7 @@ static int macb_probe(struct platform_device *pdev)
goto err_out_unregister_mdio; goto err_out_unregister_mdio;
} }
tasklet_setup(&bp->hresp_err_tasklet, macb_hresp_error_task); INIT_WORK(&bp->hresp_err_bh_work, macb_hresp_error_task);
netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
...@@ -5216,7 +5216,7 @@ static void macb_remove(struct platform_device *pdev) ...@@ -5216,7 +5216,7 @@ static void macb_remove(struct platform_device *pdev)
mdiobus_free(bp->mii_bus); mdiobus_free(bp->mii_bus);
unregister_netdev(dev); unregister_netdev(dev);
tasklet_kill(&bp->hresp_err_tasklet); cancel_work_sync(&bp->hresp_err_bh_work);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev);
if (!pm_runtime_suspended(&pdev->dev)) { if (!pm_runtime_suspended(&pdev->dev)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment