102
The Power On Linux-Kernel 課課Linux-Kernel At Summer Training In 2014. 課課 課課課課 課課課 :、 課課 課課課課課

2014暑期訓練之Linux kernel power

  • Upload
    -

  • View
    778

  • Download
    0

Embed Size (px)

DESCRIPTION

2014成功大學嵌入式系統實驗室暑期訓練之Linux Kernel(Power)的追蹤程式碼

Citation preview

Page 1: 2014暑期訓練之Linux kernel power

The PowerOn

Linux-Kernel

課程: Linux-Kernel At Summer Training In 2014.

學生:陳冠宇、郭儲嘉老師:張大緯老師

Page 2: 2014暑期訓練之Linux kernel power

• Agenda• Introduction

Why we choice

Data structure in “Kconfig”

• Explain Code

autosleep.c

poweroff.c

suspend.c

• Summary

2014

/8/2

6

2

Page 3: 2014暑期訓練之Linux kernel power

• Introduction

Why we choice.

Data structure in “Kconfig”

2014

/8/2

6

3

Page 4: 2014暑期訓練之Linux kernel power

• Why we choice

 「電」的問題無論在任何電器用品上都是重要的一環。任何控制設備都與電息息相關,舉凡開關機、待機、休眠、外接設備的驅動程式等皆與「電」脫離不了關係。 鑑於此,選擇此主題將是我們對於核心與外部設施連接的最佳切入點。

2014

/8/2

6

4

Page 5: 2014暑期訓練之Linux kernel power

• Kconfig• SUSPEND• SUSPEND_FREEZER • HIBERNATION• PM_STD_PARTITION• PM_AUTOSLEEP • PM_WAKELOCK • PM_RUNTIME • PM_DEBUG • PM_ADVANCED_DEBUG • PM_SUSPEND_TEST

2014

/8/2

6

5

Page 6: 2014暑期訓練之Linux kernel power

• SUSPEND•允許系統進入睡眠狀態。在對記憶體供電的狀況下將內容保存起來。例如: SUSPEND– TO–RAM.•相依於 ARCH_SUSPEND_POSSIBLE.

• SUSPEND_FREEZER•如果關閉此功能,在暫停的狀況下就不會讓任務凍結。 (強烈不推薦關閉 )• 相依於 SUSPEND.

2014

/8/2

6

6

Page 7: 2014暑期訓練之Linux kernel power

• HIBERNATION•啟動「 Suspend to disk(STD)」的功能,在許多作業系統的 User Interface之中,大家都稱呼他為「休眠」。 STD會將確認點放置於系統當中以確認系統的資料從記憶體儲存到硬碟當中,並將之斷電。當重新啟動的時候,此確認點將會置放於 reboot上。•相依於• SWAP• ARCH_HIBERNATION_POSSIBLE

2014

/8/2

6

7

Page 8: 2014暑期訓練之Linux kernel power

• HIBERNATION(contd.)

•在 Kconfig中有推薦使用者可以將 resume的路徑放置在核心的 bootloader的配置檔案( configuration file)當中。

2014

/8/2

6

8

Page 9: 2014暑期訓練之Linux kernel power

• PM_STD_PARTITION

•預設的重新啟動區域在做 STD時將會尋找映像檔案以完成動作。幾乎全部的使用者在此區域上都會有所不同。•該配置( PM_STD_PARTITION)必須在暫停之前設置成 SWAP磁區,否則休眠後將無法甦醒。另外,該磁區是可以被指定覆寫的。格式: resume=/dev/<other device>

範例: resume=/dev/sda2•相依於 HIBERNATION

2014

/8/2

6

9

Page 10: 2014暑期訓練之Linux kernel power

• PM_AUTOSLEEP

•允許核心觸發系統功能「進入全域性的睡眠模式」,只要沒有任何喚醒源有活動將之影響到,就不會導致喚醒的動作發生。• 相依於 PM_SLEEP(尋根究底和 SUSPEND有關 )

