[PATCH v2 18/64] dmaengine: xgene-dma: wire descriptor cleanup to dma_chan BH

From: Allen Pais

Date: Mon Jul 27 2026 - 16:38:08 EST


Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.

Signed-off-by: Allen Pais <allen.lkml@xxxxxxxxx>
---
drivers/dma/xgene-dma.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c
index fa1173e49900..8d0428c2944e 100644
--- a/drivers/dma/xgene-dma.c
+++ b/drivers/dma/xgene-dma.c
@@ -260,7 +260,6 @@ struct xgene_dma_desc_sw {
* These descriptors have already had their cleanup actions run. They
* are waiting for the ACK bit to be set by the async tx API.
* @desc_pool: descriptor pool for DMA operations
- * @tasklet: bottom half where all completed descriptors cleans
* @tx_ring: transmit ring descriptor that we use to prepare actual
* descriptors for further executions
* @rx_ring: receive ring descriptor that we use to get completed DMA
@@ -280,7 +279,6 @@ struct xgene_dma_chan {
struct list_head ld_running;
struct list_head ld_completed;
struct dma_pool *desc_pool;
- struct tasklet_struct tasklet;
struct xgene_dma_ring tx_ring;
struct xgene_dma_ring rx_ring;
};
@@ -975,9 +973,10 @@ static enum dma_status xgene_dma_tx_status(struct dma_chan *dchan,
return dma_cookie_status(dchan, cookie, txstate);
}

-static void xgene_dma_tasklet_cb(struct tasklet_struct *t)
+static void xgene_dma_tasklet_cb(struct dma_chan *c)
{
- struct xgene_dma_chan *chan = from_tasklet(chan, t, tasklet);
+ struct xgene_dma_chan *chan = container_of(c, struct xgene_dma_chan,
+ dma_chan);

/* Run all cleanup for descriptors which have been completed */
xgene_dma_cleanup_descriptors(chan);
@@ -999,11 +998,11 @@ static irqreturn_t xgene_dma_chan_ring_isr(int irq, void *id)
disable_irq_nosync(chan->rx_irq);

/*
- * Schedule the tasklet to handle all cleanup of the current
+ * Schedule the bottom half to handle all cleanup of the current
* transaction. It will start a new transaction if there is
* one pending.
*/
- tasklet_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->dma_chan);

return IRQ_HANDLED;
}
@@ -1539,7 +1538,7 @@ static int xgene_dma_async_register(struct xgene_dma *pdma, int id)
INIT_LIST_HEAD(&chan->ld_pending);
INIT_LIST_HEAD(&chan->ld_running);
INIT_LIST_HEAD(&chan->ld_completed);
- tasklet_setup(&chan->tasklet, xgene_dma_tasklet_cb);
+ dma_chan_init_bh(&chan->dma_chan, xgene_dma_tasklet_cb);

chan->pending = 0;
chan->desc_pool = NULL;
@@ -1556,7 +1555,7 @@ static int xgene_dma_async_register(struct xgene_dma *pdma, int id)
ret = dma_async_device_register(dma_dev);
if (ret) {
chan_err(chan, "Failed to register async device %d", ret);
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->dma_chan);

return ret;
}
@@ -1579,7 +1578,7 @@ static int xgene_dma_init_async(struct xgene_dma *pdma)
if (ret) {
for (j = 0; j < i; j++) {
dma_async_device_unregister(&pdma->dma_dev[j]);
- tasklet_kill(&pdma->chan[j].tasklet);
+ dma_chan_kill_bh(&pdma->chan[j].dma_chan);
}

return ret;
@@ -1790,7 +1789,7 @@ static void xgene_dma_remove(struct platform_device *pdev)

for (i = 0; i < XGENE_DMA_MAX_CHANNEL; i++) {
chan = &pdma->chan[i];
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->dma_chan);
xgene_dma_delete_chan_rings(chan);
}

--
2.43.0