android 休眠喚醒流程及定位喚醒問題總結
阿新 • • 發佈:2018-12-31
平臺資訊:
核心:linux 2.6.35
android:2.3.1
CPU:三星S5PV210
就從earlysuspend.c中說起,在early suspend中執行完所有驅動的early suspend後會呼叫wake_unlock,在wake_unlock函式中,如果判斷系統已經沒有喚醒鎖,則會排程休眠的工作佇列,此時就會執行佇列函式suspend。
見定義:static DECLARE_WORK(suspend_work, suspend);
suspend就是開始進行linux休眠的函式。
呼叫關係如下:
static void suspend(struct work_struct *work)
--> int pm_suspend(suspend_state_t state)
--> int enter_state(suspend_state_t state)
在此函式中要做一些準備工作:
同步檔案系統(sys_sync);
分配控制檯和凍結所有的程序(suspend_prepare)等;
然後呼叫下面這個函式;
[cpp] view plaincopyprint?- int suspend_devices_and_enter(suspend_state_t state)
- {
- int error;
- gfp_t saved_mask;
- /*判斷休眠的操作函式集合指標是否被賦值,此指標會在對應的平臺電源管理模組中被賦值
- 在s5pv210平臺中是在plat-samsung/pm.c中*/
- if (!suspend_ops)
- return -ENOSYS;
- if (suspend_ops->begin) {
- error = suspend_ops->begin(state);
- if (error)
- goto Close;
- }
- suspend_console();//suspend console subsystem,此時printk就不能列印資訊,但還有其他方式可以進行列印
- saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
- suspend_test_start();
- error = dpm_suspend_start(PMSG_SUSPEND);//在此函式裡,會調到驅動註冊的所有suspend函式,如果想知道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;
- suspend_enter(state); //在此函式中會呼叫到系統的休眠功能,使系統進入sleep模式,而系統也就會停留在
- 休眠的地方,當喚醒的時候再繼續往下執行。
- Resume_devices: //當系統被外部中斷喚醒的時候,這裡會被執行到
- suspend_test_start();
- dpm_resume_end(PMSG_RESUME);//此函式會執行resume流程,會呼叫驅動中註冊的所有resume函式。
- suspend_test_finish("resume devices");
- set_gfp_allowed_mask(saved_mask);
- resume_console();
- Close:
- if (suspend_ops->end)
- suspend_ops->end();
- return error;
- Recover_platform:
- if (suspend_ops->recover)
- suspend_ops->recover();
- goto Resume_devices;
- }
- staticstruct platform_suspend_ops s3c_pm_ops = {
- .enter = s3c_pm_enter, //作業系統暫存器的介面,裡面會使系統進入休眠/喚醒狀態,在其中會保留系統的暫存器的值,設定好外部喚醒源。執行完s3c_cpu_save系統就進入了休眠模式。
- 當系統被喚醒時,再從s3c_cpu_save這個函式下面開始執行。
- .prepare = s3c_pm_prepare,//為建立CRC校驗做準備,分配存放CRC值的記憶體。
- .finish = s3c_pm_finish,
- .valid = suspend_valid_only_mem,
- };//這個是s5pv210中定義的平臺的電源管理操作介面,suspend_ops會指向這個結構體變數的指標
- staticint suspend_enter(suspend_state_t state)
- {
- int error;
- if (suspend_ops->prepare) {
- error = suspend_ops->prepare();
- if (error)
- return error;
- }
- error = dpm_suspend_noirq(PMSG_SUSPEND);
- if (error) {
- printk(KERN_ERR "PM: Some devices failed to power down\n");
- goto Platfrom_finish;
- }
- if (suspend_ops->prepare_late) {
- error = suspend_ops->prepare_late();
- if (error)
- goto Power_up_devices;
- }
- if (suspend_test(TEST_PLATFORM))
- goto Platform_wake;
- error = disable_nonboot_cpus();
- if (error || suspend_test(TEST_CPUS))
- goto Enable_cpus;
- arch_suspend_disable_irqs();
- BUG_ON(!irqs_disabled());
- error = sysdev_suspend(PMSG_SUSPEND);
- if (!error) {
- if (!suspend_test(TEST_CORE))
- error = suspend_ops->enter(state); //呼叫此函式進行休眠
- sysdev_resume();
- }
- arch_suspend_enable_irqs();
- BUG_ON(irqs_disabled());
- Enable_cpus:
- enable_nonboot_cpus();
- Platform_wake:
- if (suspend_ops->wake)
- suspend_ops->wake();
- Power_up_devices:
- dpm_resume_noirq(PMSG_RESUME);
- Platfrom_finish:
- if (suspend_ops->finish)
- suspend_ops->finish();
- return error;
- }
int suspend_devices_and_enter(suspend_state_t state)
{
int error;
gfp_t saved_mask;
/*判斷休眠的操作函式集合指標是否被賦值,此指標會在對應的平臺電源管理模組中被賦值
在s5pv210平臺中是在plat-samsung/pm.c中*/
if (!suspend_ops)
return -ENOSYS;
if (suspend_ops->begin) {
error = suspend_ops->begin(state);
if (error)
goto Close;
}
suspend_console();//suspend console subsystem,此時printk就不能列印資訊,但還有其他方式可以進行列印
saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
suspend_test_start();
error = dpm_suspend_start(PMSG_SUSPEND);//在此函式裡,會調到驅動註冊的所有suspend函式,如果想知道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;
suspend_enter(state); //在此函式中會呼叫到系統的休眠功能,使系統進入sleep模式,而系統也就會停留在
休眠的地方,當喚醒的時候再繼續往下執行。
Resume_devices: //當系統被外部中斷喚醒的時候,這裡會被執行到
suspend_test_start();
dpm_resume_end(PMSG_RESUME);//此函式會執行resume流程,會呼叫驅動中註冊的所有resume函式。
suspend_test_finish("resume devices");
set_gfp_allowed_mask(saved_mask);
resume_console();
Close:
if (suspend_ops->end)
suspend_ops->end();
return error;
Recover_platform:
if (suspend_ops->recover)
suspend_ops->recover();
goto Resume_devices;
}
static struct platform_suspend_ops s3c_pm_ops = {
.enter = s3c_pm_enter, //作業系統暫存器的介面,裡面會使系統進入休眠/喚醒狀態,在其中會保留系統的暫存器的值,設定好外部喚醒源。執行完s3c_cpu_save系統就進入了休眠模式。
當系統被喚醒時,再從s3c_cpu_save這個函式下面開始執行。
.prepare = s3c_pm_prepare,//為建立CRC校驗做準備,分配存放CRC值的記憶體。
.finish = s3c_pm_finish,
.valid = suspend_valid_only_mem,
};//這個是s5pv210中定義的平臺的電源管理操作介面,suspend_ops會指向這個結構體變數的指標
static int suspend_enter(suspend_state_t state)
{
int error;
if (suspend_ops->prepare) {
error = suspend_ops->prepare();
if (error)
return error;
}
error = dpm_suspend_noirq(PMSG_SUSPEND);
if (error) {
printk(KERN_ERR "PM: Some devices failed to power down\n");
goto Platfrom_finish;
}
if (suspend_ops->prepare_late) {
error = suspend_ops->prepare_late();
if (error)
goto Power_up_devices;
}
if (suspend_test(TEST_PLATFORM))
goto Platform_wake;
error = disable_nonboot_cpus();
if (error || suspend_test(TEST_CPUS))
goto Enable_cpus;
arch_suspend_disable_irqs();
BUG_ON(!irqs_disabled());
error = sysdev_suspend(PMSG_SUSPEND);
if (!error) {
if (!suspend_test(TEST_CORE))
error = suspend_ops->enter(state); //呼叫此函式進行休眠
sysdev_resume();
}
arch_suspend_enable_irqs();
BUG_ON(irqs_disabled());
Enable_cpus:
enable_nonboot_cpus();
Platform_wake:
if (suspend_ops->wake)
suspend_ops->wake();
Power_up_devices:
dpm_resume_noirq(PMSG_RESUME);
Platfrom_finish:
if (suspend_ops->finish)
suspend_ops->finish();
return error;
}
遇到喚醒/休眠不了的問題的定位方法:
首先要讓串列埠打印出來,開啟核心除錯選項,在s5pv210平臺中;
Kernel hacking --->
Kernel debugging
System Type --->
S3C2410 PM Suspend debug
開啟這兩個選項後,就可以列印休眠/喚醒前後的所有資訊。
如果需要檢視在哪個驅動喚醒/休眠出問題了,可以通過列印來定位。
注:late_resume要等到android設定on到/sys/power/state才會被呼叫到。