linux pm runtime
pm runtime核心只提供机制(功能), 什么的时候上电/掉电等策略应由driver去实现。 driver里实现的pm runtime的call back函数被runtime 核心封装了起来,会暴露一些API接口来间接的调用这么Call back函数。pm runtime利用了一个工作队列pm_wq来负责具体的电源事务,上电和下电有同步和异步之分:设备状态在PM runtime中的表示
pm runtime核心只提供机制(功能), 什么的时候上电/掉电等策略应由driver去实现。 driver里实现的pm runtime的call back函数被runtime 核心封装了起来,会暴露一些API接口来间接的调用这么Call back函数。
pm runtime利用了一个工作队列pm_wq来负责具体的电源事务,上电和下电有同步和异步之分:
设备状态在PM runtime中的表示
enum rpm_status {
RPM_ACTIVE = 0,
RPM_RESUMING,
RPM_SUSPENDED,
RPM_SUSPENDING,
};
用于电源请求的类型,当工作队列执行一个work时,会判断请求的类型,从而执行不同的函数(rpm_idle, rpm_suspend, rpm_resume)
enum rpm_request {
RPM_REQ_NONE = 0,
RPM_REQ_IDLE,
RPM_REQ_SUSPEND,
RPM_REQ_AUTOSUSPEND,
RPM_REQ_RESUME,
};
device_register->device_init->deviec_pm_init->pm_runtime_init
void pm_runtime_init(struct device *dev) {
dev->power.runtime_status = RPM_SUSPENDED; //设备默认是SUSPEND状态,和设备的实际状态可能不一样
dev->power.idle_notification = false;
dev->power.disable_depth = 1; //设备的PM runtime 默认是禁止的
atomic_set(&dev->power.usage_count, 0);
dev->power.runtime_error = 0;
atomic_set(&dev->power.child_count, 0);
pm_suspend_ignore_children(dev, false);
dev->power.runtime_auto = true; //这里的auto指得是是否开启runtime
dev->power.request_pending = false;
dev->power.request = RPM_REQ_NONE;
dev->power.deferred_resume = false;
dev->power.accounting_timestamp = jiffies;
INIT_WORK(&dev->power.work, pm_runtime_work); //当向pm_wq工作队列提交一个工作时,将会执行pm_runtime_work函数
dev->power.timer_expires = 0;
setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn, //延时提交一个电源事件的定时器函数
(unsigned long)dev);
init_waitqueue_head(&dev->power.wait_queue);
}
static void pm_runtime_work(struct work_struct *work)
{
struct device *dev = container_of(work, struct device, power.work);
enum rpm_request req;
spin_lock_irq(&dev->power.lock);
if (!dev->power.request_pending)
goto out;
req = dev->power.request;
dev->power.request = RPM_REQ_NONE;
dev->power.request_pending = false;
switch (req) { //根据请求的类型,执行不同的核心函数, rpm_idle, rpm_suspend, rpm_resume应该是PM runtime的三个核心函数,其它的外部API都是基于这三个
函数实现的 + 定时器 + 其它的逻辑判断, 而三个核心函数的实现则是基于工作队列pm_wq来实现异步操作的
case RPM_REQ_NONE:
break;
case RPM_REQ_IDLE:
rpm_idle(dev, RPM_NOWAIT);
break;
case RPM_REQ_SUSPEND:
rpm_suspend(dev, RPM_NOWAIT); //注意,这里的函数都是同步的,也就是直接调用相应的Call back函数的,如果这里也是异步调用的话,那Call back函数应该不会被执行到
break;
case RPM_REQ_AUTOSUSPEND:
rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO);
break;
case RPM_REQ_RESUME:
rpm_resume(dev, RPM_NOWAIT);
break;
}
out:
spin_unlock_irq(&dev->power.lock);
}
static void pm_suspend_timer_fn(unsigned long data) //auto-suspend的定时器函数
{
struct device *dev = (struct device *)data;
unsigned long flags;
unsigned long expires;
spin_lock_irqsave(&dev->power.lock, flags);
expires = dev->power.timer_expires;
/* If 'expire' is after 'jiffies' we've been called too early. */
if (expires > 0 && !time_after(expires, jiffies)) {
dev->power.timer_expires = 0;
rpm_suspend(dev, dev->power.timer_autosuspends ? //向pm_wq工作队列提交一个异步的suspend工作.
(RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
}
spin_unlock_irqrestore(&dev->power.lock, flags);
}
pm_runtime_put_sync_suspend(dev)
-->__pm_runtime_suspend(dev, RPM_GET_PUT) //没有指定RPM_ASYNC标志,默认是同步
-->rpm_suspend
static int rpm_suspend(struct device *dev, int rpmflags) {
...
repeat:
retval = rpm_check_suspend_allowed(dev); //会检查一下是否允许设备suspend.
if (retval < 0)
; /* Conditions are wrong. */
/* Synchronous suspends are not allowed in the RPM_RESUMING state. */
else if (dev->power.runtime_status == RPM_RESUMING &&
!(rpmflags & RPM_ASYNC))
retval = -EAGAIN;
if (retval)
goto out
...
/* Carry out an asynchronous or a synchronous suspend. */
if (rpmflags & RPM_ASYNC) { //异步
dev->power.request = (rpmflags & RPM_AUTO) ?
RPM_REQ_AUTOSUSPEND : RPM_REQ_SUSPEND;
if (!dev->power.request_pending) {
dev->power.request_pending = true;
queue_work(pm_wq, &dev->power.work); //向工作队列提交一个work
}
goto out; //异步的话就直接退出了
}
if (dev->pm_domain) // 回调函数的选择: domain->type->class->bus.
callback = dev->pm_domain->ops.runtime_suspend;
else if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_suspend;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_suspend;
else if (dev->bus && dev->bus->pm) /*以platform_bus为例,它的dev_pm_ops为platform_dev_pm_ops, 定义为
static const struct dev_pm_ops platform_dev_pm_ops = {
.runtime_suspend = pm_generic_runtime_suspend, //该函数会判断driver里的dev_pm_ops有没有被实现,如果有的话,调用driver的回调函数
.runtime_resume = pm_generic_runtime_resume,
.runtime_idle = pm_generic_runtime_idle, //如果设备的driver定义了相应的runtime_idle函数,调用之,如果没有出错的话,在调用pm_runtime_suspend(同步版本)
USE_PLATFORM_PM_SLEEP_OPS
};
*/
callback = dev->bus->pm->runtime_suspend;
else
callback = NULL;
if (!callback && dev->driver && dev->driver->pm) //driver的pm runtime回调
callback = dev->driver->pm->runtime_suspend;
retval = rpm_callback(callback, dev); //执行回调函数
if (retval)
goto fail;
no_callback:
__update_runtime_status(dev, RPM_SUSPENDED);
pm_runtime_deactivate_timer(dev);
if (dev->parent) {
parent = dev->parent;
atomic_add_unless(&parent->power.child_count, -1, 0); //子设备已经下电, 减少父设备的child_count计数器, 每个设备有自己的使用计数器和子设备的active计数
...
/* Maybe the parent is now able to suspend. */
if (parent && !parent->power.ignore_children && !dev->power.irq_safe) { //如果父设备的子设备都已经suspend,尝试关掉父设备,一直递归上去
spin_unlock(&dev->power.lock);
spin_lock(&parent->power.lock);
rpm_idle(parent, RPM_ASYNC);
spin_unlock(&parent->power.lock);
spin_lock(&dev->power.lock);
}
}
static int rpm_check_suspend_allowed(struct device *dev)
{
int retval = 0;
if (dev->power.runtime_error)
retval = -EINVAL;
else if (dev->power.disable_depth > 0) //通过__pm_runtime_disable来暂时禁用runtime
retval = -EACCES;
else if (atomic_read(&dev->power.usage_count) > 0) //设备正在使用中
retval = -EAGAIN;
else if (!pm_children_suspended(dev)) //子设备还在使用中,父设备不能suspend,除非父设备自身设定了ignore_children标志
retval = -EBUSY;
/* Pending resume requests take precedence over suspends. */ //resume过程的优先级高点。。。
else if ((dev->power.deferred_resume
&& dev->power.runtime_status == RPM_SUSPENDING)
|| (dev->power.request_pending
&& dev->power.request == RPM_REQ_RESUME))
retval = -EAGAIN;
else if (__dev_pm_qos_read_value(dev) < 0)
retval = -EPERM;
else if (dev->power.runtime_status == RPM_SUSPENDED) //设备已经suspend过了
retval = 1;
return retval;
}
一个API的调用,会引发一连串的函数调用和影响。。。
更多推荐
所有评论(0)