Commit 5c9e6c2b authored by Marek Szyprowski's avatar Marek Szyprowski Committed by Vinod Koul
Browse files

dmaengine: pl330: Fix runtime PM support for terminated transfers



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>
parent f53243b5
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -448,6 +448,9 @@ struct dma_pl330_chan {

	/* for cyclic capability */
	bool cyclic;

	/* for runtime pm tracking */
	bool active;
};

struct pl330_dmac {
@@ -2033,6 +2036,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);
@@ -2052,6 +2056,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);
@@ -2166,6 +2171,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);
@@ -2176,6 +2182,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) {
@@ -2193,6 +2201,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;
@@ -2357,6 +2367,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);