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

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: default avatarJakub Kicinski <kuba@kernel.org>
parents 9bb3ec18 c5092ba3
Loading
Loading
Loading
Loading
+13 −13
Original line number Diff line number Diff line
@@ -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;
	int cur_size;

@@ -1595,7 +1595,7 @@ static void ace_tasklet(struct tasklet_struct *t)
#endif
		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)
 *
 * Loading rings is safe without holding the spin lock since this is
 * 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)
{
@@ -2160,7 +2160,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
	 */
	if (netif_running(dev)) {
		int cur_size;
		int run_tasklet = 0;
		int run_bh_work = 0;

		cur_size = atomic_read(&ap->cur_rx_bufs);
		if (cur_size < RX_LOW_STD_THRES) {
@@ -2172,7 +2172,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
				ace_load_std_rx_ring(dev,
						     RX_RING_SIZE - cur_size);
			} else
				run_tasklet = 1;
				run_bh_work = 1;
		}

		if (!ACE_IS_TIGON_I(ap)) {
@@ -2188,7 +2188,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
					ace_load_mini_rx_ring(dev,
							      RX_MINI_SIZE - cur_size);
				} else
					run_tasklet = 1;
					run_bh_work = 1;
			}
		}

@@ -2205,12 +2205,12 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
					ace_load_jumbo_rx_ring(dev,
							       RX_JUMBO_SIZE - cur_size);
				} else
					run_tasklet = 1;
					run_bh_work = 1;
			}
		}
		if (run_tasklet && !ap->tasklet_pending) {
			ap->tasklet_pending = 1;
			tasklet_schedule(&ap->ace_tasklet);
		if (run_bh_work && !ap->bh_work_pending) {
			ap->bh_work_pending = 1;
			queue_work(system_bh_wq, &ap->ace_bh_work);
		}
	}

@@ -2267,7 +2267,7 @@ static int ace_open(struct net_device *dev)
	/*
	 * 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;
}

@@ -2301,7 +2301,7 @@ static int ace_close(struct net_device *dev)
	cmd.idx = 0;
	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
+4 −4
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#ifndef _ACENIC_H_
#define _ACENIC_H_
#include <linux/interrupt.h>

#include <linux/workqueue.h>

/*
 * Generate TX index update each time, when TX ring is closed.
@@ -667,8 +667,8 @@ struct ace_private
	struct rx_desc		*rx_mini_ring;
	struct rx_desc		*rx_return_ring;

	int			tasklet_pending, jumbo;
	struct tasklet_struct	ace_tasklet;
	int			bh_work_pending, jumbo;
	struct work_struct	ace_bh_work;

	struct event		*evt_ring;

@@ -776,7 +776,7 @@ static int ace_open(struct net_device *dev);
static netdev_tx_t ace_start_xmit(struct sk_buff *skb,
				  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_set_multicast_list(struct net_device *dev);
static int ace_change_mtu(struct net_device *dev, int new_mtu);
+15 −15
Original line number Diff line number Diff line
@@ -403,9 +403,9 @@ static bool xgbe_ecc_ded(struct xgbe_prv_data *pdata, unsigned long *period,
	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;
	bool stop = false;

@@ -465,17 +465,17 @@ static irqreturn_t xgbe_ecc_isr(int irq, void *data)
{
	struct xgbe_prv_data *pdata = data;

	if (pdata->isr_as_tasklet)
		tasklet_schedule(&pdata->tasklet_ecc);
	if (pdata->isr_as_bh_work)
		queue_work(system_bh_wq, &pdata->ecc_bh_work);
	else
		xgbe_ecc_isr_task(&pdata->tasklet_ecc);
		xgbe_ecc_isr_bh_work(&pdata->ecc_bh_work);

	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_channel *channel;
	unsigned int dma_isr, dma_ch_isr;
@@ -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 (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 (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq))
@@ -604,10 +604,10 @@ static irqreturn_t xgbe_isr(int irq, void *data)
{
	struct xgbe_prv_data *pdata = data;

	if (pdata->isr_as_tasklet)
		tasklet_schedule(&pdata->tasklet_dev);
	if (pdata->isr_as_bh_work)
		queue_work(system_bh_wq, &pdata->dev_bh_work);
	else
		xgbe_isr_task(&pdata->tasklet_dev);
		xgbe_isr_bh_work(&pdata->dev_bh_work);

	return IRQ_HANDLED;
}
@@ -1007,8 +1007,8 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata)
	unsigned int i;
	int ret;

	tasklet_setup(&pdata->tasklet_dev, xgbe_isr_task);
	tasklet_setup(&pdata->tasklet_ecc, xgbe_ecc_isr_task);
	INIT_WORK(&pdata->dev_bh_work, xgbe_isr_bh_work);
	INIT_WORK(&pdata->ecc_bh_work, xgbe_ecc_isr_bh_work);

	ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
			       netdev_name(netdev), pdata);
@@ -1078,8 +1078,8 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata)

	devm_free_irq(pdata->dev, pdata->dev_irq, pdata);

	tasklet_kill(&pdata->tasklet_dev);
	tasklet_kill(&pdata->tasklet_ecc);
	cancel_work_sync(&pdata->dev_bh_work);
	cancel_work_sync(&pdata->ecc_bh_work);

	if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq))
		devm_free_irq(pdata->dev, pdata->ecc_irq, pdata);
+8 −8
Original line number Diff line number Diff line
@@ -274,9 +274,9 @@ static void xgbe_i2c_clear_isr_interrupts(struct xgbe_prv_data *pdata,
		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;
	unsigned int isr;

@@ -321,10 +321,10 @@ static irqreturn_t xgbe_i2c_isr(int irq, void *data)
{
	struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;

	if (pdata->isr_as_tasklet)
		tasklet_schedule(&pdata->tasklet_i2c);
	if (pdata->isr_as_bh_work)
		queue_work(system_bh_wq, &pdata->i2c_bh_work);
	else
		xgbe_i2c_isr_task(&pdata->tasklet_i2c);
		xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work);

	return IRQ_HANDLED;
}
@@ -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)
{
	xgbe_i2c_isr_task(&pdata->tasklet_i2c);
	xgbe_i2c_isr_bh_work(&pdata->i2c_bh_work);

	return IRQ_HANDLED;
}
@@ -449,7 +449,7 @@ static void xgbe_i2c_stop(struct xgbe_prv_data *pdata)

	if (pdata->dev_irq != pdata->i2c_irq) {
		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)

	/* If we have a separate I2C irq, enable it */
	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,
				       xgbe_i2c_isr, 0, pdata->i2c_name,
+8 −8
Original line number Diff line number Diff line
@@ -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");

@@ -727,17 +727,17 @@ static irqreturn_t xgbe_an_isr(int irq, void *data)
{
	struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;

	if (pdata->isr_as_tasklet)
		tasklet_schedule(&pdata->tasklet_an);
	if (pdata->isr_as_bh_work)
		queue_work(system_bh_wq, &pdata->an_bh_work);
	else
		xgbe_an_isr_task(&pdata->tasklet_an);
		xgbe_an_isr_bh_work(&pdata->an_bh_work);

	return IRQ_HANDLED;
}

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;
}
@@ -1454,7 +1454,7 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)

	if (pdata->dev_irq != pdata->an_irq) {
		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);
@@ -1477,7 +1477,7 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)

	/* If we have a separate AN irq, enable it */
	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,
				       xgbe_an_isr, 0, pdata->an_name,
Loading