alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
* [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger
@ 2019-09-24 11:41 Peter Ujfalusi
  2019-09-24 13:50 ` Peter Ujfalusi
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Peter Ujfalusi @ 2019-09-24 11:41 UTC (permalink / raw)
  To: broonie, lgirdwood; +Cc: tiwai, alsa-devel, kuninori.morimoto.gx

On stream stop currently we stop the DMA first followed by the CPU DAI.
This can cause underflow (playback) or overflow (capture) on the DAI side
as the DMA is no longer feeding data while the DAI is still active.
It can be observed easily if the DAI side does not have FIFO (or it is
disabled) to survive the time while the DMA is stopped, but still can
happen on relatively slow CPUs when relatively high sampling rate is used:
the FIFO is drained between the time the DMA is stopped and the DAI is
stopped.

It can only fixed by using different sequence within trigger for 'stop' and
'start':
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
	Start DMA first followed by CPU DAI (currently used sequence)

case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
	Stop CPU DAI first followed by DMA

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
Hi,

on a new TI platform (j721e) where we can disable the McASP FIFO (the CPU dai)
since the UDMA + PDMA provides the buffering I have started to see error
interrupts right after pcm_trigger:STOP and in rare cases even on PAUSE that
McASP underruns.
I was also able to reproduce the same issue on am335x board, but it is much
harder to trigger it.

With this patch the underrun after trigger:STOP is gone.

If I think about the issue, I'm not sure why it was not noticed before as the
behavior makes sense:
we stop the DMA first then we stop the CPU DAI. If between the DMA stop and DAI
stop we would need a sample in the DAI (which is still running) then for sure we
will underrun in the HW (or overrun in case of capture).

When I run the ALSA conformance test [1] it is easier to trigger.

Not sure if anyone else have seen such underrun/overrun when stopping a stream,
but the fact that I have seen it with both UDMA+PDMA and EDMA on different
platforms makes me wonder if the issue can be seen on other platforms as well.

[1] https://chromium.googlesource.com/chromiumos/platform/audiotest/+/master/alsa_conformance_test.md

Regards,
Peter
---
 sound/soc/soc-pcm.c | 66 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index e163dde5eab1..c96430e70752 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1047,7 +1047,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_component *component;
@@ -1056,24 +1056,60 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 	struct snd_soc_dai *codec_dai;
 	int i, ret;
 
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
+
+		ret = snd_soc_component_trigger(component, substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
 	for_each_rtd_codec_dai(rtd, i, codec_dai) {
 		ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
 		if (ret < 0)
 			return ret;
 	}
 
-	for_each_rtdcom(rtd, rtdcom) {
-		component = rtdcom->component;
+	snd_soc_dai_trigger(cpu_dai, substream, cmd);
+	if (ret < 0)
+		return ret;
 
-		ret = snd_soc_component_trigger(component, substream, cmd);
+	if (rtd->dai_link->ops->trigger) {
+		ret = rtd->dai_link->ops->trigger(substream, cmd);
 		if (ret < 0)
 			return ret;
 	}
 
+	return 0;
+}
+
+static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component;
+	struct snd_soc_rtdcom_list *rtdcom;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai;
+	int i, ret;
+
 	snd_soc_dai_trigger(cpu_dai, substream, cmd);
 	if (ret < 0)
 		return ret;
 
+	for_each_rtd_codec_dai(rtd, i, codec_dai) {
+		ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
+
+		ret = snd_soc_component_trigger(component, substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
 	if (rtd->dai_link->ops->trigger) {
 		ret = rtd->dai_link->ops->trigger(substream, cmd);
 		if (ret < 0)
@@ -1083,6 +1119,28 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 	return 0;
 }
 
+static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = soc_pcm_trigger_start(substream, cmd);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = soc_pcm_trigger_stop(substream, cmd);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
 static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
 				   int cmd)
 {
-- 
Peter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger
  2019-09-24 11:41 [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger Peter Ujfalusi
@ 2019-09-24 13:50 ` Peter Ujfalusi
  2019-09-24 14:07 ` Pierre-Louis Bossart
  2019-09-24 19:40 ` Mark Brown
  2 siblings, 0 replies; 6+ messages in thread
From: Peter Ujfalusi @ 2019-09-24 13:50 UTC (permalink / raw)
  To: broonie, lgirdwood; +Cc: tiwai, alsa-devel, kuninori.morimoto.gx



On 24/09/2019 14.41, Peter Ujfalusi wrote:
> On stream stop currently we stop the DMA first followed by the CPU DAI.
> This can cause underflow (playback) or overflow (capture) on the DAI side
> as the DMA is no longer feeding data while the DAI is still active.
> It can be observed easily if the DAI side does not have FIFO (or it is
> disabled) to survive the time while the DMA is stopped, but still can
> happen on relatively slow CPUs when relatively high sampling rate is used:
> the FIFO is drained between the time the DMA is stopped and the DAI is
> stopped.
> 
> It can only fixed by using different sequence within trigger for 'stop' and
> 'start':
> case SNDRV_PCM_TRIGGER_START:
> case SNDRV_PCM_TRIGGER_RESUME:
> case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> 	Start DMA first followed by CPU DAI (currently used sequence)
> 
> case SNDRV_PCM_TRIGGER_STOP:
> case SNDRV_PCM_TRIGGER_SUSPEND:
> case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> 	Stop CPU DAI first followed by DMA
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> ---
> Hi,
> 
> on a new TI platform (j721e) where we can disable the McASP FIFO (the CPU dai)
> since the UDMA + PDMA provides the buffering I have started to see error
> interrupts right after pcm_trigger:STOP and in rare cases even on PAUSE that
> McASP underruns.
> I was also able to reproduce the same issue on am335x board, but it is much
> harder to trigger it.
> 
> With this patch the underrun after trigger:STOP is gone.
> 
> If I think about the issue, I'm not sure why it was not noticed before as the
> behavior makes sense:
> we stop the DMA first then we stop the CPU DAI. If between the DMA stop and DAI
> stop we would need a sample in the DAI (which is still running) then for sure we
> will underrun in the HW (or overrun in case of capture).
> 
> When I run the ALSA conformance test [1] it is easier to trigger.
> 
> Not sure if anyone else have seen such underrun/overrun when stopping a stream,
> but the fact that I have seen it with both UDMA+PDMA and EDMA on different
> platforms makes me wonder if the issue can be seen on other platforms as well.
> 
> [1] https://chromium.googlesource.com/chromiumos/platform/audiotest/+/master/alsa_conformance_test.md
> 
> Regards,
> Peter
> ---
>  sound/soc/soc-pcm.c | 66 ++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 62 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
> index e163dde5eab1..c96430e70752 100644
> --- a/sound/soc/soc-pcm.c
> +++ b/sound/soc/soc-pcm.c
> @@ -1047,7 +1047,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
>  	return 0;
>  }
>  
> -static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
> +static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
>  {
>  	struct snd_soc_pcm_runtime *rtd = substream->private_data;
>  	struct snd_soc_component *component;
> @@ -1056,24 +1056,60 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
>  	struct snd_soc_dai *codec_dai;
>  	int i, ret;
>  
> +	for_each_rtdcom(rtd, rtdcom) {
> +		component = rtdcom->component;
> +
> +		ret = snd_soc_component_trigger(component, substream, cmd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>  	for_each_rtd_codec_dai(rtd, i, codec_dai) {
>  		ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
>  		if (ret < 0)
>  			return ret;
>  	}
>  
> -	for_each_rtdcom(rtd, rtdcom) {
> -		component = rtdcom->component;
> +	snd_soc_dai_trigger(cpu_dai, substream, cmd);

ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);

> +	if (ret < 0)
> +		return ret;
>  
> -		ret = snd_soc_component_trigger(component, substream, cmd);
> +	if (rtd->dai_link->ops->trigger) {
> +		ret = rtd->dai_link->ops->trigger(substream, cmd);
>  		if (ret < 0)
>  			return ret;
>  	}
>  
> +	return 0;
> +}
> +
> +static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_component *component;
> +	struct snd_soc_rtdcom_list *rtdcom;
> +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> +	struct snd_soc_dai *codec_dai;
> +	int i, ret;
> +
>  	snd_soc_dai_trigger(cpu_dai, substream, cmd);

ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);


>  	if (ret < 0)
>  		return ret;
>  
> +	for_each_rtd_codec_dai(rtd, i, codec_dai) {
> +		ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	for_each_rtdcom(rtd, rtdcom) {
> +		component = rtdcom->component;
> +
> +		ret = snd_soc_component_trigger(component, substream, cmd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>  	if (rtd->dai_link->ops->trigger) {
>  		ret = rtd->dai_link->ops->trigger(substream, cmd);
>  		if (ret < 0)
> @@ -1083,6 +1119,28 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
>  	return 0;
>  }
>  
> +static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> +	int ret;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		ret = soc_pcm_trigger_start(substream, cmd);
> +		break;
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		ret = soc_pcm_trigger_stop(substream, cmd);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>  static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
>  				   int cmd)
>  {
> 

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger
  2019-09-24 11:41 [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger Peter Ujfalusi
  2019-09-24 13:50 ` Peter Ujfalusi
@ 2019-09-24 14:07 ` Pierre-Louis Bossart
  2019-09-24 14:15   ` Peter Ujfalusi
  2019-09-24 19:40 ` Mark Brown
  2 siblings, 1 reply; 6+ messages in thread
From: Pierre-Louis Bossart @ 2019-09-24 14:07 UTC (permalink / raw)
  To: Peter Ujfalusi, broonie, lgirdwood
  Cc: tiwai, alsa-devel, kuninori.morimoto.gx



On 9/24/19 6:41 AM, Peter Ujfalusi wrote:
> On stream stop currently we stop the DMA first followed by the CPU DAI.
> This can cause underflow (playback) or overflow (capture) on the DAI side
> as the DMA is no longer feeding data while the DAI is still active.
> It can be observed easily if the DAI side does not have FIFO (or it is
> disabled) to survive the time while the DMA is stopped, but still can
> happen on relatively slow CPUs when relatively high sampling rate is used:
> the FIFO is drained between the time the DMA is stopped and the DAI is
> stopped.
> 
> It can only fixed by using different sequence within trigger for 'stop' and
> 'start':
> case SNDRV_PCM_TRIGGER_START:
> case SNDRV_PCM_TRIGGER_RESUME:
> case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> 	Start DMA first followed by CPU DAI (currently used sequence)
> 
> case SNDRV_PCM_TRIGGER_STOP:
> case SNDRV_PCM_TRIGGER_SUSPEND:
> case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> 	Stop CPU DAI first followed by DMA
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> ---
> Hi,
> 
> on a new TI platform (j721e) where we can disable the McASP FIFO (the CPU dai)
> since the UDMA + PDMA provides the buffering I have started to see error
> interrupts right after pcm_trigger:STOP and in rare cases even on PAUSE that
> McASP underruns.
> I was also able to reproduce the same issue on am335x board, but it is much
> harder to trigger it.
> 
> With this patch the underrun after trigger:STOP is gone.
> 
> If I think about the issue, I'm not sure why it was not noticed before as the
> behavior makes sense:
> we stop the DMA first then we stop the CPU DAI. If between the DMA stop and DAI
> stop we would need a sample in the DAI (which is still running) then for sure we
> will underrun in the HW (or overrun in case of capture).
> 
> When I run the ALSA conformance test [1] it is easier to trigger.
> 
> Not sure if anyone else have seen such underrun/overrun when stopping a stream,
> but the fact that I have seen it with both UDMA+PDMA and EDMA on different
> platforms makes me wonder if the issue can be seen on other platforms as well.
> 
> [1] https://chromium.googlesource.com/chromiumos/platform/audiotest/+/master/alsa_conformance_test.md

This is interesting, we had a similar issue for SOF on HDaudio platforms 
with underruns on stop [1], which we fixed 'locally' with a change 
between IPC and DMA stop.

I'll ask our CI/QA folks to check if this patch improves the results 
further.

[1] https://github.com/thesofproject/linux/pull/1169/commits

> 
> Regards,
> Peter
> ---
>   sound/soc/soc-pcm.c | 66 ++++++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 62 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
> index e163dde5eab1..c96430e70752 100644
> --- a/sound/soc/soc-pcm.c
> +++ b/sound/soc/soc-pcm.c
> @@ -1047,7 +1047,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
>   	return 0;
>   }
>   
> -static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
> +static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
>   {
>   	struct snd_soc_pcm_runtime *rtd = substream->private_data;
>   	struct snd_soc_component *component;
> @@ -1056,24 +1056,60 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
>   	struct snd_soc_dai *codec_dai;
>   	int i, ret;
>   
> +	for_each_rtdcom(rtd, rtdcom) {
> +		component = rtdcom->component;
> +
> +		ret = snd_soc_component_trigger(component, substream, cmd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>   	for_each_rtd_codec_dai(rtd, i, codec_dai) {
>   		ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
>   		if (ret < 0)
>   			return ret;
>   	}
>   
> -	for_each_rtdcom(rtd, rtdcom) {
> -		component = rtdcom->component;
> +	snd_soc_dai_trigger(cpu_dai, substream, cmd);
> +	if (ret < 0)
> +		return ret;
>   
> -		ret = snd_soc_component_trigger(component, substream, cmd);
> +	if (rtd->dai_link->ops->trigger) {
> +		ret = rtd->dai_link->ops->trigger(substream, cmd);
>   		if (ret < 0)
>   			return ret;
>   	}
>   
> +	return 0;
> +}
> +
> +static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_component *component;
> +	struct snd_soc_rtdcom_list *rtdcom;
> +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> +	struct snd_soc_dai *codec_dai;
> +	int i, ret;
> +
>   	snd_soc_dai_trigger(cpu_dai, substream, cmd);
>   	if (ret < 0)
>   		return ret;
>   
> +	for_each_rtd_codec_dai(rtd, i, codec_dai) {
> +		ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	for_each_rtdcom(rtd, rtdcom) {
> +		component = rtdcom->component;
> +
> +		ret = snd_soc_component_trigger(component, substream, cmd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>   	if (rtd->dai_link->ops->trigger) {
>   		ret = rtd->dai_link->ops->trigger(substream, cmd);
>   		if (ret < 0)
> @@ -1083,6 +1119,28 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
>   	return 0;
>   }
>   
> +static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> +	int ret;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		ret = soc_pcm_trigger_start(substream, cmd);
> +		break;
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		ret = soc_pcm_trigger_stop(substream, cmd);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>   static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
>   				   int cmd)
>   {
> 
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger
  2019-09-24 14:07 ` Pierre-Louis Bossart
@ 2019-09-24 14:15   ` Peter Ujfalusi
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Ujfalusi @ 2019-09-24 14:15 UTC (permalink / raw)
  To: Pierre-Louis Bossart, broonie, lgirdwood
  Cc: tiwai, alsa-devel, kuninori.morimoto.gx



On 24/09/2019 17.07, Pierre-Louis Bossart wrote:
> 
> 
> On 9/24/19 6:41 AM, Peter Ujfalusi wrote:
>> On stream stop currently we stop the DMA first followed by the CPU DAI.
>> This can cause underflow (playback) or overflow (capture) on the DAI side
>> as the DMA is no longer feeding data while the DAI is still active.
>> It can be observed easily if the DAI side does not have FIFO (or it is
>> disabled) to survive the time while the DMA is stopped, but still can
>> happen on relatively slow CPUs when relatively high sampling rate is
>> used:
>> the FIFO is drained between the time the DMA is stopped and the DAI is
>> stopped.
>>
>> It can only fixed by using different sequence within trigger for
>> 'stop' and
>> 'start':
>> case SNDRV_PCM_TRIGGER_START:
>> case SNDRV_PCM_TRIGGER_RESUME:
>> case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>>     Start DMA first followed by CPU DAI (currently used sequence)
>>
>> case SNDRV_PCM_TRIGGER_STOP:
>> case SNDRV_PCM_TRIGGER_SUSPEND:
>> case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>>     Stop CPU DAI first followed by DMA
>>
>> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
>> ---
>> Hi,
>>
>> on a new TI platform (j721e) where we can disable the McASP FIFO (the
>> CPU dai)
>> since the UDMA + PDMA provides the buffering I have started to see error
>> interrupts right after pcm_trigger:STOP and in rare cases even on
>> PAUSE that
>> McASP underruns.
>> I was also able to reproduce the same issue on am335x board, but it is
>> much
>> harder to trigger it.
>>
>> With this patch the underrun after trigger:STOP is gone.
>>
>> If I think about the issue, I'm not sure why it was not noticed before
>> as the
>> behavior makes sense:
>> we stop the DMA first then we stop the CPU DAI. If between the DMA
>> stop and DAI
>> stop we would need a sample in the DAI (which is still running) then
>> for sure we
>> will underrun in the HW (or overrun in case of capture).
>>
>> When I run the ALSA conformance test [1] it is easier to trigger.
>>
>> Not sure if anyone else have seen such underrun/overrun when stopping
>> a stream,
>> but the fact that I have seen it with both UDMA+PDMA and EDMA on
>> different
>> platforms makes me wonder if the issue can be seen on other platforms
>> as well.
>>
>> [1]
>> https://chromium.googlesource.com/chromiumos/platform/audiotest/+/master/alsa_conformance_test.md
>>
> 
> This is interesting, we had a similar issue for SOF on HDaudio platforms
> with underruns on stop [1], which we fixed 'locally' with a change
> between IPC and DMA stop.

First I tried to 'fix' (to be precise mask it) locally by adding a flag
in McASP driver that now the DAI is stopped and ignore any interrupts.
Obviously it fixed the print, but it did not fixed the things on the bus
- McASP shifts out the last word it had in case of underrun.
This is why I looked deeper and the soc_pcm_trigger sequence matched the
symptoms I have been seeing.

> I'll ask our CI/QA folks to check if this patch improves the results
> further.

Looking forward to see the result, it might be that you can even revert
the workaround? But looking at it more closely SOF has it's own
sequencing, perhaps the two might be needed at the same time?

> [1] https://github.com/thesofproject/linux/pull/1169/commits
> 
>>
>> Regards,
>> Peter
>> ---
>>   sound/soc/soc-pcm.c | 66 ++++++++++++++++++++++++++++++++++++++++++---
>>   1 file changed, 62 insertions(+), 4 deletions(-)
>>
>> diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
>> index e163dde5eab1..c96430e70752 100644
>> --- a/sound/soc/soc-pcm.c
>> +++ b/sound/soc/soc-pcm.c
>> @@ -1047,7 +1047,7 @@ static int soc_pcm_hw_free(struct
>> snd_pcm_substream *substream)
>>       return 0;
>>   }
>>   -static int soc_pcm_trigger(struct snd_pcm_substream *substream, int
>> cmd)
>> +static int soc_pcm_trigger_start(struct snd_pcm_substream *substream,
>> int cmd)
>>   {
>>       struct snd_soc_pcm_runtime *rtd = substream->private_data;
>>       struct snd_soc_component *component;
>> @@ -1056,24 +1056,60 @@ static int soc_pcm_trigger(struct
>> snd_pcm_substream *substream, int cmd)
>>       struct snd_soc_dai *codec_dai;
>>       int i, ret;
>>   +    for_each_rtdcom(rtd, rtdcom) {
>> +        component = rtdcom->component;
>> +
>> +        ret = snd_soc_component_trigger(component, substream, cmd);
>> +        if (ret < 0)
>> +            return ret;
>> +    }
>> +
>>       for_each_rtd_codec_dai(rtd, i, codec_dai) {
>>           ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
>>           if (ret < 0)
>>               return ret;
>>       }
>>   -    for_each_rtdcom(rtd, rtdcom) {
>> -        component = rtdcom->component;
>> +    snd_soc_dai_trigger(cpu_dai, substream, cmd);
>> +    if (ret < 0)
>> +        return ret;
>>   -        ret = snd_soc_component_trigger(component, substream, cmd);
>> +    if (rtd->dai_link->ops->trigger) {
>> +        ret = rtd->dai_link->ops->trigger(substream, cmd);
>>           if (ret < 0)
>>               return ret;
>>       }
>>   +    return 0;
>> +}
>> +
>> +static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream,
>> int cmd)
>> +{
>> +    struct snd_soc_pcm_runtime *rtd = substream->private_data;
>> +    struct snd_soc_component *component;
>> +    struct snd_soc_rtdcom_list *rtdcom;
>> +    struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>> +    struct snd_soc_dai *codec_dai;
>> +    int i, ret;
>> +
>>       snd_soc_dai_trigger(cpu_dai, substream, cmd);
>>       if (ret < 0)
>>           return ret;
>>   +    for_each_rtd_codec_dai(rtd, i, codec_dai) {
>> +        ret = snd_soc_dai_trigger(codec_dai, substream, cmd);
>> +        if (ret < 0)
>> +            return ret;
>> +    }
>> +
>> +    for_each_rtdcom(rtd, rtdcom) {
>> +        component = rtdcom->component;
>> +
>> +        ret = snd_soc_component_trigger(component, substream, cmd);
>> +        if (ret < 0)
>> +            return ret;
>> +    }
>> +
>>       if (rtd->dai_link->ops->trigger) {
>>           ret = rtd->dai_link->ops->trigger(substream, cmd);
>>           if (ret < 0)
>> @@ -1083,6 +1119,28 @@ static int soc_pcm_trigger(struct
>> snd_pcm_substream *substream, int cmd)
>>       return 0;
>>   }
>>   +static int soc_pcm_trigger(struct snd_pcm_substream *substream, int
>> cmd)
>> +{
>> +    int ret;
>> +
>> +    switch (cmd) {
>> +    case SNDRV_PCM_TRIGGER_START:
>> +    case SNDRV_PCM_TRIGGER_RESUME:
>> +    case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> +        ret = soc_pcm_trigger_start(substream, cmd);
>> +        break;
>> +    case SNDRV_PCM_TRIGGER_STOP:
>> +    case SNDRV_PCM_TRIGGER_SUSPEND:
>> +    case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>> +        ret = soc_pcm_trigger_stop(substream, cmd);
>> +        break;
>> +    default:
>> +        return -EINVAL;
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>>   static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
>>                      int cmd)
>>   {
>>

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger
  2019-09-24 11:41 [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger Peter Ujfalusi
  2019-09-24 13:50 ` Peter Ujfalusi
  2019-09-24 14:07 ` Pierre-Louis Bossart
@ 2019-09-24 19:40 ` Mark Brown
  2019-09-25 11:07   ` Peter Ujfalusi
  2 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2019-09-24 19:40 UTC (permalink / raw)
  To: Peter Ujfalusi; +Cc: tiwai, alsa-devel, lgirdwood, kuninori.morimoto.gx


[-- Attachment #1.1: Type: text/plain, Size: 1369 bytes --]

On Tue, Sep 24, 2019 at 02:41:46PM +0300, Peter Ujfalusi wrote:

> It can only fixed by using different sequence within trigger for 'stop' and
> 'start':
> case SNDRV_PCM_TRIGGER_START:
> case SNDRV_PCM_TRIGGER_RESUME:
> case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> 	Start DMA first followed by CPU DAI (currently used sequence)
> 
> case SNDRV_PCM_TRIGGER_STOP:
> case SNDRV_PCM_TRIGGER_SUSPEND:
> case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> 	Stop CPU DAI first followed by DMA

Yeah, this makes sense I think.

> If I think about the issue, I'm not sure why it was not noticed before as the
> behavior makes sense:
> we stop the DMA first then we stop the CPU DAI. If between the DMA stop and DAI
> stop we would need a sample in the DAI (which is still running) then for sure we
> will underrun in the HW (or overrun in case of capture).

There are a bunch of systems where the trigger only actually does
anything with one or the other of the IPs and the startup for the
other is handled by a hardware signal so the ordering doesn't
really matter for them.

> Not sure if anyone else have seen such underrun/overrun when stopping a stream,
> but the fact that I have seen it with both UDMA+PDMA and EDMA on different
> platforms makes me wonder if the issue can be seen on other platforms as well.

I'd guess so, especially with smaller buffers.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger
  2019-09-24 19:40 ` Mark Brown
@ 2019-09-25 11:07   ` Peter Ujfalusi
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Ujfalusi @ 2019-09-25 11:07 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, lgirdwood, kuninori.morimoto.gx



On 24/09/2019 22.40, Mark Brown wrote:
> On Tue, Sep 24, 2019 at 02:41:46PM +0300, Peter Ujfalusi wrote:
> 
>> It can only fixed by using different sequence within trigger for 'stop' and
>> 'start':
>> case SNDRV_PCM_TRIGGER_START:
>> case SNDRV_PCM_TRIGGER_RESUME:
>> case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> 	Start DMA first followed by CPU DAI (currently used sequence)
>>
>> case SNDRV_PCM_TRIGGER_STOP:
>> case SNDRV_PCM_TRIGGER_SUSPEND:
>> case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>> 	Stop CPU DAI first followed by DMA
> 
> Yeah, this makes sense I think.
> 
>> If I think about the issue, I'm not sure why it was not noticed before as the
>> behavior makes sense:
>> we stop the DMA first then we stop the CPU DAI. If between the DMA stop and DAI
>> stop we would need a sample in the DAI (which is still running) then for sure we
>> will underrun in the HW (or overrun in case of capture).
> 
> There are a bunch of systems where the trigger only actually does
> anything with one or the other of the IPs and the startup for the
> other is handled by a hardware signal so the ordering doesn't
> really matter for them.

If they use generic dmaengine pcm then their DMA is going to be
stopped/paused in trigger. Not sure how they can handle in DAI when the
DMA is stopped.

>> Not sure if anyone else have seen such underrun/overrun when stopping a stream,
>> but the fact that I have seen it with both UDMA+PDMA and EDMA on different
>> platforms makes me wonder if the issue can be seen on other platforms as well.
> 
> I'd guess so, especially with smaller buffers.

I have sent the non RFC patch with fix to the not initialized ret and
updated commit message to document the trigger sequences for start and
stop type of events.


- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-09-25 11:08 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-24 11:41 [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger Peter Ujfalusi
2019-09-24 13:50 ` Peter Ujfalusi
2019-09-24 14:07 ` Pierre-Louis Bossart
2019-09-24 14:15   ` Peter Ujfalusi
2019-09-24 19:40 ` Mark Brown
2019-09-25 11:07   ` Peter Ujfalusi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).