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 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/init.h> 15 #include <linux/cpufreq.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 index\n", 36 i, freq, table[i].index); 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; 58 unsigned int i; 59 unsigned int count = 0; 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 if (!cpu_online(policy->cpu)) 65 return -EINVAL; 66 67 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 68 policy->cpuinfo.max_freq); 69 70 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 71 unsigned int freq = table[i].frequency; 72 if (freq == CPUFREQ_ENTRY_INVALID) 73 continue; 74 if ((freq >= policy->min) && (freq <= policy->max)) 75 count++; 76 else if ((next_larger > freq) && (freq > policy->max)) 77 next_larger = freq; 78 } 79 80 if (!count) 81 policy->max = next_larger; 82 83 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 84 policy->cpuinfo.max_freq); 85 86 pr_debug("verification lead to (%u - %u kHz) for cpu %u\n", 87 policy->min, policy->max, policy->cpu); 88 89 return 0; 90 } 91 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); 92 93 94 int cpufreq_frequency_table_target(struct cpufreq_policy *policy, 95 struct cpufreq_frequency_table *table, 96 unsigned int target_freq, 97 unsigned int relation, 98 unsigned int *index) 99 { 100 struct cpufreq_frequency_table optimal = { 101 .index = ~0, 102 .frequency = 0, 103 }; 104 struct cpufreq_frequency_table suboptimal = { 105 .index = ~0, 106 .frequency = 0, 107 }; 108 unsigned int i; 109 110 pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", 111 target_freq, relation, policy->cpu); 112 113 switch (relation) { 114 case CPUFREQ_RELATION_H: 115 suboptimal.frequency = ~0; 116 break; 117 case CPUFREQ_RELATION_L: 118 optimal.frequency = ~0; 119 break; 120 } 121 122 if (!cpu_online(policy->cpu)) 123 return -EINVAL; 124 125 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 126 unsigned int freq = table[i].frequency; 127 if (freq == CPUFREQ_ENTRY_INVALID) 128 continue; 129 if ((freq < policy->min) || (freq > policy->max)) 130 continue; 131 switch (relation) { 132 case CPUFREQ_RELATION_H: 133 if (freq <= target_freq) { 134 if (freq >= optimal.frequency) { 135 optimal.frequency = freq; 136 optimal.index = i; 137 } 138 } else { 139 if (freq <= suboptimal.frequency) { 140 suboptimal.frequency = freq; 141 suboptimal.index = i; 142 } 143 } 144 break; 145 case CPUFREQ_RELATION_L: 146 if (freq >= target_freq) { 147 if (freq <= optimal.frequency) { 148 optimal.frequency = freq; 149 optimal.index = i; 150 } 151 } else { 152 if (freq >= suboptimal.frequency) { 153 suboptimal.frequency = freq; 154 suboptimal.index = i; 155 } 156 } 157 break; 158 } 159 } 160 if (optimal.index > i) { 161 if (suboptimal.index > i) 162 return -EINVAL; 163 *index = suboptimal.index; 164 } else 165 *index = optimal.index; 166 167 pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, 168 table[*index].index); 169 170 return 0; 171 } 172 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); 173 174 static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); 175 /** 176 * show_available_freqs - show available frequencies for the specified CPU 177 */ 178 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) 179 { 180 unsigned int i = 0; 181 unsigned int cpu = policy->cpu; 182 ssize_t count = 0; 183 struct cpufreq_frequency_table *table; 184 185 if (!per_cpu(cpufreq_show_table, cpu)) 186 return -ENODEV; 187 188 table = per_cpu(cpufreq_show_table, cpu); 189 190 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 191 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 192 continue; 193 count += sprintf(&buf[count], "%d ", table[i].frequency); 194 } 195 count += sprintf(&buf[count], "\n"); 196 197 return count; 198 199 } 200 201 struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { 202 .attr = { .name = "scaling_available_frequencies", 203 .mode = 0444, 204 }, 205 .show = show_available_freqs, 206 }; 207 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); 208 209 /* 210 * if you use these, you must assure that the frequency table is valid 211 * all the time between get_attr and put_attr! 212 */ 213 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, 214 unsigned int cpu) 215 { 216 pr_debug("setting show_table for cpu %u to %p\n", cpu, table); 217 per_cpu(cpufreq_show_table, cpu) = table; 218 } 219 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); 220 221 void cpufreq_frequency_table_put_attr(unsigned int cpu) 222 { 223 pr_debug("clearing show_table for cpu %u\n", cpu); 224 per_cpu(cpufreq_show_table, cpu) = NULL; 225 } 226 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); 227 228 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) 229 { 230 return per_cpu(cpufreq_show_table, cpu); 231 } 232 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); 233 234 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); 235 MODULE_DESCRIPTION("CPUfreq frequency table helpers"); 236 MODULE_LICENSE("GPL"); 237