详细的关于Runtime_PM相关的电源管理的介绍,在https://blog.youkuaiyun.com/longwang155069/article/details/53080667 这里面有详细的介绍。
首先要弄清楚一些状态信息
一、device power states
主要有以下几种,常用的是D0(正常状态)、D3(休眠状态)
D0 = 0, // Full On: full power, full functionality
D1, // Low Power On: fully functional at low power/performance
D2, // Standby: partially powered with automatic wake
D3, // Sleep: partially powered with device initiated wake
D4, // Off: unpowered
加一个C-State ---CPU状态
为了在CPU空闲时节约能源,可以使用命令让CPU进入低功耗模式。每个CPU都有几种功耗模式,它们统称为“C-State”或“C-模式”。在这篇文章中,我们将介绍这些模式的含义、其作用以及每个处理器支持的模式。
当CPU处于某种低功耗模式时所消耗的电量较少。
这些模式的基本理念是切断CPU内部的空闲部件的时钟信号和电源。停止(通过切断时钟)、降低电压或者甚至完全关闭的部件越多,节约的能源就越多,但是CPU需要更多时间才能“唤醒”并再次完全正常运行。
这些模式称为“C-State”。它们从C0开始编号,C0是正常的CPU操作模式,即CPU完全开启。C编号越高,CPU睡眠模式越深,也就是说关闭的电路和信号更多,CPU需要更多时间才能恢复到C0,即唤醒。
每个模式也都有自己的名称,其中许多模式都有具有不同省电等级的子模式,因此唤醒时间也不尽相同。
当前可用的所有C-State模式,模式C1到C3的工作方式基本上是切断CPU内使用的时钟信号,而模式C4到C6的工作方式是降低CPU电压。“增强”模式可以同时执行这两个操作。
二、system power states
standby //普通待机模式,为默认选项,对应ACPI state S1
mem //待机到内存,即内存之外把其他设备都进入低功耗模式,对应ACPI state S3
disk //待机到硬盘,即休眠,把电脑的当前状态保存到硬盘,几乎不消耗外部电源,对应ACPI state S4
off //通过调用系统的关机命令来休眠, 对应ACPI state S5
三、Device power management (来自内核文档 Document/power/devices.txt)
3.1、Two models for device power management
1,system sleep model
driver可以使用一种系统范围内的 low-power模式,suspend( to RAM or DISK)
2,Runtime power management model(RUNTIME_PM)
device也可以在系统running的时候设置为 low-power state,有时候子设备或者挂在bus上的一些设备不能孤立的被设置为low-power 状态,还需要一些相关的系统设置。
3.2、Interfaces for Entering System Sleep States
There are programming interfaces provided for subsystems (bus type, device type, device class) and device drivers to allow them to participate in the power management of devices they are concerned with.These interfaces cover both system sleep and runtime power management.
子系统级和设备驱动程序级的设备电源管理操作通过定义 struct dev_pm_ops 类型的对象来实现:
四、Runtime Power Management Framework for I/O Devices(来自内核文档 /Document/power/runtime_pm.txt)
4.1,introduction
通过以下方式在电源管理核心(PM核心)级别提供对I/O设备的运行时电源管理(运行时PM)的支持:
* 总线类型和设备驱动程序可以放置与pm相关的工作项到电源管理工作队列pm_wq中去(in which = where)。强烈建议使用pm_wq对与运行时pm相关的所有工作项进行排队,因为这允许它们与系统范围的电源转换(挂起到ram、休眠和从系统睡眠状态恢复)同步。
* “struct device”的“power”成员(类型为“struct dev_pm_info”,在include/linux/pm.h中定义)中的多个运行时pm字段,可用于相互同步运行时pm操作。
* 在 struct dev_pm_ops中定义了三个device runtime_pm的callback
4.2. Device Runtime PM Callbacks
There are three device runtime PM callbacks defined in 'struct dev_pm_ops':
struct dev_pm_ops { ...
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
int (*runtime_suspend)(struct device *dev); //suspend是深度睡眠
int (*runtime_resume)(struct device *dev); //resume表示恢复
int (*runtime_idle)(struct device *dev); //idle表示空闲
... };
*@.suspend: Executed before putting the system into a sleep state in which the contents of main memory are preserved.(在将系统置于睡眠状态(在睡眠状态下保留主内存的内容)之前执行。)在设备的子系统(PM域、设备类型、类或总线类型)上执行的确切操作结束,但通常在子系统级别@suspend()返回后,设备必须处于静止状态,这样它就不会执行任何I/O或DMA操作。在为所有设备调用子系统级@prepare()之后,将对所有设备执行子系统级@suspend()。
*@.resume: executed after waking the system up from a sleep state in which the contents of main memory were preserved.(在将系统从保存主内存内容的睡眠状态唤醒后执行。)要执行的确切操作取决于设备的子系统,但通常情况下,驱动程序需要重新开始工作,响应硬件事件和软件请求(设备本身可能处于低功耗状态,等待运行时恢复)。运行驱动程序@resume()回调时设备的状态取决于设备所属的平台和子系统。在大多数平台上,@resume()期间的时钟等资源的可用性没有限制。对所有设备调用子系统级@resume noirq()后,将对所有设备执行子系统级@resume()。
* @runtime_suspend: Prepare the device for a condition in which it won't be able to communicate with the CPU(s) and RAM due to power management.This need not mean that the device should be put into a low-power state. For example, if the device is behind a link which is about to be turned off, the device may remain at full power. If the device does go to low power and is capable of generating runtime wakeup events, remote wakeup (i.e., a hardware mechanism allowing the device to request a change of its power state via an interrupt) should be enabled for it.
* @runtime_resume: Put the device into the fully active state in response to a wakeup event generated by hardware or at the request of software. If necessary, put the device into the full-power state and restore its registers, so that it is fully operational.
*
* @runtime_idle: Device appears to be inactive and it might be put into a low-power state if all of the necessary conditions are satisfied. Check these conditions, and return 0 if it's appropriate to let the PM core queue a suspend request for the device.
->runtime_suspend()、->runtime_resume()和->runtime_idle()回调由设备子系统的pm core执行,该子系统可以是以下任一类型:
1、设备的pm域,如果设备的pm域对象dev->pm_domain存在。
2、设备类型,如果同时存在dev->type和dev->type->pm。
3、设备的设备类,如果dev->类和dev->类->pm都存在。
4、设备的总线类型,如果dev->bus和dev->bus->pm都存在。
注意这三个callback的执行有下列默认规则:
1、suspend和resume不能对一个device同时使用,
2、idle和suspend只能对active的设备使用
3、idle和susupend只能对usage counter是0的设备使用
4、resume只能对被suspend的device使用
5、如果对一个设备执行了suspend,就不能对他执行idle
4.6、Runtime PM and system sleep
Runtime PM and system sleep (i.e., system suspend and hibernation, also known as suspend-to-RAM and suspend-to-disk) interact with each other in a couple of ways.
五、声卡设备runtime_pm调试
5.1、何为runtime机制?也就是系统在非睡眠状态,设备在空闲时可以进入runtime suspend状态同时不依赖系统wake_lock机制,非空闲时执行runtime resume使得设备进入正常工作状态。
主要代码放在Runtime.c (drivers\base\power)中,同时附带的Runtime_pm.txt (documentation\power)有详细说明。要使得设备可以进入runtime_idle与runtime_suspend必须满足device的2个参数usage_count与child_count同时为0。
1:操作usage_count参数通常在HOST控制器驱动中,使用辅助runtime函数来完成。
2:操作child_count通常由子设备来完成父设备child_count的增加与减少。child_count可以理解该设备活跃的子设备的个数。
通常由子设备睡后来让父设备进入休眠,依次递归进行。
5.2、idle状态是suspend状态前的一个过渡而已,通常会在runtime_suspend调用之前调用一段时间runtime_idle回调。
sys/devices/.../power/control
on - 调用pm_runtime_forbid接口,增加设备的引用计数,然后resume设备。
auto - 调用pm_runtime_allow接口,减少设备的引用计数,如果设备的引用计数为0,则idle设备。
使设备处于active状态:
echo on > /sys/devices/platform/runtime_device/power/control,dmesg会打出resume
使设备进入suspend状态:
echo auto > /sys/devices/platform/runtime_device/power/control,dmesg会打出idle和suspend
5.3、在azx_suspend 和azx_resume()中加人log,发现会在linux系统进出disk mem standby 等PM状态的时候,这两个函数里面的log会打印出来。
当我给device runtime auto的时候,device会进入到runtime suspend状态,同时,我让系统进入standby或者disk,这时,会在log中这样显示:先azx device随系统 suspend,然后唤醒以后,azx runtime 也会resume,接着系统resume,最后因为上面echo了auto,所以decice runtime又进入到了suspend状态。说明device的power状态会影响运行时的状态,同样恢复后也一样。