vserver 1.9.3
[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         cpumask_t               saved_mask;
112         int                     retval;
113
114         ACPI_FUNCTION_TRACE("acpi_processor_set_performance");
115
116         /*
117          * TBD: Use something other than set_cpus_allowed.
118          * As set_cpus_allowed is a bit racy, 
119          * with any other set_cpus_allowed for this process.
120          */
121         saved_mask = current->cpus_allowed;
122         set_cpus_allowed(current, cpumask_of_cpu(cpu));
123         if (smp_processor_id() != cpu) {
124                 return_VALUE(-EAGAIN);
125         }
126         
127         if (state == data->acpi_data.state) {
128                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
129                         "Already at target state (P%d)\n", state));
130                 retval = 0;
131                 goto migrate_end;
132         }
133
134         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n",
135                 data->acpi_data.state, state));
136
137         /* cpufreq frequency struct */
138         cpufreq_freqs.cpu = cpu;
139         cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
140         cpufreq_freqs.new = data->freq_table[state].frequency;
141
142         /* notify cpufreq */
143         cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
144
145         /*
146          * First we write the target state's 'control' value to the
147          * control_register.
148          */
149
150         port = data->acpi_data.control_register.address;
151         bit_width = data->acpi_data.control_register.bit_width;
152         value = (u32) data->acpi_data.states[state].control;
153
154         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
155                 "Writing 0x%08x to port 0x%04x\n", value, port));
156
157         ret = acpi_processor_write_port(port, bit_width, value);
158         if (ret) {
159                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
160                         "Invalid port width 0x%04x\n", bit_width));
161                 retval = ret;
162                 goto migrate_end;
163         }
164
165         /*
166          * Then we read the 'status_register' and compare the value with the
167          * target state's 'status' to make sure the transition was successful.
168          * Note that we'll poll for up to 1ms (100 cycles of 10us) before
169          * giving up.
170          */
171
172         port = data->acpi_data.status_register.address;
173         bit_width = data->acpi_data.status_register.bit_width;
174
175         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
176                 "Looking for 0x%08x from port 0x%04x\n",
177                 (u32) data->acpi_data.states[state].status, port));
178
179         for (i=0; i<100; i++) {
180                 ret = acpi_processor_read_port(port, bit_width, &value);
181                 if (ret) {      
182                         ACPI_DEBUG_PRINT((ACPI_DB_WARN,
183                                 "Invalid port width 0x%04x\n", bit_width));
184                         retval = ret;
185                         goto migrate_end;
186                 }
187                 if (value == (u32) data->acpi_data.states[state].status)
188                         break;
189                 udelay(10);
190         }
191
192         /* notify cpufreq */
193         cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
194
195         if (value != (u32) data->acpi_data.states[state].status) {
196                 unsigned int tmp = cpufreq_freqs.new;
197                 cpufreq_freqs.new = cpufreq_freqs.old;
198                 cpufreq_freqs.old = tmp;
199                 cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
200                 cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
201                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Transition failed\n"));
202                 retval = -ENODEV;
203                 goto migrate_end;
204         }
205
206         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
207                 "Transition successful after %d microseconds\n",
208                 i * 10));
209
210         data->acpi_data.state = state;
211
212         retval = 0;
213 migrate_end:
214         set_cpus_allowed(current, saved_mask);
215         return_VALUE(retval);
216 }
217
218
219 static int
220 acpi_cpufreq_target (
221         struct cpufreq_policy   *policy,
222         unsigned int target_freq,
223         unsigned int relation)
224 {
225         struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
226         unsigned int next_state = 0;
227         unsigned int result = 0;
228
229         ACPI_FUNCTION_TRACE("acpi_cpufreq_setpolicy");
230
231         result = cpufreq_frequency_table_target(policy,
232                         data->freq_table,
233                         target_freq,
234                         relation,
235                         &next_state);
236         if (result)
237                 return_VALUE(result);
238
239         result = acpi_processor_set_performance (data, policy->cpu, next_state);
240
241         return_VALUE(result);
242 }
243
244
245 static int
246 acpi_cpufreq_verify (
247         struct cpufreq_policy   *policy)
248 {
249         unsigned int result = 0;
250         struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
251
252         ACPI_FUNCTION_TRACE("acpi_cpufreq_verify");
253
254         result = cpufreq_frequency_table_verify(policy, 
255                         data->freq_table);
256
257         return_VALUE(result);
258 }
259
260
261 static unsigned long
262 acpi_cpufreq_guess_freq (
263         struct cpufreq_acpi_io  *data,
264         unsigned int            cpu)
265 {
266         if (cpu_khz) {
267                 /* search the closest match to cpu_khz */
268                 unsigned int i;
269                 unsigned long freq;
270                 unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000;
271
272                 for (i=0; i < (data->acpi_data.state_count - 1); i++) {
273                         freq = freqn;
274                         freqn = data->acpi_data.states[i+1].core_frequency * 1000;
275                         if ((2 * cpu_khz) > (freqn + freq)) {
276                                 data->acpi_data.state = i;
277                                 return (freq);
278                         }
279                 }
280                 data->acpi_data.state = data->acpi_data.state_count - 1;
281                 return (freqn);
282         } else
283                 /* assume CPU is at P0... */
284                 data->acpi_data.state = 0;
285                 return data->acpi_data.states[0].core_frequency * 1000;
286         
287 }
288
289
290 /* 
291  * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities
292  * of this driver
293  * @perf: processor-specific acpi_io_data struct
294  * @cpu: CPU being initialized
295  *
296  * To avoid issues with legacy OSes, some BIOSes require to be informed of
297  * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC 
298  * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in
299  * driver/acpi/processor.c
300  */
301 static void 
302 acpi_processor_cpu_init_pdc_est(
303                 struct acpi_processor_performance *perf, 
304                 unsigned int cpu,
305                 struct acpi_object_list *obj_list
306                 )
307 {
308         union acpi_object *obj;
309         u32 *buf;
310         struct cpuinfo_x86 *c = cpu_data + cpu;
311         ACPI_FUNCTION_TRACE("acpi_processor_cpu_init_pdc_est");
312
313         if (!cpu_has(c, X86_FEATURE_EST))
314                 return_VOID;
315
316         /* Initialize pdc. It will be used later. */
317         if (!obj_list)
318                 return_VOID;
319                 
320         if (!(obj_list->count && obj_list->pointer))
321                 return_VOID;
322
323         obj = obj_list->pointer;
324         if ((obj->buffer.length == 12) && obj->buffer.pointer) {
325                 buf = (u32 *)obj->buffer.pointer;
326                 buf[0] = ACPI_PDC_REVISION_ID;
327                 buf[1] = 1;
328                 buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
329                 perf->pdc = obj_list;
330         }
331         return_VOID;
332 }
333  
334
335 /* CPU specific PDC initialization */
336 static void 
337 acpi_processor_cpu_init_pdc(
338                 struct acpi_processor_performance *perf, 
339                 unsigned int cpu,
340                 struct acpi_object_list *obj_list
341                 )
342 {
343         struct cpuinfo_x86 *c = cpu_data + cpu;
344         ACPI_FUNCTION_TRACE("acpi_processor_cpu_init_pdc");
345         perf->pdc = NULL;
346         if (cpu_has(c, X86_FEATURE_EST))
347                 acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list);
348         return_VOID;
349 }
350
351
352 static int
353 acpi_cpufreq_cpu_init (
354         struct cpufreq_policy   *policy)
355 {
356         unsigned int            i;
357         unsigned int            cpu = policy->cpu;
358         struct cpufreq_acpi_io  *data;
359         unsigned int            result = 0;
360
361         union acpi_object               arg0 = {ACPI_TYPE_BUFFER};
362         u32                             arg0_buf[3];
363         struct acpi_object_list         arg_list = {1, &arg0};
364
365         ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init");
366         /* setup arg_list for _PDC settings */
367         arg0.buffer.length = 12;
368         arg0.buffer.pointer = (u8 *) arg0_buf;
369
370         data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
371         if (!data)
372                 return_VALUE(-ENOMEM);
373         memset(data, 0, sizeof(struct cpufreq_acpi_io));
374
375         acpi_io_data[cpu] = data;
376
377         acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list);
378         result = acpi_processor_register_performance(&data->acpi_data, cpu);
379         data->acpi_data.pdc = NULL;
380
381         if (result)
382                 goto err_free;
383
384         /* capability check */
385         if (data->acpi_data.state_count <= 1) {
386                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No P-States\n"));
387                 result = -ENODEV;
388                 goto err_unreg;
389         }
390         if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
391             (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
392                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported address space [%d, %d]\n",
393                                   (u32) (data->acpi_data.control_register.space_id),
394                                   (u32) (data->acpi_data.status_register.space_id)));
395                 result = -ENODEV;
396                 goto err_unreg;
397         }
398
399         /* alloc freq_table */
400         data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL);
401         if (!data->freq_table) {
402                 result = -ENOMEM;
403                 goto err_unreg;
404         }
405
406         /* detect transition latency */
407         policy->cpuinfo.transition_latency = 0;
408         for (i=0; i<data->acpi_data.state_count; i++) {
409                 if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
410                         policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000;
411         }
412         policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
413
414         /* The current speed is unknown and not detectable by ACPI...  */
415         policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
416
417         /* table init */
418         for (i=0; i<=data->acpi_data.state_count; i++)
419         {
420                 data->freq_table[i].index = i;
421                 if (i<data->acpi_data.state_count)
422                         data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000;
423                 else
424                         data->freq_table[i].frequency = CPUFREQ_TABLE_END;
425         }
426
427         result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
428         if (result) {
429                 goto err_freqfree;
430         }
431                 
432
433         printk(KERN_INFO "cpufreq: CPU%u - ACPI performance management activated.\n",
434                cpu);
435         for (i = 0; i < data->acpi_data.state_count; i++)
436                 printk(KERN_INFO "cpufreq: %cP%d: %d MHz, %d mW, %d uS\n",
437                         (i == data->acpi_data.state?'*':' '), i,
438                         (u32) data->acpi_data.states[i].core_frequency,
439                         (u32) data->acpi_data.states[i].power,
440                         (u32) data->acpi_data.states[i].transition_latency);
441
442         cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
443         return_VALUE(result);
444
445  err_freqfree:
446         kfree(data->freq_table);
447  err_unreg:
448         acpi_processor_unregister_performance(&data->acpi_data, cpu);
449  err_free:
450         kfree(data);
451         acpi_io_data[cpu] = NULL;
452
453         return_VALUE(result);
454 }
455
456
457 static int
458 acpi_cpufreq_cpu_exit (
459         struct cpufreq_policy   *policy)
460 {
461         struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
462
463
464         ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit");
465
466         if (data) {
467                 cpufreq_frequency_table_put_attr(policy->cpu);
468                 acpi_io_data[policy->cpu] = NULL;
469                 acpi_processor_unregister_performance(&data->acpi_data, policy->cpu);
470                 kfree(data);
471         }
472
473         return_VALUE(0);
474 }
475
476
477 static struct freq_attr* acpi_cpufreq_attr[] = {
478         &cpufreq_freq_attr_scaling_available_freqs,
479         NULL,
480 };
481
482 static struct cpufreq_driver acpi_cpufreq_driver = {
483         .verify         = acpi_cpufreq_verify,
484         .target         = acpi_cpufreq_target,
485         .init           = acpi_cpufreq_cpu_init,
486         .exit           = acpi_cpufreq_cpu_exit,
487         .name           = "acpi-cpufreq",
488         .owner          = THIS_MODULE,
489         .attr           = acpi_cpufreq_attr,
490 };
491
492
493 static int __init
494 acpi_cpufreq_init (void)
495 {
496         int                     result = 0;
497
498         ACPI_FUNCTION_TRACE("acpi_cpufreq_init");
499
500         result = cpufreq_register_driver(&acpi_cpufreq_driver);
501         
502         return_VALUE(result);
503 }
504
505
506 static void __exit
507 acpi_cpufreq_exit (void)
508 {
509         ACPI_FUNCTION_TRACE("acpi_cpufreq_exit");
510
511         cpufreq_unregister_driver(&acpi_cpufreq_driver);
512
513         return_VOID;
514 }
515
516
517 late_initcall(acpi_cpufreq_init);
518 module_exit(acpi_cpufreq_exit);