Compare commits

...
1 Commits
Author SHA1 Message Date
Frank Zechert d34a6e5901 update bug fix 2026-08-21 12:25:43 +02:00
+83 -1
View File
@@ -47,7 +47,8 @@ running in the background is enough. Before the workaround the controller spent
uptime runtime-suspended, so the race window was being hit constantly.
Pin the audio controller out of runtime power management so the SoundWire links stay powered and the
window never opens.
window never opens. This alone is not sufficient — see "Docking re-arms it" below for the second
trigger this misses.
.box {Do not do this with udev} type:{warning}
A udev rule writing `ATTR{power/control}="on"` on `add|bind` looks like the obvious lever and
@@ -109,6 +110,79 @@ awk '{printf "suspended %d%%\n", 100*$1/($1+$2)}' \
<(paste /sys/bus/pci/devices/0000:00:1f.3/power/runtime_{suspended,active}_time)
```
### Docking re-arms it
Pinning the PCI controller is not the end of it. A panic on 2026-08-21 happened with `sof_pci_debug=1`
active and `runtime_suspended_time` flat at `0` for the whole session — the PCI-level fix was
verified working right up to the crash. What was different: the Dell U2724DE dock had been unplugged
and replugged 72 minutes earlier.
The dock's DP monitors drive an ASoC card-level jack/ELD reconfiguration on every replug — this is
card-wide, not SoundWire-specific, since the internal speakers and the DP outputs share the same
`sof-soundwire` ALSA card. That reconfiguration independently resumes whichever SoundWire links the
card touches. Confirmed by sampling `runtime_active_time` across a reproduced replug: `link.1` and
`link.2` (the two `rt1318` speaker amps) went from suspended-and-static to active and climbing within
under a minute, while `link.0` (the unused `rt715` mic) stayed suspended throughout. Boot alone never
produces this — every link starts out uniformly suspended and stays that way until something asks for
audio.
That asymmetric state — some links live and taking interrupts, one still parked — is exactly the
precondition `sdw_intel_thread`'s walk over `cdns == NULL` needs. The PCI-level pin has no visibility
into it, because it only prevents the *controller* from ever entering runtime PM; the link and codec
devices underneath are separate PM domains that a jack event can wake regardless.
Pinning those nine devices individually with a udev `add|bind` rule would repeat the mistake already
made once with the PCI controller: it would look correct and might still be silently reverted by a
driver-internal call this doc hasn't found. Instead, assert the invariant repeatedly rather than trust
a single write to hold:
`/usr/local/bin/pin-sof-soundwire-pm.sh` walks the PCI device, its three `soundwire_intel.link.*`,
their `sdw-master-*` children, and every `/sys/bus/soundwire/devices/sdw:*` codec, writing `on` to
`power/control` wherever it isn't already set. It's idempotent and only logs when it actually changes
something.
`/etc/systemd/system/pin-sof-soundwire-pm.timer` runs it every 15 seconds, forever, so any revert this
doc hasn't identified self-heals within one tick regardless of the mechanism:
```txt
[Timer]
OnBootSec=10s
OnUnitActiveSec=15s
```
`/etc/udev/rules.d/99-sof-soundwire-links-pm.rules` reasserts it immediately on the dock's own
Thunderbolt hotplug event, closing the gap between replug and the next timer tick, since the risky
moment is the resume race itself:
```txt
ACTION=="add", SUBSYSTEM=="thunderbolt", ATTR{vendor}=="0xd4", ATTR{device}=="0xc045", \
TAG+="systemd", ENV{SYSTEMD_WANTS}+="pin-sof-soundwire-pm.service"
```
.box {Use `+=`, not `=`, for `SYSTEMD_WANTS`} type:{warning}
`/usr/lib/udev/rules.d/90-bolt.rules` already sets `ENV{SYSTEMD_WANTS}+="bolt.service"` on the
same `thunderbolt` subsystem. A first draft of this rule used `=` instead of `+=`; being numbered
`99-` it loaded after bolt's rule and silently clobbered it, so every dock replug stopped
requesting `bolt.service` at all. `udevadm test --action=add /sys/bus/thunderbolt/devices/1-1`
catches this — check the merged `SYSTEMD_WANTS` line lists both services, not just one.
Update the Thunderbolt vendor/device match if the dock is ever replaced:
```sh
cat /sys/bus/thunderbolt/devices/*/vendor /sys/bus/thunderbolt/devices/*/device \
/sys/bus/thunderbolt/devices/*/device_name
```
Verify all nine devices are pinned:
```sh
for d in /sys/bus/pci/devices/0000:00:1f.3 /sys/bus/pci/devices/0000:00:1f.3/soundwire_intel.link.* \
/sys/bus/pci/devices/0000:00:1f.3/soundwire_intel.link.*/sdw-master-* \
/sys/bus/soundwire/devices/sdw:*; do
printf '%-70s %s\n' "$d" "$(cat "$d/power/control")"
done
```
### Recognising it after the fact
The panic leaves nothing behind, so identify it by shape rather than by trace. `CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE`
@@ -156,6 +230,14 @@ for the entire session — `journalctl -b -1 -k -p 4` shows only the usual boot-
(`charge_now == charge_full` on the next boot) and `battery-charge-watchdog` logs only its
startup line, never a `FAULT`.
The two did co-occur on 2026-08-21 — the fault fired for 101 minutes that morning, resolving
itself 8 seconds before the dock was unplugged, with the panic following 72 minutes later — but
the mechanisms are unrelated. Same dock event, two independent bugs.
A dock replug on the same day also reproduced `pcieport 0000:39:00.0: not ready 1023ms after
resume; giving up`. Not yet investigated; noted here since it fires on the same trigger as the
SoundWire re-arm above and could be mistaken for a symptom of it.
Capturing a fresh trace would need `efi_pstore.pstore_disable=0` on the kernel command line,
which means creating `/etc/kernel/cmdline`, regenerating the unified kernel image and re-signing
it. `CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE` is set, so panics are not persisted by default.