欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Linux運行時(shí)I/O設備的電源管理框架

本文介紹Linux運行時(shí)I/O設備的電源管理框架。屬于Linux內核文檔的翻譯。

原文:http://www.kernel.org/doc/Documentation/power/runtime_pm.txt

翻譯:CoryXie <wenxue.xie@windriver.com>

1. 介紹

對I/O設備的運行時(shí)電源管理(運行時(shí)PM)的支持,是在電源管理的核心(PM core)下借助于以下方式實(shí)現的:

  • 電源管理工作隊列pm_wq,總線(xiàn)類(lèi)型(bus types)和設備驅動(dòng)(device drivers)可以把自己的PM相關(guān)的工作項(work items)置于其上。我們強烈建議,pm_wq用于對所有運行時(shí)PM相關(guān)的工作項進(jìn)行排隊,因為這使得他們能夠與全系統的電源轉換(power transitions)進(jìn)行同步【掛起到RAM(suspend to RAM),休眠(hibernation),以及從系統睡眠狀態(tài)恢復(resume)】。pm_wq是在include/linux/pm_runtime.h中聲明的,定義在kernel /power/ main.c中。
  • 在 “struct device”的“power” 成員中的一些運行時(shí)PM字段(這是struct dev_pm_info類(lèi)型,在include/linux/pm.h中定義),可用于同步設備彼此之間的運行時(shí)PM操作。
  • struct dev_pm_ops”中的三個(gè)設備運行時(shí)PM回調函數(在include/linux/pm.h中定義)。
  •  一組定義在drivers/base/power/runtime.c中的輔助函數,他們可以用于執行運行時(shí)PM操作,而在這樣種方式下,他們之間的同步由PM核心負責照顧。鼓勵在總線(xiàn)類(lèi)型和設備驅動(dòng)程序中使用這些函數。

下面描述在“struct dev_pm_ops” 中存在的運行時(shí)PM回調函數,設備運行時(shí)PM字段“struct dev_pm_info”,以及運行時(shí)PM核心輔助函數。

2. 設備運行時(shí)PM回調函數

在“struct dev_pm_ops”中有三個(gè)設備運行時(shí)PM回調函數:

struct dev_pm_ops {
        ...
        int (*runtime_suspend)(struct device *dev);
        int (*runtime_resume)(struct device *dev);
        int (*runtime_idle)(struct device *dev);
        ...
};

->runtime_suspend(), -> runtime_resume()和 ->runtime_idle()回調函數會(huì )被PM核心針對下列類(lèi)型執行:

  • 設備類(lèi)型(device type),
  • 或設備類(lèi)(device class)(如果該設備類(lèi)型的struct dev_pm_ops對象不存在),
  • 或給定設備的總線(xiàn)類(lèi)型(bus type)(如果設備類(lèi)型的struct dev_pm_ops,以及設備類(lèi)的struct dev_pm_ops對象都不存在)

這就允許設備類(lèi)型覆蓋總線(xiàn)類(lèi)型或類(lèi)所提供的回調函數,如果有必要的話(huà)。

下面的文檔中,總線(xiàn)類(lèi)型,設備類(lèi)型和類(lèi)的回調函數都被稱(chēng)為子系統級的回調函數(subsystem-level callbacks)。
默認情況下,回調函數是在進(jìn)程上下文中,允許中斷的情況下被調用的。然而,子系統可以使用pm_runtime_irq_safe()輔助函數告訴PM核心,設備的 -> runtime_suspend()和 -> runtime_resume()回調函數應該在禁止中斷的原子上下文中被調用(-> runtime_idle()仍然使用默認的方式調用)。這意味著(zhù),這些回調例程不得block 或者sleep;但同時(shí)也意味著(zhù)在第4節末尾列出的同步輔助函數(synchronous helper functions),可以在中斷處理程序或原子上下文中被使用。
子系統的掛起回調函數(suspend callback)_完全_負責_恰當地處理設備的掛起。它可以(但不是必須)包括執行自己的設備驅動(dòng)程序的->runtime_suspend()回調(從PM核心的角度看,并不是必須要設備驅動(dòng)實(shí)現 ->runtime_suspend()回調函數,只要子系統級的掛起回調函數知道怎么去處理設備就行)。
  • 一旦子系統級的掛起回調函數(suspend callback)對給定設備成功地完成,PM核心就認為設備的確已經(jīng)被掛起,但這并不意味著(zhù)該設備真的已進(jìn)入低功耗狀態(tài)。這里的本意是,該設備將無(wú)法處理數據,且將無(wú)法與CPU和RAM通信,直到它的子系統級的恢復回調函數(resume callback)被執行。子系統級的掛起回調成功執行后,設備的運行時(shí)PM狀態(tài)是“掛起的(suspended)”。
  • 如果子系統級的掛起回調函數(suspend callback)返回-EBUSY或-EAGAIN,設備的運行時(shí)PM狀態(tài)是“活躍的(active)”,這意味著(zhù)該設備在此之后必須完全處于可運作狀態(tài)。
  • 如果子系統級的掛起回調函數返回一個(gè)不同于-EBUSY和-EAGAIN的錯誤代碼,PM核心認為這是一個(gè)致命的錯誤,會(huì )拒絕針對該設備運行第4節所述的輔助函數,直到它的狀態(tài)被直接設置為“活躍的(active)”,或“掛起的(suspended)”(PM核心提供了特殊的輔助函數用于此目的)。
