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 static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); 182 /** 183 * show_available_freqs - show available frequencies for the specified CPU 184 */ 185 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) 186 { 187 unsigned int i = 0; 188 unsigned int cpu = policy->cpu; 189 ssize_t count = 0; 190 struct cpufreq_frequency_table *table; 191 192 if (!per_cpu(cpufreq_show_table, cpu)) 193 return -ENODEV; 194 195 table = per_cpu(cpufreq_show_table, cpu); 196 197 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 198 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 199 continue; 200 count += sprintf(&buf[count], "%d ", table[i].frequency); 201 } 202 count += sprintf(&buf[count], "\n"); 203 204 return count; 205 206 } 207 208 struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { 209 .attr = { .name = "scaling_available_frequencies", 210 .mode = 0444, 211 }, 212 .show = show_available_freqs, 213 }; 214 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); 215 216 struct freq_attr *cpufreq_generic_attr[] = { 217 &cpufreq_freq_attr_scaling_available_freqs, 218 NULL, 219 }; 220 EXPORT_SYMBOL_GPL(cpufreq_generic_attr); 221 222 /* 223 * if you use these, you must assure that the frequency table is valid 224 * all the time between get_attr and put_attr! 225 */ 226 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, 227 unsigned int cpu) 228 { 229 pr_debug("setting show_table for cpu %u to %p\n", cpu, table); 230 per_cpu(cpufreq_show_table, cpu) = table; 231 } 232 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); 233 234 void cpufreq_frequency_table_put_attr(unsigned int cpu) 235 { 236 pr_debug("clearing show_table for cpu %u\n", cpu); 237 per_cpu(cpufreq_show_table, cpu) = NULL; 238 } 239 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); 240 241 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, 242 struct cpufreq_frequency_table *table) 243 { 244 int ret = cpufreq_frequency_table_cpuinfo(policy, table); 245 246 if (!ret) 247 cpufreq_frequency_table_get_attr(table, policy->cpu); 248 249 return ret; 250 } 251 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); 252 253 void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy) 254 { 255 pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n", 256 policy->cpu, policy->last_cpu); 257 per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table, 258 policy->last_cpu); 259 per_cpu(cpufreq_show_table, policy->last_cpu) = NULL; 260 } 261 262 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) 263 { 264 return per_cpu(cpufreq_show_table, cpu); 265 } 266 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); 267 268 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); 269 MODULE_DESCRIPTION("CPUfreq frequency table helpers"); 270 MODULE_LICENSE("GPL"); 271