Linux电源管理(2)_Generic PM之基本概念和软件架构

1. 前言

这里的Generic PM,是蜗蜗自己起的名字,指Linux系统中那些常规的电源管理手段,包括关机(Power off)、待机(Standby or Hibernate)、重启(Reboot)等。这些手段是在嵌入式Linux普及之前的PC或者服务器时代使用的。在那个计算机科学的蛮荒时代,人类在摩尔定律的刺激下,孜孜追求的是计算机的计算能力、处理性能,因此并不特别关心Power消耗。

在这种背景下发展出来的Linux电源管理机制,都是粗放的、静态的、被动的,具体请参考下面的介绍。

2. Generic PM在Linux操作系统中的表现形式

Linux操作系统中,和Generic PM有关的操作如下面图片:

Generic PM在Linux操作系统中的表现形式

该图片截取自蜗蜗使用的“Linux ubuntu 2.6.32-38”系统,共有3部分组成:

第1部分是系统关机、重启等操作的界面,共包含Hibernate、Restart、Shutdown三个操作选项;

2、3部分是“电源管理属性”设置,所谓的电源管理属性,可以配置系统在不同供电模式下(如AC Power、Battery等,由于蜗蜗的机器是PC机,因此就没有电池供电的选项),处于Inactive状态多久后,系统关闭Display,或者进入Sleep状态。

本文将会围绕上面提到的各个名词,讲述它们的意义、在内核中的实现方式。开始之前,先解释一下这些词汇的意义。

Shutdown,很好理解,就是关机的意思。同时意味着不再使用计算机

Restart,也很好理解,就是重启系统的意思。重启的过程,不再使用计算机

Hibernate,可翻译为冬眠。

听到“冬眠”这个词,您是否眼前一亮?蜗蜗在“Linux电源管理(1)_整体架构”中解释电源管理的概念的时候,提到过,动物冬眠就是大自然所设计的电源管理方式的一种。在动物界,冬眠是指动物们(通常针对温血动物)通过降低体温的方式而进入的类似昏睡的生理状态,在这种状态下,需要消耗的能量较少,从而可以达到省电(能量)的目的。

而在计算机界,设计师们也借用了“冬眠”的概念,在不需要使用计算机时将它当前的所有现场(执行的程序、显示器显示的图像、正在播放的声音等)保存到一些断电不会丢失的存储器中(如硬盘中),然后将计算机关闭。重新开启后,系统会从存储器中将关闭前的现场读取出来并恢复,此时从使用者的角度看,计算机就像没有关闭过一样。

如果把计算机界的“冬眠”搬到动物界,会是这样的场景:一只恐龙,迈着八字步,吃着香蕉,晃晃悠悠的走在树林中。然后,无聊的孙猴子来了,喊了一声“定!”,恐龙就定在那里了。再然后,一万年过去了,无聊的孙猴子又来了,喊了一声“动!”,恐龙继续迈着八字步,吃着香蕉,就像什么事情都没有发生一样。

Sleep,睡眠。这个词也是从生物界学来的。想象一下“睡眠”和“冬眠”的区别?“睡眠”睡的轻,随时都可以醒来。在计算机中,Hibernate需要把现场保存到断电不丢失的存储器中,并在醒来的时候读回来,这些可能需要较长的时间(因为断电不丢失存储器的访问速度都比较慢)。如果想快点,就把现场保存在内存中就可以了,这就是Sleep。不过这是要付出代价的,内存要保持供电,这就要消耗能量,鱼与熊掌不可兼得啊!

Auto Sleep,查看上面图片第3个部分,可以设置系统“处于Inactive状态多久后,自动进入Sleep状态”。比如我正在写这篇文章,然后被老婆喊去跪搓衣板了,一跪两个小时。这两个小时内,计算机不再被使用,如果不进入Sleep状态,将会消耗很多能量。为了避免这无谓的消耗,可以让系统在符合条件时(如20分钟不使用),自动睡下去。

Auto put display to Sleep,原理类似,只是操作的对象是Display(显示器等)。

 

注:

不知读者有没有注意到,蜗蜗在解释上面的词汇时,一直在用红色字体强调“计算机不再使用”。这就是Generic PM和Runtime PM的本质区别,即,在使用者的主观意愿上,是否需要暂停使用计算机(哪怕短短的一段时间)。

这也是Generic PM在传统的计算机操作系统中被广泛使用的原因,因为那个时候对计算机的使用大多是主动方式。而对当前的移动互联来说,就非常不合时宜了,因为人们需要移动设备实时在线、实时接收被动事件(如来电),也就不可能主观地暂停使用(哪怕短短的一段时间)。这种最终需求的差异,会导致在软件设计上有很大的差别,正因为如此,Runtime PM的出现和尽快成熟,才显得格外重要。

3. Generic PM的软件架构

在介绍完Generic PM的基本概念后,我们来看一下它在Linux内核中的整体实现,并抽象出简单的软件架构,以便再后续的文章中,对Generic PM的主要组成部分进行更为细致的分析。具体如下:

Generic PM Architecture

根据上面的描述可知,Generic PM主要处理关机、重启、冬眠(Hibernate)、睡眠(Sleep,在Kernel中也称作Suspend)。在内核中,大致可以分为三个软件层次:

API Layer,用于向用户空间提供接口,其中关机和重启的接口形式是系统调用(在新的内核中,关机接口还有一种新方式,具体讲到的时候再说),Hibernate和Suspend的接口形式是sysfs。

PM Core,位于kernel/power/目录下,主要处理和硬件无关的核心逻辑。

PM Driver,分为两个部分,一是体系结构无关的Driver,提供Driver框架(Framework)。另一部分是具体的体系结构相关的Driver,这也是电源管理驱动开发需要涉及到的内容(图中红色边框的模块)。

另外,电源管理是一个系统级的模块,因而会涉及到设备模型、进程管理等等方方面面的内容,我们可以在后续具体的分析过程中,细细品味。

原创文章,转发请注明出处。蜗窝科技www.wowotech.net

标签: Linux PM suspend hibernate sleep

Linux内核中进行电源管理驱动开发时,特别是在runtime状态下的功能需求,需要对内核电源管理框架有深入的理解。以下是一些关键的功能需求开发要点: ### 电源管理驱动的基本功能需求 1. **支持Runtime PM框架** Linux内核提供了一个Runtime Power Management(运行时电源管理)框架,允许设备在系统运行期间动态地进入低功耗状态。驱动程序需要注册并实现相应的回调函数,以响应电源状态的变化。这些回调函数包括: - `runtime_suspend`:当设备需要进入低功耗状态时调用。 - `runtime_resume`:当设备需要恢复到正常功耗状态时调用。 - `runtime_idle`:当设备空闲时调用,可以决定是否进入低功耗状态。 2. **设备层级的电源管理** 每个设备都可以独立地进行电源管理,这意味着驱动程序需要能够跟踪设备的使用情况,并在适当的时候请求设备进入低功耗状态或恢复到正常状态。设备的电源管理状态可以通过`pm_runtime` API进行控制,例如: - `pm_runtime_enable`:启用设备的Runtime PM功能。 - `pm_runtime_disable`:禁用设备的Runtime PM功能。 - `pm_runtime_get_sync` `pm_runtime_put_sync`:同步地增加或减少设备的使用计数,并根据计数决定是否进入或退出低功耗状态。 3. **异步电源管理** 为了提高系统的响应性性能,驱动程序可以支持异步电源管理操作。这意味着电源管理操作可以在后台执行,而不会阻塞当前的任务。例如,`pm_schedule_suspend`函数可以用于安排一个异步的挂起操作。 4. **多级电源状态支持** 设备可能支持多个不同的电源状态(如D0、D1、D2、D3hot、D3cold等),驱动程序需要能够根据设备的特性当前的工作负载选择合适的电源状态。例如,某些设备可能在D3hot状态下仍然保持部分功能,而在D3cold状态下则完全断电。 5. **上下文保存与恢复** 在设备进入低功耗状态之前,可能需要保存其寄存器的状态,以便在恢复时能够正确地恢复到原来的状态。这通常通过`pm_runtime_suspend``pm_runtime_resume`函数中的回调实现。例如,驱动程序可以在`runtime_suspend`回调中保存寄存器的状态,并在`runtime_resume`回调中恢复这些状态。 6. **中断处理与唤醒源配置** 在设备进入低功耗状态时,需要确保设备能够正确地响应外部事件并唤醒系统。驱动程序需要配置设备的中断作为唤醒源,并确保在低功耗状态下中断仍然有效。例如,可以通过`enable_irq_wake``disable_irq_wake`函数来启用或禁用中断作为唤醒源。 7. **电源管理域(Power Domain)支持** 在复杂的SoC(System on Chip)架构中,多个设备可能共享同一个电源域。驱动程序需要能够与电源域管理框架协同工作,确保设备在进入低功耗状态时不会影响到同一电源域中的其他设备。电源域管理框架可以通过`genpd`(Generic Power Domain)子系统来实现。 8. **调试与日志记录** 为了方便调试优化电源管理行为,驱动程序应提供详细的日志记录功能。可以使用`pr_debug`或`dev_dbg`等宏来记录电源管理操作的详细信息。此外,还可以通过`sysfs`或`debugfs`接口提供实时的电源管理状态查询功能。 ### 开发工具与调试方法 1. **使用`pm-utils`工具** `pm-utils`是一组用于电源管理的用户空间工具,可以帮助开发者测试调试电源管理功能。例如,`pm-suspend`命令可以用于测试系统的挂起恢复功能。 2. **使用`trace-cmd`进行跟踪** `trace-cmd`是一个用于跟踪内核事件的工具,可以帮助开发者分析电源管理操作的时间线。例如,可以通过`trace-cmd record -e power:runtime_suspend`来跟踪设备的Runtime PM事件。 3. **使用`sysfs``debugfs`接口** `sysfs``debugfs`提供了访问内核电源管理状态的接口。例如,可以通过`/sys/devices/.../power/runtime_status`文件查看设备的当前电源状态,或者通过`/sys/class/power_supply/...`文件查看电池的状态。 4. **使用`dmesg`查看内核日志** `dmesg`命令可以用于查看内核的日志信息,帮助开发者识别电源管理操作中的错误或异常情况。 ### 示例代码 以下是一个简单的示例,展示了如何在驱动程序中实现Runtime PM功能: ```c #include <linux/pm_runtime.h> #include <linux/platform_device.h> static int my_device_runtime_suspend(struct device *dev) { /* 保存设备的寄存器状态 */ // 例如:writel(0x0, dev->regs + CONTROL_REG); return 0; } static int my_device_runtime_resume(struct device *dev) { /* 恢复设备的寄存器状态 */ // 例如:writel(0x1, dev->regs + CONTROL_REG); return 0; } static const struct dev_pm_ops my_device_pm_ops = { .runtime_suspend = my_device_runtime_suspend, .runtime_resume = my_device_runtime_resume, }; static int my_device_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; /* 启用设备的Runtime PM功能 */ pm_runtime_enable(dev); return 0; } static int my_device_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; /* 禁用设备的Runtime PM功能 */ pm_runtime_disable(dev); return 0; } static struct platform_driver my_device_driver = { .probe = my_device_probe, .remove = my_device_remove, .driver = { .name = "my_device", .pm = &my_device_pm_ops, }, }; module_platform_driver(my_device_driver); ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值