1. 程式人生 > >android 核心power電源管理

android 核心power電源管理

linux核心有一套電源管理的機制,休眠/喚醒在嵌入式Linux中是非常重要的部分,而android是基於linux核心的,它在此機制基本上作了改進。

本文只是針對參考程式碼總結的具體性的知識,其它有關係統知識網上一大堆,可自己搜尋學習。

一,裝置檔案的生成:/sys/power/state 核心中的相關檔案: Kernel/power/main.c Kernel/power/suspend.c
註冊pm的流程: static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,   const char *buf, size_t n); static struct attribute * g[] = {&state_attr.attr, …… static struct attribute_group attr_group = {.attrs = g,}; static int __init pm_init(void); core_initcall(pm_init); 註冊後生成/sys /power/state 檔案,使用者可以通過讀寫sys檔案/sys /power/state 是實現控制系統休眠\喚酲 echo on/mem > /sys/power/state enter_state 是負責處理進入何種狀態的函式。在linux裡,電源管理基本都經過如下幾步: 1. suspend_prepare():分配console終端、廣播notify、凍結所有程序、儲存當前狀態 2. suspend_enter():休眠所有外設、關閉irq、休眠系統裝置和匯流排、cpu省電狀態 3. suspend_finish():恢復所有的程序 休眠的三個主要步驟: a,凍結使用者態程序和核心態任務 b,呼叫註冊裝置的suspend回撥函式 c,停止核心態所有程序,儲存上下文,使CPU進入休眠。 喚醒條件:中斷或事件喚醒系統 喚醒順序: 系統裝置與匯流排最先喚醒 恢復核心態程序 重啟各個裝置 Suspend_finish()解凍程序和任務並Notify狀態喚醒終端

二,suspend_prepare和suspend_devices_and_enter詳解

1,suspend_prepare詳解

suspend_prepare - Do prep work before entering low-power state.that is called for that we're entering.Run suspend notifiers, allocate a console and stop all processes. static int suspend_prepare(void) { pm_prepare_console();   // 建立虛擬console以便匯出輸出列印資訊,防止阻塞 error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); error = usermodehelper_disable(); error = suspend_freeze_processes(); suspend_thaw_processes();  //前面出現錯誤,下面是恢復操作 usermodehelper_enable();  Finish: pm_notifier_call_chain(PM_POST_SUSPEND); pm_restore_console(); } pm_notifier_call_chain(PM_SUSPEND_PREPARE); 呼叫Linux系統的notifier_call_chain,通知相關的子系統正在進行suspend 系統的準備工作,提示相關子系統做出相應的操作準備。 Notifier chain是Linux的一種核心態子系統通知機制,當某一個子系統發生一些事件,會通知相關的子系統,實現資訊共享,前提是其它子系統事先註冊了對應的通知回撥函式。 Notification chain由notifier block組成,其結構型別如下(include/linux/notifier.h): struct notifier_block{ int (*notifier_call)(struct notifier_block *self, unsigned long, void *); struct notifier_block *next; int priority;}; blocking_notifier_chain_register(struct notifier_block*); //註冊函式 blocking_notifier_call_chain();   //處理函式 例項參考:/arch/arm/mach-s5pv210/cpu-freq.c / * usermodehelper_disable - prevent new helpers from being started usermodehelper_disable(); 一般都是使用者態直接通知同核態做相應處理,但有的時候需要從核心通知使用者態來處理事件,這時候就用到user mode helper /**tell processes to enter the refrigerator suspend_freeze_processes(); 凍結所有程序,並儲存當前程序狀態。 linux是用它的freeze框架加上訊號處理來實現程序凍結的,在freeze所有程序的時候並沒有將之掛起或者說使其不再執行,而是在訊號處理的開始掛了一個類似於鉤子的東西,把掛起程序交給訊號處理來做,freeze框架要做的就是設定一些標誌位來指示訊號處理要凍結它了,然後設定此程序的訊號附著位,這樣該程序在返回使用者空間的時候就會進入到凍結狀態了。 /kernel/power/process.c   freeae_process(); /arch/arm/kernel/signal.c   do_signal(); suspend_thaw_processes(); usermodehelper_enable();  Finish: pm_notifier_call_chain(PM_POST_SUSPEND); pm_restore_console(); 以上的處理是在前面的處理過程失敗後,恢復到此前狀態的操作 2,suspend_devices_and_enter
詳解 /*suspend_devices_and_enter - suspend devices and enter the desired system int suspend_devices_and_enter(suspend_state_t state) { suspend_console();   //真正掛起console dpm_suspend_start(PMSG_SUSPEND); suspend_enter(state);  Resume_devices: //當掛起出現錯誤或恢復系統時執行下面部分 suspend_test_start(); dpm_resume_end(PMSG_RESUME); resume_console();  } //****Prepare devices for PM transition and suspend them. dpm_suspend_start(PMSG_SUSPEND) { error = dpm_prepare(state);// Prepare all non-sysdev devices for a system PM transition. if (!error) error = dpm_suspend(state);// Execute "suspend" callbacks for all non-sysdev devices. } //**enter the desired system sleep state. should be called after devices have been suspended. static int suspend_enter(suspend_state_t state) { dpm_suspend_noirq(PMSG_SUSPEND); //Execute "late suspend" callbacks for non-sysdev devices error = disable_nonboot_cpus();//關閉非啟動的CPU arch_suspend_disable_irqs(); //關閉所有的中斷 error = sysdev_suspend(PMSG_SUSPEND);//關閉所有的裝置 if (!error) { sysdev_resume(); } arch_suspend_enable_irqs(); BUG_ON(irqs_disabled());  Enable_cpus: enable_nonboot_cpus();  Power_up_devices: dpm_resume_noirq(PMSG_RESUME);

三,被管理的設備註冊相應的suspend和resume函式:

各設備註冊:      void register_early_suspend(struct early_suspend *handler); enum { EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50, EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100, EARLY_SUSPEND_LEVEL_DISABLE_FB = 150, }; 裝置休眠優先順序,低--à高 struct early_suspend { struct list_head link; int level; void (*suspend)(struct early_suspend *h); void (*resume)(struct early_suspend *h); }; 四,power on/off流程:

在第一步的時候,註冊模組到核心中會生成一個裝置檔案/sys /power/state

使用者可以通過讀寫sys檔案/sys /power/state 是實現控制系統休眠\喚酲 echo on/mem > /sys/power/state void request_suspend_state(suspend_state_t new_state) {……. If (new_state == PM_SUSPEND_MEM) queue_work(suspend_work_queue, &early_suspend_work); else If (new_state == PM_SUSPEND_ON) queue_work(suspend_work_queue, &late_resume_work); }

根據不同的命令queue_work相應的佇列,每個佇列都是各模組在啟動時註冊組成的,

list_for_each_entry(pos, &early_suspend_handlers, link)  {
if (pos->suspend != NULL)
pos->suspend(pos);
}
list_for_each_entry_reverse(pos, &early_suspend_handlers, link) { if (pos->resume != NULL) pos->resume(pos); } Linux 系統休眠幾種狀態 •echo  ???  > /dev/power/state •1,on ------ 喚醒系統resume •2,standy ---- 休眠(程序狀態儲存到memory,相對mem耗電,但恢復更快) •3,mem ----- 休眠(程序狀態儲存到memory) •4,disk ----- 休眠 (程序狀態儲存到磁碟,一般為swap分割槽)

在SMDKC11平臺下,核心在除錯的時候,如果進入到核心層的休眠,怎麼會同時關閉console,導致無法列印,給除錯帶來了難度,可修改程式碼以達到在核心層休眠時,console仍然能夠列印資訊,具體方法是:在/drivers/serial/samsung.c中,將s3c24xx_serial_init()中的suspend 和resume賦值語句登出掉。