Commit 6185deaa authored by Viresh Kumar's avatar Viresh Kumar Committed by Rafael J. Wysocki

PM / OPP: Update Documentation to remove RCU specific bits

Update OPP documentation to remove the RCU specific bits.
Signed-off-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: default avatarStephen Boyd <sboyd@codeaurora.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent cdd3e614
...@@ -79,22 +79,6 @@ dependent subsystems such as cpufreq are left to the discretion of the SoC ...@@ -79,22 +79,6 @@ 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 specific framework which uses the OPP library. Similar care needs to be taken
care to refresh the cpufreq table in cases of these operations. care to refresh the cpufreq table in cases of these operations.
WARNING on OPP List locking mechanism:
-------------------------------------------------
OPP library uses RCU for exclusivity. RCU allows the query functions to operate
in multiple contexts and this synchronization mechanism is optimal for a read
intensive operations on data structure as the OPP library caters to.
To ensure that the data retrieved are sane, the users such as SoC framework
should ensure that the section of code operating on OPP queries are locked
using RCU read locks. The opp_find_freq_{exact,ceil,floor},
opp_get_{voltage, freq, opp_count} fall into this category.
opp_{add,enable,disable} are updaters which use mutex and implement it's own
RCU locking mechanisms. These functions should *NOT* be called under RCU locks
and other contexts that prevent blocking functions in RCU or mutex operations
from working.
2. Initial OPP List Registration 2. Initial OPP List Registration
================================ ================================
The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
...@@ -137,15 +121,18 @@ functions return the matching pointer representing the opp if a match is ...@@ -137,15 +121,18 @@ 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 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. 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 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 availability. This function is especially useful to enable an OPP which
is not available by default. is not available by default.
Example: In a case when SoC framework detects a situation where a Example: In a case when SoC framework detects a situation where a
higher frequency could be made available, it can use this function to 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. find the OPP prior to call the dev_pm_opp_enable to actually make it available.
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false); opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
rcu_read_unlock(); dev_pm_opp_put(opp);
/* dont operate on the pointer.. just do a sanity check.. */ /* dont operate on the pointer.. just do a sanity check.. */
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
pr_err("frequency not disabled!\n"); pr_err("frequency not disabled!\n");
...@@ -163,9 +150,8 @@ dev_pm_opp_find_freq_floor - Search for an available OPP which is *at most* the ...@@ -163,9 +150,8 @@ dev_pm_opp_find_freq_floor - Search for an available OPP which is *at most* the
frequency. frequency.
Example: To find the highest opp for a device: Example: To find the highest opp for a device:
freq = ULONG_MAX; freq = ULONG_MAX;
rcu_read_lock(); opp = dev_pm_opp_find_freq_floor(dev, &freq);
dev_pm_opp_find_freq_floor(dev, &freq); dev_pm_opp_put(opp);
rcu_read_unlock();
dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the 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 provided frequency. This function is useful while searching for a
...@@ -173,17 +159,15 @@ dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the ...@@ -173,17 +159,15 @@ dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the
frequency. frequency.
Example 1: To find the lowest opp for a device: Example 1: To find the lowest opp for a device:
freq = 0; freq = 0;
rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(dev, &freq);
dev_pm_opp_find_freq_ceil(dev, &freq); dev_pm_opp_put(opp);
rcu_read_unlock();
Example 2: A simplified implementation of a SoC cpufreq_driver->target: Example 2: A simplified implementation of a SoC cpufreq_driver->target:
soc_cpufreq_target(..) soc_cpufreq_target(..)
{ {
/* Do stuff like policy checks etc. */ /* Do stuff like policy checks etc. */
/* Find the best frequency match for the req */ /* Find the best frequency match for the req */
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(dev, &freq); opp = dev_pm_opp_find_freq_ceil(dev, &freq);
rcu_read_unlock(); dev_pm_opp_put(opp);
if (!IS_ERR(opp)) if (!IS_ERR(opp))
soc_switch_to_freq_voltage(freq); soc_switch_to_freq_voltage(freq);
else else
...@@ -208,9 +192,8 @@ dev_pm_opp_enable - Make a OPP available for operation. ...@@ -208,9 +192,8 @@ dev_pm_opp_enable - Make a OPP available for operation.
implementation might choose to do something as follows: implementation might choose to do something as follows:
if (cur_temp < temp_low_thresh) { if (cur_temp < temp_low_thresh) {
/* Enable 1GHz if it was disabled */ /* Enable 1GHz if it was disabled */
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false); opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
rcu_read_unlock(); dev_pm_opp_put(opp);
/* just error check */ /* just error check */
if (!IS_ERR(opp)) if (!IS_ERR(opp))
ret = dev_pm_opp_enable(dev, 1000000000); ret = dev_pm_opp_enable(dev, 1000000000);
...@@ -224,9 +207,8 @@ dev_pm_opp_disable - Make an OPP to be not available for operation ...@@ -224,9 +207,8 @@ dev_pm_opp_disable - Make an OPP to be not available for operation
choose to do something as follows: choose to do something as follows:
if (cur_temp > temp_high_thresh) { if (cur_temp > temp_high_thresh) {
/* Disable 1GHz if it was enabled */ /* Disable 1GHz if it was enabled */
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true); opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
rcu_read_unlock(); dev_pm_opp_put(opp);
/* just error check */ /* just error check */
if (!IS_ERR(opp)) if (!IS_ERR(opp))
ret = dev_pm_opp_disable(dev, 1000000000); ret = dev_pm_opp_disable(dev, 1000000000);
...@@ -249,10 +231,9 @@ dev_pm_opp_get_voltage - Retrieve the voltage represented by the opp pointer. ...@@ -249,10 +231,9 @@ dev_pm_opp_get_voltage - Retrieve the voltage represented by the opp pointer.
soc_switch_to_freq_voltage(freq) soc_switch_to_freq_voltage(freq)
{ {
/* do things */ /* do things */
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(dev, &freq); opp = dev_pm_opp_find_freq_ceil(dev, &freq);
v = dev_pm_opp_get_voltage(opp); v = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
if (v) if (v)
regulator_set_voltage(.., v); regulator_set_voltage(.., v);
/* do other things */ /* do other things */
...@@ -266,12 +247,12 @@ dev_pm_opp_get_freq - Retrieve the freq represented by the opp pointer. ...@@ -266,12 +247,12 @@ dev_pm_opp_get_freq - Retrieve the freq represented by the opp pointer.
{ {
/* do things.. */ /* do things.. */
max_freq = ULONG_MAX; max_freq = ULONG_MAX;
rcu_read_lock();
max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq); max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq); requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
if (!IS_ERR(max_opp) && !IS_ERR(requested_opp)) if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
r = soc_test_validity(max_opp, requested_opp); r = soc_test_validity(max_opp, requested_opp);
rcu_read_unlock(); dev_pm_opp_put(max_opp);
dev_pm_opp_put(requested_opp);
/* do other things */ /* do other things */
} }
soc_test_validity(..) soc_test_validity(..)
...@@ -289,7 +270,6 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device ...@@ -289,7 +270,6 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
soc_notify_coproc_available_frequencies() soc_notify_coproc_available_frequencies()
{ {
/* Do things */ /* Do things */
rcu_read_lock();
num_available = dev_pm_opp_get_opp_count(dev); num_available = dev_pm_opp_get_opp_count(dev);
speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL); speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
/* populate the table in increasing order */ /* populate the table in increasing order */
...@@ -298,8 +278,8 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device ...@@ -298,8 +278,8 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
speeds[i] = freq; speeds[i] = freq;
freq++; freq++;
i++; i++;
dev_pm_opp_put(opp);
} }
rcu_read_unlock();
soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available); soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
/* Do other things */ /* Do other things */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment