Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / drivers / cpufreq / freq_table.c
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;
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;
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, policy->cpuinfo.max_freq);
64
65         for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
66                 unsigned int freq = table[i].frequency;
67                 if (freq == CPUFREQ_ENTRY_INVALID)
68                         continue;
69                 if ((freq >= policy->min) && (freq <= policy->max))
70                         count++;
71                 else if ((next_larger > freq) && (freq > policy->max))
72                         next_larger = freq;
73         }
74
75         if (!count)
76                 policy->max = next_larger;
77
78         cpufreq_verify_within_limits(policy,
79                                      policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
80
81         dprintk("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
82
83         return 0;
84 }
85 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
86
87
88 int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
89                                    struct cpufreq_frequency_table *table,
90                                    unsigned int target_freq,
91                                    unsigned int relation,
92                                    unsigned int *index)
93 {
94         struct cpufreq_frequency_table optimal = {
95                 .index = ~0,
96                 .frequency = 0,
97         };
98         struct cpufreq_frequency_table suboptimal = {
99                 .index = ~0,
100                 .frequency = 0,
101         };
102         unsigned int i;
103
104         dprintk("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu);
105
106         switch (relation) {
107         case CPUFREQ_RELATION_H:
108                 suboptimal.frequency = ~0;
109                 break;
110         case CPUFREQ_RELATION_L:
111                 optimal.frequency = ~0;
112                 break;
113         }
114
115         if (!cpu_online(policy->cpu))
116                 return -EINVAL;
117
118         for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
119                 unsigned int freq = table[i].frequency;
120                 if (freq == CPUFREQ_ENTRY_INVALID)
121                         continue;
122                 if ((freq < policy->min) || (freq > policy->max))
123                         continue;
124                 switch(relation) {
125                 case CPUFREQ_RELATION_H:
126                         if (freq <= target_freq) {
127                                 if (freq >= optimal.frequency) {
128                                         optimal.frequency = freq;
129                                         optimal.index = i;
130                                 }
131                         } else {
132                                 if (freq <= suboptimal.frequency) {
133                                         suboptimal.frequency = freq;
134                                         suboptimal.index = i;
135                                 }
136                         }
137                         break;
138                 case CPUFREQ_RELATION_L:
139                         if (freq >= target_freq) {
140                                 if (freq <= optimal.frequency) {
141                                         optimal.frequency = freq;
142                                         optimal.index = i;
143                                 }
144                         } else {
145                                 if (freq >= suboptimal.frequency) {
146                                         suboptimal.frequency = freq;
147                                         suboptimal.index = i;
148                                 }
149                         }
150                         break;
151                 }
152         }
153         if (optimal.index > i) {
154                 if (suboptimal.index > i)
155                         return -EINVAL;
156                 *index = suboptimal.index;
157         } else
158                 *index = optimal.index;
159
160         dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
161                 table[*index].index);
162
163         return 0;
164 }
165 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
166
167 static struct cpufreq_frequency_table *show_table[NR_CPUS];
168 /**
169  * show_scaling_governor - show the current policy for the specified CPU
170  */
171 static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
172 {
173         unsigned int i = 0;
174         unsigned int cpu = policy->cpu;
175         ssize_t count = 0;
176         struct cpufreq_frequency_table *table;
177
178         if (!show_table[cpu])
179                 return -ENODEV;
180
181         table = show_table[cpu];
182
183         for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
184                 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
185                         continue;
186                 count += sprintf(&buf[count], "%d ", table[i].frequency);
187         }
188         count += sprintf(&buf[count], "\n");
189
190         return count;
191
192 }
193
194 struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
195         .attr = { .name = "scaling_available_frequencies", .mode = 0444, .owner=THIS_MODULE },
196         .show = show_available_freqs,
197 };
198 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
199
200 /*
201  * if you use these, you must assure that the frequency table is valid
202  * all the time between get_attr and put_attr!
203  */
204 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
205                                       unsigned int cpu)
206 {
207         dprintk("setting show_table for cpu %u to %p\n", cpu, table);
208         show_table[cpu] = table;
209 }
210 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
211
212 void cpufreq_frequency_table_put_attr(unsigned int cpu)
213 {
214         dprintk("clearing show_table for cpu %u\n", cpu);
215         show_table[cpu] = NULL;
216 }
217 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
218
219 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
220 {
221         return show_table[cpu];
222 }
223 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
224
225 MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
226 MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
227 MODULE_LICENSE ("GPL");