• Linux电源管理


    1. 设备电源管理的两种模型

            在一个系统中,数量最多的是设备,耗电最多的也是设备,因此设备的电源管理是Linux电源管理的核心内容,驱动程序可以使用其中一种模型来使设备进入低功耗状态。

    1.1 系统睡眠模型

            驱动程序作为一部分,跟随系统级别的低功耗状态,比如"suspend"(也叫做"suspend-to-RAM"),或者对于有硬盘的系统,可以进入"hibernation"(也叫做"suspend-to-disk")。

            有些驱动程序可以管理硬件的唤醒事件,这些事件可以让系统离开低功耗状态。这一特性可以通过相应的/sys/devices/.../power/wakeup文件来开启和关闭。

            系统休眠模型给我的感觉是以整机角度进行省电。

            在Linux中,通过cat /sys/power/state可以得知当前设备支持的节能模式,一般情况有如下选项:

    1. standby: CPU处于浅睡眠模式,主要针对CPU功耗;
    2. mem: Suspend to RAM;
    3. disk: Suspend to Disk;

            需要设置以上模式,只需echo mem > /sys/power/state即可。

    1.2 Runtime 电源管理模型

            这种模型允许设备在系统运行阶段进入低功耗状态,原则上,他可以独立于其他的电源管理活动。不过,通常设备之间不能单独进行控制(例如,父设备不能进入suspend,除非他的所有子设备已经进入suspend状态)。如果设备在系统运行阶段进入了低功耗状态,在系统级别的电源状态迁移时(suspend或hibernation)就必须做出特别的处理。

            如果在系统运行状态,足够多的设备进入了低功耗状态,这时的效果其实和进入了系统级别的低功耗状态非常相像。这样一些驱动程序可以利用rumtime电源管理让系统进入一种类似深度省电的状态。

            大多数进入suspend状态的设备会停止所有的I/O操作:不会有DMA或者IRQ请求(需要唤醒系统的除外),不会有数据的读写,不再接受上层驱动的请求。

            Runtime电源管理模型给我的感觉是以模块角度进行省电。

            Runtime电源管理模型的原理比较简单,就是计数,当该设备驱动被使用时就加1,放弃使用时就减1,计数大于1时,就打开该设备的电源,等于0时就关闭电源。

    1.3 设备电源管理操作

            设备电源管理最核心的操作就是:在合适的时机(如不再使用,如暂停使用),将设备置为合理的状态(如关闭,如睡眠),这就是device PM callbacks的目的:定义一套统一的方式,让设备在特定的时机,步调一致的进入类似的状态。

            在旧版本的内核中,这些PM callbacks分布在设备模型的大型数据结构中,如struct bus_type中的suspend、suspend_late、resume、resume_late,如struct device_driver/struct class/struct device_type中的suspend、resume。很显然这样不具备良好的封装特性,因为随着设备复杂度的增加,简单的suspend、resume已经不能满足电源管理的需求,就需要扩充PM callbacks,就会不可避免的改动这些数据结构。

            于是新版本的内核,就将这些Callbacks统一封装为一个数据结构struct dev_pm_ops,上层的数据结构只需要包含这个结构即可。这样如果需要增加或者修改PM callbacks,就不用改动上层结构了。当然,内核为了兼容旧的设计,也保留了上述的suspend/resume类型的callbacks,只是已不建议使用。

    1. //include/linux/pm.h
    2. //子系统和驱动程序的设备电源管理操作,都定义在dev_pm_ops结构中
    3. struct dev_pm_ops {
    4. int (*prepare)(struct device *dev);
    5. void (*complete)(struct device *dev);
    6. int (*suspend)(struct device *dev);
    7. int (*resume)(struct device *dev);
    8. int (*freeze)(struct device *dev);
    9. int (*thaw)(struct device *dev);
    10. int (*poweroff)(struct device *dev);
    11. int (*restore)(struct device *dev);
    12. int (*suspend_late)(struct device *dev);
    13. int (*resume_early)(struct device *dev);
    14. int (*freeze_late)(struct device *dev);
    15. int (*thaw_early)(struct device *dev);
    16. int (*poweroff_late)(struct device *dev);
    17. int (*restore_early)(struct device *dev);
    18. int (*suspend_noirq)(struct device *dev);
    19. int (*resume_noirq)(struct device *dev);
    20. int (*freeze_noirq)(struct device *dev);
    21. int (*thaw_noirq)(struct device *dev);
    22. int (*poweroff_noirq)(struct device *dev);
    23. int (*restore_noirq)(struct device *dev);
    24. /* 最后三个方法是专门用于rumtime pm的,其他的则用于系统级别的电源状态迁移。 */
    25. int (*runtime_suspend)(struct device *dev);
    26. int (*runtime_resume)(struct device *dev);
    27. int (*runtime_idle)(struct device *dev);
    28. };

    1.4 设置唤醒源

            唤醒源最常见的就是按键中断,就如同手机进入锁屏状态下,按下电源键唤醒一样。

    2. regulator系统

            系统睡眠模型和runtime电源管理模型偏“软”,regulator系统偏“硬”,在复杂的单板中,有专门的电源管理芯片控制各个模块电源,regulator系统就是为这个电源芯片编写驱动,实现电源管理。

            如果使用 系统睡眠模型 或 Runtime电源模型 进行休眠操作,就会调用到regulator系统的操作函数,实现电源管理芯片的关闭。

            Regulator分为voltage regulator和current。一般PMIC(Power Management IC)中会包含一个或者多个regulator。通常的作用是给电子设备供电,大多数regulator可以启用(enable)和禁用(disable)其输出,同时也可以控制其输出电压(voltage)和电流(current)。

            cpu内部会集成一些regulator,通常cpu还会通过I2C controller外接多个regulator。比如,通过i2c controller外接pfuze100这个型号的电源IC,其对应的驱动程序在drivers/regulator/pfuze100-regulator.c。

    2.1 regulator framework

            调用注册接口regulator_register/devm_regulator_register进行注册regulator。

            regulator的主要功能,是输出电压/电流的调整(或改变)。由于模拟器件的特性,电压/电流的改变,是需要一定的时间的。对有些regulator而言,可以工作在不同的模式,这些模式有不同的改变速度,较快的速度,有较大的功耗。模式如下所示:

    1. include/linux/regulator/consumer.h
    2. /*
    3. * Regulator operating modes.
    4. *
    5. * Regulators can run in a variety of different operating modes depending on
    6. * output load. This allows further system power savings by selecting the
    7. * best (and most efficient) regulator mode for a desired load.
    8. *
    9. * Most drivers will only care about NORMAL. The modes below are generic and
    10. * will probably not match the naming convention of your regulator data sheet
    11. * but should match the use cases in the datasheet.
    12. *
    13. * In order of power efficiency (least efficient at top).
    14. *
    15. * Mode Description
    16. * FAST Regulator can handle fast changes in it's load.
    17. * e.g. useful in CPU voltage & frequency scaling where
    18. * load can quickly increase with CPU frequency increases.
    19. *
    20. * NORMAL Normal regulator power supply mode. Most drivers will
    21. * use this mode.
    22. *
    23. * IDLE Regulator runs in a more efficient mode for light
    24. * loads. Can be used for devices that have a low power
    25. * requirement during periods of inactivity. This mode
    26. * may be more noisy than NORMAL and may not be able
    27. * to handle fast load switching.
    28. *
    29. * STANDBY Regulator runs in the most efficient mode for very
    30. * light loads. Can be used by devices when they are
    31. * in a sleep/standby state. This mode is likely to be
    32. * the most noisy and may not be able to handle fast load
    33. * switching.
    34. *
    35. * NOTE: Most regulators will only support a subset of these modes. Some
    36. * will only just support NORMAL.
    37. *
    38. * These modes can be OR'ed together to make up a mask of valid register modes.
    39. */
    40. #define REGULATOR_MODE_FAST 0x1
    41. #define REGULATOR_MODE_NORMAL 0x2
    42. #define REGULATOR_MODE_IDLE 0x4
    43. #define REGULATOR_MODE_STANDBY 0x8

            kernel抽象出直接操作电压的方法:对应struct regulator_ops中的如下回调函数:

    1. /* get/set regulator voltage */
    2. int (*list_voltage) (struct regulator_dev *, unsigned selector);
    3. int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, unsigned *selector);
    4. int (*get_voltage) (struct regulator_dev *);

    3. 小结

            不是所有的设备都需要专门的电源IC的,所以有的设备另外配置了电源管理IC,那么就需要通过regulator系统来注册电源管理IC对应的驱动,所以当系统睡眠或该设备睡眠时,这种设备的dev_pm_ops回调接口在实现时,需要调用电源管理IC驱动的接口来设置电压/电流的大小/关闭等状态,也就是说可能不仅仅是实现ON和OFF两个状态,还需要实现IC输出不同大小的状态,比如输出1A、2A、3A三种不同电流的状态。

            还有一些简单的设备是不需要配置电源管理IC的,所以当系统睡眠或该设备睡眠时,这种设备的dev_pm_ops回调接口在实现时,实现ON和OFF两个状态就可以了。

    3.1 进入和退出睡眠

            系统睡眠模型一般是通过按键(即外部中断)的方式来进入和退出睡眠,runtime电源管理模型一般是自动进入睡眠(软件计数、定时等方式),按键(即外部中断)的方式退出睡眠。

  • 相关阅读:
    快慢指针思想(Hare & Tortoise 算法)
    策略验证_卖出口诀_三种图线交叉点卖出股票需抢先
    第十六章《正则表达式》第1节:正则表达式入门
    Java语言的特点||运算符
    力扣第131题 分割回文串 c++ 回溯+简单 动态规划(是否为回文子串)
    Linux安装tomcat9
    Fiddler配置及使用
    【实习之velocity】
    搭建直播带货源码,商品带货销售不止直播一种方式
    Azure AD统一认证及用户数据同步开发指导
  • 原文地址:https://blog.csdn.net/qq_41076734/article/details/125995739