Skip to content

Wake-on-WLAN works -- a magic packet wakes taimen from s2idle, and the association survives suspend

scope: device:google-taimen · severity: finding · confidence: proven · subsystem: wifi

It works. Two controls and one test, same kernel, same alarm, same suspend path, interleaved with the wakealarm cleared each time:

control no packet slept 101 s of 100 s wakeirq 116 pm8xxx_rtc_alarm
control no packet slept 101 s of 100 s wakeirq 116 pm8xxx_rtc_alarm
test magic pkt slept 44 s of 100 s wakeirq 132 WLAN_CE_2

The return is stamped in the same second the host sent the packet, and the waking IRQ is the one ath10k_snoc_hif_suspend() arms with enable_irq_wake(). That also settles the older question of whether the link survives: the AP delivered a frame to this station while it was asleep and the BSSID is unchanged afterwards, with no reassociation.

Two things that make this look broken when it is not.

  1. The host’s ARP entry for the phone goes FAILED while it sleeps. A unicast magic packet then never leaves the host at all. Send to the subnet broadcast (192.168.1.255), which goes to ff:ff:ff:ff:ff:ff and is delivered after the DTIM, or prime the neighbour entry first.
  2. ph-suspend-cycle.sh used to write +N to wakealarm without clearing a pending one. The RTC rejects that write, the shell swallows it, and the previous run’s alarm fires instead – so the cycle ends early at someone else’s deadline with wakeirq=<rtc> and reads as a clean timed wake. It cost one arm here before it was fixed; a +120 arm returned after 44 s, exactly on the prior cycle’s +120.

Do not add a “wake on any packet” trigger. magic-packet disconnect is what the shipped hook arms and what these numbers are for. The vendor’s own default is equivalent (gEnableWoW=3).