• PM_WAKELOCK•允許使用者空間可以搭配 sysfs-based的

Interface去創造、啟動和關閉喚醒源的事件。• 相依於 PM_SLEEP.

2014

/8/2

6

10

Page 11: 2014暑期訓練之Linux kernel power

• PM_WAKELOCK(contd.)

• Sysfs:為 Linux2.6所提供的虛擬檔案系統,這個檔案系統不僅可以把裝置、驅動程式的資訊從核心輸到用戶空間,也可以用來對裝置和驅動程式做設定。每個被加入 Driver model tree的物件包括驅動程式、裝置等都會在 sysfs檔案系統中以目錄的方式呈現。

2014

/8/2

6

11

Page 12: 2014暑期訓練之Linux kernel power

• PM_RUNTIME

•允許 I/O裝置可以在特別指定的閒置週期過後的 run-time狀況下進入低功耗狀態,如果有硬體生成的喚醒事件或是由裝置需求導致而產生,將會為了回應這些事件而導致其甦醒。• 相依於 !IA64_HP_SIM(init/Kconfig)

2014

/8/2

6

12

Page 13: 2014暑期訓練之Linux kernel power

• 各種硬體配置、工業標準等。

2014

/8/2

6

13

Page 14: 2014暑期訓練之Linux kernel power

• PM_ADVANCED_DEBUG

•該選項允許在 Power management code中做各種調整的支援,這對於 PM在 Debug和回報錯誤上是相當有幫助,例如 suspend support。• 相依於 PM.

• PM_DEBUG

•加入一個額外的 sysfs的屬性,從使用者的空間去訪問裝置物件中 PM的檔案。•在此該註解特別提醒:「如果您不是一個對

除錯和測試 PM相當有興趣的核心系統開發人員,請別任意使用。」• 相依於 PM_DEBUG.

2014

/8/2

6

14

Page 15: 2014暑期訓練之Linux kernel power

• PM_SUSPEND_TEST

•此選項可以讓您在啟動狀態下暫停您的機器,並且在數秒後再次甦醒。其甦醒源使用了RTC的計時使之產生喚醒源的警告。當然,使用者必須先擁有系統的 RTC裝置的鏈結,並請確保它是可以用的,否則使用者將無法測試。• 相依於

• SUSPEND• PM_DEBUG• RTC_CLASS

2014

/8/2

6

15

Page 16: 2014暑期訓練之Linux kernel power

• Explan Code

• autosleep.c

• poweroff.c

• suspend.c

2014

/8/2

6

16

Page 17: 2014暑期訓練之Linux kernel power

• autosleep.c

•在閒暇之時,讓系統「睡眠」。

1. 宣告、定義工作的內容和屬性。

2. 得知現行的「目標」及「狀況」。

3. 「確保」手邊的工具齊全。

4. 「開始」工作。

2014

/8/2

6

17

Page 18: 2014暑期訓練之Linux kernel power

• 注意事項• 若是喚醒源被呼叫,可以利用 mutex以確保資源的安全,否則將有可能會進入死結的狀態當中。

•另外 mutex_lock_interruptible是可以被使用的,但是如果 auto_sleep的循環不斷嘗試著去Freeze processes,則將會發生錯誤。

2014

/8/2

6

18

Page 19: 2014暑期訓練之Linux kernel power

• Autosleep_state:經被宣告為 int 型態的 suspend_state_ttypedef所宣告。• 參考: include/linux/suspend.h

• autosleep_wq: 經 Workqueue_struct 宣告,內部宣告了工作隊列表、保護用的 mutex、顏色、隊列甚至如果想要的話,則還有 sysfs、lockdep可用。• 參考: kernel/workqueue.h

2014

/8/2

6

19

Page 20: 2014暑期訓練之Linux kernel power

2014

/8/2

6

20

Page 21: 2014暑期訓練之Linux kernel power

• try_to_suspend(struct work_struct *work)

1. 判斷喚醒源數量

2. 系統是否有在跑動

3. 自動睡眠的模式為何

