一文搞懂Linux runtime pm

1, 介绍

Linux的Runtime PM(runtime power management)框架指的是运行时电源管理,设备在不运行时将自己的时钟、复位及电关闭(时钟的管理框架、regulator的管理框架之前的文章已经介绍,复位的管理框架后面会通过一篇文章来介绍),在使用的时候再打开。其目的是为了减少系统运行时的功耗。

与系统休眠唤醒式的电源管理相比,RPM采取的是分而治之的管理思想,将具体的功耗控制策略和控制权力给到各个驱动,在设备不需要工作时,可以进行相应的低功耗控制,这样既能保证系统可以正常工作,又能尽可能减少系统运行时的功耗。这里的设备有可能是外设,比如sensor、lcdc等。这里的设备也有可能是SOC内部的某些IP,比如codec、dsp、usb等。

SOC在设计的时候,为了尽可能减少运行功耗,会根据业务场景功能划分出一些power domain,一般power domain内部会包含若干功能IP,这样在不同场景下,可以根据需要尽可能地关闭不使用的power domain。其实,这些power domain也有相应的软件管理框架,rpm框架和pd的框架有很强的耦合关系,因此本文也会粗略的介绍一下pd框架,后面会通过一篇文章专门针对pd框架做介绍。

2, 框架

linux rpm框架

2.1 divers

Device drivers(包括bus、class、power domain)实现了runtime pm相关的runtime_idle/runtime_suspend/runtime_resume三个回调,runtime_suspend用于实现设备的低功耗操作,runtime_resume用于实现设备的低功耗恢复相关的操作,runtime_idle属于runtime_suspend的一个过渡,用于缓冲频繁的suspend与resume,它会判断设备是否具备suspend的条件,如果具备在合适的时机,就会suspend设备。

runtime_suspend与runtime_resume回调函数里会调用clock framework/reset framework/regulator framework提供的时钟开关、复位、电源开关的接口。

2.2 Runtime PM core

Runtime pm core主要提供了三类函数接口:

Runtime pm core会提供enable/disable接口给设备驱动,用于该设备驱动决定是否打开或关闭RPM,提供get、put类接口给设备驱动,用于决定什么时候进入或者恢复设备低功耗,在设备驱动调用了get、put接口后RPM会调用各设备驱动实现的runtime_suspend/runtime_resume接口。

对于决定设备是否进入低功耗的get/put接口的调用时机,一般会在操作设备相关寄存器前调用get接口,在操作完相关寄存器后调用put接口。或者在设备驱动的open、release、start、stop等接口里调用,用户层的services通过ioctrl或者驱动提供的文件节点调用驱动的这些接口。

  • RPM在driver中的开关接口

在驱动对设备进行初始化时,调用pm_rumtime_enable(),使能设备的runtime pm功能。当设备卸载的时候,在remove函数中调用pm_rumtime_disable(),关闭设备的runtime pm功能。对于该两个接口的实现:使用一个变量(dev->power.disable_depth)记录disable的深度。只要disable_depth大于零,就表示关闭RPM功能,此时RPM相关的API调用(如suspend/resume/put/get等)会返回失败EACCES。

RPM初始化时,会将所有设备的disable_depth置为1,也就是disable状态。driver初始化时,在probe函数的结尾会根据需要调用pm_rumtime_enable使能RPM,在驱动的remove函数中调用pm_rumtime_disable关闭RPM。

  • RPM get 操作类接口

当driver认为其设备需要进行工作(退出低功耗)时,调用pm_rumtime_get()/ pm_rumtime_get_sync (),向RPM core请求设备恢复正常,若条件满足,RPM core会执行到driver的runtime_resume回调函数,配置设备为工作的状态。

对于get操作接口的实现:每个设备都维护一个usage_count变量,用于记录该设备的使用情况。当大于0的时候说明该设备在使用,当该值从0变成非0时,会调用到设备驱动实现的runtime_resume回调,让设备退出低功耗状态。当等于0的时候说明该设备不再使用,当该值从非0变成0的时候,会调用到设备驱动实现的runtime_suspend回调,让设备进入低功耗状态。

