From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
To: Peter Ujfalusi <peter.ujfalusi@ti.com>,
broonie@kernel.org, lgirdwood@gmail.com
Cc: tiwai@suse.de, alsa-devel@alsa-project.org,
kuninori.morimoto.gx@renesas.com
Subject: Re: [alsa-devel] [RFC] ASoC: soc-pcm: Use different sequence for start/stop trigger
Date: Tue, 24 Sep 2019 09:07:45 -0500 [thread overview]
Message-ID: <ca102437-80e2-9e17-c40e-c50f2ac8e6d5@linux.intel.com> (raw)
In-Reply-To: <20190924114146.8116-1-peter.ujfalusi@ti.com>
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
next prev parent reply other threads:[~2019-09-24 14:08 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2019-09-24 14:15 ` Peter Ujfalusi
2019-09-24 19:40 ` Mark Brown
2019-09-25 11:07 ` Peter Ujfalusi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ca102437-80e2-9e17-c40e-c50f2ac8e6d5@linux.intel.com \
--to=pierre-louis.bossart@linux.intel.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=kuninori.morimoto.gx@renesas.com \
--cc=lgirdwood@gmail.com \
--cc=peter.ujfalusi@ti.com \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.