- 概述
当谈到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接口的更多细节,如上面提到的
英特尔开源技术中心(OTC)中国内核电源团队多年来一直致力于Linux电源管理子系统的质量改进工作。我们处理问题的经验,无论是通过电子邮件在Linux邮件列表或通过
- 低效率。这是因为在大多数情况下,开发人员无法在本地重现问题。因此,我们依赖于用户提供问题症状的详细描述、必要的调试信息以及一些测试结果(如果需要的话)。由于时区不同,为进一步调试做好准备可能需要几天甚至几周的时间。
- 额外的工作。这是因为Linux STI/STR/HTD是系统级低功耗状态,需要硬件、固件、Linux PM内核和许多其他内核组件(尤其是设备驱动程序)才能很好地协同工作。这意味着任何单个组件中的一个错误都可能破坏系统挂起/休眠。对于由其他组件引起的问题,即使我们找到了根本原因,在大多数情况下,我们仍然需要依赖组件所有者提供适当的修复。
因此,编写这个文档是为了帮助用户做一些调试例程,以便他们可以做以下事情:
- 如果可能的话,找出根本原因或缩小问题范围。
- 适当地提出问题,提供:
- 对问题的精确描述。
- 测试必要的调试例程的结果。
- 精确的组件和所有者,例如:Linux PM核心,驱动程序,BIOS等。
在本文档中
- 第2章介绍了一些可以在第4章中使用的常见调试方法。
- 第3章介绍了根据我们对Linux PM维护的经验引入了一些典型的问题,这些问题可以破坏Linux 挂起/休眠。
- 第4章根据问题的不同症状给出了详细的步骤说明。
因此,当用户遇到与挂起/休眠相关的问题时,我们建议用户在第4章中找到描述遇到的问题的适当部分,并直接按照该部分的逐步说明进行操作。
这里列出了一些常见的调试方法,对于遇到挂起/休眠相关问题的人非常有用。
在内核命令行cmdline中添加`initcall_debug`启动选项将跟踪启动、挂起和恢复期间的initcalls和驱动程序pm回调。检查指定的驱动程序/组件是否失败是很有用的。确保在调试STI/STR/HTD相关问题时始终启用它。通常,正结果意味着回调没有错误/警告,并在合理的时间内返回0。这在以下方面得到了证明:
1 2 | [ 76.201970] calling 0000:00:02.0+ @ 2298, parent: pci0000:00 [ 76.217006] call 0000:00:02.0+ returned 0 after 14677 usec |
负结果意味着回调要么包含一些错误/警告,要么花费不合理的长时间来完成。
在内核命令行cmdline中添加
在内核命令行cmdline中添加
对于STI/STR,添加
RTC跟踪是一种特性,用于在挂起/恢复期间以文件+行形式捕获损坏的驱动程序,将其保存到CMOS SRAM中,并在下一次引导期间恢复它。要启用这一点,请确保内核是使用
测试结果:从
现在Linux会同时挂起和恢复所有设备,以节省时间。可以使用
测试结果:在禁用异步暂停/恢复后,检查问题是否仍然存在。
测试结果可以检查哪些测试模式有问题,哪些测试模式没有问题。dmesg输出的失效模式,如果可能的话。
1 2 3 4 5 6 7 8 9 10 11 | 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 ... |
测试结果可以禁用和启用每个设备的唤醒功能可以解决这个问题。
1 2 3 | for i in $(seq 1000); do rtcwake –m mem –s 30 done |
analyze_syspend工具为系统开发人员提供了可视化挂起和恢复之间的活动的功能,允许他们识别效率低下和瓶颈。例如,你可以使用以下命令启动:
1 | ./analyze_suspend.py -rtcwake 30 -f -m mem |
30秒后系统自动恢复并在
1 | mem_dmesg.txt mem_ftrace.txt mem.html |
您可以首先用浏览器打开
1 | git clone https://github.com/01org/suspendresume.git |
更多细节,请访问主页:
测试结果:
这只适用于HTD。尝试
测试结果:当/sys/power/disk等于关机或重启时,是否仍然存在问题。
回归是指挂起/休眠可以正常工作,但是在升级内核之后会失败。在这种情况下,找到根本原因并解决问题的最快速和最有效的方法是使用git bisect找出是哪个提交导致了问题,然后将问题报告给提交作者/组件所有者。
驱动损坏可能导致:
- 系统无法进入
suspend (suspend 命令返回错误代码)。 - 在挂起/恢复期间挂起的系统。
- 系统需要不合理的长时间挂起/恢复。
- 暂停/恢复后在dmesg中生成的调试跟踪/错误日志。
- 驱动本身无法工作。
因此,当您遇到与挂起/休眠相关的问题时,通常首先要检查这个问题是否是驱动程序特有的问题。如果在恢复/挂起失败后系统是响应的(可以通过VGA/
- 将驱动程序构建为模块
- 卸载驱动程序
- 挂起并恢复机器
- 使用以下命令重新加载驱动程序:
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 。虽然监视器没有显示,但是如果系统重新启动成功,那么很可能系统工作正常,这是一个图形问题。
对于图形问题,请在
1 2 3 4 5 6 7 8 9 10 11 12 13 | [ 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 ]--- |
我们还没有看到音频驱动程序暂停/休眠,但音频驱动程序本身可能需要很长时间才能恢复,如下面的例子所示:
1 2 3 4 5 6 7 8 9 10 | [ 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问题。例如:
1 | [ 21.203077] xhci-hcd: probe of xhci-hcd.1.auto failed with error -110 |
在这种情况下,提交USB错误。
MMC失败会导致挂起操作(特别是挂起磁盘)失败。在挂起期间,检查dmesg和
1 2 | [90.373541] mmc1: Timeout waiting for hardware interrupt. [160.493633] mmc1: error -110 during resume (card was removed?) |
如果rootfs不在MMC上,请再次尝试使用
我们也曾看到若干个由I2C引发的错误,比如:
1 2 3 4 5 6 7 | 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错误并提交。
运行
- 对于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 输出和你正在使用的内核配置文件为挂起/休眠缺陷并提交。
运行:
- 检查这是否是回归。
- 如果没有,启用
initcall_debug 和no_console_suspend 。 - 如果您发现一些设备回调返回错误代码而不是0,这意味着设备不能被挂起,这将导致系统挂起/休眠产生。在这种情况下,将错误提交给驱动程序/组件所有者。
- 如果不是,文件保存挂起/休眠缺陷到
[Platform] {STI, STR, HTD}: failed to suspend ,连同挂起失败后dmesg输出和返回的错误代码。
在运行
- 检查这是否是回归。
- 如果不是,请检查这是否是图形问题。
- 如果不是,检查这是否是驱动程序特定的问题。
- 如果问题仍然存在,文件保存挂起/休眠缺陷
[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() 回调中。例如:1
2
3
4
5
6
7
8
9
10static 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 的测试结果一起报告给驱动程序/组件所有者。
症状可以是上面列出的任何症状,但区别是这些问题不是100%可重复的。有时可能需要数十甚至数百个挂起/休眠周期才能进行复制。
- 对于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,将组件设置为“休眠/挂起”,并包含所需的调试信息和测试结果。