On 21-10-16, 17:32, Dave Gerlach wrote:
> Hi,
> On 10/20/2016 03:44 AM, Viresh Kumar wrote:
> > This patch adds infrastructure to manage multiple regulators and updates
> > the only user (cpufreq-dt) of dev_pm_opp_set{put}_regulator().
> >
> > This is preparatory work for adding full support for devices with
> > multiple regulators.
> >
> > Signed-off-by: Viresh Kumar <viresh.ku...@linaro.org>
> > ---
> >  drivers/base/power/opp/core.c    | 220 
> > ++++++++++++++++++++++++++-------------
> >  drivers/base/power/opp/debugfs.c |  48 +++++++--
> >  drivers/base/power/opp/of.c      | 102 +++++++++++++-----
> >  drivers/base/power/opp/opp.h     |  10 +-
> >  drivers/cpufreq/cpufreq-dt.c     |   9 +-
> >  include/linux/pm_opp.h           |   8 +-
> >  6 files changed, 276 insertions(+), 121 deletions(-)
> >
> > diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
> > index 37fad2eb0f47..45c70ce07864 100644
> > --- a/drivers/base/power/opp/core.c
> > +++ b/drivers/base/power/opp/core.c
> > @@ -93,6 +93,8 @@ struct opp_table *_find_opp_table(struct device *dev)
> >   * Return: voltage in micro volt corresponding to the opp, else
> >   * return 0
> >   *
> > + * This is useful only for devices with single power supply.
> > + *
> >   * Locking: This function must be called under rcu_read_lock(). opp is a 
> > rcu
> >   * protected pointer. This means that opp which could have been fetched by
> >   * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
> > @@ -112,7 +114,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp 
> > *opp)
> >     if (IS_ERR_OR_NULL(tmp_opp))
> >             pr_err("%s: Invalid parameters\n", __func__);
> >     else
> > -           v = tmp_opp->supply.u_volt;
> > +           v = tmp_opp->supplies[0].u_volt;
> >
> >     return v;
> >  }
> > @@ -222,10 +224,10 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct 
> > device *dev)
> >  {
> >     struct opp_table *opp_table;
> >     struct dev_pm_opp *opp;
> > -   struct regulator *reg;
> > +   struct regulator *reg, **regulators;
> >     unsigned long latency_ns = 0;
> > -   unsigned long min_uV = ~0, max_uV = 0;
> > -   int ret;
> > +   unsigned long *min_uV, *max_uV;
> > +   int ret, size, i, count;
> >
> >     rcu_read_lock();
> >
> > @@ -235,21 +237,44 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct 
> > device *dev)
> >             return 0;
> >     }
> >
> > -   reg = opp_table->regulator;
> > -   if (IS_ERR(reg)) {
> > +   count = opp_table->regulator_count;
> > +
> > +   if (!count) {
> >             /* Regulator may not be required for device */
> >             rcu_read_unlock();
> >             return 0;
> >     }
> >
> > -   list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
> > -           if (!opp->available)
> > -                   continue;
> > +   size = count * sizeof(*regulators);
> > +   regulators = kmemdup(opp_table->regulators, size, GFP_KERNEL);
> > +   if (!regulators) {
> > +           rcu_read_unlock();
> > +           return 0;
> > +   }
> > +
> > +   min_uV = kmalloc(count * (sizeof(*min_uV) + sizeof(*max_uV)),
> > +                    GFP_KERNEL);
> > +   if (!min_uV) {
> > +           kfree(regulators);
> > +           rcu_read_unlock();
> > +           return 0;
> > +   }
> > +
> > +   max_uV = min_uV + count;
> > +
> > +   for (i = 0; i < count; i++) {
> > +           min_uV[i] = ~0;
> > +           max_uV[i] = 0;
> > +
> > +           list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
> > +                   if (!opp->available)
> > +                           continue;
> >
> > -           if (opp->supply.u_volt_min < min_uV)
> > -                   min_uV = opp->supply.u_volt_min;
> > -           if (opp->supply.u_volt_max > max_uV)
> > -                   max_uV = opp->supply.u_volt_max;
> > +                   if (opp->supplies[i].u_volt_min < min_uV[i])
> > +                           min_uV[i] = opp->supplies[i].u_volt_min;
> > +                   if (opp->supplies[i].u_volt_max > max_uV[i])
> > +                           max_uV[i] = opp->supplies[i].u_volt_max;
> > +           }
> >     }
> >
> >     rcu_read_unlock();
> > @@ -258,9 +283,14 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct 
> > device *dev)
> >      * The caller needs to ensure that opp_table (and hence the regulator)
> >      * isn't freed, while we are executing this routine.
> >      */
> > -   ret = regulator_set_voltage_time(reg, min_uV, max_uV);
> > -   if (ret > 0)
> > -           latency_ns = ret * 1000;
> > +   for (i = 0; reg = regulators[i], i < count; i++) {
> > +           ret = regulator_set_voltage_time(reg, min_uV[i], max_uV[i]);
> > +           if (ret > 0)
> > +                   latency_ns += ret * 1000;
> > +   }
> > +
> > +   kfree(min_uV);
> > +   kfree(regulators);
> >
> >     return latency_ns;
> >  }
> > @@ -580,7 +610,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned 
> > long target_freq)
> >  {
> >     struct opp_table *opp_table;
> >     struct dev_pm_opp *old_opp, *opp;
> > -   struct regulator *reg;
> > +   struct regulator *reg = ERR_PTR(-ENXIO);
> >     struct clk *clk;
> >     unsigned long freq, old_freq;
> >     struct dev_pm_opp_supply old_supply, new_supply;
> > @@ -633,14 +663,23 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned 
> > long target_freq)
> >             return ret;
> >     }
> >
> > +   if (opp_table->regulators) {
> > +           /* This function only supports single regulator per device */
> > +           if (WARN_ON(opp_table->regulator_count > 1)) {
> > +                   dev_err(dev, "multiple regulators not supported\n");
> > +                   rcu_read_unlock();
> > +                   return -EINVAL;
> > +           }
> > +
> > +           reg = opp_table->regulators[0];
> > +   }
> > +
> >     if (IS_ERR(old_opp))
> >             old_supply.u_volt = 0;
> >     else
> > -           memcpy(&old_supply, &old_opp->supply, sizeof(old_supply));
> > +           memcpy(&old_supply, old_opp->supplies, sizeof(old_supply));
> >
> > -   memcpy(&new_supply, &opp->supply, sizeof(new_supply));
> > -
> > -   reg = opp_table->regulator;
> > +   memcpy(&new_supply, opp->supplies, sizeof(new_supply));
> >
> >     rcu_read_unlock();
> >
> > @@ -764,9 +803,6 @@ static struct opp_table *_add_opp_table(struct device 
> > *dev)
> >
> >     _of_init_opp_table(opp_table, dev);
> >
> > -   /* Set regulator to a non-NULL error value */
> > -   opp_table->regulator = ERR_PTR(-ENXIO);
> > -
> >     /* Find clk for the device */
> >     opp_table->clk = clk_get(dev, NULL);
> >     if (IS_ERR(opp_table->clk)) {
> > @@ -815,7 +851,7 @@ static void _remove_opp_table(struct opp_table 
> > *opp_table)
> >     if (opp_table->prop_name)
> >             return;
> >
> > -   if (!IS_ERR(opp_table->regulator))
> > +   if (opp_table->regulators)
> >             return;
> >
> >     /* Release clk */
> > @@ -924,35 +960,49 @@ struct dev_pm_opp *_allocate_opp(struct device *dev,
> >                              struct opp_table **opp_table)
> >  {
> >     struct dev_pm_opp *opp;
> > +   int count, supply_size;
> > +   struct opp_table *table;
> >
> > -   /* allocate new OPP node */
> > -   opp = kzalloc(sizeof(*opp), GFP_KERNEL);
> > -   if (!opp)
> > +   table = _add_opp_table(dev);
> > +   if (!table)
> >             return NULL;
> >
> > -   INIT_LIST_HEAD(&opp->node);
> > +   /* Allocate space for at least one supply */
> > +   count = table->regulator_count ? table->regulator_count : 1;
> > +   supply_size = sizeof(*opp->supplies) * count;
> >
> > -   *opp_table = _add_opp_table(dev);
> > -   if (!*opp_table) {
> > -           kfree(opp);
> > +   /* allocate new OPP node + and supplies structures */
> > +   opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL);
> > +   if (!opp) {
> > +           kfree(table);
> >             return NULL;
> >     }
> >
> > +   opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
> > +   INIT_LIST_HEAD(&opp->node);
> > +
> > +   *opp_table = table;
> > +
> >     return opp;
> >  }
> >
> >  static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
> >                                      struct opp_table *opp_table)
> >  {
> > -   struct regulator *reg = opp_table->regulator;
> > -
> > -   if (!IS_ERR(reg) &&
> > -       !regulator_is_supported_voltage(reg, opp->supply.u_volt_min,
> > -                                       opp->supply.u_volt_max)) {
> > -           pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by 
> > regulator\n",
> > -                   __func__, opp->supply.u_volt_min,
> > -                   opp->supply.u_volt_max);
> > -           return false;
> > +   struct regulator *reg;
> > +   int i;
> > +
> > +   for (i = 0; i < opp_table->regulator_count; i++) {
> > +           reg = opp_table->regulators[i];
> > +
> > +           if (!regulator_is_supported_voltage(reg,
> > +                                   opp->supplies[i].u_volt_min,
> > +                                   opp->supplies[i].u_volt_max)) {
> > +                   pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported 
> > by regulator\n",
> > +                           __func__, opp->supplies[i].u_volt_min,
> > +                           opp->supplies[i].u_volt_max);
> > +                   return false;
> > +           }
> >     }
> >
> >     return true;
> > @@ -984,12 +1034,13 @@ int _opp_add(struct device *dev, struct dev_pm_opp 
> > *new_opp,
> >
> >             /* Duplicate OPPs */
> >             dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: 
> > %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
> > -                    __func__, opp->rate, opp->supply.u_volt,
> > -                    opp->available, new_opp->rate, new_opp->supply.u_volt,
> > -                    new_opp->available);
> > +                    __func__, opp->rate, opp->supplies[0].u_volt,
> > +                    opp->available, new_opp->rate,
> > +                    new_opp->supplies[0].u_volt, new_opp->available);
> >
> > +           /* Should we compare voltages for all regulators here ? */
> >             return opp->available &&
> > -                  new_opp->supply.u_volt == opp->supply.u_volt ? 0 : 
> > -EEXIST;
> > +                  new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 
> > 0 : -EEXIST;
> >     }
> >
> >     new_opp->opp_table = opp_table;
> > @@ -1056,9 +1107,9 @@ int _opp_add_v1(struct device *dev, unsigned long 
> > freq, long u_volt,
> >     /* populate the opp table */
> >     new_opp->rate = freq;
> >     tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
> > -   new_opp->supply.u_volt = u_volt;
> > -   new_opp->supply.u_volt_min = u_volt - tol;
> > -   new_opp->supply.u_volt_max = u_volt + tol;
> > +   new_opp->supplies[0].u_volt = u_volt;
> > +   new_opp->supplies[0].u_volt_min = u_volt - tol;
> > +   new_opp->supplies[0].u_volt_max = u_volt + tol;
> >     new_opp->available = true;
> >     new_opp->dynamic = dynamic;
> >
> > @@ -1303,12 +1354,14 @@ void dev_pm_opp_put_prop_name(struct device *dev)
> >  EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
> >
> >  /**
> > - * dev_pm_opp_set_regulator() - Set regulator name for the device
> > + * dev_pm_opp_set_regulators() - Set regulator names for the device
> >   * @dev: Device for which regulator name is being set.
> > - * @name: Name of the regulator.
> > + * @names: Array of pointers to the names of the regulator.
> > + * @count: Number of regulators.
> >   *
> >   * In order to support OPP switching, OPP layer needs to know the name of 
> > the
> > - * device's regulator, as the core would be required to switch voltages as 
> > well.
> > + * device's regulators, as the core would be required to switch voltages as
> > + * well.
> >   *
> >   * This must be called before any OPPs are initialized for the device.
> >   *
> > @@ -1318,11 +1371,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
> >   * that this function is *NOT* called under RCU protection or in contexts 
> > where
> >   * mutex cannot be locked.
> >   */
> > -int dev_pm_opp_set_regulator(struct device *dev, const char *name)
> > +int dev_pm_opp_set_regulators(struct device *dev, const char *names[],
> > +                         unsigned int count)
> >  {
> >     struct opp_table *opp_table;
> >     struct regulator *reg;
> > -   int ret;
> > +   int ret, i;
> >
> >     mutex_lock(&opp_table_lock);
> >
> > @@ -1338,26 +1392,43 @@ int dev_pm_opp_set_regulator(struct device *dev, 
> > const char *name)
> >             goto err;
> >     }
> >
> > -   /* Already have a regulator set */
> > -   if (WARN_ON(!IS_ERR(opp_table->regulator))) {
> > +   /* Already have regulators set */
> > +   if (WARN_ON(opp_table->regulators)) {
> >             ret = -EBUSY;
> >             goto err;
> >     }
> > -   /* Allocate the regulator */
> > -   reg = regulator_get_optional(dev, name);
> > -   if (IS_ERR(reg)) {
> > -           ret = PTR_ERR(reg);
> > -           if (ret != -EPROBE_DEFER)
> > -                   dev_err(dev, "%s: no regulator (%s) found: %d\n",
> > -                           __func__, name, ret);
> > +
> > +   opp_table->regulators = kmalloc_array(count,
> > +                                         sizeof(*opp_table->regulators),
> > +                                         GFP_KERNEL);
> > +   if (!opp_table->regulators)
> >             goto err;
> > +
> > +   for (i = 0; i < count; i++) {
> > +           reg = regulator_get_optional(dev, names[i]);
> > +           pr_info("%s: %d: %p: %s\n", __func__, __LINE__, reg, names[i]);
> 
> Think this is leftover debug msg?

Yes.

> > +           if (IS_ERR(reg)) {
> > +                   ret = PTR_ERR(reg);
> > +                   if (ret != -EPROBE_DEFER)
> > +                           dev_err(dev, "%s: regulator (%s) not found: 
> > %d\n",
> > +                                   __func__, names[i], ret);
> > +                   goto free_regulators;
> > +           }
> > +
> > +           opp_table->regulators[i] = reg;
> >     }
> >
> > -   opp_table->regulator = reg;
> > +   opp_table->regulator_count = count;
> >
> >     mutex_unlock(&opp_table_lock);
> >     return 0;
> >
> > +free_regulators:
> > +   while (i != 0)
> > +           regulator_put(opp_table->regulators[--i]);
> > +
> > +   kfree(opp_table->regulators);
> > +   opp_table->regulators = NULL;
> >  err:
> >     _remove_opp_table(opp_table);
> >  unlock:
> > @@ -1365,11 +1436,11 @@ int dev_pm_opp_set_regulator(struct device *dev, 
> > const char *name)
> >
> >     return ret;
> >  }
> > -EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
> > +EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
> >
> >  /**
> > - * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
> > - * @dev: Device for which regulator was set.
> > + * dev_pm_opp_put_regulators() - Releases resources blocked for regulators
> > + * @dev: Device for which regulators were set.
> >   *
> >   * Locking: The internal opp_table and opp structures are RCU protected.
> >   * Hence this function internally uses RCU updater strategy with mutex 
> > locks
> > @@ -1377,9 +1448,10 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
> >   * that this function is *NOT* called under RCU protection or in contexts 
> > where
> >   * mutex cannot be locked.
> >   */
> > -void dev_pm_opp_put_regulator(struct device *dev)
> > +void dev_pm_opp_put_regulators(struct device *dev)
> >  {
> >     struct opp_table *opp_table;
> > +   int i;
> >
> >     mutex_lock(&opp_table_lock);
> >
> > @@ -1391,16 +1463,20 @@ void dev_pm_opp_put_regulator(struct device *dev)
> >             goto unlock;
> >     }
> >
> > -   if (IS_ERR(opp_table->regulator)) {
> > -           dev_err(dev, "%s: Doesn't have regulator set\n", __func__);
> > +   if (!opp_table->regulators) {
> > +           dev_err(dev, "%s: Doesn't have regulators set\n", __func__);
> >             goto unlock;
> >     }
> >
> >     /* Make sure there are no concurrent readers while updating opp_table */
> >     WARN_ON(!list_empty(&opp_table->opp_list));
> >
> > -   regulator_put(opp_table->regulator);
> > -   opp_table->regulator = ERR_PTR(-ENXIO);
> > +   for (i = opp_table->regulator_count - 1; i >= 0; i--)
> > +           regulator_put(opp_table->regulators[i]);
> > +
> > +   kfree(opp_table->regulators);
> > +   opp_table->regulators = NULL;
> > +   opp_table->regulator_count = 0;
> >
> >     /* Try freeing opp_table if this was the last blocking resource */
> >     _remove_opp_table(opp_table);
> > @@ -1408,7 +1484,7 @@ void dev_pm_opp_put_regulator(struct device *dev)
> >  unlock:
> >     mutex_unlock(&opp_table_lock);
> >  }
> > -EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
> > +EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
> >
> >  /**
> >   * dev_pm_opp_add()  - Add an OPP table from a table definitions
> > diff --git a/drivers/base/power/opp/debugfs.c 
> > b/drivers/base/power/opp/debugfs.c
> > index c897676ca35f..cb5e5fde3d39 100644
> > --- a/drivers/base/power/opp/debugfs.c
> > +++ b/drivers/base/power/opp/debugfs.c
> > @@ -34,6 +34,43 @@ void opp_debug_remove_one(struct dev_pm_opp *opp)
> >     debugfs_remove_recursive(opp->dentry);
> >  }
> >
> > +static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
> > +                                 struct opp_table *opp_table,
> > +                                 struct dentry *pdentry)
> > +{
> > +   struct dentry *d;
> > +   int i = 0;
> > +   char name[] = "supply-X"; /* support only 0-9 supplies */
> > +
> > +   /* Always create at least supply-0 directory */
> > +   do {
> > +           name[7] = i + '0';
> > +
> > +           /* Create per-opp directory */
> > +           d = debugfs_create_dir(name, pdentry);
> > +           if (!d)
> > +                   return false;
> > +
> > +           if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d,
> > +                                     &opp->supplies[i].u_volt))
> > +                   return false;
> > +
> > +           if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d,
> > +                                     &opp->supplies[i].u_volt_min))
> > +                   return false;
> > +
> > +           if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d,
> > +                                     &opp->supplies[i].u_volt_max))
> > +                   return false;
> > +
> > +           if (!debugfs_create_ulong("u_amp", S_IRUGO, d,
> > +                                     &opp->supplies[i].u_amp))
> > +                   return false;
> > +   } while (++i < opp_table->regulator_count);
> > +
> > +   return true;
> > +}
> > +
> >  int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table 
> > *opp_table)
> >  {
> >     struct dentry *pdentry = opp_table->dentry;
> > @@ -63,16 +100,7 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct 
> > opp_table *opp_table)
> >     if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
> >             return -ENOMEM;
> >
> > -   if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, 
> > &opp->supply.u_volt))
> > -           return -ENOMEM;
> > -
> > -   if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, 
> > &opp->supply.u_volt_min))
> > -           return -ENOMEM;
> > -
> > -   if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, 
> > &opp->supply.u_volt_max))
> > -           return -ENOMEM;
> > -
> > -   if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->supply.u_amp))
> > +   if (!opp_debug_create_supplies(opp, opp_table, d))
> >             return -ENOMEM;
> >
> >     if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
> > diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c
> > index b7fcd0a1b58b..c857fb07a5bc 100644
> > --- a/drivers/base/power/opp/of.c
> > +++ b/drivers/base/power/opp/of.c
> > @@ -17,6 +17,7 @@
> >  #include <linux/errno.h>
> >  #include <linux/device.h>
> >  #include <linux/of.h>
> > +#include <linux/slab.h>
> >  #include <linux/export.h>
> >
> >  #include "opp.h"
> > @@ -105,12 +106,13 @@ static bool _opp_is_supported(struct device *dev, 
> > struct opp_table *opp_table,
> 
> Though not in the patch there's a comment to
> 
> /* TODO: Support multiple regulators */
> 
> in the file right above the below opp_parse_supplies function that can 
> probably
> be removed as part of this patch.

Sure.

-- 
viresh

Reply via email to