特別的,如果為了能夠適當地工作,驅動(dòng)程序需要遠程喚醒功能(即,設備請求使其電源狀態(tài)變化的硬件機制,如PCI PME), 而device_run_wake()返回“false”的設備,則->runtime_suspend()應該返回-EBUSY。另一方面,對于device_run_wake()返回“true”的設備,且在子系統級掛起回調的執行過(guò)程中該設備進(jìn)入了低功耗狀態(tài),我們期望設備的遠程喚醒就已經(jīng)被啟動(dòng)。一般情況下,所有在運行時(shí)被設置進(jìn)入低功耗狀態(tài)的輸入設備應該啟用遠程喚醒。
 
子系統級的恢復回調函數(resume callback)要_完全_負責_處理設備的恢復,這可能(但不一定)包括執行自己的設備驅動(dòng)程序的 ->runtime_resume()回調(從PM核心的角度看,并不是必須要在設備驅動(dòng)程序中實(shí)現->runtime_resume()回調函數,只要子系統級的恢復回調知道怎樣能處理設備就行)。 
  • 一旦子系統級的恢復回調(resume callback)已順利完成,PM核心認為設備已處于完全可運作狀態(tài),這意味著(zhù)該設備必須能夠完成I/O操作。 然后,設備的運行時(shí)PM狀態(tài)是“活躍的(active)”。
  • 如果子系統級的恢復回調(resume callback)返回一個(gè)錯誤代碼,PM核心認為這是一個(gè)致命的錯誤,會(huì )拒絕針對該設備運行第4節所述的輔助函數,直到其狀態(tài)被直接設置為“活躍的(active)”或“掛起的(suspended)”(PM核心提供了特殊的輔助函數用于此目的)。
每當設備看起來(lái)空閑的時(shí)候【這是通過(guò)兩個(gè)計數器來(lái)向PM核心指示的,設備使用計數(usage counter),以及設備的“活躍子設備”(active children)計數】,子系統級的空閑回調函數(idle callback)就會(huì )被PM核心執行。
  • 如果任何一個(gè)計數器被減少到零(使用PM核心所提供的輔助函數),就檢查另一個(gè)計數器。如果該計數器也等于零,PM核心就執行子系統級的空閑回調,使用設備作參數。
