[PATCH] ASoC: Intel: avs: Reset the stream unless it is already prepared

From: Sergey Tiraspolsky

Date: Sat Oct 10 2026 - 06:38:06 EST


Commit cfca1637bc2b ("ASoC: Intel: avs: Unprepare a stream when XRUN
occurs") resets the HDA stream when ->prepare() is called in the XRUN
state. User space does not always recover that way. PipeWire's ALSA
backend recovers from an underrun with snd_pcm_drop(), snd_pcm_prepare()
and a new start, so ->prepare() runs in the SETUP state,
hdac_stream->prepared is still set and the reset is skipped. Every
recovery attempt then fails the same way:

spa.alsa: hw:avsmax98927,1p: snd_pcm_avail after recover: Broken pipe

On a Google Pixelbook (Kaby Lake, max98927 speakers) this happens after
an occasional underrun during normal playback and silences the speakers
for one to four minutes, until the PCM is closed. It can be provoked by
stopping PipeWire with SIGSTOP for 0.5 s during playback: in one run
that single underrun led to 1297 failed recoveries over two minutes,
until the sink was suspended. A plain alsa-lib program that recovers
with snd_pcm_drop() and snd_pcm_prepare() hits the same loop, while
snd_pcm_prepare() straight from XRUN recovers at once.

Skip the reset only when the stream is already PREPARED, the repeated
->prepare() case the check exists for, and reset it otherwise. With
this change both kinds of recovery succeed with a single restart.

Fixes: cfca1637bc2b ("ASoC: Intel: avs: Unprepare a stream when XRUN occurs")
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Sergey Tiraspolsky <stiraspo@xxxxxxxxx>
---
How this was tested, and what was not:

- Built out of tree against a 7.2.5 distribution kernel (Omarchy
linux-omarchy 7.2.5-3, whose sound backports do not touch
avs_dai_fe_prepare()). The rebuilt stock module's .text matched the
shipped one byte for byte; the patched one differs only in this
comparison. It was installed in place of the stock module and tested
from a clean boot. It was not built or run on this branch.
- alsa-lib reproducer, no PipeWire: on hw:avsmax98927,1 write four
periods, stall 0.5 s so the stream underruns, recover, then keep
writing for 1 s, recovering every further -EPIPE the same way.
Recovering with snd_pcm_drop() + snd_pcm_prepare(): stock 958, 228
and 526 further xruns in that second; patched none (3 runs each).
Recovering with snd_pcm_prepare() from XRUN: none on either.
- PipeWire, SIGSTOP for 0.5 s during playback: stock got stuck in XRUN
3 out of 3 times until the sink was suspended; patched recovered with
a single restart 3 out of 3 times.
- Patched, also checked: HDMI 1-3, headphone playback, headset and DMIC
capture (repeated prepare and both recovery styles, no further
xruns), audible speaker playback, headphone hot-plug, and
suspend/resume during playback. After resume PipeWire logs one
"after recover: Broken pipe" and plays on, on stock and patched alike.
- Only one machine (Google Pixelbook, Kaby Lake) was tested.

sound/soc/intel/avs/pcm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index ad25bd355..880cd7a9f 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -756,7 +756,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
data = snd_soc_dai_get_dma_data(dai, substream);
host_stream = data->host_stream;

- if (runtime->state == SNDRV_PCM_STATE_XRUN)
+ if (runtime->state != SNDRV_PCM_STATE_PREPARED)
hdac_stream(host_stream)->prepared = false;
if (hdac_stream(host_stream)->prepared)
return 0;

base-commit: f90f8afb61beb268ca8092e7f3a826b520d3e8da
--
2.55.0