dmaengine: pl330: Fix runtime PM support for terminated transfers
commit 5c9e6c2b2ba3ec3a442e2fb5b4286498f8b4dcb7 upstream. PL330 DMA engine driver is leaking a runtime reference after any terminated DMA transactions. This patch fixes this issue by tracking runtime PM state of the device and making additional call to pm_runtime_put() in terminate_all callback if needed. Fixes: ae43b3289186 ("ARM: 8202/1: dmaengine: pl330: Add runtime Power Management support v12") Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
238623ce48
commit
a5291c1a9e
@ -445,6 +445,9 @@ struct dma_pl330_chan {
|
||||
|
||||
/* for cyclic capability */
|
||||
bool cyclic;
|
||||
|
||||
/* for runtime pm tracking */
|
||||
bool active;
|
||||
};
|
||||
|
||||
struct pl330_dmac {
|
||||
@ -1994,6 +1997,7 @@ static void pl330_tasklet(unsigned long data)
|
||||
_stop(pch->thread);
|
||||
spin_unlock(&pch->thread->dmac->lock);
|
||||
power_down = true;
|
||||
pch->active = false;
|
||||
} else {
|
||||
/* Make sure the PL330 Channel thread is active */
|
||||
spin_lock(&pch->thread->dmac->lock);
|
||||
@ -2015,6 +2019,7 @@ static void pl330_tasklet(unsigned long data)
|
||||
desc->status = PREP;
|
||||
list_move_tail(&desc->node, &pch->work_list);
|
||||
if (power_down) {
|
||||
pch->active = true;
|
||||
spin_lock(&pch->thread->dmac->lock);
|
||||
_start(pch->thread);
|
||||
spin_unlock(&pch->thread->dmac->lock);
|
||||
@ -2129,6 +2134,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
|
||||
unsigned long flags;
|
||||
struct pl330_dmac *pl330 = pch->dmac;
|
||||
LIST_HEAD(list);
|
||||
bool power_down = false;
|
||||
|
||||
pm_runtime_get_sync(pl330->ddma.dev);
|
||||
spin_lock_irqsave(&pch->lock, flags);
|
||||
@ -2139,6 +2145,8 @@ static int pl330_terminate_all(struct dma_chan *chan)
|
||||
pch->thread->req[0].desc = NULL;
|
||||
pch->thread->req[1].desc = NULL;
|
||||
pch->thread->req_running = -1;
|
||||
power_down = pch->active;
|
||||
pch->active = false;
|
||||
|
||||
/* Mark all desc done */
|
||||
list_for_each_entry(desc, &pch->submitted_list, node) {
|
||||
@ -2156,6 +2164,8 @@ static int pl330_terminate_all(struct dma_chan *chan)
|
||||
list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
|
||||
spin_unlock_irqrestore(&pch->lock, flags);
|
||||
pm_runtime_mark_last_busy(pl330->ddma.dev);
|
||||
if (power_down)
|
||||
pm_runtime_put_autosuspend(pl330->ddma.dev);
|
||||
pm_runtime_put_autosuspend(pl330->ddma.dev);
|
||||
|
||||
return 0;
|
||||
@ -2302,6 +2312,7 @@ static void pl330_issue_pending(struct dma_chan *chan)
|
||||
* updated on work_list emptiness status.
|
||||
*/
|
||||
WARN_ON(list_empty(&pch->submitted_list));
|
||||
pch->active = true;
|
||||
pm_runtime_get_sync(pch->dmac->ddma.dev);
|
||||
}
|
||||
list_splice_tail_init(&pch->submitted_list, &pch->work_list);
|
||||
|
Loading…
x
Reference in New Issue
Block a user