Tuesday, March 12, 2013

pm-cpuidle: High level code flow from bootup

When the kernel boots up, it starts as a single thread for which PID = 0. It is named as "swapper". This eventually calls cpu_idle() (which is architecture specific function) and this task is nothing but idle task.

init/main.c
start_kernel(void)
{
  ...
  rest_init();

  This is the last function that is called after all inits are called.
}


rest_init()
{
  ...
  /* We need to spawn init first so that it obtains pid 1, however
   * the init task will end up wanting to create kthreads, which, if
   * we schedule it before we create kthreadd, will OOPS.
   */
  kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);    PID = 1
  ...
  pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);   PID = 2
  ...
  /*
   * The boot idle thread must execute schedule()
   * at least once to get things moving:
   */
  init_idle_bootup_task(current);
  schedule_preempt_disabled();
  /* Call into cpu_idle with preempt disabled */
  cpu_idle();     PID = 0

}

arch/arm/kernel/process.c
cpu_idle()
 
{
  ...
  /* endless idle loop with no priority at all */
  while (1) {

    ...
    while (!need_resched()) {
      ...
      if (cpuidle_idle_call())     
        pm_idle()
      If CPU_IDLE is enabled, in non-error case, cpuidle_idle_call()
      returns 0. Thereby pm_idle() is not called. Determining and
      entering the sleep state is done in cpuidle_idle_call()
      itself.
      ...
    }
  }
}

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
pm_idle()
 cpu_do_idle() => cpu_v7_do_idle

arch/arm/mm/proc-v7.S
 ENTRY(cpu_v7_do_idle)
    dsb           @ WFI may enter a low-power mode
    wfi
    mov     pc, lr
 ENDPROC(cpu_v7_do_idle)
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


drivers/cpuidle/cpuidle.c
int cpuidle_idle_call(void)
{
  ...
  /* ask the governor for the next state */
 
  next_state = cpuidle_curr_governor->select(drv, dev);
  Current cpuidle governer identifies the appropriate idle
  state. Platform data is used by the governor to select the
  approprite sleep state.
  ...
  entered_state = cpuidle_enter_ops(dev, drv, next_state);

  Here we enter the idle state suggested by current cpuidle
  governor. Platform specific code comes into picture to set
  the appropriate idle state. 
  ...
}



[Based on Linux kernel v3.4]

No comments:

Post a Comment