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 {

.enters3c6410_pm_enter,

.validsuspend_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));

……

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值