4. 確認是否有其他的任務也嘗試著讓系統睡眠

5. 再次判斷喚醒源的數量,若還是有,則代表

有錯誤發生,處理錯誤。

2014

/8/2

6

21

Page 22: 2014暑期訓練之Linux kernel power

• pm_get_wakeup_count():• 功用:讀取暫存器的 wakeup-events的數量。如果並沒有任何處理中的喚醒事件則回傳 ture。• 來源: drivers/base/power/wakeup.c

2014

/8/2

6

22

Page 23: 2014暑期訓練之Linux kernel power

• pm_save_wakeup_count():• 功用:若當前的 Counter和喚醒源的事件數量相同且並無任何喚醒源事件,則將目前的Counter記錄下來並且回傳 True確認正在處理事件。• 來源: drivers/base/power/wakeup.c 20

14/8

/26

23

Page 24: 2014暑期訓練之Linux kernel power

• PM_SUSPEND_ON:• 功用: ACPI的 S0。• 來源: driver/acpi/sleep.c 20

14/8

/26

24

Page 25: 2014暑期訓練之Linux kernel power

• ACPI• ACPI( Advanced configuration and power

interface):工業標準。提供作業系統應用程式管理所有電源管理介面。其中工作狀態分之為:• G0(S0):正常工作狀態。• G1:睡眠,細分為 S1~S4 四種狀態,喚醒時間從 S1~S4 愈來愈慢。• STANDBY、MEM、MAX,分別等於

S1(最耗電的睡眠模式 )、 S3( 掛置到記憶體中,稱之為暫停,仍然對記憶體供電 ) 及S5(G2)

2014

/8/2

6

25

Page 26: 2014暑期訓練之Linux kernel power

• ACPI(contd.)

G2(S5): Soft off,電腦仍然可以被鍵盤、 clk、網路、電話或是 USB裝置所喚醒。

G3:Mechanical off。幾乎和 G2相同,將電腦的電源全部移開,但此時的 RTC依然在跳動。

2014

/8/2

6

26

Page 27: 2014暑期訓練之Linux kernel power

• pm_suspend() :• 功用:確認系統暫停的狀態。確認是否有其他的任務也試著讓系統進入暫停狀態。而後藉由Freeze來凍結外部的程序。• 來源: kernel/power/suspend.c 20

14/8

/26

27

Page 28: 2014暑期訓練之Linux kernel power

• schedule_timeout_uninterruptible(HZ/2)• 功用:若系統喚醒的發生原因未知,則會等待,並防止系統暫停及喚醒的循環。如果之後程式正常,則會繼續排程 (schedule)。但如果有問題,則會由核心告知系統錯誤並且傾印問題進入 stack中。• 來源: kernel/timer.c

2014

/8/2

6

28

Page 29: 2014暑期訓練之Linux kernel power

2014

/8/2

6

29

Page 30: 2014暑期訓練之Linux kernel power

• static DECLARE_WORK()• 功用:在此是將 try_to_suspend 初始化。利用到 __WORK_INITIALIZER(n, f)),將內部的料、入口、使用 Function、工作的 lockdep等初始化。• 來源: include/linux/workqueue.h

2014

/8/2

6

30

Page 31: 2014暑期訓練之Linux kernel power

• queue_up_suspend_work()• 功用:讓設備在指定的 CPU中工作。內部判斷目前 autosleep的狀態,如果到達一定標準則開始做排隊,此時才會去關閉一些外部設備,否則若無此判斷進來無意義。 __queue_work(cpu, *wq, *work)來指定相對的 CPU和隊列、工作等將之傳入。• 來源: kernel/workqueue.c

2014

/8/2

6

31

Page 32: 2014暑期訓練之Linux kernel power

• pm_autosleep_state(void)• 功用:整數型態。將回傳目前 autosleep的狀態 autosleep_state。 (呼應到suspend_state_t)• 來源: kernel/power

2014

/8/2

6

32

Page 33: 2014暑期訓練之Linux kernel power

