aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cpufreq-dt.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2018-10-03 06:05:21 -0400
committerViresh Kumar <viresh.kumar@linaro.org>2018-10-03 23:41:38 -0400
commit51c99dd2c06b234575661fa1e0a1dea6c3ef566f (patch)
tree82c8945cbf9a7d5149f4b521716deaf424e6877e /drivers/cpufreq/cpufreq-dt.c
parent09f662f95306f3e3d47ab6842bc4b0bb868a80ad (diff)
cpufreq: dt: Try freeing static OPPs only if we have added them
We can not call dev_pm_opp_of_cpumask_remove_table() freely anymore since the latest OPP core updates as that uses reference counting to free resources. There are cases where no static OPPs are added (using DT) for a platform and trying to remove the OPP table may end up decrementing refcount which is already zero and hence generating warnings. Lets track if we were able to add static OPPs or not and then only remove the table based on that. Some reshuffling of code is also done to do that. Reported-by: Niklas Cassel <niklas.cassel@linaro.org> Tested-by: Niklas Cassel <niklas.cassel@linaro.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Diffstat (limited to 'drivers/cpufreq/cpufreq-dt.c')
-rw-r--r--drivers/cpufreq/cpufreq-dt.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 0a9ebf00be46..e58bfcb1169e 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -32,6 +32,7 @@ struct private_data {
32 struct device *cpu_dev; 32 struct device *cpu_dev;
33 struct thermal_cooling_device *cdev; 33 struct thermal_cooling_device *cdev;
34 const char *reg_name; 34 const char *reg_name;
35 bool have_static_opps;
35}; 36};
36 37
37static struct freq_attr *cpufreq_dt_attr[] = { 38static struct freq_attr *cpufreq_dt_attr[] = {
@@ -204,6 +205,15 @@ static int cpufreq_init(struct cpufreq_policy *policy)
204 } 205 }
205 } 206 }
206 207
208 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
209 if (!priv) {
210 ret = -ENOMEM;
211 goto out_put_regulator;
212 }
213
214 priv->reg_name = name;
215 priv->opp_table = opp_table;
216
207 /* 217 /*
208 * Initialize OPP tables for all policy->cpus. They will be shared by 218 * Initialize OPP tables for all policy->cpus. They will be shared by
209 * all CPUs which have marked their CPUs shared with OPP bindings. 219 * all CPUs which have marked their CPUs shared with OPP bindings.
@@ -214,7 +224,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
214 * 224 *
215 * OPPs might be populated at runtime, don't check for error here 225 * OPPs might be populated at runtime, don't check for error here
216 */ 226 */
217 dev_pm_opp_of_cpumask_add_table(policy->cpus); 227 if (!dev_pm_opp_of_cpumask_add_table(policy->cpus))
228 priv->have_static_opps = true;
218 229
219 /* 230 /*
220 * But we need OPP table to function so if it is not there let's 231 * 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 __func__, ret); 251 __func__, ret);
241 } 252 }
242 253
243 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
244 if (!priv) {
245 ret = -ENOMEM;
246 goto out_free_opp;
247 }
248
249 priv->reg_name = name;
250 priv->opp_table = opp_table;
251
252 ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); 254 ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
253 if (ret) { 255 if (ret) {
254 dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); 256 dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
255 goto out_free_priv; 257 goto out_free_opp;
256 } 258 }
257 259
258 priv->cpu_dev = cpu_dev; 260 priv->cpu_dev = cpu_dev;
@@ -282,10 +284,11 @@ static int cpufreq_init(struct cpufreq_policy *policy)
282 284
283out_free_cpufreq_table: 285out_free_cpufreq_table:
284 dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); 286 dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
285out_free_priv:
286 kfree(priv);
287out_free_opp: 287out_free_opp:
288 dev_pm_opp_of_cpumask_remove_table(policy->cpus); 288 if (priv->have_static_opps)
289 dev_pm_opp_of_cpumask_remove_table(policy->cpus);
290 kfree(priv);
291out_put_regulator:
289 if (name) 292 if (name)
290 dev_pm_opp_put_regulators(opp_table); 293 dev_pm_opp_put_regulators(opp_table);
291out_put_clk: 294out_put_clk:
@@ -300,7 +303,8 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
300 303
301 cpufreq_cooling_unregister(priv->cdev); 304 cpufreq_cooling_unregister(priv->cdev);
302 dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); 305 dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
303 dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); 306 if (priv->have_static_opps)
307 dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
304 if (priv->reg_name) 308 if (priv->reg_name)
305 dev_pm_opp_put_regulators(priv->opp_table); 309 dev_pm_opp_put_regulators(priv->opp_table);
306 310