Skip to content

CS35L56/L57 SoundWire amps go UNATTACHED after an s2idle (suspend) cycle that stalls ~21 s before freeze_processes() — ThinkPad X9-15p Gen 1, Panther Lake, kernel 7.2 #5898

Description

@leferi99

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

  1. Play audio through the internal speakers.
  2. Stop playback.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions