diff options
author | Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> | 2017-05-16 01:09:17 +0200 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2017-05-19 11:25:23 +0200 |
commit | a1ed64efc5f68fc830fea08e96363d4459bb07a6 (patch) | |
tree | fd83bb08a3dbb44ec8043c55c65c4b15a2d22ae5 /drivers/dma | |
parent | dmaengine: rcar-dmac: implement device_synchronize() (diff) | |
download | linux-a1ed64efc5f68fc830fea08e96363d4459bb07a6.tar.xz linux-a1ed64efc5f68fc830fea08e96363d4459bb07a6.zip |
dmaengine: rcar-dmac: wait for ISR to finish before freeing resources
This fixes a race condition where the channel resources could be freed
before the ISR had finished running resulting in a NULL pointer
reference from the ISR.
[ 167.148934] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 167.157051] pgd = ffff80003c641000
[ 167.160449] [00000000] *pgd=000000007c507003, *pud=000000007c4ff003, *pmd=0000000000000000
[ 167.168719] Internal error: Oops: 96000046 [#1] PREEMPT SMP
[ 167.174289] Modules linked in:
[ 167.177348] CPU: 3 PID: 10547 Comm: dma_ioctl Not tainted 4.11.0-rc1-00001-g8d92afddc2f6633a #73
[ 167.186131] Hardware name: Renesas Salvator-X board based on r8a7795 (DT)
[ 167.192917] task: ffff80003a411a00 task.stack: ffff80003bcd4000
[ 167.198850] PC is at rcar_dmac_chan_prep_sg+0xe0/0x400
[ 167.203985] LR is at rcar_dmac_chan_prep_sg+0x48/0x400
Based of previous work by:
Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/sh/rcar-dmac.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index fb07cd5fe77b..d2cb4a0916e6 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1010,7 +1010,11 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan) rcar_dmac_chan_halt(rchan); spin_unlock_irq(&rchan->lock); - /* Now no new interrupts will occur */ + /* + * Now no new interrupts will occur, but one might already be + * running. Wait for it to finish before freeing resources. + */ + synchronize_irq(rchan->irq); if (rchan->mid_rid >= 0) { /* The caller is holding dma_list_mutex */ |