• pm_autosleep_lock(void)• 功用:整數型態。內部將判斷該藉由快速通道或是慢速來進行 mutex的 luck。若為快速則是內部 count從 1->0時上 lock,若為慢速則有可能會使用到 interrupt.

• 來源: • asm-generic/mutex-xchg.h• kernel/locking/mutex.c

2014

/8/2

6

33

Page 34: 2014暑期訓練之Linux kernel power

• 快速:藉使用 mutex_set_owner 直接對該lock.owner做當前狀態的儲存。

• 慢速:必須將目前的 LOCK、任務中斷、回傳點等一一傳入 __mutex_lock_common中,禁止搶占(preempt_disable)後才可以取得 mutex的使用。

2014

/8/2

6

34

Page 35: 2014暑期訓練之Linux kernel power

• pm_autosleep_unlock(void)• 功用:相對於 pm_autosleep_lock,此 function則是利用 mutex_unlock() 直接解除autosleep_lock的鎖。• 來源: kernel/locking/mutex.c

2014

/8/2

6

35

Page 36: 2014暑期訓練之Linux kernel power

• pm_autosleep_set_state(int state)• 功用:確認目前的狀態,如果狀態確定是非正

常工作狀態才進入 suspend,否則就關閉自動睡眠並且回到正常工作。• 步驟:1. 通知 PM Core有喚醒事件。(防止其他喚醒源)

2. Mutex上鎖、讀取當前工作的狀態。3. 通知 PM Core喚醒事件已經結束了。4. 確認目前工作狀態。5. 解除 mutex。

2014

/8/2

6

36

Page 37: 2014暑期訓練之Linux kernel power

• EINVAL(invalid argument無效參數 )=22。• 來源: include/uapi/asm-generic/errno-base.h

2014

/8/2

6

37

Page 38: 2014暑期訓練之Linux kernel power

• __pm_stay_awake(autosleep_ws)• 功用:通知 PM Core喚醒事件,傳入參數為

Wakeup-source。告知目前狀態的喚醒源。• 來源: drivers/base/power/wakeup.c

2014

/8/2

6

38

Page 39: 2014暑期訓練之Linux kernel power

• __pm_relax(autosleep_ws)• 功用:通知 PM Core喚醒事件結束。允許其他喚醒源通知。• 來源: drivers/base/power/wakeup.c

2014

/8/2

6

39

Page 40: 2014暑期訓練之Linux kernel power

• pm_wakep_autosleep_enabled(bool)• 功用:修改全部喚醒源的 autosleep的啟動狀態。• 來源: drivers/base/power/wakeup.c 20

14/8

/26

40

Page 41: 2014暑期訓練之Linux kernel power

• pm_autosleep_init(void)• 功用:初始化 autosleep,結果正常則會回傳

0,否則將回傳 ENOMEM。• 步驟:1. 判斷喚醒源是否製造成功2. 判斷分配工作隊列是否成功3. 移除喚醒源,回傳錯誤。

2014

/8/2

6

41

Page 42: 2014暑期訓練之Linux kernel power

• wakeup_source_register(char *name)• 功用:製造一個喚醒源並且將之加入到列表中。內部會先使用 wakeup_source_create(name),並且利用 wakeup_source_add將之加入。• ENOMEM=Out of memory• 來源: drivers/base/power/wakeup.c

2014

/8/2

6

42

Page 43: 2014暑期訓練之Linux kernel power

• alloc_ordered_workqueue(name, arg)• 功用:分配已有序的工作隊列。與

alloc_workqueue相關,分配一個特定的區段給它。• 來源: • include/linux/workqueue.h• Documentation/workqueue.txt.

2014

/8/2

6

43

Page 44: 2014暑期訓練之Linux kernel power

• wakeup_source_unregister(void)• 功用:從表列中移除喚醒源。利用到

wakeup_source_remove(ws) ,  wakeup_source_destroy(ws)。• 來源: deivers/base/power/wakeup.c

2014

/8/2

