aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHsin-Yu Chao <hychao@chromium.org>2016-08-23 05:16:55 -0400
committerVinod Koul <vinod.koul@intel.com>2016-09-09 07:52:42 -0400
commita40235a2278a315261ee007fc433ec1cfb31666f (patch)
treec9d66a25fab25615b58e869f32d8b4a3e4e78503
parentd64e9a2c750930272492952c16f3f2c95311a6c9 (diff)
dmaengine: pl330: Acquire dmac's spinlock in pl330_tx_status
There is a racing when accessing dmac thread in pl330_tx_status that the pl330_update is handling active request at the same time and changing the status of descriptors. This could cause an invalid transferred count from BUSY descriptor added up to the residual number. Fix the bug by using the dmac's spinlock in pl330_tx_status to protect thread resources from changing. Note that the nested order of holding dmac's and dma_chan's spinlock is consistent with the rest of the driver: dma_chan first and then dmac, so it is safe from deadlock scenario. Signed-off-by: Hsin-Yu Chao <hychao@chromium.org> Reviewed-by: Guenter Roeck <groeck@chromium.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/pl330.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 31e9c49e5604..c4d61528072f 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2287,6 +2287,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
2287 goto out; 2287 goto out;
2288 2288
2289 spin_lock_irqsave(&pch->lock, flags); 2289 spin_lock_irqsave(&pch->lock, flags);
2290 spin_lock(&pch->thread->dmac->lock);
2290 2291
2291 if (pch->thread->req_running != -1) 2292 if (pch->thread->req_running != -1)
2292 running = pch->thread->req[pch->thread->req_running].desc; 2293 running = pch->thread->req[pch->thread->req_running].desc;
@@ -2329,6 +2330,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
2329 if (desc->last) 2330 if (desc->last)
2330 residual = 0; 2331 residual = 0;
2331 } 2332 }
2333 spin_unlock(&pch->thread->dmac->lock);
2332 spin_unlock_irqrestore(&pch->lock, flags); 2334 spin_unlock_irqrestore(&pch->lock, flags);
2333 2335
2334out: 2336out: