Unverified Commit 0a1b0834 authored by Pan Xiuli's avatar Pan Xiuli Committed by Mark Brown
Browse files

ASoC: SOF: pcm: harden PCM STOP sequence



The old STOP sequence is: 1. stop DMA 2. send STOP ipc
If delay happen before the steps 1 and 2, the DMA buffer will be empty in
short time and cause pipeline xrun then stop the pipeline.
Then the step 2 ipc stop will return error as pipeline is already stopped.

Suggested change to avoid the issue is to switch the order of steps 1 and 2
for the stop sequence.

Signed-off-by: default avatarPan Xiuli <xiuli.pan@linux.intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20190927200538.660-7-pierre-louis.bossart@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent e66e52c5
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -323,6 +323,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
	struct sof_ipc_stream stream;
	struct sof_ipc_reply reply;
	bool reset_hw_params = false;
	bool ipc_first = false;
	int ret;

	/* nothing to do for BE */
@@ -343,6 +344,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
		ipc_first = true;
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
@@ -363,6 +365,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_STOP:
		stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
		ipc_first = true;
		reset_hw_params = true;
		break;
	default:
@@ -370,12 +373,22 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
		return -EINVAL;
	}

	/*
	 * DMA and IPC sequence is different for start and stop. Need to send
	 * STOP IPC before stop DMA
	 */
	if (!ipc_first)
		snd_sof_pcm_platform_trigger(sdev, substream, cmd);

	/* send IPC to the DSP */
	ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
				 sizeof(stream), &reply, sizeof(reply));

	/* need to STOP DMA even if STOP IPC failed */
	if (ipc_first)
		snd_sof_pcm_platform_trigger(sdev, substream, cmd);

	/* free PCM if reset_hw_params is set and the STOP IPC is successful */
	if (!ret && reset_hw_params)
		ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);