Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59861547 authored by Bin Liu's avatar Bin Liu Committed by Vinod Koul
Browse files

dmaengine: cppi41: delete channel from pending list when stop channel



The driver defines three states for a cppi channel.
- idle: .chan_busy == 0 && not in .pending list
- pending: .chan_busy == 0 && in .pending list
- busy: .chan_busy == 1 && not in .pending list

There are cases in which the cppi channel could be in the pending state
when cppi41_dma_issue_pending() is called after cppi41_runtime_suspend()
is called.

cppi41_stop_chan() has a bug for these cases to set channels to idle state.
It only checks the .chan_busy flag, but not the .pending list, then later
when cppi41_runtime_resume() is called the channels in .pending list will
be transitioned to busy state.

Removing channels from the .pending list solves the problem.

Fixes: 975faaeb ("dma: cppi41: start tear down only if channel is busy")
Cc: stable@vger.kernel.org # v3.15+
Signed-off-by: default avatarBin Liu <b-liu@ti.com>
Reviewed-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 64068853
Loading
Loading
Loading
Loading
+15 −1
Original line number Original line Diff line number Diff line
@@ -723,8 +723,22 @@ static int cppi41_stop_chan(struct dma_chan *chan)


	desc_phys = lower_32_bits(c->desc_phys);
	desc_phys = lower_32_bits(c->desc_phys);
	desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
	desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
	if (!cdd->chan_busy[desc_num])
	if (!cdd->chan_busy[desc_num]) {
		struct cppi41_channel *cc, *_ct;

		/*
		 * channels might still be in the pendling list if
		 * cppi41_dma_issue_pending() is called after
		 * cppi41_runtime_suspend() is called
		 */
		list_for_each_entry_safe(cc, _ct, &cdd->pending, node) {
			if (cc != c)
				continue;
			list_del(&cc->node);
			break;
		}
		return 0;
		return 0;
	}


	ret = cppi41_tear_down_chan(c);
	ret = cppi41_tear_down_chan(c);
	if (ret)
	if (ret)