讓系統 idle 時更省電_採用平臺相關 idle 函數以降低平均功耗的一個實踐
作者: 宋立新
Email:[email protected]
從 Linux 內核啓動說起。
話說某用戶按下開機鍵, bootloader 將內核放入內存,然後跳轉到內核首地址。
如果內核爲壓縮版本 ( zImage) 內核會進行自解壓, 然後運行非解壓內核(Image)。
Image 的代碼起點在 (arch/arm/kernel/head.S), 首先會初始化硬件(所做不多,因爲很多操作 bootloader 已經完成), 獲取 cpu id, machine id, 設置少量的頁表,然後打開 MMU。清空 BSS 後, 會跳轉到 C 語言函數 start_kernel
Start_kernel 調了很多早期初始化函數, 然後會調用 rest_init.
Rest_init 函數中, 會創建 init 線程,並調度它, 該線程最終調用用戶空間的 init 程序, 進化爲一切其他用戶程序的祖宗進程。
原來的 rest_init 會繼續執行,它先通過手工方式,把自己演變成0號進程, 然後調用 cpu_idle 函數, 此函數乃一 while(1){} 循環, 永不退出!
這樣, 系統啓動顯示運行0號進程,然後運行 1 號進程, 只有在系統沒事可幹時, 纔會調用 0 號進程, 所以, 0 號進程又叫 idle 進程。
那麼,idle 進程到底幹了些什麼呢?
簡單說, 它就是讓 cpu 進入 idle 狀態, 直到有事可幹, 才調用 schedule 讓系統切換出去。
Arm 平臺下, cpu_idle 會調用 pm_idle 函數指針指向的idle 函數, 缺省的, 它就是:default_idle() 函數, 繼而, 該函數會調用 arch_idle, arch_idle 會調用 cpu_do_idle, cpu_do_idle 會被映射到 某 CPU 特有的 idle 函數, 比如: cpu_xsc3_do_idle, 此乃一彙編函數, 其實現與具體 CPU 相關, 比如:
ENTRY(cpu_xsc3_do_idle)
mov r0, #1
mcr p14, 0, r0, c7, c0, 0 @ go to idle
mov pc, lr
這樣, Linux 內核儘量的爲我們省電, 當然, 它通過函數指針, 留下一個後門,我們可以利用它針對具體的板子做優化。
比如, marvell 內核中,就實現了:
if(pm_idle != mspm_do_idle) {
}
這樣, 在系統 idle 時,就會調用優化過的mspm_do_idle函數, 從而達到省電的目的。
mspm_do_idle 會讓 CPU 進入 其特有的 d0cs 模式, 該模式通過只使用 32K 低精度時鐘而省電。