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