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>
This commit is contained in:
parent
b24b6478e6
commit
d417e0691a
|
@ -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);
|
||||
|
||||
|
|
|
@ -362,10 +362,24 @@ int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
|
|||
return ret;
|
||||
|
||||
policy->freq_table = table;
|
||||
return set_freq_table_sorted(policy);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
|
||||
|
||||
int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!policy->freq_table)
|
||||
return 0;
|
||||
|
||||
ret = cpufreq_frequency_table_cpuinfo(policy, policy->freq_table);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return set_freq_table_sorted(policy);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION("CPUfreq frequency table helpers");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -962,6 +962,7 @@ extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
|
|||
extern struct freq_attr *cpufreq_generic_attr[];
|
||||
int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table);
|
||||
int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy);
|
||||
|
||||
unsigned int cpufreq_generic_get(unsigned int cpu);
|
||||
int cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
|
|
Loading…
Reference in a new issue