Linux 3.14 待机流程分析

1:待机节点创建static int __init pm_init(void){int error = pm_start_workqueue();if (error)return error;hibernate_image_size_init();hibernate_reserved_size_init();power_kobj = kobject_create_and_add("power", NULL);if (!power_kobj)return -ENOMEM;#ifdef CONFIG_X86_INTEL_XGOLDpower_hal_kobj = kobject_create_and_add("power_HAL_suspend",power_kobj);if (!power_hal_kobj)return -ENOMEM;#endiferror = sysfs_create_group(power_kobj, &attr_group);if (error)return error;pm_print_times_init();return pm_autosleep_init();}core_initcall(pm_init);

pm_init使用core_initcall,顾名思义这是内核一个核心节点。pm_init完成创建"power"节点,至于如何创建,节点位置,想了解的看下如下这一小部分

struct kobject *kobject_create_and_add(const char *name, struct kobject *parent){struct kobject *kobj;int retval;kobj = kobject_create();if (!kobj)return NULL;retval = kobject_add(kobj, parent, "%s", name);if (retval) {printk(KERN_WARNING "%s: kobject_add error: %d\n",__func__, retval);kobject_put(kobj);kobj = NULL;}return kobj;}EXPORT_SYMBOL_GPL(kobject_create_and_add);节点是挂在kobj下,那么kobj在哪里呢?struct kobject *kobject_create(void){struct kobject *kobj;kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);if (!kobj)return NULL;kobject_init(kobj, &dynamic_kobj_ktype);return kobj;}static struct kobj_type dynamic_kobj_ktype = {.release= dynamic_kobj_release,.sysfs_ops= &kobj_sysfs_ops,};所以,可以知道power节点是在sysfs的ops下创建,它的位置就是 /sys/power/

1.1:power节点下子节点群创建

power作为内核待机主要节点,也可以说是父节点,很多相关节点都在它低下创建;这就要看它的attribute_group

static struct attribute * g[] = {&state_attr.attr,#ifdef CONFIG_PM_TRACE&pm_trace_attr.attr,&pm_trace_dev_match_attr.attr,#endif#ifdef CONFIG_PM_SLEEP&pm_async_attr.attr,&wakeup_count_attr.attr,#ifdef CONFIG_PM_AUTOSLEEP&autosleep_attr.attr,#endif#ifdef CONFIG_PM_WAKELOCKS&wake_lock_attr.attr,&wake_unlock_attr.attr,#endif#ifdef CONFIG_PM_DEBUG&pm_test_attr.attr,#endif#ifdef CONFIG_PM_SLEEP_DEBUG&pm_print_times_attr.attr,#endif#endif#ifdef CONFIG_FREEZER&pm_freeze_timeout_attr.attr,#endifNULL,};

如下是创建的节点群

# ls /sys/power/autosleeppm_asyncpm_freeze_timeoutpm_print_timespm_testpower_HAL_suspendstatewake_lockwake_unlockwakeup_count

2:待机入口函数

从之前的文章分析,内核还在3.10之前,state节点是待机唯一入口。

当然内核延续性,这些接口作用都不变也可以用,如下命令待机:

# cat /sys/power/state freeze mem

# echo mem > sys/power/state [ 168.644948] PM: suspend entry 2015-06-12 06:48:07.903751731 UTC[ 168.651206] PM: Syncing filesystems … done.[ 168.704213] Freezing user space processes … (elapsed 0.005 seconds) done.[ 168.717090] Freezing remaining freezable tasks … (elapsed 0.004 seconds) done.[ 168.728986] Suspending console(s) (use no_console_suspend to debug)

从上面子节点群,我们注意到增加了一个叫autosleep的节点。没错!这是新增的接口,autosleep替代以前google加在linux之上的earlysuspend机制,所以从这个版本开始,不需要google的android来操心内核增加什么待机方面代码了。

2.1:autosleep入口函数

我们先看这个入口函数的store回调

static ssize_t autosleep_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n){suspend_state_t state = decode_state(buf, n);int error;if (state == PM_SUSPEND_ON&& strcmp(buf, "off") && strcmp(buf, "off\n"))return -EINVAL;error = pm_autosleep_set_state(state);return error ? error : n;}如果autosleep节点值是off的话,autosleep功能关闭。和旧接口state不同的是,autosleep不需要关心唤醒,所以传入的state不能是on。

接下来就进入到autosleep的主要回调pm_autosleep_set_state去了。

2.2:wake lock/unlock 和__pm_stay_awake/__pm_relax

内核3.10用的加锁解锁流程是

wake_lock_init初始化一个lock

wake_lock加锁(非超时锁,需要手动解锁)

wake_lock_timeout加超时锁,,到时自动解锁

wake_unlock解锁

wake_lock_destroy销毁一个lock

内核3.14兼容这些接口,开发者可以使用之前的驱动代码,也可以保持风格,因为这些接口都做了兼容,

在include/linux/wakelock.h里面都有兼容性定义;如

static inline void wake_lock_init(struct wake_lock *lock, int type,const char *name){wakeup_source_init(&lock->ws, name);}其他接口就不全列出来。

内核3.14使用wakelock source概念,通过锁的红黑树记录并管理系统所有的锁,这是锁机制的最大改变

static struct rb_root wakelocks_tree = RB_ROOT;

我们后面单独介绍,现在先把使用流程搞清楚。

后来逐渐有广州花城的,

Linux 3.14 待机流程分析

相关文章:

你感兴趣的文章:

标签云: