From 8953603eb5447be52f6fc3d8fcae1b3ce9899189 Mon Sep 17 00:00:00 2001 From: Christian 'Ansuel' Marangi Date: Mon, 6 Jun 2022 11:58:49 +0200 Subject: [PATCH v4 1/4] 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 --- drivers/devfreq/governor_passive.c | 39 +++++++++++++----------------- 1 file changed, 17 insertions(+), 22 deletions(-) --- a/drivers/devfreq/governor_passive.c +++ b/drivers/devfreq/governor_passive.c @@ -34,6 +34,20 @@ get_parent_cpu_data(struct devfreq_passi return NULL; } +static void delete_parent_cpu_data(struct devfreq_passive_data *p_data) +{ + struct devfreq_cpu_data *parent_cpu_data, *tmp; + + list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) { + list_del(&parent_cpu_data->node); + + if (parent_cpu_data->opp_table) + dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); + + kfree(parent_cpu_data); + } +} + static unsigned long get_target_freq_by_required_opp(struct device *p_dev, struct opp_table *p_opp_table, struct opp_table *opp_table, @@ -222,8 +236,7 @@ static int cpufreq_passive_unregister_no { struct devfreq_passive_data *p_data = (struct devfreq_passive_data *)devfreq->data; - struct devfreq_cpu_data *parent_cpu_data; - int cpu, ret = 0; + int ret; if (p_data->nb.notifier_call) { ret = cpufreq_unregister_notifier(&p_data->nb, @@ -232,27 +245,9 @@ static int cpufreq_passive_unregister_no return ret; } - for_each_possible_cpu(cpu) { - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - if (!policy) { - ret = -EINVAL; - continue; - } - - parent_cpu_data = get_parent_cpu_data(p_data, policy); - if (!parent_cpu_data) { - cpufreq_cpu_put(policy); - continue; - } - - list_del(&parent_cpu_data->node); - if (parent_cpu_data->opp_table) - dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); - kfree(parent_cpu_data); - cpufreq_cpu_put(policy); - } + delete_parent_cpu_data(p_data); - return ret; + return 0; } static int cpufreq_passive_register_notifier(struct devfreq *devfreq)