[REGRESSION 7.2-rc3] ASoC: cs35l56: component p robe waits for an init_completion that cannot be signalled unti l the wait ends — whole sof_sdw card fails

"Salman S. Tahir" <[email protected]> Wed, 15 Jul 2026 18:08:09 +0300
Newsgroups org.alsa-project.alsa-devel,org.kernel.vger.linux-sound
Message-ID <[email protected]>
Hi,

On a Lenovo Yoga 9 2-in-1 14ILL10 (83LC, Core Ultra 7 258V / Lunar Lake; 
CS42L43
plus two SPI-attached CS35L56 amps behind it) the machine has no sound 
card at all
on 7.2-rc3. /proc/asound/cards is empty and PipeWire falls back to a 
null sink.

The right-hand amp's ASoC component probe times out waiting for 
init_completion,
returns -ENODEV, and ASoC then tears down the entire card -- so 
speakers, internal
mics, headset and all three HDMI outputs die because of one failed 
component:

[ 10.301...] cs35l56 spi-cs35l56-right: _cs35l56_component_probe: 
init_completion timed out
[ 10.301...] cs35l56 spi-cs35l56-right: ASoC error (-19): at 
snd_soc_component_probe() on spi-cs35l56-right
[ 10.302...] sof_sdw sof_sdw: ASoC: failed to instantiate card -19

This is 100% reproducible. Scanning my whole journal (151 boots, back to
2026-03-07): 11 failures in 11 boots on 7.2.0-rc3, against 0 failures in 
138 boots
on every kernel I ran before it -- 6.17.0-14 (1 boot), 6.19.4 (83), 
7.0.0-15 (20),
7.0.0-22 (20), 7.0.0-27 (14). It breaks at the first 7.2-rc3 boot and 
has failed
every one since. (A 12th 7.2-rc3 boot is clean, but only because of the 
workaround
described below.) Those failures were all captured on an otherwise stock 
machine --
clean kernel cmdline, distro modprobe.d only, no out-of-tree modules 
(other than the
timeout experiment below), no DSDT override, distro Cirrus firmware. I 
now run a
local workaround (a snd_soc_sof_sdw blacklist plus a service that loads 
it late --
described below); I can drop it and reproduce the failure on demand.


This is not a slow-firmware race
--------------------------------

The obvious reading of that log is "the amp is a bit too slow and misses 
the 5s
deadline". It isn't, and I want to save you from chasing that. I rebuilt
snd-soc-cs35l56 for 7.2-rc3 with a single change -- the component-probe 
wait at
sound/soc/codecs/cs35l56.c:1371, msecs_to_jiffies(5000) -> 
msecs_to_jiffies(30000)
-- and booted it. It fails identically, just later:

component-probe timeout | wait expires at | right amp's cs35l56_init() 
actually starts
------------------------+-----------------+-------------------------------------------
5000 ms (stock) | 10.301 s | 10.355 s -- 54 ms after the wait gave up
30000 ms (patched) | 35.901 s | 36.005 s -- 104 ms after the wait gave up

During the entire 30-second wait the right amp emits nothing. It does 
not even reach
the cs35l56_hw_init() identification print that the left amp produced at 
5.29 s:

[ 5.294911] cs35l56 spi-cs35l56-left: Cirrus Logic CS35L56 Rev B0 OTP3 
fw:3.4.4 (patched=0)
[ 5.603038] cs35l56 spi-cs35l56-left: DSP1: 
cirrus/cs35l56-b0-dsp1-misc-17aa3832-spkid0.wmfw: format 3 ...
[ 7.681077] cs35l56 spi-cs35l56-left: DSP1: Firmware: 1a00d6 vendor: 0x2 
v3.11.26, 41 algorithms
[ 9.498049] cs35l56 spi-cs35l56-left: Calibration applied
<-- 26 seconds of silence from the right amp -->
[ 35.901035] cs35l56 spi-cs35l56-right: _cs35l56_component_probe: 
init_completion timed out
[ 35.902534] sof_sdw sof_sdw: ASoC: failed to instantiate card -19
[ 36.005138] cs35l56 spi-cs35l56-right: Cirrus Logic CS35L56 Rev B0 OTP3 
fw:3.4.4 (patched=0)