子系統級的空閑回調(idle callback)執行的操作是完全依賴(lài)于子系統本身的,但期望和建議的操作是,檢查設備是否可以?huà)炱穑磼炱鹪撛O備的所有必要條件是否滿(mǎn)足),且在這種情況下,為該設備排隊一個(gè)掛起請求(queue up a suspend request)。這個(gè)回調函數返回的值將被PM核心忽略。
在第4節所述的PM核心所提供的輔助函數,保證對總線(xiàn)類(lèi)型的運行時(shí)PM回調滿(mǎn)足以下約束:
 
  1. 回調是互斥的(例如,對于同一個(gè)設備,禁止并行執行->runtime_suspend()和->runtime_resume(),或另一個(gè)->runtime_suspend()的實(shí)例);例外的情形是,-> runtime_suspend()或 -> runtime_resume()可以和-> runtime_idle()并行執行(雖然對同一設備,-> runtime_idle()將不會(huì )在任何其他回調正在執行時(shí)啟動(dòng))。
  2. -> runtime_idle() 和-> runtime_suspend()只能對 “活躍的(active)”設備執行(即PM核心只會(huì )對運行時(shí)PM狀態(tài)是“活躍的(active)” 的設備執行 ->runtime_idle() 和-> runtime_suspend())。
  3. ->runtime_idle()和->runtime_suspend()只能對其使用計數(usage counter)是零,且其“活躍子設備”(‘a(chǎn)ctive' children)個(gè)數是零或“power.ignore_children”標志被設置的設備執行。
  4. ->runtime_resume()只能對“掛起(suspended)”狀態(tài)的設備執行(即PM核心只會(huì )對運行時(shí)PM狀態(tài)是“掛起(suspended)”的設備執行->runtime_resume())。
此外,由PM核心提供的輔助函數遵循以下規則:
  • 如果 ->runtime_suspend()正將要執行,或有一個(gè)等待中的請求來(lái)執行它,對同一設備->runtime_idle()就不會(huì )被執行。
  • 請求執行或安排執行 ->runtime_suspend(),將取消任何等待對相同設備的->runtime_idle()執行請求。
  • 如果 ->runtime_resume()正將要執行,或有一個(gè)掛起的請求來(lái)執行它,相同設備的其他的回調將不會(huì )被執行。
執行->runtime_resume()請求,將取消任何對同一設備的等待中的(pending)或已被調度的(scheduled)回調執行請求,除了已被調度的自動(dòng)掛起(autosuspend)。

3. 設備的運行時(shí)PM字段

以下是在'struct dev_pm_info'中的設備的運行時(shí)PM字段,定義在include / linux/ pm.h:

  • struct timer_list suspend_timer;

用于調度(延遲的)掛起和自動(dòng)休眠(suspend and autosuspend)請求的定時(shí)器。

  • unsigned long timer_expires;

定時(shí)器到期時(shí)間,單位是jiffies(如果這異于零,則定時(shí)器正在運行,并將于該時(shí)間到期;否則定時(shí)器未運行)。

  • struct work_struct work;

用于請求排隊的工作結構(即pm_wq中工作項)。

  • wait_queue_head_t wait_queue;

等待隊列,當任何輔助函數需要等待另一個(gè)完成的時(shí)候使用。

  • spinlock_t lock;

用于同步。

  • atomic_t usage_count;

設備的使用計數。

  • atomic_t child_count;

“活躍的(active)”的子設備的個(gè)數。

  • unsigned int ignore_children;

如果置位,child_count的值將被忽略(但仍然要被更新)

  • unsigned int disable_depth;

用于禁用輔助函數(如果該值等于零,它們正常工作),它的初始值是1(即運行時(shí)PM最初對所有設備都是禁用的)

  • unsigned int runtime_error;

如果該值被設置,就表明有致命錯誤(在第2節中所述的回調函數返回的錯誤代碼之一),因此輔助函數直到這個(gè)標志被清除之前將無(wú)法正常工作,這是失敗的回調函數返回的錯誤代碼。

  • unsigned int idle_notification;

      如果該值被設置,則->runtime_idle()正在被執行。
  • unsigned int request_pending;
如果該值被設置,則有掛起的請求(即有工作項被排隊在pm_wq中)
  • enum rpm_request request;
掛起的請求類(lèi)型(如果request_pending被設置時(shí)有效)。
  • unsigned int deferred_resume;
當設備正在執行-> runtime_suspend()的時(shí)候,如果->runtime_resume()將要運行,而等待掛起操作完成并不實(shí)際,就會(huì )設置該值;這里的意思是“一旦你掛起完成,我就開(kāi)始恢復”。
  • unsigned int run_wake;
如果設備能夠生成運行時(shí)喚醒事件,該值就被設置。

  • enum rpm_status runtime_status;

設備的運行時(shí)PM狀態(tài); 此字段的初始值是RPM_SUSPENDED,這意味著(zhù)PM核心認為每個(gè)設備最初都處于'掛起',不論其實(shí)際的硬件狀態(tài)如何。

  • unsigned int no_callbacks;

表示該設備不使用運行時(shí)PM回調(參見(jiàn)第8節),它只可能會(huì )被輔助函數pm_runtime_no_callbacks()修改。

  • unsigned int irq_safe;

表示->runtime_suspend()和->runtime_resume()回調函數將在持有自旋鎖并禁止中斷的情況下被調用。

  • unsigned int use_autosuspend;

表明該設備的驅動(dòng)程序支持延遲的自動(dòng)休眠功能(見(jiàn)第9節),它只可能被輔助函數pm_runtime{_dont}_use_autosuspend()修改。

  • unsigned int timer_autosuspends;

表明PM核心應該在定時(shí)器到期時(shí)嘗試進(jìn)行自動(dòng)休眠(autosuspend),而不是一個(gè)常規的掛起(normal suspend)。

  • int autosuspend_delay;

延遲時(shí)間(以毫秒為單位),可用于自動(dòng)休眠功能。

  • unsigned long last_busy;

所有上述字段都是“structdevice”的成員“power”中的成員。

4. 運行時(shí)PM設備輔助函數

以下的運行時(shí)PM輔助函數被定義在drivers/base/power/runtime.c以及 include/linux/pm_runtime.h中:

  • void pm_runtime_init(struct device * dev);

初始化dev_pm_info結構中的設備運行時(shí)PM字段。

  • void pm_runtime_remove(struct device *dev);

確保設備的運行時(shí)PM在該設備從設備層次刪除后將被禁用。

  •  int pm_runtime_idle(struct device *dev);

執行子系統級的設備空閑回調,返回0成功,或失敗的錯誤代碼,其中的-EINPROGRESS 表示->runtime_idle()已經(jīng)在執行。

  • int pm_runtime_suspend(struct device *dev);

對設備執行子系統級的掛起回調;返回0表示成功;如果設備的運行時(shí)PM狀態(tài)已經(jīng)是“掛起”則返回1;或失敗時(shí)返回錯誤代碼,其中,-EAGAIN或-EBUSY意味著(zhù)企圖在未來(lái)再次掛起設備是安全的。

  • int pm_runtime_autosuspend(struct device*dev);

與pm_runtime_suspend()相同,除了考慮了自動(dòng)休眠延遲時(shí)間;如果pm_runtime_autosuspend_expiration()說(shuō)該延遲尚未到期,那么就會(huì )調度適當時(shí)間的自動(dòng)休眠功能,并返回0。

  • int pm_runtime_resume(struct device *dev);

對設備執行子系統級的恢復回調;返回0表示成功;如果設備的運行時(shí)PM狀態(tài)已經(jīng)是“活躍的(active)”就返回1;或失敗時(shí)錯誤代碼,其中-EAGAIN意味著(zhù)在未來(lái)試圖恢復設備可能是安全的;但應附加對‘power.runtime_error’進(jìn)行檢查。

  • int pm_request_idle(struct device *dev);

對設備提交一個(gè)執行子系統級的空閑回調的請求(請求由一個(gè)pm_wq的工作項代表);返回0表示成功,或如果請求沒(méi)有排隊成功就返回錯誤代碼。

  • int pm_request_autosuspend(struct device*dev);

調度子系統級的掛起回調函數,使其在設備的自動(dòng)休眠延遲(autosuspend delay)過(guò)期時(shí)執行;如果延遲已過(guò)期,則工作項立即被排隊。

  • int pm_schedule_suspend(struct device *dev,unsigned int delay);

調度在未來(lái)執行設備的子系統級的掛起回調,其中“delay”是在pm_wq上排隊掛起回調工作項之前等待的時(shí)間,以毫秒為單位(如果“delay”是零,工作項馬上進(jìn)行排隊);返回0表示成功;如果該設備的運行時(shí)PM狀態(tài)已經(jīng)是“掛起”時(shí)返回1;或在當請求沒(méi)有被調度(或 “delay”為0時(shí)被排隊)時(shí)返回錯誤代碼;如果->runtime_suspend()的執行已經(jīng)被調度但尚未到期,則“delay”的新值將被用來(lái)作為等待的時(shí)間。

  • int pm_request_resume(struct device *dev);

對設備提交一個(gè)執行子系統級恢復回調的請求(該請求由一個(gè)pm_wq中的工作項代表);成功返回0;如果設備的運行時(shí)PM狀態(tài)已經(jīng)是”活躍的(active)“則返回1;或當請求沒(méi)有被排上隊時(shí)返回錯誤代碼。

  • void pm_runtime_get_noresume(struct device*dev);

遞增設備的使用計數。

  • int pm_runtime_get(struct device *dev);

遞增設備的使用計數,運行pm_request_resume(dev),并返回其結果。

  • int pm_runtime_get_sync(struct device *dev);

遞增設備的使用計數,運行pm_runtime_resume(dev),并返回其結果。

  • void pm_runtime_put_noidle(struct device*dev);

遞減設備的使用計數。

  • int pm_runtime_put(struct device *dev);

設備的使用計數減1,如果結果是0,則運行pm_request_idle(dev)并返回其結果。

  • int pm_runtime_put_autosuspend(struct device*dev);

設備的使用計數減1,如果結果是0,則運行pm_request_autosuspend(dev)并返回其結果。

  • int pm_runtime_put_sync(struct device *dev);

設備的使用計數減1,如果結果是0,則運行pm_runtime_idle(dev)并返回其結果。

  • int pm_runtime_put_sync_suspend(struct device*dev);

設備的使用計數減1,如果結果是0,則運行pm_runtime_suspend(dev)并返回其結果。

  • int pm_runtime_put_sync_autosuspend(structdevice *dev);

設備的使用計數減1,如果結果是0,則運行pm_runtime_autosuspend(dev)并返回其結果。

  • void pm_runtime_enable(struct device *dev);

使能運行時(shí)PM的輔助函數,使其能運行第2節中所描述的設備的總線(xiàn)類(lèi)型的運行時(shí)PM回調。

  • int pm_runtime_disable(struct device *dev);

防止運行時(shí)PM輔助函數運行設備的子系統級的運行時(shí)PM回調,確保設備的所有等待中的運行時(shí)PM操作已完成或取消;如果有一個(gè)恢復請求正在等待,且為了滿(mǎn)足該請求而執行設備的子系統級的恢復回調是必要的,則返回1;否則返回0。

  • void pm_suspend_ignore_children(struct device*dev, bool enable);

設置/取消設備的power.ignore_children標志。

  • int pm_runtime_set_active(struct device*dev);

清除設備的“power.runtime_error”標志,設置設備的運行時(shí)PM狀態(tài)為”活躍的(active)“,并更新其父設備的”活躍子設備“計數(唯一有效的使用此函數的條件是,如果“power.runtime_error”被設置,或者“power.disable_depth”大于零);如果設備的父設備是不活躍的,且其“power.ignore_children”標志沒(méi)有設置,該函數就會(huì )失敗并返回錯誤代碼。

  • void pm_runtime_set_suspended(struct device *dev);

清除設備的“power.runtime_error”標志,設置設備的運行時(shí)PM狀態(tài)為“掛起”,并恰當更新其父設備的“活躍的子設備”計數(此函數唯一有效的使用條件是,如果“power.runtime_error”被設置,或“power.disable_depth”大于零)。

  • bool pm_runtime_suspended(struct device*dev);

如果該設備的運行時(shí)PM狀態(tài)為“掛起”且其“power.disable_depth”字段等于0,返回true;否則返回false。

  • void pm_runtime_allow(struct device *dev);

設置設備的power.runtime_auto標志,并遞減其使用計數(用于/sys/devices/.../power/control接口,實(shí)際上允許使設備在運行時(shí)被電源管理)。

  • void pm_runtime_forbid(struct device *dev);

取消設置設備的power.runtime_auto標志,并遞增其使用計數(用于/sys/devices/.../power/control接口,實(shí)際上禁止設備在運行時(shí)被電源管理)。

  • void pm_runtime_no_callbacks(struct device*dev);

設置設備的power.no_callbacks標志,并從/sys/devices/.../power中刪除運行時(shí)PM屬性(或防止設備在注冊時(shí)添加他們)。

  • void pm_runtime_irq_safe(struct device *dev);

設置設備的power.irq_safe標志,造成運行時(shí)PM掛起和恢復回調在禁止中斷的情況下被調用(但不包括空閑回調)。

  • void pm_runtime_mark_last_busy(struct device*dev);

設置power.last_busy字段為當前時(shí)間。

  • void pm_runtime_use_autosuspend(struct device*dev);

設置power.use_autosuspend標志,使能自動(dòng)休眠延遲。

  • void pm_runtime_dont_use_autosuspend(structdevice *dev);

清除power.use_autosuspend標志,禁用自動(dòng)休眠延遲。

  • void pm_runtime_set_autosuspend_delay(structdevice *dev, int delay);

設置power.autosuspend_delay的值為“delay”(以毫秒為單位),如果“delay”是負的,則防止運行時(shí)掛起。

  •  unsigned longpm_runtime_autosuspend_expiration(struct device *dev);

基于power.last_busy和power.autosuspend_delay計算當前自動(dòng)休眠延遲的到期時(shí)間;如果延遲時(shí)間是1000毫秒或更大,則到期時(shí)間四舍五入精確到秒(rounded up);如果延遲時(shí)間已經(jīng)過(guò)期或power.use_autosuspend沒(méi)有設置,則返回0;否則返回以jiffies計的過(guò)期時(shí)間。

從中斷上下文中執行以下輔助函數是安全的:

  • pm_request_idle()
  • pm_request_autosuspend()
  • pm_schedule_suspend()
  • pm_request_resume()
  • pm_runtime_get_noresume()
  • pm_runtime_get()
  • pm_runtime_put_noidle()
  • pm_runtime_put()
  • pm_runtime_put_autosuspend()
  • pm_runtime_enable()
  • pm_suspend_ignore_children()
  • pm_runtime_set_active()
  • pm_runtime_set_suspended()
  • pm_runtime_suspended()
  • pm_runtime_mark_last_busy()
  • pm_runtime_autosuspend_expiration()

如果pm_runtime_irq_safe()為設備調用,則以下輔助函數也可以在中斷上下文中使用:

  • pm_runtime_suspend()
  • pm_runtime_autosuspend()
  • pm_runtime_resume()
  • pm_runtime_get_sync()
  • pm_runtime_put_sync_suspend()

5. 運行時(shí)PM初始化,設備檢測和刪除

最初,所有設備的運行時(shí)PM被禁用,這意味著(zhù)第4節中描述的大部分的運行時(shí)PM輔助函數將返回-EAGAIN,直到為設備調用pm_runtime_enable()之后。

此外,所有設備的運行時(shí)PM的初始狀態(tài)都是'掛起(suspended)',但它不一定反映實(shí)際的物理設備狀態(tài)。因此,如果設備最初是活躍的(即,它能夠處理I/O),其運行時(shí)PM狀態(tài)必須在pm_runtime_set_active()的幫助之下,在為設備調用pm_runtime_enable()之前,被改變?yōu)椤盎钴S”。

然而,如果該設備有父設備且其父設備的運行時(shí)PM是啟用的,為設備調用pm_runtime_set_active()會(huì )影響其父設備,除非其父設備的“power.ignore_children”標志位被設置。也就是說(shuō),在這種情況下,使用PM核心的輔助函數,父設備不能在運行時(shí)被掛起,只要子設備的狀態(tài)是“活躍的”,即使子設備的運行時(shí)PM還是禁用的(即pm_runtime_enable ()尚未對該子設備調用,或對該子設備已調用pm_runtime_disable())。出于這個(gè)原因,一旦pm_runtime_set_active()被為設備調用,pm_runtime_enable()也應該被盡早調用;否則其運行時(shí)PM狀態(tài)應該在pm_runtime_set_suspended()的幫助下改回為“掛起”。

如果設備的默認初始運行時(shí)PM狀態(tài)(即“掛起”)反映了實(shí)際設備狀態(tài),它的總線(xiàn)類(lèi)型或它的驅動(dòng)程序的->probe()回調函數將可能需要使用在第4節描述的PM核心的輔助函數喚醒它。在這種情況下,應使用pm_runtime_resume()。當然,為達此目的,在此之前,設備的運行時(shí)PM應通過(guò)調用pm_runtime_enable()被啟動(dòng)。

