1 Star 0 Fork 1

watermelon / Linux_drivers_framework_doc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Linux电源管理Run-time PM 详解 29.66 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
from  www.wowotech.net
-------------------------------
Runtime PM(简称RPM)
-------------------------------
推崇使用RPM进行日常的动态电源管理, 而不是suspend机制。
软件工程的基本思想就是模块化:高内聚和低耦合。
通俗地讲,就是“各人自扫门前雪”, 尽量扫好自己的(高内聚),尽量不和别人交互(低耦合)。
而RPM正体现了这一思想:每个设备(包括CPU)都处理好自身的电源管理工作,尽量以最低的能耗完成交代的任务,
尽量在不需要工作的时候进入低功耗状态, 尽量不和其它模块有过多耦合。
每个设备都是最节省的话,整个系统一定是最节省的状态。
-------------------------------
Runtime PM的软件框架
-------------------------------
     RPM代码,也就是drivers/base/power/runtime.c中1400行而已。
--------------------------------------------------------------------------------------------
|Runtime PM Core|
pm_runtime_put_xxx
pm_runtime_get_xxx
-↓↑--↓(control driver's power state)---------------↑(tell driver's running state)-----------
↓↑ |xxxx driver|  
↓↑
↓↑ .runtime_suspend
↓↑ .runtime_resume
↓↑ .runtime_idle
↓↑
-↓↑-------------↑↓--------------------------------------------------------------------------
|device model|
dev_pm_ops
--------------------------------------------------------------------------------------------
Runtime PM的软件框架:
//
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,以节省功耗。
//
好吧,说总是简单,那做呢?
很不幸,到目前为止,linux kernel的runtime PM还是很复杂。
这里的复杂,不是从实现的角度,而是从对外的角度。
在“include\linux\pm_runtime.h”中,RPM提供了将近50个接口。
软件模块化的设计理念中,最重要的一个原则, 就是提供简洁的接口。 很显然,RPM没有做到!
//
无论RPM面对的问题有多么复杂,无论理由有多么充分,它也应坚守“简洁性”这一原则。否则,结果只有一个----无人敢用。
这就是当前Linux kernel电源管理中“Opportunistic suspend”和RPM两种机制并存的原因。
但是,就算现状不理想,也不能否认RPM的先进性,在当前以及未来很长的一段时间内,它会是kernel电源管理更新比较活跃的部分,因为可以做的还很多。
//
鉴于这个现状,本文以及后续RPM有关的文章,会选取kernel(当前为linux-3.17),以便及时同步相关的更新。
---------------------------
3. Runtime PM的运行机制
---------------------------
3.1 核心机制
1)为每个设备维护一个引用计数(device->power.usage_count),用于指示该设备的使用状态。
2)需要使用设备时,device driver调用pm_runtime_get(或pm_runtime_get_sync)接口,增加引用计数;
  不再使用设备时,device driver调用pm_runtime_put(或pm_runtime_put_sync)接口,减少引用计数。
3)每一次put,RPM core都会判断引用计数的值。如果为零,表示该设备不再使用(idle)了,则
         使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_idle回调函数。
4).runtime_idle的存在,是为了在idle和suspend之间加一个缓冲?, 避免频繁的suspend/resume操作。
    因此它的职责是:判断设备是否具备suspend的条件,如果具备,在合适的时机,suspend设备。
可以不提供,RPM core会使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_suspend回调函数,suspend设备,同时记录设备的PM状态;
可以调用RPM core提供的helper函数(
pm_runtime_autosuspend_expiration、
pm_runtime_autosuspend、
pm_request_autosuspend),
要求在指定的时间后,suspend设备。
5)pm_runtime_autosuspend、pm_request_autosuspend等接口,会起一个timer,并在timer到期后,使用异步(ASYNC)或同步(SYNC)的方式,
    调用设备的.runtime_suspend回调函数,suspend设备,同时记录设备的PM状态。
