Commit 64f758a0 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-opp'

* pm-opp: (24 commits)
  PM / OPP: Expose _of_get_opp_desc_node as dev_pm_opp API
  PM / OPP: Make _find_opp_table_unlocked() static
  PM / OPP: Update Documentation to remove RCU specific bits
  PM / OPP: Simplify dev_pm_opp_get_max_volt_latency()
  PM / OPP: Simplify _opp_set_availability()
  PM / OPP: Move away from RCU locking
  PM / OPP: Take kref from _find_opp_table()
  PM / OPP: Update OPP users to put reference
  PM / OPP: Add 'struct kref' to struct dev_pm_opp
  PM / OPP: Use dev_pm_opp_get_opp_table() instead of _add_opp_table()
  PM / OPP: Take reference of the OPP table while adding/removing OPPs
  PM / OPP: Return opp_table from dev_pm_opp_set_*() routines
  PM / OPP: Add 'struct kref' to OPP table
  PM / OPP: Add per OPP table mutex
  PM / OPP: Split out part of _add_opp_table() and _remove_opp_table()
  PM / OPP: Don't expose srcu_head to register notifiers
  PM / OPP: Rename dev_pm_opp_get_suspend_opp() and return OPP rate
  PM / OPP: Don't allocate OPP table from _opp_allocate()
  PM / OPP: Rename and split _dev_pm_opp_remove_table()
  PM / OPP: Add light weight _opp_free() routine
  ...
