diff options
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 40 | ||||
-rw-r--r-- | drivers/cpufreq/freq_table.c | 22 | ||||
-rw-r--r-- | include/linux/cpufreq.h | 2 |
3 files changed, 64 insertions, 0 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d533c205eea4..3509ca04b5bb 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -1073,6 +1073,46 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, | |||
1073 | } | 1073 | } |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | /* | ||
1077 | * Sometimes boot loaders set CPU frequency to a value outside of | ||
1078 | * frequency table present with cpufreq core. In such cases CPU might be | ||
1079 | * unstable if it has to run on that frequency for long duration of time | ||
1080 | * and so its better to set it to a frequency which is specified in | ||
1081 | * freq-table. This also makes cpufreq stats inconsistent as | ||
1082 | * cpufreq-stats would fail to register because current frequency of CPU | ||
1083 | * isn't found in freq-table. | ||
1084 | * | ||
1085 | * Because we don't want this change to effect boot process badly, we go | ||
1086 | * for the next freq which is >= policy->cur ('cur' must be set by now, | ||
1087 | * otherwise we will end up setting freq to lowest of the table as 'cur' | ||
1088 | * is initialized to zero). | ||
1089 | * | ||
1090 | * We are passing target-freq as "policy->cur - 1" otherwise | ||
1091 | * __cpufreq_driver_target() would simply fail, as policy->cur will be | ||
1092 | * equal to target-freq. | ||
1093 | */ | ||
1094 | if ((cpufreq_driver->flags & CPUFREQ_NEED_INITIAL_FREQ_CHECK) | ||
1095 | && has_target()) { | ||
1096 | /* Are we running at unknown frequency ? */ | ||
1097 | ret = cpufreq_frequency_table_get_index(policy, policy->cur); | ||
1098 | if (ret == -EINVAL) { | ||
1099 | /* Warn user and fix it */ | ||
1100 | pr_warn("%s: CPU%d: Running at unlisted freq: %u KHz\n", | ||
1101 | __func__, policy->cpu, policy->cur); | ||
1102 | ret = __cpufreq_driver_target(policy, policy->cur - 1, | ||
1103 | CPUFREQ_RELATION_L); | ||
1104 | |||
1105 | /* | ||
1106 | * Reaching here after boot in a few seconds may not | ||
1107 | * mean that system will remain stable at "unknown" | ||
1108 | * frequency for longer duration. Hence, a BUG_ON(). | ||
1109 | */ | ||
1110 | BUG_ON(ret); | ||
1111 | pr_warn("%s: CPU%d: Unlisted initial frequency changed to: %u KHz\n", | ||
1112 | __func__, policy->cpu, policy->cur); | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1076 | /* related cpus should atleast have policy->cpus */ | 1116 | /* related cpus should atleast have policy->cpus */ |
1077 | cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); | 1117 | cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); |
1078 | 1118 | ||
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 3458d27f63b4..a8ac0427fbfe 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c | |||
@@ -178,7 +178,29 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, | |||
178 | } | 178 | } |
179 | EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); | 179 | EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); |
180 | 180 | ||
181 | int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, | ||
182 | unsigned int freq) | ||
183 | { | ||
184 | struct cpufreq_frequency_table *table; | ||
185 | int i; | ||
186 | |||
187 | table = cpufreq_frequency_get_table(policy->cpu); | ||
188 | if (unlikely(!table)) { | ||
189 | pr_debug("%s: Unable to find frequency table\n", __func__); | ||
190 | return -ENOENT; | ||
191 | } | ||
192 | |||
193 | for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { | ||
194 | if (table[i].frequency == freq) | ||
195 | return i; | ||
196 | } | ||
197 | |||
198 | return -EINVAL; | ||
199 | } | ||
200 | EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); | ||
201 | |||
181 | static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); | 202 | static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); |
203 | |||
182 | /** | 204 | /** |
183 | * show_available_freqs - show available frequencies for the specified CPU | 205 | * show_available_freqs - show available frequencies for the specified CPU |
184 | */ | 206 | */ |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 91b8c84e8cd0..aaf800eb9dd2 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
@@ -450,6 +450,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, | |||
450 | unsigned int target_freq, | 450 | unsigned int target_freq, |
451 | unsigned int relation, | 451 | unsigned int relation, |
452 | unsigned int *index); | 452 | unsigned int *index); |
453 | int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, | ||
454 | unsigned int freq); | ||
453 | 455 | ||
454 | void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); | 456 | void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); |
455 | ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); | 457 | ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); |