電源管理/喚醒觸發器

出自 Arch Linux 中文维基

喚醒觸發器是可以將系統從任何硬體節能狀態喚醒的事件源。顯而易見的例子是電源或掛起按鈕、網絡喚醒英語Wake-on-LAN功能或筆記本電腦系統中的蓋開關。喚醒觸發器可以通過下面列出的各種內核接口進行控制。沒有涵蓋所有可能的觸發器的統一接口。

喚醒觸發器接口[編輯 | 編輯原始碼]

/proc/acpi/wakeup[編輯 | 編輯原始碼]

讀取 /proc/acpi/wakeup 文件將生成 ACPI 註冊的喚醒源列表,其中包含相應的 sysfs IDs(如果可用)。將條目從設備列寫入文件可切換其狀態。例如,要禁用打開筆記本電腦蓋時的喚醒功能,請運行:

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

/sys/module/acpi/parameters/ec_no_wakeup[編輯 | 編輯原始碼]

該文件表示 ACPI 內核模塊選項 ec_no_wakeup 的值,當系統處於掛起到空閒(s2idle電源狀態時,該選項控制從嵌入式控制器傳遞喚醒觸發器[1]。在現代筆記本電腦上,嵌入式控制器喚醒在某些英語Lenovo ThinkPad Helix 2nd Gen#Disable embedded-controller wake-ups情況下會導致電池過度消耗。

/sys/devices/[編輯 | 編輯原始碼]

每個支持喚醒的 sysfs 設備都在設備的 power 子目錄中包含文件 wakeup。該文件包含喚醒觸發器的狀態,也可以寫入。總線控制器和端點設備能夠喚醒系統。例如,若要禁用第一個 USB 控制器(總線)的喚醒,請運行:

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

如果啟用了觸發器,端點設備應該能夠喚醒設備,而不管控制器的設置如何,但這可能與依賴於硬體。

編寫 PowerTOPsysfs 的接口,但它只通過讀取 /sys/class/net//sys/bus/usb/devices/(包括到 /sys/devices/ 的符號連結)來列出網絡和 USB 設備的喚醒觸發器。

/sys/class/wakeup/*[編輯 | 編輯原始碼]

幾乎所有的喚醒觸發器都可以在 /sys/class/wakeup 目錄中找到,該目錄包含指向所有相關設備的符號連結。這對於通過子目錄查找可能的喚醒觸發器非常有用。一些觸發器可以對應於虛擬設備,而與硬體相關的喚醒觸發器至少包含以下文件之一:

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

/sys/class/wakeup 中的一些喚醒觸發器還提供了一個以下文件指向所在位置隱藏的 /proc/acpi/wakeup 名稱的連結:

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

持久設置[編輯 | 編輯原始碼]

原先的 方法應該足以設置 /proc/acpi/wakeup 狀態和 acpi.ec_no_wakeups 內核參數,而 udev事件驅動 途徑是配置 sysfs 設備的可靠方式。

使用 systemd 的原先方法[編輯 | 編輯原始碼]

ec_no_wakeups ACPI 內核模塊選項可以在啟動時設置,如本文所述。在引導時設置 sysfs 值的標準解決方案是 systemd services,例如在故障排除中。/proc/acpi/wakeup 的另一個基於 systemd 的管理器是 wakeup-triggersAUR

一些系統可以在電源狀態轉換時覆蓋一些 ACPI 喚醒觸發器,這更像是一個 bug,而不是一個功能。如果硬體能在可預測的時間覆蓋觸發器,則仍然可以使用適當構建的 systemd units 來解決。sleep.target 是一個通用目標,涵蓋所有不同的掛起狀態,在這種情況下可能會有所幫助,但沒有通用的 wakeup.target [2]

此方法僅適用於始終連接的 sysfs 設備。

使用 udev 的事件驅動[編輯 | 編輯原始碼]

使用 udev 規則設置喚醒觸發器狀態是一種事件驅動的方法,在連接具有喚醒觸發器的設備時都能可靠地工作。關鍵是檢測規則中是否添加了新設備( ACTION=="add"),並將喚醒觸發器狀態設置為 ATTR{power/wakeup}="disabled"。如果硬體正在重置此設置,udev 可以嘗試在每次設備更改時重新應用規則來規避此設置(ACTION=="add|change")。通過 udevadm info -q all -a /sys/devices/... 可以獲得一個設備樹,其中包含用於匹配 sysfs 中找到的特定設備的可能參數。

這裡一個典型的常見例子是羅技統一 USB 接收器。它的喚醒觸發器應該在默認情況下啟用,如果不需要,解決方案可以是 udev 規則,如下所示:

/etc/udev/rules.d/logitech-unifying.rules
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c52b", ATTR{power/wakeup}="disabled"

udev 文章中描述了啟用必要觸發器的相反情況。

udev 觸發器在設備枚舉中出現得太早,以至於使用上述方法禁用喚醒觸發器會導致(某些?)禁用的觸發器不在 /sys/class/wakeup 中列出。這可能取決於設備在啟動時是否已經存在,需要進一步闡明。

疑難解答[編輯 | 編輯原始碼]

列出設備和/或總線樹[編輯 | 編輯原始碼]

當試圖理解某個系統的所有喚醒觸發器時,這些輔助命令會很有用,有助於編寫 udev 規則或進行常見的喚醒源故障排除:

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

掛起後被立即喚醒[編輯 | 編輯原始碼]

對於某些帶有 LynxPoint 或 LynxPoint-LP 晶片組的 Intel Haswell 系統,有報告稱它們會在掛起後就立即被喚醒。這與錯誤的 BIOS ACPI 實現,以及 xhci_hcd 如何在引導期間如何解釋它們都有關。作為一項解決方案,內核會將報告的受影響系統逐個添加到拒絕列表(名為 XHCI_SPURIOUS_WAKEUP[3]

電腦也有可能在其它情況下發生立即恢復,比如,一個 USB 設備在掛起後插入,且啟動了 ACPI 喚醒觸發器。對於這樣的情況,如果受影響的系統尚未被加入上述拒絕列表,一個可行的方案是禁用相關的喚醒觸發器。通過 USB 禁用喚醒的例子見後[4]

要查看當前配置:

$ 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
...

可以看到相關的設備有 EHC1EHC2XHC(USB 3.0設備)。要切換它們的狀態,你需要以 root 權限把設備名寫入到文件裡。

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

這能使掛起重新工作。但是,此設置只是臨時的,需要在每次啟動時設置。要實現自動化,請參閱 Systemd#臨時文件論壇帖子以了解可能的解決方案。

nouveau 驅動程序[編輯 | 編輯原始碼]

如果使用了 nouveau 驅動程序,則立即喚醒的原因可能是驅動程序中的錯誤,這有時會阻止 GPU 掛起。一種可能的解決方法是在休眠前卸載 nouveau 內核模塊,並在喚醒後重新加載。為此,請創建以下腳本:

/usr/lib/systemd/system-sleep/10-nouveau.sh
#!/bin/bash

case $1/$2 in
  pre/*)
    # echo "進入 $2 狀態..."
    /usr/bin/echo "0" > /sys/class/vtconsole/vtcon1/bind
    /usr/bin/rmmod nouveau
    ;;
  post/*)
    # echo "從 $2 狀態喚醒..."
    /usr/bin/modprobe nouveau
    /usr/bin/echo "1" > /sys/class/vtconsole/vtcon1/bind
    ;;
esac

第一個 echo 行將 nouveaufb 從幀緩衝控制台驅動程序(fbcon)中解除綁定。通常它是 vtcon1,如本例所示,但也可能是另一個 vtcon*。查看 /sys/class/vtconsole/vtcon*/name 其中哪一個是 frame buffer device [5]