update bug fix
This commit is contained in:
@@ -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.
|
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
|
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}
|
.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
|
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)
|
<(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
|
### 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`
|
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
|
(`charge_now == charge_full` on the next boot) and `battery-charge-watchdog` logs only its
|
||||||
startup line, never a `FAULT`.
|
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,
|
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
|
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.
|
it. `CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE` is set, so panics are not persisted by default.
|
||||||
|
|||||||
Reference in New Issue
Block a user