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: Pan Xiuli <xiuli.pan@linux.intel.com> Signed-off-by: Pierre-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: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
e66e52c5b7
commit
0a1b08345b
|
@ -323,6 +323,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
struct sof_ipc_stream stream;
|
struct sof_ipc_stream stream;
|
||||||
struct sof_ipc_reply reply;
|
struct sof_ipc_reply reply;
|
||||||
bool reset_hw_params = false;
|
bool reset_hw_params = false;
|
||||||
|
bool ipc_first = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* nothing to do for BE */
|
/* nothing to do for BE */
|
||||||
|
@ -343,6 +344,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
|
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
|
||||||
|
ipc_first = true;
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_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_SUSPEND:
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
|
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
|
||||||
|
ipc_first = true;
|
||||||
reset_hw_params = true;
|
reset_hw_params = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -370,12 +373,22 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
|
/*
|
||||||
|
* 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 */
|
/* send IPC to the DSP */
|
||||||
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
|
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
|
||||||
sizeof(stream), &reply, sizeof(reply));
|
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)
|
if (!ret && reset_hw_params)
|
||||||
ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
|
ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue