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/kernel.h> 15 #include <linux/module.h> 16 #include <linux/init.h> 17 #include <linux/cpufreq.h> 18 19 /********************************************************************* 20 * FREQUENCY TABLE HELPERS * 21 *********************************************************************/ 22 23 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, 24 struct cpufreq_frequency_table *table) 25 { 26 unsigned int min_freq = ~0; 27 unsigned int max_freq = 0; 28 unsigned int i; 29 30 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 31 unsigned int freq = table[i].frequency; 32 if (freq == CPUFREQ_ENTRY_INVALID) { 33 pr_debug("table entry %u is invalid, skipping\n", i); 34 35 continue; 36 } 37 pr_debug("table entry %u: %u kHz, %u driver_data\n", 38 i, freq, table[i].driver_data); 39 if (freq < min_freq) 40 min_freq = freq; 41 if (freq > max_freq) 42 max_freq = freq; 43 } 44 45 policy->min = policy->cpuinfo.min_freq = min_freq; 46 policy->max = policy->cpuinfo.max_freq = max_freq; 47 48 if (policy->min == ~0) 49 return -EINVAL; 50 else 51 return 0; 52 } 53 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo); 54 55 56 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, 57 struct cpufreq_frequency_table *table) 58 { 59 unsigned int next_larger = ~0; 60 unsigned int i; 61 unsigned int count = 0; 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_limits(policy, policy->cpuinfo.min_freq, 67 policy->cpuinfo.max_freq); 68 69 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 70 unsigned int freq = table[i].frequency; 71 if (freq == CPUFREQ_ENTRY_INVALID) 72 continue; 73 if ((freq >= policy->min) && (freq <= policy->max)) 74 count++; 75 else if ((next_larger > freq) && (freq > policy->max)) 76 next_larger = freq; 77 } 78 79 if (!count) 80 policy->max = next_larger; 81 82 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 83 policy->cpuinfo.max_freq); 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 int cpufreq_frequency_table_target(struct cpufreq_policy *policy, 94 struct cpufreq_frequency_table *table, 95 unsigned int target_freq, 96 unsigned int relation, 97 unsigned int *index) 98 { 99 struct cpufreq_frequency_table optimal = { 100 .driver_data = ~0, 101 .frequency = 0, 102 }; 103 struct cpufreq_frequency_table suboptimal = { 104 .driver_data = ~0, 105 .frequency = 0, 106 }; 107 unsigned int i; 108 109 pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", 110 target_freq, relation, policy->cpu); 111 112 switch (relation) { 113 case CPUFREQ_RELATION_H: 114 suboptimal.frequency = ~0; 115 break; 116 case CPUFREQ_RELATION_L: 117 optimal.frequency = ~0; 118 break; 119 } 120 121 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 122 unsigned int freq = table[i].frequency; 123 if (freq == CPUFREQ_ENTRY_INVALID) 124 continue; 125 if ((freq < policy->min) || (freq > policy->max)) 126 continue; 127 switch (relation) { 128 case CPUFREQ_RELATION_H: 129 if (freq <= target_freq) { 130 if (freq >= optimal.frequency) { 131 optimal.frequency = freq; 132 optimal.driver_data = i; 133 } 134 } else { 135 if (freq <= suboptimal.frequency) { 136 suboptimal.frequency = freq; 137 suboptimal.driver_data = i; 138 } 139 } 140 break; 141 case CPUFREQ_RELATION_L: 142 if (freq >= target_freq) { 143 if (freq <= optimal.frequency) { 144 optimal.frequency = freq; 145 optimal.driver_data = i; 146 } 147 } else { 148 if (freq >= suboptimal.frequency) { 149 suboptimal.frequency = freq; 150 suboptimal.driver_data = i; 151 } 152 } 153 break; 154 } 155 } 156 if (optimal.driver_data > i) { 157 if (suboptimal.driver_data > i) 158 return -EINVAL; 159 *index = suboptimal.driver_data; 160 } else 161 *index = optimal.driver_data; 162 163 pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, 164 table[*index].driver_data); 165 166 return 0; 167 } 168 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); 169 170 static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); 171 /** 172 * show_available_freqs - show available frequencies for the specified CPU 173 */ 174 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) 175 { 176 unsigned int i = 0; 177 unsigned int cpu = policy->cpu; 178 ssize_t count = 0; 179 struct cpufreq_frequency_table *table; 180 181 if (!per_cpu(cpufreq_show_table, cpu)) 182 return -ENODEV; 183 184 table = per_cpu(cpufreq_show_table, cpu); 185 186 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 187 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 188 continue; 189 count += sprintf(&buf[count], "%d ", table[i].frequency); 190 } 191 count += sprintf(&buf[count], "\n"); 192 193 return count; 194 195 } 196 197 struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { 198 .attr = { .name = "scaling_available_frequencies", 199 .mode = 0444, 200 }, 201 .show = show_available_freqs, 202 }; 203 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); 204 205 /* 206 * if you use these, you must assure that the frequency table is valid 207 * all the time between get_attr and put_attr! 208 */ 209 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, 210 unsigned int cpu) 211 { 212 pr_debug("setting show_table for cpu %u to %p\n", cpu, table); 213 per_cpu(cpufreq_show_table, cpu) = table; 214 } 215 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); 216 217 void cpufreq_frequency_table_put_attr(unsigned int cpu) 218 { 219 pr_debug("clearing show_table for cpu %u\n", cpu); 220 per_cpu(cpufreq_show_table, cpu) = NULL; 221 } 222 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); 223 224 void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy) 225 { 226 pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n", 227 policy->cpu, policy->last_cpu); 228 per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table, 229 policy->last_cpu); 230 per_cpu(cpufreq_show_table, policy->last_cpu) = NULL; 231 } 232 233 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) 234 { 235 return per_cpu(cpufreq_show_table, cpu); 236 } 237 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); 238 239 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); 240 MODULE_DESCRIPTION("CPUfreq frequency table helpers"); 241 MODULE_LICENSE("GPL"); 242