요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
==========================================
Operating Performance Points (OPP) Library
==========================================
(C) 2009-2010 Nishanth Menon <[email protected]>, Texas Instruments Incorporated
.. Contents
1. Introduction
2. Initial OPP List Registration
3. OPP Search Functions
4. OPP Availability Control Functions
5. OPP Data Retrieval Functions
6. Data Structures
1. Introduction
===============
1.1 What is an Operating Performance Point (OPP)?
-------------------------------------------------
Complex SoCs of today consists of a multiple sub-modules working in conjunction.
In an operational system executing varied use cases, not all modules in the SoC
need to function at their highest performing frequency all the time. To
facilitate this, sub-modules in a SoC are grouped into domains, allowing some
domains to run at lower voltage and frequency while other domains run at
voltage/frequency pairs that are higher.
The set of discrete tuples consisting of frequency and voltage pairs that
the device will support per domain are called Operating Performance Points or
OPPs.
As an example:
Let us consider an MPU device which supports the following:
{300MHz at minimum voltage of 1V}, {800MHz at minimum voltage of 1.2V},
{1GHz at minimum voltage of 1.3V}
We can represent these as three OPPs as the following {Hz, uV} tuples:
- {300000000, 1000000}
- {800000000, 1200000}
- {1000000000, 1300000}
1.2 Operating Performance Points Library
----------------------------------------
OPP library provides a set of helper functions to organize and query the OPP
information. The library is located in drivers/opp/ directory and the header
is located in include/linux/pm_opp.h. OPP library can be enabled by enabling
CONFIG_PM_OPP from power management menuconfig menu. Certain SoCs such as Texas
Instrument's OMAP framework allows to optionally boot at a certain OPP without
needing cpufreq.
Typical usage of the OPP library is as follows::
(users) -> registers a set of default OPPs -> (library)
SoC framework -> modifies on required cases certain OPPs -> OPP layer
-> queries to search/retrieve information ->
OPP layer expects each domain to be represented by a unique device pointer. SoC
framework registers a set of initial OPPs per device with the OPP layer. This
list is expected to be an optimally small number typically around 5 per device.
This initial list contains a set of OPPs that the framework expects to be safely
enabled by default in the system.
Note on OPP Availability
^^^^^^^^^^^^^^^^^^^^^^^^
As the system proceeds to operate, SoC framework may choose to make certain
OPPs available or not available on each device based on various external
factors. Example usage: Thermal management or other exceptional situations where
SoC framework might choose to disable a higher frequency OPP to safely continue
operations until that OPP could be re-enabled if possible.
OPP library facilitates this concept in its implementation. The following
operational functions operate only on available 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 is meant to be used to find the opp pointer
which can then be used for dev_pm_opp_enable/disable functions to make an
opp available as required.
WARNING: Users of OPP library should refresh their availability count using
get_opp_count if dev_pm_opp_enable/disable functions are invoked for a
device, the exact mechanism to trigger these or the notification mechanism
to other dependent subsystems such as cpufreq are left to the discretion of
the SoC specific framework which uses the OPP library. Similar care needs
to be taken care to refresh the cpufreq table in cases of these operations.
2. Initial OPP List Registration
================================
The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
device. It is expected that the SoC framework will register the OPP entries
optimally- typical numbers range to be less than 5. The list generated by
registering the OPPs is maintained by OPP library throughout the device
operation. The SoC framework can subsequently control the availability of the
OPPs dynamically using the dev_pm_opp_enable / disable functions.
dev_pm_opp_add
Add a new OPP for a specific domain represented by the device pointer.
The OPP is defined using the frequency and voltage. Once added, the OPP
is assumed to be available and control of its availability can be done
with the dev_pm_opp_enable/disable functions. OPP library
internally stores and manages this information in the dev_pm_opp struct.
This function may be used by SoC framework to define a optimal list
as per the demands of SoC usage environment.
WARNING:
Do not use this function in interrupt context.
Example::
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 Search Functions
=======================
High level framework such as cpufreq operates on frequencies. To map the
frequency back to the corresponding OPP, OPP library provides handy functions
to search the OPP list that OPP library internally manages. These search
functions return the matching pointer representing the opp if a match is
found, else returns error. These errors are expected to be handled by standard
error checks such as IS_ERR() and appropriate actions taken by the caller.
Callers of these functions shall call dev_pm_opp_put() after they have used the
OPP. Otherwise the memory for the OPP will never get freed and result in
memleak.
dev_pm_opp_find_freq_exact
Search for an OPP based on an *exact* frequency and
availability. This function is especially useful to enable an OPP which
is not available by default.
Example: In a case when SoC framework detects a situation where a
higher frequency could be made available, it can use this function to
find the OPP prior to call the dev_pm_opp_enable to actually make
it available::
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);
}
NOTE:
This is the only search function that operates on OPPs which are
not available.
dev_pm_opp_find_freq_floor
Search for an available OPP which is *at most* the
provided frequency. This function is useful while searching for a lesser
match OR operating on OPP information in the order of decreasing
frequency.
Example: To find the highest opp for a device::
freq = ULONG_MAX;
opp = dev_pm_opp_find_freq_floor(dev, &freq);
dev_pm_opp_put(opp);
dev_pm_opp_find_freq_ceil
Search for an available OPP which is *at least* the
provided frequency. This function is useful while searching for a
higher match OR operating on OPP information in the order of increasing
frequency.
Example 1: To find the lowest opp for a device::
freq = 0;
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
dev_pm_opp_put(opp);
Example 2: A simplified implementation of a 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 Availability Control Functions
=====================================
A default OPP list registered with the OPP library may not cater to all possible
situation. The OPP library provides a set of functions to modify the
availability of a OPP within the OPP list. This allows SoC frameworks to have
fine grained dynamic control of which sets of OPPs are operationally available.
These functions are intended to *temporarily* remove an OPP in conditions such
as thermal considerations (e.g. don't use OPPx until the temperature drops).
WARNING:
Do not use these functions in interrupt context.
dev_pm_opp_enable
Make a OPP available for operation.
Example: Lets say that 1GHz OPP is to be made available only if the
SoC temperature is lower than a certain threshold. The SoC framework
implementation might choose to do something as follows::
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
Make an OPP to be not available for operation
Example: Lets say that 1GHz OPP is to be disabled if the temperature
exceeds a threshold value. The SoC framework implementation might
choose to do something as follows::
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 Data Retrieval Functions
===============================
Since OPP library abstracts away the OPP information, a set of functions to pull
information from the dev_pm_opp structure is necessary. Once an OPP pointer is
retrieved using the search functions, the following functions can be used by SoC
framework to retrieve the information represented inside the OPP layer.
dev_pm_opp_get_voltage
Retrieve the voltage represented by the opp pointer.
Example: At a cpufreq transition to a different frequency, SoC
framework requires to set the voltage represented by the OPP using
the regulator framework to the Power Management chip providing the
voltage::
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
Retrieve the freq represented by the opp pointer.
Example: Lets say the SoC framework uses a couple of helper functions
we could pass opp pointers instead of doing additional parameters to
handle quiet a bit of data parameters::
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
Retrieve the number of available opps for a device
Example: Lets say a co-processor in the SoC needs to know the available
frequencies in a table, the main processor can notify as following::
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. Data Structures
==================
Typically an SoC contains multiple voltage domains which are variable. Each
domain is represented by a device pointer. The relationship to OPP can be
represented as follows::
SoC
|- device 1
| |- opp 1 (availability, freq, voltage)
| |- opp 2 ..
... ...
| `- opp n ..
|- device 2
...
`- device m
OPP library maintains a internal list that the SoC framework populates and
accessed by various functions as described above. However, the structures
representing the actual OPPs and domains are internal to the OPP library itself
to allow for suitable abstraction reusable across systems.
struct dev_pm_opp
The internal data structure of OPP library which is used to
represent an OPP. In addition to the freq, voltage, availability
information, it also contains internal book keeping information required
for the OPP library to operate on. Pointer to this structure is
provided back to the users such as SoC framework to be used as a
identifier for OPP in the interactions with OPP layer.
WARNING:
The struct dev_pm_opp pointer should not be parsed or modified by the
users. The defaults of for an instance is populated by
dev_pm_opp_add, but the availability of the OPP can be modified
by dev_pm_opp_enable/disable functions.
struct device
This is used to identify a domain to the OPP layer. The
nature of the device and its implementation is left to the user of
OPP library such as the SoC framework.
Overall, in a simplistic view, the data structure operations is represented as
following::
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
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
OPP의 정의와 library
1-54현대의 복잡한 SoC는 여러 sub-module이 함께 동작합니다. 다양한 use case를 실행할 때 모든 module이 늘 최고 frequency로 동작할 필요는 없습니다. 그래서 sub-module을 domain으로 묶어 어떤 domain은 낮은 voltage·frequency에서, 다른 domain은 더 높은 voltage·frequency pair에서 실행할 수 있게 합니다.
Domain별로 device가 지원하는 이산적인 frequency·voltage tuple 집합을 Operating Performance Point, 즉 OPP라고 합니다.
예를 들어 MPU가 최소 1V에서 300MHz, 최소 1.2V에서 800MHz, 최소 1.3V에서 1GHz를 지원한다면 세 OPP를 `{Hz, uV}` tuple로 표현할 수 있습니다.
각 frequency를 안정적으로 동작시키는 최소 voltage를 tuple로 기록합니다.
OPP library는 OPP 정보를 구성하고 조회하는 helper function 집합입니다. 구현은 `drivers/opp/`, header는 `include/linux/pm_opp.h`에 있으며 power management menuconfig의 `CONFIG_PM_OPP`로 enable합니다.
Texas Instruments OMAP framework 같은 일부 SoC는 cpufreq 없이도 특정 OPP로 boot할 수 있습니다.
Workload에 필요한 domain만 높은 OPP로 올려 성능과 소비 전력을 조절합니다.
==========================================
Operating Performance Points (OPP) Library
==========================================
(C) 2009-2010 Nishanth Menon <[email protected]>, Texas Instruments Incorporated
.. Contents
1. Introduction
2. Initial OPP List Registration
3. OPP Search Functions
4. OPP Availability Control Functions
5. OPP Data Retrieval Functions
6. Data Structures
1. Introduction
===============
1.1 What is an Operating Performance Point (OPP)?
-------------------------------------------------
Complex SoCs of today consists of a multiple sub-modules working in conjunction.
In an operational system executing varied use cases, not all modules in the SoC
need to function at their highest performing frequency all the time. To
facilitate this, sub-modules in a SoC are grouped into domains, allowing some
domains to run at lower voltage and frequency while other domains run at
voltage/frequency pairs that are higher.
The set of discrete tuples consisting of frequency and voltage pairs that
the device will support per domain are called Operating Performance Points or
OPPs.
As an example:
Let us consider an MPU device which supports the following:
{300MHz at minimum voltage of 1V}, {800MHz at minimum voltage of 1.2V},
{1GHz at minimum voltage of 1.3V}
We can represent these as three OPPs as the following {Hz, uV} tuples:
- {300000000, 1000000}
- {800000000, 1200000}
- {1000000000, 1300000}
1.2 Operating Performance Points Library
----------------------------------------
OPP library provides a set of helper functions to organize and query the OPP
information. The library is located in drivers/opp/ directory and the header
is located in include/linux/pm_opp.h. OPP library can be enabled by enabling
CONFIG_PM_OPP from power management menuconfig menu. Certain SoCs such as Texas
Instrument's OMAP framework allows to optionally boot at a certain OPP without
needing cpufreq.
일반 사용 흐름과 availability
55-91일반적인 사용 흐름에서 SoC framework는 기본 OPP 집합을 library에 등록하고, 필요한 상황에 일부 OPP를 수정하며, OPP layer에 정보를 검색·조회합니다.
SoC framework가 domain별 기본 목록을 등록하고 runtime 정책에 따라 availability를 바꿉니다.
OPP layer는 각 domain을 고유한 device pointer 하나로 표현한다고 가정합니다. SoC framework는 device마다 초기 OPP 집합을 등록하며, 일반적으로 device당 약 5개인 최적으로 작은 목록을 권장합니다. 초기 목록에는 system에서 기본적으로 안전하게 enable할 수 있는 OPP를 넣습니다.
동작 중에는 thermal management 같은 외부 조건에 따라 특정 OPP를 available 또는 unavailable로 바꿀 수 있습니다. 예를 들어 온도가 내려갈 때까지 높은 frequency OPP를 disable하여 안전하게 계속 동작하게 할 수 있습니다.
`dev_pm_opp_find_freq_ceil`, `dev_pm_opp_find_freq_floor`, `dev_pm_opp_get_voltage`, `dev_pm_opp_get_freq`, `dev_pm_opp_get_opp_count`는 available OPP만 대상으로 동작합니다.
`dev_pm_opp_find_freq_exact`는 unavailable OPP도 찾을 수 있는 유일한 search function이며, 얻은 pointer를 `dev_pm_opp_enable()` 또는 `dev_pm_opp_disable()`에 대응하는 판단에 사용할 수 있습니다.
OPP availability를 바꾼 뒤 사용자는 `get_opp_count`로 available count를 갱신해야 합니다. cpufreq 같은 의존 subsystem에 알리는 방식은 SoC-specific framework가 결정하며, 이 동작 뒤 cpufreq table도 새로 고쳐야 합니다.
일반 query는 available OPP만 보지만 exact search는 원하는 availability를 명시합니다.
Typical usage of the OPP library is as follows::
(users) -> registers a set of default OPPs -> (library)
SoC framework -> modifies on required cases certain OPPs -> OPP layer
-> queries to search/retrieve information ->
OPP layer expects each domain to be represented by a unique device pointer. SoC
framework registers a set of initial OPPs per device with the OPP layer. This
list is expected to be an optimally small number typically around 5 per device.
This initial list contains a set of OPPs that the framework expects to be safely
enabled by default in the system.
Note on OPP Availability
^^^^^^^^^^^^^^^^^^^^^^^^
As the system proceeds to operate, SoC framework may choose to make certain
OPPs available or not available on each device based on various external
factors. Example usage: Thermal management or other exceptional situations where
SoC framework might choose to disable a higher frequency OPP to safely continue
operations until that OPP could be re-enabled if possible.
OPP library facilitates this concept in its implementation. The following
operational functions operate only on available 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 is meant to be used to find the opp pointer
which can then be used for dev_pm_opp_enable/disable functions to make an
opp available as required.
WARNING: Users of OPP library should refresh their availability count using
get_opp_count if dev_pm_opp_enable/disable functions are invoked for a
device, the exact mechanism to trigger these or the notification mechanism
to other dependent subsystems such as cpufreq are left to the discretion of
the SoC specific framework which uses the OPP library. Similar care needs
to be taken care to refresh the cpufreq table in cases of these operations.
초기 OPP 목록 등록
92-127SoC 구현은 device별로 `dev_pm_opp_add()`를 반복 호출해 OPP를 등록합니다. 일반적인 OPP 수는 5개 미만이 되도록 최적화합니다. 생성된 목록은 device가 동작하는 동안 OPP library가 유지하고, 이후 `dev_pm_opp_enable()`과 `dev_pm_opp_disable()`로 availability를 동적으로 제어할 수 있습니다.
`dev_pm_opp_add`는 device pointer가 나타내는 domain에 frequency와 voltage로 정의한 새 OPP를 추가합니다. 추가 직후에는 available로 간주하며 내부 `struct dev_pm_opp`에 저장·관리됩니다.
SoC framework는 실제 사용 환경의 요구에 맞는 최적 목록을 정의할 수 있습니다. 이 함수는 interrupt context에서 사용하면 안 됩니다.
예제 `soc_pm_init()`은 `dev_pm_opp_add(mpu_dev, 1000000, 900000)`을 호출하고 결과에 따라 cpufreq setup 또는 나머지 초기화로 진행합니다. 원문 code와 control flow는 아래 source block에 그대로 보존합니다.
초기 등록 시점에 domain, frequency, voltage를 연결합니다.
작은 기본 목록을 만들고 runtime 정책이 availability만 바꿉니다.
2. Initial OPP List Registration
================================
The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
device. It is expected that the SoC framework will register the OPP entries
optimally- typical numbers range to be less than 5. The list generated by
registering the OPPs is maintained by OPP library throughout the device
operation. The SoC framework can subsequently control the availability of the
OPPs dynamically using the dev_pm_opp_enable / disable functions.
dev_pm_opp_add
Add a new OPP for a specific domain represented by the device pointer.
The OPP is defined using the frequency and voltage. Once added, the OPP
is assumed to be available and control of its availability can be done
with the dev_pm_opp_enable/disable functions. OPP library
internally stores and manages this information in the dev_pm_opp struct.
This function may be used by SoC framework to define a optimal list
as per the demands of SoC usage environment.
WARNING:
Do not use this function in interrupt context.
Example::
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 */
}
Search 공통 규칙과 exact 검색
128-163Cpufreq 같은 high-level framework는 frequency를 기준으로 동작합니다. OPP library는 frequency를 내부 OPP 목록의 항목으로 다시 매핑하는 search function을 제공합니다.
일치하는 OPP가 있으면 이를 나타내는 pointer를 반환하고, 없으면 error pointer를 반환합니다. Caller는 `IS_ERR()` 같은 표준 error check로 처리해야 합니다.
Search function으로 얻은 OPP를 다 쓴 뒤에는 반드시 `dev_pm_opp_put()`을 호출해야 합니다. 그렇지 않으면 OPP memory가 영원히 해제되지 않아 leak가 발생합니다.
`dev_pm_opp_find_freq_exact()`는 exact frequency와 요청한 availability가 일치하는 OPP를 찾습니다. 기본적으로 unavailable인 OPP를 다시 enable하려는 상황에 특히 유용합니다.
예제는 1GHz이면서 unavailable인 OPP를 찾고 error 여부를 확인한 뒤 `dev_pm_opp_enable(dev, 1000000000)`을 호출합니다. 이 함수만 unavailable OPP를 검색할 수 있습니다.
현재 비활성인 정확한 OPP가 존재하는지 확인한 뒤 availability를 전환합니다.
3. OPP Search Functions
=======================
High level framework such as cpufreq operates on frequencies. To map the
frequency back to the corresponding OPP, OPP library provides handy functions
to search the OPP list that OPP library internally manages. These search
functions return the matching pointer representing the opp if a match is
found, else returns error. These errors are expected to be handled by standard
error checks such as IS_ERR() and appropriate actions taken by the caller.
Callers of these functions shall call dev_pm_opp_put() after they have used the
OPP. Otherwise the memory for the OPP will never get freed and result in
memleak.
dev_pm_opp_find_freq_exact
Search for an OPP based on an *exact* frequency and
availability. This function is especially useful to enable an OPP which
is not available by default.
Example: In a case when SoC framework detects a situation where a
higher frequency could be made available, it can use this function to
find the OPP prior to call the dev_pm_opp_enable to actually make
it available::
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);
}
NOTE:
This is the only search function that operates on OPPs which are
not available.
Floor·ceil 검색
164-200`dev_pm_opp_find_freq_floor()`는 제공한 frequency 이하에서 가장 높은 available OPP를 찾습니다. 낮은 쪽 일치 항목을 찾거나 frequency 내림차순으로 OPP를 순회할 때 사용합니다.
Device의 최고 OPP를 찾으려면 `freq = ULONG_MAX`로 시작해 floor search를 호출합니다.
`dev_pm_opp_find_freq_ceil()`은 제공한 frequency 이상에서 가장 낮은 available OPP를 찾습니다. 높은 쪽 일치 항목을 찾거나 frequency 오름차순으로 순회할 때 사용합니다.
Device의 최저 OPP는 `freq = 0`에서 ceil search로 찾습니다. 단순화한 `cpufreq_driver->target` 예제는 요청 frequency를 ceil search에 넘기고 성공하면 `soc_switch_to_freq_voltage(freq)`로 frequency와 voltage를 전환합니다.
Floor와 ceil은 available OPP 집합에서 경계값을 선택합니다.
요청을 만족하는 최소 상위 OPP를 선택해 clock·voltage transition에 사용합니다.
dev_pm_opp_find_freq_floor
Search for an available OPP which is *at most* the
provided frequency. This function is useful while searching for a lesser
match OR operating on OPP information in the order of decreasing
frequency.
Example: To find the highest opp for a device::
freq = ULONG_MAX;
opp = dev_pm_opp_find_freq_floor(dev, &freq);
dev_pm_opp_put(opp);
dev_pm_opp_find_freq_ceil
Search for an available OPP which is *at least* the
provided frequency. This function is useful while searching for a
higher match OR operating on OPP information in the order of increasing
frequency.
Example 1: To find the lowest opp for a device::
freq = 0;
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
dev_pm_opp_put(opp);
Example 2: A simplified implementation of a 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 */
}
OPP availability 제어
201-246기본 OPP 목록만으로 모든 상황을 처리할 수는 없습니다. OPP library는 목록 안의 OPP availability를 바꾸는 함수로 SoC framework가 operational OPP 집합을 세밀하게 동적 제어하게 합니다.
이 함수는 온도가 내려갈 때까지 특정 OPP를 사용하지 않는 경우처럼 OPP를 일시적으로 제거하려는 용도입니다. Interrupt context에서 사용하면 안 됩니다.
`dev_pm_opp_enable()`은 OPP를 operational하게 만듭니다. 예제는 현재 온도가 낮은 threshold 아래로 내려가면 1GHz unavailable OPP를 exact search로 찾고, 존재할 때 enable합니다.
`dev_pm_opp_disable()`은 OPP를 operational set에서 제외합니다. 예제는 온도가 높은 threshold를 넘으면 현재 available인 1GHz OPP를 exact search로 찾고 disable합니다.
낮은 threshold에서 고성능 OPP를 복구하고 높은 threshold에서 다시 제한합니다.
두 함수 모두 device와 exact frequency로 OPP 상태를 바꿉니다.
4. OPP Availability Control Functions
=====================================
A default OPP list registered with the OPP library may not cater to all possible
situation. The OPP library provides a set of functions to modify the
availability of a OPP within the OPP list. This allows SoC frameworks to have
fine grained dynamic control of which sets of OPPs are operationally available.
These functions are intended to *temporarily* remove an OPP in conditions such
as thermal considerations (e.g. don't use OPPx until the temperature drops).
WARNING:
Do not use these functions in interrupt context.
dev_pm_opp_enable
Make a OPP available for operation.
Example: Lets say that 1GHz OPP is to be made available only if the
SoC temperature is lower than a certain threshold. The SoC framework
implementation might choose to do something as follows::
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
Make an OPP to be not available for operation
Example: Lets say that 1GHz OPP is to be disabled if the temperature
exceeds a threshold value. The SoC framework implementation might
choose to do something as follows::
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;
}
Voltage·frequency 조회
247-298OPP library가 내부 정보를 abstraction하므로 `struct dev_pm_opp` pointer에서 값을 읽는 accessor가 필요합니다. Search로 OPP pointer를 얻은 뒤 SoC framework는 다음 함수를 사용합니다.
`dev_pm_opp_get_voltage()`는 OPP의 voltage를 반환합니다. Cpufreq transition 예제는 ceil search로 OPP를 찾고 voltage를 얻은 뒤 regulator framework의 `regulator_set_voltage(.., v)`로 Power Management chip의 전압을 설정합니다.
`dev_pm_opp_get_freq()`는 OPP의 frequency를 반환합니다. Helper 사이에 여러 개별 parameter를 넘기는 대신 OPP pointer를 전달하고 필요한 frequency·voltage를 accessor로 읽을 수 있습니다.
예제 `soc_cpufreq_target()`은 최고 OPP와 요청 OPP를 찾아 `soc_test_validity()`에 넘깁니다. Validation 함수는 요청 OPP의 voltage나 frequency가 최고 OPP보다 크면 `-EINVAL`을 반환합니다. 각 pointer는 사용 후 `dev_pm_opp_put()`으로 놓습니다.
Opaque pointer를 직접 해석하지 않고 공식 accessor로 값을 읽습니다.
선택한 OPP의 voltage를 regulator에 적용하고 대응 frequency로 전환합니다.
5. OPP Data Retrieval Functions
===============================
Since OPP library abstracts away the OPP information, a set of functions to pull
information from the dev_pm_opp structure is necessary. Once an OPP pointer is
retrieved using the search functions, the following functions can be used by SoC
framework to retrieve the information represented inside the OPP layer.
dev_pm_opp_get_voltage
Retrieve the voltage represented by the opp pointer.
Example: At a cpufreq transition to a different frequency, SoC
framework requires to set the voltage represented by the OPP using
the regulator framework to the Power Management chip providing the
voltage::
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
Retrieve the freq represented by the opp pointer.
Example: Lets say the SoC framework uses a couple of helper functions
we could pass opp pointers instead of doing additional parameters to
handle quiet a bit of data parameters::
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.. */
}
Available OPP 수와 순회
299-321`dev_pm_opp_get_opp_count()`는 device에서 현재 available인 OPP 수를 반환합니다.
예제에서는 SoC co-processor에 available frequency table을 알려 주기 위해 count만큼 `u32` 배열을 할당합니다. `freq = 0`에서 시작해 `dev_pm_opp_find_freq_ceil()`이 error를 반환할 때까지 오름차순으로 OPP를 찾고 각 frequency를 배열에 저장합니다.
각 iteration에서 `freq++`로 다음 OPP보다 큰 검색 시작점을 만들고, 얻은 OPP는 `dev_pm_opp_put()`으로 놓습니다. 완성한 table은 `soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available)`로 전달합니다.
Count로 memory를 확보한 뒤 ceil search를 반복해 오름차순 table을 만듭니다.
dev_pm_opp_get_opp_count
Retrieve the number of available opps for a device
Example: Lets say a co-processor in the SoC needs to know the available
frequencies in a table, the main processor can notify as following::
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 */
}
Domain과 내부 구조체
322-361일반적인 SoC에는 voltage를 바꿀 수 있는 domain이 여러 개 있고 각 domain을 device pointer로 나타냅니다. 각 device 아래에는 availability, frequency, voltage를 가진 OPP가 여러 개 있습니다.
원문의 tree diagram을 domain 관계로 다시 구성했습니다.
OPP library는 SoC framework가 채운 내부 목록을 관리하고 앞서 설명한 함수들이 접근하게 합니다. 실제 OPP와 domain을 나타내는 구조체는 여러 system에서 재사용 가능한 abstraction을 위해 library 내부에 숨깁니다.
`struct dev_pm_opp`는 하나의 OPP를 나타내는 내부 구조체입니다. Frequency, voltage, availability뿐 아니라 library 동작에 필요한 bookkeeping 정보를 포함합니다. SoC framework 같은 사용자는 이 pointer를 OPP layer와 상호 작용할 identifier로 받습니다.
사용자는 `struct dev_pm_opp` pointer를 직접 parse하거나 수정하면 안 됩니다. 기본 항목은 `dev_pm_opp_add()`가 채우고 availability는 enable/disable API로만 바꿉니다.
`struct device`는 OPP layer에서 domain을 식별합니다. 실제 device의 성격과 구현은 SoC framework 같은 library 사용자에게 맡깁니다.
Public interaction은 opaque OPP pointer와 device domain identifier를 사용합니다.
6. Data Structures
==================
Typically an SoC contains multiple voltage domains which are variable. Each
domain is represented by a device pointer. The relationship to OPP can be
represented as follows::
SoC
|- device 1
| |- opp 1 (availability, freq, voltage)
| |- opp 2 ..
... ...
| `- opp n ..
|- device 2
...
`- device m
OPP library maintains a internal list that the SoC framework populates and
accessed by various functions as described above. However, the structures
representing the actual OPPs and domains are internal to the OPP library itself
to allow for suitable abstraction reusable across systems.
struct dev_pm_opp
The internal data structure of OPP library which is used to
represent an OPP. In addition to the freq, voltage, availability
information, it also contains internal book keeping information required
for the OPP library to operate on. Pointer to this structure is
provided back to the users such as SoC framework to be used as a
identifier for OPP in the interactions with OPP layer.
WARNING:
The struct dev_pm_opp pointer should not be parsed or modified by the
users. The defaults of for an instance is populated by
dev_pm_opp_add, but the availability of the OPP can be modified
by dev_pm_opp_enable/disable functions.
struct device
This is used to identify a domain to the OPP layer. The
nature of the device and its implementation is left to the user of
OPP library such as the SoC framework.
등록·검색·조회 관계도
362-381원문의 마지막 ASCII 그림은 initialization/modification, search, retrieval 세 종류의 API가 `domain_info(device)`와 `opp` object를 중심으로 연결되는 방식을 보여 줍니다.
OPP를 domain에 추가한 뒤 enable·disable로 operational set을 바꿉니다.
Device domain과 frequency 조건으로 opaque OPP pointer를 얻습니다.
OPP pointer에서는 voltage·frequency를, domain에서는 available count를 읽습니다.
Overall, in a simplistic view, the data structure operations is represented as
following::
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
요약·해설
opp.rst:1-381OPP library는 device pointer를 domain identifier로 사용해 안전한 frequency·voltage pair를 관리합니다. Search 결과의 reference를 반드시 `dev_pm_opp_put()`으로 해제하고, thermal 정책은 enable·disable 뒤 count와 cpufreq table을 갱신해야 합니다.