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->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 67 int 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 } 100 EXPORT_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 */ 106 int 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 } 113 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); 114 115 int 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 } 206 EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted); 207 208 int 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 } 225 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); 226 227 /* 228 * show_available_freqs - show available frequencies for the specified CPU 229 */ 230 static 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[count], "%u ", pos->frequency); 255 } 256 count += sprintf(&buf[count], "\n"); 257 258 return count; 259 260 } 261 262 #define cpufreq_attr_available_freq(_name) \ 263 struct 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 */ 270 static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy, 271 char *buf) 272 { 273 return show_available_freqs(policy, buf, false); 274 } 275 cpufreq_attr_available_freq(scaling_available); 276 277 /* 278 * scaling_boost_frequencies_show - show available boost frequencies for 279 * the specified CPU 280 */ 281 static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy, 282 char *buf) 283 { 284 return show_available_freqs(policy, buf, true); 285 } 286 cpufreq_attr_available_freq(scaling_boost); 287 288 static 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 343 int 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 366 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); 367 MODULE_DESCRIPTION("CPUfreq frequency table helpers"); 368