Commit d21814a8 authored by Marek Szyprowski's avatar Marek Szyprowski Committed by Greg Kroah-Hartman

dmaengine: pl330: Fix runtime PM support for terminated transfers

commit 5c9e6c2b 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: ae43b328 ("ARM: 8202/1: dmaengine: pl330: Add runtime Power Management support v12")
Signed-off-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: default avatarKrzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 172270c7
...@@ -448,6 +448,9 @@ struct dma_pl330_chan { ...@@ -448,6 +448,9 @@ struct dma_pl330_chan {
/* for cyclic capability */ /* for cyclic capability */
bool cyclic; bool cyclic;
/* for runtime pm tracking */
bool active;
}; };
struct pl330_dmac { struct pl330_dmac {
...@@ -2031,6 +2034,7 @@ static void pl330_tasklet(unsigned long data) ...@@ -2031,6 +2034,7 @@ static void pl330_tasklet(unsigned long data)
_stop(pch->thread); _stop(pch->thread);
spin_unlock(&pch->thread->dmac->lock); spin_unlock(&pch->thread->dmac->lock);
power_down = true; power_down = true;
pch->active = false;
} else { } else {
/* Make sure the PL330 Channel thread is active */ /* Make sure the PL330 Channel thread is active */
spin_lock(&pch->thread->dmac->lock); spin_lock(&pch->thread->dmac->lock);
...@@ -2050,6 +2054,7 @@ static void pl330_tasklet(unsigned long data) ...@@ -2050,6 +2054,7 @@ static void pl330_tasklet(unsigned long data)
desc->status = PREP; desc->status = PREP;
list_move_tail(&desc->node, &pch->work_list); list_move_tail(&desc->node, &pch->work_list);
if (power_down) { if (power_down) {
pch->active = true;
spin_lock(&pch->thread->dmac->lock); spin_lock(&pch->thread->dmac->lock);
_start(pch->thread); _start(pch->thread);
spin_unlock(&pch->thread->dmac->lock); spin_unlock(&pch->thread->dmac->lock);
...@@ -2164,6 +2169,7 @@ static int pl330_terminate_all(struct dma_chan *chan) ...@@ -2164,6 +2169,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
unsigned long flags; unsigned long flags;
struct pl330_dmac *pl330 = pch->dmac; struct pl330_dmac *pl330 = pch->dmac;
LIST_HEAD(list); LIST_HEAD(list);
bool power_down = false;
pm_runtime_get_sync(pl330->ddma.dev); pm_runtime_get_sync(pl330->ddma.dev);
spin_lock_irqsave(&pch->lock, flags); spin_lock_irqsave(&pch->lock, flags);
...@@ -2174,6 +2180,8 @@ static int pl330_terminate_all(struct dma_chan *chan) ...@@ -2174,6 +2180,8 @@ static int pl330_terminate_all(struct dma_chan *chan)
pch->thread->req[0].desc = NULL; pch->thread->req[0].desc = NULL;
pch->thread->req[1].desc = NULL; pch->thread->req[1].desc = NULL;
pch->thread->req_running = -1; pch->thread->req_running = -1;
power_down = pch->active;
pch->active = false;
/* Mark all desc done */ /* Mark all desc done */
list_for_each_entry(desc, &pch->submitted_list, node) { list_for_each_entry(desc, &pch->submitted_list, node) {
...@@ -2191,6 +2199,8 @@ static int pl330_terminate_all(struct dma_chan *chan) ...@@ -2191,6 +2199,8 @@ static int pl330_terminate_all(struct dma_chan *chan)
list_splice_tail_init(&pch->completed_list, &pl330->desc_pool); list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
spin_unlock_irqrestore(&pch->lock, flags); spin_unlock_irqrestore(&pch->lock, flags);
pm_runtime_mark_last_busy(pl330->ddma.dev); 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); pm_runtime_put_autosuspend(pl330->ddma.dev);
return 0; return 0;
...@@ -2350,6 +2360,7 @@ static void pl330_issue_pending(struct dma_chan *chan) ...@@ -2350,6 +2360,7 @@ static void pl330_issue_pending(struct dma_chan *chan)
* updated on work_list emptiness status. * updated on work_list emptiness status.
*/ */
WARN_ON(list_empty(&pch->submitted_list)); WARN_ON(list_empty(&pch->submitted_list));
pch->active = true;
pm_runtime_get_sync(pch->dmac->ddma.dev); pm_runtime_get_sync(pch->dmac->ddma.dev);
} }
list_splice_tail_init(&pch->submitted_list, &pch->work_list); list_splice_tail_init(&pch->submitted_list, &pch->work_list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment