Wifi card vanishing from the PCIe bus? Stop rebooting, make it self-heal

On a Toshiba CB35-3340 (Bay Trail Chromebook running MX Linux / Debian 13 on MrChromebox firmware), the internal Intel Wireless 7260 disappears every few hours. The SSID list goes empty, every scan fails with -EIO, and toggling wifi does nothing. Only a reboot brought it back.

The giveaway is in the kernel log:

iwlwifi 0000:01:00.0: iwlwifi device memory mapped registers:
iwlwifi 0000:01:00.0: 00000000: ffffffff ffffffff ffffffff ffffffff
WARNING: ... __iwl_trans_pcie_grab_nic_access+0x14c/0x150 [iwlwifi]
iwlwifi 0000:01:00.0: Error sending STATISTICS_CMD: enqueue_hcmd failed: -5

MMIO reads returning all-ones means the device is off the bus, not merely confused. That is why modprobe -r iwlwifi && modprobe iwlwifi fails with Could not load the [0] uCode section — there is nothing there to load firmware into.

Two things fix the recovery path. First, let the driver admit the device is gone:

# /etc/modprobe.d/iwlwifi-stability.conf
options iwlwifi remove_when_gone=1

Then a bare bus rescan re-enumerates it completely — firmware reloads, iwlwifi rebinds, the netdev comes back:

echo 1 | sudo tee /sys/bus/pci/rescan

No module reload, no reboot. Put it in a watchdog and the outage becomes invisible; mine recovered a real failure in 8 seconds:

#!/bin/bash
DEV=0000:01:00.0
while :; do
    if [ ! -e "/sys/bus/pci/devices/$DEV" ]; then
        echo 1 > /sys/bus/pci/rescan
        sleep 8
    fi
    sleep 20
done

Two traps will make that rescan backfire. If broadcom-sta is installed, its wl module has a wildcarded PCI match and can win the probe race after a rescan, binding itself to your Intel card — and unbinding it then wedges uninterruptibly in the kernel, so only a reboot clears it. If the machine has no Broadcom wireless, blacklist wl and move on.

The other trap is NetworkManager. A profile carrying connection.interface-name=wlan0 silently refuses to activate when the card returns as wlan1, which is exactly what happens if anything else claimed wlan0 in the meantime. You get a working card with no network. Bind profiles to the card instead of the name:

sudo nmcli con mod <uuid> connection.interface-name "" \
     802-11-wireless.mac-address a4:c4:94:a3:1a:5b

Finally, the thing not to bother with: disabling ASPM. It is the obvious suspect, and on this box it is worse than the disease. pcie_aspm.policy=performance on the kernel command line was completely inert — coreboot's _OSC never grants the OS ASPM control, so the kernel ignores the policy and lspci -vv still shows LnkCtl: ASPM L1 Enabled. Disabling it per-device does work:

echo 0 | sudo tee /sys/bus/pci/devices/0000:01:00.0/link/l1_aspm

...and the card then died at 2h12m instead of 5h, with correctable PCIe errors jumping from 0.6/min to 60/min. Note you can disable ASPM at runtime but not re-enable it, for the same _OSC reason — reverting needs a reboot.

One debugging aside that cost me an hour: if the RTC backup battery is dead, journalctl wall-clock timestamps lie. The clock comes up wrong and chrony steps it seconds into boot (System clock was stepped by 22559603.802825 seconds), so a single 5.8-day boot appeared to span nine months and journalctl -b -1 returned different counts for the same boot. Use journalctl -o short-monotonic and trust uptime, not dates.

Comments

  1. Markdown is allowed. HTML tags allowed: <strong>, <em>, <blockquote>, <code>, <pre>, <a>.