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 > > -- மணிவண்ணன் சதாசிவம்