1. 前言
Linux电源管理中,相当多的部分是在处理Hibernate、Suspend、Runtime PM等功能。而这些功能都基于一套相似的逻辑,即“Power management interface”。该Interface的代码实现于“include/linux/pm.h”、“drivers/base/power/main.c”等文件中。主要功能是:对下,定义Device PM相关的回调函数,让各个Driver实现;对上,实现统一的PM操作函数,供PM核心逻辑调用。
因此在对Hibernate、Suspend、RunTIme PM等功能解析之前,有必要先熟悉一下PM Interface,这就是本文的主要目的。
2. device PM callbacks
在一个系统中,数量最多的是设备,耗电最多的也是设备,因此设备的电源管理是Linux电源管理的核心内容。而设备电源管理最核心的操作就是:在合适的时机(如不再使用,如暂停使用),将设备置为合理的状态(如关闭,如睡眠)。这就是device PM callbacks的目的:定义一套统一的方式,让设备在特定的时机,步调一致的进入类似的状态(可以想象一下军训时的“一二一”口令)。
在旧版本的内核中,这些PM callbacks分布在设备模型的大型数据结构中,如struct bus_type中的suspend、suspend_late、resume、resume_late,如struct device_driver/struct class/struct device_type中的suspend、resume。很显然这样不具备良好的封装特性,因为随着设备复杂度的增加,简单的suspend、resume已经不能满足电源管理的需求,就需要扩充PM callbacks,就会不可避免的改动这些数据结构。
于是新版本的内核,就将这些Callbacks统一封装为一个数据结构----struct dev_pm_ops,上层的数据结构只需要包含这个结构即可。这样如果需要增加或者修改PM callbacks,就不用改动上层结构了(这就是软件设计中抽象和封装的生动体现,像艺术一样优雅)。当然,内核为了兼容旧的设计,也保留了上述的suspend/resume类型的callbacks,只是已不建议使用,本文就不再介绍它们了。
相信每一个熟悉了旧版本内核的Linux工程师,看到struct dev_pm_ops时都会虎躯一震,这玩意也太复杂了吧!不信您请看:
1: /* include/linux/pm.h, line 276 in linux-3.10.29 */
2: struct dev_pm_ops {
3: int (*prepare)(struct device *dev);
4: void (*complete)(struct device *dev);
5: int (*suspend)(struct device *dev);
6: int (*resume)(struct device *dev);
7: int (*freeze)(struct device *dev);
8: int (*thaw)(struct device *dev);
9: int (*poweroff)(struct device *dev);
10: int (*restore)(struct device *dev);
11: int (*suspend_late)(struct device *dev);</