6

44

Page 45: 2014暑期訓練之Linux kernel power

• Poweroff.c•系統要求正常地將機器關機 (斷電 )。• 步驟:

1. 設定關機的執行步驟

2. 將「關機」這項工作宣告好

3. 將此「工作」放進排程中

4. 宣告成結構,方便呼叫引用

5. 初始化此結構,並將此初始化放置於列表中。

2014

/8/2

6

45

Page 46: 2014暑期訓練之Linux kernel power

• do_poweroff(struct)• 功用:將系統正常關機,內部使用到

kernel_power_off。• 步驟:1. 關機前的準備。 (shutdown_prepare)2. 判斷是否準備完成(指定完成),完成後做該 Function的動作。 (Poweroff-prepare)

3. 設定指定的CPU去工作。 (migrate)4. 讓系統核心逐一關閉。 (syscore-

shutdown)5. 系統回傳信息後將核心信息存好。

(kmsg_dump)6. 機器關機。 (machine_power_off)

2014

/8/2

6

46

Page 47: 2014暑期訓練之Linux kernel power

2014

/8/2

6

47

Page 48: 2014暑期訓練之Linux kernel power

• kernel_shutdown_perpare(enum)• 功用:關機前的準備。使用鏈上的功能,並將當前系統狀態處存下來,而後關閉Usermodehelper並將每一個裝置關機。• 來源: kernel/reboot.c

2014

/8/2

6

48

Page 49: 2014暑期訓練之Linux kernel power

• 通知鏈結 (notifier_call_chain):• 功用: Linux系統中有提供「通知鏈結」的功能,鏈表上的每一個節點都有一個 Function,當事件發生時表上的節點所對應的 Function將會被執行。所以對表來說有一個接收、一個通知。• 總和來說,事件的接收者將事件發生時所對應的操作存起來,當事件發生時通知者依次執行每一個元素的 Function。• 程式中使用的是可阻塞的通知鏈。• 程式來源: kernel/reboot.c

2014

/8/2

6

49

Page 50: 2014暑期訓練之Linux kernel power

• 通知時的注意事項•功用:關閉 RCU機制才去做通知。•來源: kernel/reboot.c

2014

/8/2

6

50

Page 51: 2014暑期訓練之Linux kernel power

• RCU(Read Copy Update)• 功能:允許多個讀取與更新同時發生的事件,不使用 Lock的概念,適合讀者多寫者少的狀況。利用 read-lock(時間到輪流 )來避免強佔事件。• 來源: kernel/locking/rwsem.c

2014

/8/2

6

51

Page 52: 2014暑期訓練之Linux kernel power

• usermodehelper_disable() :

• 功用:一般而言,系統調用函式是相當常見的,一般而言都是由使用者調用 kernel的function。• 當方向相反的使用則需要使用

usermodehelper。例如當 kernel找到一個device,而需要 load 某個 module。而此function就是防止有新的 helper 出現。

• 來源: Kernel/kmod.c

2014

/8/2

6

52

Page 53: 2014暑期訓練之Linux kernel power

2014

/8/2

6

53

Page 54: 2014暑期訓練之Linux kernel power

• device_shutdown()• 功用:對每一個裝置呼叫 shutdown()指令。利用尋訪 Device list去一一的將裝置關機,又稱offline• 來源: drivers/base/core.c

2014

/8/2

6

54

Page 55: 2014暑期訓練之Linux kernel power

2014

/8/2

6

55

Page 56: 2014暑期訓練之Linux kernel power

• pm_power_off_prepare()• 功用:利用 Function point的方式,可以從外部將需要的功能存入此函式中並且將之執行。用判斷式判斷是否已指向需要的 Function。• 來源: kernel/reboot.c 20

14/8

/26

56

Page 57: 2014暑期訓練之Linux kernel power

• migrate_to_reboot_cpu()• 功用:關閉熱插拔裝置、運行任務在指定的

