系統掛起程式碼流程

版權:

© 2020 Intel Corporation

作者:

Rafael J. Wysocki <rafael.j.wysocki@intel.com>

為了使系統從工作狀態進入某個支援的睡眠狀態,至少需要進行一次全域性系統級轉換。休眠需要多次轉換才能達到此目的,但其他睡眠狀態,通常稱為系統級掛起(或簡稱系統掛起)狀態,只需要一次轉換。

對於這些睡眠狀態,系統從工作狀態到目標睡眠狀態的轉換也稱為系統掛起(在大多數情況下,這表示轉換還是系統睡眠狀態應該從上下文中明確),而從睡眠狀態回到工作狀態的轉換則稱為系統恢復

與系統不同睡眠狀態的掛起和恢復轉換相關的核心程式碼流程非常相似,但在掛起到空閒的程式碼流程與掛起到記憶體待機睡眠狀態相關的程式碼流程之間存在一些顯著差異。

掛起到記憶體待機睡眠狀態的實現離不開平臺支援,它們之間的差異歸結為平臺驅動程式為使其可用而必須提供的掛起和恢復鉤子所執行的平臺特定操作。除此之外,這些睡眠狀態的掛起和恢復程式碼流程大致相同,因此在下文中它們都被統稱為平臺依賴掛起狀態。

掛起到空閒掛起程式碼流程

為了將系統從工作狀態轉換為掛起到空閒睡眠狀態,將採取以下步驟

  1. 呼叫系統級掛起通知器。

    核心子系統可以註冊回撥函式,以便在即將發生掛起轉換和恢復轉換完成後呼叫。

    這允許它們為系統狀態的改變做準備,並在返回工作狀態後進行清理。

  2. 凍結任務。

    凍結任務主要是為了避免使用者空間透過直接暴露給它的 MMIO 區域或 I/O 暫存器進行未經檢查的硬體訪問,並防止使用者空間在轉換的下一步進行中進入核心(這可能由於各種原因而出現問題)。

    所有使用者空間任務都被攔截,如同它們收到了訊號,並進入不可中斷睡眠,直到隨後的系統恢復轉換結束。

    出於特定原因選擇在系統掛起期間凍結的核心執行緒隨後被凍結,但它們不會被攔截。相反,它們被期望定期檢查是否需要凍結,如果需要則將自己置於不可中斷睡眠狀態。[但請注意,核心執行緒可以使用核心空間中可用的鎖定和其他併發控制機制來與系統掛起和恢復同步,這比凍結要精確得多,因此後者不推薦用於核心執行緒。]

  3. 掛起裝置並重新配置 IRQ。

    裝置分四個階段掛起,分別稱為準備掛起後期掛起無 IRQ 掛起(有關每個階段具體發生的情況的更多資訊,請參閱裝置電源管理基礎)。

    每個裝置在每個階段都會被訪問,但通常在其中不超過兩個階段會進行物理訪問。

    後期掛起階段,每個裝置的執行時 PM API 都被停用,並且在無 IRQ掛起階段之前,高階(“動作”)中斷處理程式被阻止呼叫。

    之後中斷仍然被處理,但它們只被中斷控制器確認,而不執行任何在系統工作狀態下會觸發的裝置特定動作(這些動作會推遲到隨後的系統恢復轉換,如下文所述)。

    與系統喚醒裝置相關的 IRQ 被“武裝”,以便當其中一個訊號事件時啟動系統的恢復轉換。

  4. 凍結排程器時鐘並掛起時間保持。

    當所有裝置都已掛起時,CPU 進入空閒迴圈並進入最深的可用空閒狀態。在此過程中,每個 CPU 都“凍結”自己的排程器時鐘,以便在 CPU 被另一箇中斷源喚醒之前,與時鐘相關的定時器事件不會發生。

    最後一個進入空閒狀態的 CPU 也會停止時間保持,這(除其他外)會阻止高精度定時器在未來的觸發,直到第一個被喚醒的 CPU 重新啟動時間保持。這使得 CPU 能夠一次在深度空閒狀態中保持相對較長的時間。

    從這一點開始,CPU 只能被非定時器硬體中斷喚醒。如果發生這種情況,它們會回到空閒狀態,除非喚醒其中一個 CPU 的中斷來自已武裝用於系統喚醒的 IRQ,在這種情況下,系統恢復轉換會啟動。

掛起到空閒恢復程式碼流程