parents 7089db84 0764c604
...@@ -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 */
......
...@@ -130,17 +130,16 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, ...@@ -130,17 +130,16 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
freq = clk_get_rate(clk); freq = clk_get_rate(clk);
clk_put(clk); clk_put(clk);
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(dev, &freq); opp = dev_pm_opp_find_freq_ceil(dev, &freq);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
pr_err("%s: unable to find boot up OPP for vdd_%s\n", pr_err("%s: unable to find boot up OPP for vdd_%s\n",
__func__, vdd_name); __func__, vdd_name);
goto exit; goto exit;
} }
bootup_volt = dev_pm_opp_get_voltage(opp); bootup_volt = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
if (!bootup_volt) { if (!bootup_volt) {
pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n", pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n",
__func__, vdd_name); __func__, vdd_name);
......
This diff is collapsed.
...@@ -42,11 +42,6 @@ ...@@ -42,11 +42,6 @@
* *
* WARNING: It is important for the callers to ensure refreshing their copy of * WARNING: It is important for the callers to ensure refreshing their copy of
* the table if any of the mentioned functions have been invoked in the interim. * the table if any of the mentioned functions have been invoked in the interim.
*
* Locking: The internal opp_table and opp structures are RCU protected.
* Since we just use the regular accessor functions to access the internal data
* structures, we use RCU read lock inside this function. As a result, users of
* this function DONOT need to use explicit locks for invoking.
*/ */
int dev_pm_opp_init_cpufreq_table(struct device *dev, int dev_pm_opp_init_cpufreq_table(struct device *dev,
struct cpufreq_frequency_table **table) struct cpufreq_frequency_table **table)
...@@ -56,19 +51,13 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, ...@@ -56,19 +51,13 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
int i, max_opps, ret = 0; int i, max_opps, ret = 0;
unsigned long rate; unsigned long rate;
rcu_read_lock();
max_opps = dev_pm_opp_get_opp_count(dev); max_opps = dev_pm_opp_get_opp_count(dev);
if (max_opps <= 0) { if (max_opps <= 0)
ret = max_opps ? max_opps : -ENODATA; return max_opps ? max_opps : -ENODATA;
goto out;
}
freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC); freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
if (!freq_table) { if (!freq_table)
ret = -ENOMEM; return -ENOMEM;
goto out;
}
for (i = 0, rate = 0; i < max_opps; i++, rate++) { for (i = 0, rate = 0; i < max_opps; i++, rate++) {
/* find next rate */ /* find next rate */
...@@ -83,6 +72,8 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, ...@@ -83,6 +72,8 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
/* Is Boost/turbo opp ? */ /* Is Boost/turbo opp ? */
if (dev_pm_opp_is_turbo(opp)) if (dev_pm_opp_is_turbo(opp))
freq_table[i].flags = CPUFREQ_BOOST_FREQ; freq_table[i].flags = CPUFREQ_BOOST_FREQ;
dev_pm_opp_put(opp);
} }
freq_table[i].driver_data = i; freq_table[i].driver_data = i;
...@@ -91,7 +82,6 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, ...@@ -91,7 +82,6 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
*table = &freq_table[0]; *table = &freq_table[0];
out: out:
rcu_read_unlock();
if (ret) if (ret)
kfree(freq_table); kfree(freq_table);
...@@ -147,12 +137,6 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of) ...@@ -147,12 +137,6 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of)
* This removes the OPP tables for CPUs present in the @cpumask. * This removes the OPP tables for CPUs present in the @cpumask.
* This should be used to remove all the OPPs entries associated with * This should be used to remove all the OPPs entries associated with
* the cpus in @cpumask. * the cpus in @cpumask.
*
* Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
*/ */
void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask) void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask)
{ {
...@@ -169,12 +153,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_cpumask_remove_table); ...@@ -169,12 +153,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_cpumask_remove_table);
* @cpumask. * @cpumask.
* *
* Returns -ENODEV if OPP table isn't already present. * Returns -ENODEV if OPP table isn't already present.
*
* Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
*/ */
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
const struct cpumask *cpumask) const struct cpumask *cpumask)
...@@ -184,13 +162,9 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, ...@@ -184,13 +162,9 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
struct device *dev; struct device *dev;
int cpu, ret = 0; int cpu, ret = 0;
mutex_lock(&opp_table_lock);
opp_table = _find_opp_table(cpu_dev); opp_table = _find_opp_table(cpu_dev);
if (IS_ERR(opp_table)) { if (IS_ERR(opp_table))
ret = PTR_ERR(opp_table); return PTR_ERR(opp_table);
goto unlock;
}
for_each_cpu(cpu, cpumask) { for_each_cpu(cpu, cpumask) {
if (cpu == cpu_dev->id) if (cpu == cpu_dev->id)
...@@ -213,8 +187,8 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, ...@@ -213,8 +187,8 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
/* Mark opp-table as multiple CPUs are sharing it now */ /* Mark opp-table as multiple CPUs are sharing it now */
opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
} }
unlock:
mutex_unlock(&opp_table_lock); dev_pm_opp_put_opp_table(opp_table);
return ret; return ret;
} }
...@@ -229,12 +203,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus); ...@@ -229,12 +203,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
* *
* Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP * Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP
* table's status is access-unknown. * table's status is access-unknown.
*
* Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
*/ */
int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
{ {
...@@ -242,17 +210,13 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) ...@@ -242,17 +210,13 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
struct opp_table *opp_table; struct opp_table *opp_table;
int ret = 0; int ret = 0;
mutex_lock(&opp_table_lock);
opp_table = _find_opp_table(cpu_dev); opp_table = _find_opp_table(cpu_dev);
if (IS_ERR(opp_table)) { if (IS_ERR(opp_table))
ret = PTR_ERR(opp_table); return PTR_ERR(opp_table);
goto unlock;
}
if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) { if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
ret = -EINVAL; ret = -EINVAL;
goto unlock; goto put_opp_table;
} }
cpumask_clear(cpumask); cpumask_clear(cpumask);
...@@ -264,8 +228,8 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) ...@@ -264,8 +228,8 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
cpumask_set_cpu(cpu_dev->id, cpumask); cpumask_set_cpu(cpu_dev->id, cpumask);
} }
unlock: put_opp_table:
mutex_unlock(&opp_table_lock); dev_pm_opp_put_opp_table(opp_table);
return ret; return ret;
} }
......
This diff is collapsed.
...@@ -16,11 +16,11 @@ ...@@ -16,11 +16,11 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/rculist.h> #include <linux/notifier.h>
#include <linux/rcupdate.h>
struct clk; struct clk;
struct regulator; struct regulator;
...@@ -51,11 +51,9 @@ extern struct list_head opp_tables; ...@@ -51,11 +51,9 @@ extern struct list_head opp_tables;
* @node: opp table node. The nodes are maintained throughout the lifetime * @node: opp table node. The nodes are maintained throughout the lifetime
* of boot. It is expected only an optimal set of OPPs are * of boot. It is expected only an optimal set of OPPs are
* added to the library by the SoC framework. * added to the library by the SoC framework.
* RCU usage: opp table is traversed with RCU locks. node
* modification is possible realtime, hence the modifications
* are protected by the opp_table_lock for integrity.
* IMPORTANT: the opp nodes should be maintained in increasing * IMPORTANT: the opp nodes should be maintained in increasing
* order. * order.
* @kref: for reference count of the OPP.
* @available: true/false - marks if this OPP as available or not * @available: true/false - marks if this OPP as available or not
* @dynamic: not-created from static DT entries. * @dynamic: not-created from static DT entries.
* @turbo: true if turbo (boost) OPP * @turbo: true if turbo (boost) OPP
...@@ -65,7 +63,6 @@ extern struct list_head opp_tables; ...@@ -65,7 +63,6 @@ extern struct list_head opp_tables;
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
* frequency from any other OPP's frequency. * frequency from any other OPP's frequency.
* @opp_table: points back to the opp_table struct this opp belongs to * @opp_table: points back to the opp_table struct this opp belongs to
* @rcu_head: RCU callback head used for deferred freeing
* @np: OPP's device node. * @np: OPP's device node.
* @dentry: debugfs dentry pointer (per opp) * @dentry: debugfs dentry pointer (per opp)
* *
...@@ -73,6 +70,7 @@ extern struct list_head opp_tables; ...@@ -73,6 +70,7 @@ extern struct list_head opp_tables;
*/ */
struct dev_pm_opp { struct dev_pm_opp {
struct list_head node; struct list_head node;
struct kref kref;
bool available; bool available;
bool dynamic; bool dynamic;
...@@ -85,7 +83,6 @@ struct dev_pm_opp { ...@@ -85,7 +83,6 @@ struct dev_pm_opp {
unsigned long clock_latency_ns; unsigned long clock_latency_ns;
struct opp_table *opp_table; struct opp_table *opp_table;
struct rcu_head rcu_head;
struct device_node *np; struct device_node *np;
...@@ -98,7 +95,6 @@ struct dev_pm_opp { ...@@ -98,7 +95,6 @@ struct dev_pm_opp {
* struct opp_device - devices managed by 'struct opp_table' * struct opp_device - devices managed by 'struct opp_table'
* @node: list node * @node: list node
* @dev: device to which the struct object belongs * @dev: device to which the struct object belongs
* @rcu_head: RCU callback head used for deferred freeing
* @dentry: debugfs dentry pointer (per device) * @dentry: debugfs dentry pointer (per device)
* *
* This is an internal data structure maintaining the devices that are managed * This is an internal data structure maintaining the devices that are managed
...@@ -107,7 +103,6 @@ struct dev_pm_opp { ...@@ -107,7 +103,6 @@ struct dev_pm_opp {
struct opp_device { struct opp_device {
struct list_head node; struct list_head node;
const struct device *dev; const struct device *dev;
struct rcu_head rcu_head;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *dentry; struct dentry *dentry;
...@@ -125,12 +120,11 @@ enum opp_table_access { ...@@ -125,12 +120,11 @@ enum opp_table_access {
* @node: table node - contains the devices with OPPs that * @node: table node - contains the devices with OPPs that
* have been registered. Nodes once added are not modified in this * have been registered. Nodes once added are not modified in this
* table. * table.
* RCU usage: nodes are not modified in the table of opp_table, * @head: notifier head to notify the OPP availability changes.
* however addition is possible and is secured by opp_table_lock
* @srcu_head: notifier head to notify the OPP availability changes.
* @rcu_head: RCU callback head used for deferred freeing
* @dev_list: list of devices that share these OPPs * @dev_list: list of devices that share these OPPs
* @opp_list: table of opps * @opp_list: table of opps
* @kref: for reference count of the table.
* @lock: mutex protecting the opp_list.
* @np: struct device_node pointer for opp's DT node. * @np: struct device_node pointer for opp's DT node.
* @clock_latency_ns_max: Max clock latency in nanoseconds. * @clock_latency_ns_max: Max clock latency in nanoseconds.
* @shared_opp: OPP is shared between multiple devices. * @shared_opp: OPP is shared between multiple devices.
...@@ -151,18 +145,15 @@ enum opp_table_access { ...@@ -151,18 +145,15 @@ enum opp_table_access {
* This is an internal data structure maintaining the link to opps attached to * This is an internal data structure maintaining the link to opps attached to
* a device. This structure is not meant to be shared to users as it is * a device. This structure is not meant to be shared to users as it is
* meant for book keeping and private to OPP library. * meant for book keeping and private to OPP library.
*
* Because the opp structures can be used from both rcu and srcu readers, we
* need to wait for the grace period of both of them before freeing any
* resources. And so we have used kfree_rcu() from within call_srcu() handlers.
*/ */
struct opp_table { struct opp_table {
struct list_head node; struct list_head node;
struct srcu_notifier_head srcu_head; struct blocking_notifier_head head;
struct rcu_head rcu_head;
struct list_head dev_list; struct list_head dev_list;
struct list_head opp_list; struct list_head opp_list;
struct kref kref;
struct mutex lock;
struct device_node *np; struct device_node *np;
unsigned long clock_latency_ns_max; unsigned long clock_latency_ns_max;
...@@ -190,14 +181,17 @@ struct opp_table { ...@@ -190,14 +181,17 @@ struct opp_table {
}; };
/* Routines internal to opp core */ /* Routines internal to opp core */
void _get_opp_table_kref(struct opp_table *opp_table);
struct opp_table *_find_opp_table(struct device *dev); struct opp_table *_find_opp_table(struct device *dev);
struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
void _dev_pm_opp_remove_table(struct device *dev, bool remove_all); void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all);
struct dev_pm_opp *_allocate_opp(struct device *dev, struct opp_table **opp_table); void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all);
struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
void _opp_free(struct dev_pm_opp *opp);
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp, bool notify); int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt, bool dynamic);
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of); void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of);
struct opp_table *_add_opp_table(struct device *dev);
#ifdef CONFIG_OF #ifdef CONFIG_OF
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev); void _of_init_opp_table(struct opp_table *opp_table, struct device *dev);
......
...@@ -633,16 +633,12 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate) ...@@ -633,16 +633,12 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
int i, uv; int i, uv;
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);
if (IS_ERR(opp)) { if (IS_ERR(opp))
rcu_read_unlock();
return PTR_ERR(opp); return PTR_ERR(opp);
}
uv = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); uv = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
for (i = 0; i < td->i2c_lut_size; i++) { for (i = 0; i < td->i2c_lut_size; i++) {
if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv) if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv)
...@@ -1440,8 +1436,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) ...@@ -1440,8 +1436,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
int lut; int lut;
rcu_read_lock();
rate = ULONG_MAX; rate = ULONG_MAX;
opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate); opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
...@@ -1449,6 +1443,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) ...@@ -1449,6 +1443,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
goto out; goto out;
} }
v_max = dev_pm_opp_get_voltage(opp); v_max = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
v = td->soc->cvb->min_millivolts * 1000; v = td->soc->cvb->min_millivolts * 1000;
lut = find_vdd_map_entry_exact(td, v); lut = find_vdd_map_entry_exact(td, v);
...@@ -1465,6 +1460,8 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) ...@@ -1465,6 +1460,8 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
if (v_opp <= td->soc->cvb->min_millivolts * 1000) if (v_opp <= td->soc->cvb->min_millivolts * 1000)
td->dvco_rate_min = dev_pm_opp_get_freq(opp); td->dvco_rate_min = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
for (;;) { for (;;) {
v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j)); v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j));
if (v >= v_opp) if (v >= v_opp)
...@@ -1496,8 +1493,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) ...@@ -1496,8 +1493,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
ret = 0; ret = 0;
out: out:
rcu_read_unlock();
return ret; return ret;
} }
......
...@@ -148,7 +148,6 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -148,7 +148,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
struct private_data *priv; struct private_data *priv;
struct device *cpu_dev; struct device *cpu_dev;
struct clk *cpu_clk; struct clk *cpu_clk;
struct dev_pm_opp *suspend_opp;
unsigned int transition_latency; unsigned int transition_latency;
bool fallback = false; bool fallback = false;
const char *name; const char *name;
...@@ -252,11 +251,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -252,11 +251,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
policy->driver_data = priv; policy->driver_data = priv;
policy->clk = cpu_clk; policy->clk = cpu_clk;
rcu_read_lock(); policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;
suspend_opp = dev_pm_opp_get_suspend_opp(cpu_dev);
if (suspend_opp)
policy->suspend_freq = dev_pm_opp_get_freq(suspend_opp) / 1000;
rcu_read_unlock();
ret = cpufreq_table_validate_and_show(policy, freq_table); ret = cpufreq_table_validate_and_show(policy, freq_table);
if (ret) { if (ret) {
......
...@@ -118,12 +118,10 @@ static int init_div_table(void) ...@@ -118,12 +118,10 @@ static int init_div_table(void)
unsigned int tmp, clk_div, ema_div, freq, volt_id; unsigned int tmp, clk_div, ema_div, freq, volt_id;
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
rcu_read_lock();
cpufreq_for_each_entry(pos, freq_tbl) { cpufreq_for_each_entry(pos, freq_tbl) {
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
pos->frequency * 1000, true); pos->frequency * 1000, true);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(dvfs_info->dev, dev_err(dvfs_info->dev,
"failed to find valid OPP for %u KHZ\n", "failed to find valid OPP for %u KHZ\n",
pos->frequency); pos->frequency);
...@@ -140,6 +138,7 @@ static int init_div_table(void) ...@@ -140,6 +138,7 @@ static int init_div_table(void)
/* Calculate EMA */ /* Calculate EMA */
volt_id = dev_pm_opp_get_voltage(opp); volt_id = dev_pm_opp_get_voltage(opp);
volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP; volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP;
if (volt_id < PMIC_HIGH_VOLT) { if (volt_id < PMIC_HIGH_VOLT) {
ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) | ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) |
...@@ -157,9 +156,9 @@ static int init_div_table(void) ...@@ -157,9 +156,9 @@ static int init_div_table(void)
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
(pos - freq_tbl)); (pos - freq_tbl));
dev_pm_opp_put(opp);
} }
rcu_read_unlock();
return 0; return 0;
} }
......
...@@ -53,16 +53,15 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -53,16 +53,15 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
freq_hz = new_freq * 1000; freq_hz = new_freq * 1000;
old_freq = clk_get_rate(arm_clk) / 1000; old_freq = clk_get_rate(arm_clk) / 1000;
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
return PTR_ERR(opp); return PTR_ERR(opp);
} }
volt = dev_pm_opp_get_voltage(opp); volt = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
volt_old = regulator_get_voltage(arm_reg); volt_old = regulator_get_voltage(arm_reg);
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
...@@ -321,14 +320,15 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) ...@@ -321,14 +320,15 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
* freq_table initialised from OPP is therefore sorted in the * freq_table initialised from OPP is therefore sorted in the
* same order. * same order.
*/ */
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(cpu_dev, opp = dev_pm_opp_find_freq_exact(cpu_dev,
freq_table[0].frequency * 1000, true); freq_table[0].frequency * 1000, true);
min_volt = dev_pm_opp_get_voltage(opp); min_volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
opp = dev_pm_opp_find_freq_exact(cpu_dev, opp = dev_pm_opp_find_freq_exact(cpu_dev,
freq_table[--num].frequency * 1000, true); freq_table[--num].frequency * 1000, true);
max_volt = dev_pm_opp_get_voltage(opp); max_volt = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt); ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
if (ret > 0) if (ret > 0)
transition_latency += ret * 1000; transition_latency += ret * 1000;
......
...@@ -232,16 +232,14 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -232,16 +232,14 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
freq_hz = freq_table[index].frequency * 1000; freq_hz = freq_table[index].frequency * 1000;
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
pr_err("cpu%d: failed to find OPP for %ld\n", pr_err("cpu%d: failed to find OPP for %ld\n",
policy->cpu, freq_hz); policy->cpu, freq_hz);
return PTR_ERR(opp); return PTR_ERR(opp);
} }
vproc = dev_pm_opp_get_voltage(opp); vproc = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
/* /*
* If the new voltage or the intermediate voltage is higher than the * If the new voltage or the intermediate voltage is higher than the
...@@ -411,16 +409,14 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) ...@@ -411,16 +409,14 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
/* Search a safe voltage for intermediate frequency. */ /* Search a safe voltage for intermediate frequency. */
rate = clk_get_rate(inter_clk); rate = clk_get_rate(inter_clk);
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
pr_err("failed to get intermediate opp for cpu%d\n", cpu); pr_err("failed to get intermediate opp for cpu%d\n", cpu);
ret = PTR_ERR(opp); ret = PTR_ERR(opp);
goto out_free_opp_table; goto out_free_opp_table;
} }
info->intermediate_voltage = dev_pm_opp_get_voltage(opp); info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
info->cpu_dev = cpu_dev; info->cpu_dev = cpu_dev;
info->proc_reg = proc_reg; info->proc_reg = proc_reg;
......
...@@ -63,16 +63,14 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -63,16 +63,14 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
freq = ret; freq = ret;
if (mpu_reg) { if (mpu_reg) {
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq); opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
__func__, new_freq); __func__, new_freq);
return -EINVAL; return -EINVAL;
} }
volt = dev_pm_opp_get_voltage(opp); volt = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
tol = volt * OPP_TOLERANCE / 100; tol = volt * OPP_TOLERANCE / 100;
volt_old = regulator_get_voltage(mpu_reg); volt_old = regulator_get_voltage(mpu_reg);
} }
......
...@@ -160,6 +160,7 @@ static int sti_cpufreq_set_opp_info(void) ...@@ -160,6 +160,7 @@ static int sti_cpufreq_set_opp_info(void)
int pcode, substrate, major, minor; int pcode, substrate, major, minor;
int ret; int ret;
char name[MAX_PCODE_NAME_LEN]; char name[MAX_PCODE_NAME_LEN];
struct opp_table *opp_table;
reg_fields = sti_cpufreq_match(); reg_fields = sti_cpufreq_match();
if (!reg_fields) { if (!reg_fields) {
...@@ -211,20 +212,20 @@ static int sti_cpufreq_set_opp_info(void) ...@@ -211,20 +212,20 @@ static int sti_cpufreq_set_opp_info(void)
snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode); snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode);
ret = dev_pm_opp_set_prop_name(dev, name); opp_table = dev_pm_opp_set_prop_name(dev, name);
if (ret) { if (IS_ERR(opp_table)) {
dev_err(dev, "Failed to set prop name\n"); dev_err(dev, "Failed to set prop name\n");
return ret; return PTR_ERR(opp_table);
} }
version[0] = BIT(major); version[0] = BIT(major);
version[1] = BIT(minor); version[1] = BIT(minor);
version[2] = BIT(substrate); version[2] = BIT(substrate);
ret = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS); opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
if (ret) { if (IS_ERR(opp_table)) {
dev_err(dev, "Failed to set supported hardware\n"); dev_err(dev, "Failed to set supported hardware\n");
return ret; return PTR_ERR(opp_table);
} }
dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n", dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
......
...@@ -111,18 +111,16 @@ static void devfreq_set_freq_table(struct devfreq *devfreq) ...@@ -111,18 +111,16 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
return; return;
} }
rcu_read_lock();
for (i = 0, freq = 0; i < profile->max_state; i++, freq++) { for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq); opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
devm_kfree(devfreq->dev.parent, profile->freq_table); devm_kfree(devfreq->dev.parent, profile->freq_table);
profile->max_state = 0; profile->max_state = 0;
rcu_read_unlock();
return; return;
} }
dev_pm_opp_put(opp);
profile->freq_table[i] = freq; profile->freq_table[i] = freq;
} }
rcu_read_unlock();
} }
/** /**
...@@ -1112,17 +1110,16 @@ static ssize_t available_frequencies_show(struct device *d, ...@@ -1112,17 +1110,16 @@ static ssize_t available_frequencies_show(struct device *d,
ssize_t count = 0; ssize_t count = 0;
unsigned long freq = 0; unsigned long freq = 0;
rcu_read_lock();
do { do {
opp = dev_pm_opp_find_freq_ceil(dev, &freq); opp = dev_pm_opp_find_freq_ceil(dev, &freq);
if (IS_ERR(opp)) if (IS_ERR(opp))
break; break;
dev_pm_opp_put(opp);
count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
"%lu ", freq); "%lu ", freq);
freq++; freq++;
} while (1); } while (1);
rcu_read_unlock();
/* Truncate the trailing space */ /* Truncate the trailing space */
if (count) if (count)
...@@ -1224,11 +1221,8 @@ subsys_initcall(devfreq_init); ...@@ -1224,11 +1221,8 @@ subsys_initcall(devfreq_init);
* @freq: The frequency given to target function * @freq: The frequency given to target function
* @flags: Flags handed from devfreq framework. * @flags: Flags handed from devfreq framework.
* *
* Locking: This function must be called under rcu_read_lock(). opp is a rcu * The callers are required to call dev_pm_opp_put() for the returned OPP after
* protected pointer. The reason for the same is that the opp pointer which is * use.
* returned will remain valid for use with opp_get_{voltage, freq} only while
* under the locked area. The pointer returned must be used prior to unlocking
* with rcu_read_unlock() to maintain the integrity of the pointer.
*/ */
struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
unsigned long *freq, unsigned long *freq,
...@@ -1265,18 +1259,7 @@ EXPORT_SYMBOL(devfreq_recommended_opp); ...@@ -1265,18 +1259,7 @@ EXPORT_SYMBOL(devfreq_recommended_opp);
*/ */
int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
{ {
struct srcu_notifier_head *nh; return dev_pm_opp_register_notifier(dev, &devfreq->nb);
int ret = 0;
rcu_read_lock();
nh = dev_pm_opp_get_notifier(dev);
if (IS_ERR(nh))
ret = PTR_ERR(nh);
rcu_read_unlock();
if (!ret)
ret = srcu_notifier_chain_register(nh, &devfreq->nb);
return ret;
} }
EXPORT_SYMBOL(devfreq_register_opp_notifier); EXPORT_SYMBOL(devfreq_register_opp_notifier);
...@@ -1292,18 +1275,7 @@ EXPORT_SYMBOL(devfreq_register_opp_notifier); ...@@ -1292,18 +1275,7 @@ EXPORT_SYMBOL(devfreq_register_opp_notifier);
*/ */
int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq) int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
{ {
struct srcu_notifier_head *nh; return dev_pm_opp_unregister_notifier(dev, &devfreq->nb);
int ret = 0;
rcu_read_lock();
nh = dev_pm_opp_get_notifier(dev);
if (IS_ERR(nh))
ret = PTR_ERR(nh);
rcu_read_unlock();
if (!ret)
ret = srcu_notifier_chain_unregister(nh, &devfreq->nb);
return ret;
} }
EXPORT_SYMBOL(devfreq_unregister_opp_notifier); EXPORT_SYMBOL(devfreq_unregister_opp_notifier);
......
...@@ -103,18 +103,17 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags) ...@@ -103,18 +103,17 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
int ret = 0; int ret = 0;
/* Get new opp-bus instance according to new bus clock */ /* Get new opp-bus instance according to new bus clock */
rcu_read_lock();
new_opp = devfreq_recommended_opp(dev, freq, flags); new_opp = devfreq_recommended_opp(dev, freq, flags);
if (IS_ERR(new_opp)) { if (IS_ERR(new_opp)) {
dev_err(dev, "failed to get recommended opp instance\n"); dev_err(dev, "failed to get recommended opp instance\n");
rcu_read_unlock();
return PTR_ERR(new_opp); return PTR_ERR(new_opp);
} }
new_freq = dev_pm_opp_get_freq(new_opp); new_freq = dev_pm_opp_get_freq(new_opp);
new_volt = dev_pm_opp_get_voltage(new_opp); new_volt = dev_pm_opp_get_voltage(new_opp);
dev_pm_opp_put(new_opp);
old_freq = bus->curr_freq; old_freq = bus->curr_freq;
rcu_read_unlock();
if (old_freq == new_freq) if (old_freq == new_freq)
return 0; return 0;
...@@ -214,17 +213,16 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq, ...@@ -214,17 +213,16 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
int ret = 0; int ret = 0;
/* Get new opp-bus instance according to new bus clock */ /* Get new opp-bus instance according to new bus clock */
rcu_read_lock();
new_opp = devfreq_recommended_opp(dev, freq, flags); new_opp = devfreq_recommended_opp(dev, freq, flags);
if (IS_ERR(new_opp)) { if (IS_ERR(new_opp)) {
dev_err(dev, "failed to get recommended opp instance\n"); dev_err(dev, "failed to get recommended opp instance\n");
rcu_read_unlock();
return PTR_ERR(new_opp); return PTR_ERR(new_opp);
} }
new_freq = dev_pm_opp_get_freq(new_opp); new_freq = dev_pm_opp_get_freq(new_opp);
dev_pm_opp_put(new_opp);
old_freq = bus->curr_freq; old_freq = bus->curr_freq;
rcu_read_unlock();
if (old_freq == new_freq) if (old_freq == new_freq)
return 0; return 0;
...@@ -358,16 +356,14 @@ static int exynos_bus_parse_of(struct device_node *np, ...@@ -358,16 +356,14 @@ static int exynos_bus_parse_of(struct device_node *np,
rate = clk_get_rate(bus->clk); rate = clk_get_rate(bus->clk);
rcu_read_lock();
opp = devfreq_recommended_opp(dev, &rate, 0); opp = devfreq_recommended_opp(dev, &rate, 0);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
dev_err(dev, "failed to find dev_pm_opp\n"); dev_err(dev, "failed to find dev_pm_opp\n");
rcu_read_unlock();
ret = PTR_ERR(opp); ret = PTR_ERR(opp);
goto err_opp; goto err_opp;
} }
bus->curr_freq = dev_pm_opp_get_freq(opp); bus->curr_freq = dev_pm_opp_get_freq(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
return 0; return 0;
......
...@@ -59,14 +59,14 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq, ...@@ -59,14 +59,14 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
* list of parent device. Because in this case, *freq is temporary * list of parent device. Because in this case, *freq is temporary
* value which is decided by ondemand governor. * value which is decided by ondemand governor.
*/ */
rcu_read_lock();
opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0); opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0);
rcu_read_unlock();
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
ret = PTR_ERR(opp); ret = PTR_ERR(opp);
goto out; goto out;
} }
dev_pm_opp_put(opp);
/* /*
* Get the OPP table's index of decided freqeuncy by governor * Get the OPP table's index of decided freqeuncy by governor
* of parent device. * of parent device.
......
...@@ -91,17 +91,13 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq, ...@@ -91,17 +91,13 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
unsigned long target_volt, target_rate; unsigned long target_volt, target_rate;
int err; int err;
rcu_read_lock();
opp = devfreq_recommended_opp(dev, freq, flags); opp = devfreq_recommended_opp(dev, freq, flags);
if (IS_ERR(opp)) { if (IS_ERR(opp))
rcu_read_unlock();
return PTR_ERR(opp); return PTR_ERR(opp);
}
target_rate = dev_pm_opp_get_freq(opp); target_rate = dev_pm_opp_get_freq(opp);
target_volt = dev_pm_opp_get_voltage(opp); target_volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
rcu_read_unlock();
if (dmcfreq->rate == target_rate) if (dmcfreq->rate == target_rate)
return 0; return 0;
...@@ -422,15 +418,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) ...@@ -422,15 +418,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
data->rate = clk_get_rate(data->dmc_clk); data->rate = clk_get_rate(data->dmc_clk);
rcu_read_lock();
opp = devfreq_recommended_opp(dev, &data->rate, 0); opp = devfreq_recommended_opp(dev, &data->rate, 0);
if (IS_ERR(opp)) { if (IS_ERR(opp))
rcu_read_unlock();
return PTR_ERR(opp); return PTR_ERR(opp);
}
data->rate = dev_pm_opp_get_freq(opp); data->rate = dev_pm_opp_get_freq(opp);
data->volt = dev_pm_opp_get_voltage(opp); data->volt = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
rk3399_devfreq_dmc_profile.initial_freq = data->rate; rk3399_devfreq_dmc_profile.initial_freq = data->rate;
......
...@@ -487,15 +487,13 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq, ...@@ -487,15 +487,13 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
unsigned long rate = *freq * KHZ; unsigned long rate = *freq * KHZ;
rcu_read_lock();
opp = devfreq_recommended_opp(dev, &rate, flags); opp = devfreq_recommended_opp(dev, &rate, flags);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(dev, "Failed to find opp for %lu KHz\n", *freq); dev_err(dev, "Failed to find opp for %lu KHz\n", *freq);
return PTR_ERR(opp); return PTR_ERR(opp);
} }
rate = dev_pm_opp_get_freq(opp); rate = dev_pm_opp_get_freq(opp);
rcu_read_unlock(); dev_pm_opp_put(opp);
clk_set_min_rate(tegra->emc_clock, rate); clk_set_min_rate(tegra->emc_clock, rate);
clk_set_rate(tegra->emc_clock, 0); clk_set_rate(tegra->emc_clock, 0);
......
...@@ -297,8 +297,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, ...@@ -297,8 +297,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
if (!power_table) if (!power_table)
return -ENOMEM; return -ENOMEM;
rcu_read_lock();
for (freq = 0, i = 0; for (freq = 0, i = 0;
opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp); opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
freq++, i++) { freq++, i++) {
...@@ -306,13 +304,13 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, ...@@ -306,13 +304,13 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
u64 power; u64 power;
if (i >= num_opps) { if (i >= num_opps) {
rcu_read_unlock();
ret = -EAGAIN; ret = -EAGAIN;
goto free_power_table; goto free_power_table;
} }
freq_mhz = freq / 1000000; freq_mhz = freq / 1000000;
voltage_mv = dev_pm_opp_get_voltage(opp) / 1000; voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
dev_pm_opp_put(opp);
/* /*
* Do the multiplication with MHz and millivolt so as * Do the multiplication with MHz and millivolt so as
...@@ -328,8 +326,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, ...@@ -328,8 +326,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
power_table[i].power = power; power_table[i].power = power;
} }
rcu_read_unlock();
if (i != num_opps) { if (i != num_opps) {
ret = PTR_ERR(opp); ret = PTR_ERR(opp);
goto free_power_table; goto free_power_table;
...@@ -433,13 +429,10 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device, ...@@ -433,13 +429,10 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
return 0; return 0;
} }
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz, opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,
true); true);
voltage = dev_pm_opp_get_voltage(opp); voltage = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
rcu_read_unlock();
if (voltage == 0) { if (voltage == 0) {
dev_warn_ratelimited(cpufreq_device->cpu_dev, dev_warn_ratelimited(cpufreq_device->cpu_dev,
......
...@@ -113,15 +113,15 @@ static int partition_enable_opps(struct devfreq_cooling_device *dfc, ...@@ -113,15 +113,15 @@ static int partition_enable_opps(struct devfreq_cooling_device *dfc,
unsigned int freq = dfc->freq_table[i]; unsigned int freq = dfc->freq_table[i];
bool want_enable = i >= cdev_state ? true : false; bool want_enable = i >= cdev_state ? true : false;
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable); opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
rcu_read_unlock();
if (PTR_ERR(opp) == -ERANGE) if (PTR_ERR(opp) == -ERANGE)
continue; continue;
else if (IS_ERR(opp)) else if (IS_ERR(opp))
return PTR_ERR(opp); return PTR_ERR(opp);
dev_pm_opp_put(opp);
if (want_enable) if (want_enable)
ret = dev_pm_opp_enable(dev, freq); ret = dev_pm_opp_enable(dev, freq);
else else
...@@ -221,15 +221,12 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) ...@@ -221,15 +221,12 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
if (!dfc->power_ops->get_static_power) if (!dfc->power_ops->get_static_power)
return 0; return 0;
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(dev, freq, true); opp = dev_pm_opp_find_freq_exact(dev, freq, true);
if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE)) if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE))
opp = dev_pm_opp_find_freq_exact(dev, freq, false); opp = dev_pm_opp_find_freq_exact(dev, freq, false);
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
dev_pm_opp_put(opp);
rcu_read_unlock();
if (voltage == 0) { if (voltage == 0) {
dev_warn_ratelimited(dev, dev_warn_ratelimited(dev,
...@@ -412,18 +409,14 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) ...@@ -412,18 +409,14 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc)
unsigned long power_dyn, voltage; unsigned long power_dyn, voltage;
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
rcu_read_lock();
opp = dev_pm_opp_find_freq_floor(dev, &freq); opp = dev_pm_opp_find_freq_floor(dev, &freq);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock();
ret = PTR_ERR(opp); ret = PTR_ERR(opp);
goto free_tables; goto free_tables;
} }
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
dev_pm_opp_put(opp);
rcu_read_unlock();
if (dfc->power_ops) { if (dfc->power_ops) {
power_dyn = get_dynamic_power(dfc, freq, voltage); power_dyn = get_dynamic_power(dfc, freq, voltage);
......
...@@ -78,6 +78,9 @@ struct dev_pm_set_opp_data { ...@@ -78,6 +78,9 @@ struct dev_pm_set_opp_data {
#if defined(CONFIG_PM_OPP) #if defined(CONFIG_PM_OPP)
struct opp_table *dev_pm_opp_get_opp_table(struct device *dev);
void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp); unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
...@@ -88,7 +91,7 @@ int dev_pm_opp_get_opp_count(struct device *dev); ...@@ -88,7 +91,7 @@ int dev_pm_opp_get_opp_count(struct device *dev);
unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev); unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev);
unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev); unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev);
unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev); unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev);
struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev); unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev);
struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
unsigned long freq, unsigned long freq,
...@@ -99,6 +102,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, ...@@ -99,6 +102,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
unsigned long *freq); unsigned long *freq);
void dev_pm_opp_put(struct dev_pm_opp *opp);
int dev_pm_opp_add(struct device *dev, unsigned long freq, int dev_pm_opp_add(struct device *dev, unsigned long freq,
unsigned long u_volt); unsigned long u_volt);
...@@ -108,22 +112,30 @@ int dev_pm_opp_enable(struct device *dev, unsigned long freq); ...@@ -108,22 +112,30 @@ int dev_pm_opp_enable(struct device *dev, unsigned long freq);
int dev_pm_opp_disable(struct device *dev, unsigned long freq); int dev_pm_opp_disable(struct device *dev, unsigned long freq);
struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev); int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb);
int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb);
unsigned int count);
void dev_pm_opp_put_supported_hw(struct device *dev); struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
int dev_pm_opp_set_prop_name(struct device *dev, const char *name); void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
void dev_pm_opp_put_prop_name(struct device *dev); struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name);
void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count); struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
void dev_pm_opp_put_regulators(struct opp_table *opp_table); void dev_pm_opp_put_regulators(struct opp_table *opp_table);
int dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
void dev_pm_opp_register_put_opp_helper(struct device *dev); void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table);
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask); int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
void dev_pm_opp_remove_table(struct device *dev); void dev_pm_opp_remove_table(struct device *dev);
void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask); void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask);
#else #else
static inline struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
{
return ERR_PTR(-ENOTSUPP);
}
static inline void dev_pm_opp_put_opp_table(struct opp_table *opp_table) {}
static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
{ {
return 0; return 0;
...@@ -159,9 +171,9 @@ static inline unsigned long dev_pm_opp_get_max_transition_latency(struct device ...@@ -159,9 +171,9 @@ static inline unsigned long dev_pm_opp_get_max_transition_latency(struct device
return 0; return 0;
} }
static inline struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev) static inline unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
{ {
return NULL; return 0;
} }
static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
...@@ -182,6 +194,8 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, ...@@ -182,6 +194,8 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-ENOTSUPP);
} }
static inline void dev_pm_opp_put(struct dev_pm_opp *opp) {}
static inline int dev_pm_opp_add(struct device *dev, unsigned long freq, static inline int dev_pm_opp_add(struct device *dev, unsigned long freq,
unsigned long u_volt) unsigned long u_volt)
{ {
...@@ -202,35 +216,39 @@ static inline int dev_pm_opp_disable(struct device *dev, unsigned long freq) ...@@ -202,35 +216,39 @@ static inline int dev_pm_opp_disable(struct device *dev, unsigned long freq)
return 0; return 0;
} }
static inline struct srcu_notifier_head *dev_pm_opp_get_notifier( static inline int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
struct device *dev)
{ {
return ERR_PTR(-ENOTSUPP); return -ENOTSUPP;
}
static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb)
{
return -ENOTSUPP;
} }
static inline int dev_pm_opp_set_supported_hw(struct device *dev, static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
const u32 *versions, const u32 *versions,
unsigned int count) unsigned int count)
{ {
return -ENOTSUPP; return ERR_PTR(-ENOTSUPP);
} }
static inline void dev_pm_opp_put_supported_hw(struct device *dev) {} static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
static inline int dev_pm_opp_register_set_opp_helper(struct device *dev, static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
int (*set_opp)(struct dev_pm_set_opp_data *data)) int (*set_opp)(struct dev_pm_set_opp_data *data))
{ {
return -ENOTSUPP; return ERR_PTR(-ENOTSUPP);
} }
static inline void dev_pm_opp_register_put_opp_helper(struct device *dev) {} static inline void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table) {}
static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name) static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
{ {
return -ENOTSUPP; return ERR_PTR(-ENOTSUPP);
} }
static inline void dev_pm_opp_put_prop_name(struct device *dev) {} static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {}
static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count) static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
{ {
...@@ -270,6 +288,7 @@ void dev_pm_opp_of_remove_table(struct device *dev); ...@@ -270,6 +288,7 @@ void dev_pm_opp_of_remove_table(struct device *dev);
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask); int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask); void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask);
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev);
#else #else
static inline int dev_pm_opp_of_add_table(struct device *dev) static inline int dev_pm_opp_of_add_table(struct device *dev)
{ {
...@@ -293,6 +312,11 @@ static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct ...@@ -293,6 +312,11 @@ static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
{
return NULL;
}
#endif #endif
#endif /* __LINUX_OPP_H__ */ #endif /* __LINUX_OPP_H__ */
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