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 21 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, 22 struct cpufreq_frequency_table *table) 23 { 24 unsigned int min_freq = ~0; 25 unsigned int max_freq = 0; 26 unsigned int i; 27 28 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 29 unsigned int freq = table[i].frequency; 30 if (freq == CPUFREQ_ENTRY_INVALID) { 31 pr_debug("table entry %u is invalid, skipping\n", i); 32 33 continue; 34 } 35 if (!cpufreq_boost_enabled() 36 && (table[i].flags & CPUFREQ_BOOST_FREQ)) 37 continue; 38 39 pr_debug("table entry %u: %u kHz\n", i, freq); 40 if (freq < min_freq) 41 min_freq = freq; 42 if (freq > max_freq) 43 max_freq = freq; 44 } 45 46 policy->min = policy->cpuinfo.min_freq = min_freq; 47 policy->max = policy->cpuinfo.max_freq = max_freq; 48 49 if (policy->min == ~0) 50 return -EINVAL; 51 else 52 return 0; 53 } 54 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo); 55 56 57 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, 58 struct cpufreq_frequency_table *table) 59 { 60 unsigned int next_larger = ~0, freq, i = 0; 61 bool found = false; 62 63 pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n", 64 policy->min, policy->max, policy->cpu); 65 66 cpufreq_verify_within_cpu_limits(policy); 67 68 for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) { 69 if (freq == CPUFREQ_ENTRY_INVALID) 70 continue; 71 if ((freq >= policy->min) && (freq <= policy->max)) { 72 found = true; 73 break; 74 } 75 76 if ((next_larger > freq) && (freq > policy->max)) 77 next_larger = freq; 78 } 79 80 if (!found) { 81 policy->max = next_larger; 82 cpufreq_verify_within_cpu_limits(policy); 83 } 84 85 pr_debug("verification lead to (%u - %u kHz) for cpu %u\n", 86 policy->min, policy->max, policy->cpu); 87 88 return 0; 89 } 90 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); 91 92 /* 93 * Generic routine to verify policy & frequency table, requires driver to set 94 * policy->freq_table prior to it. 95 */ 96 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) 97 { 98 struct cpufreq_frequency_table *table = 99 cpufreq_frequency_get_table(policy->cpu); 100 if (!table) 101 return -ENODEV; 102 103 return cpufreq_frequency_table_verify(policy, table); 104 } 105 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); 106 107 int cpufreq_frequency_table_target(struct cpufreq_policy *policy, 108 struct cpufreq_frequency_table *table, 109 unsigned int target_freq, 110 unsigned int relation, 111 unsigned int *index) 112 { 113 struct cpufreq_frequency_table optimal = { 114 .driver_data = ~0, 115 .frequency = 0, 116 }; 117 struct cpufreq_frequency_table suboptimal = { 118 .driver_data = ~0, 119 .frequency = 0, 120 }; 121 unsigned int i; 122 123 pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", 124 target_freq, relation, policy->cpu); 125 126 switch (relation) { 127 case CPUFREQ_RELATION_H: 128 suboptimal.frequency = ~0; 129 break; 130 case CPUFREQ_RELATION_L: 131 optimal.frequency = ~0; 132 break; 133 } 134 135 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 136 unsigned int freq = table[i].frequency; 137 if (freq == CPUFREQ_ENTRY_INVALID) 138 continue; 139 if ((freq < policy->min) || (freq > policy->max)) 140 continue; 141 switch (relation) { 142 case CPUFREQ_RELATION_H: 143 if (freq <= target_freq) { 144 if (freq >= optimal.frequency) { 145 optimal.frequency = freq; 146 optimal.driver_data = i; 147 } 148 } else { 149 if (freq <= suboptimal.frequency) { 150 suboptimal.frequency = freq; 151 suboptimal.driver_data = i; 152 } 153 } 154 break; 155 case CPUFREQ_RELATION_L: 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 } 169 } 170 if (optimal.driver_data > i) { 171 if (suboptimal.driver_data > i) 172 return -EINVAL; 173 *index = suboptimal.driver_data; 174 } else 175 *index = optimal.driver_data; 176 177 pr_debug("target index is %u, freq is:%u kHz\n", *index, 178 table[*index].frequency); 179 180 return 0; 181 } 182 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); 183 184 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, 185 unsigned int freq) 186 { 187 struct cpufreq_frequency_table *table; 188 int i; 189 190 table = cpufreq_frequency_get_table(policy->cpu); 191 if (unlikely(!table)) { 192 pr_debug("%s: Unable to find frequency table\n", __func__); 193 return -ENOENT; 194 } 195 196 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { 197 if (table[i].frequency == freq) 198 return i; 199 } 200 201 return -EINVAL; 202 } 203 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); 204 205 /** 206 * show_available_freqs - show available frequencies for the specified CPU 207 */ 208 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, 209 bool show_boost) 210 { 211 unsigned int i = 0; 212 ssize_t count = 0; 213 struct cpufreq_frequency_table *table = policy->freq_table; 214 215 if (!table) 216 return -ENODEV; 217 218 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 219 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 220 continue; 221 /* 222 * show_boost = true and driver_data = BOOST freq 223 * display BOOST freqs 224 * 225 * show_boost = false and driver_data = BOOST freq 226 * show_boost = true and driver_data != BOOST freq 227 * continue - do not display anything 228 * 229 * show_boost = false and driver_data != BOOST freq 230 * display NON BOOST freqs 231 */ 232 if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ)) 233 continue; 234 235 count += sprintf(&buf[count], "%d ", table[i].frequency); 236 } 237 count += sprintf(&buf[count], "\n"); 238 239 return count; 240 241 } 242 243 #define cpufreq_attr_available_freq(_name) \ 244 struct freq_attr cpufreq_freq_attr_##_name##_freqs = \ 245 __ATTR_RO(_name##_frequencies) 246 247 /** 248 * show_scaling_available_frequencies - show available normal frequencies for 249 * the specified CPU 250 */ 251 static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy, 252 char *buf) 253 { 254 return show_available_freqs(policy, buf, false); 255 } 256 cpufreq_attr_available_freq(scaling_available); 257 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); 258 259 /** 260 * show_available_boost_freqs - show available boost frequencies for 261 * the specified CPU 262 */ 263 static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy, 264 char *buf) 265 { 266 return show_available_freqs(policy, buf, true); 267 } 268 cpufreq_attr_available_freq(scaling_boost); 269 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs); 270 271 struct freq_attr *cpufreq_generic_attr[] = { 272 &cpufreq_freq_attr_scaling_available_freqs, 273 #ifdef CONFIG_CPU_FREQ_BOOST_SW 274 &cpufreq_freq_attr_scaling_boost_freqs, 275 #endif 276 NULL, 277 }; 278 EXPORT_SYMBOL_GPL(cpufreq_generic_attr); 279 280 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, 281 struct cpufreq_frequency_table *table) 282 { 283 int ret = cpufreq_frequency_table_cpuinfo(policy, table); 284 285 if (!ret) 286 policy->freq_table = table; 287 288 return ret; 289 } 290 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); 291 292 struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu); 293 294 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) 295 { 296 struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); 297 return policy ? policy->freq_table : NULL; 298 } 299 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); 300 301 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); 302 MODULE_DESCRIPTION("CPUfreq frequency table helpers"); 303 MODULE_LICENSE("GPL"); 304