6)每一次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”中的解释,供大家参考:
* Once the subsystem-level suspend callback (or the driver suspend callback,
if invoked directly) has completed successfully for the given device, the PM
core regards the device as suspended, which need not mean that it has been
put into a low power state. It is supposed to mean, however, that the
device will not process data and will not communicate with the CPU(s) and
RAM until the appropriate resume callback is executed for it. The runtime
PM status of a device after successful execution of the suspend callback is
'suspended'.
注2:
回忆一下wakeup events和wakeup lock,  
Runtime PM和它们在本质上是一样的,都是实时的向PM core报告“我不工作了,可以睡了”、“我要工作了,不能睡(或醒来吧)”。
不同的是:wakeup events和RPM的报告者是内核空间drivers,
      而wakeup lock是用户空间进程;
wakeup events和wakelock涉及的睡眠对象是整个系统,包括CPU和所有的devices,
而RPM是一个一个独立的device(CPU除外,它由cpu idle模块处理,可看作RPM的特例)。
3.2 get和put的时机
这个话题的本质是:device idle的判断标准是什么?
再回忆一下“autosleep”中有关“Opportunistic suspend”的讨论,
对“Opportunistic suspend”而言,suspend时机的判断是相当困难的,因为整机的运行环境比较复杂。
而每一个具体设备的idle,就容易多了(YES), 这就是Runtime PM的优势。
回到这个话题上,对device而言,什么是idle?
device是通过用户程序为用户提供服务的,而服务的方式分为两种:
接受指令,做事情(被动);
上报事件(主动,一般通过中断的方式)。
因此,设备active的时间段,包括【接受指令,完成指令】和【事件到达,由driver记录下来】两个。
除此之外的时间,包括driver从用户程序获得指令(以及相关的数据)、driver将事件(以及相关的数据)交给应用程序,都是idle时间。
那idle时间是否应立即suspend以节省功耗?不一定,要具体场景具体对待:例如网络传输,如果网络连接正常,那么在可预期的、很短的时间内,设备又会active(传输网络数据),如果频繁suspend,会降低性能,且不会省电;比如用户按键,具有突发性,因而可以考虑suspend;等等。
由于get和put正是设备idle状态的切换点,因此get和put的时机就容易把握了:
1)主动访问设备时,如写寄存器、发起数据传输等等,get,增加引用计数,告诉RPM core设备active;访问结束后,put,减小引用计数,告诉RPM core设备可能idle。
2)设备有事件通知时,get(可能在中断处理中);driver处理完事件后,put。
注3:以上只是理论场景,实际可以放宽,以减小设计的复杂度。
3.3 异步(ASYNC)和同步(SYNC)
设备驱动代码可在进程和中断两种上下文执行,因此put和get等接口,要么是由用户进程调用,要么是由中断处理函数调用。
由于这些接口可能会执行device的.runtime_xxx回调函数,而这些接口的执行时间是不确定的,
有些可能还会睡眠等待。这对用户进程或者中断处理函数来说,是不能接受的。
因此,RPM core提供的默认接口(pm_runtime_get/pm_runtime_put等),采用异步调用的方式(由ASYNC flag表示),启动一个work queue,
在单独的线程中,调用.runtime_xxx回调函数,这可以保证设备驱动之外的其它模块正常运行。
另外,如果设备驱动清楚地知道自己要做什么,也可以使用同步接口(pm_runtime_get_sync/pm_runtime_put_sync等),它们会直接调用.runtime_xxx回调函数,不过,后果自负!
-----------------------------------
3.4 Runtime PM过程中的同步问题
-----------------------------------
由于.runtime_xxx回调函数可能采用异步的形式调用,以及Generic PM suspend和RPM并存的现状,要求RPM要小心处理同步问题,包括:
多个.runtime_suspend请求之间的同步;
多个.runtime_resume请求之间的同步;
多个.runtime_idle请求之间的同步;
.runtime_suspend请求和.runtime_resume请求之间的同步;
.runtime_suspend请求和system suspend之间的同步;
.runtime_resume请求和system resume之间的同步;
等等。
由此可知,RPM core将会有相当一部分代码,用来处理同步问题。
-----------------------------------
3.5 级联设备之间的Runtime PM
-----------------------------------
struct device结构中,有一个parent指针,指向该设备的父设备(没有的话为空)。父设备通常是Bus、host controller,设备的正常工作,依赖父设备。体现在RPM中,就是如下的行为:
1)parent设备下任何一个设备处于active状态,parent必须active。
2)parent设备下任何一个设备idle了,要通知parent,parent以此记录处于active状态的child设备个数。
3)parent设备下所有子设备都idle了,parent才可以idle。
以上行为RPM core会自动处理,不需要驱动工程师太过操心。
-----------------------------------
3.6 device的runtime status及其初始状态
-----------------------------------
在Runtime Power Management的过程中,device可处于四种状态:RPM_ACTIVE、RPM_RESUMING、RPM_SUSPENDED和RPM_SUSPENDING。
RPM_ACTIVE,设备处于正常工作的状态,表示设备的.runtime_resume回调函数执行成功;
RPM_SUSPENDED,设备处于suspend状态,表示设备.runtime_suspend回调函数执行成功;
RPM_RESUMING,设备的.runtime_resume正在被执行;
RPM_SUSPENDING,设备的.runtime_suspend正在被执行。
注4:前面说过,.runtime_idle只是suspend前的过渡,因此runtime status和idle无关。
device注册时,设备模型代码会调用pm_runtime_init接口,将设备的runtime status初始化为RPM_SUSPENDED,而kernel并不知道某个设备初始化时的真正状态,因此设备驱动需要根据实际情况,调用RPM的helper函数,将自身的status设置正确。
-----------------------------------
4. runtime PM的API汇整
-----------------------------------
RPM提供的API位于“include/linux/pm_runtime.h”中,在这里先浏览一下,
目的有二:一是对前面描述的RPM运行机制有一个感性的认识;
       二是为后面分析RPM的运行机制做准备。
