Rev 775 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
582 | mauro | 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 | */ |
||
770 | mauro | 154 | /*static*/ ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf) |
582 | mauro | 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 += sprintf26(&buf[count], "%d ", table[i].frequency); |
||
170 | } |
||
171 | |||
172 | return count; |
||
173 | |||
174 | } |
||
175 | |||
775 | mauro | 176 | int get_available_freqs (struct cpufreq_policy *policy, int *buf) |
177 | { |
||
178 | unsigned int i = 0; |
||
179 | unsigned int cpu = policy->cpu; |
||
180 | ssize_t count = 0; |
||
181 | struct cpufreq_frequency_table *table; |
||
182 | |||
183 | if (!show_table[cpu]) |
||
184 | return -ENODEV; |
||
185 | |||
186 | table = show_table[cpu]; |
||
187 | |||
188 | for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { |
||
189 | if (table[i].frequency == CPUFREQ_ENTRY_INVALID) |
||
190 | continue; |
||
191 | buf[count] = table[i].frequency; |
||
192 | count++; |
||
193 | } |
||
194 | |||
195 | return count; |
||
196 | |||
197 | } |
||
198 | |||
582 | mauro | 199 | struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { |
200 | .attr = { .name = "scaling_available_frequencies", .mode = 0444 }, |
||
201 | .show = show_available_freqs, |
||
202 | }; |
||
203 | EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); |
||
204 | |||
205 | /* |
||
206 | * if you use these, you must assure that the frequency table is valid |
||
207 | * all the time between get_attr and put_attr! |
||
208 | */ |
||
209 | void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, |
||
210 | unsigned int cpu) |
||
211 | { |
||
212 | show_table[cpu] = table; |
||
213 | } |
||
214 | EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); |
||
215 | |||
216 | void cpufreq_frequency_table_put_attr(unsigned int cpu) |
||
217 | { |
||
218 | show_table[cpu] = NULL; |
||
219 | } |
||
220 | EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); |
||
221 | |||
222 | |||
223 | MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>"); |
||
224 | MODULE_DESCRIPTION ("CPUfreq frequency table helpers"); |
||
225 | MODULE_LICENSE ("GPL"); |