Chasing Down a Stubborn Airplane Mode Bug on My HP Envy

I run Ubuntu 24.04 on an older HP Envy 17, and for months I’ve tiptoed around a maddening bug: every time the laptop went to sleep, it would wake up straight into airplane mode. The Wi-Fi hardware light glowed orange, NetworkManager insisted the radio was off, and the only way out was a full reboot. I finally set aside an evening to attack the problem, notebook in hand, determined to turn it into a postmortem instead of another rage-reboot.

First order of business was to prove the failure. I built a little diagnostic script that scooped up rfkillnmclidmesg, and journal entries right after waking from suspend. The very first log told the story: the Intel 7260 Wi-Fi adapter came back “hard blocked.” In other words, the embedded controller itself was asserting the hardware kill switch. That meant user-space toggles were doomed from the start.

Since systemd loves to restore previous radio states, I masked systemd-rfkill.service and its socket. A reboot, suspend, and another diagnostic run later, the hard block was still there. So much for an easy win. The logs did, however, show the HP WMI hotkey driver participating in the resume sequence, so I tried blacklisting it next. No dice; the EC simply reasserted the kill line on its own.

With the firmware still in charge, I tried to wrestle control back in software. I dropped a systemd sleep hook that unbound and rebound the iwlwifi driver after every resume, sprinkled in rfkill unblock all, and told NetworkManager to wake up. The hook dutifully ran—my logs suddenly showed the device jumping from phy0 to phy1—but the EC flipped the RF_KILL bit again the instant the driver came back. Close, but not enough.

I even crawled through the InsydeH2O BIOS setup, hoping for a hidden “Wireless Button State” toggle. Nothing. That sent me back to the kernel docs, where I found a clue: this HP implements classic S3 suspend (deep), which hands control fully over to the embedded controller. If the EC is buggy, switching to the lighter-weight s2idle state can keep it from meddling with the radio.

I manually nudged /sys/power/mem_sleep to s2idle, closed the lid, and held my breath. When the machine woke up, Wi-Fi stayed alive. No hard block, no orange LED, no angry logs. That was the breakthrough. All that was left was to make it permanent by adding mem_sleep_default=s2idle to /etc/default/grub and regenerating GRUB.

Looking back, the path was messy but methodical: gather evidence, eliminate the usual suspects (systemd-rfkill, HP WMI), experiment with manual driver resets, and finally change the suspend strategy. For anyone else fighting resume-induced airplane mode on HP hardware, switching to s2idle might be the cleanest fix. At the very least, you’ll have a script full of juicy logs to show for the effort.

The diagnostic script:

#!/bin/bash
# Collect diagnostic data when Wi-Fi stays disabled after resume.

set -o pipefail
set -o nounset

if [[ "$EUID" -ne 0 ]]; then
  echo "Please run this script with sudo." >&2
  exit 1
fi

out_path="${1:-/home/dfish/suspend_airplane_diag_$(date +%Y%m%d_%H%M%S).log}"
mkdir -p "$(dirname "$out_path")"

{
  echo "==== Suspend/Radio Diagnostic Report ===="
  echo "Timestamp: $(date --iso-8601=seconds)"
  echo "Hostname: $(hostname)"
  echo "Kernel: $(uname -r)"
  echo "---- rfkill ----"
  rfkill list || echo "rfkill list failed"

  echo "---- nmcli radio ----"
  if command -v nmcli >/dev/null 2>&1; then
    nmcli radio all || echo "nmcli radio all failed"
    nmcli device status || echo "nmcli device status failed"
  else
    echo "nmcli not installed"
  fi

  echo "---- Network Interfaces ----"
  ip link show
  echo
  ip addr show

  echo "---- Wireless Tools ----"
  if command -v iwconfig >/dev/null 2>&1; then
    iwconfig 2>/dev/null || true
  else
    echo "iwconfig not installed"
  fi
  if command -v iw >/dev/null 2>&1; then
    iw dev || true
  else
    echo "iw not installed"
  fi

  echo "---- systemd rfkill ----"
  systemctl status systemd-rfkill.service --no-pager || true
  systemctl status systemd-rfkill.socket --no-pager || true

  echo "---- Recent journal (last 5 minutes) ----"
  journalctl -b --since "5 minutes ago" --no-pager || true

  echo "---- Recent rfkill/hp_wmi logs (current boot) ----"
  journalctl -b --no-pager | grep -Ei 'rfkill|hp_wmi|wlan|iwl|ath|suspend|resume' || true

  echo "---- Recent dmesg (last 200 lines) ----"
  dmesg | tail -n 200 || true

  echo "---- Loaded wireless modules ----"
  lsmod | grep -E 'iwl|ath|rtl|brcm|hp_wmi' || true

  echo "---- PCI wireless devices ----"
  lspci -nn | grep -Ei 'network|wireless' || true

  echo "---- USB wireless devices ----"
  lsusb | grep -Ei 'network|wireless' || true

  echo "==== End of Report ===="
} > "$out_path"

echo "Diagnostic data saved to $out_path"

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *