首页 > 系统相关 >Linux PM机制

Linux PM机制

时间:2022-09-28 00:11:20浏览次数:70  
标签:suspend struct PM dev Linux device 机制 runtime pm

概述

RPM即Runtime power management的缩写,之Linux提供的一套电源管理框架。核心思想是分而治之的管理思想,将具体的控制策略和控制权力下放到各个驱动。 为所有device提供一种相对独立的电源管理方案,驱动可以自行决定何时打开或者关闭电源。Linux的suspend/resume机制也可以在合适的时机统一执行设备的休眠和唤醒动作,进而形成系统级电源管理方案。

软件框图

device driver(或者driver所在的bus、class等)需要提供3个回调函数,runtime_suspend、runtime_resume和runtime_idle,分别用于suspend device、resume device和idle device。它们一般由RPM core在合适的时机调用,以便降低device的power consumption。

而调用的时机,最终是由device driver决定的。driver会在适当的操作点,调用RPM core提供的put和get系列的helper function,汇报device的当前状态。RPM core会为每个device维护一个引用计数,get时增加计数值,put时减少计数值,当计数为0时,表明device不再被使用,可以立即或一段时间后suspend,以节省功耗。

除了RPM之外,Android上提出一种电源管理机制Opportunistic suspend。但目前Linux kernel用的比较多的还是RPM。

核心机制

  • 为每个设备维护一个引用计数(device->power.usage_count),用于指示该设备的使用状态。
  • 需要使用设备时,device driver调用pm_runtime_get(或pm_runtime_get_sync)接口,增加引用计数;不再使用设备时,device driver调用pm_runtime_put(或pm_runtime_put_sync)接口,减少引用计数。
  • 每一次put,RPM core都会判断引用计数的值。如果为零,表示该设备不再使用(idle)了,则使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_idle回调函数。
  • runtime_idle的存在,是为了在idle和suspend之间加一个缓冲,避免频繁的suspend/resume操作。因此它的职责是:判断设备是否具备suspend的条件,如果具备,在合适的时机,suspend设备。
1 可以不提供,RPM core会使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_suspend回调函数,suspend设备,同时记录设备的PM状态,
2 可以调用RPM core提供helper函数(pm_runtime_autosuspend_expiration、pm_runtime_autosuspend、pm_request_autosuspend),要求在指定的时间后,suspend设备。
  • pm_runtime_autosuspend、pm_request_autosuspend等接口,会起一个timer,并在timer到期后,使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_suspend回调函数,suspend设备,同时记录设备的PM状态。
  • 每一次get,RPM core都会判断设备的PM状态,如果不是active,则会使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_resume回调函数,resume设备。

注1 :Runtime PM中的“suspend”,不一定要求设备必须进入低功耗状态,而是要求设备在suspend后,不再处理数据,不再和CPUs、RAM进行任何的交互,直到设备的.runtime_resume被调用。因为此时设备的parent(如bus controller)、CPU是、RAM等,都有可能因为suspend而不再工作,如果设备再有任何动作,都会造成不可预期的异常。下面是“Documentation\power\runtime_pm.txt”中的解释,供大家参考:

1 * Once the subsystem-level suspend callback (or the driver suspend callback,
2   if invoked directly) has completed successfully for the given device, the PM
3   core regards the device as suspended, which need not mean that it has been
4   put into a low power state.  It is supposed to mean, however, that the
5   device will not process data and will not communicate with the CPU(s) and
6   RAM until the appropriate resume callback is executed for it.  The runtime
7   PM status of a device after successful execution of the suspend callback is
8   'suspended'.

注2 :回忆一下wakeup eventswakeup lock,Runtime PM和它们在本质上是一样的,都是实时的向PM core报告“我不工作了,可以睡了”、“我要工作了,不能睡(或醒来吧)”。不同的是:wakeup events和RPM的报告者是内核空间drivers,而wakeup lock是用户空间进程;wakeup events和wakelock涉及的睡眠对象是整个系统,包括CPU和所有的devices,而RPM是一个一个独立的device(CPU除外,它由cpu idle模块处理,可看作RPM的特例)。

