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