suspend小节
概括:
事件触发-----》
1.PowerManagerService----》
2.Native AutoSuspend----》
3.Autosuspend Driver----》
4.(Suspend kworks:freezing tasks -> devices level suspend -> system level suspend -> platform level suspend -> cpu enter WFI)----》
5.SPM
代码追踪:
上层接收到事件,通过power manager service操作位于sys/power的节点:
上层会调用autosuspend_enable()函数
//system/core/libsuspend/autosuspend.c
int autosuspend_enable(void)
{
autosuspend_init();
autosuspend_ops->enable();
}
int autosuspend_disable(void)
{
autosuspend_init();
autosuspend_ops->disable();
}
static int autosuspend_init(void)
{
autosuspend_ops = autosuspend_wakeup_count_init();
}
//system/core/libsuspend/autosuspend_wakeup_count.c
#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
struct autosuspend_ops *autosuspend_wakeup_count_init(void)
{
wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
}
//没有锁,写mem>/sys/power/state
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
while (1) {
usleep(100000);
wakeup_count_len = read(wakeup_count_fd, wakeup_count,sizeof(wakeup_count));
sem_wait(&suspend_lockout);
ret=write(wakeup_count_fd, wakeup_count, wakeup_count_len));
if (ret < 0)
{
}
else
{
write(state_fd, sleep_state, strlen(sleep_state));
}
}
}
static int autosuspend_wakeup_count_enable(void)
{
sem_post(&suspend_lockout);
}
static int autosuspend_wakeup_count_disable(void)
{
sem_wait(&suspend_lockout);
}
//kernel/kernel/power/main.c
static ssize_t wakeup_count_show(struct kobject *kobj,struct kobj_attribute *attr,char *buf)
{
unsigned int val;
return pm_get_wakeup_count(&val, true) ?
sprintf(buf, "%u\n", val) : -EINTR;
}
static ssize_t wakeup_count_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{
unsigned int val;
error = -EINVAL;
if (sscanf(buf, "%u", &val) == 1) {
if (pm_save_wakeup_count(val))
error = n;
}
out:
return error;
}
power_attr(wakeup_count);
bool pm_get_wakeup_count(unsigned int *count, bool block)
{
unsigned int cnt, inpr;
if (block) {
DEFINE_WAIT(wait);
for (;;) {
prepare_to_wait(&wakeup_count_wait_queue, &wait,
TASK_INTERRUPTIBLE);
split_counters(&cnt, &inpr);
if (inpr == 0 || signal_pending(current))
break;
schedule();
}
finish_wait(&wakeup_count_wait_queue, &wait);
}
split_counters(&cnt, &inpr);
*count = cnt;
return !inpr;
}
/**
* pm_save_wakeup_count - Save the current number of registered wakeup events.
* @count: Value to compare with the current number of registered wakeup events.
*
* If @count is equal to the current number of registered wakeup events and the
* current number of wakeup events being processed is zero, store @count as the
* old number of registered wakeup events for pm_check_wakeup_events(), enable
* wakeup events detection and return 'true'. Otherwise disable wakeup events
* detection and return 'false'.
*/
bool pm_save_wakeup_count(unsigned int count)
{
unsigned int cnt, inpr;
unsigned long flags;
events_check_enabled = false;
spin_lock_irqsave(&events_lock, flags);
split_counters(&cnt, &inpr);
if (cnt == count && inpr == 0) {
saved_count = count;
events_check_enabled = true;
}
spin_unlock_irqrestore(&events_lock, flags);
return events_check_enabled;
}
/*
上面的作用是对/sys/power/wakeup_count进行读写(涉及到变量combined_event_count,
可参考https://blog.csdn.net/mike8825/article/details/80422993),如果所有的锁都已解锁,
则写"mem"到/sys/power/state进行休眠*/
/********************************************************************************************************************************************************
简单总结:
autosuspend_enable() -> autosuspend_init() -> autosuspend_wakeup_count_init()此时“/sys/power/wakeup_count”节点已经打开,方便后面计数操作 -> 当确认没有锁时转到suspend_thread_func()先给wakeup_count写值,再为state节点写值mem
********************************************************************************************************************************************************/
sys/power/state节点生成于:kernel/kernel/power/main.c
当对该节点进行写操作时会调用函数state_store()
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
{
state = decode_state(buf, n);//将"mem"转换成对应的数字
error = pm_suspend(state);
}
int pm_suspend(suspend_state_t state)
{
pm_suspend_marker("entry");
error = enter_state(state);
pm_suspend_marker("exit");
}
static void pm_suspend_marker(char *annotation)
{
struct timespec ts;
struct rtc_time tm;
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec, &tm);
pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n",
annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}
static int enter_state(suspend_state_t state)
{
printk(KERN_INFO "PM: Syncing filesystems ... ");
sys_sync();
printk("done.\n");
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
error = suspend_prepare(state);
pr_debug("PM: Entering %s sleep\n", pm_states[state]);
pm_restrict_gfp_mask();
error = suspend_devices_and_enter(state);
pm_restore_gfp_mask();
Finish:
pr_debug("PM: Finishing wakeup.\n");
suspend_finish();
}
static inline int suspend_freeze_processes(void)
{
error = freeze_processes();
error = freeze_kernel_threads();
}
static int suspend_prepare(suspend_state_t state) //冻结所有进程
{
if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter)) //kernel/drivers/cpuidle/lpm-levels.c suspend_set_ops(&lpm_suspend_ops);
return -EPERM;
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
error = suspend_freeze_processes();
pm_notifier_call_chain(PM_POST_SUSPEND);
return error;
}
int suspend_devices_and_enter(suspend_state_t state)
{
int error;
bool wakeup = false;
if (need_suspend_ops(state) && !suspend_ops)
return -ENOSYS;
if (need_suspend_ops(state) && suspend_ops->begin) {
error = suspend_ops->begin(state);
if (error)
goto Close;
}
suspend_console();
error = dpm_suspend_start(PMSG_SUSPEND);
if (error) {
printk(KERN_ERR "PM: Some devices failed to suspend\n");
goto Recover_platform;
}
suspend_test_finish("suspend devices");
if (suspend_test(TEST_DEVICES))
goto Recover_platform;
do {
error = suspend_enter(state, &wakeup); //正常休眠会停在该函数,如果唤醒了,则走下面的流程
} while (!error && !wakeup && need_suspend_ops(state)
&& suspend_ops->suspend_again && suspend_ops->suspend_again());
Resume_devices:
dpm_resume_end(PMSG_RESUME);
resume_console();
Close:
if (need_suspend_ops(state) && suspend_ops->end)
suspend_ops->end();
return error;
Recover_platform:
if (need_suspend_ops(state) && suspend_ops->recover)
suspend_ops->recover();
goto Resume_devices;
}
static int suspend_enter(suspend_state_t state, bool *wakeup)
{
error = dpm_suspend_end(PMSG_SUSPEND);
error = disable_nonboot_cpus();
arch_suspend_disable_irqs();
error = syscore_suspend();
if (!error) {
*wakeup = pm_wakeup_pending();
if (!(suspend_test(TEST_CORE) || *wakeup)) {
error = suspend_ops->enter(state);//停在这..........
events_check_enabled = false;
}
syscore_resume();
}
arch_suspend_enable_irqs();
Enable_cpus:
enable_nonboot_cpus();
Platform_wake:
if (need_suspend_ops(state) && suspend_ops->wake)
suspend_ops->wake();
dpm_resume_start(PMSG_RESUME);
Platform_finish:
if (need_suspend_ops(state) && suspend_ops->finish)
suspend_ops->finish();
return error;
}
/********************************************************************************************************************************************************
简单总结:
对state节点进行写操作会调用:state_store() -> pm_suspend() -> enter_state() -> suspend_prepare()准备冻结进程 -> suspend_freeze_processes()冻结所有进程
|—> suspend_devices_and_enter() -> suspend_ops->begin()->dpm_suspend_start()会依次调用驱动的suspend() 回调来休眠掉所有的设备。
|--> suspend_enter() -> suspend_ops->enter()最终停在这里,这个函数会关闭arch irq, 调用 device_power_down(),
它会调用suspend_late()函数, 这个函数是系统真正进入休眠最后调用的函数,通常会在这个函数中作最后的检查。 如果检查没问题,
接下来休眠所有的系统设备和总线,并且调用 suspend_pos->enter() 来使CPU进入省电状态,这时就已经休眠了。代码的执行也就停在这里了。
********************************************************************************************************************************************************/
首先有一个suspend事件,上层服务会使能autosuspend,接着修改count数值,判断是否有wakeup_lock被占用,若没有,向steat节点写值。
写值会调用一系列函数,先冻结进程,之后遍历执行设备链表中各个设备的suspend函数(dpm_suspend_start()),在关闭arch irq,休眠所有设备和总线(suspend_ops->enter())。
其中有任意一环不符合条件就会终止suspend,恢复之前的状态