同步和异步

级联设备PM

PM的API汇总

到目前为止,linux kernel的runtime PM接口定义在“include\linux\pm_runtime.h”中,有将近50个接口。实际使用中并非全部会用到。

RPM提供的API位于“include/linux/pm_runtime.h”中,常用的接口如下:

1 extern int __pm_runtime_idle(struct device *dev, int rpmflags);
2 extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
3 extern int __pm_runtime_resume(struct device *dev, int rpmflags);

这三个函数是RPM的idle、put/suspend、get/resume等操作的基础,根据rpmflag,有着不同的操作逻辑。后续很多API,都是基于它们三个。一般不会在设备驱动中直接使用。

1 extern int **pm_schedule_suspend(**struct **device *dev, unsigned** int **delay);**

在指定的时间后(delay,单位是ms),suspend设备。该接口为异步调用,不会更改设备的引用计数,可在driver的.rpm_idle中调用,免去driver自己再启一个timer的烦恼。

1 extern void **pm_runtime_enable(**struct **device *dev);** 
2 extern void **pm_runtime_disable(**struct **device *dev);**

设备RPM功能的enable/disable,可嵌套调用,会使用一个变量(dev->power.disable_depth)记录disable的深度。只要disable_depth大于零,就意味着RPM功能不可使用,很多的API调用(如suspend/reesume/put/get等)会返回失败。RPM初始化时,会将所有设备的disable_depth置为1,也就是disable状态,driver初始化完毕后,要根据设备的时机状态,调用这两个函数,将RPM状态设置正确。

1 extern void pm_runtime_allow(struct device *dev);
2 extern void pm_runtime_forbid(struct device *dev);

RPM core通过sysfs(drivers/base/power/sysfs.c),为每个设备提供一个“/sys/devices/.../power/control”文件,通过该文件可让用户空间程序直接访问device的RPM功能。这两个函数用来控制是否开启该功能(默认开启)。

1 extern int **pm_runtime_barrier(**struct **device *dev);**

这名字起的!!!由3.3的描述可知,很多RPM请求都是异步的,这些请求会挂到一个名称为“pm_wq”的工作队列上,这个函数的目的,就是清空这个队列,另外如果有resume请求,同步等待resume完成。好复杂,希望driver永远不要用到它!!

1 extern int pm_generic_runtime_idle(struct device *dev);
2 extern int pm_generic_runtime_suspend(struct device *dev);
3 extern int pm_generic_runtime_resume(struct device *dev);

几个通用的函数,一般给subsystem的RPM driver使用,直接调用devie driver的相应的callback函数。

 1 extern void **pm_runtime_no_callbacks(**struct *device dev);

告诉RPM core自己没有回调函数,不用再调用了(或者调用都是成功的),真啰嗦。

 1 extern void **pm_runtime_irq_safe(**struct *device dev);

告诉RPM core,如下函数可以在中断上下文调用: pm_runtime_idle() pm_runtime_suspend() pm_runtime_autosuspend() pm_runtime_resume() pm_runtime_get_sync() pm_runtime_put_sync() pm_runtime_put_sync_suspend() pm_runtime_put_sync_autosuspend()

1 static inline int pm_runtime_idle(struct device *dev)
2 static inline int pm_runtime_suspend(struct device *dev)
3 static inline int pm_runtime_resume(struct device *dev)

直接使用同步的方式,尝试idle/suspend/resume设备,如果条件许可,就会执行相应的callback函数。driver尽量不要使用它们。

1 static inline int pm_request_idle(struct device *dev)
2 static inline int pm_request_resume(struct device *dev)

和上面类似,不过调用方式为异步。尽量不要使用它们。

1 static inline int pm_runtime_get(struct device *dev)
2 static inline int pm_runtime_put(struct device *dev)

增加/减少设备的使用计数,并判断是否为0,如果为零,尝试调用设备的idle callback,如果不为零,尝试调用设备的resume callback。这两个接口是RPM的正统接口啊,多多使用!

