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