summaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cpufreq.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2018-02-22 06:59:44 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-02-27 18:22:12 +0100
commitd417e0691ac00d35c4e6b90fc3fc85631a7865ad (patch)
treef335e4959da76cd7c61542d928e72c31b68dd574 /drivers/cpufreq/cpufreq.c
parentcpufreq: Reorder cpufreq_online() error code path (diff)
downloadlinux-d417e0691ac00d35c4e6b90fc3fc85631a7865ad.tar.xz
linux-d417e0691ac00d35c4e6b90fc3fc85631a7865ad.zip
cpufreq: Validate frequency table in the core
By design, cpufreq drivers are responsible for calling cpufreq_frequency_table_cpuinfo() from their ->init() callbacks to validate the frequency table. However, if a cpufreq driver is buggy and fails to do so properly, it lead to unexpected behavior of the driver or the cpufreq core at a later point in time. It would be better if the core could validate the frequency table during driver initialization. To that end, introduce cpufreq_table_validate_and_sort() and make the cpufreq core call it right after invoking the ->init() callback of the driver and destroy the cpufreq policy if the table is invalid. For the time being the validation of the table happens twice, once from the driver and then from the core. The individual drivers will be updated separately to drop table validation if they don't need it for other reasons. The frequency table is marked "sorted" or "unsorted" by the new helper now instead of in cpufreq_table_validate_and_show(), as it should only be done after validating the table (which the drivers won't do going forward). Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> [ rjw: Subject/changelog ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r--drivers/cpufreq/cpufreq.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8814c572e263..239063fb6afc 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1219,6 +1219,10 @@ static int cpufreq_online(unsigned int cpu)
goto out_free_policy;
}
+ ret = cpufreq_table_validate_and_sort(policy);
+ if (ret)
+ goto out_exit_policy;
+
down_write(&policy->rwsem);
if (new_policy) {
@@ -1249,7 +1253,7 @@ static int cpufreq_online(unsigned int cpu)
policy->cur = cpufreq_driver->get(policy->cpu);
if (!policy->cur) {
pr_err("%s: ->get() failed\n", __func__);
- goto out_exit_policy;
+ goto out_destroy_policy;
}
}
@@ -1296,7 +1300,7 @@ static int cpufreq_online(unsigned int cpu)
if (new_policy) {
ret = cpufreq_add_dev_interface(policy);
if (ret)
- goto out_exit_policy;
+ goto out_destroy_policy;
cpufreq_stats_create_table(policy);
@@ -1311,7 +1315,7 @@ static int cpufreq_online(unsigned int cpu)
__func__, cpu, ret);
/* cpufreq_policy_free() will notify based on this */
new_policy = false;
- goto out_exit_policy;
+ goto out_destroy_policy;
}
up_write(&policy->rwsem);
@@ -1326,12 +1330,13 @@ static int cpufreq_online(unsigned int cpu)
return 0;
-out_exit_policy:
+out_destroy_policy:
for_each_cpu(j, policy->real_cpus)
remove_cpu_dev_symlink(policy, get_cpu_device(j));
up_write(&policy->rwsem);
+out_exit_policy:
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);