TA的每日心情 | 开心 2019-11-20 15:00 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
linux电源管理3
! z$ P8 A6 X' A7 ~% o设备初始化流程:5 p, y% W* G8 E7 b( B& M" M
device_register(dev)->device_initialize(dev)->device_pm_init(dev)->INIT_LIST_HEAD(&dev->power.entry);
6 s5 k% X, N3 K设备添加流程:
) [" p2 g+ o5 X% X6 M5 o9 q1 Rdevice_add(dev)->device_pm_add(dev)->list_add_tail(&dev->power.entry,&dpm_list);
* e8 W5 _3 N9 n6 N$ \, t( A: N: T8 T% E3 y: X
) ^% t: F% y% ^' b3 I8 R
从设备初始化和添加到设备模型的流程可以看出,每个设备在注册和添加的过程中对应的device->power.entry被添加到了dpm_list链表中。3 V7 y; Y; O6 q* w6 V2 \9 I
: |# f: e& \7 D8 u* ?9 v1 T+ l/ P7 s
devicesuspend由suspend模块完成,suspend模块由CONFIG_SUSPEND宏开关控制 f: k: ^, N! B1 g3 Z( X7 [. E
* c! o9 h" H6 J$ [[cpp] view plaincopyprint?9 ]# M1 H# f6 ?! `, O2 b
: [* A( l- y" \8 u7 d9 c! f( H7 m4 b- obj-$(CONFIG_SUSPEND) += suspend.o7 L+ @; e( O5 T6 c% Y/ z3 A* X
! k( \" I7 v @代码就在kernel/power/suspend.c中
0 q3 C) |6 i. o* j$ X5 K; [suspend模块对外导出了pm_suspend接口:
" q) r* m; Q: E- u
r* l* d. M: c[cpp] view plaincopyprint?) Z3 z1 w [2 K" y
6 x& \ m5 ~. o9 W, J0 a: K; f
- 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);. {1 u n* S. j! P1 `- l
, y# m K; c! ?/ m" b8 A
( A) X3 M: m! R) K
pm_suspend被用来控制系统的设备进入指定的状态。前面提到的Linux定义的四种电源状态会被传递到这个函数,pm_suspend会对电源状态做检查,如果传入的是非法之,直接返回EINVAL。
: k J+ J6 N( G' q四种电源状态定在include/linux/suspend.h文件中) P5 B0 M5 |; D4 h* W" J. W
; [/ z$ g5 J; N. T[cpp] view plaincopyprint? o9 s5 N8 H. S/ p& U
2 [% o. J7 ~- P: J+ A! k
- 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)! z7 R% H0 S- o/ V8 `
# A- {" g+ D# b) g; e" I$ j1 _9 X2 G) p! U) J$ Z
/ F" B. p1 A3 ?6 Q% P针对具体设备休眠的操作都在针对设备休眠的驱动里面。相关的文件在driver/base/power/目录下。针对设备的休眠动作在driver/base/power/main.c文件中。该文件对外导出了三个接口,suspend模块用到了这些接口。
% ^$ K/ s1 D) ]4 G! m- d" u[cpp] view plaincopyprint?
/ H! d1 l( p2 n1 h' P4 h
( ~! w% E. `! _) ^- 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);
2 i# ` w+ K' G0 h6 n/ D( H( }' K ` s3 x- d, }. \
1 q' ~& i2 u) r/ I
: O8 z6 K/ M: x5 Z
: t) @ X+ _+ S: K0 r4 k+ a3.3平台相关挂起操作(platform suspending)在设备挂起操作完成之后,会针对特定平台做状态转换操作。Linux内核电源管理模块也为此定义了一组标准函数接口。不同架构只需要实现相应接口即可。
+ r0 i9 [+ a( ?% a6 P[cpp] view plaincopyprint?, }7 D3 v" d) l( b: U+ |
) ]5 F0 e; L. a4 x0 J' L
- 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);
- };
# G( s; g# l' v/ \* ^ $ E% E# Z' w, b" f9 y' ]% W
5 H3 x# D9 H! r& {$ f# _: H" M这组函数功能如下:, I: k# I% D8 z9 ]0 j7 A/ {
structplatform_suspend_ops定义了一组用于管理不同平台的下系统进入休眠状态的回调函数。这部分跟mcu关系非常紧密,涉及到时钟,PLL,电压域,频率,总线等系统级的物理模块进入休眠状态。每个具体的函数功能,在sourcecode中有详细的注释。0 u: ~+ l4 B, J$ l* e9 s
! u( f8 D( [5 c+ B( S
2 M+ M: j5 A& n; d
* h! l' I- `' E: J$ Z7 f. `
|
|