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 pr_debug("table entry %u: %u kHz, %u driver_data\n", 36 i, freq, table[i].driver_data); 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 unsigned int next_larger = ~0, freq, i = 0; 58 bool found = false; 59 60 pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n", 61 policy->min, policy->max, policy->cpu); 62 63 cpufreq_verify_within_cpu_limits(policy); 64 65 for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) { 66 if (freq == CPUFREQ_ENTRY_INVALID) 67 continue; 68 if ((freq >= policy->min) && (freq <= policy->max)) { 69 found = true; 70 break; 71 } 72 73 if ((next_larger > freq) && (freq > policy->max)) 74 next_larger = freq; 75 } 76 77 if (!found) { 78 policy->max = next_larger; 79 cpufreq_verify_within_cpu_limits(policy); 80 } 81 82 pr_debug("verification lead to (%u - %u kHz) for cpu %u\n", 83 policy->min, policy->max, policy->cpu); 84 85 return 0; 86 } 87 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); 88 89 /* 90 * Generic routine to verify policy & frequency table, requires driver to call 91 * cpufreq_frequency_table_get_attr() prior to it. 92 */ 93 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) 94 { 95 struct cpufreq_frequency_table *table = 96 cpufreq_frequency_get_table(policy->cpu); 97 if (!table) 98 return -ENODEV; 99 100 return cpufreq_frequency_table_verify(policy, table); 101 } 102 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); 103 104 int cpufreq_frequency_table_target(struct cpufreq_policy *policy, 105 struct cpufreq_frequency_table *table, 106 unsigned int target_freq, 107 unsigned int relation, 108 unsigned int *index) 109 { 110 struct cpufreq_frequency_table optimal = { 111 .driver_data = ~0, 112 .frequency = 0, 113 }; 114 struct cpufreq_frequency_table suboptimal = { 115 .driver_data = ~0, 116 .frequency = 0, 117 }; 118 unsigned int i; 119 120 pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", 121 target_freq, relation, policy->cpu); 122 123 switch (relation) { 124 case CPUFREQ_RELATION_H: 125 suboptimal.frequency = ~0; 126 break; 127 case CPUFREQ_RELATION_L: 128 optimal.frequency = ~0; 129 break; 130 } 131 132 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 133 unsigned int freq = table[i].frequency; 134 if (freq == CPUFREQ_ENTRY_INVALID) 135 continue; 136 if ((freq < policy->min) || (freq > policy->max)) 137 continue; 138 switch (relation) { 139 case CPUFREQ_RELATION_H: 140 if (freq <= target_freq) { 141 if (freq >= optimal.frequency) { 142 optimal.frequency = freq; 143 optimal.driver_data = i; 144 } 145 } else { 146 if (freq <= suboptimal.frequency) { 147 suboptimal.frequency = freq; 148 suboptimal.driver_data = i; 149 } 150 } 151 break; 152 case CPUFREQ_RELATION_L: 153 if (freq >= target_freq) { 154 if (freq <= optimal.frequency) { 155 optimal.frequency = freq; 156 optimal.driver_data = i; 157 } 158 } else { 159 if (freq >= suboptimal.frequency) { 160 suboptimal.frequency = freq; 161 suboptimal.driver_data = i; 162 } 163 } 164 break; 165 } 166 } 167 if (optimal.driver_data > i) { 168 if (suboptimal.driver_data > i) 169 return -EINVAL; 170 *index = suboptimal.driver_data; 171 } else 172 *index = optimal.driver_data; 173 174 pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, 175 table[*index].driver_data); 176 177 return 0; 178 } 179 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); 180 181 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, 182 unsigned int freq) 183 { 184 struct cpufreq_frequency_table *table; 185 int i; 186 187 table = cpufreq_frequency_get_table(policy->cpu); 188 if (unlikely(!table)) { 189 pr_debug("%s: Unable to find frequency table\n", __func__); 190 return -ENOENT; 191 } 192 193 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { 194 if (table[i].frequency == freq) 195 return i; 196 } 197 198 return -EINVAL; 199 } 200 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); 201 202 static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); 203 204 /** 205 * show_available_freqs - show available frequencies for the specified CPU 206 */ 207 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) 208 { 209 unsigned int i = 0; 210 unsigned int cpu = policy->cpu; 211 ssize_t count = 0; 212 struct cpufreq_frequency_table *table; 213 214 if (!per_cpu(cpufreq_show_table, cpu)) 215 return -ENODEV; 216 217 table = per_cpu(cpufreq_show_table, cpu); 218 219 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 220 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 221 continue; 222 count += sprintf(&buf[count], "%d ", table[i].frequency); 223 } 224 count += sprintf(&buf[count], "\n"); 225 226 return count; 227 228 } 229 230 struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { 231 .attr = { .name = "scaling_available_frequencies", 232 .mode = 0444, 233 }, 234 .show = show_available_freqs, 235 }; 236 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); 237 238 struct freq_attr *cpufreq_generic_attr[] = { 239 &cpufreq_freq_attr_scaling_available_freqs, 240 NULL, 241 }; 242 EXPORT_SYMBOL_GPL(cpufreq_generic_attr); 243 244 /* 245 * if you use these, you must assure that the frequency table is valid 246 * all the time between get_attr and put_attr! 247 */ 248 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, 249 unsigned int cpu) 250 { 251 pr_debug("setting show_table for cpu %u to %p\n", cpu, table); 252 per_cpu(cpufreq_show_table, cpu) = table; 253 } 254 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); 255 256 void cpufreq_frequency_table_put_attr(unsigned int cpu) 257 { 258 pr_debug("clearing show_table for cpu %u\n", cpu); 259 per_cpu(cpufreq_show_table, cpu) = NULL; 260 } 261 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); 262 263 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, 264 struct cpufreq_frequency_table *table) 265 { 266 int ret = cpufreq_frequency_table_cpuinfo(policy, table); 267 268 if (!ret) 269 cpufreq_frequency_table_get_attr(table, policy->cpu); 270 271 return ret; 272 } 273 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); 274 275 void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy) 276 { 277 pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n", 278 policy->cpu, policy->last_cpu); 279 per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table, 280 policy->last_cpu); 281 per_cpu(cpufreq_show_table, policy->last_cpu) = NULL; 282 } 283 284 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) 285 { 286 return per_cpu(cpufreq_show_table, cpu); 287 } 288 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); 289 290 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); 291 MODULE_DESCRIPTION("CPUfreq frequency table helpers"); 292 MODULE_LICENSE("GPL"); 293