Power management/Wakeup triggers - ArchWiki

Jump to content

# Power management/Wakeup triggers

From ArchWiki
< Power management

Related articles

- Wake-on-LAN
- Laptop

Wakeup triggers are event sources that can wake the system from any of the hardware power-saving states. The obvious example is the power or suspend button, the Wake-on-LAN functionality or the lid switch in laptop systems. Wakeup triggers can be controlled through various kernel interfaces listed below. There is no unified interface covering all possible triggers.

## Wakeup trigger interfaces

### /proc/acpi/wakeup

Reading the `/proc/acpi/wakeup` file yields list of ACPI-registered wakeup sources with corresponding `sysfs` IDs where available. Writing an entry from the Device column to the file toggles its state. For example, to disable waking on opening the laptop lid, run:

    # echo "LID" > /proc/acpi/wakeup

### /sys/module/acpi/parameters/ec_no_wakeup

This file represents the value of ACPI kernel module option `ec_no_wakeup`, which controls passing the wakeup triggers from embedded controller when the system is in the suspend-to-idle (`s2idle`) power state [1]. On modern laptops embedded controller wakeups can cause excessive battery drain in some cases.

### /sys/devices/

Each `sysfs` device that supports wakeup contains the file `wakeup` in a device's `power` subdirectory. The file contains wakeup trigger's status and can be written to as well. Bus controllers as well as endpoint devices can be capable of waking up the system. For example, to disable wakeups from the first USB controller (bus), run:

    # echo "disabled" > /sys/bus/usb/devices/usb1/power/wakeup

An endpoint device should be able to wake the device if the trigger is enabled regardless of the controller's setting, however this might be hardware-dependent.

Program PowerTOP interfaces with `sysfs`, but it only lists wakeup triggers of networking and USB devices by reading `/sys/class/net/` and `/sys/bus/usb/devices/` (containing symlinks to `/sys/devices/`).

### /sys/class/wakeup/*

Almost all wakeup triggers can be found in the `/sys/class/wakeup` directory, which contains symlinks to all relevant devices. This is useful for finding possible wakeup triggers by going through subdirectories. Some of the triggers can correspond to virtual devices while hardware-related wakeup triggers are the ones that contain at least one of these files:

    /sys/class/wakeup/*/device/physical_node/power/wakeup
    /sys/class/wakeup/*/device/power/wakeup

Some of wakeup triggers in `/sys/class/wakeup` also provide a link to the cryptic `/proc/acpi/wakeup` names where the following file is present:

    /sys/class/wakeup/*/device/path

## Persistent settings

The one-time methods should suffice for setting the `/proc/acpi/wakeup` states and `acpi.ec_no_wakeup` kernel parameter while the event-driven approach with udev is the reliable way to configure the `sysfs` devices.

### One-time with systemd

The `ec_no_wakeup` ACPI kernel module option can be set at boot as described in the article. The standard solution to set the `sysfs` values at boot are systemd services such as in this troubleshooting case. Another systemd-based manager for `/proc/acpi/wakeup` is wakeup-triggersAUR.

Some systems can override some of the ACPI wakeup triggers upon power state transition(s) in what is more of a bug rather than a feature. If the hardware is overriding triggers at predictable times that can still be solved with appropriately crafted systemd units. The `sleep.target` is a generic target covering all different suspended states that might be helpful in this case, but there is no generic `wakeup.target` [2].

This method only works reliably with `sysfs` devices that are connected all the time.

### Event-driven with udev

Setting the wakeup trigger status with udev rules is an event-driven method that works reliably any time the devices with wakeup triggers are connected. The key is to detect an addition of a new device (`ACTION=="add"`) in a rule and set the wakeup trigger status with `ATTR{power/wakeup}="disabled"`. If the hardware is resetting this setting, udev can try to circumvent it by reapplying rules upon every device change (`ACTION=="add|change"`). A device tree with possible parameters for matching a particular device found in `sysfs` can be obtained with `udevadm info -q all -a /sys/devices/...`.

A representative common example here would be a Logitech Unifying USB receiver. Its wakeup trigger should be enabled by default and if that is not desired, a solution could be a udev rule, as follows:

    /etc/udev/rules.d/logitech-unifying.rules

    ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c52b", ATTR{power/wakeup}="disabled"

The reverse case to enable the necessary trigger(s) is described in the udev article.

udev triggers so early in the device enumeration that disabling wakeup trigger with the method above causes (some?) disabled triggers to not be listed in `/sys/class/wakeup`. That might be dependent on whether the device was already present at boot and needs further clarification.

## Troubleshooting

### List device and/or bus trees

These auxiliary commands can be helpful when trying to understand all wakeup triggers of a certain system, to aid with udev rule writing or general wakeup source troubleshooting:

    # lshw -businfo -numeric
    # lspci -DPPnn
    # lsusb -tvv

### Last wakeup trigger source

The information on which wakeup source was the reason for the last device wakeup is unfortunately platform-specific. On x86 machines dmidecode can be used:

    # dmidecode -t system | grep -P '\tWake-up Type\: '

However for some computers it always reports "Power Switch" regardless of the real cause, e.g. for any of the USB keyboard, laptop keyboard, the power switch and the mouse.

In some cases, the wakeup count information can also be useful to find the last wakeup trigger source:

    # grep -F "" /sys/class/wakeup/*/device/power/wakeup_count

