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()
This commit is contained in:
commit
c2dc121c64
@ -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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
*
|
*
|
||||||
* 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)
|
|||||||
__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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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);
|
|||||||
* 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,
|
|||||||
|
|
||||||
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,
|
|||||||
* 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)
|
|||||||
|
|
||||||
/* 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);
|
|||||||
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,11 +644,15 @@ 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);
|
||||||
|
|
||||||
|
goto remove_table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
remove_table:
|
||||||
/* Free all other OPPs */
|
/* Free all other OPPs */
|
||||||
_dev_pm_opp_cpumask_remove_table(cpumask, cpu);
|
_dev_pm_opp_cpumask_remove_table(cpumask, cpu);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user