diff mbox series

alsa / dma: Sound stops playing after xrun

Message ID 49b8b57c-4e69-6e9e-9bb5-a2ef2df2f258@flowbird.group
State New
Headers show
Series alsa / dma: Sound stops playing after xrun | expand

Commit Message

Martin Fuzzey April 17, 2020, 10:34 a.m. UTC
Hi all,

I am seeing a sound problem leading to no more sound after an XRUN .
I see more or less what is happening and have a work around but am not
entirely sure of the correct solution.

The problem occurs on an i.MX6DL using mainline kernel 5.4 with the
fsl_ssi driver and a SGTL5000 audio codec connected over I2S.
The userspace is Android 8 using tinnyhal + tinyalsa.
This uses ioctl to push samples rather than mmap.

The scenario is:
1) A buffer underrun occurs, causing -EPIPE to be returned to userspace.
2) Userpsapce (the tinyalsa component) does a pcm_prepare() to recover 
(which
completes OK).
3) Userspace starts sending data again and then, when the start threshold
is exceeded this kernel log is generated

     fsl-ssi-dai 2028000.ssi: Timeout waiting TX FIFO filling

4) From this point on no more sound is played, further writes timeout
after 10s and return -EIO.

My analsysis is as follows:

When the underrun occurs snd_dmaengine_pcm_trigger(SNDRV_PCM_TRIGGER_STOP)
is performed which does
     dmaengine_terminate_async()

When the stream is restarted 
snd_dmaengine_pcm_trigger(SNDRV_PCM_TRIGGER_START
does
     dmaengine_submit()
     dma_async_issue_pending()

Because dmaengine_terminate_async() is asynchronus it sometimes completes
after the dmaengine_submit(), causing the new DMA request to be cancelled
before it has started.

This results in the "Timeout waiting TX FIFO filling" message (in 
fsl_ssi_config_enable())
because it enables the SSI and expects data to be transfered to the FIFO by
DMA.

The message is only a warning, (void function with no error return)
So without DMA running the buffer quicky fills up, resulting in all future
writes timeouting waiting for buffer space.

Where I'm not sure is if this is an ALSA bug or a bug in the i.MX6 SDMA
controller driver. IE is it OK to do dmaengine_terminate_async() and later
dmaengine_submit() on the same DMA channel without waiting for the
terminate to complete?

My workaround is to wait for the terminate to complete before returning
-EPIPE (just after releasing the lock which prevents sleeping earlier).

Ie this:

         snd_pcm_update_state(substream, runtime);


Regards,


Martin
diff mbox series

Patch

diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 2236b5e..b03dac3 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -18,6 +18,9 @@ 
  #include <sound/pcm_params.h>
  #include <sound/timer.h>

+#include <linux/dmaengine.h>
+#include <sound/dmaengine_pcm.h>
+
  #include "pcm_local.h"

  #ifdef CONFIG_SND_PCM_XRUN_DEBUG
@@ -2239,6 +2242,10 @@  snd_pcm_sframes_t __snd_pcm_lib_xfer(struct 
snd_pcm_substream *substream,
                 }
         }
   _end_unlock:
+    /* MF: Workaround for broken sound after XRUN. */
+    if (err == -EPIPE)
+ dmaengine_synchronize(snd_dmaengine_pcm_get_chan(substream));
+
     runtime->twake = 0;
     if (xfer > 0 && err >= 0)