[PATCH v4 5/7] dmaengine: dw: drain the tasklet before releasing channel resources
From: James Hilliard
Date: Thu Oct 29 2026 - 18:31:14 EST
The controller tasklet invokes callbacks after dropping the channel lock.
Releasing a channel can therefore clear its configuration and disable the
controller while that tasklet run is still using them.
Disable the tasklet before clearing channel resources and re-enable it
after updating the controller's in-use mask. This waits for an executing
run while preserving pending schedules for the other channels. Have a
pending run return before accessing registers when the last channel has
already been released.
Fixes: 3bfb1d20b547 ("dmaengine: Driver for the Synopsys DesignWare DMA controller")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/dma/dw/core.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 1d6419e1cd3c..3bda85adbeee 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -398,6 +398,10 @@ static void dw_dma_tasklet(struct tasklet_struct *t)
u32 status_err;
unsigned int i;
+ /* Channel release may have drained a polled completion before this run. */
+ if (!dw->in_use)
+ return;
+
status_xfer = dma_readl(dw, RAW.XFER);
status_err = dma_readl(dw, RAW.ERROR);
@@ -1067,6 +1071,8 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
struct dw_dma *dw = to_dw_dma(chan->device);
unsigned long flags;
+ tasklet_disable(&dw->tasklet);
+
dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__,
dwc->descs_allocated);
@@ -1092,6 +1098,8 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
if (!dw->in_use)
do_dw_dma_off(dw);
+ tasklet_enable(&dw->tasklet);
+
dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
}
--
2.53.0