Commit c2dc121c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'opp/linux-next' of...

Merge branch 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm into pm-opp

Pull more operating performance points (OPP) framework updates for 4.20
from Viresh Kumar:

"That contains some important fixes reported recently."

* 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  PM / OPP: _of_add_opp_table_v2(): increment count only if OPP is added
  cpufreq: dt: Try freeing static OPPs only if we have added them
  OPP: Return error on error from dev_pm_opp_get_opp_count()
  OPP: Improve error handling in dev_pm_opp_of_cpumask_add_table()
parents fb64207b deac8703
...@@ -32,6 +32,7 @@ struct private_data { ...@@ -32,6 +32,7 @@ struct private_data {
struct device *cpu_dev; struct device *cpu_dev;
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
const char *reg_name; const char *reg_name;
bool have_static_opps;
}; };
static struct freq_attr *cpufreq_dt_attr[] = { static struct freq_attr *cpufreq_dt_attr[] = {
...@@ -204,6 +205,15 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -204,6 +205,15 @@ static int cpufreq_init(struct cpufreq_policy *policy)
} }
} }
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto out_put_regulator;
}
priv->reg_name = name;
priv->opp_table = opp_table;
/* /*
* Initialize OPP tables for all policy->cpus. They will be shared by * Initialize OPP tables for all policy->cpus. They will be shared by
* all CPUs which have marked their CPUs shared with OPP bindings. * all CPUs which have marked their CPUs shared with OPP bindings.
...@@ -214,7 +224,8 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -214,7 +224,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
* *
* OPPs might be populated at runtime, don't check for error here * OPPs might be populated at runtime, don't check for error here
*/ */
dev_pm_opp_of_cpumask_add_table(policy->cpus); if (!dev_pm_opp_of_cpumask_add_table(policy->cpus))
priv->have_static_opps = true;
/* /*
* But we need OPP table to function so if it is not there let's * But we need OPP table to function so if it is not there let's
...@@ -240,19 +251,10 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -240,19 +251,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
__func__, ret); __func__, ret);
} }
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto out_free_opp;
}
priv->reg_name = name;
priv->opp_table = opp_table;
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) { if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
goto out_free_priv; goto out_free_opp;
} }
priv->cpu_dev = cpu_dev; priv->cpu_dev = cpu_dev;
...@@ -282,10 +284,11 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -282,10 +284,11 @@ static int cpufreq_init(struct cpufreq_policy *policy)
out_free_cpufreq_table: out_free_cpufreq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
out_free_priv:
kfree(priv);
out_free_opp: out_free_opp:
if (priv->have_static_opps)
dev_pm_opp_of_cpumask_remove_table(policy->cpus); dev_pm_opp_of_cpumask_remove_table(policy->cpus);
kfree(priv);
out_put_regulator:
if (name) if (name)
dev_pm_opp_put_regulators(opp_table); dev_pm_opp_put_regulators(opp_table);
out_put_clk: out_put_clk:
...@@ -300,6 +303,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy) ...@@ -300,6 +303,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
cpufreq_cooling_unregister(priv->cdev); cpufreq_cooling_unregister(priv->cdev);
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
if (priv->have_static_opps)
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
if (priv->reg_name) if (priv->reg_name)
dev_pm_opp_put_regulators(priv->opp_table); dev_pm_opp_put_regulators(priv->opp_table);
......
...@@ -318,7 +318,7 @@ int dev_pm_opp_get_opp_count(struct device *dev) ...@@ -318,7 +318,7 @@ int dev_pm_opp_get_opp_count(struct device *dev)
count = PTR_ERR(opp_table); count = PTR_ERR(opp_table);
dev_dbg(dev, "%s: OPP table not found (%d)\n", dev_dbg(dev, "%s: OPP table not found (%d)\n",
__func__, count); __func__, count);
return 0; return count;
} }
count = _get_opp_count(opp_table); count = _get_opp_count(opp_table);
......
...@@ -297,15 +297,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); ...@@ -297,15 +297,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
* removed by dev_pm_opp_remove. * removed by dev_pm_opp_remove.
* *
* Return: * Return:
* 0 On success OR * Valid OPP pointer:
* On success
* NULL:
* Duplicate OPPs (both freq and volt are same) and opp->available * Duplicate OPPs (both freq and volt are same) and opp->available
* -EEXIST Freq are same and volt are different OR * OR if the OPP is not supported by hardware.
* ERR_PTR(-EEXIST):
* Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available * Duplicate OPPs (both freq and volt are same) and !opp->available
* -ENOMEM Memory allocation failure * ERR_PTR(-ENOMEM):
* -EINVAL Failed parsing the OPP node * Memory allocation failure
* ERR_PTR(-EINVAL):
* Failed parsing the OPP node
*/ */
static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
struct device_node *np) struct device *dev, struct device_node *np)
{ {
struct dev_pm_opp *new_opp; struct dev_pm_opp *new_opp;
u64 rate = 0; u64 rate = 0;
...@@ -315,7 +321,7 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, ...@@ -315,7 +321,7 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
new_opp = _opp_allocate(opp_table); new_opp = _opp_allocate(opp_table);
if (!new_opp) if (!new_opp)
return -ENOMEM; return ERR_PTR(-ENOMEM);
ret = of_property_read_u64(np, "opp-hz", &rate); ret = of_property_read_u64(np, "opp-hz", &rate);
if (ret < 0) { if (ret < 0) {
...@@ -390,12 +396,12 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, ...@@ -390,12 +396,12 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
* frequency/voltage list. * frequency/voltage list.
*/ */
blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp); blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
return 0; return new_opp;
free_opp: free_opp:
_opp_free(new_opp); _opp_free(new_opp);
return ret; return ERR_PTR(ret);
} }
/* Initializes OPP tables based on new bindings */ /* Initializes OPP tables based on new bindings */
...@@ -415,14 +421,15 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table) ...@@ -415,14 +421,15 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
/* We have opp-table node now, iterate over it and add OPPs */ /* We have opp-table node now, iterate over it and add OPPs */
for_each_available_child_of_node(opp_table->np, np) { for_each_available_child_of_node(opp_table->np, np) {
count++; opp = _opp_add_static_v2(opp_table, dev, np);
if (IS_ERR(opp)) {
ret = _opp_add_static_v2(opp_table, dev, np); ret = PTR_ERR(opp);
if (ret) {
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
ret); ret);
of_node_put(np); of_node_put(np);
goto put_list_kref; goto put_list_kref;
} else if (opp) {
count++;
} }
} }
...@@ -614,16 +621,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table); ...@@ -614,16 +621,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
{ {
struct device *cpu_dev; struct device *cpu_dev;
int cpu, ret = 0; int cpu, ret;
WARN_ON(cpumask_empty(cpumask)); if (WARN_ON(cpumask_empty(cpumask)))
return -ENODEV;
for_each_cpu(cpu, cpumask) { for_each_cpu(cpu, cpumask) {
cpu_dev = get_cpu_device(cpu); cpu_dev = get_cpu_device(cpu);
if (!cpu_dev) { if (!cpu_dev) {
pr_err("%s: failed to get cpu%d device\n", __func__, pr_err("%s: failed to get cpu%d device\n", __func__,
cpu); cpu);
continue; ret = -ENODEV;
goto remove_table;
} }
ret = dev_pm_opp_of_add_table(cpu_dev); ret = dev_pm_opp_of_add_table(cpu_dev);
...@@ -635,12 +644,16 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) ...@@ -635,12 +644,16 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
pr_debug("%s: couldn't find opp table for cpu:%d, %d\n", pr_debug("%s: couldn't find opp table for cpu:%d, %d\n",
__func__, cpu, ret); __func__, cpu, ret);
/* Free all other OPPs */ goto remove_table;
_dev_pm_opp_cpumask_remove_table(cpumask, cpu);
break;
} }
} }
return 0;
remove_table:
/* Free all other OPPs */
_dev_pm_opp_cpumask_remove_table(cpumask, cpu);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table); EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
......
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