Как работает linux suspend/wakeup для mach-omap2?
Я пытаюсь выяснить, как приостановка / пробуждение реализовано для mach-omap2
В частности, в Linux 2.6.37 для TI OMAP3530/DM3730.
Вот некоторый связанный код:
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:
и восстанавливает все. Это правильно?
1 ответ
Система приостановки происходит в середине omap_sram_idle()
, Вторая часть omap_sram_idle()
на самом деле восстанавливает код. Точнее, фактический сон осуществляется wfi
ARM инструкция в omap34xx_cpu_suspend()
ассемблерная функция. Читайте дальше для деталей.
Приостановить путь
- взгляните на реализацию функции omap_sram_idle()
- Вы можете видеть (судя по комментариям), что последняя строка перед сном системы
_omap_sram_idle()
позвонить ( здесь) _omap_sram_idle()
указывает на функцию ассемблера omap34xx_cpu_suspend(), которая ранее была скопирована в SRAM (чтобы она не терялась при отключении памяти); взгляните на следующие строки кода:- _omap_sram_idle() присваивание (обратите внимание, что первый передаваемый ему параметр
omap34xx_cpu_suspend
адрес функции) - реализация omap_sram_push(); обратите внимание на вызов memcpy ():
omap_sram_ceil
это начальный адрес памяти SRAM,start
это адресomap34xx_cpu_suspend() function
реализация omap34xx_cpu_suspend(); это фактическая функция, выполняемая в этой строке (вместо
_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() присваивание (обратите внимание, что первый передаваемый ему параметр
фактический сон происходит в инструкции ARM wfi (Wait For Interrupt)
omap34xx_cpu_suspend()
функция); процессор будет спать, и он проснется только тогда, когда произойдет некоторое прерывание- есть 2 места в
omap34xx_cpu_suspend()
когдаwfi
может быть выполнен:
Восстановить путь
Как только прозвучит сигнал пробуждения, CPU продолжит выполнять инструкции сразу после wfi
инструкция (которые уложили его в первую очередь). Итак, ваша система просыпается в omap34xx_cpu_suspend()
функция ассемблера (начиная с wait_sdrk_ok:
метка), затем возвращается к omap_sram_idle()
(к этой строке), а затем возвращается к omap3_pm_suspend()
, чтобы restore:
этикетка.