Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit aa612f2b authored by Charles Keepax's avatar Charles Keepax Committed by Mark Brown
Browse files

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: a2bcbc1b ("ASoC: wm_adsp: Shutdown any compressed streams on DSP watchdog timeout")
Signed-off-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Cc: stable@kernel.org
parent fdf34366
Loading
Loading
Loading
Loading
+4 −6
Original line number Original line Diff line number Diff line
@@ -4092,7 +4092,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,


	buf = compr->buf;
	buf = compr->buf;


	if (!buf || buf->error) {
	if (dsp->fatal_error || !buf || buf->error) {
		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
		ret = -EIO;
		ret = -EIO;
		goto out;
		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,
static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
			      char __user *buf, size_t count)
			      char __user *buf, size_t count)
{
{
	struct wm_adsp *dsp = compr->dsp;
	int ntotal = 0;
	int ntotal = 0;
	int nwords, nbytes;
	int nwords, nbytes;


	compr_dbg(compr, "Requested read of %zu bytes\n", count);
	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);
		snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
		return -EIO;
		return -EIO;
	}
	}
@@ -4262,13 +4263,10 @@ static void wm_adsp_fatal_error(struct wm_adsp *dsp)
	dsp->fatal_error = true;
	dsp->fatal_error = true;


	list_for_each_entry(compr, &dsp->compr_list, list) {
	list_for_each_entry(compr, &dsp->compr_list, list) {
		if (compr->stream) {
		if (compr->stream)
			snd_compr_stop_error(compr->stream,
					     SNDRV_PCM_STATE_XRUN);
			snd_compr_fragment_elapsed(compr->stream);
			snd_compr_fragment_elapsed(compr->stream);
	}
	}
}
}
}


irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)
irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)
{
{