1 static inline int pm_runtime_get_sync(struct device *dev)
2 static inline int pm_runtime_put_sync(struct device *dev)
3 static inline int pm_runtime_put_sync_suspend(struct device *dev)

和上面类似,只不过为同步调用。另外提供了一个可直接调用suspend的put接口,何必的!

1 static inline int pm_runtime_autosuspend(struct device *dev)
2 static inline int pm_request_autosuspend(struct device *dev)
3 static inline int pm_runtime_put_autosuspend(struct device *dev)
4 static inline int pm_runtime_put_sync_autosuspend(struct device *dev)

autosuspend相关接口。所谓的autosuspend,就是在suspend的基础上,增加一个timer,还是觉得有点啰嗦。不说了。

1 static inline void pm_runtime_use_autosuspend(struct device *dev)
2 static inline void pm_runtime_dont_use_autosuspend(struct device *dev)
3 extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
4 extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);

控制是否使用autosuspend功能,以及设置/获取autosuspend的超时值。

总结一下:总觉得这些API所提供的功能有些重叠,重叠的有点啰嗦。可能设计者为了提供更多的便利,可过渡的便利和自由,反而是一种束缚和烦恼!

20220602

标签:suspend,struct,PM,dev,Linux,device,机制,runtime,pm
From: https://www.cnblogs.com/545235abc/p/16338050.html

相关文章

  • Linux网络日志分析与流量监控 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1OG-5_4ebMeQjSUeO_3l-IA点击这里获取提取码 ......
  • Linux新手要了解的十个知识点
    Linux对于有的新手来说,感觉无从下手,或者不知道从哪儿学起?怎么学?针对这些问题,我给大家说说新手学习Linux需要了解的十个知识点。注意大小写Linux是大小写敏感的系......
  • linux服务器部署多个项目:出现启动一个项目另一个项目就挂掉问题
    问题:linux测试环境部署了多个项目,今天新加了一个项目,出现了部署这一个会让原来一个项目挂掉。重新启动了原来的,新的项目有会挂掉。原因:两个项目启动所配置的内存总和超过,l......
  • 3.TCP-IP & Linux 模型简介
    Dearall,  更新一节Linux网络驱动视频——3.TCP-IP&Linux模型简介,下节课开始正式编写driver。  B站链接:https://www.bilibili.com/video/BV1DG4y1s7ad/?vd_......
  • Linux驱动|rtc-hym8563移植笔记
    本文基于瑞芯微rk3568平台,关于该平台快速入手操作,大家可以参考以下文章:《瑞芯微rk356x板子快速上手》0、什么是rtc-hym8563?RTC:实时时钟的缩写是(Real_TimeClock)。RTC......
  • 垃圾回收机制与控制流程及流程控制理论
    今日内容总结垃圾回收机制"""有一些语言内存空间的申请和释放都需要程序员自己写代码才能完成但是python却不需要通过垃圾回收机制自动管理"""1.引用计数nam......
  • python垃圾回收机制与流程控制
    垃圾回收机制有一些语言,内存空间的申请和清除都需要程序员自己写代码才可以完成,但是在python中却不需要,通过垃圾回收机制自动管理1.引用计数name='lizhi'表示数......
  • 垃圾回收机制与流程控制
    垃圾回收机制与流程控制目录垃圾回收机制与流程控制一、垃圾回收机制1.为什么要用垃圾回收机制2.垃圾回收机制的原理分析二、流程控制理论1.顺序结构2.分支结构3.循环结......
  • 流程控制-垃圾回收机制
    垃圾回收机制与流程控制垃圾回收机制引用计数数据值身上的引用计数name='123'#引用计数为1name1=name#引用计数+1delname1#引用计数-1'''数据值每多......
  • 垃圾回收机制与流程控制
    垃圾回收机制与流程控制1.垃圾回收机制引用计数数据值被引用的数量eg:name='timi'#数据值timi身上的引用计数为1name1=name#timi身上的引用计数为2当数据......