如果設備的總線(xiàn)類(lèi)型或驅動(dòng)程序的->probe()回調運行pm_runtime_suspend()或pm_runtime_idle()或與之對應的異步函數(asynchronous counterparts),他們將失敗返回-EAGAIN,因為該設備的使用計數已經(jīng)被驅動(dòng)程序核心遞增,然后再執行->probe()。盡管如此,可能仍然比較想要設備在->probe()完成后盡快被掛起,所以驅動(dòng)那時(shí)候會(huì )核心采用pm_runtime_put_sync()來(lái)調用子系統級的設備空閑回調。

此外,在__device_release_driver()中,驅動(dòng)核心可以防止運行時(shí)PM回調與總線(xiàn)通知(notifier)回調競爭,這是必要的,因為一些子系統使用通知(notifier)來(lái)進(jìn)行影響運行時(shí)PM的操作。這是通過(guò)在driver_sysfs_remove()和BUS_NOTIFY_UNBIND_DRIVER通知之前調用pm_runtime_get_sync()來(lái)實(shí)現該目的的。如果設備已經(jīng)處于掛起狀態(tài),這將恢復該設備,并會(huì )防止在這些例程正在執行時(shí)再次被掛起。

為了讓總線(xiàn)類(lèi)型和驅動(dòng)程序在其->remove()例程中調用pm_runtime_suspend()將設備放到掛起狀態(tài),在__ ??device_release_driver()中驅動(dòng)程序核心在運行BUS_NOTIFY_UNBIND_DRIVER通知后執行pm_runtime_put_sync()。這就需要總線(xiàn)類(lèi)型和驅動(dòng)程序避免其->remove()回調函數與運行時(shí)PM直接競爭,但也讓驅動(dòng)程序在處理設備的移除過(guò)程中有更多的靈活性。