So the right amp's init is not losing a race against the deadline -- it 
is blocked by
the wait itself, and only proceeds once the waiter gives up. Increasing 
the timeout
just increases the wait; a 300-second timeout would fail at 305 seconds. 
The amp is
not slow: once released it completes cs35l56_init() normally. (It gets 
no firmware
download at that point -- the timeout path returns -ENODEV well before the
queue_work(&cs35l56->dsp_work) at the end of _cs35l56_component_probe(), 
so nothing
ever queues one for it.)


The hardware is fine -- the card is just built ~100 ms too early
----------------------------------------------------------------

After the failed instantiation, spi-cs35l56-right is bound to the 
driver, i.e. its
probe returned 0 and complete(&cs35l56->init_completion) did run. 
Nothing about the
hardware, the firmware download or the SPI-over-SoundWire path is 
broken; the card is
simply instantiated before the right amp is ready, and nothing ever 
retries it.

I confirmed that by keeping the deadlock from forming at all, rather 
than repairing it
afterwards: blacklist snd_soc_sof_sdw, wait until both amps have 
signalled init, then
load it. With no card probe in flight there is nothing to starve the 
right amp: both
amps reach their identification print within ~260 ms of each other 
(4.744 s and
5.008 s), the component probe's wait returns immediately, no timeout 
fires, and the
card registers first time. Both amps are still patched=0 at that point, 
so both take
the full firmware-download path, and both calibrate:

[ 19.770067] cs35l56 spi-cs35l56-left: Calibration applied
[ 19.777038] cs35l56 spi-cs35l56-right: Calibration applied

That boot has since suspended and resumed with the card intact, and 
contains no error
or warning from cs35l56, cs42l43 or SOF at all.


Hypothesis (unverified -- offered only as a starting point)
-----------------------------------------------------------

Something in 7.2 appears to have changed the ordering such that the 
right amp's probe
and the sof_sdw card probe end up on the same execution context (the 
deferred-probe
worker would fit the ~100 ms lag), so the blocking wait in 
_cs35l56_component_probe()
starves the very work it is waiting for. I have not confirmed that, and 
I have not
bisected -- I am reporting the reproducible behaviour rather than 
guessing at the
culprit commit, and I would rather not send you down a path I only inferred.


Suggested direction
-------------------

Regardless of what changed the ordering, blocking in a component probe 
on a completion
that a different probe must signal looks fragile by construction. Returning
-EPROBE_DEFER instead -- letting the driver core retry the card once the 
amp is bound
-- would use the mechanism the kernel already has for this, and 
snd_soc_bind_card()
already special-cases -EPROBE_DEFER from soc_probe_link_components(). 
Something along
the lines of:

if (!wait_for_completion_timeout(&cs35l56->init_completion,
msecs_to_jiffies(5000)))
return 
dev_err_probe(cs35l56->https://www.google.com/url?q=http://base.dev&source=gmail&ust=1784212475584000&sa=E, 
-EPROBE_DEFER,
"init_completion not signalled, deferring\n");

I have not tested that; I did not want to submit a patch built on a 
mechanism I have
only hypothesised.

I have the hardware, I can reproduce this on every boot, and I am happy 
to test
patches, run instrumented builds, or bisect if that would help. Just 
tell me what
would be most useful.


Environment
-----------

- Lenovo Yoga 9 2-in-1 14ILL10 (83LC), Core Ultra 7 258V (Lunar Lake)
- CS42L43 (SoundWire) + 2x CS35L56 Rev B0, SPI-attached via the CS42L43
- Firmware: cirrus/cs35l56-b0-dsp1-misc-17aa3832-spkid0.wmfw v3.11.26 
(distro linux-firmware)
- Bad: 7.2-rc3 (7.2.0-070200rc3-generic, mainline build) -- 11 failures 
/ 11 boots
- Good: 7.0.0-27 (14 boots), 7.0.0-22 (20), 7.0.0-15 (20), 6.19.4 (83), 
6.17.0-14 (1)
-- 138 boots, 0 failures
- Only the 30 s-timeout boot above ran a rebuilt (out-of-tree, 
kernel-tainting)
snd-soc-cs35l56; every stock-timeout failure was on the untainted distro 
module
- Not bisected
- Workaround currently in place: blacklist snd_soc_sof_sdw + a systemd 
unit that
modprobes it once both amps have signalled init. Removable on request -- 
I can
reproduce the failure on any boot.

Thanks,
Salman S. Tahir