Linux:电源管理

Linux电源管理(6)_Generic PM之Suspend功能

1. 前言

Linux内核提供了三种Suspend: Freeze、Standby和STR(Suspend to RAM),
在用户空间向”/sys/power/state”文件分别写入”freeze”、”standby”和”mem”,即可触发它们。

内核中,Suspend及Resume过程涉及到PM Core、Device PM、各个设备的驱动、Platform dependent PM、CPU control等多个模块,涉及了console switch、process freeze、CPU hotplug、wakeup处理等过个知识点。

2. Suspend功能有关的代码分布

内核中Suspend功能有关的代码包括PM core、Device PM、Platform PM等几大块。

  1. PM Core

    kernel/power/main.c----提供用户空间接口(/sys/power/state)
    kernel/power/suspend.c----Suspend功能的主逻辑
    kernel/power/suspend_test.c----Suspend功能的测试逻辑
    kernel/power/console.c----Suspend过程中对控制台的处理逻辑
    kernel/power/process.c----Suspend过程中对进程的处理逻辑

  2. Device PM
    drivers/base/power/*----具体可参考“Linux电源管理(4)_Power Management Interface”的描述。
    设备驱动----具体设备驱动的位置,不再涉及。

  3. Platform dependent PM
    include/linux/suspend.h----定义platform dependent PM有关的操作函数集
    arch/xxx/mach-xxx/xxx.c或者
    arch/xxx/plat-xxx/xxx.c----平台相关的电源管理操作

3. suspend&resume过程概述

4. 代码分析

4.1 suspend入口

在用户空间执行如下操作:
        echo "freeze" > /sys/power/state
        echo "standby" > /sys/power/state
        echo "mem" > /sys/power/state

根据state的值,如果不是(PM_SUSPEND_MAX,对应hibernate功能),则调用pm_suspend接口,进行后续的处理。 
pm_suspend在kernel/power/suspend.c定义,处理所有的suspend过程。

4.2 pm_suspend & enter_state

pm_suspend的实现非常简单,简单的做一下参数合法性判断

4.3 suspend_devices_and_enter
  • a)再次检查平台代码是否需要提供以及是否提供了suspend_ops。
  • b)调用suspend_ops的begin回调(有的话),通知平台代码,以便让其作相应的处理(需要的话)。可能失败,需要跳至Close处执行恢复操作(suspend_ops->end)。
  • c)调用suspend_console,挂起console。该接口由"kernel\printk.c"实现,主要是hold住一个lock,该lock会阻止其它代码访问console。
  • d)调用ftrace_stop,停止ftrace功能。
  • e)调用dpm_suspend_start,调用所有设备的->prepare和->suspend回调函数
  • f)以上都是suspend前的准备工作,此时,调用suspend_enter接口,使系统进入指定的电源状态。
4.4 suspend_enter接口
  • f1)该接口处理完后,会通过返回值告知是否enter成功,同时通过wakeup指针,告知调用者,是否有wakeup事件发生,导致电源状态切换失败。
  • f2)调用suspend_ops的prepare回调(有的话),通知平台代码,以便让其在即将进行状态切换之时,再做一些处理(需要的话)。该回调可能失败(平台代码出现意外),失败的话,需要跳至Platform_finish处,调用suspend_ops的finish回调,执行恢复操作。
  • f3)调用dpm_suspend_end,调用所有设备的->suspend_late和->suspend_noirq回调函数,suspend late suspend设备和需要在关中断下suspend的设备。需要说明的是,这里的noirq,是通过禁止所有的中断线的形式,而不是通过关全局中断的方式。同样,该操作可能会失败,失败的话,跳至Platform_finish处,执行恢复动作。
  • f4)调用suspend_ops的prepare_late回调(有的话),通知平台代码,以便让其在最后关头,再做一些处理(需要的话)。该回调可能失败(平台代码出现意外),失败的话,需要跳至Platform_wake处,调用suspend_ops的wake回调,执行device的resume、调用suspend_ops的finish回调,执行恢复操作。
  • f5)如果是suspend to freeze,执行相应的操作,包括冻结进程、suspended devices(参数为PM_SUSPEND_FREEZE)、cpu进入idle。如果有任何事件使CPU从idle状态退出,跳至Platform_wake处,执行wake操作。

  • f6)调用disable_nonboot_cpus,禁止所有的非boot cpu。也会失败,执行恢复操作即可

  • f7)调用arch_suspend_disable_irqs,关全局中断。如果无法关闭,则为bug。

  • f8)调用syscore_suspend,suspend system core。同样会失败,执行恢复操作即可。有关syscore,我会在另一篇文章中详细描述。

  • f9)如果很幸运,以上操作都成功了,那么,切换吧。不过,别高兴太早,还得调用pm_wakeup_pending检查一下,这段时间内,是否有唤醒事件发生,如果有就要终止suspend。

  • f10)如果一切顺利,调用suspend_ops的enter回调,进行状态切换。这时,系统应该已经suspend了…

  • f11)suspend过程中,唤醒事件发生,系统唤醒,该函数接着执行resume动作,并最终返回。resume动作基本上是suspend的反动作。
    resume操作,resume device、start ftrace、resume console、suspend_ops->end等等。

  • f12)或者,由于意外,suspend终止,该函数也会返回。

  • f13)该函数返回后,表示系统已经resume。 

4.5 suspend_finish

a)恢复所有的用户空间进程和内核线程。
b)发送suspend结束的通知。
c)将console切换回原来的。

5. 知识点回顾

5.1 PM notifier

PM notifier是基于内核blocking notifier功能实现的。
一种kernel内部的消息通知机制,消息接受者通过notifier注册的方式,注册一个回调函数,关注消息发送者发出的notifier。当消息产生时,消息产生者通过调用回调函数的形式,通知消息接受者。

5.2 device PM ops 和platform PM ops的调用时机

device PM ops和platform PM ops就是电源管理(suspend)的全部,只要在合适的地方,实现合适的回调函数,即可实现系统的电源管理。

5.3 suspend过程的同步和PM wakeup

Android用suspend作日常的待机(操作就相当频繁了),这时问题就大了。那怎么解决呢?得靠system wakeup framework,也就是suspend过程中所调用的pm_wakeup_pending接口所在的模块。

Linux电源管理(7)_Wakeup events framework

1.  前言

wakeup events framework是这个话题的一个临时性的解决方案,包括wake lock、wakeup count、autosleep等机制。它们就是本文的话题。

2. wakeup events framework要解决的问题

系统处于suspend状态,可通过wakeup events唤醒。具体的wakeup events可以是按键按下,可以是充电器插入,等等。但是,如果在suspend的过程中,产生了wakeup events,怎么办?答案很肯定,"wakeup"系统。由于此时系统没有真正suspend,所以这的"wakeup"是个假动作,实际上只是终止suspend。

但由于系统在suspend的过程中,会进行process freeze、 device suspend等操作,而这些操作可能导致内核或用户空间程序不能及时获取wakeup events,从而使系统不能正确wakeup,这就是wakeup events framework要解决的问题:system suspend和system wakeup events之间的同步问题

3. wakeup events framework的功能总结

情况1:内核空间的同步

  • wakeup events产生后,通常是以中断的形式通知device driver。driver会处理events,处理的过程中,系统不能suspend。
    注1:同步问题只存在于中断开启的情况,因为若中断关闭,就不会产生wakeup events,也就不存在同步的概念。

情况2:用户空间的同步

  • 一般情况下,driver对wakeup events处理后,会交给用户空间程序继续处理,处理的过程,也不允许suspend。这又可以分为两种情况

wakeup events framework就包括3大功能:

  1. 解决内核空间同步问题(framework的核心功能);
  2. 解决用户空间同步问题的情景1(wakeup count功能);
  3. 解决用户空间同步问题的情景2(wake lock功能) 。
4. wakeup events framework architecture

下面图片描述了wakeup events framework的architecture:

图片中红色边框的block是wakeup events相关的block:

1)wakeup events framework core,在drivers/base/power/wakeup.c中实现,提供了wakeup events framework的核心功能,包括:

  • 抽象wakeup source和wakeup event的概念;
  • 向各个device driver提供wakeup source的注册、使能等接口;
  • 向各个device driver提供wakeup event的上报、停止等接口;
  • 向上层的PM core(包括wakeup count、auto sleep、suspend、hibernate等模块)提供wakeup event的查询接口,以判断是否可以suspend、是否需要终止正在进行的suspend。

2)wakeup events framework sysfs,将设备的wakeup信息,以sysfs的形式提供到用户空间,供用户空间程序查询、配置。在drivers/base/power/sysfs.c中实现。

3)wake lock/unlock,为了兼容Android旧的wakeup lock机制而留下的一个后门,扩展wakeup events framework的功能,允许用户空间程序报告/停止wakeup events。换句话说,该后门允许用户空间的任一程序决定系统是否可以休眠。

4)wakeup count,基于wakeup events framework,解决用户空间同步的问题。

5)auto sleep,允许系统在没有活动时(即一段时间内,没有产生wakeup event),自动休眠。

5. 代码分析
5.1  wakeup source和wakeup event

介绍struct device结构时,涉及到一个struct dev_pm_info类型的power变量。
该结构中有一个power变量,保存了和wakeup event相关的信息,让我们接着看一下struct dev_pm_info数据结构。

can_wakeup,标识本设备是否具有唤醒能力。只有具备唤醒能力的设备,才会在sysfs中有一个power目录,用于提供所有的wakeup信息,这些信息是以struct wakeup_source的形式组织起来的。也就是上面wakeup指针。

一个wakeup source代表了一个具有唤醒能力的设备,也称该设备为一个wakeup source。。该结构中各个字段的意义如下:

  • 一个wakeup source产生了wakeup event,称作wakeup source activate,wakeup event处理完毕后(不再需要系统为此保持active),称作deactivate。
  • activate和deactivate的操作可以由driver亲自设置,也可以在activate时,指定一个timeout时间,时间到达后,由wakeup events framework自动将其设置为deactivate状态。这里的timer以及expires时间,就是用来实现该功能;
  • event_count,wakeup source产生的wakeup event的个数;
  • active,产生wakeup event时,wakeup source需要切换到activate状态。
    active_count,wakeup source activate的次数;

    relax_count, wakeup source deactivate的次数;

  • wakeup_count,wakeup source终止suspend过程的次数;

wakeup source代表一个具有唤醒能力的设备,该设备产生的可以唤醒系统的事件,就称作wakeup event。当wakeup source产生wakeup event时,需要将wakeup source切换为activate状态;当wakeup event处理完毕后,要切换为deactivate状态。

5.3 wakeup events framework的核心功能

wakeup events framework的核心功能体现在它向底层的设备驱动所提供的用于上报wakeup event的接口,这些接口根据操作对象可分为两类,具体如下。
类型一(操作对象为wakeup source,编写设备驱动时,一般不会直接使用):
类型二(操作对象为device,为设备驱动的常用接口):

  • 1: /* include/linux/pm_wakeup.h */   
    2: extern int device_wakeup_enable(struct device *dev);   
    3: extern int device_wakeup_disable(struct device *dev);   
    4: extern void device_set_wakeup_capable(struct device *dev, bool capable);
    5: extern int device_init_wakeup(struct device *dev, bool val);
    6: extern int device_set_wakeup_enable(struct device *dev, bool enable);
    7: extern void pm_stay_awake(struct device *dev);
    8: extern void pm_relax(struct device *dev);
    9: extern void pm_wakeup_event(struct device *dev, unsigned int msec);

5.3.1 device_set_wakeup_capable
        1)wakeup
        2)wakeup_count

5.3.2 device_wakeup_enable/device_wakeup_disable/device_set_wakeup_enable
该接口位于在drivers/base/power/wakeup.c中,代码

5.3.4 pm_relax
5.3.5 pm_wakeup_event
5.3.6 pm_wakeup_pending

Linux电源管理(8)_Wakeup count功能

1. 前言

Wakeup count是Wakeup events framework的组成部分,用于解决“system suspend和system wakeup events之间的同步问题”。

2. wakeup count在电源管理中的位置

wakeup count的实现位于wakeup events framework中(drivers/base/power/wakeup.c),主要为两个模块提供接口:通过PM core向用户空间提供sysfs接口;直接向autosleep(请参考下一篇文章)提供接口。

3. wakeup count的功能
4. wakeup count的实现逻辑
4.2 /sys/power/wakeup_count
4.3 pm_get_wakeup_count
4.4 pm_save_wakeup_count
4.5 /sys/power/state

wakeup_count文件是在kernel/power/main.c中,利用power_attr注册的。
注2:wakeup后,会清除events_check_enabled标记。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值