USB 電源管理¶
- 作者:
Alan Stern <stern@rowland.harvard.edu>
- 日期:
最後更新:2014 年 2 月
什麼是電源管理?¶
電源管理 (PM) 是一種透過在計算機系統的某些部分未被使用時將其掛起來節省能源的做法。當一個元件被 掛起 時,它處於一個非功能性的低功耗狀態;它甚至可能被完全關閉。當核心需要使用一個掛起的元件時,它可以被 恢復(返回到功能齊全的滿功率狀態)。(還有一些形式的 PM 將元件置於功能較弱但仍可用的狀態,而不是掛起;例如降低 CPU 的時鐘頻率。本文件將不討論這些其他形式。)
當被掛起的部分包括 CPU 和系統的大部分時,我們稱之為“系統掛起”。當一個特定的裝置在整個系統保持執行的情況下被關閉時,我們稱之為“動態掛起”(也稱為“執行時掛起”或“選擇性掛起”)。本文件主要集中在 USB 子系統中如何實現動態 PM,儘管系統 PM 也有所涉及(有關係統 PM 的更多資訊,請參閱 Documentation/power/*.rst)。
只有在構建核心時啟用了 CONFIG_SUSPEND 或 CONFIG_HIBERNATION,才存在系統 PM 支援。動態 PM 支援
只有在構建核心時啟用了 CONFIG_PM,才存在 USB 的支援。
[從歷史上看,只有在構建核心時啟用了 CONFIG_USB_SUSPEND(依賴於 CONFIG_PM_RUNTIME),才存在 USB 的動態 PM 支援。從 3.10 核心版本開始,只要構建核心時啟用了 CONFIG_PM_RUNTIME,就存在 USB 的動態 PM 支援。CONFIG_USB_SUSPEND 選項已被刪除。]
什麼是遠端喚醒?¶
當一個裝置被掛起時,通常要等到計算機告訴它才能恢復。同樣,如果整個計算機被掛起,通常要等到使用者告訴它才能恢復,例如按下電源按鈕或開啟蓋子。
然而,有些裝置有能力自己恢復,或請求核心恢復它們,甚至告訴整個計算機恢復。這種能力有幾個名稱,例如“Wake On LAN”;我們將它泛稱為“遠端喚醒”。當一個裝置被啟用遠端喚醒並被掛起時,它可能會響應一些外部事件而自行恢復(或傳送一個恢復請求)。例如,一個掛起的鍵盤在按下鍵時恢復,或一個掛起的 USB 集線器在插入裝置時恢復。
何時 USB 裝置處於空閒狀態?¶
當核心認為一個裝置沒有忙於做任何重要的事情,因此可以被掛起時,它就處於空閒狀態。確切的定義取決於裝置的驅動程式;驅動程式可以宣告一個裝置即使在沒有實際通訊發生時也不處於空閒狀態。(例如,除非插入集線器的所有裝置都已經掛起,否則集線器不被認為是空閒的。)此外,只要一個程式保持其 usbfs 檔案開啟,即使沒有任何 I/O 發生,一個裝置也不被認為是空閒的。
如果一個 USB 裝置沒有驅動程式,它的 usbfs 檔案沒有開啟,並且沒有透過 sysfs 訪問它,那麼它肯定是空閒的。
動態 PM 的形式¶
當核心決定掛起一個空閒裝置時,就會發生動態掛起。這簡稱為 自動掛起。一般來說,一個裝置除非空閒了一段時間,即所謂的空閒延遲時間,否則不會被自動掛起。
當然,核心自己採取的任何措施都不應該妨礙計算機或其裝置正常工作。如果一個裝置被自動掛起,並且一個程式試圖使用它,核心將自動恢復該裝置(自動恢復)。出於同樣的原因,如果裝置支援遠端喚醒,那麼一個自動掛起的裝置通常會啟用遠端喚醒。
值得一提的是,許多 USB 驅動程式不支援自動掛起。事實上,在撰寫本文時(Linux 2.6.23),唯一支援它的驅動程式是集線器驅動程式、kaweth、asix、usblp、usblcd 和 usb-skeleton(這不算數)。如果一個不支援的驅動程式繫結到一個裝置,該裝置將不會被自動掛起。實際上,核心假裝該裝置永遠不處於空閒狀態。
我們可以將電源管理事件分為兩大類:外部事件和內部事件。外部事件是由 USB 堆疊之外的某個代理觸發的:系統掛起/恢復(由使用者空間觸發)、手動動態恢復(也由使用者空間觸發)和遠端喚醒(由裝置觸發)。內部事件是在 USB 堆疊內觸發的:自動掛起和自動恢復。請注意,所有動態掛起事件都是內部事件;不允許外部代理發出動態掛起。
動態 PM 的使用者介面¶
控制動態 PM 的使用者介面位於每個 USB 裝置的 sysfs 目錄的 power/ 子目錄中,也就是說,位於 /sys/bus/usb/devices/.../power/ 中,其中“...”是裝置的 ID。相關的屬性檔案是:wakeup、control 和 autosuspend_delay_ms。(也可能有一個名為 level 的檔案;該檔案已從 2.6.35 核心開始棄用,並被 control 檔案取代。在 2.6.38 中,autosuspend 檔案將被棄用,並被 autosuspend_delay_ms 檔案取代。唯一的區別是,較新的檔案以毫秒為單位表示延遲,而較舊的檔案使用秒。令人困惑的是,這兩個檔案都存在於 2.6.37 中,但只有 autosuspend 起作用。)
power/wakeup如果裝置不支援遠端喚醒,則此檔案為空。否則,該檔案包含單詞
enabled或單詞disabled,您可以將這些單詞寫入該檔案。該設定決定了下次掛起裝置時是否啟用遠端喚醒。(如果在裝置掛起時更改了該設定,則該更改將在下一次掛起時生效。)
power/control此檔案包含兩個單詞之一:
on或auto。您可以將這些單詞寫入該檔案以更改裝置的設定。
on意味著應該恢復該裝置,並且不允許自動掛起。(當然,仍然允許系統掛起。)
auto是正常狀態,在這種狀態下,核心可以自動掛起和自動恢復該裝置。(在 2.6.32 之前的核心中,您也可以指定
suspend,這意味著該裝置應該保持掛起狀態,並且不允許自動恢復。此設定不再受支援。)
power/autosuspend_delay_ms此檔案包含一個整數值,該值是裝置在核心自動掛起它之前應該保持空閒的毫秒數(空閒延遲時間)。預設值為 2000。0 意味著一旦裝置進入空閒狀態就立即自動掛起,負值意味著永遠不自動掛起。您可以將一個數字寫入該檔案以更改自動掛起空閒延遲時間。
將 -1 寫入 power/autosuspend_delay_ms 和將 on 寫入 power/control 本質上做的是同一件事 -- 它們都阻止裝置被自動掛起。是的,這是 API 中的一個冗餘。
(在 2.6.21 中,將 0 寫入 power/autosuspend 會阻止裝置被自動掛起;該行為在 2.6.22 中被更改。power/autosuspend 屬性在 2.6.21 之前不存在,power/level 屬性在 2.6.22 之前不存在。power/control 在 2.6.34 中新增,power/autosuspend_delay_ms 在 2.6.37 中新增,但在 2.6.38 之前沒有生效。)
更改預設空閒延遲時間¶
預設的自動掛起空閒延遲時間(以秒為單位)由 usbcore 中的一個模組引數控制。您可以在載入 usbcore 時指定該值。例如,要將其設定為 5 秒而不是 2 秒,您可以這樣做
modprobe usbcore autosuspend=5
等效地,您可以在 /etc/modprobe.d 中的一個配置檔案中新增一行,內容為
options usbcore autosuspend=5
一些發行版在引導過程中非常早就載入了 usbcore 模組,透過一個程式或指令碼從 initramfs 映象執行。要更改引數值,您必須重建該映象。
如果 usbcore 被編譯到核心中,而不是作為可載入模組構建,您可以新增
usbcore.autosuspend=5
到核心的引導命令列。
最後,可以在系統執行時更改引數值。如果您這樣做
echo 5 >/sys/module/usbcore/parameters/autosuspend
那麼每個新的 USB 裝置都會將其自動掛起空閒延遲初始化為 5。(現有裝置的空閒延遲值將不會受到影響。)
將初始預設空閒延遲設定為 -1 將阻止任何 USB 裝置的自動掛起。這樣做的好處是允許您隨後為選定的裝置啟用自動掛起。
警告¶
USB 規範指出所有 USB 裝置都必須支援電源管理。然而,可悲的事實是,許多裝置對它的支援並不好。您可以正確地掛起它們,但是當您嘗試恢復它們時,它們會從 USB 匯流排斷開連線,或者它們會完全停止工作。這在印表機和掃描器中似乎特別普遍,但是許多其他型別的裝置也存在同樣的缺陷。
因此,預設情況下,核心會停用自動掛起(power/control 屬性初始化為 on),對於除集線器之外的所有裝置。至少,集線器在這方面表現得相當好。
(在 2.6.21 和 2.6.22 中,情況並非如此。預設情況下,幾乎所有 USB 裝置都啟用了自動掛起。結果,許多人遇到了問題。)
這意味著,除非使用者或程式顯式啟用它,否則非集線器裝置不會被自動掛起。在撰寫本文時,沒有任何廣泛的程式會這樣做;我們希望在不久的將來,像 HAL 這樣的裝置管理器將承擔起這一額外的責任。與此同時,您始終可以手動執行必要的操作,或者將它們新增到 udev 指令碼中。您還可以更改空閒延遲時間;2 秒並不是每個裝置的最佳選擇。
如果一個驅動程式知道它的裝置具有正確的掛起/恢復支援,它可以自行啟用自動掛起。例如,筆記型電腦的網路攝像頭的影片驅動程式可能會這樣做(在最近的核心中,它們會這樣做),因為這些裝置很少使用,因此通常應該自動掛起。
有時會發現,即使一個裝置在自動掛起的情況下工作正常,仍然存在問題。例如,管理鍵盤和滑鼠的 usbhid 驅動程式具有自動掛起支援。使用多個鍵盤的測試表明,在掛起的鍵盤上打字,雖然會導致鍵盤正確地進行遠端喚醒,但仍然經常會導致按鍵丟失。使用滑鼠的測試表明,有些滑鼠會響應按鈕按下而發出遠端喚醒請求,但不會響應移動,有些滑鼠則不會響應任何一個。
核心不會阻止您在無法處理的裝置上啟用自動掛起。從理論上講,甚至有可能在錯誤的時間掛起裝置而損壞裝置。(可能性很小,但有可能。)小心。
電源管理的驅動介面¶
USB 驅動程式支援外部電源管理的要求非常簡單;驅動程式只需要在其 usb_driver 結構中定義
.suspend
.resume
.reset_resume
方法,並且 reset_resume 方法是可選的。這些方法的工作非常簡單
suspend方法被呼叫來警告驅動程式裝置即將被掛起。如果驅動程式返回一個負的錯誤程式碼,掛起將被中止。通常,驅動程式將返回 0,在這種情況下,它必須取消所有未完成的 URB(usb_kill_urb())並且不再提交任何 URB。
resume方法被呼叫來告訴驅動程式裝置已經被恢復,並且驅動程式可以恢復正常執行。URB 可以再次被提交。
reset_resume方法被呼叫來告訴驅動程式裝置已經被恢復,並且它也被重置了。驅動程式應該重新執行任何必要的裝置初始化,因為該裝置可能已經丟失了大部分或全部狀態(儘管介面將與掛起之前的 altsetting 相同)。
如果裝置在掛起時斷開連線或斷電,將呼叫 disconnect 方法,而不是 resume 或 reset_resume 方法。當從休眠狀態喚醒時,這種情況也很可能發生,因為許多系統在休眠期間不保持到 USB 主控制器的掛起電流。(可以透過使用 USB 持久化工具來解決休眠強制斷開連線的問題。)
reset_resume 方法被 USB 持久化工具使用(參見 系統掛起期間的 USB 裝置永續性),並且在未啟用 CONFIG_USB_PERSIST 的某些情況下也可以使用。目前,如果在恢復期間重置了一個裝置,並且驅動程式沒有 reset_resume 方法,則驅動程式不會收到任何關於恢復的通知。以後的核心將呼叫驅動程式的 disconnect 方法;2.6.23 不會這樣做。
USB 驅動程式繫結到介面,因此當介面被掛起或恢復時,它們的 suspend 和 resume 方法會被呼叫。原則上,人們可能希望掛起一個裝置上的一些介面(即,強制這些介面的驅動程式停止所有活動),而不掛起其他介面。USB 核心不允許這樣做;當裝置本身被掛起時,所有介面都被掛起,當裝置被恢復時,所有介面都被恢復。不可能掛起或恢復一些但不是全部裝置的介面。最接近的方法是解除繫結介面的驅動程式。
自動掛起和自動恢復的驅動介面¶
為了支援自動掛起和自動恢復,驅動程式應該實現上面列出的所有三種方法。此外,驅動程式透過在其 usb_driver 結構中設定 .supports_autosuspend 標誌來表明它支援自動掛起。然後,它負責在其中一個介面變得繁忙或空閒時通知 USB 核心。驅動程式透過呼叫這六個函式來做到這一點
int usb_autopm_get_interface(struct usb_interface *intf);
void usb_autopm_put_interface(struct usb_interface *intf);
int usb_autopm_get_interface_async(struct usb_interface *intf);
void usb_autopm_put_interface_async(struct usb_interface *intf);
void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
這些函式透過在 usb_interface 的嵌入式裝置結構中維護一個使用計數器來工作。當計數器 > 0 時,該介面被認為是繁忙的,並且核心不會自動掛起該介面的裝置。當使用計數器 = 0 時,該介面被認為是空閒的,並且核心可能會自動掛起該裝置。
驅動程式必須小心平衡它們對使用計數器的總體更改。當一個驅動程式從其介面解除繫結時,未平衡的“get”仍然有效,如果該介面再次繫結到一個驅動程式,則會阻止該裝置進入執行時掛起。另一方面,驅動程式可以透過呼叫 usb_autopm_* 函式來實現這種平衡,即使在它們的 disconnect 例程返回之後 -- 例如從一個工作佇列例程中 -- 前提是它們保留了對該介面的活動引用(透過 usb_get_intf 和 usb_put_intf)。
使用非同步例程的驅動程式負責它們自己的同步和互斥。
usb_autopm_get_interface()遞增使用計數器,並且如果裝置被掛起,則執行自動恢復。如果自動恢復失敗,計數器將遞減回來。
usb_autopm_put_interface()遞減使用計數器,並且如果新值 = 0,則嘗試自動掛起。
usb_autopm_get_interface_async()和usb_autopm_put_interface_async()做的事情幾乎與它們的非非同步對應物相同。最大的區別是它們使用一個工作佇列來完成它們的工作的恢復或掛起部分。因此,它們可以在一個原子上下文中被呼叫,例如 URB 的完成處理程式,但是當它們返回時,裝置通常不會處於所需的狀態。
usb_autopm_get_interface_no_resume()和usb_autopm_put_interface_no_suspend()僅僅遞增或遞減使用計數器;它們不嘗試執行自動恢復或自動掛起。因此,它們可以在一個原子上下文中被呼叫。
最簡單的使用模式是,驅動程式在其 open 例程中呼叫 usb_autopm_get_interface(),並在其 close 或 release 例程中呼叫 usb_autopm_put_interface()。但是也可能有其他模式。
上面提到的自動掛起嘗試通常會由於某種原因而失敗。例如,power/control 屬性可能被設定為 on,或者同一裝置中的另一個介面可能不處於空閒狀態。這是完全正常的。如果失敗的原因是裝置空閒的時間不夠長,則會安排一個定時器在自動掛起空閒延遲到期時自動執行該操作。
自動恢復嘗試也可能失敗,儘管失敗意味著該裝置不再存在或無法正常執行。與自動掛起不同,自動恢復沒有空閒延遲。
驅動介面的其他部分¶
驅動程式可以透過呼叫
usb_enable_autosuspend(struct usb_device *udev);
在其 probe() 例程中,如果它們知道該裝置能夠正確地掛起和恢復,來為它們的裝置啟用自動掛起。這與將 auto 寫入裝置的 power/control 屬性完全等效。同樣,驅動程式可以透過呼叫
usb_disable_autosuspend(struct usb_device *udev);
來停用自動掛起。這與將 on 寫入 power/control 屬性完全相同。
有時驅動程式需要確保在自動掛起期間啟用遠端喚醒。例如,如果使用者不能透過在鍵盤上打字來導致鍵盤執行遠端喚醒,那麼自動掛起鍵盤就沒有多大意義。如果驅動程式將 intf->needs_remote_wakeup 設定為 1,那麼如果遠端喚醒不可用,核心將不會自動掛起該裝置。(但是,如果裝置已經自動掛起,則設定此標誌不會導致核心自動恢復它。通常,驅動程式會在其 probe 方法中設定此標誌,此時保證裝置不會被自動掛起。)
如果一個驅動程式在中斷上下文中非同步地執行其 I/O,它應該在開始輸出之前呼叫 usb_autopm_get_interface_async(),並在輸出佇列耗盡時呼叫 usb_autopm_put_interface_async()。當它接收到一個輸入事件時,它應該在事件處理程式中呼叫
usb_mark_last_busy(struct usb_device *udev);
這告訴 PM 核心該裝置剛剛繁忙,因此下一次自動掛起空閒延遲到期應該被推遲。許多 usb_autopm_* 例程也會進行此呼叫,因此驅動程式只需要在中斷驅動的輸入到達時擔心。
非同步操作總是會受到競爭的影響。例如,一個驅動程式可能會在核心剛剛決定裝置空閒了足夠長的時間,但還沒有來得及呼叫驅動程式的 suspend 方法時呼叫 usb_autopm_get_interface_async() 例程。suspend 方法必須負責與 I/O 請求例程和 URB 完成處理程式同步;如果驅動程式需要使用該裝置,它應該導致自動掛起失敗並返回 -EBUSY。
不應該允許外部掛起呼叫以這種方式失敗,只有自動掛起呼叫。驅動程式可以透過將 PMSG_IS_AUTO() 宏應用於 suspend 方法的訊息引數來區分它們;對於內部 PM 事件(自動掛起),它將返回 True,對於外部 PM 事件,它將返回 False。
互斥¶
對於外部事件 -- 但不一定是對於自動掛起或自動恢復 -- 當呼叫 suspend 或 resume 方法時,裝置訊號量 (udev->dev.sem) 將被持有。這意味著外部掛起/恢復事件與對 probe、disconnect、pre_reset 和 post_reset 的呼叫是互斥的;USB 核心保證這也適用於自動掛起/自動恢復事件。
如果一個驅動程式想要在一些關鍵部分阻止所有掛起/恢復呼叫,最好的方法是鎖定該裝置並呼叫 usb_autopm_get_interface()(並在關鍵部分的末尾執行相反的操作)。持有裝置訊號量將阻止所有外部 PM 呼叫,並且 usb_autopm_get_interface() 將阻止任何內部 PM 呼叫,即使它失敗了。(練習:為什麼?)
動態 PM 和系統 PM 之間的互動¶
動態電源管理和系統電源管理可以通過幾種方式進行互動。
首先,當發生系統掛起時,一個裝置可能已經被自動掛起。由於系統掛起應該儘可能透明,因此裝置應該在系統恢復後保持掛起狀態。但是這個理論可能無法很好地在實踐中應用;隨著時間的推移,核心在這方面的行為已經發生了變化。從 2.6.37 開始,策略是在系統恢復期間恢復所有裝置,並讓它們在之後處理它們自己的執行時掛起。
其次,動態電源管理事件可能會在系統掛起過程中發生。這個視窗期很短,因為系統掛起不會花費很長時間(通常是幾秒鐘),但這種情況確實可能發生。例如,一個已掛起的裝置可能會在系統掛起時傳送遠端喚醒訊號。遠端喚醒可能成功,這會導致系統掛起中止。如果遠端喚醒不成功,它可能仍然保持活動狀態,從而導致系統在系統掛起完成後立即恢復。或者,遠端喚醒可能失敗並丟失。最終結果取決於時序以及硬體和韌體設計。
xHCI 硬體鏈路電源管理¶
xHCI 主機控制器為支援鏈路電源管理的 usb2.0(xHCI 1.0 特性)和 usb3.0 裝置提供硬體鏈路電源管理。透過啟用硬體 LPM,主機可以自動將裝置置於較低的功耗狀態(usb2.0 裝置的 L1,或 usb3.0 裝置的 U1/U2),裝置可以非常快速地進入和恢復到該狀態。
用於控制硬體 LPM 的使用者介面位於每個 USB 裝置的 sysfs 目錄的 power/ 子目錄中,即 /sys/bus/usb/devices/.../power/ 中,其中“...”是裝置的 ID。相關的屬性檔案是 usb2_hardware_lpm 和 usb3_hardware_lpm。
power/usb2_hardware_lpm當支援 LPM 的 USB2 裝置插入到支援軟體 LPM 的 xHCI 主機根集線器時,主機將為其執行軟體 LPM 測試;如果裝置成功進入 L1 狀態並恢復,並且主機支援 USB2 硬體 LPM,則此檔案將顯示,並且驅動程式將為裝置啟用硬體 LPM。您可以將 y/Y/1 或 n/N/0 寫入該檔案以手動啟用/停用 USB2 硬體 LPM。這主要用於測試目的。
power/usb3_hardware_lpm_u1power/usb3_hardware_lpm_u2當支援 USB 3.0 lpm 的裝置插入到支援鏈路電源管理的 xHCI 主機時,它將檢查 BOS 描述符中是否已設定 U1 和 U2 退出延遲;如果檢查透過並且主機支援 USB3 硬體 LPM,則將為裝置啟用 USB3 硬體 LPM,並且將建立這些檔案。這些檔案儲存一個字串值(enable 或 disable),指示是否為裝置啟用了 USB3 硬體 LPM U1 或 U2。
USB 埠電源控制¶
除了掛起端點裝置和啟用硬體控制的鏈路電源管理之外,USB 子系統還能夠在某些情況下停用埠的電源。電源透過對集線器的 Set/ClearPortFeature(PORT_POWER) 請求來控制。對於根集線器或平臺內部集線器,主機控制器驅動程式將 PORT_POWER 請求轉換為平臺韌體 (ACPI) 方法呼叫以設定埠電源狀態。有關更多背景資訊,請參見 Linux Plumbers Conference 2012 幻燈片 [1] 和影片 [2]
收到 ClearPortFeature(PORT_POWER) 請求後,USB 埠在邏輯上處於關閉狀態,並且可能會觸發埠實際失去 VBUS [3]。如果一個集線器將多個埠連線到一個共享電源井中,導致電源保持直到所有埠都關閉,則可以維持 VBUS。VBUS 也可以由配置為充電應用的集線器埠維護。在任何情況下,一個邏輯上關閉的埠將失去與其裝置的連線,不響應熱插拔事件,也不響應遠端喚醒事件。
警告
關閉埠可能會導致無法熱新增裝置。 有關詳細資訊,請參見“埠電源控制的使用者介面”。
就對裝置本身的影響而言,它類似於裝置在系統掛起期間所經歷的過程,即電源會話丟失。任何在系統掛起期間行為不端的 USB 裝置或驅動程式都會受到埠電源週期事件的類似影響。因此,該實現與集線器的系統恢復路徑共享相同的裝置恢復路徑(並遵守相同的怪癖)。
埠電源控制的使用者介面¶
埠電源控制機制使用 PM 執行時系統。透過清除埠裝置的 power/pm_qos_no_power_off 標誌(預設為 1)來請求斷電。如果埠已斷開連線,它將立即收到 ClearPortFeature(PORT_POWER) 請求。否則,它將遵守 pm 執行時規則,並要求附加的子裝置和所有後代裝置都掛起。此機制依賴於集線器在其集線器描述符中宣告埠電源切換(wHubCharacteristics 邏輯電源切換模式欄位)。
注意,某些介面裝置/驅動程式不支援自動掛起。使用者空間可能需要在 usb_device 掛起之前取消繫結介面驅動程式。預設情況下,未繫結的介面裝置已掛起。取消繫結時,請注意取消繫結介面驅動程式,而不是父 usb 裝置的驅動程式。此外,保留集線器介面驅動程式繫結。如果 usb 裝置(而非介面)的驅動程式未繫結,則核心不再能夠恢復該裝置。如果集線器介面驅動程式未繫結,則對其子埠的控制將丟失,並且所有連線的子裝置都將斷開連線。一個好的經驗法則是,如果裝置的 'driver/module' 連結指向 /sys/module/usbcore,則取消繫結它將干擾埠電源控制。
埠電源控制的相關檔案示例。注意,在此示例中,這些檔案相對於 usb 集線器裝置(字首)
prefix=/sys/devices/pci0000:00/0000:00:14.0/usb3/3-1
attached child device +
hub port device + |
hub interface device + | |
v v v
$prefix/3-1:1.0/3-1-port1/device
$prefix/3-1:1.0/3-1-port1/power/pm_qos_no_power_off
$prefix/3-1:1.0/3-1-port1/device/power/control
$prefix/3-1:1.0/3-1-port1/device/3-1.1:<intf0>/driver/unbind
$prefix/3-1:1.0/3-1-port1/device/3-1.1:<intf1>/driver/unbind
...
$prefix/3-1:1.0/3-1-port1/device/3-1.1:<intfN>/driver/unbind
除了這些檔案之外,某些埠可能具有指向另一個集線器上的埠的“peer”連結。 預期是所有 superspeed 埠都具有 hi-speed peer
$prefix/3-1:1.0/3-1-port1/peer -> ../../../../usb2/2-1/2-1:1.0/2-1-port1
../../../../usb2/2-1/2-1:1.0/2-1-port1/peer -> ../../../../usb3/3-1/3-1:1.0/3-1-port1
與“companion ports”或“ehci/xhci 共享切換埠”不同,peer 埠只是組合到單個 usb3 聯結器中的高速和超高速介面引腳。 Peer 埠共享相同的祖先 XHCI 裝置。
當超高速埠斷電時,裝置可能會降級其連線並嘗試連線到高速引腳。 該實現採取措施防止這種情況
埠掛起按順序排列,以保證高速埠在其超高速 peer 埠允許斷電之前斷電。 這意味著在超高速埠上將
pm_qos_no_power_off設定為零可能不會導致埠斷電,直到其高速 peer 埠進入其執行時掛起狀態。 如果使用者空間想要保證超高速埠斷電,則必須注意對掛起進行排序。埠恢復按順序排列,以強制超高速埠在其高速 peer 埠之前通電。
埠恢復始終會觸發附加的子裝置恢復。 在電源會話丟失後,裝置可能已被移除,或者需要重置。 當父埠重新獲得電源時恢復子裝置可以解決這些狀態,並將最大埠電源週期頻率限制在子裝置可以掛起 (autosuspend-delay) 和恢復 (reset-resume latency) 的速率。
與埠電源控制相關的 Sysfs 檔案
<hubdev-portX>/power/pm_qos_no_power_off:此可寫標誌控制空閒埠的狀態。 一旦所有子裝置和後代裝置都已掛起,只要 pm_qos_no_power_off 為“0”,該埠就可以掛起/斷電。 如果 pm_qos_no_power_off 為“1”,則無論後代的統計資訊如何,該埠都將保持活動/通電狀態。 預設為 1。
<hubdev-portX>/power/runtime_status:此檔案反映埠是“活動”(通電)還是“已掛起”(邏輯上關閉)。 沒有向用戶空間指示是否仍然提供 VBUS。
<hubdev-portX>/connect_type:一個向用戶空間指示埠的位置和連線型別的諮詢只讀標誌。 它返回四個值之一“hotplug”、“hardwired”、“not used”和“unknown”。 除了 unknown 之外,所有值均由平臺韌體設定。
hotplug指示平臺上的外部可連線/可見埠。 通常,使用者空間會選擇保持此類埠通電以處理新的裝置連線事件。
hardwired指的是不可見但可連線的埠。 例如,可以透過外部開關斷開連線的 USB 藍牙的內部埠或具有硬連線 USB 攝像頭的埠。 只要 pm_qos_no_power_off 與任何門控連線的開關協調,允許這些埠掛起應該是安全的。 使用者空間必須安排在埠斷電之前連線裝置,或者在透過開關啟用連線之前啟用埠。
not used指的是預計永遠不會連線裝置的內部埠。 這些可能是空的內部埠,或者是在平臺上未物理暴露的埠。 認為可以隨時斷電。
unknown意味著平臺韌體未提供此埠的資訊。 最常見的是指外部集線器埠,對於策略決策,應將其視為“hotplug”。注意
由於我們依賴 BIOS 來正確獲取此 ACPI 資訊,因此 USB 埠描述可能缺失或錯誤。
請注意清除
pm_qos_no_power_off。 一旦電源關閉,此埠將不會響應新的連線事件。一旦連線了子裝置,在允許埠斷電之前,將應用其他約束。
<child>/power/control:必須為
auto,並且在<child>/power/runtime_status反映“掛起”狀態之前,埠不會斷電。 預設值由子裝置驅動程式控制。<child>/power/persist:對於大多數裝置,此值預設為
1,並指示核心是否可以在電源會話丟失(掛起/埠電源事件)時保持裝置的配置。 當此值為0(有問題的裝置)時,埠斷電將被停用。<child>/driver/unbind:能夠喚醒的裝置將阻止埠斷電。 此時,清除介面裝置的 usb 內部喚醒功能的唯一機制是取消繫結其驅動程式。
相對於埠裝置,斷電先決條件設定的摘要
echo 0 > power/pm_qos_no_power_off
echo 0 > peer/power/pm_qos_no_power_off # if it exists
echo auto > power/control # this is the default value
echo auto > <child>/power/control
echo 1 > <child>/power/persist # this is the default value
建議的使用者空間埠電源策略¶
如上所述,使用者空間需要小心謹慎地確定哪些埠啟用斷電。
預設配置是所有埠都以 power/pm_qos_no_power_off 設定為 1 開始,從而導致埠始終保持活動狀態。
如果確信平臺韌體對埠的描述(埠的 ACPI _PLD 記錄填充了“connect_type”)是正確的,則使用者空間可以為所有“not used”埠清除 pm_qos_no_power_off。 只要埠的斷電與任何連線開關協調,對於“hardwired”埠也可以這樣做。
更積極的使用者空間策略是在某些外部因素表明使用者已停止與系統互動時,為所有埠啟用 USB 埠斷電(將 <hubdev-portX>/power/pm_qos_no_power_off 設定為 0)。 例如,發行版可能希望在螢幕變為空白時關閉所有 USB 埠的電源,並在螢幕變為活動狀態時重新為其供電。 智慧手機和平板電腦可能希望在使用者按下電源按鈕時關閉 USB 埠的電源。