1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * linux/drivers/cpufreq/freq_table.c
4 *
5 * Copyright (C) 2002 - 2003 Dominik Brodowski
6 */
7
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10 #include <linux/cpufreq.h>
11 #include <linux/module.h>
12 #include <trace/hooks/cpufreq.h>
13
14 /*********************************************************************
15 * FREQUENCY TABLE HELPERS *
16 *********************************************************************/
17
policy_has_boost_freq(struct cpufreq_policy * policy)18 bool policy_has_boost_freq(struct cpufreq_policy *policy)
19 {
20 struct cpufreq_frequency_table *pos, *table = policy->freq_table;
21
22 if (!table)
23 return false;
24
25 cpufreq_for_each_valid_entry(pos, table)
26 if (pos->flags & CPUFREQ_BOOST_FREQ)
27 return true;
28
29 return false;
30 }
31 EXPORT_SYMBOL_GPL(policy_has_boost_freq);
32
cpufreq_frequency_table_cpuinfo(struct cpufreq_policy * policy,struct cpufreq_frequency_table * table)33 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
34 struct cpufreq_frequency_table *table)
35 {
36 struct cpufreq_frequency_table *pos;
37 unsigned int min_freq = ~0;
38 unsigned int max_freq = 0;
39 unsigned int freq;
40
41 cpufreq_for_each_valid_entry(pos, table) {
42 freq = pos->frequency;
43
44 if (!cpufreq_boost_enabled()
45 && (pos->flags & CPUFREQ_BOOST_FREQ))
46 continue;
47
48 pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
49 if (freq < min_freq)
50 min_freq = freq;
51 if (freq > max_freq)
52 max_freq = freq;
53 }
54
55 trace_android_vh_freq_table_limits(policy, min_freq, max_freq);
56 policy->min = policy->cpuinfo.min_freq = min_freq;
57 policy->max = max_freq;
58 /*
59 * If the driver has set its own cpuinfo.max_freq above max_freq, leave
60 * it as is.
61 */
62 if (policy->cpuinfo.max_freq < max_freq)
63 policy->max = policy->cpuinfo.max_freq = max_freq;
64
65 if (policy->min == ~0)
66 return -EINVAL;
67 else
68 return 0;
69 }
70
cpufreq_frequency_table_verify(struct cpufreq_policy_data * policy,struct cpufreq_frequency_table * table)71 int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy,
72 struct cpufreq_frequency_table *table)
73 {
74 struct cpufreq_frequency_table *pos;
75 unsigned int freq, next_larger = ~0;
76 bool found = false;
77
78 pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
79 policy->min, policy->max, policy->cpu);
80
81 cpufreq_verify_within_cpu_limits(policy);
82
83 cpufreq_for_each_valid_entry(pos, table) {
84 freq = pos->frequency;
85
86 if ((freq >= policy->min) && (freq <= policy->max)) {
87 found = true;
88 break;
89 }
90
91 if ((next_larger > freq) && (freq > policy->max))
92 next_larger = freq;
93 }
94
95 if (!found) {
96 policy->max = next_larger;
97 cpufreq_verify_within_cpu_limits(policy);
98 }
99
100 pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
101 policy->min, policy->max, policy->cpu);
102
103 return 0;
104 }
105 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
106
107 /*
108 * Generic routine to verify policy & frequency table, requires driver to set
109 * policy->freq_table prior to it.
110 */
cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data * policy)111 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy)
112 {
113 if (!policy->freq_table)
114 return -ENODEV;
115
116 return cpufreq_frequency_table_verify(policy, policy->freq_table);
117 }
118 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
119
cpufreq_table_index_unsorted(struct cpufreq_policy * policy,unsigned int target_freq,unsigned int relation)120 int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
121 unsigned int target_freq,
122 unsigned int relation)
123 {
124 struct cpufreq_frequency_table optimal = {
125 .driver_data = ~0,
126 .frequency = 0,
127 };
128 struct cpufreq_frequency_table suboptimal = {
129 .driver_data = ~0,
130 .frequency = 0,
131 };
132 struct cpufreq_frequency_table *pos;
133 struct cpufreq_frequency_table *table = policy->freq_table;
134 unsigned int freq, diff, i = 0;
135 int index;
136
137 pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
138 target_freq, relation, policy->cpu);
139
140 switch (relation) {
141 case CPUFREQ_RELATION_H:
142 suboptimal.frequency = ~0;
143 break;
144 case CPUFREQ_RELATION_L:
145 case CPUFREQ_RELATION_C:
146 optimal.frequency = ~0;
147 break;
148 }
149
150 cpufreq_for_each_valid_entry_idx(pos, table, i) {
151 freq = pos->frequency;
152
153 if ((freq < policy->min) || (freq > policy->max))
154 continue;
155 if (freq == target_freq) {
156 optimal.driver_data = i;
157 break;
158 }
159 switch (relation) {
160 case CPUFREQ_RELATION_H:
161 if (freq < target_freq) {
162 if (freq >= optimal.frequency) {
163 optimal.frequency = freq;
164 optimal.driver_data = i;
165 }
166 } else {
167 if (freq <= suboptimal.frequency) {
168 suboptimal.frequency = freq;
169 suboptimal.driver_data = i;
170 }
171 }
172 break;
173 case CPUFREQ_RELATION_L:
174 if (freq > target_freq) {
175 if (freq <= optimal.frequency) {
176 optimal.frequency = freq;
177 optimal.driver_data = i;
178 }
179 } else {
180 if (freq >= suboptimal.frequency) {
181 suboptimal.frequency = freq;
182 suboptimal.driver_data = i;
183 }
184 }
185 break;
186 case CPUFREQ_RELATION_C:
187 diff = abs(freq - target_freq);
188 if (diff < optimal.frequency ||
189 (diff == optimal.frequency &&
190 freq > table[optimal.driver_data].frequency)) {
191 optimal.frequency = diff;
192 optimal.driver_data = i;
193 }
194 break;
195 }
196 }
197 if (optimal.driver_data > i) {
198 if (suboptimal.driver_data > i) {
199 WARN(1, "Invalid frequency table: %d\n", policy->cpu);
200 return 0;
201 }
202
203 index = suboptimal.driver_data;
204 } else
205 index = optimal.driver_data;
206
207 pr_debug("target index is %u, freq is:%u kHz\n", index,
208 table[index].frequency);
209 return index;
210 }
211 EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted);
212
cpufreq_frequency_table_get_index(struct cpufreq_policy * policy,unsigned int freq)213 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
214 unsigned int freq)
215 {
216 struct cpufreq_frequency_table *pos, *table = policy->freq_table;
217 int idx;
218
219 if (unlikely(!table)) {
220 pr_debug("%s: Unable to find frequency table\n", __func__);
221 return -ENOENT;
222 }
223
224 cpufreq_for_each_valid_entry_idx(pos, table, idx)
225 if (pos->frequency == freq)
226 return idx;
227
228 return -EINVAL;
229 }
230 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
231
232 /*
233 * show_available_freqs - show available frequencies for the specified CPU
234 */
show_available_freqs(struct cpufreq_policy * policy,char * buf,bool show_boost)235 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
236 bool show_boost)
237 {
238 ssize_t count = 0;
239 struct cpufreq_frequency_table *pos, *table = policy->freq_table;
240
241 if (!table)
242 return -ENODEV;
243
244 cpufreq_for_each_valid_entry(pos, table) {
245 /*
246 * show_boost = true and driver_data = BOOST freq
247 * display BOOST freqs
248 *
249 * show_boost = false and driver_data = BOOST freq
250 * show_boost = true and driver_data != BOOST freq
251 * continue - do not display anything
252 *
253 * show_boost = false and driver_data != BOOST freq
254 * display NON BOOST freqs
255 */
256 if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
257 continue;
258
259 count += sprintf(&buf[count], "%d ", pos->frequency);
260 }
261 count += sprintf(&buf[count], "\n");
262
263 return count;
264
265 }
266
267 #define cpufreq_attr_available_freq(_name) \
268 struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
269 __ATTR_RO(_name##_frequencies)
270
271 /*
272 * scaling_available_frequencies_show - show available normal frequencies for
273 * the specified CPU
274 */
scaling_available_frequencies_show(struct cpufreq_policy * policy,char * buf)275 static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
276 char *buf)
277 {
278 return show_available_freqs(policy, buf, false);
279 }
280 cpufreq_attr_available_freq(scaling_available);
281 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
282
283 /*
284 * scaling_boost_frequencies_show - show available boost frequencies for
285 * the specified CPU
286 */
scaling_boost_frequencies_show(struct cpufreq_policy * policy,char * buf)287 static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
288 char *buf)
289 {
290 return show_available_freqs(policy, buf, true);
291 }
292 cpufreq_attr_available_freq(scaling_boost);
293 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
294
295 struct freq_attr *cpufreq_generic_attr[] = {
296 &cpufreq_freq_attr_scaling_available_freqs,
297 NULL,
298 };
299 EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
300
set_freq_table_sorted(struct cpufreq_policy * policy)301 static int set_freq_table_sorted(struct cpufreq_policy *policy)
302 {
303 struct cpufreq_frequency_table *pos, *table = policy->freq_table;
304 struct cpufreq_frequency_table *prev = NULL;
305 int ascending = 0;
306
307 policy->freq_table_sorted = CPUFREQ_TABLE_UNSORTED;
308
309 cpufreq_for_each_valid_entry(pos, table) {
310 if (!prev) {
311 prev = pos;
312 continue;
313 }
314
315 if (pos->frequency == prev->frequency) {
316 pr_warn("Duplicate freq-table entries: %u\n",
317 pos->frequency);
318 return -EINVAL;
319 }
320
321 /* Frequency increased from prev to pos */
322 if (pos->frequency > prev->frequency) {
323 /* But frequency was decreasing earlier */
324 if (ascending < 0) {
325 pr_debug("Freq table is unsorted\n");
326 return 0;
327 }
328
329 ascending++;
330 } else {
331 /* Frequency decreased from prev to pos */
332
333 /* But frequency was increasing earlier */
334 if (ascending > 0) {
335 pr_debug("Freq table is unsorted\n");
336 return 0;
337 }
338
339 ascending--;
340 }
341
342 prev = pos;
343 }
344
345 if (ascending > 0)
346 policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_ASCENDING;
347 else
348 policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_DESCENDING;
349
350 pr_debug("Freq table is sorted in %s order\n",
351 ascending > 0 ? "ascending" : "descending");
352
353 return 0;
354 }
355
cpufreq_table_validate_and_sort(struct cpufreq_policy * policy)356 int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
357 {
358 int ret;
359
360 if (!policy->freq_table)
361 return 0;
362
363 ret = cpufreq_frequency_table_cpuinfo(policy, policy->freq_table);
364 if (ret)
365 return ret;
366
367 return set_freq_table_sorted(policy);
368 }
369
370 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
371 MODULE_DESCRIPTION("CPUfreq frequency table helpers");
372 MODULE_LICENSE("GPL");
373