通過(guò)將/sys/devices/.../power/control屬性值改變?yōu)椤皁n”,用戶(hù)空間可以有效地禁止設備驅動(dòng)程序進(jìn)行運行時(shí)電源管理,這會(huì )導致pm_runtime_forbid()被調用。原則上,也可以使用這個(gè)機制有效地關(guān)閉運行時(shí)設備電源管理,直到用戶(hù)空間打開(kāi)它。也就是說(shuō),在初始化時(shí),驅動(dòng)程序可以確保設備的運行時(shí)PM狀態(tài)是“活躍的(active)”,并調用pm_runtime_forbid()。應該指出的是,如果用戶(hù)空間已經(jīng)有意改變/sys/devices/.../power/control 的值為“自動(dòng)”,讓驅動(dòng)在運行時(shí)進(jìn)行設備的電源管理,驅動(dòng)程序這樣用pm_runtime_forbid()可能會(huì )讓用戶(hù)空間產(chǎn)生混淆。

6. 運行時(shí)PM和系統休眠

運行時(shí)PM和系統休眠(即,系統掛起和休眠,也被稱(chēng)為掛起到RAM和掛起到磁盤(pán))以多種方式互相交互。如果系統休眠開(kāi)始時(shí)設備處于活躍狀態(tài),那么一切都簡(jiǎn)單。但如果設備已掛起,會(huì )發(fā)生什么呢?

對于運行時(shí)PM和系統休眠,設備可能有不同的喚醒設置。例如,遠程喚醒可能會(huì )在運行時(shí)PM中啟用,但不允許系統休眠時(shí)啟用(device_may_wakeup(dev)返回“false”)。當發(fā)生這種情況時(shí),子系統級系統掛起回調(system suspend callback)負責改變設備的喚醒設定(它可能將這個(gè)責任交給設備驅動(dòng)器的系統掛起例程)。為了做到這一點(diǎn),可能需要先恢復設備,再掛起它。如果驅動(dòng)程序對運行時(shí)掛起和系統休眠使用不同的電源級別或其他設置,也是如此。

在系統恢復時(shí),設備一般應恢復到全功率狀態(tài),即使他們在系統休眠開(kāi)始前已經(jīng)被掛起。這有幾個(gè)原因,包括:

  • 該設備可能需要切換功率等級(power levels),喚醒設置等。
  • 遠程喚醒事件可能已被固件丟失。
  • 該設備的子設備可能需要該設備以全功率運行,以恢復他們自己。
  •  驅動(dòng)程序對設備狀態(tài)的想法可能與設備的物理狀態(tài)不同。這可能在從休眠(hibernation)狀態(tài)恢復時(shí)發(fā)生。
  • 該設備可能需要進(jìn)行復位。
  •  即使設備被掛起,如果其使用計數>0,那么它仍然很可能會(huì )在不久的將來(lái)需要運行時(shí)恢復。
  • 總是回到全功率是最簡(jiǎn)單的。

如果系統睡眠開(kāi)始前設備已經(jīng)被掛起,那么它的運行時(shí)PM狀態(tài)將必須被更新,以反映實(shí)際的系統睡眠后的狀態(tài)。做到這一點(diǎn)的方法是:

  • pm_runtime_disable(dev);
  • pm_runtime_set_active(dev);
  • pm_runtime_enable(dev);

7. 通用的子系統回調函數

