- 概述 當談到Linux系統的掛起/休眠時, 我們指的是以下三種受支持的Linux系統休眠狀態:
- STI(Suspend To Idle)是一種通用的、純軟件、輕量級系統睡眠狀態。與特定於平臺的驅動程序增強一起,可以使用這種狀態來達到Intel®平臺上的S0i3狀態。要進入這種狀態,運行shell命令:
echo freeze
>/sys/power/state
- STR(Suspend To RAM)提供了顯著的功耗節省,因爲系統中除了內存之外的所有東西都進入了低功耗狀態。應將內存置於自刷新模式以保留其內容。ACPI平臺掛起到RAM後在S3中。要進入這種狀態,運行shell命令:
echo mem
>/sys/power/state
- 休眠(Hibernate To Disk)的操作類似於掛起內存,但是包括最後一個步驟,即把內存內容寫到磁盤。在恢復時,將讀取此值並將內存恢復到presuspend狀態。通常,ACPI平臺掛載到磁盤後處於S4狀態。要進入這種狀態,運行shell命令:
echo disk
>/sys/power/state
有關每個系統低功耗狀態的詳細信息,請參考系統電源管理休眠狀態。
關於Linux 掛起/休眠的sysfs接口的更多細節,如上面提到的/sys/power/state
,請參考https://www.kernel.org/doc/Documentation/power/interface.txt。
英特爾開源技術中心(OTC)中國內核電源團隊多年來一直致力於Linux電源管理子系統的質量改進工作。我們處理問題的經驗,無論是通過電子郵件在Linux郵件列表或通過https://bugzilla.kernel.org/
顯示如下:
- 低效率。這是因爲在大多數情況下,開發人員無法在本地重現問題。因此,我們依賴於用戶提供問題症狀的詳細描述、必要的調試信息以及一些測試結果(如果需要的話)。由於時區不同,爲進一步調試做好準備可能需要幾天甚至幾周的時間。
- 額外的工作。這是因爲Linux STI/STR/HTD是系統級低功耗狀態,需要硬件、固件、Linux PM內核和許多其他內核組件(尤其是設備驅動程序)才能很好地協同工作。這意味着任何單個組件中的一個錯誤都可能破壞系統掛起/休眠。對於由其他組件引起的問題,即使我們找到了根本原因,在大多數情況下,我們仍然需要依賴組件所有者提供適當的修復。
因此,編寫這個文檔是爲了幫助用戶做一些調試例程,以便他們可以做以下事情:
- 如果可能的話,找出根本原因或縮小問題範圍。
- 適當地提出問題,提供:
- 對問題的精確描述。
- 測試必要的調試例程的結果。
- 精確的組件和所有者,例如:Linux PM核心,驅動程序,BIOS等。
在本文檔中
- 第2章介紹了一些可以在第4章中使用的常見調試方法。
- 第3章介紹了根據我們對Linux PM維護的經驗引入了一些典型的問題,這些問題可以破壞Linux 掛起/休眠。
- 第4章根據問題的不同症狀給出了詳細的步驟說明。
因此,當用戶遇到與掛起/休眠相關的問題時,我們建議用戶在第4章中找到描述遇到的問題的適當部分,並直接按照該部分的逐步說明進行操作。
initcall_debug
[ 76.201970] calling 0000:00:02.0+ @ 2298, parent: pci0000:00
[ 76.217006] call 0000:00:02.0+ returned 0 after 14677 usec
負結果意味着回調要麼包含一些錯誤/警告,要麼花費不合理的長時間來完成。
no_console_suspend
在內核命令行cmdline中添加no_console_suspend
啓動選項可以在掛起/休眠期間禁用控制檯的掛起。添加此選項後,調試消息可以到達各種控制檯,而系統的其他部分則處於休眠狀態。這可能不能在所有控制檯都可靠地工作,但是衆所周知,它可以在串口和VGA控制檯上工作。
ignore_loglevel
在內核命令行cmdline中添加ignore_loglevel
啓動選項可以將所有內核消息輸出到控制檯,無論當前的loglevel是什麼,這對於調試非常有用。
對於STI/STR,添加dyndbg="file .c +p"
引導選項,對於HTD,添加file swap.c +p;file snapshot.c +p;file hibernate.c +p
引導選項,用這些選項啓用動態調試,這樣我們可以在休眠過程中收集更多的信息。
serial console
serial console
輸出對於跟蹤某些系統掛起問題非常有用,尤其是當VGA控制檯宕機或無法記錄完整的崩潰日誌時。要啓用serial console
,請將console=ttyS0,115200
和no_console_suspend
添加到內核的命令行cmdline,然後在另一臺機器上使用minicom
或GNU screen
等程序將串行端口設置爲115200 8-N-1
以捕獲日誌。有關更多細節,請參考https://www.kernel.org/doc/Documentation/serial-console.txt
。
RTC跟蹤
RTC跟蹤是一種特性,用於在掛起/恢復期間以文件+行形式捕獲損壞的驅動程序,將其保存到CMOS SRAM中,並在下一次引導期間恢復它。要啓用這一點,請確保內核是使用CONFIG_PM_TRACE_RTC=y
構建的,並且通過echo 0 > /sys/power/pm_async
禁用pm異步。更多信息請參考https://www.kernel.org/doc/Documentation/power/s2ram.txt
。
測試結果:從STI/STR/HTD
失敗重啓後的dmesg輸出。請注意,重新啓動必須在三分鐘內發生,否則保存在SRAM中的數據將被破壞。
pm_async
現在Linux會同時掛起和恢復所有設備,以節省時間。可以使用echo 0 > /sys/power/pm_async
來檢查掛起/休眠失敗是否由未知的設備依賴問題引起。這也可以用來調優驅動程序掛起/恢復延遲。
測試結果:在禁用異步暫停/恢復後,檢查問題是否仍然存在。
pm_test
pm_test
是一種調試方法,系統可以部分地進行STR/HTD
調試,它可以用來縮小導致STI/STR/HTD
故障的代碼的範圍。請參考https://www.kernel.org/doc/Documentation/power/basic-pm-debugging.txt
獲得更多細節。
測試結果可以檢查哪些測試模式有問題,哪些測試模式沒有問題。dmesg輸出的失效模式,如果可能的話。
ACPI喚醒
/proc/acpi/wakeup
列出了所有ACPI設備的喚醒能力,以及對可用物理設備的引用。如下例所示,戳這個文件可以啓用/禁用設備的喚醒功能。例如,你可以通過以下步驟禁用/啓用“啓用”/“禁用”設備:
root@linux-machine# cat /proc/acpi/wakeup
Device S-state Status Sysfs node
...
EHC1 S4 *enabled pci:0000:00:1d.0
...
root@linux-machine# echo EHC1 > /proc/acpi/wakeup
root@linux-machine# cat /proc/acpi/wakeup
Device S-state Status Sysfs node
...
EHC1 S4 *disabled pci:0000:00:1d.0
...
測試結果可以禁用和啓用每個設備的喚醒功能可以解決這個問題。
acpidump
acpidump
是一個可以用來轉儲BIOS提供的ACPI表的工具。這在調試可能由ACPI引起的掛起/休眠問題時非常有用。要獲得該工具,只需轉到內核源代碼的tools/power/acpi/
目錄,並運行make
。
rtcwake
rtcwake
是一個工具,可以用來進入系統休眠狀態(掛起/休眠),直到指定的喚醒時間。你可以很容易地使用它來執行掛起/休眠壓力測試。例如,你可以使用這個簡單的腳本輕鬆運行1000個STR循環:
for i in $(seq 1000); do
rtcwake –m mem –s 30
done
analyze_suspend
analyze_syspend工具爲系統開發人員提供了可視化掛起和恢復之間的活動的功能,允許他們識別效率低下和瓶頸。例如,你可以使用以下命令啓動:
./analyze_suspend.py -rtcwake 30 -f -m mem
30秒後系統自動恢復並在./suspend-yymmddyy-hhmmss
目錄下生成3個文件:
mem_dmesg.txt mem_ftrace.txt mem.html
您可以首先用瀏覽器打開mem.html
文件,然後深入mem_ftrace.txt
查找數據細節。你可以通過git獲得analyze_suspend
工具:
git clone https://github.com/01org/suspendresume.git
更多細節,請訪問主頁:https://01.org/endresume
。
測試結果:mem_dmesg.txt mem_ftrace.txt mem.html
磁盤模式
這隻適用於HTD。嘗試echo {shutdown/reboot} > /sys/power/disk
跳過一些平臺特定的代碼,這些代碼在運行echo disk > /sys/power/state
之前可能會有bug。在ACPI平臺上,系統實際進入的是S5而不是S4。
測試結果:當/sys/power/disk等於關機或重啓時,是否仍然存在問題。
迴歸是指掛起/休眠可以正常工作,但是在升級內核之後會失敗。在這種情況下,找到根本原因並解決問題的最快速和最有效的方法是使用git bisect找出是哪個提交導致了問題,然後將問題報告給提交作者/組件所有者。
驅動損壞可能導致:
- 系統無法進入
suspend
(suspend
命令返回錯誤代碼)。 - 在掛起/恢復期間掛起的系統。
- 系統需要不合理的長時間掛起/恢復。
- 暫停/恢復後在dmesg中生成的調試跟蹤/錯誤日誌。
- 驅動本身無法工作。
因此,當您遇到與掛起/休眠相關的問題時,通常首先要檢查這個問題是否是驅動程序特有的問題。如果在恢復/掛起失敗後系統是響應的(可以通過VGA/serial console
、ssh等訪問系統),嘗試使用啓動選項initcall_debug
和no_console_suspend
重現問題。如果有,做以下事情:
- 將驅動程序構建爲模塊
- 卸載驅動程序
- 掛起並恢復機器
- 使用以下命令重新加載驅動程序:
modprobe -r foo && echo mem > /sys/power/state & modprobe foo
- 如果驅動程序是不可加載的,那麼根本不要通過Kconfig設置構建驅動程序。
- 如果問題不能重現,並且錯誤/警告在此之後沒有重新出現,那麼這是一個驅動程序特定的問題。
如果系統不響應,請執行以下操作:
- 啓用
serial console
並使用initcall_debug
和no_console_suspend
引導。 - 檢查
serial console
輸出是否有驅動程序引起的錯誤/警告。 - 如果發現任何錯誤/警告,將驅動程序構建爲模塊。
- 卸載驅動程序。
- 如果驅動程序無法在運行時卸載,則完全不要通過
Kconfig
設置構建驅動程序。 - 掛起並恢復機器。
- 重新加載驅動程序:
modprobe -r foo && echo mem > /sys/power/state & modprobe foo
- 如果問題不能重現,並且在這些步驟之後錯誤/警告沒有重新出現,那麼驅動程序就會導致問題。
如果系統在恢復後運行良好,但是一些驅動程序不再工作,請執行以下操作:
- 將驅動程序構建爲模塊。
- 卸載驅動程序
- 掛起並恢復機器
- 重新加載驅動程序:
modprobe -r foo && echo mem > /sys/power/state & modprobe foo
如果問題是不可重現的,這是一個驅動特有的問題。
對於這些問題,直接向驅動程序/組件所有者提交錯誤報告,因爲這些問題表明有問題的驅動程序/組件破壞了Linux 掛起/休眠。
下面幾節將討論一些典型的驅動程序特有的問題,這些問題可能會導致掛起/休眠中斷。
當系統在掛起/休眠期間掛起或恢復後監視器不再顯示時,請嘗試以下步驟:
- 禁用您正在使用的內核圖形驅動程序。在Intel平臺上,設置
CONFIG_DRM_I915=n
。 - 注意:不要在命令行中使用
nomodeset modprobe.blacklist=i915
,因爲有時i915驅動程序可能會被其他組件探測。 - 嘗試再次暫停/恢復。
- 如果在恢復後看到黑屏,沒有圖像,請嘗試通過串口控制檯或SSH訪問系統。如果系統仍在工作,這是一個圖形問題。
- 如果
serial console
和SSH都不可用,請按PS2鍵盤上的Num Lock
。如果Num Lock LED
在您按下鍵時亮起,則使用鍵盤輸入reboot
。雖然監視器沒有顯示,但是如果系統重新啓動成功,那麼很可能系統工作正常,這是一個圖形問題。
對於圖形問題,請在https://bugs.freedesktop.org/
中提交一個錯誤。例如,我們從dmesg輸出的下面幾行代碼中得到提示,將掛起/休眠問題的根本原因隔離到圖形驅動程序中:
[ 218.176542] ------------[ cut here ]------------
[ 218.176550] WARNING: CPU: 1 PID: 221 at drivers/gpu/drm/i915/intel_lrc.c:1100 gen8_init_rcs_context+0x15d/0x160()
[ 218.176552] WARN_ON(w->count == 0)
[ 218.176553] Modules linked in:
[ 218.176556] CPU: 1 PID: 221 Comm: kworker/u16:3 Tainted: G W 3.18.0-eywa-dirty #30
[ 218.176558] Hardware name: Intel Corporation Skylake Client platform/Skylake Y LPDDR3 RVP3, BIOS SKLSE2P1.86C.B060.R01.1411140050 11/14/2014
[ 218.176564] Workqueue: events_unbound async_run_entry_fn
[ 218.176567] 0000000000000009 ffff88009a96fad8 ffffffff82431683 0000000000000001
[ 218.176570] ffff88009a96fb28 ffff88009a96fb18 ffffffff8111e001 00000000fffe6b2d
[ 218.176573] ffff88009b42f300 0000000000000005 ffff88009b670000 ffff88009b671ce8
[ 218.176574] Call Trace:
...
[ 218.176657] ---[ end trace f587fddb962240b1 ]---
我們還沒有看到音頻驅動程序暫停/休眠,但音頻驅動程序本身可能需要很長時間才能恢復,如下面的例子所示:
[ 61.273112] calling hdaudioC0D2+ @ 1236, parent: 0000:00:1f.3
[ 64.295757] snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to polling mode: last cmd=0x208f8100
[ 65.303916] snd_hda_intel 0000:00:1f.3: No response from codec, disabling MSI: last cmd=0x208f8100
[ 66.312147] snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to single_cmd mode: last cmd=0x208f8100
[ 66.312402] azx_single_wait_for_response: 153 callbacks suppressed
[ 66.323406] snd_hda_codec_hdmi hdaudioC0D2: Unable to sync register 0x2f0d00. -5
[ 66.323791] snd_hda_codec_hdmi hdaudioC0D2: HDMI: invalid ELD buf size -1
[ 66.324179] snd_hda_codec_hdmi hdaudioC0D2: HDMI: invalid ELD buf size -1
[ 66.324565] snd_hda_codec_hdmi hdaudioC0D2: HDMI: invalid ELD buf size -1
[ 66.324571] call hdaudioC0D2+ returned 0 after 4932188 usecs
在這種情況下,提交一個音頻錯誤。
通常,USB問題不會掛起系統,但一些USB設備可能會停止工作後,系統恢復。如果一些USB設備(如USB鼠標/鍵盤/網絡)在恢復系統後停止工作,而其他設備(如PS/2鍵盤)似乎可以正常工作,請檢查dmesg/串行日誌中的USB警告。如果您發現一個警告,這可能是一個USB問題。例如:
[ 21.203077] xhci-hcd: probe of xhci-hcd.1.auto failed with error -110
在這種情況下,提交USB錯誤。
MMC失敗會導致掛起操作(特別是掛起磁盤)失敗。在掛起期間,檢查dmesg和serial console
輸出中的MMC警告。例如:
[90.373541] mmc1: Timeout waiting for hardware interrupt.
[160.493633] mmc1: error -110 during resume (card was removed?)
如果rootfs不在MMC上,請再次嘗試使用modprobe.blacklist = mmc_block
啓動選項。如果rootfs在MMC上,請使用具有相同內核/發行版的USB驅動器,然後再次嘗試使用modprobe.blacklist = mmc_block
。如果在將MMC驅動程序列入黑名單後問題已經解決,則提交MMC錯誤。
我們也曾看到若干個由I2C引發的錯誤,比如:
calling i2c_designware.0+ @ 2867, parent: 0000:00:15.0
------------[ cut here ]------------
WARNING: CPU: 1 PID: 2867 at drivers/clk/clk.c:845 __clk_disable+0x5b/0x60()
[<ffffffff810751fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff81623a5b>] __clk_disable+0x5b/0x60
[<ffffffff81624267>] clk_disable+0x37/0x50
[<ffffffffa03a9029>] dw_i2c_suspend+0x29/0x40
在這種情況下用文件記錄I2C錯誤並提交。
運行cat /sys/power/state
,輸出未列舉freeze/mem/disk
,從而系統不能進入STI/STR/HTD
狀態。
- 對於STI
- 檢查內核是否使用
CONFIG_SUSPEND
構建。如果否就設置它。 - 檢查內核是否使用參數
relative_sleep_states=1
引導。如果有就移除它。
- 檢查內核是否使用
- 對於STR
- 檢查內核是否使用
CONFIG_SUSPEND
構建。如果否就設置它。 - 引導後檢查dmesg輸出,尋找有這樣關鍵字的行
ACPI: (supports S0 S3 S4 S5)
。如果S3沒有列出,它通常意味着平臺不支持S3。如果你不確定,保存一個掛起/休眠的缺陷到文件。
- 檢查內核是否使用
- 對於HTD
- 檢查內核是否使用
CONFIG_HIBERNATION
構建。如果否就用CONFIG_HIBERNATION=y
重新構建。 - 引導後檢查dmesg輸出,尋找有這樣關鍵字的行
ACPI: (supports S0 S3 S4 S5)
。如果S4沒有列出,它通常意味着平臺不支持S4。如果你不確定,保存一個掛起/休眠的缺陷到文件。
- 檢查內核是否使用
- 如果上面的測試後問題仍然存在,保存
[platform] {STI, STR, HTD}: state not available,
,連同dmesg
輸出,acpidump
輸出和你正在使用的內核配置文件爲掛起/休眠缺陷並提交。
運行: echo freeze/mem/disk > /sys/power/state
,返回有錯誤代碼。
- 檢查這是否是迴歸。
- 如果沒有,啓用
initcall_debug
和no_console_suspend
。 - 如果您發現一些設備回調返回錯誤代碼而不是0,這意味着設備不能被掛起,這將導致系統掛起/休眠產生。在這種情況下,將錯誤提交給驅動程序/組件所有者。
- 如果不是,文件保存掛起/休眠缺陷到
[Platform] {STI, STR, HTD}: failed to suspend
,連同掛起失敗後dmesg輸出和返回的錯誤代碼。
在運行echo freeze/mem/disk > /sys/power/state
之後,屏幕變黑,就像掛起/休眠成功一樣,但是系統變得沒有響應,無法喚醒到工作狀態。這可能在掛起或恢復期間發生。或者,系統進入預期的睡眠狀態,但是在恢復時沒有響應,只顯示黑屏或崩潰日誌。例如,風扇開始旋轉,任何現有的電源按鈕背光改變,但系統永遠不會回到工作狀態。
- 檢查這是否是迴歸。
- 如果不是,請檢查這是否是圖形問題。
- 如果不是,檢查這是否是驅動程序特定的問題。
- 如果問題仍然存在,文件保存掛起/休眠缺陷
[Platform] {STI, STR, HTD}: system hangs during suspend/resume
,以及問題重現後的串口控制檯輸出/截圖,/var/log/kern.log
內容,以及磁盤模式(僅限HTD)、pm_test
、pm_async
和rtc
跟蹤的測試結果。
屏幕變暗,重新啓動,用戶什麼都不做。
- 檢查這是否是迴歸。
- 如果不是,請檢查這是否是圖形問題。
- 如果不是,檢查這是否是驅動程序特定的問題。
- 如果問題仍然存在,文件保存掛起/休眠缺陷
{STI, STR, HTD}: system reboot during suspend/resume
,以及問題重現後的串口控制檯輸出/截圖,/var/log/kern.log
內容,以及磁盤模式(僅限HTD)、pm_test
、pm_async
和rtc
跟蹤的測試結果。
系統可以掛起並從STI/STR/HTD狀態恢復,但是某些組件或驅動程序可能無法工作,或者在恢復後的dmesg中可能出現錯誤或警告。
- 檢查這是否是迴歸。
- 如果不是,檢查這是否是驅動程序特定的問題。
- 如果問題仍然存在,文件保存掛起/休眠缺陷
[Platform] {STI, STR, HTD}: xxx broken after resume
,以及恢復後dmesg輸出。
掛起後系統很快就會回到工作狀態,而用戶不做任何事情。dmesg顯示系統已經完成了一個完整的掛起/恢復週期。
- 檢查這是否是迴歸。
- 檢查這是否是一個驅動程序特定的問題,刪除任何不必要的外設,如USB驅動器,網線等。
當您按下電源鍵、使用鍵盤等時,系統不會自動喚醒。
-
檢查這是否是迴歸。對於STI,檢查驅動程序是否有自己的託管中斷。如果是,檢查
enable_irq_wake()
是否爲驅動程序使用的中斷調用。如果不是,將其添加到驅動程序.probe()
或.suspend()
回調中。例如:static int bu21013_suspend(struct device *dev) { ... if (device_may_wakeup(&client->dev)) enable_irq_wake(bu21013_data->irq); else disable_irq(bu21013_data->irq); ... return 0; }
-
如果問題仍然存在,文件保存掛起/休眠缺陷
[Platform] {STI, STR, HTD}: XXX cannot wake up the system
,確保包含dmesg、acpidump輸出、ACPI喚醒的測試結果以及缺陷報告。
總的/特定的驅動程序掛起/恢復時間比預期/要求的長。
你已經確定了一個特定的驅動程序,需要花太多的時間暫停/恢復,文件錯誤的驅動程序所有者。
如果總體掛起/恢復延遲很高,請執行以下操作:
- 使用
initcall_debug
和no_console_suspend
啓動選項重新啓動。 - 禁用異步掛起/恢復。
- 使用
analyze_suspend
重做掛起/恢復。 - 檢查測試結果,找出哪些驅動程序和組件在掛起/恢復期間花費的時間最多,並將問題連同
analyze_suspend
的測試結果一起報告給驅動程序/組件所有者。
- 對於HTD,
- 檢查用於交換分區的驅動程序。
- 如果驅動程序是作爲模塊構建的,則將驅動程序構建進來並檢查問題是否仍然存在。
- 如果沒有,文件保存
[Platform] HTD: hibernate fails when disk driver is built as module
。 - 如果是,請按照以下步驟繼續調試。
- 使用
initcall_debug
、no_console_suspend
、ignore_loglevel
、動態調試和serial console
重新啓動。 - 使用rtcwake進行壓力測試。
- 按照上面一節中的說明,當掛起/hibernate無法驗證和提出問題時,可以很好地描述症狀。
如果您已經縮小了問題的範圍,或者發現問題的根本原因是驅動程序特定的問題:
- 如果您知道在哪裏爲指定的驅動程序提出問題,則直接在那裏提出。例如,對於圖形問題,在https://bugs.freedesktop.org/中提交一個錯誤報告。
- 如果您不清楚在哪裏提出問題,最好的方法是在檢查了http://vger.kernel.org/vger-lists.html之後訂閱子系統/驅動程序郵件列表並在那裏提出問題,在提出問題時請執行CC [email protected]。
如果不是驅動程序特定的問題,或者在調試之後您不確定問題是什麼,可以在https://bugzilla.kernel.org/enter_bug.cgi?product=Power%20Management,將組件設置爲“休眠/掛起”,幷包含所需的調試信息和測試結果。