ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / i386 / kernel / cpu / cpufreq / acpi.c
1 /*
2  * acpi-cpufreq-io.c - ACPI Processor P-States Driver ($Revision: 1.3 $)
3  *
4  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6  *  Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
7  *
8  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or (at
13  *  your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License along
21  *  with this program; if not, write to the Free Software Foundation, Inc.,
22  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23  *
24  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25  */
26
27 #include <linux/config.h>
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/init.h>
31 #include <linux/cpufreq.h>
32 #include <linux/proc_fs.h>
33 #include <linux/seq_file.h>
34 #include <asm/io.h>
35 #include <asm/delay.h>
36 #include <asm/uaccess.h>
37
38 #include <linux/acpi.h>
39 #include <acpi/processor.h>
40
41 #define ACPI_PROCESSOR_COMPONENT        0x01000000
42 #define ACPI_PROCESSOR_CLASS            "processor"
43 #define ACPI_PROCESSOR_DRIVER_NAME      "ACPI Processor P-States Driver"
44 #define ACPI_PROCESSOR_DEVICE_NAME      "Processor"
45
46 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
47 ACPI_MODULE_NAME                ("acpi_processor_perf")
48
49 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
50 MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME);
51 MODULE_LICENSE("GPL");
52
53
54 struct cpufreq_acpi_io {
55         struct acpi_processor_performance       acpi_data;
56         struct cpufreq_frequency_table          *freq_table;
57 };
58
59 static struct cpufreq_acpi_io   *acpi_io_data[NR_CPUS];
60
61
62 static int
63 acpi_processor_write_port(
64         u16     port,
65         u8      bit_width,
66         u32     value)
67 {
68         if (bit_width <= 8) {
69                 outb(value, port);
70         } else if (bit_width <= 16) {
71                 outw(value, port);
72         } else if (bit_width <= 32) {
73                 outl(value, port);
74         } else {
75                 return -ENODEV;
76         }
77         return 0;
78 }
79
80 static int
81 acpi_processor_read_port(
82         u16     port,
83         u8      bit_width,
84         u32     *ret)
85 {
86         *ret = 0;
87         if (bit_width <= 8) {
88                 *ret = inb(port);
89         } else if (bit_width <= 16) {
90                 *ret = inw(port);
91         } else if (bit_width <= 32) {
92                 *ret = inl(port);
93         } else {
94                 return -ENODEV;
95         }
96         return 0;
97 }
98
99 static int
100 acpi_processor_set_performance (
101         struct cpufreq_acpi_io  *data,
102         unsigned int            cpu,
103         int                     state)
104 {
105         u16                     port = 0;
106         u8                      bit_width = 0;
107         int                     ret = 0;
108         u32                     value = 0;
109         int                     i = 0;
110         struct cpufreq_freqs    cpufreq_freqs;
111
112         ACPI_FUNCTION_TRACE("acpi_processor_set_performance");
113
114         if (state == data->acpi_data.state) {
115                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
116                         "Already at target state (P%d)\n", state));
117                 return_VALUE(0);
118         }
119
120         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n",
121                 data->acpi_data.state, state));
122
123         /* cpufreq frequency struct */
124         cpufreq_freqs.cpu = cpu;
125         cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
126         cpufreq_freqs.new = data->freq_table[state].frequency;
127
128         /* notify cpufreq */
129         cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
130
131         /*
132          * First we write the target state's 'control' value to the
133          * control_register.
134          */
135
136         port = data->acpi_data.control_register.address;
137         bit_width = data->acpi_data.control_register.bit_width;
138         value = (u32) data->acpi_data.states[state].control;
139
140         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
141                 "Writing 0x%08x to port 0x%04x\n", value, port));
142
143         ret = acpi_processor_write_port(port, bit_width, value);
144         if (ret) {
145                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
146                         "Invalid port width 0x%04x\n", bit_width));
147                 return_VALUE(ret);
148         }
149
150         /*
151          * Then we read the 'status_register' and compare the value with the
152          * target state's 'status' to make sure the transition was successful.
153          * Note that we'll poll for up to 1ms (100 cycles of 10us) before
154          * giving up.
155          */
156
157         port = data->acpi_data.status_register.address;
158         bit_width = data->acpi_data.status_register.bit_width;
159
160         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
161                 "Looking for 0x%08x from port 0x%04x\n",
162                 (u32) data->acpi_data.states[state].status, port));
163
164         for (i=0; i<100; i++) {
165                 ret = acpi_processor_read_port(port, bit_width, &value);
166                 if (ret) {      
167                         ACPI_DEBUG_PRINT((ACPI_DB_WARN,
168                                 "Invalid port width 0x%04x\n", bit_width));
169                         return_VALUE(ret);
170                 }
171                 if (value == (u32) data->acpi_data.states[state].status)
172                         break;
173                 udelay(10);
174         }
175
176         /* notify cpufreq */
177         cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
178
179         if (value != (u32) data->acpi_data.states[state].status) {
180                 unsigned int tmp = cpufreq_freqs.new;
181                 cpufreq_freqs.new = cpufreq_freqs.old;
182                 cpufreq_freqs.old = tmp;
183                 cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
184                 cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
185                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Transition failed\n"));
186                 return_VALUE(-ENODEV);
187         }
188
189         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
190                 "Transition successful after %d microseconds\n",
191                 i * 10));
192
193         data->acpi_data.state = state;
194
195         return_VALUE(0);
196 }
197
198
199 static int
200 acpi_cpufreq_target (
201         struct cpufreq_policy   *policy,
202         unsigned int target_freq,
203         unsigned int relation)
204 {
205         struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
206         unsigned int next_state = 0;
207         unsigned int result = 0;
208
209         ACPI_FUNCTION_TRACE("acpi_cpufreq_setpolicy");
210
211         result = cpufreq_frequency_table_target(policy,
212                         data->freq_table,
213                         target_freq,
214                         relation,
215                         &next_state);
216         if (result)
217                 return_VALUE(result);
218
219         result = acpi_processor_set_performance (data, policy->cpu, next_state);
220
221         return_VALUE(result);
222 }
223
224
225 static int
226 acpi_cpufreq_verify (
227         struct cpufreq_policy   *policy)
228 {
229         unsigned int result = 0;
230         struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
231
232         ACPI_FUNCTION_TRACE("acpi_cpufreq_verify");
233
234         result = cpufreq_frequency_table_verify(policy, 
235                         data->freq_table);
236
237         return_VALUE(result);
238 }
239
240
241 static unsigned long
242 acpi_cpufreq_guess_freq (
243         struct cpufreq_acpi_io  *data,
244         unsigned int            cpu)
245 {
246         if (cpu_khz) {
247                 /* search the closest match to cpu_khz */
248                 unsigned int i;
249                 unsigned long freq;
250                 unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000;
251
252                 for (i=0; i < (data->acpi_data.state_count - 1); i++) {
253                         freq = freqn;
254                         freqn = data->acpi_data.states[i+1].core_frequency * 1000;
255                         if ((2 * cpu_khz) > (freqn + freq)) {
256                                 data->acpi_data.state = i;
257                                 return (freq);
258                         }
259                 }
260                 data->acpi_data.state = data->acpi_data.state_count - 1;
261                 return (freqn);
262         } else
263                 /* assume CPU is at P0... */
264                 data->acpi_data.state = 0;
265                 return data->acpi_data.states[0].core_frequency * 1000;
266         
267 }
268
269 static int
270 acpi_cpufreq_cpu_init (
271         struct cpufreq_policy   *policy)
272 {
273         unsigned int            i;
274         unsigned int            cpu = policy->cpu;
275         struct cpufreq_acpi_io  *data;
276         unsigned int            result = 0;
277
278         ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init");
279
280         data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
281         if (!data)
282                 return_VALUE(-ENOMEM);
283         memset(data, 0, sizeof(struct cpufreq_acpi_io));
284
285         acpi_io_data[cpu] = data;
286
287         result = acpi_processor_register_performance(&data->acpi_data, cpu);
288         if (result)
289                 goto err_free;
290
291         /* capability check */
292         if (data->acpi_data.state_count <= 1) {
293                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No P-States\n"));
294                 result = -ENODEV;
295                 goto err_unreg;
296         }
297         if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
298             (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
299                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported address space [%d, %d]\n",
300                                   (u32) (data->acpi_data.control_register.space_id),
301                                   (u32) (data->acpi_data.status_register.space_id)));
302                 result = -ENODEV;
303                 goto err_unreg;
304         }
305
306         /* alloc freq_table */
307         data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL);
308         if (!data->freq_table) {
309                 result = -ENOMEM;
310                 goto err_unreg;
311         }
312
313         /* detect transition latency */
314         policy->cpuinfo.transition_latency = 0;
315         for (i=0; i<data->acpi_data.state_count; i++) {
316                 if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
317                         policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000;
318         }
319         policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
320
321         /* The current speed is unknown and not detectable by ACPI...  */
322         policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
323
324         /* table init */
325         for (i=0; i<=data->acpi_data.state_count; i++)
326         {
327                 data->freq_table[i].index = i;
328                 if (i<data->acpi_data.state_count)
329                         data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000;
330                 else
331                         data->freq_table[i].frequency = CPUFREQ_TABLE_END;
332         }
333
334         result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
335         if (result) {
336                 goto err_freqfree;
337         }
338                 
339
340         printk(KERN_INFO "cpufreq: CPU%u - ACPI performance management activated.\n",
341                cpu);
342         for (i = 0; i < data->acpi_data.state_count; i++)
343                 printk(KERN_INFO "cpufreq: %cP%d: %d MHz, %d mW, %d uS\n",
344                         (i == data->acpi_data.state?'*':' '), i,
345                         (u32) data->acpi_data.states[i].core_frequency,
346                         (u32) data->acpi_data.states[i].power,
347                         (u32) data->acpi_data.states[i].transition_latency);
348
349         cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
350         return_VALUE(result);
351
352  err_freqfree:
353         kfree(data->freq_table);
354  err_unreg:
355         acpi_processor_unregister_performance(&data->acpi_data, cpu);
356  err_free:
357         kfree(data);
358         acpi_io_data[cpu] = NULL;
359
360         return_VALUE(result);
361 }
362
363
364 static int
365 acpi_cpufreq_cpu_exit (
366         struct cpufreq_policy   *policy)
367 {
368         struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
369
370
371         ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit");
372
373         if (data) {
374                 cpufreq_frequency_table_put_attr(policy->cpu);
375                 acpi_io_data[policy->cpu] = NULL;
376                 acpi_processor_unregister_performance(&data->acpi_data, policy->cpu);
377                 kfree(data);
378         }
379
380         return_VALUE(0);
381 }
382
383
384 static struct freq_attr* acpi_cpufreq_attr[] = {
385         &cpufreq_freq_attr_scaling_available_freqs,
386         NULL,
387 };
388
389 static struct cpufreq_driver acpi_cpufreq_driver = {
390         .verify         = acpi_cpufreq_verify,
391         .target         = acpi_cpufreq_target,
392         .init           = acpi_cpufreq_cpu_init,
393         .exit           = acpi_cpufreq_cpu_exit,
394         .name           = "acpi-cpufreq",
395         .owner          = THIS_MODULE,
396         .attr           = acpi_cpufreq_attr,
397 };
398
399
400 static int __init
401 acpi_cpufreq_init (void)
402 {
403         int                     result = 0;
404
405         ACPI_FUNCTION_TRACE("acpi_cpufreq_init");
406
407         result = cpufreq_register_driver(&acpi_cpufreq_driver);
408         
409         return_VALUE(result);
410 }
411
412
413 static void __exit
414 acpi_cpufreq_exit (void)
415 {
416         ACPI_FUNCTION_TRACE("acpi_cpufreq_exit");
417
418         cpufreq_unregister_driver(&acpi_cpufreq_driver);
419
420         return_VOID;
421 }
422
423
424 late_initcall(acpi_cpufreq_init);
425 module_exit(acpi_cpufreq_exit);