Blame view
drivers/cpufreq/freq_table.c
7.8 KB
1da177e4c
|
1 2 3 4 |
/* * linux/drivers/cpufreq/freq_table.c * * Copyright (C) 2002 - 2003 Dominik Brodowski |
4f7436942
|
5 6 7 8 9 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * |
1da177e4c
|
10 |
*/ |
db7011516
|
11 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c
|
12 |
#include <linux/cpufreq.h> |
5ff0a2680
|
13 |
#include <linux/module.h> |
1da177e4c
|
14 |
|
1da177e4c
|
15 16 17 18 19 20 21 |
/********************************************************************* * FREQUENCY TABLE HELPERS * *********************************************************************/ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { |
041526f91
|
22 |
struct cpufreq_frequency_table *pos; |
1da177e4c
|
23 24 |
unsigned int min_freq = ~0; unsigned int max_freq = 0; |
041526f91
|
25 |
unsigned int freq; |
1da177e4c
|
26 |
|
041526f91
|
27 28 |
cpufreq_for_each_valid_entry(pos, table) { freq = pos->frequency; |
1da177e4c
|
29 |
|
6f19efc0a
|
30 |
if (!cpufreq_boost_enabled() |
041526f91
|
31 |
&& (pos->flags & CPUFREQ_BOOST_FREQ)) |
6f19efc0a
|
32 |
continue; |
041526f91
|
33 34 |
pr_debug("table entry %u: %u kHz ", (int)(pos - table), freq); |
1da177e4c
|
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
if (freq < min_freq) min_freq = freq; if (freq > max_freq) max_freq = freq; } policy->min = policy->cpuinfo.min_freq = min_freq; policy->max = policy->cpuinfo.max_freq = max_freq; if (policy->min == ~0) return -EINVAL; else return 0; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo); int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { |
041526f91
|
55 56 |
struct cpufreq_frequency_table *pos; unsigned int freq, next_larger = ~0; |
77db50c4e
|
57 |
bool found = false; |
1da177e4c
|
58 |
|
2d06d8c49
|
59 60 |
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u ", |
e08f5f5bb
|
61 |
policy->min, policy->max, policy->cpu); |
1da177e4c
|
62 |
|
be49e3465
|
63 |
cpufreq_verify_within_cpu_limits(policy); |
1da177e4c
|
64 |
|
041526f91
|
65 66 |
cpufreq_for_each_valid_entry(pos, table) { freq = pos->frequency; |
77db50c4e
|
67 68 69 70 71 72 |
if ((freq >= policy->min) && (freq <= policy->max)) { found = true; break; } if ((next_larger > freq) && (freq > policy->max)) |
1da177e4c
|
73 74 |
next_larger = freq; } |
77db50c4e
|
75 |
if (!found) { |
1da177e4c
|
76 |
policy->max = next_larger; |
be49e3465
|
77 |
cpufreq_verify_within_cpu_limits(policy); |
77db50c4e
|
78 |
} |
1da177e4c
|
79 |
|
2d06d8c49
|
80 81 |
pr_debug("verification lead to (%u - %u kHz) for cpu %u ", |
e08f5f5bb
|
82 |
policy->min, policy->max, policy->cpu); |
1da177e4c
|
83 84 85 86 |
return 0; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); |
184345129
|
87 |
/* |
e0b3165ba
|
88 89 |
* Generic routine to verify policy & frequency table, requires driver to set * policy->freq_table prior to it. |
184345129
|
90 91 92 93 94 95 96 97 98 99 100 |
*/ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) { struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(policy->cpu); if (!table) return -ENODEV; return cpufreq_frequency_table_verify(policy, table); } EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); |
1da177e4c
|
101 102 103 104 105 106 107 |
int cpufreq_frequency_table_target(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table, unsigned int target_freq, unsigned int relation, unsigned int *index) { |
484944a5b
|
108 |
struct cpufreq_frequency_table optimal = { |
507015880
|
109 |
.driver_data = ~0, |
484944a5b
|
110 111 112 |
.frequency = 0, }; struct cpufreq_frequency_table suboptimal = { |
507015880
|
113 |
.driver_data = ~0, |
484944a5b
|
114 115 |
.frequency = 0, }; |
041526f91
|
116 |
struct cpufreq_frequency_table *pos; |
5b0c0b16d
|
117 |
unsigned int freq, diff, i = 0; |
1da177e4c
|
118 |
|
2d06d8c49
|
119 120 |
pr_debug("request for target %u kHz (relation: %u) for cpu %u ", |
e08f5f5bb
|
121 |
target_freq, relation, policy->cpu); |
1da177e4c
|
122 123 124 |
switch (relation) { case CPUFREQ_RELATION_H: |
1da177e4c
|
125 126 127 |
suboptimal.frequency = ~0; break; case CPUFREQ_RELATION_L: |
5b0c0b16d
|
128 |
case CPUFREQ_RELATION_C: |
1da177e4c
|
129 |
optimal.frequency = ~0; |
1da177e4c
|
130 131 |
break; } |
041526f91
|
132 133 134 135 |
cpufreq_for_each_valid_entry(pos, table) { freq = pos->frequency; i = pos - table; |
1da177e4c
|
136 137 |
if ((freq < policy->min) || (freq > policy->max)) continue; |
1e4988563
|
138 139 140 141 |
if (freq == target_freq) { optimal.driver_data = i; break; } |
97acec55d
|
142 |
switch (relation) { |
1da177e4c
|
143 |
case CPUFREQ_RELATION_H: |
1e4988563
|
144 |
if (freq < target_freq) { |
1da177e4c
|
145 146 |
if (freq >= optimal.frequency) { optimal.frequency = freq; |
507015880
|
147 |
optimal.driver_data = i; |
1da177e4c
|
148 149 150 151 |
} } else { if (freq <= suboptimal.frequency) { suboptimal.frequency = freq; |
507015880
|
152 |
suboptimal.driver_data = i; |
1da177e4c
|
153 154 155 156 |
} } break; case CPUFREQ_RELATION_L: |
1e4988563
|
157 |
if (freq > target_freq) { |
1da177e4c
|
158 159 |
if (freq <= optimal.frequency) { optimal.frequency = freq; |
507015880
|
160 |
optimal.driver_data = i; |
1da177e4c
|
161 162 163 164 |
} } else { if (freq >= suboptimal.frequency) { suboptimal.frequency = freq; |
507015880
|
165 |
suboptimal.driver_data = i; |
1da177e4c
|
166 167 168 |
} } break; |
5b0c0b16d
|
169 170 171 172 173 174 175 176 177 |
case CPUFREQ_RELATION_C: diff = abs(freq - target_freq); if (diff < optimal.frequency || (diff == optimal.frequency && freq > table[optimal.driver_data].frequency)) { optimal.frequency = diff; optimal.driver_data = i; } break; |
1da177e4c
|
178 179 |
} } |
507015880
|
180 181 |
if (optimal.driver_data > i) { if (suboptimal.driver_data > i) |
1da177e4c
|
182 |
return -EINVAL; |
507015880
|
183 |
*index = suboptimal.driver_data; |
1da177e4c
|
184 |
} else |
507015880
|
185 |
*index = optimal.driver_data; |
1da177e4c
|
186 |
|
ae87f10f3
|
187 188 189 |
pr_debug("target index is %u, freq is:%u kHz ", *index, table[*index].frequency); |
1da177e4c
|
190 191 192 193 |
return 0; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); |
d3916691c
|
194 195 196 |
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq) { |
041526f91
|
197 |
struct cpufreq_frequency_table *pos, *table; |
d3916691c
|
198 199 200 201 202 203 204 |
table = cpufreq_frequency_get_table(policy->cpu); if (unlikely(!table)) { pr_debug("%s: Unable to find frequency table ", __func__); return -ENOENT; } |
041526f91
|
205 206 207 |
cpufreq_for_each_valid_entry(pos, table) if (pos->frequency == freq) return pos - table; |
d3916691c
|
208 209 210 211 |
return -EINVAL; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); |
1da177e4c
|
212 |
/** |
e32d22f77
|
213 |
* show_available_freqs - show available frequencies for the specified CPU |
1da177e4c
|
214 |
*/ |
6f19efc0a
|
215 216 |
static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, bool show_boost) |
1da177e4c
|
217 |
{ |
1da177e4c
|
218 |
ssize_t count = 0; |
041526f91
|
219 |
struct cpufreq_frequency_table *pos, *table = policy->freq_table; |
1da177e4c
|
220 |
|
e0b3165ba
|
221 |
if (!table) |
1da177e4c
|
222 |
return -ENODEV; |
041526f91
|
223 |
cpufreq_for_each_valid_entry(pos, table) { |
6f19efc0a
|
224 225 226 227 228 229 230 231 232 233 234 |
/* * show_boost = true and driver_data = BOOST freq * display BOOST freqs * * show_boost = false and driver_data = BOOST freq * show_boost = true and driver_data != BOOST freq * continue - do not display anything * * show_boost = false and driver_data != BOOST freq * display NON BOOST freqs */ |
041526f91
|
235 |
if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ)) |
6f19efc0a
|
236 |
continue; |
041526f91
|
237 |
count += sprintf(&buf[count], "%d ", pos->frequency); |
1da177e4c
|
238 239 240 241 242 243 244 |
} count += sprintf(&buf[count], " "); return count; } |
6f19efc0a
|
245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
#define cpufreq_attr_available_freq(_name) \ struct freq_attr cpufreq_freq_attr_##_name##_freqs = \ __ATTR_RO(_name##_frequencies) /** * show_scaling_available_frequencies - show available normal frequencies for * the specified CPU */ static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy, char *buf) { return show_available_freqs(policy, buf, false); } cpufreq_attr_available_freq(scaling_available); |
1da177e4c
|
259 |
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); |
6f19efc0a
|
260 261 262 263 264 265 266 267 268 269 270 |
/** * show_available_boost_freqs - show available boost frequencies for * the specified CPU */ static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy, char *buf) { return show_available_freqs(policy, buf, true); } cpufreq_attr_available_freq(scaling_boost); EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs); |
184345129
|
271 272 |
struct freq_attr *cpufreq_generic_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, |
6f19efc0a
|
273 274 275 |
#ifdef CONFIG_CPU_FREQ_BOOST_SW &cpufreq_freq_attr_scaling_boost_freqs, #endif |
184345129
|
276 277 278 |
NULL, }; EXPORT_SYMBOL_GPL(cpufreq_generic_attr); |
27047a603
|
279 280 281 282 283 284 |
int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { int ret = cpufreq_frequency_table_cpuinfo(policy, table); if (!ret) |
e0b3165ba
|
285 |
policy->freq_table = table; |
27047a603
|
286 287 288 289 |
return ret; } EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); |
e0b3165ba
|
290 |
struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu); |
b8eed8af9
|
291 |
|
1da177e4c
|
292 293 |
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) { |
e0b3165ba
|
294 295 |
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); return policy ? policy->freq_table : NULL; |
1da177e4c
|
296 297 |
} EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); |
97acec55d
|
298 299 300 |
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); MODULE_DESCRIPTION("CPUfreq frequency table helpers"); MODULE_LICENSE("GPL"); |