diff options
author | Charles Keepax <ckeepax@opensource.cirrus.com> | 2019-04-04 13:56:01 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-04-04 20:51:34 +0700 |
commit | aa612f2b006aa3552871dabcd6a8e90e33f65e09 (patch) | |
tree | 110656840bce5f8cf9b98d92e1cf67569deddb7f /sound/soc/codecs/wm_adsp.c | |
parent | fdf34366d3242d5eeffa1b4d9a3497ebf30a4ecb (diff) |
ASoC: wm_adsp: Avoid calling snd_compr_stop_error from WDT expiry
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: a2bcbc1b9ac2f ("ASoC: wm_adsp: Shutdown any compressed streams on DSP watchdog timeout")
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Cc: stable@kernel.org
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 10 |
1 files changed, 4 insertions, 6 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index c8c49d5b8ac9..a9298bfddd9c 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); - } } } |