1. 實驗平台
cpu: omap4460 blaze tablet
memory: 1-GB DRAM
OS: android 4.0.3, kernel 3.0.31
2.流程分析
1). echo "mem" > /sys/power/state
2). state_store() kernel/power/main.c
3). request_suspend_states(PM_SUSPEND_MEM) kernel/power/earlysuspend.c
4). queue_work(suspend_work_queue, &early_suspend_work) kernel/power/earlysuspend.c
early_suspend()
// call device driver's early-suspend function to turn off multi-touch, LCM, frame buffer,sensors,release "main" wakelock
5). wake_unlock(&main_wake_lock) kernel/power/wakelock.c
// if system has no activate wakelock,call kernel/power/wakelock.c suspend() start suspend progress.
6). queue_work(suspend_work_queue, &suspend_work);
7). suspend()
sys_sync()
pm_suspend()
// here enter suspend
// return from this function means exit suspend(resume)
8). pm_suspend(PM_SUSPEND_MEM)
enter_state()
sys_sync()
suspend_prepare()
pm_notifier_call_chain(PM_SUSPEND_PREPARE)
suspend_freeze_processes()
freeze_processes() kernel/power/process.c
// the same as hibernation process to freeze user space process and task in kernel
pm_restrict_gfp_mask()
// avoid i/o and fs to allocate memory during suspend progress
// clear bit GFP_IOFS of gfp_allowed_mask
suspend_devices_and_enter()
omap4_pm_begin() arch/arm/mach-omap2/pm44xx.c
suspend_prepare() drivers/regulator/core.c
// regulator linked with regulator_list
suspend_console()
dpm_suspend_start(PMSG_SUSPEND)
dpm_prepare(PMSG_SUSPEND) drivers/base/power/main.c
// execute ->prepare() callback for all non-sysdev devices, device list movement dpm_list-->dpm_prepared_list
dpm_suspend(PMSG_SUSPEND)
// execute ->suspend() callback for all non-sysdev devices, device list movement dpm_prepared_list-->dpm_suspended_list
suspend_enter()
dpm_suspend_noirq(PMSG_SUSPEND)
// execute "late suspend"
suspend_device_irqs() kernel/irq/pm.c
// disable all currently enabled interrupt lines
// after this function, device will can't receive interrupt
device_suspend_noirq()
// execute -->suspend_noirq callback for all non-sysdev devices, device list movement dpm_suspended_list-->dpm_noirq_list
disable_nonboot_cpus()
arch_suspend_disable_irqs() kernel/power/suspend.c
local_irq_disable()
// disable local cpu interrupt,so there will no interrtup from now on
syscore_suspend() driver/base/syscore.c
// Execute all the registered system core suspend callbacks
check_wakeup_irqs() kernel/irq/pm.c
// check if any wakeup interrupts are pending, if ture, exit suspend
// then to execute sysdev's suspend callback, all sysdev are linked with syscore_ops_list
omap4_pm_enter() arch/arm/mach-omap2/pm4xx.c
omap2_pm_wakeup_on_timer() arch/arm/mach-omap2/pm-debug.c
// setup a hareware timer if debug enabled
omap4_configure_pwrst(off_mode_enabled)
// Program all powerdomain(except cpu0_pwrdm and cpu1_pwrdm) to required power domain state
// powerdomain linked with pwrst_list
// off_mode_enabled = 1
omap4_device_set_state_off(1)
// setup device off state
omap4_enter_sleep()
pwrdm_clear_all_prev_pwrst()
//Clear the powerdomain's previous power state
omap4_device_clear_prev_off_state()
pwrdm_read_next_pwrst()
//get next powerdomain power state
omap2_gpio_prepare_for_idle()
omap2_gpio_set_wakeupenables()
// enable wakeup gpio in the list omap_gpio_list
omap4_print_wakeirq()
// resuming.
// Print wakeup interrupt for debug
xxxxxxx