2 * acpi-cpufreq-io.c - ACPI Processor P-States Driver ($Revision: 1.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>
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
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.
24 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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>
35 #include <asm/delay.h>
36 #include <asm/uaccess.h>
38 #include <linux/acpi.h>
39 #include <acpi/processor.h>
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"
46 #define _COMPONENT ACPI_PROCESSOR_COMPONENT
47 ACPI_MODULE_NAME ("acpi_processor_perf")
49 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
50 MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME);
51 MODULE_LICENSE("GPL");
54 struct cpufreq_acpi_io {
55 struct acpi_processor_performance acpi_data;
56 struct cpufreq_frequency_table *freq_table;
59 static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
63 acpi_processor_write_port(
70 } else if (bit_width <= 16) {
72 } else if (bit_width <= 32) {
81 acpi_processor_read_port(
89 } else if (bit_width <= 16) {
91 } else if (bit_width <= 32) {
100 acpi_processor_set_performance (
101 struct cpufreq_acpi_io *data,
110 struct cpufreq_freqs cpufreq_freqs;
112 ACPI_FUNCTION_TRACE("acpi_processor_set_performance");
114 if (state == data->acpi_data.state) {
115 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
116 "Already at target state (P%d)\n", state));
120 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n",
121 data->acpi_data.state, state));
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;
129 cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
132 * First we write the target state's 'control' value to the
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;
140 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
141 "Writing 0x%08x to port 0x%04x\n", value, port));
143 ret = acpi_processor_write_port(port, bit_width, value);
145 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
146 "Invalid port width 0x%04x\n", bit_width));
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
157 port = data->acpi_data.status_register.address;
158 bit_width = data->acpi_data.status_register.bit_width;
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));
164 for (i=0; i<100; i++) {
165 ret = acpi_processor_read_port(port, bit_width, &value);
167 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
168 "Invalid port width 0x%04x\n", bit_width));
171 if (value == (u32) data->acpi_data.states[state].status)
177 cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
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);
189 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
190 "Transition successful after %d microseconds\n",
193 data->acpi_data.state = state;
200 acpi_cpufreq_target (
201 struct cpufreq_policy *policy,
202 unsigned int target_freq,
203 unsigned int relation)
205 struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
206 unsigned int next_state = 0;
207 unsigned int result = 0;
209 ACPI_FUNCTION_TRACE("acpi_cpufreq_setpolicy");
211 result = cpufreq_frequency_table_target(policy,
217 return_VALUE(result);
219 result = acpi_processor_set_performance (data, policy->cpu, next_state);
221 return_VALUE(result);
226 acpi_cpufreq_verify (
227 struct cpufreq_policy *policy)
229 unsigned int result = 0;
230 struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
232 ACPI_FUNCTION_TRACE("acpi_cpufreq_verify");
234 result = cpufreq_frequency_table_verify(policy,
237 return_VALUE(result);
242 acpi_cpufreq_guess_freq (
243 struct cpufreq_acpi_io *data,
247 /* search the closest match to cpu_khz */
250 unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000;
252 for (i=0; i < (data->acpi_data.state_count - 1); i++) {
254 freqn = data->acpi_data.states[i+1].core_frequency * 1000;
255 if ((2 * cpu_khz) > (freqn + freq)) {
256 data->acpi_data.state = i;
260 data->acpi_data.state = data->acpi_data.state_count - 1;
263 /* assume CPU is at P0... */
264 data->acpi_data.state = 0;
265 return data->acpi_data.states[0].core_frequency * 1000;
270 acpi_cpufreq_cpu_init (
271 struct cpufreq_policy *policy)
274 unsigned int cpu = policy->cpu;
275 struct cpufreq_acpi_io *data;
276 unsigned int result = 0;
278 ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init");
280 data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
282 return_VALUE(-ENOMEM);
283 memset(data, 0, sizeof(struct cpufreq_acpi_io));
285 acpi_io_data[cpu] = data;
287 result = acpi_processor_register_performance(&data->acpi_data, cpu);
291 /* capability check */
292 if (data->acpi_data.state_count <= 1) {
293 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No P-States\n"));
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)));
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) {
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;
319 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
321 /* The current speed is unknown and not detectable by ACPI... */
322 policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
325 for (i=0; i<=data->acpi_data.state_count; i++)
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;
331 data->freq_table[i].frequency = CPUFREQ_TABLE_END;
334 result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
340 printk(KERN_INFO "cpufreq: CPU%u - ACPI performance management activated.\n",
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);
349 cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
350 return_VALUE(result);
353 kfree(data->freq_table);
355 acpi_processor_unregister_performance(&data->acpi_data, cpu);
358 acpi_io_data[cpu] = NULL;
360 return_VALUE(result);
365 acpi_cpufreq_cpu_exit (
366 struct cpufreq_policy *policy)
368 struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
371 ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit");
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);
384 static struct freq_attr* acpi_cpufreq_attr[] = {
385 &cpufreq_freq_attr_scaling_available_freqs,
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,
401 acpi_cpufreq_init (void)
405 ACPI_FUNCTION_TRACE("acpi_cpufreq_init");
407 result = cpufreq_register_driver(&acpi_cpufreq_driver);
409 return_VALUE(result);
414 acpi_cpufreq_exit (void)
416 ACPI_FUNCTION_TRACE("acpi_cpufreq_exit");
418 cpufreq_unregister_driver(&acpi_cpufreq_driver);
424 late_initcall(acpi_cpufreq_init);
425 module_exit(acpi_cpufreq_exit);