Android休眠唤醒驱动流程分析(二)

suspend_freeze_processes()函数中调用了freeze_processes()函数,而freeze_processes()函数中又调用了try_to_freeze_tasks()来完成冻结任务。在冻结过程中,会判断当前进程是否有wake_lock,若有,则冻结失败,函数会放弃冻结。

static int try_to_freeze_tasks(bool sig_only)

{

struct task_struct *g, *p;

unsigned long end_time;

unsigned int todo;

struct timeval start, end;

u64 elapsed_csecs64;

unsigned int elapsed_csecs;

unsigned int wakeup = 0;

 

do_gettimeofday(&start);

 

end_time = jiffies + TIMEOUT;

do {

todo = 0;

read_lock(&tasklist_lock);

do_each_thread(g, p) {

if (frozen(p) || !freezeable(p))

continue;

 

if (!freeze_task(p, sig_only))

continue;

 

 

if (!task_is_stopped_or_traced(p) &&

    !freezer_should_skip(p))

todo++;

} while_each_thread(g, p);

read_unlock(&tasklist_lock);

yield();

if (todo && has_wake_lock(WAKE_LOCK_SUSPEND)) {

wakeup = 1;

break;

}

if (time_after(jiffies, end_time))

break;

} while (todo);

 

do_gettimeofday(&end);

elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);

do_div(elapsed_csecs64, NSEC_PER_SEC / 100);

elapsed_csecs = elapsed_csecs64;

 

if (todo) {

 

if(wakeup) {

printk("\n");

printk(KERN_ERR "Freezing of %s aborted\n",

sig_only ? "user space " : "tasks ");

}

else {

printk("\n");

printk(KERN_ERR "Freezing of tasks failed after %d.d seconds "

"(%d tasks refusing to freeze):\n",

elapsed_csecs / 100, elapsed_csecs % 100, todo);

show_state();

}

read_lock(&tasklist_lock);

do_each_thread(g, p) {

task_lock(p);

if (freezing(p) && !freezer_should_skip(p))

printk(KERN_ERR " %s\n", p->comm);

cancel_freezing(p);

task_unlock(p);

} while_each_thread(g, p);

read_unlock(&tasklist_lock);

} else {

printk("(elapsed %d.d seconds) ", elapsed_csecs / 100,

elapsed_csecs % 100);

}

return todo ? -EBUSY : 0;

}

 

现在所有的进程(也包括workqueue/kthread) 都已经停止了内核态进程有可能在停止的时候握有一些信号量所以如果这时候在外设里面去解锁这个信号量有可能会发生死锁 所以在外设suspend()函数里面作lock/unlock锁要非常小心建议不要在外设的suspend()里面等待锁而且suspend过程中,有一些log是无法输出的所以一旦出现问题非常难调试

 

回到enter_state()函数中,再冻结进程完成后,调用suspend_devices_and_enter()函数让外设进入休眠。该函数中,首先休眠串口(之后不能再显示log,解决方法为在kernel配置选项的cmd_line中,添加no_console_suspend选项),再通过device_suspend()函数调用各驱动的suspend函数。

当外设进入休眠后,suspend_ops->prepare()被调用,suspend_ops是板级的PM操作(本文中粉红色的函数,依赖于具体的平台),以s3c6410为例,其注册在linux_source/arch/arm/plat-s3c64xx/pm.c中,只定义了suspend_ops->enter()函数。

static struct platform_suspend_ops s3c6410_pm_ops = {

.enter = s3c6410_pm_enter,

.valid = suspend_valid_only_mem,

};

接下来,多CPU中的非启动CPU被关闭。

int suspend_devices_and_enter(suspend_state_t state)

{

int error;

 

if (!suspend_ops)

return -ENOSYS;

 

if (suspend_ops->begin) {

error = suspend_ops->begin(state);

if (error)

goto Close;

}

suspend_console();

suspend_test_start();

error = device_suspend(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;

 

if (suspend_ops->prepare) {

error = suspend_ops->prepare();

if (error)

goto Resume_devices;

}

 

if (suspend_test(TEST_PLATFORM))

goto Finish;

 

error = disable_nonboot_cpus();

if (!error && !suspend_test(TEST_CPUS))

suspend_enter(state);

 

enable_nonboot_cpus();

 Finish:

if (suspend_ops->finish)

suspend_ops->finish();

 Resume_devices:

suspend_test_start();

device_resume(PMSG_RESUME);

suspend_test_finish("resume devices");

resume_console();

 Close:

if (suspend_ops->end)

suspend_ops->end();

return error;

 

 Recover_platform:

if (suspend_ops->recover)

suspend_ops->recover();

goto Resume_devices;

}

 

接下来suspend_enter()被调用,该函数首先关闭IRQ,然后调用device_power_down(), 它会调用suspend_late()函数这个函数是系统真正进入休眠最后调用的函数通常会在这个函数中作最后的检查接下来休眠所有的系统设备和总线。最后调用 suspend_pos->enter() 来使CPU进入省电状态这时候,整个休眠过程完成,代码的执行也就停在这里了

static int suspend_enter(suspend_state_t state)

{

int error = 0;

 

device_pm_lock();

#ifdef CONFIG_CPU_FREQ

cpufreq_get_cpufreq_name(0);

strcpy(governor_name, cpufreq_governor_name);

if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) {

cpufreq_set_policy(0, "performance");

}

#endif 

arch_suspend_disable_irqs();

BUG_ON(!irqs_disabled());

 

if ((error = device_power_down(PMSG_SUSPEND))) {

printk(KERN_ERR "PM: Some devices failed to power down\n");

goto Done;

}

 

error = sysdev_suspend(PMSG_SUSPEND);

if (!error) {

if (!suspend_test(TEST_CORE))

error = suspend_ops->enter(state);

sysdev_resume();

}

 

device_power_up(PMSG_RESUME);

 Done:

arch_suspend_enable_irqs();

#ifdef CONFIG_CPU_FREQ

if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) {

cpufreq_set_policy(0, governor_name);

}

#endif 

BUG_ON(irqs_disabled());

device_pm_unlock();

return error;

}

 

suspend_pos->enter()所对应的函数中,代码最终停止在pm_cpu_sleep();处。

static int s3c6410_pm_enter(suspend_state_t state)

{

 ……

s3c6410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));

s3c6410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));

s3c6410_pm_do_save(core_save, ARRAY_SIZE(core_save));

s3c6410_pm_do_save(sromc_save, ARRAY_SIZE(sromc_save));

 

 

 

__raw_writel(__raw_readl(S3C_WAKEUP_STAT), S3C_WAKEUP_STAT);

 

 

#ifdef CONFIG_MACH_SMDK6410

 

__raw_writel(0xffffff00, S3C_NORMAL_CFG);

 

 

__raw_writel(0xffffffff, S3C_HCLK_GATE);

__raw_writel(0xffffffff, S3C_PCLK_GATE);

__raw_writel(0xffffffff, S3C_SCLK_GATE);

        ……

 

 

if (s3c6410_cpu_save(regs_save) == 0) {

flush_cache_all();

pm_cpu_sleep();

}

 

 

cpu_init();

 

__raw_writel(s3c_eint_mask_val, S3C_EINT_MASK);

 

 

s3c6410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));

s3c6410_pm_do_restore(sromc_save, ARRAY_SIZE(sromc_save));

……

}

 

你可能感兴趣的:(Android休眠唤醒驱动流程分析(二))