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