為了將系統從掛起到空閒睡眠狀態轉換為工作狀態,將採取以下步驟

  1. 恢復時間保持並解凍排程器時鐘。

    當其中一個 CPU 被喚醒(透過非定時器硬體中斷)時,它離開在先前掛起轉換的最後一步中進入的空閒狀態,重新啟動時間保持(除非它已經被另一個更早醒來的 CPU 重新啟動),並且該 CPU 上的排程器時鐘被解凍。

    如果喚醒 CPU 的中斷被武裝用於系統喚醒,則系統恢復轉換開始。

  2. 恢復裝置並恢復 IRQ 的工作狀態配置。

    裝置分四個階段恢復,分別稱為無 IRQ 恢復早期恢復恢復完成(有關每個階段具體發生的情況的更多資訊,請參閱裝置電源管理基礎)。

    每個裝置在每個階段都會被訪問,但通常在其中不超過兩個階段會進行物理訪問。

    IRQ 的工作狀態配置在無 IRQ恢復階段之後恢復,並且在早期恢復階段,每個支援執行時 PM API 的裝置的執行時 PM API 都被重新啟用。

  3. 解凍任務。

    在先前掛起轉換的第 2 步中凍結的任務被“解凍”,這意味著它們從當時進入的不可中斷睡眠中被喚醒,並且允許使用者空間任務退出核心。

  4. 呼叫系統級恢復通知器。

    這類似於掛起轉換的第 1 步,此時呼叫相同的回撥函式集,但傳遞給它們的是不同的“通知型別”引數值。

平臺依賴掛起程式碼流程

為了將系統從工作狀態轉換為平臺依賴掛起狀態,將採取以下步驟

  1. 呼叫系統級掛起通知器。

    此步驟與上述掛起到空閒掛起轉換的第 1 步相同。

  2. 凍結任務。

    此步驟與上述掛起到空閒掛起轉換的第 2 步相同。

  3. 掛起裝置並重新配置 IRQ。

    此步驟類似於上述掛起到空閒掛起轉換的第 3 步,但武裝 IRQ 以進行系統喚醒通常對平臺沒有任何影響。

    有些平臺當所有 CPU 都處於足夠深的空閒狀態且所有 I/O 裝置都已進入低功耗狀態時,可以在內部進入非常深的低功耗狀態。在這些平臺上,掛起到空閒可以非常有效地降低系統功耗。

    然而,在其他平臺上,低階元件(如中斷控制器)需要以平臺特定的方式關閉(在平臺驅動程式提供的鉤子中實現),以實現可比的功耗降低。

    這通常會阻止帶內硬體中斷喚醒系統,這必須以特殊的平臺依賴方式完成。然後,系統喚醒源的配置通常在系統喚醒裝置掛起時開始,並由平臺掛起鉤子在稍後完成。

  4. 停用非引導 CPU。

    在某些平臺上,上述掛起鉤子必須在單 CPU 配置的系統上執行(特別是,硬體不能被與平臺掛起鉤子並行執行的任何程式碼訪問,這些鉤子可能會,並且經常會,陷入平臺韌體以完成掛起轉換)。

    出於此原因,CPU 離線/線上(CPU 熱插拔)框架用於將系統中除一個 CPU(引導 CPU)之外的所有 CPU 離線(通常,已離線的 CPU 進入深度空閒狀態)。

    這意味著所有任務都從這些 CPU 遷移開,並且所有 IRQ 都重新路由到唯一保持線上的 CPU。

  5. 掛起核心系統元件。

    這為核心系統元件(可能)在未來斷電做準備,並掛起時間保持。

  6. 平臺特定電源移除。

    這預計會切斷除記憶體控制器和 RAM(為了保留後者內容)以及一些指定用於系統喚醒的裝置之外的所有系統元件的電源。

    在許多情況下,控制權會傳遞給平臺韌體,平臺韌體應根據需要完成掛起轉換。

平臺依賴恢復程式碼流程

為了將系統從平臺依賴掛起狀態轉換為工作狀態,將採取以下步驟

  1. 平臺特定系統喚醒。

    平臺由一個指定系統喚醒裝置的訊號喚醒(這不一定是帶內硬體中斷),並且控制權交還給核心(平臺韌體可能需要在核心重新獲得控制權之前恢復平臺的工作配置)。

  2. 恢復核心系統元件。

    核心系統元件的掛起時配置被恢復,並且時間保持被恢復。

  3. 重新啟用非引導 CPU。

    在先前掛起轉換的第 4 步中停用的 CPU 重新上線,並恢復其掛起時配置。

  4. 恢復裝置並恢復 IRQ 的工作狀態配置。

    此步驟與上述掛起到空閒恢復轉換的第 2 步相同。

  5. 解凍任務。

    此步驟與上述掛起到空閒恢復轉換的第 3 步相同。

  6. 呼叫系統級恢復通知器。

    此步驟與上述掛起到空閒恢復轉換的第 4 步相同。