CPU上並防止有其他的任務遷移至本區、確認只運行在適當的處理器上。可參考同檔案下的kernel_restart。• 來源: kernel/reboot.c

2014

/8/2

6

57

Page 58: 2014暑期訓練之Linux kernel power

• CPU_hotplug_disable()• 功用:將熱插拔系統關閉。熱插拔指的是在電

腦熱機的狀態增減硬體。過去大家是使用套件,當新裝置進入時該套件會自行配置。在linux2.6 版過後,採用 udev 自動產生,而它不只是一個設備檔案產生器,更是一個核心信息的監聽器。• 來源 : kernel/cpu.c

2014

/8/2

6

58

Page 59: 2014暑期訓練之Linux kernel power

• set_cpus_allowed_ptr(current, cpumask_of(cpu))• 功用:確保只運行在指定的 CPU上。內部使用到 task_lock來確認不會有其他的任務參雜且可確認任務的正確性及 CPU使用的正確性。• 來源: kernel/sched/core.c

2014

/8/2

6

59

Page 60: 2014暑期訓練之Linux kernel power

• syscore_shutdown()• 功用:執行 Function使得被暫存的系統核心逐一關閉,例如中斷裝置等。本部分也是利用 list的方式逐一關閉。• 來源: deivers/base/syscore.c

2014

/8/2

6

60

Page 61: 2014暑期訓練之Linux kernel power

• pr_emerg("Power down\n")• 功用:在定義中使用 printk的方式由核心告知使用者,優先權為 KERN_EMERG(最高優先權,告知系統不可用 )• 來源: include/linux/printk.h, kern_levels.h

2014

/8/2

6

61

Page 62: 2014暑期訓練之Linux kernel power

• kmsg_dump()• 功用:將 kernel的 log 傾印至 kernel message

dumpers中,方便以後檢索時可以使用。傾印可以儲存程式資訊,以便在偵錯的時候使用。 • 來源: kernel/printk/printk.c

2014

/8/2

6

62

Page 63: 2014暑期訓練之Linux kernel power

• machine_power_off(void)• 功用:因 include reboot.c,故以該檔內的意思為主。直接執行 struct machine_ops的 power_off將系統關閉,此處若用 int做受值可以接受回傳的系統值即可知道錯誤與否。• 來源: arch/sh/kernel/reboot.c

2014

/8/2

6

63

Page 64: 2014暑期訓練之Linux kernel power

• DECLARE_WORK(poweroff_work, do_poweroff)• 功用:工作的宣告。此 Function是使用

__WORK_INITIALIZER()去初始化結構內部的值,第一個是之後使用的入口地址、後方放的是「工作」,初始化包含 data, entry address, function and lockdep。• 來源: include/linux/lockdep.h

2014

/8/2

6

64

Page 65: 2014暑期訓練之Linux kernel power

• Lockdep:假設每一個 Process都是鑰匙,而資源稱之為鎖。在 linux系統中,如果發生了AB-BA 死結狀態,可能可以用「順序」的方式去解開,但是面對成千上萬的「鎖」卻無法如此。•而 lockdep在 2006 年引入 Linux-kernel中,它的操作並非以單一一個資源為例,而是以同個類別去觀察。• 它循跡每一個鎖的狀態和關係,並且通過一系列的驗證規則以確保各個狀態之間的依賴關係是可行且正確的。• 參考: include/linux/lockdep.h

2014

/8/2

6

65

Page 66: 2014暑期訓練之Linux kernel power

• handle_poweroff(int key)•功用:在啟動的 CPU上運行系統所要求的關機指令。使用到 schedule_work_on,將從目前在線的 CPU 列表中挑選出第一個,並將它及關機的動作送入工作排程之中。 20

14/8

/26

66

Page 67: 2014暑期訓練之Linux kernel power

• queue_work()• 功用:讓工作排在工作隊列上。如果回傳 False則代表 already。在此要特別注意,此工作雖然一樣是讓工作在特定的 CPU上排隊準備,但這邊要請使用者確認該工作不會突然離去導致隊列出問題。• 來源: include/linux/workqueue.h

