Fixing Sleep and Hibernation Issues with ath11k_pci Wi-Fi Driver

Certain laptop Wi-Fi cards made by Qualcomm are plagued by a rather unfortunate issue when using Linux: After the laptop resumes from sleep or hibernation, the Wi-Fi card is unusable. This occurs because the ath11k_pci driver cannot handle system suspend. Fortunately a workaround exists.

The solution is to unload the driver before the system suspends and reload it after it resumes. To do so, you can create a systemd unit for each of these two events. Systemd units are configured in /etc/systemd/system. First make sure the driver gets unloaded before any suspend event:

[Unit]
Description=Suspend: rmmod ath11k_pci
Before=sleep.target

[Service]
Type=simple
ExecStart=/usr/bin/sh -c 'if (lsmod | grep -wq ath11k_pci); then \
	logger -p user.info "Unloading ath11k_pci kernel module before suspend."; \
	rmmod ath11k_pci; fi'

[Install]
WantedBy=sleep.target

Then create a second unit to reload the driver after the system resumes from sleep or hibernation:

[Unit]
Description=Resume: modprobe ath11k_pci
After=suspend.target suspend-then-hibernate.target hibernate.target hybrid-sleep.target

[Service]
Type=simple
ExecStart=/usr/bin/sh -c 'if ! (lsmod | grep -wq ath11k_pci); then \
	logger -p user.info "Loading ath11k_pci kernel module after suspend."; \
	modprobe ath11k_pci; fi'

[Install]
WantedBy=suspend.target suspend-then-hibernate.target hibernate.target hybrid-sleep.target
Note

You cannot use sleep.target in the resume unit, since this target finishes before the system actually goes to sleep.

Finally, run systemctl enable for the two units. Now you should be able to sleep and hibernate without the Wi-Fi card breaking.

Tip

If you’re using NetworkManager, you might need to restart it after the driver is reloaded. For example:

ExecStart=/usr/bin/sh -c 'if ! (lsmod | grep -wq ath11k_pci); then \
	logger -p user.info "Loading ath11k_pci kernel module after suspend."; \
	modprobe ath11k_pci; \
	sleep 3; \
	systemctl restart NetworkManager.service; fi'

Stable Network Interface Name

Usually, the Wi-Fi network interface is named wlan0. However, when the driver is reloaded, the Wi-Fi card gets detected as a new device, and the network interface name will have a different number at the end. If you want the name to stay the same, you can create a udev rule that forces a specific interface name.

You’ll need to find the MAC address of your Wi-Fi card (using ip a for example). Then, create a new udev rule in /etc/udev/rules.d (make sure the file name ends with .rules):

SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="de:ad:be:ef:01:23", NAME="wlan0"