Как работает 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 (чтобы она не терялась при отключении памяти); взгляните на следующие строки кода:

    1. _omap_sram_idle() присваивание (обратите внимание, что первый передаваемый ему параметр omap34xx_cpu_suspend адрес функции)
    2. реализация omap_sram_push(); обратите внимание на вызов memcpy (): omap_sram_ceil это начальный адрес памяти SRAM, start это адрес omap34xx_cpu_suspend() function
    3. реализация 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.
       */
      
  • фактический сон происходит в инструкции 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: этикетка.

Другие вопросы по тегам