hardware bugs in xps13
This commit is contained in:
+60
-10
@@ -49,20 +49,41 @@ 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.
|
||||
|
||||
`/etc/udev/rules.d/99-sof-audio-no-runtime-pm.rules`:
|
||||
.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
|
||||
matches correctly — `udevadm test` confirms it fires for both actions — but it does not hold.
|
||||
`snd_sof_pci` calls `pm_runtime_allow()` from `sof_pci_probe_complete()`, which runs *after* the
|
||||
uevents udev hooks, so the driver reverts `power/control` to `auto` on every boot.
|
||||
|
||||
This cost five further panics between 2026-08-11 and 2026-08-20 while the rule sat in
|
||||
`/etc/udev/rules.d/` looking like active protection.
|
||||
|
||||
Gate the driver instead. Bit 0 of `sof_pci_debug` (`SOF_PCI_DISABLE_PM_RUNTIME`) makes
|
||||
`sof_pci_probe_complete()` return before it reaches the runtime PM setup, so there is no ordering to
|
||||
lose:
|
||||
|
||||
```txt
|
||||
ACTION=="add|bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", ATTR{device}=="0xa828", ATTR{power/control}="on"
|
||||
sof_pci_probe_complete:
|
||||
testb $0x1, sof_pci_debug ; skip the block entirely when bit 0 is set
|
||||
je ...
|
||||
pm_runtime_set_autosuspend_delay(dev, 0x7d0) ; 2000 ms
|
||||
__pm_runtime_use_autosuspend(dev, 1)
|
||||
pm_runtime_allow(dev) ; this is what reverts power/control to "auto"
|
||||
```
|
||||
|
||||
Matching on the PCI ID `8086:a828` rather than the slot `0000:00:1f.3` keeps the rule valid if the
|
||||
device is ever renumbered. `add|bind` covers both device registration and driver bind.
|
||||
`/etc/modprobe.d/99-sof-no-runtime-pm.conf`:
|
||||
|
||||
Apply it without rebooting:
|
||||
```txt
|
||||
options snd_sof_pci sof_pci_debug=1
|
||||
```
|
||||
|
||||
`snd_sof_pci` is not in the initramfs, so this needs no `mkinitcpio` run and no re-signing of the
|
||||
unified kernel image. It takes effect on the next boot.
|
||||
|
||||
Close the window immediately on a running system, without waiting for a reboot:
|
||||
|
||||
```sh
|
||||
sudo udevadm control --reload
|
||||
sudo udevadm trigger --action=add /sys/bus/pci/devices/0000:00:1f.3
|
||||
echo on | sudo tee /sys/bus/pci/devices/0000:00:1f.3/power/control
|
||||
```
|
||||
|
||||
Verify. `control` must read `on` and `runtime_status` must read `active`:
|
||||
@@ -79,14 +100,37 @@ cat /sys/bus/pci/devices/0000:00:1f.3/power/runtime_suspended_time
|
||||
cat /sys/bus/pci/devices/0000:00:1f.3/power/runtime_active_time
|
||||
```
|
||||
|
||||
Confirm the rule also applies on a fresh boot rather than only surviving the manual trigger:
|
||||
Check the ratio after a fresh boot, not just the manual write. Unmitigated, the controller spends
|
||||
around 90% of uptime suspended and cycles constantly rather than settling — roughly 30 seconds of
|
||||
active time accrues in the first 8 minutes, so the race window is being re-entered continuously:
|
||||
|
||||
```sh
|
||||
udevadm test --action=add /sys/bus/pci/devices/0000:00:1f.3 2>&1 | grep power/control
|
||||
awk '{printf "suspended %d%%\n", 100*$1/($1+$2)}' \
|
||||
<(paste /sys/bus/pci/devices/0000:00:1f.3/power/runtime_{suspended,active}_time)
|
||||
```
|
||||
|
||||
### 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`
|
||||
is set and no pstore backend is registered, so `/sys/fs/pstore` and `/var/lib/systemd/pstore` are
|
||||
both empty after a hang.
|
||||
|
||||
A crashed boot ends mid-heartbeat with no shutdown sequence. Compare the last line of each boot: a
|
||||
clean shutdown ends in `Unmounted /efi` or `Stopping Flush Journal to Persistent Storage`, while a
|
||||
panic ends on whatever was logging periodically — usually `kdeconnectd`, exactly on its 30-second
|
||||
cadence, with the next tick missing:
|
||||
|
||||
```sh
|
||||
for b in $(journalctl --list-boots -q | awk '{print $1}'); do
|
||||
printf "%4s %s\n" "$b" "$(journalctl -b "$b" -o short-iso -q | tail -1)"
|
||||
done
|
||||
```
|
||||
|
||||
The machine is always idle when it dies, not under load, and the journal is silent on the kernel side
|
||||
for the entire session — `journalctl -b -1 -k -p 4` shows only the usual boot-time noise.
|
||||
|
||||
.box {This is a mitigation, not a fix} type:{warning}
|
||||
The driver defect is still present. The rule only stops it from being triggered.
|
||||
The driver defect is still present. Disabling runtime PM only stops it from being triggered.
|
||||
|
||||
If the freezes return, bypass SoundWire entirely by forcing the legacy HDA driver in
|
||||
`/etc/modprobe.d/`:
|
||||
@@ -106,6 +150,12 @@ udevadm test --action=add /sys/bus/pci/devices/0000:00:1f.3 2>&1 | grep power/co
|
||||
The hardware is fine too: no machine check exceptions, no ECC or EDAC errors, and `fwupdmgr`
|
||||
reports all firmware current.
|
||||
|
||||
The battery charge-controller fault is a separate problem and not the cause of these hangs. It
|
||||
presents the same way from the outside — the machine dies with no clean shutdown and nothing in
|
||||
the journal — so check it off explicitly. In a SoundWire panic the battery is untouched
|
||||
(`charge_now == charge_full` on the next boot) and `battery-charge-watchdog` logs only its
|
||||
startup line, never a `FAULT`.
|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user