子系統可能希望通過(guò)使用PM核心提供的一套通用的,定義在driver/base/power/generic_ops.c中的電源管理回調函數,以節省代碼空間:

  •  int pm_generic_runtime_idle(struct device*dev);

調用此設備的驅動(dòng)程序提供的->runtime_idle()回調函數(如果有定義的話(huà)),并在該回調返回值是0或者回調沒(méi)有定義的情況下,調用pm_runtime_suspend()。

  • int pm_generic_runtime_suspend(struct device*dev);

調用此設備的驅動(dòng)程序提供的 ->runtime_suspend()回調函數,并返回其結果,或如果該回調函數沒(méi)有定義時(shí)返回-EINVAL。

  • int pm_generic_runtime_resume(struct device*dev);

調用此設備的驅動(dòng)程序提供的->runtime_resume()回調函數,并返回其結果,或如果該回調函數沒(méi)有定義時(shí)返回-EINVAL。

  • int pm_generic_suspend(struct device *dev);

如果該設備未在運行時(shí)被掛起,調用此設備的驅動(dòng)程序提供的->suspend()回調函數,并    返回其結果,或如果該回調函數沒(méi)有定義時(shí)返回-EINVAL。

  • int pm_generic_resume(struct device *dev);

調用此設備的驅動(dòng)程序提供的->resume()回調函數,且如果成功的話(huà),改變設備的運行時(shí)PM狀態(tài)為“活躍的”。

  • int pm_generic_freeze(struct device *dev);

如果該設備未在運行時(shí)被掛起,調用此設備的驅動(dòng)程序提供的-> freeze ()回調函數,并    返回其結果,或如果該回調函數沒(méi)有定義時(shí)返回-EINVAL。

  •  int pm_generic_thaw(struct device *dev);

如果該設備未在運行時(shí)被掛起,調用此設備的驅動(dòng)程序提供的-> thaw ()回調函數,并    返回其結果,或如果該回調函數沒(méi)有定義時(shí)返回-EINVAL。

  •  int pm_generic_poweroff(struct device *dev);

如果該設備未在運行時(shí)被掛起,調用此設備的驅動(dòng)程序提供的-> poweroff ()回調函數,并返回其結果,或如果該回調函數沒(méi)有定義時(shí)返回-EINVAL。

  •  int pm_generic_restore(struct device *dev);

調用此設備的驅動(dòng)程序提供的-> restore()回調函數,且如果成功的話(huà),改變設備的運行時(shí)PM狀態(tài)為“活躍的”。


這些函數可以被賦值給系統級dev_pm_ops結構體的下列回調函數指針:
  • ->runtime_idle(),
  • ->runtime_suspend(),
  • ->runtime_resume(),
  • ->suspend(),
  • ->resume(),
  • ->freeze(),
  • ->thaw(),
  • ->poweroff()
  • ->restore()

如果子系統希望同時(shí)使用所有的這些函數,可以簡(jiǎn)單地將GENERIC_SUBSYS_PM_OPS宏(定義在include/linux/pm.h)賦值給其dev_pm_ops結構的指針。

希望使用相同的函數作為系統掛起(system suspend), 凍結(freeze),斷電(poweroff)以及運行時(shí)掛起(run-time suspend),以及類(lèi)似的,系統恢復(system resume),解凍(thaw),恢復(restore)和運行時(shí)恢復(run-timeresume)等回調函數的設備驅動(dòng)程序,可以在定義在include/linux/pm.h中的UNIVERSAL_DEV_PM_OPS宏的幫助下做到這一點(diǎn)(可能是其最后一個(gè)參數設置為NULL)。

9. 自動(dòng)休眠功能或自動(dòng)延時(shí)掛起

改變設備的電源狀態(tài)并不是免費的,它也需要時(shí)間和能耗。只有當有理由認為設備將保持在這種狀態(tài)下大量的時(shí)間時(shí),才應將設備置入低功耗狀態(tài)。一個(gè)通常的啟發(fā)式說(shuō)法,一直沒(méi)有怎么用的設備很可能繼續保持在未使用狀態(tài),按照這個(gè)建議,驅動(dòng)程序不應該允許設備在運行時(shí)掛起,直到他們處于非活躍狀態(tài)已經(jīng)有一段最低限度的時(shí)間。即使該啟發(fā)式說(shuō)法最終并非最佳,它仍然會(huì )阻止設備在低功耗和全功率狀態(tài)之間迅速“反彈”。

術(shù)語(yǔ)“自動(dòng)休眠(autosuspend)”是一個(gè)歷史遺留下來(lái)的名字。這并不意味著(zhù)該設備就會(huì )自動(dòng)掛起(子系統或驅動(dòng)程序仍然需要調用適當的PM例程),然而這意味著(zhù)運行時(shí)掛起(run-time suspends)將自動(dòng)被延遲,直到所需的一段時(shí)間空閑后。

