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