]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dmaengine: sun6i-dma: Fix reclaim descriptors while terminating DMA
authorHongling Zeng <zenghongling@kylinos.cn>
Wed, 1 Jul 2026 04:57:33 +0000 (12:57 +0800)
committerVinod Koul <vkoul@kernel.org>
Wed, 1 Jul 2026 08:17:09 +0000 (13:47 +0530)
When terminating DMA transfers, active descriptors are not properly
reclaimed. Only cyclic descriptors were handled, leaving non-cyclic
descriptors and their LLI chains to be permanently leaked.

Fix by using vchan_terminate_vdesc() which handles both cyclic and
non-cyclic descriptors by adding them to desc_terminated queue for
proper cleanup.

Add pchan->desc != pchan->done check to prevent double-adding completed
descriptors, which would corrupt the list.

Fixes: 555859308723 ("dmaengine: sun6i: Add driver for the Allwinner A31 DMA controller")
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Suggested-by: Frank Li <Frank.li@oss.nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260701045733.33654-1-zenghongling@kylinos.cn
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/sun6i-dma.c

index a9a254dbf8cb94fd04a5edd98e097c007a1688a5..f47a326dd7ffa686557d363a997011bfc35ca5fa 100644 (file)
@@ -945,16 +945,13 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
 
        spin_lock_irqsave(&vchan->vc.lock, flags);
 
-       if (vchan->cyclic) {
-               vchan->cyclic = false;
-               if (pchan && pchan->desc) {
-                       struct virt_dma_desc *vd = &pchan->desc->vd;
-                       struct virt_dma_chan *vc = &vchan->vc;
+       if (pchan && pchan->desc && pchan->desc != pchan->done) {
+               struct virt_dma_desc *vd = &pchan->desc->vd;
 
-                       list_add_tail(&vd->node, &vc->desc_completed);
-               }
+               vchan_terminate_vdesc(vd);
        }
 
+       vchan->cyclic = false;
        vchan_get_all_descriptors(&vchan->vc, &head);
 
        if (pchan) {