diff mbox series

ASoC: wm_adsp: Avoid calling snd_compr_stop_error from WDT expiry

Message ID 20190404125601.11684-1-ckeepax@opensource.cirrus.com (mailing list archive)
State Accepted
Commit aa612f2b006aa3552871dabcd6a8e90e33f65e09
Headers show
Series ASoC: wm_adsp: Avoid calling snd_compr_stop_error from WDT expiry | expand

Commit Message

Charles Keepax April 4, 2019, 12:56 p.m. UTC
It is unsafe to call snd_compr_stop_error from outside of the
compressed ops. Firstly the compressed device lock needs to be held
and secondly it queues error work to issue a trigger stop which
should not happen after the stream has been freed. To avoid these
issues use the same trick used for the IRQ handling, simply send a
snd_compr_fragment_elapsed to cause user-space to wake on the poll,
then report the error when user-space issues the pointer request
after it wakes.

Fixes: 56bc22bd1dac ("ASoC: wm_adsp: Shutdown any compressed streams on DSP watchdog timeout")
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
 sound/soc/codecs/wm_adsp.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

Comments

Mark Brown April 4, 2019, 1:39 p.m. UTC | #1
On Thu, Apr 04, 2019 at 01:56:01PM +0100, Charles Keepax wrote:

> Fixes: 56bc22bd1dac ("ASoC: wm_adsp: Shutdown any compressed streams on DSP watchdog timeout")

This commit doesn't exist upstream...
Charles Keepax April 4, 2019, 2:38 p.m. UTC | #2
On Thu, Apr 04, 2019 at 08:39:20PM +0700, Mark Brown wrote:
> On Thu, Apr 04, 2019 at 01:56:01PM +0100, Charles Keepax wrote:
> 
> > Fixes: 56bc22bd1dac ("ASoC: wm_adsp: Shutdown any compressed streams on DSP watchdog timeout")
> 
> This commit doesn't exist upstream...

Argh... sorry about that thanks for fixing it up. Took the hash
from the wrong branch.

Thanks,
Charles
diff mbox series

Patch

diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index c8c49d5b8ac95..a9298bfddd9c7 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -4092,7 +4092,7 @@  int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
 
 	buf = compr->buf;
 
-	if (!buf || buf->error) {
+	if (dsp->fatal_error || !buf || buf->error) {
 		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
 		ret = -EIO;
 		goto out;
@@ -4196,12 +4196,13 @@  static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
 static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
 			      char __user *buf, size_t count)
 {
+	struct wm_adsp *dsp = compr->dsp;
 	int ntotal = 0;
 	int nwords, nbytes;
 
 	compr_dbg(compr, "Requested read of %zu bytes\n", count);
 
-	if (!compr->buf || compr->buf->error) {
+	if (dsp->fatal_error || !compr->buf || compr->buf->error) {
 		snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
 		return -EIO;
 	}
@@ -4262,11 +4263,8 @@  static void wm_adsp_fatal_error(struct wm_adsp *dsp)
 	dsp->fatal_error = true;
 
 	list_for_each_entry(compr, &dsp->compr_list, list) {
-		if (compr->stream) {
-			snd_compr_stop_error(compr->stream,
-					     SNDRV_PCM_STATE_XRUN);
+		if (compr->stream)
 			snd_compr_fragment_elapsed(compr->stream);
-		}
 	}
 }