diff options
Diffstat (limited to 'arch/x86/kernel/cpu/cpufreq')
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/Kconfig | 14 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 50 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/elanfreq.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/gx-suspmod.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/longhaul.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/longrun.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/p4-clockmod.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c | 621 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/powernow-k6.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/powernow-k7.c | 19 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 44 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-ich.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-lib.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-lib.h | 24 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-smi.c | 3 |
17 files changed, 721 insertions, 75 deletions
diff --git a/arch/x86/kernel/cpu/cpufreq/Kconfig b/arch/x86/kernel/cpu/cpufreq/Kconfig index f138c6c389b9..870e6cc6ad28 100644 --- a/arch/x86/kernel/cpu/cpufreq/Kconfig +++ b/arch/x86/kernel/cpu/cpufreq/Kconfig | |||
@@ -10,6 +10,20 @@ if CPU_FREQ | |||
10 | 10 | ||
11 | comment "CPUFreq processor drivers" | 11 | comment "CPUFreq processor drivers" |
12 | 12 | ||
13 | config X86_PCC_CPUFREQ | ||
14 | tristate "Processor Clocking Control interface driver" | ||
15 | depends on ACPI && ACPI_PROCESSOR | ||
16 | help | ||
17 | This driver adds support for the PCC interface. | ||
18 | |||
19 | For details, take a look at: | ||
20 | <file:Documentation/cpu-freq/pcc-cpufreq.txt>. | ||
21 | |||
22 | To compile this driver as a module, choose M here: the | ||
23 | module will be called pcc-cpufreq. | ||
24 | |||
25 | If in doubt, say N. | ||
26 | |||
13 | config X86_ACPI_CPUFREQ | 27 | config X86_ACPI_CPUFREQ |
14 | tristate "ACPI Processor P-States driver" | 28 | tristate "ACPI Processor P-States driver" |
15 | select CPU_FREQ_TABLE | 29 | select CPU_FREQ_TABLE |
diff --git a/arch/x86/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile index 509296df294d..1840c0a5170b 100644 --- a/arch/x86/kernel/cpu/cpufreq/Makefile +++ b/arch/x86/kernel/cpu/cpufreq/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o | 5 | obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o |
6 | obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o | 6 | obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o |
7 | obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o | ||
7 | obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o | 8 | obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o |
8 | obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o | 9 | obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o |
9 | obj-$(CONFIG_X86_LONGHAUL) += longhaul.o | 10 | obj-$(CONFIG_X86_LONGHAUL) += longhaul.o |
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 8b581d3905cb..459168083b77 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/cpufreq.h> | 33 | #include <linux/cpufreq.h> |
34 | #include <linux/compiler.h> | 34 | #include <linux/compiler.h> |
35 | #include <linux/dmi.h> | 35 | #include <linux/dmi.h> |
36 | #include <linux/slab.h> | ||
36 | #include <trace/events/power.h> | 37 | #include <trace/events/power.h> |
37 | 38 | ||
38 | #include <linux/acpi.h> | 39 | #include <linux/acpi.h> |
@@ -68,9 +69,9 @@ struct acpi_cpufreq_data { | |||
68 | unsigned int cpu_feature; | 69 | unsigned int cpu_feature; |
69 | }; | 70 | }; |
70 | 71 | ||
71 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data); | 72 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); |
72 | 73 | ||
73 | static DEFINE_PER_CPU(struct aperfmperf, old_perf); | 74 | static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf); |
74 | 75 | ||
75 | /* acpi_perf_data is a pointer to percpu data. */ | 76 | /* acpi_perf_data is a pointer to percpu data. */ |
76 | static struct acpi_processor_performance *acpi_perf_data; | 77 | static struct acpi_processor_performance *acpi_perf_data; |
@@ -190,9 +191,11 @@ static void do_drv_write(void *_cmd) | |||
190 | 191 | ||
191 | static void drv_read(struct drv_cmd *cmd) | 192 | static void drv_read(struct drv_cmd *cmd) |
192 | { | 193 | { |
194 | int err; | ||
193 | cmd->val = 0; | 195 | cmd->val = 0; |
194 | 196 | ||
195 | smp_call_function_single(cpumask_any(cmd->mask), do_drv_read, cmd, 1); | 197 | err = smp_call_function_any(cmd->mask, do_drv_read, cmd, 1); |
198 | WARN_ON_ONCE(err); /* smp_call_function_any() was buggy? */ | ||
196 | } | 199 | } |
197 | 200 | ||
198 | static void drv_write(struct drv_cmd *cmd) | 201 | static void drv_write(struct drv_cmd *cmd) |
@@ -214,14 +217,14 @@ static u32 get_cur_val(const struct cpumask *mask) | |||
214 | if (unlikely(cpumask_empty(mask))) | 217 | if (unlikely(cpumask_empty(mask))) |
215 | return 0; | 218 | return 0; |
216 | 219 | ||
217 | switch (per_cpu(drv_data, cpumask_first(mask))->cpu_feature) { | 220 | switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) { |
218 | case SYSTEM_INTEL_MSR_CAPABLE: | 221 | case SYSTEM_INTEL_MSR_CAPABLE: |
219 | cmd.type = SYSTEM_INTEL_MSR_CAPABLE; | 222 | cmd.type = SYSTEM_INTEL_MSR_CAPABLE; |
220 | cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; | 223 | cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; |
221 | break; | 224 | break; |
222 | case SYSTEM_IO_CAPABLE: | 225 | case SYSTEM_IO_CAPABLE: |
223 | cmd.type = SYSTEM_IO_CAPABLE; | 226 | cmd.type = SYSTEM_IO_CAPABLE; |
224 | perf = per_cpu(drv_data, cpumask_first(mask))->acpi_data; | 227 | perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data; |
225 | cmd.addr.io.port = perf->control_register.address; | 228 | cmd.addr.io.port = perf->control_register.address; |
226 | cmd.addr.io.bit_width = perf->control_register.bit_width; | 229 | cmd.addr.io.bit_width = perf->control_register.bit_width; |
227 | break; | 230 | break; |
@@ -268,8 +271,8 @@ static unsigned int get_measured_perf(struct cpufreq_policy *policy, | |||
268 | if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) | 271 | if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) |
269 | return 0; | 272 | return 0; |
270 | 273 | ||
271 | ratio = calc_aperfmperf_ratio(&per_cpu(old_perf, cpu), &perf); | 274 | ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf); |
272 | per_cpu(old_perf, cpu) = perf; | 275 | per_cpu(acfreq_old_perf, cpu) = perf; |
273 | 276 | ||
274 | retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; | 277 | retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; |
275 | 278 | ||
@@ -278,7 +281,7 @@ static unsigned int get_measured_perf(struct cpufreq_policy *policy, | |||
278 | 281 | ||
279 | static unsigned int get_cur_freq_on_cpu(unsigned int cpu) | 282 | static unsigned int get_cur_freq_on_cpu(unsigned int cpu) |
280 | { | 283 | { |
281 | struct acpi_cpufreq_data *data = per_cpu(drv_data, cpu); | 284 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu); |
282 | unsigned int freq; | 285 | unsigned int freq; |
283 | unsigned int cached_freq; | 286 | unsigned int cached_freq; |
284 | 287 | ||
@@ -322,7 +325,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, | |||
322 | static int acpi_cpufreq_target(struct cpufreq_policy *policy, | 325 | static int acpi_cpufreq_target(struct cpufreq_policy *policy, |
323 | unsigned int target_freq, unsigned int relation) | 326 | unsigned int target_freq, unsigned int relation) |
324 | { | 327 | { |
325 | struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); | 328 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); |
326 | struct acpi_processor_performance *perf; | 329 | struct acpi_processor_performance *perf; |
327 | struct cpufreq_freqs freqs; | 330 | struct cpufreq_freqs freqs; |
328 | struct drv_cmd cmd; | 331 | struct drv_cmd cmd; |
@@ -416,7 +419,7 @@ out: | |||
416 | 419 | ||
417 | static int acpi_cpufreq_verify(struct cpufreq_policy *policy) | 420 | static int acpi_cpufreq_verify(struct cpufreq_policy *policy) |
418 | { | 421 | { |
419 | struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); | 422 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); |
420 | 423 | ||
421 | dprintk("acpi_cpufreq_verify\n"); | 424 | dprintk("acpi_cpufreq_verify\n"); |
422 | 425 | ||
@@ -574,7 +577,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
574 | return -ENOMEM; | 577 | return -ENOMEM; |
575 | 578 | ||
576 | data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); | 579 | data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); |
577 | per_cpu(drv_data, cpu) = data; | 580 | per_cpu(acfreq_data, cpu) = data; |
578 | 581 | ||
579 | if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) | 582 | if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) |
580 | acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; | 583 | acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; |
@@ -725,20 +728,20 @@ err_unreg: | |||
725 | acpi_processor_unregister_performance(perf, cpu); | 728 | acpi_processor_unregister_performance(perf, cpu); |
726 | err_free: | 729 | err_free: |
727 | kfree(data); | 730 | kfree(data); |
728 | per_cpu(drv_data, cpu) = NULL; | 731 | per_cpu(acfreq_data, cpu) = NULL; |
729 | 732 | ||
730 | return result; | 733 | return result; |
731 | } | 734 | } |
732 | 735 | ||
733 | static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) | 736 | static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) |
734 | { | 737 | { |
735 | struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); | 738 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); |
736 | 739 | ||
737 | dprintk("acpi_cpufreq_cpu_exit\n"); | 740 | dprintk("acpi_cpufreq_cpu_exit\n"); |
738 | 741 | ||
739 | if (data) { | 742 | if (data) { |
740 | cpufreq_frequency_table_put_attr(policy->cpu); | 743 | cpufreq_frequency_table_put_attr(policy->cpu); |
741 | per_cpu(drv_data, policy->cpu) = NULL; | 744 | per_cpu(acfreq_data, policy->cpu) = NULL; |
742 | acpi_processor_unregister_performance(data->acpi_data, | 745 | acpi_processor_unregister_performance(data->acpi_data, |
743 | policy->cpu); | 746 | policy->cpu); |
744 | kfree(data); | 747 | kfree(data); |
@@ -749,7 +752,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) | |||
749 | 752 | ||
750 | static int acpi_cpufreq_resume(struct cpufreq_policy *policy) | 753 | static int acpi_cpufreq_resume(struct cpufreq_policy *policy) |
751 | { | 754 | { |
752 | struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); | 755 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); |
753 | 756 | ||
754 | dprintk("acpi_cpufreq_resume\n"); | 757 | dprintk("acpi_cpufreq_resume\n"); |
755 | 758 | ||
@@ -764,14 +767,15 @@ static struct freq_attr *acpi_cpufreq_attr[] = { | |||
764 | }; | 767 | }; |
765 | 768 | ||
766 | static struct cpufreq_driver acpi_cpufreq_driver = { | 769 | static struct cpufreq_driver acpi_cpufreq_driver = { |
767 | .verify = acpi_cpufreq_verify, | 770 | .verify = acpi_cpufreq_verify, |
768 | .target = acpi_cpufreq_target, | 771 | .target = acpi_cpufreq_target, |
769 | .init = acpi_cpufreq_cpu_init, | 772 | .bios_limit = acpi_processor_get_bios_limit, |
770 | .exit = acpi_cpufreq_cpu_exit, | 773 | .init = acpi_cpufreq_cpu_init, |
771 | .resume = acpi_cpufreq_resume, | 774 | .exit = acpi_cpufreq_cpu_exit, |
772 | .name = "acpi-cpufreq", | 775 | .resume = acpi_cpufreq_resume, |
773 | .owner = THIS_MODULE, | 776 | .name = "acpi-cpufreq", |
774 | .attr = acpi_cpufreq_attr, | 777 | .owner = THIS_MODULE, |
778 | .attr = acpi_cpufreq_attr, | ||
775 | }; | 779 | }; |
776 | 780 | ||
777 | static int __init acpi_cpufreq_init(void) | 781 | static int __init acpi_cpufreq_init(void) |
diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/arch/x86/kernel/cpu/cpufreq/elanfreq.c index 006b278b0d5d..c587db472a75 100644 --- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c +++ b/arch/x86/kernel/cpu/cpufreq/elanfreq.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | 22 | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/cpufreq.h> | 24 | #include <linux/cpufreq.h> |
26 | 25 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c index ac27ec2264d5..16e3483be9e3 100644 --- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c | |||
@@ -80,6 +80,7 @@ | |||
80 | #include <linux/cpufreq.h> | 80 | #include <linux/cpufreq.h> |
81 | #include <linux/pci.h> | 81 | #include <linux/pci.h> |
82 | #include <linux/errno.h> | 82 | #include <linux/errno.h> |
83 | #include <linux/slab.h> | ||
83 | 84 | ||
84 | #include <asm/processor-cyrix.h> | 85 | #include <asm/processor-cyrix.h> |
85 | 86 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c index cabd2fa3fc93..7e7eea4f8261 100644 --- a/arch/x86/kernel/cpu/cpufreq/longhaul.c +++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c | |||
@@ -885,7 +885,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | |||
885 | 885 | ||
886 | /* Find ACPI data for processor */ | 886 | /* Find ACPI data for processor */ |
887 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, | 887 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, |
888 | ACPI_UINT32_MAX, &longhaul_walk_callback, | 888 | ACPI_UINT32_MAX, &longhaul_walk_callback, NULL, |
889 | NULL, (void *)&pr); | 889 | NULL, (void *)&pr); |
890 | 890 | ||
891 | /* Check ACPI support for C3 state */ | 891 | /* Check ACPI support for C3 state */ |
diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/arch/x86/kernel/cpu/cpufreq/longrun.c index da5f70fcb766..e7b559d74c52 100644 --- a/arch/x86/kernel/cpu/cpufreq/longrun.c +++ b/arch/x86/kernel/cpu/cpufreq/longrun.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/slab.h> | ||
13 | #include <linux/cpufreq.h> | 12 | #include <linux/cpufreq.h> |
14 | #include <linux/timex.h> | 13 | #include <linux/timex.h> |
15 | 14 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c index 869615193720..7b8a8ba67b07 100644 --- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/smp.h> | 26 | #include <linux/smp.h> |
27 | #include <linux/cpufreq.h> | 27 | #include <linux/cpufreq.h> |
28 | #include <linux/slab.h> | ||
29 | #include <linux/cpumask.h> | 28 | #include <linux/cpumask.h> |
30 | #include <linux/timex.h> | 29 | #include <linux/timex.h> |
31 | 30 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c new file mode 100644 index 000000000000..ce7cde713e71 --- /dev/null +++ b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c | |||
@@ -0,0 +1,621 @@ | |||
1 | /* | ||
2 | * pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface | ||
3 | * | ||
4 | * Copyright (C) 2009 Red Hat, Matthew Garrett <mjg@redhat.com> | ||
5 | * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. | ||
6 | * Nagananda Chumbalkar <nagananda.chumbalkar@hp.com> | ||
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; version 2 of the License. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON | ||
17 | * INFRINGEMENT. See the GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/smp.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/cpufreq.h> | ||
32 | #include <linux/compiler.h> | ||
33 | #include <linux/slab.h> | ||
34 | |||
35 | #include <linux/acpi.h> | ||
36 | #include <linux/io.h> | ||
37 | #include <linux/spinlock.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | |||
40 | #include <acpi/processor.h> | ||
41 | |||
42 | #define PCC_VERSION "1.00.00" | ||
43 | #define POLL_LOOPS 300 | ||
44 | |||
45 | #define CMD_COMPLETE 0x1 | ||
46 | #define CMD_GET_FREQ 0x0 | ||
47 | #define CMD_SET_FREQ 0x1 | ||
48 | |||
49 | #define BUF_SZ 4 | ||
50 | |||
51 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ | ||
52 | "pcc-cpufreq", msg) | ||
53 | |||
54 | struct pcc_register_resource { | ||
55 | u8 descriptor; | ||
56 | u16 length; | ||
57 | u8 space_id; | ||
58 | u8 bit_width; | ||
59 | u8 bit_offset; | ||
60 | u8 access_size; | ||
61 | u64 address; | ||
62 | } __attribute__ ((packed)); | ||
63 | |||
64 | struct pcc_memory_resource { | ||
65 | u8 descriptor; | ||
66 | u16 length; | ||
67 | u8 space_id; | ||
68 | u8 resource_usage; | ||
69 | u8 type_specific; | ||
70 | u64 granularity; | ||
71 | u64 minimum; | ||
72 | u64 maximum; | ||
73 | u64 translation_offset; | ||
74 | u64 address_length; | ||
75 | } __attribute__ ((packed)); | ||
76 | |||
77 | static struct cpufreq_driver pcc_cpufreq_driver; | ||
78 | |||
79 | struct pcc_header { | ||
80 | u32 signature; | ||
81 | u16 length; | ||
82 | u8 major; | ||
83 | u8 minor; | ||
84 | u32 features; | ||
85 | u16 command; | ||
86 | u16 status; | ||
87 | u32 latency; | ||
88 | u32 minimum_time; | ||
89 | u32 maximum_time; | ||
90 | u32 nominal; | ||
91 | u32 throttled_frequency; | ||
92 | u32 minimum_frequency; | ||
93 | }; | ||
94 | |||
95 | static void __iomem *pcch_virt_addr; | ||
96 | static struct pcc_header __iomem *pcch_hdr; | ||
97 | |||
98 | static DEFINE_SPINLOCK(pcc_lock); | ||
99 | |||
100 | static struct acpi_generic_address doorbell; | ||
101 | |||
102 | static u64 doorbell_preserve; | ||
103 | static u64 doorbell_write; | ||
104 | |||
105 | static u8 OSC_UUID[16] = {0x63, 0x9B, 0x2C, 0x9F, 0x70, 0x91, 0x49, 0x1f, | ||
106 | 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46}; | ||
107 | |||
108 | struct pcc_cpu { | ||
109 | u32 input_offset; | ||
110 | u32 output_offset; | ||
111 | }; | ||
112 | |||
113 | static struct pcc_cpu *pcc_cpu_info; | ||
114 | |||
115 | static int pcc_cpufreq_verify(struct cpufreq_policy *policy) | ||
116 | { | ||
117 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, | ||
118 | policy->cpuinfo.max_freq); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static inline void pcc_cmd(void) | ||
123 | { | ||
124 | u64 doorbell_value; | ||
125 | int i; | ||
126 | |||
127 | acpi_read(&doorbell_value, &doorbell); | ||
128 | acpi_write((doorbell_value & doorbell_preserve) | doorbell_write, | ||
129 | &doorbell); | ||
130 | |||
131 | for (i = 0; i < POLL_LOOPS; i++) { | ||
132 | if (ioread16(&pcch_hdr->status) & CMD_COMPLETE) | ||
133 | break; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static inline void pcc_clear_mapping(void) | ||
138 | { | ||
139 | if (pcch_virt_addr) | ||
140 | iounmap(pcch_virt_addr); | ||
141 | pcch_virt_addr = NULL; | ||
142 | } | ||
143 | |||
144 | static unsigned int pcc_get_freq(unsigned int cpu) | ||
145 | { | ||
146 | struct pcc_cpu *pcc_cpu_data; | ||
147 | unsigned int curr_freq; | ||
148 | unsigned int freq_limit; | ||
149 | u16 status; | ||
150 | u32 input_buffer; | ||
151 | u32 output_buffer; | ||
152 | |||
153 | spin_lock(&pcc_lock); | ||
154 | |||
155 | dprintk("get: get_freq for CPU %d\n", cpu); | ||
156 | pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); | ||
157 | |||
158 | input_buffer = 0x1; | ||
159 | iowrite32(input_buffer, | ||
160 | (pcch_virt_addr + pcc_cpu_data->input_offset)); | ||
161 | iowrite16(CMD_GET_FREQ, &pcch_hdr->command); | ||
162 | |||
163 | pcc_cmd(); | ||
164 | |||
165 | output_buffer = | ||
166 | ioread32(pcch_virt_addr + pcc_cpu_data->output_offset); | ||
167 | |||
168 | /* Clear the input buffer - we are done with the current command */ | ||
169 | memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); | ||
170 | |||
171 | status = ioread16(&pcch_hdr->status); | ||
172 | if (status != CMD_COMPLETE) { | ||
173 | dprintk("get: FAILED: for CPU %d, status is %d\n", | ||
174 | cpu, status); | ||
175 | goto cmd_incomplete; | ||
176 | } | ||
177 | iowrite16(0, &pcch_hdr->status); | ||
178 | curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) | ||
179 | / 100) * 1000); | ||
180 | |||
181 | dprintk("get: SUCCESS: (virtual) output_offset for cpu %d is " | ||
182 | "0x%x, contains a value of: 0x%x. Speed is: %d MHz\n", | ||
183 | cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), | ||
184 | output_buffer, curr_freq); | ||
185 | |||
186 | freq_limit = (output_buffer >> 8) & 0xff; | ||
187 | if (freq_limit != 0xff) { | ||
188 | dprintk("get: frequency for cpu %d is being temporarily" | ||
189 | " capped at %d\n", cpu, curr_freq); | ||
190 | } | ||
191 | |||
192 | spin_unlock(&pcc_lock); | ||
193 | return curr_freq; | ||
194 | |||
195 | cmd_incomplete: | ||
196 | iowrite16(0, &pcch_hdr->status); | ||
197 | spin_unlock(&pcc_lock); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | static int pcc_cpufreq_target(struct cpufreq_policy *policy, | ||
202 | unsigned int target_freq, | ||
203 | unsigned int relation) | ||
204 | { | ||
205 | struct pcc_cpu *pcc_cpu_data; | ||
206 | struct cpufreq_freqs freqs; | ||
207 | u16 status; | ||
208 | u32 input_buffer; | ||
209 | int cpu; | ||
210 | |||
211 | spin_lock(&pcc_lock); | ||
212 | cpu = policy->cpu; | ||
213 | pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); | ||
214 | |||
215 | dprintk("target: CPU %d should go to target freq: %d " | ||
216 | "(virtual) input_offset is 0x%x\n", | ||
217 | cpu, target_freq, | ||
218 | (pcch_virt_addr + pcc_cpu_data->input_offset)); | ||
219 | |||
220 | freqs.new = target_freq; | ||
221 | freqs.cpu = cpu; | ||
222 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
223 | |||
224 | input_buffer = 0x1 | (((target_freq * 100) | ||
225 | / (ioread32(&pcch_hdr->nominal) * 1000)) << 8); | ||
226 | iowrite32(input_buffer, | ||
227 | (pcch_virt_addr + pcc_cpu_data->input_offset)); | ||
228 | iowrite16(CMD_SET_FREQ, &pcch_hdr->command); | ||
229 | |||
230 | pcc_cmd(); | ||
231 | |||
232 | /* Clear the input buffer - we are done with the current command */ | ||
233 | memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); | ||
234 | |||
235 | status = ioread16(&pcch_hdr->status); | ||
236 | if (status != CMD_COMPLETE) { | ||
237 | dprintk("target: FAILED for cpu %d, with status: 0x%x\n", | ||
238 | cpu, status); | ||
239 | goto cmd_incomplete; | ||
240 | } | ||
241 | iowrite16(0, &pcch_hdr->status); | ||
242 | |||
243 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
244 | dprintk("target: was SUCCESSFUL for cpu %d\n", cpu); | ||
245 | spin_unlock(&pcc_lock); | ||
246 | |||
247 | return 0; | ||
248 | |||
249 | cmd_incomplete: | ||
250 | iowrite16(0, &pcch_hdr->status); | ||
251 | spin_unlock(&pcc_lock); | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | static int pcc_get_offset(int cpu) | ||
256 | { | ||
257 | acpi_status status; | ||
258 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
259 | union acpi_object *pccp, *offset; | ||
260 | struct pcc_cpu *pcc_cpu_data; | ||
261 | struct acpi_processor *pr; | ||
262 | int ret = 0; | ||
263 | |||
264 | pr = per_cpu(processors, cpu); | ||
265 | pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); | ||
266 | |||
267 | status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer); | ||
268 | if (ACPI_FAILURE(status)) | ||
269 | return -ENODEV; | ||
270 | |||
271 | pccp = buffer.pointer; | ||
272 | if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { | ||
273 | ret = -ENODEV; | ||
274 | goto out_free; | ||
275 | }; | ||
276 | |||
277 | offset = &(pccp->package.elements[0]); | ||
278 | if (!offset || offset->type != ACPI_TYPE_INTEGER) { | ||
279 | ret = -ENODEV; | ||
280 | goto out_free; | ||
281 | } | ||
282 | |||
283 | pcc_cpu_data->input_offset = offset->integer.value; | ||
284 | |||
285 | offset = &(pccp->package.elements[1]); | ||
286 | if (!offset || offset->type != ACPI_TYPE_INTEGER) { | ||
287 | ret = -ENODEV; | ||
288 | goto out_free; | ||
289 | } | ||
290 | |||
291 | pcc_cpu_data->output_offset = offset->integer.value; | ||
292 | |||
293 | memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); | ||
294 | memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); | ||
295 | |||
296 | dprintk("pcc_get_offset: for CPU %d: pcc_cpu_data " | ||
297 | "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", | ||
298 | cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); | ||
299 | out_free: | ||
300 | kfree(buffer.pointer); | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | static int __init pcc_cpufreq_do_osc(acpi_handle *handle) | ||
305 | { | ||
306 | acpi_status status; | ||
307 | struct acpi_object_list input; | ||
308 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
309 | union acpi_object in_params[4]; | ||
310 | union acpi_object *out_obj; | ||
311 | u32 capabilities[2]; | ||
312 | u32 errors; | ||
313 | u32 supported; | ||
314 | int ret = 0; | ||
315 | |||
316 | input.count = 4; | ||
317 | input.pointer = in_params; | ||
318 | input.count = 4; | ||
319 | input.pointer = in_params; | ||
320 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
321 | in_params[0].buffer.length = 16; | ||
322 | in_params[0].buffer.pointer = OSC_UUID; | ||
323 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
324 | in_params[1].integer.value = 1; | ||
325 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
326 | in_params[2].integer.value = 2; | ||
327 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
328 | in_params[3].buffer.length = 8; | ||
329 | in_params[3].buffer.pointer = (u8 *)&capabilities; | ||
330 | |||
331 | capabilities[0] = OSC_QUERY_ENABLE; | ||
332 | capabilities[1] = 0x1; | ||
333 | |||
334 | status = acpi_evaluate_object(*handle, "_OSC", &input, &output); | ||
335 | if (ACPI_FAILURE(status)) | ||
336 | return -ENODEV; | ||
337 | |||
338 | if (!output.length) | ||
339 | return -ENODEV; | ||
340 | |||
341 | out_obj = output.pointer; | ||
342 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
343 | ret = -ENODEV; | ||
344 | goto out_free; | ||
345 | } | ||
346 | |||
347 | errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); | ||
348 | if (errors) { | ||
349 | ret = -ENODEV; | ||
350 | goto out_free; | ||
351 | } | ||
352 | |||
353 | supported = *((u32 *)(out_obj->buffer.pointer + 4)); | ||
354 | if (!(supported & 0x1)) { | ||
355 | ret = -ENODEV; | ||
356 | goto out_free; | ||
357 | } | ||
358 | |||
359 | kfree(output.pointer); | ||
360 | capabilities[0] = 0x0; | ||
361 | capabilities[1] = 0x1; | ||
362 | |||
363 | status = acpi_evaluate_object(*handle, "_OSC", &input, &output); | ||
364 | if (ACPI_FAILURE(status)) | ||
365 | return -ENODEV; | ||
366 | |||
367 | if (!output.length) | ||
368 | return -ENODEV; | ||
369 | |||
370 | out_obj = output.pointer; | ||
371 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
372 | ret = -ENODEV; | ||
373 | goto out_free; | ||
374 | } | ||
375 | |||
376 | errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); | ||
377 | if (errors) { | ||
378 | ret = -ENODEV; | ||
379 | goto out_free; | ||
380 | } | ||
381 | |||
382 | supported = *((u32 *)(out_obj->buffer.pointer + 4)); | ||
383 | if (!(supported & 0x1)) { | ||
384 | ret = -ENODEV; | ||
385 | goto out_free; | ||
386 | } | ||
387 | |||
388 | out_free: | ||
389 | kfree(output.pointer); | ||
390 | return ret; | ||
391 | } | ||
392 | |||
393 | static int __init pcc_cpufreq_probe(void) | ||
394 | { | ||
395 | acpi_status status; | ||
396 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
397 | struct pcc_memory_resource *mem_resource; | ||
398 | struct pcc_register_resource *reg_resource; | ||
399 | union acpi_object *out_obj, *member; | ||
400 | acpi_handle handle, osc_handle; | ||
401 | int ret = 0; | ||
402 | |||
403 | status = acpi_get_handle(NULL, "\\_SB", &handle); | ||
404 | if (ACPI_FAILURE(status)) | ||
405 | return -ENODEV; | ||
406 | |||
407 | status = acpi_get_handle(handle, "_OSC", &osc_handle); | ||
408 | if (ACPI_SUCCESS(status)) { | ||
409 | ret = pcc_cpufreq_do_osc(&osc_handle); | ||
410 | if (ret) | ||
411 | dprintk("probe: _OSC evaluation did not succeed\n"); | ||
412 | /* Firmware's use of _OSC is optional */ | ||
413 | ret = 0; | ||
414 | } | ||
415 | |||
416 | status = acpi_evaluate_object(handle, "PCCH", NULL, &output); | ||
417 | if (ACPI_FAILURE(status)) | ||
418 | return -ENODEV; | ||
419 | |||
420 | out_obj = output.pointer; | ||
421 | if (out_obj->type != ACPI_TYPE_PACKAGE) { | ||
422 | ret = -ENODEV; | ||
423 | goto out_free; | ||
424 | } | ||
425 | |||
426 | member = &out_obj->package.elements[0]; | ||
427 | if (member->type != ACPI_TYPE_BUFFER) { | ||
428 | ret = -ENODEV; | ||
429 | goto out_free; | ||
430 | } | ||
431 | |||
432 | mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; | ||
433 | |||
434 | dprintk("probe: mem_resource descriptor: 0x%x," | ||
435 | " length: %d, space_id: %d, resource_usage: %d," | ||
436 | " type_specific: %d, granularity: 0x%llx," | ||
437 | " minimum: 0x%llx, maximum: 0x%llx," | ||
438 | " translation_offset: 0x%llx, address_length: 0x%llx\n", | ||
439 | mem_resource->descriptor, mem_resource->length, | ||
440 | mem_resource->space_id, mem_resource->resource_usage, | ||
441 | mem_resource->type_specific, mem_resource->granularity, | ||
442 | mem_resource->minimum, mem_resource->maximum, | ||
443 | mem_resource->translation_offset, | ||
444 | mem_resource->address_length); | ||
445 | |||
446 | if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { | ||
447 | ret = -ENODEV; | ||
448 | goto out_free; | ||
449 | } | ||
450 | |||
451 | pcch_virt_addr = ioremap_nocache(mem_resource->minimum, | ||
452 | mem_resource->address_length); | ||
453 | if (pcch_virt_addr == NULL) { | ||
454 | dprintk("probe: could not map shared mem region\n"); | ||
455 | goto out_free; | ||
456 | } | ||
457 | pcch_hdr = pcch_virt_addr; | ||
458 | |||
459 | dprintk("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); | ||
460 | dprintk("probe: PCCH header is at physical address: 0x%llx," | ||
461 | " signature: 0x%x, length: %d bytes, major: %d, minor: %d," | ||
462 | " supported features: 0x%x, command field: 0x%x," | ||
463 | " status field: 0x%x, nominal latency: %d us\n", | ||
464 | mem_resource->minimum, ioread32(&pcch_hdr->signature), | ||
465 | ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major), | ||
466 | ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features), | ||
467 | ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), | ||
468 | ioread32(&pcch_hdr->latency)); | ||
469 | |||
470 | dprintk("probe: min time between commands: %d us," | ||
471 | " max time between commands: %d us," | ||
472 | " nominal CPU frequency: %d MHz," | ||
473 | " minimum CPU frequency: %d MHz," | ||
474 | " minimum CPU frequency without throttling: %d MHz\n", | ||
475 | ioread32(&pcch_hdr->minimum_time), | ||
476 | ioread32(&pcch_hdr->maximum_time), | ||
477 | ioread32(&pcch_hdr->nominal), | ||
478 | ioread32(&pcch_hdr->throttled_frequency), | ||
479 | ioread32(&pcch_hdr->minimum_frequency)); | ||
480 | |||
481 | member = &out_obj->package.elements[1]; | ||
482 | if (member->type != ACPI_TYPE_BUFFER) { | ||
483 | ret = -ENODEV; | ||
484 | goto pcch_free; | ||
485 | } | ||
486 | |||
487 | reg_resource = (struct pcc_register_resource *)member->buffer.pointer; | ||
488 | |||
489 | doorbell.space_id = reg_resource->space_id; | ||
490 | doorbell.bit_width = reg_resource->bit_width; | ||
491 | doorbell.bit_offset = reg_resource->bit_offset; | ||
492 | doorbell.access_width = 64; | ||
493 | doorbell.address = reg_resource->address; | ||
494 | |||
495 | dprintk("probe: doorbell: space_id is %d, bit_width is %d, " | ||
496 | "bit_offset is %d, access_width is %d, address is 0x%llx\n", | ||
497 | doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, | ||
498 | doorbell.access_width, reg_resource->address); | ||
499 | |||
500 | member = &out_obj->package.elements[2]; | ||
501 | if (member->type != ACPI_TYPE_INTEGER) { | ||
502 | ret = -ENODEV; | ||
503 | goto pcch_free; | ||
504 | } | ||
505 | |||
506 | doorbell_preserve = member->integer.value; | ||
507 | |||
508 | member = &out_obj->package.elements[3]; | ||
509 | if (member->type != ACPI_TYPE_INTEGER) { | ||
510 | ret = -ENODEV; | ||
511 | goto pcch_free; | ||
512 | } | ||
513 | |||
514 | doorbell_write = member->integer.value; | ||
515 | |||
516 | dprintk("probe: doorbell_preserve: 0x%llx," | ||
517 | " doorbell_write: 0x%llx\n", | ||
518 | doorbell_preserve, doorbell_write); | ||
519 | |||
520 | pcc_cpu_info = alloc_percpu(struct pcc_cpu); | ||
521 | if (!pcc_cpu_info) { | ||
522 | ret = -ENOMEM; | ||
523 | goto pcch_free; | ||
524 | } | ||
525 | |||
526 | printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency" | ||
527 | " limits: %d MHz, %d MHz\n", PCC_VERSION, | ||
528 | ioread32(&pcch_hdr->minimum_frequency), | ||
529 | ioread32(&pcch_hdr->nominal)); | ||
530 | kfree(output.pointer); | ||
531 | return ret; | ||
532 | pcch_free: | ||
533 | pcc_clear_mapping(); | ||
534 | out_free: | ||
535 | kfree(output.pointer); | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) | ||
540 | { | ||
541 | unsigned int cpu = policy->cpu; | ||
542 | unsigned int result = 0; | ||
543 | |||
544 | if (!pcch_virt_addr) { | ||
545 | result = -1; | ||
546 | goto pcch_null; | ||
547 | } | ||
548 | |||
549 | result = pcc_get_offset(cpu); | ||
550 | if (result) { | ||
551 | dprintk("init: PCCP evaluation failed\n"); | ||
552 | goto free; | ||
553 | } | ||
554 | |||
555 | policy->max = policy->cpuinfo.max_freq = | ||
556 | ioread32(&pcch_hdr->nominal) * 1000; | ||
557 | policy->min = policy->cpuinfo.min_freq = | ||
558 | ioread32(&pcch_hdr->minimum_frequency) * 1000; | ||
559 | policy->cur = pcc_get_freq(cpu); | ||
560 | |||
561 | dprintk("init: policy->max is %d, policy->min is %d\n", | ||
562 | policy->max, policy->min); | ||
563 | |||
564 | return 0; | ||
565 | free: | ||
566 | pcc_clear_mapping(); | ||
567 | free_percpu(pcc_cpu_info); | ||
568 | pcch_null: | ||
569 | return result; | ||
570 | } | ||
571 | |||
572 | static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy) | ||
573 | { | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static struct cpufreq_driver pcc_cpufreq_driver = { | ||
578 | .flags = CPUFREQ_CONST_LOOPS, | ||
579 | .get = pcc_get_freq, | ||
580 | .verify = pcc_cpufreq_verify, | ||
581 | .target = pcc_cpufreq_target, | ||
582 | .init = pcc_cpufreq_cpu_init, | ||
583 | .exit = pcc_cpufreq_cpu_exit, | ||
584 | .name = "pcc-cpufreq", | ||
585 | .owner = THIS_MODULE, | ||
586 | }; | ||
587 | |||
588 | static int __init pcc_cpufreq_init(void) | ||
589 | { | ||
590 | int ret; | ||
591 | |||
592 | if (acpi_disabled) | ||
593 | return 0; | ||
594 | |||
595 | ret = pcc_cpufreq_probe(); | ||
596 | if (ret) { | ||
597 | dprintk("pcc_cpufreq_init: PCCH evaluation failed\n"); | ||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | ret = cpufreq_register_driver(&pcc_cpufreq_driver); | ||
602 | |||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | static void __exit pcc_cpufreq_exit(void) | ||
607 | { | ||
608 | cpufreq_unregister_driver(&pcc_cpufreq_driver); | ||
609 | |||
610 | pcc_clear_mapping(); | ||
611 | |||
612 | free_percpu(pcc_cpu_info); | ||
613 | } | ||
614 | |||
615 | MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar"); | ||
616 | MODULE_VERSION(PCC_VERSION); | ||
617 | MODULE_DESCRIPTION("Processor Clocking Control interface driver"); | ||
618 | MODULE_LICENSE("GPL"); | ||
619 | |||
620 | late_initcall(pcc_cpufreq_init); | ||
621 | module_exit(pcc_cpufreq_exit); | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c index f10dea409f40..b3379d6a5c57 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/cpufreq.h> | 14 | #include <linux/cpufreq.h> |
15 | #include <linux/ioport.h> | 15 | #include <linux/ioport.h> |
16 | #include <linux/slab.h> | ||
17 | #include <linux/timex.h> | 16 | #include <linux/timex.h> |
18 | #include <linux/io.h> | 17 | #include <linux/io.h> |
19 | 18 | ||
@@ -164,7 +163,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) | |||
164 | } | 163 | } |
165 | 164 | ||
166 | /* cpuinfo and default policy values */ | 165 | /* cpuinfo and default policy values */ |
167 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; | 166 | policy->cpuinfo.transition_latency = 200000; |
168 | policy->cur = busfreq * max_multiplier; | 167 | policy->cur = busfreq * max_multiplier; |
169 | 168 | ||
170 | result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio); | 169 | result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio); |
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c index d47c775eb0ab..9a97116f89e5 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c | |||
@@ -714,14 +714,17 @@ static struct freq_attr *powernow_table_attr[] = { | |||
714 | }; | 714 | }; |
715 | 715 | ||
716 | static struct cpufreq_driver powernow_driver = { | 716 | static struct cpufreq_driver powernow_driver = { |
717 | .verify = powernow_verify, | 717 | .verify = powernow_verify, |
718 | .target = powernow_target, | 718 | .target = powernow_target, |
719 | .get = powernow_get, | 719 | .get = powernow_get, |
720 | .init = powernow_cpu_init, | 720 | #ifdef CONFIG_X86_POWERNOW_K7_ACPI |
721 | .exit = powernow_cpu_exit, | 721 | .bios_limit = acpi_processor_get_bios_limit, |
722 | .name = "powernow-k7", | 722 | #endif |
723 | .owner = THIS_MODULE, | 723 | .init = powernow_cpu_init, |
724 | .attr = powernow_table_attr, | 724 | .exit = powernow_cpu_exit, |
725 | .name = "powernow-k7", | ||
726 | .owner = THIS_MODULE, | ||
727 | .attr = powernow_table_attr, | ||
725 | }; | 728 | }; |
726 | 729 | ||
727 | static int __init powernow_init(void) | 730 | static int __init powernow_init(void) |
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index 3f12dabeab52..b6215b9798e2 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c | |||
@@ -806,7 +806,7 @@ static int find_psb_table(struct powernow_k8_data *data) | |||
806 | static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, | 806 | static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, |
807 | unsigned int index) | 807 | unsigned int index) |
808 | { | 808 | { |
809 | acpi_integer control; | 809 | u64 control; |
810 | 810 | ||
811 | if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE)) | 811 | if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE)) |
812 | return; | 812 | return; |
@@ -824,7 +824,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) | |||
824 | { | 824 | { |
825 | struct cpufreq_frequency_table *powernow_table; | 825 | struct cpufreq_frequency_table *powernow_table; |
826 | int ret_val = -ENODEV; | 826 | int ret_val = -ENODEV; |
827 | acpi_integer control, status; | 827 | u64 control, status; |
828 | 828 | ||
829 | if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { | 829 | if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { |
830 | dprintk("register performance failed: bad ACPI data\n"); | 830 | dprintk("register performance failed: bad ACPI data\n"); |
@@ -929,7 +929,8 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, | |||
929 | powernow_table[i].index = index; | 929 | powernow_table[i].index = index; |
930 | 930 | ||
931 | /* Frequency may be rounded for these */ | 931 | /* Frequency may be rounded for these */ |
932 | if (boot_cpu_data.x86 == 0x10 || boot_cpu_data.x86 == 0x11) { | 932 | if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) |
933 | || boot_cpu_data.x86 == 0x11) { | ||
933 | powernow_table[i].frequency = | 934 | powernow_table[i].frequency = |
934 | freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7); | 935 | freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7); |
935 | } else | 936 | } else |
@@ -948,7 +949,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, | |||
948 | u32 fid; | 949 | u32 fid; |
949 | u32 vid; | 950 | u32 vid; |
950 | u32 freq, index; | 951 | u32 freq, index; |
951 | acpi_integer status, control; | 952 | u64 status, control; |
952 | 953 | ||
953 | if (data->exttype) { | 954 | if (data->exttype) { |
954 | status = data->acpi_data.states[i].status; | 955 | status = data->acpi_data.states[i].status; |
@@ -1118,7 +1119,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, | |||
1118 | static int powernowk8_target(struct cpufreq_policy *pol, | 1119 | static int powernowk8_target(struct cpufreq_policy *pol, |
1119 | unsigned targfreq, unsigned relation) | 1120 | unsigned targfreq, unsigned relation) |
1120 | { | 1121 | { |
1121 | cpumask_t oldmask; | 1122 | cpumask_var_t oldmask; |
1122 | struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); | 1123 | struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); |
1123 | u32 checkfid; | 1124 | u32 checkfid; |
1124 | u32 checkvid; | 1125 | u32 checkvid; |
@@ -1131,9 +1132,13 @@ static int powernowk8_target(struct cpufreq_policy *pol, | |||
1131 | checkfid = data->currfid; | 1132 | checkfid = data->currfid; |
1132 | checkvid = data->currvid; | 1133 | checkvid = data->currvid; |
1133 | 1134 | ||
1134 | /* only run on specific CPU from here on */ | 1135 | /* only run on specific CPU from here on. */ |
1135 | oldmask = current->cpus_allowed; | 1136 | /* This is poor form: use a workqueue or smp_call_function_single */ |
1136 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(pol->cpu)); | 1137 | if (!alloc_cpumask_var(&oldmask, GFP_KERNEL)) |
1138 | return -ENOMEM; | ||
1139 | |||
1140 | cpumask_copy(oldmask, tsk_cpus_allowed(current)); | ||
1141 | set_cpus_allowed_ptr(current, cpumask_of(pol->cpu)); | ||
1137 | 1142 | ||
1138 | if (smp_processor_id() != pol->cpu) { | 1143 | if (smp_processor_id() != pol->cpu) { |
1139 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); | 1144 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); |
@@ -1193,7 +1198,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, | |||
1193 | ret = 0; | 1198 | ret = 0; |
1194 | 1199 | ||
1195 | err_out: | 1200 | err_out: |
1196 | set_cpus_allowed_ptr(current, &oldmask); | 1201 | set_cpus_allowed_ptr(current, oldmask); |
1202 | free_cpumask_var(oldmask); | ||
1197 | return ret; | 1203 | return ret; |
1198 | } | 1204 | } |
1199 | 1205 | ||
@@ -1351,6 +1357,7 @@ static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol) | |||
1351 | 1357 | ||
1352 | kfree(data->powernow_table); | 1358 | kfree(data->powernow_table); |
1353 | kfree(data); | 1359 | kfree(data); |
1360 | per_cpu(powernow_data, pol->cpu) = NULL; | ||
1354 | 1361 | ||
1355 | return 0; | 1362 | return 0; |
1356 | } | 1363 | } |
@@ -1370,7 +1377,7 @@ static unsigned int powernowk8_get(unsigned int cpu) | |||
1370 | int err; | 1377 | int err; |
1371 | 1378 | ||
1372 | if (!data) | 1379 | if (!data) |
1373 | return -EINVAL; | 1380 | return 0; |
1374 | 1381 | ||
1375 | smp_call_function_single(cpu, query_values_on_cpu, &err, true); | 1382 | smp_call_function_single(cpu, query_values_on_cpu, &err, true); |
1376 | if (err) | 1383 | if (err) |
@@ -1393,14 +1400,15 @@ static struct freq_attr *powernow_k8_attr[] = { | |||
1393 | }; | 1400 | }; |
1394 | 1401 | ||
1395 | static struct cpufreq_driver cpufreq_amd64_driver = { | 1402 | static struct cpufreq_driver cpufreq_amd64_driver = { |
1396 | .verify = powernowk8_verify, | 1403 | .verify = powernowk8_verify, |
1397 | .target = powernowk8_target, | 1404 | .target = powernowk8_target, |
1398 | .init = powernowk8_cpu_init, | 1405 | .bios_limit = acpi_processor_get_bios_limit, |
1399 | .exit = __devexit_p(powernowk8_cpu_exit), | 1406 | .init = powernowk8_cpu_init, |
1400 | .get = powernowk8_get, | 1407 | .exit = __devexit_p(powernowk8_cpu_exit), |
1401 | .name = "powernow-k8", | 1408 | .get = powernowk8_get, |
1402 | .owner = THIS_MODULE, | 1409 | .name = "powernow-k8", |
1403 | .attr = powernow_k8_attr, | 1410 | .owner = THIS_MODULE, |
1411 | .attr = powernow_k8_attr, | ||
1404 | }; | 1412 | }; |
1405 | 1413 | ||
1406 | /* driver entry point for init */ | 1414 | /* driver entry point for init */ |
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c index 8d672ef162ce..9b1ff37de46a 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/sched.h> /* current */ | 20 | #include <linux/sched.h> /* current */ |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/compiler.h> | 22 | #include <linux/compiler.h> |
23 | #include <linux/gfp.h> | ||
23 | 24 | ||
24 | #include <asm/msr.h> | 25 | #include <asm/msr.h> |
25 | #include <asm/processor.h> | 26 | #include <asm/processor.h> |
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c index 3ae5a7a3a500..561758e95180 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/cpufreq.h> | 24 | #include <linux/cpufreq.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/slab.h> | ||
27 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
28 | 27 | ||
29 | #include "speedstep-lib.h" | 28 | #include "speedstep-lib.h" |
@@ -39,7 +38,7 @@ static struct pci_dev *speedstep_chipset_dev; | |||
39 | 38 | ||
40 | /* speedstep_processor | 39 | /* speedstep_processor |
41 | */ | 40 | */ |
42 | static unsigned int speedstep_processor; | 41 | static enum speedstep_processor speedstep_processor; |
43 | 42 | ||
44 | static u32 pmbase; | 43 | static u32 pmbase; |
45 | 44 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c index f4c290b8482f..a94ec6be69fa 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/cpufreq.h> | 15 | #include <linux/cpufreq.h> |
16 | #include <linux/slab.h> | ||
17 | 16 | ||
18 | #include <asm/msr.h> | 17 | #include <asm/msr.h> |
19 | #include <asm/tsc.h> | 18 | #include <asm/tsc.h> |
@@ -34,7 +33,7 @@ static int relaxed_check; | |||
34 | * GET PROCESSOR CORE SPEED IN KHZ * | 33 | * GET PROCESSOR CORE SPEED IN KHZ * |
35 | *********************************************************************/ | 34 | *********************************************************************/ |
36 | 35 | ||
37 | static unsigned int pentium3_get_frequency(unsigned int processor) | 36 | static unsigned int pentium3_get_frequency(enum speedstep_processor processor) |
38 | { | 37 | { |
39 | /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */ | 38 | /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */ |
40 | struct { | 39 | struct { |
@@ -227,7 +226,7 @@ static unsigned int pentium4_get_frequency(void) | |||
227 | 226 | ||
228 | 227 | ||
229 | /* Warning: may get called from smp_call_function_single. */ | 228 | /* Warning: may get called from smp_call_function_single. */ |
230 | unsigned int speedstep_get_frequency(unsigned int processor) | 229 | unsigned int speedstep_get_frequency(enum speedstep_processor processor) |
231 | { | 230 | { |
232 | switch (processor) { | 231 | switch (processor) { |
233 | case SPEEDSTEP_CPU_PCORE: | 232 | case SPEEDSTEP_CPU_PCORE: |
@@ -380,7 +379,7 @@ EXPORT_SYMBOL_GPL(speedstep_detect_processor); | |||
380 | * DETECT SPEEDSTEP SPEEDS * | 379 | * DETECT SPEEDSTEP SPEEDS * |
381 | *********************************************************************/ | 380 | *********************************************************************/ |
382 | 381 | ||
383 | unsigned int speedstep_get_freqs(unsigned int processor, | 382 | unsigned int speedstep_get_freqs(enum speedstep_processor processor, |
384 | unsigned int *low_speed, | 383 | unsigned int *low_speed, |
385 | unsigned int *high_speed, | 384 | unsigned int *high_speed, |
386 | unsigned int *transition_latency, | 385 | unsigned int *transition_latency, |
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h index 2b6c04e5a304..70d9cea1219d 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h | |||
@@ -11,18 +11,18 @@ | |||
11 | 11 | ||
12 | 12 | ||
13 | /* processors */ | 13 | /* processors */ |
14 | 14 | enum speedstep_processor { | |
15 | #define SPEEDSTEP_CPU_PIII_C_EARLY 0x00000001 /* Coppermine core */ | 15 | SPEEDSTEP_CPU_PIII_C_EARLY = 0x00000001, /* Coppermine core */ |
16 | #define SPEEDSTEP_CPU_PIII_C 0x00000002 /* Coppermine core */ | 16 | SPEEDSTEP_CPU_PIII_C = 0x00000002, /* Coppermine core */ |
17 | #define SPEEDSTEP_CPU_PIII_T 0x00000003 /* Tualatin core */ | 17 | SPEEDSTEP_CPU_PIII_T = 0x00000003, /* Tualatin core */ |
18 | #define SPEEDSTEP_CPU_P4M 0x00000004 /* P4-M */ | 18 | SPEEDSTEP_CPU_P4M = 0x00000004, /* P4-M */ |
19 | |||
20 | /* the following processors are not speedstep-capable and are not auto-detected | 19 | /* the following processors are not speedstep-capable and are not auto-detected |
21 | * in speedstep_detect_processor(). However, their speed can be detected using | 20 | * in speedstep_detect_processor(). However, their speed can be detected using |
22 | * the speedstep_get_frequency() call. */ | 21 | * the speedstep_get_frequency() call. */ |
23 | #define SPEEDSTEP_CPU_PM 0xFFFFFF03 /* Pentium M */ | 22 | SPEEDSTEP_CPU_PM = 0xFFFFFF03, /* Pentium M */ |
24 | #define SPEEDSTEP_CPU_P4D 0xFFFFFF04 /* desktop P4 */ | 23 | SPEEDSTEP_CPU_P4D = 0xFFFFFF04, /* desktop P4 */ |
25 | #define SPEEDSTEP_CPU_PCORE 0xFFFFFF05 /* Core */ | 24 | SPEEDSTEP_CPU_PCORE = 0xFFFFFF05, /* Core */ |
25 | }; | ||
26 | 26 | ||
27 | /* speedstep states -- only two of them */ | 27 | /* speedstep states -- only two of them */ |
28 | 28 | ||
@@ -31,10 +31,10 @@ | |||
31 | 31 | ||
32 | 32 | ||
33 | /* detect a speedstep-capable processor */ | 33 | /* detect a speedstep-capable processor */ |
34 | extern unsigned int speedstep_detect_processor (void); | 34 | extern enum speedstep_processor speedstep_detect_processor(void); |
35 | 35 | ||
36 | /* detect the current speed (in khz) of the processor */ | 36 | /* detect the current speed (in khz) of the processor */ |
37 | extern unsigned int speedstep_get_frequency(unsigned int processor); | 37 | extern unsigned int speedstep_get_frequency(enum speedstep_processor processor); |
38 | 38 | ||
39 | 39 | ||
40 | /* detect the low and high speeds of the processor. The callback | 40 | /* detect the low and high speeds of the processor. The callback |
@@ -42,7 +42,7 @@ extern unsigned int speedstep_get_frequency(unsigned int processor); | |||
42 | * SPEEDSTEP_LOW; the second argument is zero so that no | 42 | * SPEEDSTEP_LOW; the second argument is zero so that no |
43 | * cpufreq_notify_transition calls are initiated. | 43 | * cpufreq_notify_transition calls are initiated. |
44 | */ | 44 | */ |
45 | extern unsigned int speedstep_get_freqs(unsigned int processor, | 45 | extern unsigned int speedstep_get_freqs(enum speedstep_processor processor, |
46 | unsigned int *low_speed, | 46 | unsigned int *low_speed, |
47 | unsigned int *high_speed, | 47 | unsigned int *high_speed, |
48 | unsigned int *transition_latency, | 48 | unsigned int *transition_latency, |
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c index befea088e4f5..8abd869baabf 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/cpufreq.h> | 19 | #include <linux/cpufreq.h> |
20 | #include <linux/slab.h> | ||
21 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
22 | #include <linux/io.h> | 21 | #include <linux/io.h> |
23 | #include <asm/ist.h> | 22 | #include <asm/ist.h> |
@@ -35,7 +34,7 @@ static int smi_cmd; | |||
35 | static unsigned int smi_sig; | 34 | static unsigned int smi_sig; |
36 | 35 | ||
37 | /* info about the processor */ | 36 | /* info about the processor */ |
38 | static unsigned int speedstep_processor; | 37 | static enum speedstep_processor speedstep_processor; |
39 | 38 | ||
40 | /* | 39 | /* |
41 | * There are only two frequency states for each processor. Values | 40 | * There are only two frequency states for each processor. Values |