Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM / devfreq: Fix cpufreq passive unregister erroring on PROBE_DEFER

With the passive governor, the cpu based scaling can PROBE_DEFER due to
the fact that CPU policy are not ready.
The cpufreq passive unregister notifier is called both from the
GOV_START errors and for the GOV_STOP and assume the notifier is
successfully registred every time. With GOV_START failing it's wrong to
loop over each possible CPU since the register path has failed for
some CPU policy not ready. Change the logic and unregister the notifer
based on the current allocated parent_cpu_data list to correctly handle
errors and the governor unregister path.

Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor")
Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>

authored by

Christian 'Ansuel' Marangi and committed by
Chanwoo Choi
0cca7e8d e52b045f

+17 -22
+17 -22
drivers/devfreq/governor_passive.c
··· 34 34 return NULL; 35 35 } 36 36 37 + static void delete_parent_cpu_data(struct devfreq_passive_data *p_data) 38 + { 39 + struct devfreq_cpu_data *parent_cpu_data, *tmp; 40 + 41 + list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) { 42 + list_del(&parent_cpu_data->node); 43 + 44 + if (parent_cpu_data->opp_table) 45 + dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); 46 + 47 + kfree(parent_cpu_data); 48 + } 49 + } 50 + 37 51 static unsigned long get_target_freq_by_required_opp(struct device *p_dev, 38 52 struct opp_table *p_opp_table, 39 53 struct opp_table *opp_table, ··· 236 222 { 237 223 struct devfreq_passive_data *p_data 238 224 = (struct devfreq_passive_data *)devfreq->data; 239 - struct devfreq_cpu_data *parent_cpu_data; 240 - int cpu, ret = 0; 225 + int ret; 241 226 242 227 if (p_data->nb.notifier_call) { 243 228 ret = cpufreq_unregister_notifier(&p_data->nb, ··· 245 232 return ret; 246 233 } 247 234 248 - for_each_possible_cpu(cpu) { 249 - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 250 - if (!policy) { 251 - ret = -EINVAL; 252 - continue; 253 - } 235 + delete_parent_cpu_data(p_data); 254 236 255 - parent_cpu_data = get_parent_cpu_data(p_data, policy); 256 - if (!parent_cpu_data) { 257 - cpufreq_cpu_put(policy); 258 - continue; 259 - } 260 - 261 - list_del(&parent_cpu_data->node); 262 - if (parent_cpu_data->opp_table) 263 - dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); 264 - kfree(parent_cpu_data); 265 - cpufreq_cpu_put(policy); 266 - } 267 - 268 - return ret; 237 + return 0; 269 238 } 270 239 271 240 static int cpufreq_passive_register_notifier(struct devfreq *devfreq)