One can then compare the result after a wakeup with the values from before to find the reason for the wakeup.

### Instantaneous wakeup after suspending

#### Intel Haswell with LynxPoint(-LP)

For some Intel Haswell systems with the LynxPoint and LynxPoint-LP chipset, instantaneous wakeups after suspending are reported. They are linked to erroneous BIOS ACPI implementations and how the `xhci_hcd` module interprets it during boot. As a work-around reported affected systems are added to a denylist (named `XHCI_SPURIOUS_WAKEUP`) by the kernel case-by-case [3].

Wakeup may happen, for example, if a USB device is plugged during suspending and ACPI wakeup triggers are enabled. A viable workaround for such a system is to disable the relevant wakeup triggers. An example to disable wakeup through USB is described as follows [4].

To view the current configuration:

    $ cat /proc/acpi/wakeup

    Device  S-state   Status   Sysfs node
    ...
    EHC1      S3    *enabled  pci:0000:00:1d.0
    EHC2      S3    *enabled  pci:0000:00:1a.0
    XHC       S3    *enabled  pci:0000:00:14.0
    ...

The relevant devices are `EHC1`, `EHC2` and `XHC` (for USB 3.0). To toggle their state you have to echo the device name to the file as root:

    # echo EHC1 > /proc/acpi/wakeup
    # echo EHC2 > /proc/acpi/wakeup
    # echo XHC > /proc/acpi/wakeup

This should result in suspension working again. However, this settings are only temporary and need to be set at every boot. To automate this, see systemd-tmpfiles or BBS thread for possible solutions.

#### Gigabyte motherboards

##### GPP bridge

On some Gigabyte motherboards, the GPP bridge to the NVMe drive may cause premature wakeups from suspend.

Known boards affected:

- B550i AORUS,
- B550 AORUS ELITE V2,
- B550 AORUS ELITE AX V2 (Rev. 1.5),
- B550M DS3H
- B550M AORUS PRO-P
- A520M K V2

Setting the status of `GPP0` to disabled may fix the issue:

    # echo GPP0 > /proc/acpi/wakeup

This setting is only temporary. Disabling it for all PCIe devices can be made permanent using a udev rule:

    /etc/udev/rules.d/90-gigabyte.rules

    ACTION=="add", SUBSYSTEM=="pci", DRIVER=="pcieport", ATTR{power/wakeup}="disabled"

It's also possible to target the specific device:

    /etc/udev/rules.d/90-gigabyte.rules

    ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:00:01.1", ATTR{power/wakeup}="disabled"

The value for `KERNEL` is the `Sysfs node` column, without the `pci:` prefix, from `/proc/acpi/wakeup`.

##### ACPI _OSI string

For some Gigabyte motherboards, disabling everything in `/proc/acpi/wakeup` including `GPP0` does not prevent an instantaneous wakeup from suspension. If this is the case, your motherboard may have issues with ACPI in Linux.

Known boards affected:

- B850M AORUS ELITE WIFI6E ICE
- B850 GAMING X WIFI6E
- B650 GAMING X AX V2
- B650 AORUS ELITE AX (Rev. 1.0)
- B650 EAGLE AX
- B650i AORUS ULTRA (Rev. 1.0)
- X670E AORUS PRO X
- X670 GAMING X AX V2
- X870E AORUS ELITE WIFI7
- X870 EAGLE WIFI7
- MSI PRO X870E-P WIFI

Apply the following to your kernel parameters:

    acpi_osi="!Windows 2015"

Note

- You may also try other strings that your DSDT provides. See DSDT#Tell the kernel to report a version of Windows for examples.
- Depending on your setup, you may or may not need to disable wakeup triggers. See #Wakeup trigger interfaces.

#### ASRock AM5 motherboards

Certain ASRock motherboards for the AM5 platform may instantly wake from sleep also. This is due to the USB xHCI controller.

