From d64e9a2c750930272492952c16f3f2c95311a6c9 Mon Sep 17 00:00:00 2001 From: Stephen Barber Date: Thu, 18 Aug 2016 17:59:59 -0700 Subject: dmaengine: pl330: fix residual for non-running BUSY descriptors Only one descriptor in the work list should be running at any given time, but it's possible to have an enqueued BUSY descriptor that has not yet transferred any data, or for a BUSY descriptor to linger briefly before transitioning to DONE. These cases should be handled to keep residual calculations consistent even with the non-running BUSY descriptors in the work list. Signed-off-by: Stephen Barber Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 4fc3ffbd5ca0..31e9c49e5604 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2274,7 +2274,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, { enum dma_status ret; unsigned long flags; - struct dma_pl330_desc *desc, *running = NULL; + struct dma_pl330_desc *desc, *running = NULL, *last_enq = NULL; struct dma_pl330_chan *pch = to_pchan(chan); unsigned int transferred, residual = 0; @@ -2291,6 +2291,8 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, if (pch->thread->req_running != -1) running = pch->thread->req[pch->thread->req_running].desc; + last_enq = pch->thread->req[pch->thread->lstenq].desc; + /* Check in pending list */ list_for_each_entry(desc, &pch->work_list, node) { if (desc->status == DONE) @@ -2298,6 +2300,15 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, else if (running && desc == running) transferred = pl330_get_current_xferred_count(pch, desc); + else if (desc->status == BUSY) + /* + * Busy but not running means either just enqueued, + * or finished and not yet marked done + */ + if (desc == last_enq) + transferred = 0; + else + transferred = desc->bytes_requested; else transferred = 0; residual += desc->bytes_requested - transferred; -- cgit v1.2.3 From a40235a2278a315261ee007fc433ec1cfb31666f Mon Sep 17 00:00:00 2001 From: Hsin-Yu Chao Date: Tue, 23 Aug 2016 17:16:55 +0800 Subject: 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 Reviewed-by: Guenter Roeck Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/dma/pl330.c') 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, goto out; spin_lock_irqsave(&pch->lock, flags); + spin_lock(&pch->thread->dmac->lock); if (pch->thread->req_running != -1) running = pch->thread->req[pch->thread->req_running].desc; @@ -2329,6 +2330,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, if (desc->last) residual = 0; } + spin_unlock(&pch->thread->dmac->lock); spin_unlock_irqrestore(&pch->lock, flags); out: -- cgit v1.2.3