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