Summary
On a Lenovo ThinkPad X9-15p Gen 1 (Intel Panther Lake), roughly 30 % of s2idle cycles (suspend) stall for a fixed ~21 s between Filesystems sync and Freezing user space processes. Every cycle that stalls leaves all four Cirrus CS35L57 SoundWire amplifiers UNATTACHED, and audio is dead until reboot. Cycles that do not stall are always fine.
The failure only ever occurs after audio has been played and stopped, which makes it look like a race between the amps' post-playback power-down and the start of suspend.
Hardware / software
Lenovo ThinkPad X9-15p Gen 1 (21VV004FHV), Intel Panther Lake
ALSA card: sof-soundwire / LENOVO-21VV004FHV-ThinkPadX9_15pGen1
4x Cirrus Logic CS35L57 Rev B2 OTP1 fw:4.2.1 (links 1 and 2)
1x Cirrus Logic CS42L43 (link 3)
kernel 7.2.0-1-cachyos
sof-firmware 2025.12.2-1
alsa-ucm-conf 1.2.16.1-1
linux-firmware-cirrus 1:20260810-2
pipewire 1.6.8
KDE Plasma 6.7.4
Reproducer
- Play audio through the internal speakers.
- Stop playback.
- Suspend within a few seconds (lid close or idle timeout).
Roughly 1 in 3 attempts fails. Waiting ~30 s after stopping playback avoids it entirely.
Symptoms after a failed cycle
$ for f in /sys/bus/soundwire/devices/sdw:*/status; do echo "$f $(cat $f)"; done
sdw:0:1:01fa:3557:01:0 UNATTACHED
sdw:0:1:01fa:3557:01:1 UNATTACHED
sdw:0:2:01fa:3557:01:2 UNATTACHED
sdw:0:2:01fa:3557:01:3 UNATTACHED
sdw:0:3:01fa:4243:01 Attached <- cs42l43 unaffected
$ cat /sys/power/suspend_stats/last_failed_dev
sdw:0:2:01fa:3557:01:3
The ALSA card and all PCMs still exist. PipeWire falls back to a Dummy Output. The headphone jack and microphone are also unusable even though the CS42L43 stays Attached, so the whole card's routing is affected, not just the speaker path. Only a reboot recovers it.
Clean enumeration at boot, for comparison
cs35l56 sdw:0:1:01fa:3557:01:0: Cirrus Logic CS35L57 Rev B2 OTP1 fw:4.2.1 (patched=0)
cs35l56 sdw:0:1:01fa:3557:01:0: DSP1: cirrus/cs35l57-b2-dsp1-misc-17aa2355-spkid1.wmfw: format 3 timestamp 0x683df784
cs35l56 sdw:0:1:01fa:3557:01:0: DSP1: Firmware: 1a01d6 vendor: 0x2 v4.5.3, 43 algorithms
cs35l56 sdw:0:1:01fa:3557:01:0: DSP1: cirrus/cs35l57-b2-dsp1-misc-17aa2355-spkid1-l1u0.bin (v1): v4.5.3
A failing cycle
Read with journalctl -k -o short-monotonic. Wall-clock timestamps are misleading because messages after Suspending console(s) buffer until resume.
[ 599.093021] PM: suspend entry (s2idle)
[ 599.141264] Filesystems sync: 0.047 seconds
<-- 20.99 s, machine awake
[ 620.134726] Freezing user space processes
[ 620.134879] Freezing user space processes completed (elapsed 0.002 seconds)
[ 620.143480] PM: Some devices failed to suspend, or early wake event detected
[ 620.151216] cs35l56 sdw:0:1:01fa:3557:01:0: Initialization not complete
[ 620.154564] cs35l56 sdw:0:1:01fa:3557:01:0: PM: dpm_run_callback(): acpi_subsys_resume returns -110
[ 620.160111] cs35l56 sdw:0:1:01fa:3557:01:0: PM: failed to resume: error -110
[ 620.171034] cs35l56 sdw:0:1:01fa:3557:01:1: Initialization not complete
[ 620.194149] cs35l56 sdw:0:1:01fa:3557:01:1: PM: failed to resume: error -110
[ 620.244952] Restarting tasks: Done
[ 620.414010] PM: suspend exit
The freezer itself takes 2 ms. The 21 s is spent before it, and the kernel then reports an early wake event, so dpm_prepare() bails out and the amps are resumed from runtime suspend during the rollback, where they time out.
The next leg finds them already broken:
[ 620.419013] Filesystems sync: 0.004 seconds
[ 628.391212] Freezing user space processes
[ 628.392545] cs35l56 sdw:0:1:01fa:3557:01:0: Initialization not complete
[ 628.398813] cs35l56 sdw:0:1:01fa:3557:01:0: PS0 wait failed: -16
[ 628.456295] cs35l56 sdw:0:1:01fa:3557:01:0: PM: failed to resume: error -22
Subsequent playback attempts produce:
cs35l56 ...: Not enumerated, skip programming BUSCLOCK_SCALE
cs35l56 ...: DPN_PortCtrl register write failed for port 1
soundwire sdw-master-0-1: Program transport params failed: -61
SDW1-Playback-SmartAmp: ASoC error (-61): at snd_soc_link_prepare()
The stall is a fixed timeout
Six failures, measured Filesystems sync to Freezing user space processes:
21.34 21.14 21.18 20.92 20.98 21.02 seconds
A 400 ms spread over six occurrences. Every long stall (the 21s ones) lost the amps (6/6); every short one (<2s) was fine (15/15).
Kernel stacks sampled during the stall bottom out in the PM_SUSPEND_PREPARE notifier chain:
[<0>] blocking_notifier_call_chain_robust+0x68/0x1b0
[<0>] pm_notifier_call_chain_robust+0x20/0x40
[<0>] pm_suspend+0x185/0x5a0
[<0>] state_store+0x100/0x120
The specific callback has not been identified. Note that reading /proc/PID/stack on the stalled task blocks for the whole stall, which makes naive sampling unreliable.
Investigated and ruled out
- Userspace audio.
pipewire and pipewire-pulse run uninterrupted across every suspend. systemctl --user restart wireplumber does not recover the amps; UNATTACHED is bus-level.
- Runtime PM. Pinning
power/control=on on all four amps changes nothing: a cycle with it set still stalled 21.18 s and still lost them.
- The firmware loader. With
file drivers/base/firmware_loader/main.c +p, all 22 firmware blobs cached in 7 ms and the 21 s followed. 22 jobs started, 22 completed.
- System load. Suspends with many windows open behave the same as bare ones. Four cycles on a fresh boot with no audio ever played could not stall.
Timing dependence
/sys/power/pm_test=freezer inserts its own 5 s wait before the freezer, and with it armed, the failure never occurs: 29 cycles, zero stalls, against a ~30 % base rate (0.7^29 ≈ 0.005 %). Combined with the 30 s workaround, that is two independent indications that a few seconds of delay in the pre-freeze window resolves whatever is racing.
Possibly relevant
All observed failures followed a suspend initiated by the desktop (org_kde_powerdevil via logind: lid close or idle timeout), which on this system produces two kernel suspend legs, the first aborting on a pending wake event. No failure has been seen across 18+ manual systemctl suspend invocations, which produce a single leg. Small sample, but it may matter for reproduction.
An unrelated Realtek RTS522A SD card reader (mmc0, no card inserted) asserts a wakeup that aborts the first leg of most suspends on this machine, which is where the early wake event detected comes from.
Summary
On a Lenovo ThinkPad X9-15p Gen 1 (Intel Panther Lake), roughly 30 % of s2idle cycles (suspend) stall for a fixed ~21 s between
Filesystems syncandFreezing user space processes. Every cycle that stalls leaves all four Cirrus CS35L57 SoundWire amplifiersUNATTACHED, and audio is dead until reboot. Cycles that do not stall are always fine.The failure only ever occurs after audio has been played and stopped, which makes it look like a race between the amps' post-playback power-down and the start of suspend.
Hardware / software
Reproducer
Roughly 1 in 3 attempts fails. Waiting ~30 s after stopping playback avoids it entirely.
Symptoms after a failed cycle
The ALSA card and all PCMs still exist. PipeWire falls back to a Dummy Output. The headphone jack and microphone are also unusable even though the CS42L43 stays
Attached, so the whole card's routing is affected, not just the speaker path. Only a reboot recovers it.Clean enumeration at boot, for comparison
A failing cycle
Read with
journalctl -k -o short-monotonic. Wall-clock timestamps are misleading because messages afterSuspending console(s)buffer until resume.The freezer itself takes 2 ms. The 21 s is spent before it, and the kernel then reports an early wake event, so
dpm_prepare()bails out and the amps are resumed from runtime suspend during the rollback, where they time out.The next leg finds them already broken:
Subsequent playback attempts produce:
The stall is a fixed timeout
Six failures, measured
Filesystems synctoFreezing user space processes:A 400 ms spread over six occurrences. Every long stall (the 21s ones) lost the amps (6/6); every short one (<2s) was fine (15/15).
Kernel stacks sampled during the stall bottom out in the
PM_SUSPEND_PREPAREnotifier chain:The specific callback has not been identified. Note that reading
/proc/PID/stackon the stalled task blocks for the whole stall, which makes naive sampling unreliable.Investigated and ruled out
pipewireandpipewire-pulserun uninterrupted across every suspend.systemctl --user restart wireplumberdoes not recover the amps;UNATTACHEDis bus-level.power/control=onon all four amps changes nothing: a cycle with it set still stalled 21.18 s and still lost them.file drivers/base/firmware_loader/main.c +p, all 22 firmware blobs cached in 7 ms and the 21 s followed. 22 jobs started, 22 completed.Timing dependence
/sys/power/pm_test=freezerinserts its own 5 s wait before the freezer, and with it armed, the failure never occurs: 29 cycles, zero stalls, against a ~30 % base rate (0.7^29≈ 0.005 %). Combined with the 30 s workaround, that is two independent indications that a few seconds of delay in the pre-freeze window resolves whatever is racing.Possibly relevant
All observed failures followed a suspend initiated by the desktop (
org_kde_powerdevilvia logind: lid close or idle timeout), which on this system produces two kernel suspend legs, the first aborting on a pending wake event. No failure has been seen across 18+ manualsystemctl suspendinvocations, which produce a single leg. Small sample, but it may matter for reproduction.An unrelated Realtek RTS522A SD card reader (
mmc0, no card inserted) asserts a wakeup that aborts the first leg of most suspends on this machine, which is where theearly wake event detectedcomes from.