dmaengine: sf-pdma: Fix an error that calls callback twice
authorBrad Kim <brad.kim@sifive.com>
Thu, 3 Sep 2020 11:17:26 +0000 (20:17 +0900)
committerVinod Koul <vkoul@kernel.org>
Fri, 11 Sep 2020 12:09:53 +0000 (17:39 +0530)
Because a callback is called twice when DMA transfer complete
the second callback may be possible to access a freed memory
if the first callback routines perform the dma_release_channel function.
So this patch serialized the callback functions

Signed-off-by: Brad Kim <brad.kim@semifive.com>
Tested-and-reviewed-by: Green Wan <green.wan@sifive.com>
Signed-off-by: Brad Kim <brad.kim@sifive.com>
Link: https://lore.kernel.org/r/20200903111726.3413-1-brad.kim@sifive.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/sf-pdma/sf-pdma.c

index 6e530dc..7549940 100644 (file)
@@ -295,7 +295,10 @@ static void sf_pdma_donebh_tasklet(unsigned long arg)
        }
        spin_unlock_irqrestore(&chan->lock, flags);
 
-       dmaengine_desc_get_callback_invoke(desc->async_tx, NULL);
+       spin_lock_irqsave(&chan->vchan.lock, flags);
+       list_del(&chan->desc->vdesc.node);
+       vchan_cookie_complete(&chan->desc->vdesc);
+       spin_unlock_irqrestore(&chan->vchan.lock, flags);
 }
 
 static void sf_pdma_errbh_tasklet(unsigned long arg)
@@ -332,8 +335,7 @@ static irqreturn_t sf_pdma_done_isr(int irq, void *dev_id)
        residue = readq(regs->residue);
 
        if (!residue) {
-               list_del(&chan->desc->vdesc.node);
-               vchan_cookie_complete(&chan->desc->vdesc);
+               tasklet_hi_schedule(&chan->done_tasklet);
        } else {
                /* submit next trascatioin if possible */
                struct sf_pdma_desc *desc = chan->desc;
@@ -347,8 +349,6 @@ static irqreturn_t sf_pdma_done_isr(int irq, void *dev_id)
 
        spin_unlock_irqrestore(&chan->vchan.lock, flags);
 
-       tasklet_hi_schedule(&chan->done_tasklet);
-
        return IRQ_HANDLED;
 }