工作效能點(OPP)庫¶
2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated
1. 簡介¶
1.1 什麼是工作效能點(OPP)?¶
當今複雜的SoC由多個協同工作的子模組組成。在執行各種用例的執行系統中,並非SoC中的所有模組都需要始終以其最高效能頻率執行。為了方便這一點,SoC中的子模組被分組到域中,允許一些域以較低的電壓和頻率執行,而其他域以較高的電壓/頻率對執行。
裝置將支援的每個域的離散元組集合,包括頻率和電壓對,稱為工作效能點或OPP。
例如
讓我們考慮一個MPU裝置,它支援以下內容:{300MHz,最小電壓為1V},{800MHz,最小電壓為1.2V},{1GHz,最小電壓為1.3V}
我們可以將這些表示為以下{Hz,uV}元組的三個OPP
{300000000, 1000000}
{800000000, 1200000}
{1000000000, 1300000}
1.2 工作效能點庫¶
OPP庫提供了一組輔助函式來組織和查詢OPP資訊。該庫位於drivers/opp/目錄中,標頭檔案位於include/linux/pm_opp.h中。可以透過從電源管理menuconfig選單中啟用CONFIG_PM_OPP來啟用OPP庫。某些SoC(例如德州儀器的OMAP框架)允許可選地以某個OPP啟動而無需cpufreq。
OPP庫的典型用法如下
(users) -> registers a set of default OPPs -> (library)
SoC framework -> modifies on required cases certain OPPs -> OPP layer
-> queries to search/retrieve information ->
OPP層期望每個域都由唯一的裝置指標表示。SoC框架為每個裝置向OPP層註冊一組初始OPP。此列表預計是一個最佳的小數字,通常每個裝置大約5個。此初始列表包含框架希望預設情況下在系統中安全啟用的OPP集合。
關於OPP可用性的說明¶
隨著系統繼續執行,SoC框架可能會選擇基於各種外部因素使某些OPP在每個裝置上可用或不可用。用例:散熱管理或其他特殊情況,SoC框架可能會選擇停用更高的頻率OPP,以安全地繼續執行,直到可以重新啟用該OPP為止(如果可能)。
OPP庫在其實現中促進了這一概念。以下操作函式僅在可用的opps上執行:dev_pm_opp_find_freq_{ceil, floor},dev_pm_opp_get_voltage,dev_pm_opp_get_freq,dev_pm_opp_get_opp_count。
dev_pm_opp_find_freq_exact旨在用於查詢opp指標,然後可以使用該指標進行dev_pm_opp_enable/disable函式以根據需要使opp可用。
警告:OPP庫的使用者應在使用get_opp_count重新整理其可用性計數,如果在裝置上呼叫了dev_pm_opp_enable/disable函式,則觸發這些的確切機制或其他依賴子系統(如cpufreq)的通知機制留給SoC特定的框架酌情決定使用OPP庫。在這些操作的情況下,還需要注意重新整理cpufreq表。
2. 初始OPP列表註冊¶
SoC實現迭代呼叫dev_pm_opp_add函式以新增每個裝置的OPP。預計SoC框架將以最佳方式註冊OPP條目 - 典型數字範圍小於5。透過註冊OPP生成的列表由OPP庫在整個裝置操作過程中維護。SoC框架可以隨後使用dev_pm_opp_enable/disable函式動態控制OPP的可用性。
- dev_pm_opp_add
為由裝置指標表示的特定域新增新的OPP。OPP是使用頻率和電壓定義的。新增後,假定OPP可用,並且可以使用dev_pm_opp_enable/disable函式控制其可用性。OPP庫在dev_pm_opp結構中內部儲存和管理此資訊。SoC框架可以使用此函式來定義一個最佳列表,以滿足SoC使用環境的需求。
- 警告
請勿在中斷上下文中使用此函式。
示例
soc_pm_init() { /* Do things */ r = dev_pm_opp_add(mpu_dev, 1000000, 900000); if (!r) { pr_err("%s: unable to register mpu opp(%d)\n", r); goto no_cpufreq; } /* Do cpufreq things */ no_cpufreq: /* Do remaining things */ }
3. OPP搜尋函式¶
諸如cpufreq之類的高階框架以頻率執行。為了將頻率映射回相應的OPP,OPP庫提供了便捷的函式來搜尋OPP庫在內部管理的OPP列表。如果找到匹配項,這些搜尋函式將返回表示opp的匹配指標,否則返回錯誤。這些錯誤應由標準錯誤檢查(例如IS_ERR())處理,並且呼叫方應採取適當的操作。
這些函式的呼叫者在使用OPP後應呼叫dev_pm_opp_put()。否則,OPP的記憶體將永遠不會被釋放,並導致記憶體洩漏。
- dev_pm_opp_find_freq_exact
基於確切的頻率和可用性搜尋OPP。此函式對於啟用預設情況下不可用的OPP特別有用。示例:在SoC框架檢測到可以使更高頻率可用的情況下,它可以使用此函式在呼叫dev_pm_opp_enable以實際使其可用之前查詢OPP。
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false); dev_pm_opp_put(opp); /* dont operate on the pointer.. just do a sanity check.. */ if (IS_ERR(opp)) { pr_err("frequency not disabled!\n"); /* trigger appropriate actions.. */ } else { dev_pm_opp_enable(dev,1000000000); }- 注意
這是唯一可以在不可用的OPP上執行的搜尋函式。
- dev_pm_opp_find_freq_floor
搜尋至多為提供的頻率的可用OPP。此函式在搜尋較小的匹配項或以降低頻率的順序處理OPP資訊時很有用。示例:查詢裝置的最高opp
freq = ULONG_MAX; opp = dev_pm_opp_find_freq_floor(dev, &freq); dev_pm_opp_put(opp);
- dev_pm_opp_find_freq_ceil
搜尋至少為提供的頻率的可用OPP。此函式在搜尋更高的匹配項或以增加頻率的順序處理OPP資訊時很有用。示例1:查詢裝置的最低opp
freq = 0; opp = dev_pm_opp_find_freq_ceil(dev, &freq); dev_pm_opp_put(opp);
示例2:SoC cpufreq_driver->target的簡化實現
soc_cpufreq_target(..) { /* Do stuff like policy checks etc. */ /* Find the best frequency match for the req */ opp = dev_pm_opp_find_freq_ceil(dev, &freq); dev_pm_opp_put(opp); if (!IS_ERR(opp)) soc_switch_to_freq_voltage(freq); else /* do something when we can't satisfy the req */ /* do other stuff */ }
4. OPP可用性控制函式¶
使用OPP庫註冊的預設OPP列表可能無法滿足所有可能的情況。OPP庫提供了一組函式來修改OPP列表中OPP的可用性。這允許SoC框架對哪些OPP在操作上可用進行細粒度的動態控制。這些函式旨在臨時刪除在諸如散熱考慮因素(例如,在溫度降至某個溫度之前不要使用OPPx)之類的條件下的OPP。
- 警告
請勿在中斷上下文中使用這些函式。
- dev_pm_opp_enable
使OPP可用於操作。示例:假設只有當SoC溫度低於某個閾值時才能使用1GHz OPP。SoC框架實現可能會選擇執行以下操作
if (cur_temp < temp_low_thresh) { /* Enable 1GHz if it was disabled */ opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false); dev_pm_opp_put(opp); /* just error check */ if (!IS_ERR(opp)) ret = dev_pm_opp_enable(dev, 1000000000); else goto try_something_else; }- dev_pm_opp_disable
使OPP不可用於操作示例:假設如果溫度超過閾值,則停用1GHz OPP。SoC框架實現可能會選擇執行以下操作
if (cur_temp > temp_high_thresh) { /* Disable 1GHz if it was enabled */ opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true); dev_pm_opp_put(opp); /* just error check */ if (!IS_ERR(opp)) ret = dev_pm_opp_disable(dev, 1000000000); else goto try_something_else; }
5. OPP資料檢索函式¶
由於OPP庫抽象了OPP資訊,因此有必要提供一組從dev_pm_opp結構中提取資訊的函式。使用搜索函式檢索OPP指標後,SoC框架可以使用以下函式來檢索OPP層內部表示的資訊。
- dev_pm_opp_get_voltage
檢索opp指標表示的電壓。示例:在cpufreq轉換到不同頻率時,SoC框架需要使用穩壓器框架將OPP表示的電壓設定為提供電壓的電源管理晶片
soc_switch_to_freq_voltage(freq) { /* do things */ opp = dev_pm_opp_find_freq_ceil(dev, &freq); v = dev_pm_opp_get_voltage(opp); dev_pm_opp_put(opp); if (v) regulator_set_voltage(.., v); /* do other things */ }- dev_pm_opp_get_freq
檢索opp指標表示的頻率。示例:假設SoC框架使用了一些輔助函式,我們可以傳遞opp指標而不是傳遞其他引數來處理相當多的資料引數
soc_cpufreq_target(..) { /* do things.. */ max_freq = ULONG_MAX; max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq); requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq); if (!IS_ERR(max_opp) && !IS_ERR(requested_opp)) r = soc_test_validity(max_opp, requested_opp); dev_pm_opp_put(max_opp); dev_pm_opp_put(requested_opp); /* do other things */ } soc_test_validity(..) { if(dev_pm_opp_get_voltage(max_opp) < dev_pm_opp_get_voltage(requested_opp)) return -EINVAL; if(dev_pm_opp_get_freq(max_opp) < dev_pm_opp_get_freq(requested_opp)) return -EINVAL; /* do things.. */ }- dev_pm_opp_get_opp_count
檢索裝置可用的opp數量示例:假設SoC中的協處理器需要知道表中的可用頻率,則主處理器可以按以下方式通知
soc_notify_coproc_available_frequencies() { /* Do things */ num_available = dev_pm_opp_get_opp_count(dev); speeds = kcalloc(num_available, sizeof(u32), GFP_KERNEL); /* populate the table in increasing order */ freq = 0; while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) { speeds[i] = freq; freq++; i++; dev_pm_opp_put(opp); } soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available); /* Do other things */ }
6. 資料結構¶
通常,SoC包含多個可變的電壓域。每個域由一個裝置指標表示。與OPP的關係可以表示如下
SoC
|- device 1
| |- opp 1 (availability, freq, voltage)
| |- opp 2 ..
... ...
| `- opp n ..
|- device 2
...
`- device m
OPP庫維護一個內部列表,SoC框架會填充該列表,並由上述各種函式訪問。但是,表示實際OPP和域的結構是OPP庫內部的,以便允許適合跨系統可重用的抽象。
- struct dev_pm_opp
OPP庫的內部資料結構,用於表示OPP。除了頻率,電壓,可用性資訊外,它還包含OPP庫執行所需的內部帳簿資訊。此結構的指標會提供回給使用者(例如SoC框架),以用作OPP層互動中OPP的識別符號。
- 警告
struct dev_pm_opp指標不應由使用者解析或修改。例項的預設值由dev_pm_opp_add填充,但是OPP的可用性可以透過dev_pm_opp_enable/disable函式修改。
- struct device
這用於將域標識到OPP層。裝置的性質及其實現留給OPP庫的使用者(例如SoC框架)。
總體而言,在一個簡單的檢視中,資料結構操作表示如下
Initialization / modification:
+-----+ /- dev_pm_opp_enable
dev_pm_opp_add --> | opp | <-------
| +-----+ \- dev_pm_opp_disable
\-------> domain_info(device)
Search functions:
/-- dev_pm_opp_find_freq_ceil ---\ +-----+
domain_info<---- dev_pm_opp_find_freq_exact -----> | opp |
\-- dev_pm_opp_find_freq_floor ---/ +-----+
Retrieval functions:
+-----+ /- dev_pm_opp_get_voltage
| opp | <---
+-----+ \- dev_pm_opp_get_freq
domain_info <- dev_pm_opp_get_opp_count