[PATCH] dmaengine: dw: synchronize completion callbacks

From: James Hilliard

Date: Wed Oct 21 2026 - 17:14:22 EST


The controller tasklet can remove a descriptor from active_list and
invoke its callback outside the channel lock. Terminating the channel
does not wait for that callback, and there is no device_synchronize
hook. A client can therefore reuse callback state or release its buffers
after dmaengine_synchronize() while an old callback still uses them.

Drain the controller tasklet from device_synchronize, outside the
channel lock. This also waits for callbacks on the other channels
because the tasklet is shared, without stopping their hardware
transfers. Clients must continue to exclude new submissions on the
channel being synchronized.

Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/dma/dw/core.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index dd75f97a33b3..eb3f5ce471a2 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -965,6 +965,14 @@ static int dwc_terminate_all(struct dma_chan *chan)
return 0;
}

+static void dwc_synchronize(struct dma_chan *chan)
+{
+ struct dw_dma *dw = to_dw_dma(chan->device);
+
+ /* Callbacks run outside the channel lock in the controller tasklet. */
+ tasklet_kill(&dw->tasklet);
+}
+
static struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c)
{
struct dw_desc *desc;
@@ -1321,6 +1329,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
dw->dma.device_pause = dwc_pause;
dw->dma.device_resume = dwc_resume;
dw->dma.device_terminate_all = dwc_terminate_all;
+ dw->dma.device_synchronize = dwc_synchronize;

dw->dma.device_tx_status = dwc_tx_status;
dw->dma.device_issue_pending = dwc_issue_pending;

---
base-commit: 93f51579e7df248780214094418f205253383cc5
change-id: 20261021-submit-dw-dma-synchronize-v1-e550f47fd1da

Best regards,
--
James Hilliard <james.hilliard1@xxxxxxxxx>