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