Linux电源管理之RuntimePM模型
Linux电源管理之RuntimePM模型
前言
本文简述了runtime power management(RPM)的概念,分析RPM的软件框架,介绍运行机制。最后讲解修改驱动程序以支持RPM的步骤,在应用层如何使用等。
一、概念
Linux的Runtime PM(runtime power management)框架指的是运行时电源管理,设备在不运行时将自己的时钟、复位及电关闭,在使用的时候再打开。其目的是为了减少系统运行时的功耗。
问题来了:
怎样动态地打开或关闭设备的电源?
最简单的方法:
在驱动程序里,在open函数中打开电源,在close函数中关闭电源
上述方法有一个缺点: 多个APP使用该设备时可能造成干扰?
解决方法:给驱动添加使用计数值: 每当open一次就增加一次计数,close一次减少一次计数,当该计数大于0时打开电源, 等于0时关闭电源。便有了RPM的软件框架。
二、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。
-
RPM core会为每个device维护一个引用计数,get时增加计数值,put时减少计数值,当计数为0时,表明device不再被使用,可以立即或一段时间后suspend,以节省功耗。
三、Runtime PM的运行机制
1、核心机制
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设备。
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设备。
个人见解:
2、get和put的时机
由于get和put正是设备idle状态的切换点,因此get和put的时机就容易把握了:
1)主动访问设备时,如写寄存器、发起数据传输等等,get,增加引用计数,告诉RPM core设备active;访问结束后,put,减小引用计数,告诉RPM core设备可能idle。
2)设备有事件通知时,get(可能在中断处理中);driver处理完事件后,put。
3、异步和同步
RPM core提供的默认接口(pm_runtime_get/pm_runtime_put等),采用异步调用的方式(由ASYNC flag表示),启动一个work queue,在单独的线程中,调用.runtime_xxx回调函数,这可以保证设备驱动之外的其它模块正常运行。
另外,如果设备驱动清楚地知道自己要做什么,也可以使用同步接口(pm_runtime_get_sync/pm_runtime_put_sync等),它们会直接调用.runtime_xxx回调函数。
4、级联设备之间的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。
四、修改驱动程序和使用
1、应用层
如何使用runtime PM?
驱动程序提供接口, APP来调用
- echo on > /sys/devices/…/power/control
// 导致驱动程序调用
control_store -> pm_runtime_forbid(dev); :
atomic_inc(&dev->power.usage_count);
rpm_resume(dev, 0);
- echo auto > /sys/devices/…/power/control
// 导致驱动程序调用
control_store -> pm_runtime_allow(dev); :
atomic_dec_and_test(&dev->power.usage_count)C
rpm_idle(dev, RPM_AUTO);
2、驱动层
-
前提: 配置内核支持runtime PM
make menuconfig
Power management options —>
[*] Run-time PM core functionality
2.1、通用模板
-
在dev_pm_ops里提供3个回调函数: runtime_suspend, runtime_resume, runtime_idle
-
对于runtime PM,默认状态下设备的状态是suspended, 如果硬件上它是运行状态,需要调用pm_runtime_set_active()来修改它的状态
然后调用pm_runtime_enable()来使能runtime PM一般是在probe函数里调用上述函数
-
在对应的系统调用接口里调用: pm_runtime_get_sync / pm_runtime_put_sync : 增加/减小计数值, 并且让设备处于resume或suspend状态
-
在remove函数里调用pm_runtime_disable()
2.2、autosuspend功能
-
如果不想让设备频繁地开、关,可以使用autosuspend功能
驱动里: 执行pm_runtime_use_autosuspend来设置启动autosuspend功能,
put设备时, 执行这2个函数:
pm_runtime_mark_last_busy(&lcd_dev.dev);
pm_runtime_put_sync_autosuspend(&lcd_dev.dev); -
用户空间, 执行以下命令设置时间值:
echo 2000 > /sys/devices/platform/mylcd/power/autosuspend_delay_ms
五、实例
参考内核驱动示例: drivers\input\misc\bma150.c
参考资料
蜗窝科技-电源管理子系统
韦东山嵌入式第三期