不活躍(Inactivity)是根據power.last_busy字段來(lái)確定的。驅動(dòng)程序應該在進(jìn)行I/O后調用pm_runtime_mark_last_busy()來(lái)更新這個(gè)字段,通常是在剛要調用pm_runtime_put_autosuspend()之前。所需的空閑時(shí)間長(cháng)度是一個(gè)策略問(wèn)題。子系統可以在最初調用pm_runtime_set_autosuspend_delay()設置該長(cháng)度,但設備注冊后該長(cháng)度應由用戶(hù)空間控制,使用/sys/devices/.../power/autosuspend_delay_ms屬性。

為了使用自動(dòng)休眠(autosuspend),子系統或驅動(dòng)程序必須調用pm_runtime_use_autosuspend()(最好是在注冊設備之前),此后他們應該使用各種*_autosuspend()輔助函數,來(lái)代替非自動(dòng)休眠的對應函數(non-autosuspend counterparts):

  • 不用:pm_runtime_suspend    而用:pm_runtime_autosuspend;
  • 不用:pm_schedule_suspend   而用:pm_request_autosuspend;
  • 不用:pm_runtime_put        而用:pm_runtime_put_autosuspend;
  • 不用:pm_runtime_put_sync   而用:pm_runtime_put_sync_autosuspend.

驅動(dòng)程序可以繼續使用非自動(dòng)休眠功能輔助函數,他們會(huì )表現正常,而不把自動(dòng)休眠延遲考慮進(jìn)來(lái)。同樣,如果power.use_autosuspend字段沒(méi)有被設置,則自動(dòng)休眠的輔助函數,使用起來(lái)就像是非自動(dòng)休眠的對應函數(non-autosuspend counterparts)。

該實(shí)現非常適合用于異步中斷上下文中。然而,這樣的使用不可避免地涉及到競爭,這是由于PM核心不能同步 ->runtime_suspend()回調與I/O請求的到來(lái)。該同步必須由驅動(dòng)程序使用其私有鎖來(lái)完成。這里是一個(gè)原理性的偽代碼示例:

  1. foo_read_or_write(structfoo_priv *foo, void *data)  
  2. {  
  3.        lock(&foo->private_lock);  
  4.        add_request_to_io_queue(foo,data);  
  5.        if(foo->num_pending_requests++ == 0)  
  6.                pm_runtime_get(&foo->dev);  
  7.        if(!foo->is_suspended)  
  8.                foo_process_next_request(foo);  
  9.        unlock(&foo->private_lock);  
  10. }  
  11.   
  12. foo_io_completion(structfoo_priv *foo, void *req)  
  13. {  
  14.        lock(&foo->private_lock);  
  15.        if(--foo->num_pending_requests == 0) {  
  16.                pm_runtime_mark_last_busy(&foo->dev);  
  17.                pm_runtime_put_autosuspend(&foo->dev);  
  18.        }else {  
  19.                foo_process_next_request(foo);  
  20.        }  
  21.        unlock(&foo->private_lock);  
  22.        /*Send req result back to the user ... */  
  23. }  
  24.   
  25. intfoo_runtime_suspend(struct device *dev)  
  26. {  
  27.        structfoo_priv foo = container_of(dev, ...);  
  28.        intret = 0;  
  29.   
  30.        lock(&foo->private_lock);  
  31.        if(foo->num_pending_requests > 0) {  
  32.                ret= -EBUSY;  
  33.        }else {  
  34.                /*... suspend the device ... */  
  35.                foo->is_suspended= 1;  
  36.        }  
  37.        unlock(&foo->private_lock);  
  38.        returnret;  
  39. }  
  40.   
  41. intfoo_runtime_resume(struct device *dev)  
  42. {  
  43.        structfoo_priv foo = container_of(dev, ...);  
  44.   
  45.        lock(&foo->private_lock);  
  46.        /*... resume the device ... */  
  47.        foo->is_suspended= 0;  
  48.        pm_runtime_mark_last_busy(&foo->dev);  
  49.        if(foo->num_pending_requests > 0)  
  50.                foo_process_requests(foo);  
  51.        unlock(&foo->private_lock);  
  52.        return0;  
  53. }  

最重要的一點(diǎn)是,在foo_io_completion()要求自動(dòng)休眠之后,foo_runtime_suspend()回調可能與foo_read_or_write()競爭。因此foo_runtime_suspend()必須檢查是否有任何掛起的I/O請求(在持有私有鎖的情況下),然后才允許掛起進(jìn)行。

此外,power.autosuspend_delay字段可以由用戶(hù)空間在任何時(shí)間改變。如果驅動(dòng)程序關(guān)心這個(gè),它可以在持有其私有鎖的情況下在->runtime_suspend()回調內調用pm_runtime_autosuspend_expiration()。如果該函數返回非零值,那么該延誤尚未過(guò)期,則該回調應該返回-EAGAIN。

 
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
runtime_suspend runtime_resume
Linux電源管理之 Power Domain
新版linux系統設備架構中關(guān)于電源管理方式的變更
ahci: sata hotplug doesn't work after suspend...
翻譯:Linux的電源管理架構
《Linux那些事兒之我是USB》我是U盤(pán)(11)從協(xié)議中來(lái)到協(xié)議中去
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久