注5:我会把和驱动编写相关度较高的API加粗,其它的能不用就不用、能不看就不看!
extern int __pm_runtime_idle(struct device *dev, int rpmflags);
extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
extern int __pm_runtime_resume(struct device *dev, int rpmflags);
这三个函数是RPM的idle、put/suspend、get/resume等操作的基础,
根据rpmflag,有着不同的操作逻辑。 后续很多API,都是基于它们三个。 一般不会在设备驱动中直接使用。
extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
在指定的时间后(delay,单位是ms),suspend设备。该接口为异步调用,不会更改设备的引用计数,可在driver的.rpm_idle中调用,
免去driver自己再启一个timer的烦恼。
extern void pm_runtime_enable(struct device *dev);
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状态设置正确。
extern void pm_runtime_allow(struct device *dev);
extern void pm_runtime_forbid(struct device *dev);
RPM core通过sysfs(drivers/base/power/sysfs.c),为每个设备提供一个“/sys/devices/.../power/control”文件,
通过该文件可让用户空间程序直接访问device的RPM功能。 这两个函数用来控制是否开启该功能(默认开启)。
extern int pm_runtime_barrier(struct device *dev);
这名字起的!
由3.3的描述可知,很多RPM请求都是异步的,这些请求会挂到一个名称为“pm_wq”的工作队列上,
这个函数的目的,就是清空这个队列,另外如果有resume请求,同步等待resume完成。
好复杂,希望driver永远不要用到它!!
extern int pm_generic_runtime_idle(struct device *dev);
extern int pm_generic_runtime_suspend(struct device *dev);
extern int pm_generic_runtime_resume(struct device *dev);
几个通用的函数,一般给subsystem的RPM driver使用,直接调用devie driver的相应的callback函数。
extern void pm_runtime_no_callbacks(struct device *dev);
告诉RPM core自己没有回调函数,不用再调用了(或者调用都是成功的),真啰嗦。
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()
static inline int pm_runtime_idle(struct device *dev)
static inline int pm_runtime_suspend(struct device *dev)
static inline int pm_runtime_resume(struct device *dev)
直接使用同步的方式,尝试idle/suspend/resume设备,如果条件许可,就会执行相应的callback函数。driver尽量不要使用它们。
static inline int pm_request_idle(struct device *dev)
static inline int pm_request_resume(struct device *dev)
和上面类似,不过调用方式为异步。尽量不要使用它们。
static inline int pm_runtime_get(struct device *dev)
static inline int pm_runtime_put(struct device *dev)
增加/减少设备的使用计数,并判断是否为0,如果为零,尝试调用设备的idle callback,如果不为零,尝试调用设备的resume callback。
这两个接口是RPM的正统接口啊,多多使用!
static inline int pm_runtime_get_sync(struct device *dev)
static inline int pm_runtime_put_sync(struct device *dev)
static inline int pm_runtime_put_sync_suspend(struct device *dev)
和上面类似,只不过为同步调用。 另外提供了一个可直接调用suspend的put接口,何必的!
static inline int pm_runtime_autosuspend(struct device *dev)
static inline int pm_request_autosuspend(struct device *dev)
static inline int pm_runtime_put_autosuspend(struct device *dev)
static inline int pm_runtime_put_sync_autosuspend(struct device *dev)
autosuspend相关接口。所谓的autosuspend,就是在suspend的基础上,增加一个timer,还是觉得有点啰嗦。不说了。
static inline void pm_runtime_use_autosuspend(struct device *dev)
static inline void pm_runtime_dont_use_autosuspend(struct device *dev)
extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
控制是否使用autosuspend功能,以及设置/获取autosuspend的超时值。
总结一下:总觉得这些API所提供的功能有些重叠,重叠的有点啰嗦。
5. runtime PM的使用步骤
觉得上面已经讲了,就不再重复了。
-----------------------------------------------------------------------------------------
2.
-----------------------------------------------------------------------------------------
Run-time PM 详解
每个device或者bus, 都会向run-time PM core注册3个callback:
struct dev_pm_ops {
...
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
...
};
每个device或者bus都会有2个计数器:
一个是device的usage counter,
一个是device的active 状态的children个数(why 儿?)。
当这个device的两个counter都减少为0的时候, run-time PM core就会去调用runtime_idle函数,但是这idle函数可不是当前device的idle函数:
代码如下:
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->bus->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
} else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->type->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
} else if (dev->class && dev->class->pm && dev->class->pm->runtime_idle) {
spin_unlock_irq(&dev->power.lock);
dev->class->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
}
按照dev->bus, dev->type, dev->class的顺序去调用,
//
那么,疑问了,那runtime_suspend函数什么时候调用?
runtime_suspend函数不会被RPM core主动去调用,一般情况下是在bus,或者class的idle函数里去调用。
例如:
static int xxx_runtime_idle(struct device *dev)
{
return pm_schedule_suspend(dev, 50);
}
//pm_schedule_suspend函数会去调用device里的suspend函数,调用顺序代码如下:
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->bus->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->type && dev->type->pm
&& dev->type->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->type->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->class && dev->class->pm
&& dev->class->pm->runtime_suspend) {
spin_unlock_irq(&dev->power.lock);
retval = dev->class->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else {
retval = -ENOSYS;
}
发现了吧,和idle顺序是一模一样哒。当然肯定也会有不一样了,否则runtime_suspend函数没存在意义了。
在跑完此dev的bus or type or class的suspend函数以后。
紧接着会做一个巨艰巨的任务,就是
if (parent && !parent->power.ignore_children) {
spin_unlock_irq(&dev->power.lock);
pm_request_idle(parent);
spin_lock_irq(&dev->power.lock);
}
会去调用当前这个device的parent device的idle函数!!!
之后会去递归的往上层调用。为啥会这么做呢???
其实RPM机制总体来说就是管理总线结构和主次设备结构的电源。
假如一个bus上有2个device。
这个bus首先会有一个bus_type,其次还会有一个代表bus的device(谁说bus不是device了!)
首先命名以下,bus device叫做Bdev,
两个bus上的子device是dev1, dev2。
dev1,dev2是Bdev的子设备,也就是说dev1,dev2的parent是Bdev。
其中bus_type里会有一套runtime_pm的3个callback,Bdev自身还有另一套runtime_pm的三个callback。
当dev1的两个counter都为零了,就会调用bus_type里的runtime_idle,一般情况下这个idle会调用pm_runtime_suspend,仅按照上面的介绍,
就会调用这个bus_type里的runtime_suspend call back。
之后是不是就该是最重要的那一步了?pm_request_idle(parent);
pm_request_idle里的一系列操作会首先判断parent的两个counter是否为零了,因为dev2还活着呢,所以条件不满足,返回!
当dev2也来这么一套之后,再调用pm_request_idle(parent);的时候,Bdev里的runtime_idle就能跑啦。
总结一下,
bus_type的runtime_系列回调函数是用来处理bus上的device函数的。而bus自己的device的函数是用来处理自己的。
因为体系结构的因素,bus套bus的情况,最后就会形成一个device大树。
runtime这套机制就可以从根到树顶都能管理得到。
比如:I2C device挂在I2C bus上,I2C bus controller是PCI的一个设备,因为挂在PCI上。
这个PCI bus一般还是在南桥上,然后再通过南桥在跑到北桥PCI上。。。。
是不是疯了...但是有这么个递归电源管理,一切搞定...
说完了睡的流程,
-----------------------------------------------------------------------------------
还有醒的流程:
当device调用完suspend函数后,这个device就处于了一个suspended状态。
当某个device被唤醒后,就会调用pm_runtime_get_sync类似的函数。
这个函数做了啥呢? 通过上述的睡过程,有点脑子的人就能想出醒流程,反着来呗!!!必须从大树顶往下跑,才能最后让根伸出来。
代码如下:
if (!parent && dev->parent) {
/*
* Increment the parent's resume counter and resume it if
* necessary.
*/
parent = dev->parent;
spin_unlock(&dev->power.lock);
pm_runtime_get_noresume(parent);
spin_lock(&parent->power.lock);
/*
* We can resume if the parent's run-time PM is disabled or it
* is set to ignore children.
*/
if (!parent->power.disable_depth
&& !parent->power.ignore_children) {
__pm_runtime_resume(parent, false);
if (parent->power.runtime_status != RPM_ACTIVE)
retval = -EBUSY;
}
spin_unlock(&parent->power.lock);
spin_lock(&dev->power.lock);
if (retval)
goto out;
goto repeat;
}
首先跑这个device的parent的resume函数。之后
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
spin_unlock_irq(&dev->power.lock);
retval = dev->bus->pm->runtime_resume(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->type && dev->type->pm
&& dev->type->pm->runtime_resume) {
spin_unlock_irq(&dev->power.lock);
retval = dev->type->pm->runtime_resume(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else if (dev->class && dev->class->pm
&& dev->class->pm->runtime_resume) {
spin_unlock_irq(&dev->power.lock);
retval = dev->class->pm->runtime_resume(dev);
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
} else {
retval = -ENOSYS;
}
跑的是bus的resume函数。通过这个函数进行递归,直到递归到树顶后,树顶的resume就开始run了,run完一个往下面继续传,直到我们的这一连串device的resume函数都跑完,我们的device就算醒了。
RPM常用接口如下:
void pm_runtime_init(struct device *dev);
- initialize the device run-time PM fields in 'struct dev_pm_info'
void pm_runtime_remove(struct device *dev);
- make sure that the run-time PM of the device will be disabled after
removing the device from device hierarchy
int pm_runtime_idle(struct device *dev);
- execute the subsystem-level idle callback for the device; returns 0 on
success or error code on failure, where -EINPROGRESS means that
->runtime_idle() is already being executed
int pm_runtime_suspend(struct device *dev);
- execute the subsystem-level suspend callback for the device; returns 0 on
success, 1 if the device's run-time PM status was already 'suspended', or
error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt
to suspend the device again in future
int pm_runtime_resume(struct device *dev);
- execute the subsystem-level resume callback for the device; returns 0 on
success, 1 if the device's run-time PM status was already 'active' or
error code on failure, where -EAGAIN means it may be safe to attempt to
resume the device again in future, but 'power.runtime_error' should be
checked additionally
int pm_request_idle(struct device *dev);
- submit a request to execute the subsystem-level idle callback for the
device (the request is represented by a work item in pm_wq); returns 0 on
success or error code if the request has not been queued up
int pm_schedule_suspend(struct device *dev, unsigned int delay);
- schedule the execution of the subsystem-level suspend callback for the
device in future, where 'delay' is the time to wait before queuing up a
suspend work item in pm_wq, in milliseconds (if 'delay' is zero, the work
item is queued up immediately); returns 0 on success, 1 if the device's PM
run-time status was already 'suspended', or error code if the request
hasn't been scheduled (or queued up if 'delay' is 0); if the execution of
->runtime_suspend() is already scheduled and not yet expired, the new
value of 'delay' will be used as the time to wait
int pm_request_resume(struct device *dev);
- submit a request to execute the subsystem-level resume callback for the
device (the request is represented by a work item in pm_wq); returns 0 on
success, 1 if the device's run-time PM status was already 'active', or
error code if the request hasn't been queued up
void pm_runtime_get_noresume(struct device *dev);
- increment the device's usage counter
int pm_runtime_get(struct device *dev);
- increment the device's usage counter, run pm_request_resume(dev) and
return its result
int pm_runtime_get_sync(struct device *dev);
- increment the device's usage counter, run pm_runtime_resume(dev) and
return its result
void pm_runtime_put_noidle(struct device *dev);
- decrement the device's usage counter
int pm_runtime_put(struct device *dev);
- decrement the device's usage counter, run pm_request_idle(dev) and return
its result
int pm_runtime_put_sync(struct device *dev);
- decrement the device's usage counter, run pm_runtime_idle(dev) and return
its result
void pm_runtime_enable(struct device *dev);
- enable the run-time PM helper functions to run the device bus type's
run-time PM callbacks described in Section 2
int pm_runtime_disable(struct device *dev);
- prevent the run-time PM helper functions from running subsystem-level
run-time PM callbacks for the device, make sure that all of the pending
run-time PM operations on the device are either completed or canceled;
returns 1 if there was a resume request pending and it was necessary to
execute the subsystem-level resume callback for the device to satisfy that
request, otherwise 0 is returned
void pm_suspend_ignore_children(struct device *dev, bool enable);
- set/unset the power.ignore_children flag of the device
int pm_runtime_set_active(struct device *dev);
- clear the device's 'power.runtime_error' flag, set the device's run-time
PM status to 'active' and update its parent's counter of 'active'
children as appropriate (it is only valid to use this function if
'power.runtime_error' is set or 'power.disable_depth' is greater than
zero); it will fail and return error code if the device has a parent
which is not active and the 'power.ignore_children' flag of which is unset
void pm_runtime_set_suspended(struct device *dev);
- clear the device's 'power.runtime_error' flag, set the device's run-time
PM status to 'suspended' and update its parent's counter of 'active'
children as appropriate (it is only valid to use this function if
'power.runtime_error' is set or 'power.disable_depth' is greater than
zero)
bool pm_runtime_suspended(struct device *dev);
- return true if the device's runtime PM status is 'suspended', or false
otherwise
void pm_runtime_allow(struct device *dev);
- set the power.runtime_auto flag for the device and decrease its usage
counter (used by the /sys/devices/.../power/control interface to
effectively allow the device to be power managed at run time)
void pm_runtime_forbid(struct device *dev);
- unset the power.runtime_auto flag for the device and increase its usage
counter (used by the /sys/devices/.../power/control interface to
effectively prevent the device from being power managed at run time)
可以中断里跑的接口:
pm_request_idle()
pm_schedule_suspend()
pm_request_resume()
pm_runtime_get_noresume()
pm_runtime_get()
pm_runtime_put_noidle()
pm_runtime_put()
pm_suspend_ignore_children()
pm_runtime_set_active()
pm_runtime_set_suspended()
pm_runtime_enable()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mstar666/Linux_drivers_framework_doc.git
git@gitee.com:mstar666/Linux_drivers_framework_doc.git
mstar666
Linux_drivers_framework_doc
Linux_drivers_framework_doc
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891