This can be fixed by disabling wakeup on this device, in line with the Gigabyte instructions above:

    # echo XH00 > /proc/acpi/wakeup

This behaviour has been noticed on the B850M Pro-A WiFi, the B850M Pro RS model (and will presumably also extend to the very similar B850M Pro RS WiFi.)

#### MSI AM5 motherboards

Certain MSI motherboards for the AM5 platform may also be affected by the premature wakeups from suspend because of the GPP bridge to the NVME drive.

This can be fixed by disabling wakeup on this device, in line with the Gigabyte instructions above:

    # echo GPP1 > /proc/acpi/wakeup

This behaviour has been noticed on the X870 Tomahawk model.

#### Ryzen 7000 Series

For some newer AMD Ryzen 7000 Series systems, instantaneous wakeups after suspending, or wake up from s2idle when plugging in the AC adapter or by closing the lid, may occur. It is due to the redundant IRQ interrupt from the GPIO controller in `AMDI0030:00`. [5][6]

The current workaround is to configure the kernel to ignore the interrupt from the problematic GPIO pins. Add the following to your kernel parameters:

    gpiolib_acpi.ignore_interrupt=AMDI0030:00@2,AMDI0030:00@3,...

Multiple GPIO pins can be appended to the ignore list in the format of `AMDI0030:00@N`. However, the corresponding GPIO pins that cause the system to wake up is depended to the device model. You may find the pin number from the `dmesg` log after enabling debug messages from the system suspend/hibernation infrastructure:

    # echo 1 > /sys/power/pm_debug_messages

Perform a suspend/resume cycle, you may find the following lines in `dmesg` log.

    kernel: GPIO 3 is active: 0x30047ce0

Usually GPIO 2, 3 and 4 would be the one response to this issue. Then, you may mount the `debugfs` to `/sys/kernel/debug` to trace the state of the GPIOs.

Look for the lines in `/sys/kernel/debug/gpio` with data in `S0i3` and `S3` columns.

    gpio      int|active|trigger|S0i3| S3|S4/S5| Z|wake|pull|  orient|       debounce|reg
    #3         😛|     ↑|   edge|  ⏰| ⏰|     |  |    |    |input  ↑|               |0x54800

Ignore the corresponding GPIO pins in `gpiolib_acpi.ignore_interrupt`, regenerate the initramfs image, and reboot.

#### NVIDIA drivers

Installing NVIDIA proprietary drivers might render suspension and hibernation not possible. In that case the system log might include:

    kernel: NVRM: GPU 0000:01:00.0: PreserveVideoMemoryAllocations module parameter is set. System Power Management attempted without driver procfs suspend interface. Please refer to the 'Configuring Power Management Support' section in the driver README.
    kernel: PM: pci_pm_suspend(): nv_pmops_suspend+0x0/0x20 [nvidia] returns -5
    kernel: PM: dpm_run_callback(): pci_pm_suspend+0x0/0x160 returns -5
    kernel: nvidia 0000:01:00.0: PM: failed to suspend async: error -5

See NVIDIA/Tips and tricks#Preserve video memory after suspend.

#### nouveau driver

If the nouveau driver is used, the reason for instantaneous wakeups may be a bug in the driver, which sometimes prevents GPU from suspending. A possible workaround is unloading the `nouveau` kernel module right before going to sleep and loading it back after wakeup. To do this, create the following script:

    /usr/lib/systemd/system-sleep/10-nouveau.sh

    #!/bin/bash

    case $1/$2 in
      pre/*)
        # echo "Going to $2..."
        /usr/bin/echo "0" > /sys/class/vtconsole/vtcon1/bind
        /usr/bin/rmmod nouveau
        ;;
      post/*)
        # echo "Waking up from $2..."
        /usr/bin/modprobe nouveau
        /usr/bin/echo "1" > /sys/class/vtconsole/vtcon1/bind
        ;;
    esac

The first echo line unbinds `nouveaufb` from the framebuffer console driver (`fbcon`). Usually it is `vtcon1` as in this example, but it may also be another `vtcon*`. See `/sys/class/vtconsole/vtcon*/name` which one of them is a frame buffer device [7].

#### Logi Bolt receiver

The Logitech Bolt receiver is a dongle with a yellow hexagon that has a lightning bolt shape cut out of it. It can cause immediate wakeup after suspending. See Logitech Unifying Receiver#PC wakes immediately from sleep.

#### intel_hid kernel module

As is described in [8] and [9], the kernel module `intel_hid` prevents suspend to disk and causes wakeup immediately on some Dell laptops. Simple workaround is blacklisting `intel_hid` or unload this module before suspending to disk.

Categories:

- Power management
- Laptops

Power management/Wakeup triggers
Add topic