Re: [PATCH v2 1/3] dmaengine: dw-edma: Implement device_synchronize() callback

Manivannan Sadhasivam <[email protected]> Wed, 22 Jul 2026 07:58:34 +0200
Newsgroups dev.linux.lists.mhi,org.kernel.vger.dmaengine,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <a7rswvi476dml2vuvqycnzsq7orc5jxzxl3n4wixclly4cvqrl@x26rz7ytdrr3>
On Tue, Jul 21, 2026 at 09:05:59PM -0400, Frank Li wrote:
> On Tue, Jul 14, 2026 at 02:08:32PM +0200, Manivannan Sadhasivam wrote:
> > device_synchronize() callback is required by the client drivers to ensure
> > all the DMA operations are completed so that they can free the memory
> > associated with the complete callbacks.
> >
> > So implement this callback by first making sure that all the in-flight DMA
> > operations are completed and then call vchan_synchronize() to drain the
> > DMA tasklet.
> >
> > Signed-off-by: Manivannan Sadhasivam <[email protected]>
> > ---
> 
> Similar implement already in linux-next, recent many fixes and update about
> dw edma already merged in dma tree.
> 

Ah, I didn't notice this patch. I've dropped this patch from my series.

This patch also suffers from the same RMW issue that Sashiko pointed out. So
I'll send a separate fix for that.

- Mani

> commit 99109a51efd28c9a661fbfb9469b023c517b31d1
> Author: Koichiro Den <[email protected]>
> Date:   Sat Jul 18 03:06:32 2026 +0900
> 
>     dmaengine: dw-edma: Terminate all descriptors without callbacks
> 
>     The DMA Engine client documentation says in the "Terminate APIs" section
>     of Documentation/driver-api/dmaengine/client.rst:
> 
>     "No callback functions will be called for any incomplete transfers."
> 
>     dw-edma instead calls vchan_cookie_complete() when a deferred STOP reaches
>     the interrupt handler. This schedules a callback for the active descriptor
>     and leaves other issued or submitted descriptors queued. A late callback
>     after dmaengine_terminate_sync() can dereference client state that has
>     already been freed, while leftover descriptors may later restart into
>     reused buffers or leak.
> 
>     Move all issued and submitted descriptors to the terminated list whenever
>     termination completes. For a pending STOP, do this from both the DONE and
>     ABORT paths. Complete their cookies in order without scheduling callbacks.
> 
>     A STOP can remain pending until the running transfer raises an
>     interrupt. Make device_synchronize() wait for such a pending STOP to
>     complete before releasing terminated descriptors. Reuse it from
>     free_chan_resources(), then release the remaining virt-dma resources.
>     Sleep instead of busy-polling while waiting, and warn if the existing
>     timeout expires.
> 
>     Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
>     Reviewed-by: Frank Li <[email protected]>
>     Signed-off-by: Koichiro Den <[email protected]>
>     Link: https://patch.msgid.link/[email protected]
>     Signed-off-by: Vinod Koul <[email protected]>
> 
> Frank
> 
> >  drivers/dma/dw-edma/dw-edma-core.c | 16 ++++++++++++++++
> >  1 file changed, 16 insertions(+)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index c2feb3adc79f..df0d1a946ed0 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -12,6 +12,7 @@
> >  #include <linux/dmaengine.h>
> >  #include <linux/err.h>
> >  #include <linux/interrupt.h>
> > +#include <linux/iopoll.h>
> >  #include <linux/irq.h>
> >  #include <linux/dma/edma.h>
> >  #include <linux/dma-mapping.h>
> > @@ -331,6 +332,20 @@ static int dw_edma_device_terminate_all(struct dma_chan *dchan)
> >  	return err;
> >  }
> >
> > +static void dw_edma_device_synchronize(struct dma_chan *dchan)
> > +{
> > +	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
> > +
> > +	/*
> > +	 * Make sure all the in-flight DMA operations are completed before
> > +	 * draining the tasklet using vchan_synchronize().
> > +	 */
> > +	read_poll_timeout(READ_ONCE, chan->status, chan->status != EDMA_ST_BUSY,
> > +			  10, 0, false, chan->status);
> > +
> > +	vchan_synchronize(&chan->vc);
> > +}
> > +
> >  static void dw_edma_device_issue_pending(struct dma_chan *dchan)
> >  {
> >  	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
> > @@ -968,6 +983,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
> >  	dma->device_pause = dw_edma_device_pause;
> >  	dma->device_resume = dw_edma_device_resume;
> >  	dma->device_terminate_all = dw_edma_device_terminate_all;
> > +	dma->device_synchronize = dw_edma_device_synchronize;
> >  	dma->device_issue_pending = dw_edma_device_issue_pending;
> >  	dma->device_tx_status = dw_edma_device_tx_status;
> >  	dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
> >
> > --
> > 2.43.0
> >

-- 
மணிவண்ணன் சதாசிவம்