diff options
author | Brad Kim <brad.kim@sifive.com> | 2020-09-03 20:17:26 +0900 |
---|---|---|
committer | Vinod Koul <vkoul@kernel.org> | 2020-09-11 17:39:53 +0530 |
commit | 8f6b6d0606023c8403ac04ba42177ecbb55769f6 (patch) | |
tree | 6d3cee9438e16209ba8a152ab8fbbac6767c7382 /drivers/dma | |
parent | 78e7a522693b5f5b1c8b8a7b8bd066e4dddb3d3c (diff) |
dmaengine: sf-pdma: Fix an error that calls callback twice
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>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/sf-pdma/sf-pdma.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c index 6e530dca6d9e..754994087e5f 100644 --- a/drivers/dma/sf-pdma/sf-pdma.c +++ b/drivers/dma/sf-pdma/sf-pdma.c @@ -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; } |