電源管理/喚醒觸發器
喚醒觸發器是可以將系統從任何硬件節能狀態喚醒的事件源。顯而易見的例子是電源或掛起按鈕、網絡喚醒功能或筆記本電腦系統中的蓋開關。喚醒觸發器可以通過下面列出的各種內核接口進行控制。沒有涵蓋所有可能的觸發器的統一接口。
喚醒觸發器接口[編輯 | 編輯原始碼]
/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]。在現代筆記本電腦上,嵌入式控制器喚醒在某些情況下會導致電池過度消耗。
/sys/devices/[編輯 | 編輯原始碼]
每個支持喚醒的 sysfs
設備都在設備的 power
子目錄中包含文件 wakeup
。該文件包含喚醒觸發器的狀態,也可以寫入。總線控制器和端點設備能夠喚醒系統。例如,若要禁用第一個 USB 控制器(總線)的喚醒,請運行:
# echo "disabled" > /sys/bus/usb/devices/usb1/power/wakeup
如果啟用了觸發器,端點設備應該能夠喚醒設備,而不管控制器的設置如何,但這可能與依賴於硬件。
編寫 PowerTOP 與 sysfs
的接口,但它只通過讀取 /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 ...
可以看到相關的設備有 EHC1
、EHC2
和 XHC
(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]。