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