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