vserver 1.9.5.x5
[linux-2.6.git] / 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 = 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");