diff options
author | Mark Langsdorf <mark.langsdorf@amd.com> | 2010-03-18 13:41:46 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-04-09 17:07:40 -0400 |
commit | a2fed573f065e526bfd5cbf26e5491973d9e9aaa (patch) | |
tree | 069ea4932051dd4535de4bf896e09deff836e0b9 /arch/x86/kernel/cpu/cpufreq | |
parent | d65ad45cd82a0db9544469b8c54f5dc5cafbb2d8 (diff) |
x86, cpufreq: Add APERF/MPERF support for AMD processors
Starting with model 10 of Family 0x10, AMD processors may have
support for APERF/MPERF. Add support for identifying it and using
it within cpufreq. Move the APERF/MPERF functions out of the
acpi-cpufreq code and into their own file so they can easily be
shared.
Signed-off-by: Mark Langsdorf <mark.langsdorf@amd.com>
LKML-Reference: <20100401141956.GA1930@aftab>
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
Reviewed-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel/cpu/cpufreq')
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 44 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/mperf.c | 51 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/mperf.h | 9 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 8 |
5 files changed, 72 insertions, 44 deletions
diff --git a/arch/x86/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile index 1840c0a5170b..bd54bf67e6fb 100644 --- a/arch/x86/kernel/cpu/cpufreq/Makefile +++ b/arch/x86/kernel/cpu/cpufreq/Makefile | |||
@@ -2,8 +2,8 @@ | |||
2 | # K8 systems. ACPI is preferred to all other hardware-specific drivers. | 2 | # K8 systems. ACPI is preferred to all other hardware-specific drivers. |
3 | # speedstep-* is preferred over p4-clockmod. | 3 | # speedstep-* is preferred over p4-clockmod. |
4 | 4 | ||
5 | obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o | 5 | obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o |
6 | obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o | 6 | obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o |
7 | obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o | 7 | obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o |
8 | obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o | 8 | obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o |
9 | obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o | 9 | obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o |
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 1b1920fa7c80..dc68e5c2c071 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/msr.h> | 45 | #include <asm/msr.h> |
46 | #include <asm/processor.h> | 46 | #include <asm/processor.h> |
47 | #include <asm/cpufeature.h> | 47 | #include <asm/cpufeature.h> |
48 | #include "mperf.h" | ||
48 | 49 | ||
49 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ | 50 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ |
50 | "acpi-cpufreq", msg) | 51 | "acpi-cpufreq", msg) |
@@ -70,8 +71,6 @@ struct acpi_cpufreq_data { | |||
70 | 71 | ||
71 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); | 72 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); |
72 | 73 | ||
73 | static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf); | ||
74 | |||
75 | /* acpi_perf_data is a pointer to percpu data. */ | 74 | /* acpi_perf_data is a pointer to percpu data. */ |
76 | static struct acpi_processor_performance *acpi_perf_data; | 75 | static struct acpi_processor_performance *acpi_perf_data; |
77 | 76 | ||
@@ -239,45 +238,6 @@ static u32 get_cur_val(const struct cpumask *mask) | |||
239 | return cmd.val; | 238 | return cmd.val; |
240 | } | 239 | } |
241 | 240 | ||
242 | /* Called via smp_call_function_single(), on the target CPU */ | ||
243 | static void read_measured_perf_ctrs(void *_cur) | ||
244 | { | ||
245 | struct aperfmperf *am = _cur; | ||
246 | |||
247 | get_aperfmperf(am); | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * Return the measured active (C0) frequency on this CPU since last call | ||
252 | * to this function. | ||
253 | * Input: cpu number | ||
254 | * Return: Average CPU frequency in terms of max frequency (zero on error) | ||
255 | * | ||
256 | * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance | ||
257 | * over a period of time, while CPU is in C0 state. | ||
258 | * IA32_MPERF counts at the rate of max advertised frequency | ||
259 | * IA32_APERF counts at the rate of actual CPU frequency | ||
260 | * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and | ||
261 | * no meaning should be associated with absolute values of these MSRs. | ||
262 | */ | ||
263 | static unsigned int get_measured_perf(struct cpufreq_policy *policy, | ||
264 | unsigned int cpu) | ||
265 | { | ||
266 | struct aperfmperf perf; | ||
267 | unsigned long ratio; | ||
268 | unsigned int retval; | ||
269 | |||
270 | if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) | ||
271 | return 0; | ||
272 | |||
273 | ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf); | ||
274 | per_cpu(acfreq_old_perf, cpu) = perf; | ||
275 | |||
276 | retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; | ||
277 | |||
278 | return retval; | ||
279 | } | ||
280 | |||
281 | static unsigned int get_cur_freq_on_cpu(unsigned int cpu) | 241 | static unsigned int get_cur_freq_on_cpu(unsigned int cpu) |
282 | { | 242 | { |
283 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu); | 243 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu); |
@@ -701,7 +661,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
701 | 661 | ||
702 | /* Check for APERF/MPERF support in hardware */ | 662 | /* Check for APERF/MPERF support in hardware */ |
703 | if (cpu_has(c, X86_FEATURE_APERFMPERF)) | 663 | if (cpu_has(c, X86_FEATURE_APERFMPERF)) |
704 | acpi_cpufreq_driver.getavg = get_measured_perf; | 664 | acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; |
705 | 665 | ||
706 | dprintk("CPU%u - ACPI performance management activated.\n", cpu); | 666 | dprintk("CPU%u - ACPI performance management activated.\n", cpu); |
707 | for (i = 0; i < perf->state_count; i++) | 667 | for (i = 0; i < perf->state_count; i++) |
diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.c b/arch/x86/kernel/cpu/cpufreq/mperf.c new file mode 100644 index 000000000000..911e193018ae --- /dev/null +++ b/arch/x86/kernel/cpu/cpufreq/mperf.c | |||
@@ -0,0 +1,51 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/smp.h> | ||
3 | #include <linux/module.h> | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/cpufreq.h> | ||
6 | #include <linux/slab.h> | ||
7 | |||
8 | #include "mperf.h" | ||
9 | |||
10 | static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf); | ||
11 | |||
12 | /* Called via smp_call_function_single(), on the target CPU */ | ||
13 | static void read_measured_perf_ctrs(void *_cur) | ||
14 | { | ||
15 | struct aperfmperf *am = _cur; | ||
16 | |||
17 | get_aperfmperf(am); | ||
18 | } | ||
19 | |||
20 | /* | ||
21 | * Return the measured active (C0) frequency on this CPU since last call | ||
22 | * to this function. | ||
23 | * Input: cpu number | ||
24 | * Return: Average CPU frequency in terms of max frequency (zero on error) | ||
25 | * | ||
26 | * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance | ||
27 | * over a period of time, while CPU is in C0 state. | ||
28 | * IA32_MPERF counts at the rate of max advertised frequency | ||
29 | * IA32_APERF counts at the rate of actual CPU frequency | ||
30 | * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and | ||
31 | * no meaning should be associated with absolute values of these MSRs. | ||
32 | */ | ||
33 | unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, | ||
34 | unsigned int cpu) | ||
35 | { | ||
36 | struct aperfmperf perf; | ||
37 | unsigned long ratio; | ||
38 | unsigned int retval; | ||
39 | |||
40 | if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) | ||
41 | return 0; | ||
42 | |||
43 | ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf); | ||
44 | per_cpu(acfreq_old_perf, cpu) = perf; | ||
45 | |||
46 | retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; | ||
47 | |||
48 | return retval; | ||
49 | } | ||
50 | EXPORT_SYMBOL_GPL(cpufreq_get_measured_perf); | ||
51 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.h b/arch/x86/kernel/cpu/cpufreq/mperf.h new file mode 100644 index 000000000000..5dbf2950dc22 --- /dev/null +++ b/arch/x86/kernel/cpu/cpufreq/mperf.h | |||
@@ -0,0 +1,9 @@ | |||
1 | /* | ||
2 | * (c) 2010 Advanced Micro Devices, Inc. | ||
3 | * Your use of this code is subject to the terms and conditions of the | ||
4 | * GNU general public license version 2. See "COPYING" or | ||
5 | * http://www.gnu.org/licenses/gpl.html | ||
6 | */ | ||
7 | |||
8 | unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, | ||
9 | unsigned int cpu); | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index 74ca34b5c003..52fce638f444 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #define PFX "powernow-k8: " | 45 | #define PFX "powernow-k8: " |
46 | #define VERSION "version 2.20.00" | 46 | #define VERSION "version 2.20.00" |
47 | #include "powernow-k8.h" | 47 | #include "powernow-k8.h" |
48 | #include "mperf.h" | ||
48 | 49 | ||
49 | /* serialize freq changes */ | 50 | /* serialize freq changes */ |
50 | static DEFINE_MUTEX(fidvid_mutex); | 51 | static DEFINE_MUTEX(fidvid_mutex); |
@@ -57,6 +58,8 @@ static int cpu_family = CPU_OPTERON; | |||
57 | static bool cpb_capable, cpb_enabled; | 58 | static bool cpb_capable, cpb_enabled; |
58 | static struct msr __percpu *msrs; | 59 | static struct msr __percpu *msrs; |
59 | 60 | ||
61 | static struct cpufreq_driver cpufreq_amd64_driver; | ||
62 | |||
60 | #ifndef CONFIG_SMP | 63 | #ifndef CONFIG_SMP |
61 | static inline const struct cpumask *cpu_core_mask(int cpu) | 64 | static inline const struct cpumask *cpu_core_mask(int cpu) |
62 | { | 65 | { |
@@ -1251,6 +1254,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) | |||
1251 | struct powernow_k8_data *data; | 1254 | struct powernow_k8_data *data; |
1252 | struct init_on_cpu init_on_cpu; | 1255 | struct init_on_cpu init_on_cpu; |
1253 | int rc; | 1256 | int rc; |
1257 | struct cpuinfo_x86 *c = &cpu_data(pol->cpu); | ||
1254 | 1258 | ||
1255 | if (!cpu_online(pol->cpu)) | 1259 | if (!cpu_online(pol->cpu)) |
1256 | return -ENODEV; | 1260 | return -ENODEV; |
@@ -1325,6 +1329,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) | |||
1325 | return -EINVAL; | 1329 | return -EINVAL; |
1326 | } | 1330 | } |
1327 | 1331 | ||
1332 | /* Check for APERF/MPERF support in hardware */ | ||
1333 | if (cpu_has(c, X86_FEATURE_APERFMPERF)) | ||
1334 | cpufreq_amd64_driver.getavg = cpufreq_get_measured_perf; | ||
1335 | |||
1328 | cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); | 1336 | cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); |
1329 | 1337 | ||
1330 | if (cpu_family == CPU_HW_PSTATE) | 1338 | if (cpu_family == CPU_HW_PSTATE) |