2014

/8/2

6

67

Page 68: 2014暑期訓練之Linux kernel power

•將設置好的動作送入結構中以備使用需要•將初始化的動作包裝起,送入列表當中。

2014

/8/2

6

68

Page 69: 2014暑期訓練之Linux kernel power

• pm_sysrq_init(void)• 功用:呼叫了 __sysrq_swap_key_ops,將結構

送入 sysrq_key_table[i] 列表中。最後將 RCU做同步,使得更新與讀取是為同步。• 來源: drivers/tty/sysrq.c

2014

/8/2

6

69

Page 70: 2014暑期訓練之Linux kernel power

• subsys_initcall()• 功用:子程序的初始化,此 Function定義於

__define_initcall中,通常 USB 及外部裝置都會將相關的函式放入其內。它們使用並非隨便任意,而是有相關的順序,而順序取決於當時給予其之參數。• 來源: include/linux/init.h

2014

/8/2

6

70

Page 71: 2014暑期訓練之Linux kernel power

•Suspend.c

•流程• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

2014

/8/2

6

71

Page 72: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 73: 2014暑期訓練之Linux kernel power

int pm_suspend(suspend_state_t state)(line 427)• 判斷狀態參數是否正確• include/linux/suspend.h, line 36

• #define PM_SUSPEND_ON ((__force suspend_state_t) 0)• #define PM_SUSPEND_FREEZE ((__force suspend_state_t) 1)• #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2)• #define PM_SUSPEND_MEM ((__force suspend_state_t) 3)• #define PM_SUSPEND_MIN PM_SUSPEND_FREEZE• #define PM_SUSPEND_MAX ((__force suspend_state_t) 4)

• 進入 enter_state• 將結果記錄下來

Page 74: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 75: 2014暑期訓練之Linux kernel power

static int enter_state(suspend_state_t state)(line 370)

• 追蹤 suspend_enter的狀態• include/trace/events/power.h, line 12• #define TPS(x) tracepoint_string(x)• include/linux/ftrace_event.h, line 604• 可將該參數的狀態、內容等等資訊映射出來

Page 76: 2014暑期訓練之Linux kernel power

static int enter_state(suspend_state_t state)(line 370)

• 判斷是否為凍結狀態• kernel/power/main.c, line 75• [TEST_NONE] = "none"• [TEST_CORE] = "core"• [TEST_CPUS] = "processors"• [TEST_PLATFORM] = "platform"• [TEST_DEVICES] = "devices"• [TEST_FREEZER] = "freezer"

Page 77: 2014暑期訓練之Linux kernel power

static int enter_state(suspend_state_t state)(line 370)• 判斷是否支持該電源狀態• 需要較低層級的支持和實作

• 互斥鎖• 只允許處理一個 suspend

•如果 state是 freeze,調用 freeze_begin, 將凍結喚醒關閉 (suspend_freeze_wake = false)

Page 78: 2014暑期訓練之Linux kernel power

static int enter_state(suspend_state_t state)(line 370)

• 追蹤 sync_filesystems的狀態• 同步 filesystems

•進行 suspend前的準備

Page 79: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 80: 2014暑期訓練之Linux kernel power

static int suspend_prepare(suspend_state_t state)(line 167)

•需要處理什麼狀態,同時是否支援此狀態

•將當前 console切換到一個虛擬 console並重定向kernel的 kmsg

Page 81: 2014暑期訓練之Linux kernel power

static int suspend_prepare(suspend_state_t state)(line 167)

•發送 suspend開始的消息• include/linux/suspend.h, line 350• #define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */• #define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */• #define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */• #define PM_POST_SUSPEND 0x0004 /* Suspend finished */• #define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */• #define PM_POST_RESTORE 0x0006 /* Restore failed */

• 追蹤 freeze_processes的狀態• freeze user processes和一些 kernel threads

Page 82: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 83: 2014暑期訓練之Linux kernel power

static int enter_state(suspend_state_t state)(line 370)

• 判斷是否為 suspend to freeze

• 避免在 suspend過程中使用 I/O設備

Page 84: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 85: 2014暑期訓練之Linux kernel power

int suspend_devices_and_enter(suspend_state_t state)(line 297)

• 再次檢查是否提供此狀態處理

• Suspend console• 由 "kernel/printk/printk.c" 實現,主要是 hold住一個

lock,該 lock會阻止其它訪問 console

•開始測試系統 suspend/resume過程是否有異常• 將其測試時間設為 jiffies• 每秒 1000 次

Page 86: 2014暑期訓練之Linux kernel power

int suspend_devices_and_enter(suspend_state_t state)(line 297)

• 準備設備的狀態轉換,並暫停他們• drivers/base/power/main.c, line 1647• 調用所有設備的 ->prepare和 ->suspend

Page 87: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 88: 2014暑期訓練之Linux kernel power

static int suspend_enter(suspend_state_t state, bool *wakeup)(line 213)

•設備的狀態轉換• drivers/base/power/main.c, line 1280• 調用所有設備的 ->suspend_late和 ->suspend_noirq• suspend_noirq:防止設備接收中斷和呼叫 noirq的處理

• 追蹤 machine_suspend的狀態• 進入 freeze_enter• idle processors

Page 89: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 90: 2014暑期訓練之Linux kernel power

static void freeze_enter(void)(line 63)• enable the “deepest idle” mode• drivers/cpuidle/cpuidle.c, line 78• cpuidle會忽略調節器• 此功能只能在調用 cpuidle_pause之後被呼叫

• cpuidle_resume• drivers/cpuidle/cpuidle.c, line 259• cpuidle_install_idle_handler• drivers/cpuidle/cpuidle.c, line 208• 確保我們切換到 new idle之前,完成所有變更

•等待 suspend_freeze_wake變為 true

Page 91: 2014暑期訓練之Linux kernel power

static void freeze_enter(void)(line 63)

• cpuidle_pause• drivers/cpuidle/cpuidle.c, line 251• cpuidle_uninstall_idle_handler• drivers/cpuidle/cpuidle.c, line 220• 強制所有 CPU空閒出來

• disable the “deepest idle” mode

Page 92: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 93: 2014暑期訓練之Linux kernel power

static int suspend_enter(suspend_state_t state, bool *wakeup)(line 213)

•停止 function tracer

• 禁止所有的 non-boot cpu

•關閉 local中斷• 如果無法關閉,則為 bug

• suspend所有 system core

Page 94: 2014暑期訓練之Linux kernel power

static int suspend_enter(suspend_state_t state, bool *wakeup)(line 213)

•是否有喚醒事件發生,如果有就要終止 suspend•恢復所有 system core•開啟 local中斷•恢復所有的 non-boot cpu•恢復 function tracer• dpm_resume_start• 調用所有設備的 ->noirq和 ->early

Page 95: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 96: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 97: 2014暑期訓練之Linux kernel power

static int enter_state(suspend_state_t state)(line 370)

•恢復使用 I/O設備

Page 98: 2014暑期訓練之Linux kernel power

• pm_suspend->• enter_state->• suspend_prepare• suspend_devices_and_enter->suspend_enter

->freeze_enter• suspend_finish

Page 99: 2014暑期訓練之Linux kernel power

static void suspend_finish(void)(line 355)• 恢復所有的 user processes和 kernel threads

• 發送 suspend結束的通知

• 將 console切換回原來的 console

Page 100: 2014暑期訓練之Linux kernel power

• Summary

• Data Flow.• Program structure.

2014

/8/2

6

100

Page 101: 2014暑期訓練之Linux kernel power

• Reference

• Hackpad of Emp-Chen-Learn.https://emp-learn.hackpad.com/2014Linux-Kernel-ajEOESxnPs5

2014

/8/2

6

101

Page 102: 2014暑期訓練之Linux kernel power

Thanks you for attention.

2014

/8/2

6

102