linux suspend/wakeup 如何用于 mach-omap2?
How linux suspend/wakeup works for mach-omap2?
我想弄清楚 suspend/wakeup 是如何为 mach-omap2
实现的,特别是在针对 TI OMAP3530/DM3730.[=17= 的 Linux 2.6.37 中]
下面是一些相关代码:
http://lxr.free-electrons.com/source/arch/arm/mach-omap2/pm34xx.c?v=2.6.37
static int omap3_pm_suspend(void)
{
struct power_state *pwrst;
int state, ret = 0;
if (wakeup_timer_seconds || wakeup_timer_milliseconds)
omap2_pm_wakeup_on_timer(wakeup_timer_seconds,
wakeup_timer_milliseconds);
/* Read current next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node)
pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
/* Set ones wanted by suspend */
list_for_each_entry(pwrst, &pwrst_list, node) {
if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
goto restore;
if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
goto restore;
}
omap_uart_prepare_suspend();
omap3_intc_suspend();
omap_sram_idle();
restore:
/* Restore next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node) {
state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
if (state > pwrst->next_state) {
printk(KERN_INFO "Powerdomain (%s) didn't enter "
"target state %d\n",
pwrst->pwrdm->name, pwrst->next_state);
ret = -1;
}
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
}
if (ret)
printk(KERN_ERR "Could not enter target state in pm_suspend\n");
else
printk(KERN_INFO "Successfully put all powerdomains "
"to target state\n");
return ret;
}
我真的很难理解它是如何工作的。
看起来,当挂起过程运行到 omap_sram_idle();
之后,系统已经处于挂起模式,在此函数的上下文中,一切都冻结在那里。当它醒来时,它只是从 restore:
继续并恢复一切。这个对吗?
系统挂起发生在 omap_sram_idle()
的中间。 omap_sram_idle()
的第二部分实际上是恢复代码。更准确地说,实际休眠是由 omap34xx_cpu_suspend()
汇编函数中的 wfi
ARM 指令完成的。进一步阅读了解详情。
暂停路径
- 看看omap_sram_idle()函数实现
- 你可以看到(从注释判断)系统进入休眠前的最后一行是
_omap_sram_idle()
call (here)
_omap_sram_idle()
指向omap34xx_cpu_suspend() assembler function, which copied previously to SRAM(所以RAM掉电不会丢失);看看下一行代码:
- _omap_sram_idle() assignment(注意传递给它的第一个参数是
omap34xx_cpu_suspend
函数地址)
- omap_sram_push() implementation; pay attention to memcpy() call:
omap_sram_ceil
是SRAM内存的起始地址,start
是omap34xx_cpu_suspend() function
的地址
omap34xx_cpu_suspend() implementation; it's the actual function being executed at this line(而不是 _omap_sram_idle()
)。看看这个函数上面的评论:
/*
* Forces OMAP into idle state
*
* omap34xx_suspend() - This bit of code just executes the WFI
* for normal idles.
*
* Note: This code get's copied to internal SRAM at boot. When the OMAP
* wakes up it continues execution at the point it went to sleep.
*/
实际休眠发生在wfi(等待中断)ARM指令中(在omap34xx_cpu_suspend()
函数中);处理器会休眠,只有在某些 IRQ 发生时才会唤醒
omap34xx_cpu_suspend()
有2个地方可以执行wfi
:
还原路径
一旦发生唤醒信号,CPU 将继续执行 wfi
指令之后的指令(首先将其置于睡眠状态)。所以你的系统在 omap34xx_cpu_suspend()
汇编函数中唤醒(从 wait_sdrk_ok:
标签开始),然后 returns 回到 omap_sram_idle()
(到 this 行),然后 returns 回到 omap3_pm_suspend()
,回到 restore:
标签。
我想弄清楚 suspend/wakeup 是如何为 mach-omap2
实现的,特别是在针对 TI OMAP3530/DM3730.[=17= 的 Linux 2.6.37 中]
下面是一些相关代码:
http://lxr.free-electrons.com/source/arch/arm/mach-omap2/pm34xx.c?v=2.6.37
static int omap3_pm_suspend(void)
{
struct power_state *pwrst;
int state, ret = 0;
if (wakeup_timer_seconds || wakeup_timer_milliseconds)
omap2_pm_wakeup_on_timer(wakeup_timer_seconds,
wakeup_timer_milliseconds);
/* Read current next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node)
pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
/* Set ones wanted by suspend */
list_for_each_entry(pwrst, &pwrst_list, node) {
if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
goto restore;
if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
goto restore;
}
omap_uart_prepare_suspend();
omap3_intc_suspend();
omap_sram_idle();
restore:
/* Restore next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node) {
state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
if (state > pwrst->next_state) {
printk(KERN_INFO "Powerdomain (%s) didn't enter "
"target state %d\n",
pwrst->pwrdm->name, pwrst->next_state);
ret = -1;
}
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
}
if (ret)
printk(KERN_ERR "Could not enter target state in pm_suspend\n");
else
printk(KERN_INFO "Successfully put all powerdomains "
"to target state\n");
return ret;
}
我真的很难理解它是如何工作的。
看起来,当挂起过程运行到 omap_sram_idle();
之后,系统已经处于挂起模式,在此函数的上下文中,一切都冻结在那里。当它醒来时,它只是从 restore:
继续并恢复一切。这个对吗?
系统挂起发生在 omap_sram_idle()
的中间。 omap_sram_idle()
的第二部分实际上是恢复代码。更准确地说,实际休眠是由 omap34xx_cpu_suspend()
汇编函数中的 wfi
ARM 指令完成的。进一步阅读了解详情。
暂停路径
- 看看omap_sram_idle()函数实现
- 你可以看到(从注释判断)系统进入休眠前的最后一行是
_omap_sram_idle()
call (here) _omap_sram_idle()
指向omap34xx_cpu_suspend() assembler function, which copied previously to SRAM(所以RAM掉电不会丢失);看看下一行代码:- _omap_sram_idle() assignment(注意传递给它的第一个参数是
omap34xx_cpu_suspend
函数地址) - omap_sram_push() implementation; pay attention to memcpy() call:
omap_sram_ceil
是SRAM内存的起始地址,start
是omap34xx_cpu_suspend() function
的地址
omap34xx_cpu_suspend() implementation; it's the actual function being executed at this line(而不是
_omap_sram_idle()
)。看看这个函数上面的评论:/* * Forces OMAP into idle state * * omap34xx_suspend() - This bit of code just executes the WFI * for normal idles. * * Note: This code get's copied to internal SRAM at boot. When the OMAP * wakes up it continues execution at the point it went to sleep. */
- _omap_sram_idle() assignment(注意传递给它的第一个参数是
实际休眠发生在wfi(等待中断)ARM指令中(在
omap34xx_cpu_suspend()
函数中);处理器会休眠,只有在某些 IRQ 发生时才会唤醒omap34xx_cpu_suspend()
有2个地方可以执行wfi
:
还原路径
一旦发生唤醒信号,CPU 将继续执行 wfi
指令之后的指令(首先将其置于睡眠状态)。所以你的系统在 omap34xx_cpu_suspend()
汇编函数中唤醒(从 wait_sdrk_ok:
标签开始),然后 returns 回到 omap_sram_idle()
(到 this 行),然后 returns 回到 omap3_pm_suspend()
,回到 restore:
标签。