]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'pm-opp'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sat, 7 Nov 2015 00:30:40 +0000 (01:30 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sat, 7 Nov 2015 00:30:40 +0000 (01:30 +0100)
* pm-opp:
  PM / OPP: Add opp_rcu_lockdep_assert() to _find_device_opp()
  PM / OPP: Hold dev_opp_list_lock for writers
  PM / OPP: Protect updates to list_dev with mutex
  PM / OPP: Propagate error properly from dev_pm_opp_set_sharing_cpus()
  PM / OPP: Parse all power-supply related bindings together
  PM / OPP: Rename routines specific to old bindings with _v1
  PM / OPP: Improve print messages with pr_fmt

drivers/base/power/opp/core.c
drivers/base/power/opp/cpu.c
drivers/base/power/opp/opp.h

index d5c1149ff123c335b58e1f8ee68ed97a66784fec..5e4b1d82b2f80c4c48b4162d936cf4b655e405a1 100644 (file)
@@ -11,6 +11,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/slab.h>
@@ -27,7 +29,7 @@
  */
 static LIST_HEAD(dev_opp_list);
 /* Lock to allow exclusive modification to the device and opp lists */
-static DEFINE_MUTEX(dev_opp_list_lock);
+DEFINE_MUTEX(dev_opp_list_lock);
 
 #define opp_rcu_lockdep_assert()                                       \
 do {                                                                   \
@@ -79,14 +81,18 @@ static struct device_opp *_managed_opp(const struct device_node *np)
  * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or
  * -EINVAL based on type of error.
  *
- * Locking: This function must be called under rcu_read_lock(). device_opp
- * is a RCU protected pointer. This means that device_opp is valid as long
- * as we are under RCU lock.
+ * Locking: For readers, this function must be called under rcu_read_lock().
+ * device_opp is a RCU protected pointer, which means that device_opp is valid
+ * as long as we are under RCU lock.
+ *
+ * For Writers, this function must be called with dev_opp_list_lock held.
  */
 struct device_opp *_find_device_opp(struct device *dev)
 {
        struct device_opp *dev_opp;
 
+       opp_rcu_lockdep_assert();
+
        if (IS_ERR_OR_NULL(dev)) {
                pr_err("%s: Invalid parameters\n", __func__);
                return ERR_PTR(-EINVAL);
@@ -701,7 +707,7 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
 }
 
 /**
- * _opp_add_dynamic() - Allocate a dynamic OPP.
+ * _opp_add_v1() - Allocate a OPP based on v1 bindings.
  * @dev:       device for which we do this operation
  * @freq:      Frequency in Hz for this OPP
  * @u_volt:    Voltage in uVolts for this OPP
@@ -727,8 +733,8 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
  *             Duplicate OPPs (both freq and volt are same) and !opp->available
  * -ENOMEM     Memory allocation failure
  */
-static int _opp_add_dynamic(struct device *dev, unsigned long freq,
-                           long u_volt, bool dynamic)
+static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
+                      bool dynamic)
 {
        struct device_opp *dev_opp;
        struct dev_pm_opp *new_opp;
@@ -770,9 +776,10 @@ unlock:
 }
 
 /* TODO: Support multiple regulators */
-static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev)
+static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev)
 {
        u32 microvolt[3] = {0};
+       u32 val;
        int count, ret;
 
        /* Missing property isn't a problem, but an invalid entry is */
@@ -805,6 +812,9 @@ static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev)
        opp->u_volt_min = microvolt[1];
        opp->u_volt_max = microvolt[2];
 
+       if (!of_property_read_u32(opp->np, "opp-microamp", &val))
+               opp->u_amp = val;
+
        return 0;
 }
 
@@ -869,13 +879,10 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
        if (!of_property_read_u32(np, "clock-latency-ns", &val))
                new_opp->clock_latency_ns = val;
 
-       ret = opp_get_microvolt(new_opp, dev);
+       ret = opp_parse_supplies(new_opp, dev);
        if (ret)
                goto free_opp;
 
-       if (!of_property_read_u32(new_opp->np, "opp-microamp", &val))
-               new_opp->u_amp = val;
-
        ret = _opp_add(dev, new_opp, dev_opp);
        if (ret)
                goto free_opp;
@@ -939,7 +946,7 @@ unlock:
  */
 int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
 {
-       return _opp_add_dynamic(dev, freq, u_volt, true);
+       return _opp_add_v1(dev, freq, u_volt, true);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_add);
 
@@ -1172,13 +1179,17 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
        struct device_opp *dev_opp;
        int ret = 0, count = 0;
 
+       mutex_lock(&dev_opp_list_lock);
+
        dev_opp = _managed_opp(opp_np);
        if (dev_opp) {
                /* OPPs are already managed */
                if (!_add_list_dev(dev, dev_opp))
                        ret = -ENOMEM;
+               mutex_unlock(&dev_opp_list_lock);
                return ret;
        }
+       mutex_unlock(&dev_opp_list_lock);
 
        /* We have opp-list node now, iterate over it and add OPPs */
        for_each_available_child_of_node(opp_np, np) {
@@ -1196,15 +1207,20 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
        if (WARN_ON(!count))
                return -ENOENT;
 
+       mutex_lock(&dev_opp_list_lock);
+
        dev_opp = _find_device_opp(dev);
        if (WARN_ON(IS_ERR(dev_opp))) {
                ret = PTR_ERR(dev_opp);
+               mutex_unlock(&dev_opp_list_lock);
                goto free_table;
        }
 
        dev_opp->np = opp_np;
        dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared");
 
+       mutex_unlock(&dev_opp_list_lock);
+
        return 0;
 
 free_table:
@@ -1241,7 +1257,7 @@ static int _of_add_opp_table_v1(struct device *dev)
                unsigned long freq = be32_to_cpup(val++) * 1000;
                unsigned long volt = be32_to_cpup(val++);
 
-               if (_opp_add_dynamic(dev, freq, volt, false))
+               if (_opp_add_v1(dev, freq, volt, false))
                        dev_warn(dev, "%s: Failed to add OPP %ld\n",
                                 __func__, freq);
                nr -= 2;
index 7654c5606307f7e3d71903385964e3af9a71caea..7b445e88a0d559f091918be5e841f6a1380a33da 100644 (file)
@@ -10,6 +10,9 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/err.h>
@@ -124,12 +127,12 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
        struct device *dev;
        int cpu, ret = 0;
 
-       rcu_read_lock();
+       mutex_lock(&dev_opp_list_lock);
 
        dev_opp = _find_device_opp(cpu_dev);
        if (IS_ERR(dev_opp)) {
                ret = -EINVAL;
-               goto out_rcu_read_unlock;
+               goto unlock;
        }
 
        for_each_cpu(cpu, cpumask) {
@@ -150,10 +153,10 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
                        continue;
                }
        }
-out_rcu_read_unlock:
-       rcu_read_unlock();
+unlock:
+       mutex_unlock(&dev_opp_list_lock);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
 
index dcb38f78dae429dad1e6387c53fd984b967f64a4..7366b2aa8997897f89890cf99a4990d83e61a5a6 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 
+/* Lock to allow exclusive modification to the device and opp lists */
+extern struct mutex dev_opp_list_lock;
+
 /*
  * Internal data structure organization with the OPP layer library is as
  * follows: