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