电源管理--Runtime

单独关闭某一设备

Runtime运行流程

RPM的核心机制是这样的:

  • 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设备,否则,虽然起始想要suspend,但设备实际只会idle空闲,不会挂起。

可以不提供,RPM core会使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_suspend回调函数,suspend设备,同时记录设备的PM状态;

idle空闲时间是否应立即suspend以节省功耗?不一定,要具体场景具体对待:例如网络传输,如果网络连接正常,那么在可预期的、很短的时间内,设备又会active(传输网络数据),如果频繁suspend,会降低性能,且不会省电;比如用户按键,具有突发性,因而可以考虑suspend;等等。

可以调用RPM core提供helper函数(pm_runtime_autosuspend_expiration、pm_runtime_autosuspend、pm_request_autosuspend),要求在指定的时间后,suspend设备。

  • 5)pm_runtime_autosuspend、pm_request_autosuspend等接口,会起一个timer(定时器,为防止设备被频繁的开关,在timer到时候,才会执行suspend),并在timer到期后,使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_suspend回调函数,suspend设备,同时记录设备的PM状态。

  • 6)每一次get,RPM core都会判断设备的PM状态,如果不是active,则会使用异步(ASYNC)或同步(SYNC)的方式,调用设备的.runtime_resume回调函数,resume设备。如果设备已经是RPM_ACTIVE,就没必要再次resume,直接返回,如果设备处于RPM_RESUMING/RPM_SUSPENDING, 等待该操作完成,

注1:Runtime PM中的“suspend”,不一定要求设备必须进入低功耗状态,而是要求设备在suspend后,不再处理数据,不再和CPUs、RAM进行任何的通信,直到设备的.runtime_resume被调用。因为当设备suspend后,它的通信对象CPU、RAM等,都有可能因为suspend而不再工作,如果设备再有任何动作,都会造成不可预期的异常。

resume执行调用顺序

suspend执行调用顺序

异步(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回调函数,不过,后果自负!

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正在被执行。

注:前面说过,.runtime_idle只是suspend前的过渡,因此runtime status和idle无关。

device注册时,设备模型代码会调用pm_runtime_init接口,将设备的runtime status初始化为RPM_SUSPENDED,而kernel并不知道某个设备初始化时的真正状态,因此设备驱动需要根据实际情况,调用RPM的helper函数,将自身的status设置正确。

驱动

修改驱动程序和使用

参考内核驱动示例: drivers\input\misc\bma150.c

2.1 在dev_pm_ops里提供3个回调函数: runtime_suspend, runtime_resume, runtime_idle

2.2 对于runtime PM,默认状态下设备的状态是suspended, 如果硬件上它是运行状态,需要调用pm_runtime_set_active()来修改它的状态,然后调用pm_runtime_enable()来使能runtime PM

一般是在probe函数里调用上述函数

2.3 在对应的系统调用接口里调用: pm_runtime_get / pm_runtime_put : 增加/减小计数值, 并且让设备处于resume或suspend状态

2.4 在remove函数里调用pm_runtime_disable()

前提: 配置内核支持runtime PM

make menuconfig

Power management options --->

[*] Run-time PM core functionality

手动echo文件,启动或关闭设备

使用:

使设备处于active状态

echo on > /sys/devices/platform/runtime_device/power/control

使设备进入suspend状态

echo auto > /sys/devices/platform/runtime_device/power/control

在系统调用接口中开启或关闭runtime

相关函数

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状态设置正确。

猜你喜欢

转载自blog.csdn.net/qq_52353238/article/details/129780591