aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2013-12-03 00:50:46 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-06 08:17:25 -0500
commitd3916691c90dfc9f08328d5cef8181e9ea508c55 (patch)
treee32b3422823ef3a64a42c1c72785a169fff20a9c /drivers/cpufreq
parentae6b427132ba39d023e332e7d920e9931ff05313 (diff)
cpufreq: Make sure CPU is running on a freq from freq-table
Sometimes boot loaders set CPU frequency to a value outside of frequency table present with cpufreq core. In such cases CPU might be unstable if it has to run on that frequency for long duration of time and so its better to set it to a frequency which is specified in freq-table. This also makes cpufreq stats inconsistent as cpufreq-stats would fail to register because current frequency of CPU isn't found in freq-table. Because we don't want this change to affect boot process badly, we go for the next freq which is >= policy->cur ('cur' must be set by now, otherwise we will end up setting freq to lowest of the table as 'cur' is initialized to zero). In case current frequency doesn't match any frequency from freq-table, we throw warnings to user, so that user can get this fixed in their bootloaders or freq-tables. Reported-by: Carlos Hernandez <ceh@ti.com> Reported-and-tested-by: Nishanth Menon <nm@ti.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq.c40
-rw-r--r--drivers/cpufreq/freq_table.c22
2 files changed, 62 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}
179EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); 179EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
180 180
181int 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}
200EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
201
181static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); 202static 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 */