该类接口总的有两类,通过名字可以直观地看出两类API的区别:对于pm_rumtime_get()用于异步操作,而pm_rumtime_get_sync ()用于同步操作。如果期望在执行get操作后立马访问设备,那么就使用pm_rumtime_get_sync ()接口,因为pm_rumtime_get()接口会把一些核心的操作放到一个工作队列(workqueue)中延后执行。

  • RPM put 操作

当driver认为其设备不需要进行工作(关闭)时,则调用pm_rumtime_put()/ pm_rumtime_put_sync (),向RPM core请求设备进入低功耗,若条件满足,RPM core会执行到driver的runtime_suspend回调函数,配置设备进入低功耗状态。

2.3 power domain framework

一个power domain上可能包含多个IP,每个IP可能对应一个或多个设备。这些设备会在dts中描述与power domain的绑定关系。系统初始化的时候,会将这个power domain放到一个链表中,然后根据设备中dts描述的与power domain的关系,将设备挂在power domain节点下的链表中。

当某个设备驱动通过put接口调用,将usage_count从1减少到0,这时会先调用power domain注册的runtime_suspend接口,在这个接口中,会先调用该设备驱动的runtime_suspend,然后遍历该power domain下所有的设备是否都允许suspend(各设备驱动的usage_count是否为0),若允许就会直接调用关闭power domian的接口,否则直接返回。当某个设备驱动通过get接口调用,将usage_count从0增加到1,这时会先调用power domain注册的runtime_resume接口,在这个接口中,会先将power domain上电,然后再调用设备驱动对应的runtime_resume回调函数,让设备退出低功耗。

2.4 runtime pm的sysfs

对于支持rpm的设备,在相应的设备节点下有多个rpm相关属性的文件节点,分别为control,runtime_susupend_time,runtime_active_time,autosuspend_delay_ms,runtime_status。

/sys/devices/.../power/control

  • on - 调用pm_runtime_forbid接口,增加设备的引用计数,然后resume设备。
  • auto - 调用pm_runtime_allow接口,减少设备的引用计数,如果设备的引用计数为0,则idle设备。

/sys/devices/.../power/runtime_status

  • active - 设备的状态是正常工作状态。
  • suspend- 设备的状态是低功耗模式。
  • suspending-设备的状态正在从active->suspend转化。
  • resuming-设备的状态正在从suspend->active转化。
  • error-设备runtime出现错误,此时runtime_error的标志置位。
  • unsupported-设备的runtime 没有使能,此时disable_depth标志置位。

/sys/devices/.../power/runtime_suspend_time

  • 设备在suspend状态的时间

/sys/devices/.../power/runtime_active_time

  • 设备在active状态的时间

/sys/devices/.../power/autosuspend_delay_ms

  • 设备在idle状态多久之后suspend,设置延迟suspend的延迟时间。

3, 数据结构

linux rpm数据结构

4, 流程

4.1 初始化过程中rpm相关操作流程

设备rpm初始化流程

4.2 remove过程中rpm相关操作流程

设备remove过程中rpm相关操作流程

4.3 shutdown过程中rpm相关操作流程

shutdown过程中rpm相关操作流程

4.4 休眠唤醒过程中rpm相关操作流程

休眠唤醒过程中rpm相关操作流程

4.5 工作流程

Runtime PM中主要有四个状态:

  • Active
  • Suspending
  • Suspended
  • Resuming

还有可能是reset、power on、power off几个基本的Power manager基本操作设备管理操作,还有在实际运行过程中使能设备中部分核心,关闭部分内核这种,这种都属于Power manager管理的部分。

具体的状态切换如下:

rpm状态切换图

pm_runtime_get

pm_runtime_put

(平时会分享linux技术干货文章,关注我可以定期收到相关文章的推送,知乎、微信同名:黑客与摄影师)

猜你喜欢

转载自blog.csdn.net/u012294613/article/details/132482521