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