TA的每日心情 | 开心 2019-11-20 15:00 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
linux电源管理3 & ]* [1 R' k m& v' ^* @
设备初始化流程:
5 p% O7 h& X6 \" `" _" adevice_register(dev)->device_initialize(dev)->device_pm_init(dev)->INIT_LIST_HEAD(&dev->power.entry);, \1 G ~ G+ w9 k1 X2 p3 u
设备添加流程:. Z4 P( N, e; F3 Z g/ n! |
device_add(dev)->device_pm_add(dev)->list_add_tail(&dev->power.entry,&dpm_list);% t3 H( }+ r3 |7 j6 E) g( H
4 N$ x0 O7 k! M5 o7 ]
8 v6 `& ?3 h3 n. B3 n, }- r
从设备初始化和添加到设备模型的流程可以看出,每个设备在注册和添加的过程中对应的device->power.entry被添加到了dpm_list链表中。6 V9 B. _. d+ D. v+ d! |+ P4 R/ S" Q
: w8 H- P, G3 N+ x* \. L1 T+ o: l; N! j
& D2 J1 a+ H$ u9 {+ P0 Cdevicesuspend由suspend模块完成,suspend模块由CONFIG_SUSPEND宏开关控制
@) _2 `) S+ f4 ~! b5 X4 N0 ^8 h; m$ }0 I W
[cpp] view plaincopyprint?
+ M: j Z: e5 s) c' y" y" N! \8 c$ I. G8 Q& q
- obj-$(CONFIG_SUSPEND) += suspend.o
/ U# S% \0 w6 x5 g/ s1 q8 H# o2 D 1 T z2 [4 ~- h! v5 v4 v! P0 w
代码就在kernel/power/suspend.c中
5 Z8 o- e) e& \ g! n* {8 osuspend模块对外导出了pm_suspend接口:
( I% ^2 L3 N1 s( ~# K
5 {: ~) \5 r$ U9 ^& g' ~( u9 z[cpp] view plaincopyprint?( _9 B; W" ?- S) B. c! V d
( o# m. M+ ?4 {, ]" k: E6 e- int pm_suspend(suspend_state_t state)
- {
- int error;
- if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
- return -EINVAL;
- error = enter_state(state);
- if (error) {
- suspend_stats.fail++;
- dpm_save_failed_errno(error);
- } else {
- suspend_stats.success++;
- }
- return error;
- }
- EXPORT_SYMBOL(pm_suspend);) G) V$ d4 d* C
& i% g# a5 }, S! q# c% I8 U1 B) ] P- }+ g" v0 s
pm_suspend被用来控制系统的设备进入指定的状态。前面提到的Linux定义的四种电源状态会被传递到这个函数,pm_suspend会对电源状态做检查,如果传入的是非法之,直接返回EINVAL。
c+ v9 n" E8 V( @! {四种电源状态定在include/linux/suspend.h文件中0 S/ W' d' I. C5 B0 H2 ^
0 {, ^* ^5 f) T% ~/ j5 r
[cpp] view plaincopyprint?* X6 w! s2 ?9 v5 W
" F: N& ]0 K& T! s$ o" f- typedef int __bitwise suspend_state_t;
- #define PM_SUSPEND_ON ((__force suspend_state_t) 0)
- #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 1)
- #define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
- #define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
& x \/ m4 N8 o4 u# ~# P' n $ J+ T5 b" n$ y
: r7 X! N& i0 F8 N: [
& m; S, @' g2 M: ~/ C2 J1 u针对具体设备休眠的操作都在针对设备休眠的驱动里面。相关的文件在driver/base/power/目录下。针对设备的休眠动作在driver/base/power/main.c文件中。该文件对外导出了三个接口,suspend模块用到了这些接口。. b2 ^& | K: Z# z h
[cpp] view plaincopyprint?! w. }; q+ |, m1 g* o
: P, C$ U4 }$ p" C
- int dpm_suspend_start(pm_message_t state)
- {
- int error;
- error = dpm_prepare(state);
- if (error) {
- suspend_stats.failed_prepare++;
- dpm_save_failed_step(SUSPEND_PREPARE);
- } else
- error = dpm_suspend(state);
- return error;
- }
- EXPORT_SYMBOL_GPL(dpm_suspend_start);
- void __suspend_report_result(const char *function, void *fn, int ret)
- {
- if (ret)
- printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
- }
- EXPORT_SYMBOL_GPL(__suspend_report_result);
- int device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
- {
- dpm_wait(dev, subordinate->power.async_suspend);
- return async_error;
- }
- EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
7 w# ]( L- H6 \
; {( a* j/ I* N0 K E$ E3 |. f* Y6 M
$ c! s5 w9 ]3 Y2 C% _7 D( x
% |% }( W. v+ I0 O6 W3.3平台相关挂起操作(platform suspending)在设备挂起操作完成之后,会针对特定平台做状态转换操作。Linux内核电源管理模块也为此定义了一组标准函数接口。不同架构只需要实现相应接口即可。
3 {* S' v2 l( g3 f8 _7 \7 D[cpp] view plaincopyprint?
* u7 v- r8 |7 \6 T+ G+ g4 B! S# R& k% I6 q* }! h% o7 q
- struct platform_suspend_ops {
- int (*valid)(suspend_state_t state);
- int (*begin)(suspend_state_t state);
- int (*prepare)(void);
- int (*prepare_late)(void);
- int (*enter)(suspend_state_t state);
- void (*wake)(void);
- void (*finish)(void);
- bool (*suspend_again)(void);
- void (*end)(void);
- void (*recover)(void);
- };0 N% ?% K; Z1 ]/ |- F3 j
, b: o: j: C: O
8 A- D! c- y3 s9 l这组函数功能如下:. {$ d3 N/ M" V+ ]
structplatform_suspend_ops定义了一组用于管理不同平台的下系统进入休眠状态的回调函数。这部分跟mcu关系非常紧密,涉及到时钟,PLL,电压域,频率,总线等系统级的物理模块进入休眠状态。每个具体的函数功能,在sourcecode中有详细的注释。# U, w% S* M* x# _% ?
5 H" S* V4 `! n- F4 ^- z2 D
7 T9 F2 P0 T+ u( D0 S2 o* ~' w( S5 `, u4 X0 e' o
|
|