diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-09-02 05:49:52 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-09-15 10:51:26 -0400 |
commit | 5cbc19a983141729d716be17197028434127b376 (patch) | |
tree | cabde63550658a141404fe85fbf23d3ab735481e | |
parent | a8303aaf2b2f74714db6d204ab4fcb810942664e (diff) |
x86: Add generic aperf/mperf code
Move some of the aperf/mperf code out from the cpufreq driver
thingy so that other people can enjoy it too.
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: Yanmin <yanmin_zhang@linux.intel.com>
Cc: Dave Jones <davej@redhat.com>
Cc: Len Brown <len.brown@intel.com>
Cc: Yinghai Lu <yhlu.kernel@gmail.com>
Cc: cpufreq@vger.kernel.org
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/include/asm/processor.h | 30 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 79 |
2 files changed, 39 insertions, 70 deletions
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index e08ea043e08..4ae2ccfed63 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -27,6 +27,7 @@ struct mm_struct; | |||
27 | #include <linux/cpumask.h> | 27 | #include <linux/cpumask.h> |
28 | #include <linux/cache.h> | 28 | #include <linux/cache.h> |
29 | #include <linux/threads.h> | 29 | #include <linux/threads.h> |
30 | #include <linux/math64.h> | ||
30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
31 | 32 | ||
32 | /* | 33 | /* |
@@ -1020,4 +1021,33 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip, | |||
1020 | extern int get_tsc_mode(unsigned long adr); | 1021 | extern int get_tsc_mode(unsigned long adr); |
1021 | extern int set_tsc_mode(unsigned int val); | 1022 | extern int set_tsc_mode(unsigned int val); |
1022 | 1023 | ||
1024 | struct aperfmperf { | ||
1025 | u64 aperf, mperf; | ||
1026 | }; | ||
1027 | |||
1028 | static inline void get_aperfmperf(struct aperfmperf *am) | ||
1029 | { | ||
1030 | WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_APERFMPERF)); | ||
1031 | |||
1032 | rdmsrl(MSR_IA32_APERF, am->aperf); | ||
1033 | rdmsrl(MSR_IA32_MPERF, am->mperf); | ||
1034 | } | ||
1035 | |||
1036 | #define APERFMPERF_SHIFT 10 | ||
1037 | |||
1038 | static inline | ||
1039 | unsigned long calc_aperfmperf_ratio(struct aperfmperf *old, | ||
1040 | struct aperfmperf *new) | ||
1041 | { | ||
1042 | u64 aperf = new->aperf - old->aperf; | ||
1043 | u64 mperf = new->mperf - old->mperf; | ||
1044 | unsigned long ratio = aperf; | ||
1045 | |||
1046 | mperf >>= APERFMPERF_SHIFT; | ||
1047 | if (mperf) | ||
1048 | ratio = div64_u64(aperf, mperf); | ||
1049 | |||
1050 | return ratio; | ||
1051 | } | ||
1052 | |||
1023 | #endif /* _ASM_X86_PROCESSOR_H */ | 1053 | #endif /* _ASM_X86_PROCESSOR_H */ |
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 509e6a7db71..4109679863c 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -70,11 +70,7 @@ struct acpi_cpufreq_data { | |||
70 | 70 | ||
71 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data); | 71 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data); |
72 | 72 | ||
73 | struct acpi_msr_data { | 73 | static DEFINE_PER_CPU(struct aperfmperf, old_perf); |
74 | u64 saved_aperf, saved_mperf; | ||
75 | }; | ||
76 | |||
77 | static DEFINE_PER_CPU(struct acpi_msr_data, msr_data); | ||
78 | 74 | ||
79 | DEFINE_TRACE(power_mark); | 75 | DEFINE_TRACE(power_mark); |
80 | 76 | ||
@@ -243,23 +239,12 @@ static u32 get_cur_val(const struct cpumask *mask) | |||
243 | return cmd.val; | 239 | return cmd.val; |
244 | } | 240 | } |
245 | 241 | ||
246 | struct perf_pair { | ||
247 | union { | ||
248 | struct { | ||
249 | u32 lo; | ||
250 | u32 hi; | ||
251 | } split; | ||
252 | u64 whole; | ||
253 | } aperf, mperf; | ||
254 | }; | ||
255 | |||
256 | /* Called via smp_call_function_single(), on the target CPU */ | 242 | /* Called via smp_call_function_single(), on the target CPU */ |
257 | static void read_measured_perf_ctrs(void *_cur) | 243 | static void read_measured_perf_ctrs(void *_cur) |
258 | { | 244 | { |
259 | struct perf_pair *cur = _cur; | 245 | struct aperfmperf *am = _cur; |
260 | 246 | ||
261 | rdmsr(MSR_IA32_APERF, cur->aperf.split.lo, cur->aperf.split.hi); | 247 | get_aperfmperf(am); |
262 | rdmsr(MSR_IA32_MPERF, cur->mperf.split.lo, cur->mperf.split.hi); | ||
263 | } | 248 | } |
264 | 249 | ||
265 | /* | 250 | /* |
@@ -278,63 +263,17 @@ static void read_measured_perf_ctrs(void *_cur) | |||
278 | static unsigned int get_measured_perf(struct cpufreq_policy *policy, | 263 | static unsigned int get_measured_perf(struct cpufreq_policy *policy, |
279 | unsigned int cpu) | 264 | unsigned int cpu) |
280 | { | 265 | { |
281 | struct perf_pair readin, cur; | 266 | struct aperfmperf perf; |
282 | unsigned int perf_percent; | 267 | unsigned long ratio; |
283 | unsigned int retval; | 268 | unsigned int retval; |
284 | 269 | ||
285 | if (smp_call_function_single(cpu, read_measured_perf_ctrs, &readin, 1)) | 270 | if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) |
286 | return 0; | 271 | return 0; |
287 | 272 | ||
288 | cur.aperf.whole = readin.aperf.whole - | 273 | ratio = calc_aperfmperf_ratio(&per_cpu(old_perf, cpu), &perf); |
289 | per_cpu(msr_data, cpu).saved_aperf; | 274 | per_cpu(old_perf, cpu) = perf; |
290 | cur.mperf.whole = readin.mperf.whole - | ||
291 | per_cpu(msr_data, cpu).saved_mperf; | ||
292 | per_cpu(msr_data, cpu).saved_aperf = readin.aperf.whole; | ||
293 | per_cpu(msr_data, cpu).saved_mperf = readin.mperf.whole; | ||
294 | |||
295 | #ifdef __i386__ | ||
296 | /* | ||
297 | * We dont want to do 64 bit divide with 32 bit kernel | ||
298 | * Get an approximate value. Return failure in case we cannot get | ||
299 | * an approximate value. | ||
300 | */ | ||
301 | if (unlikely(cur.aperf.split.hi || cur.mperf.split.hi)) { | ||
302 | int shift_count; | ||
303 | u32 h; | ||
304 | |||
305 | h = max_t(u32, cur.aperf.split.hi, cur.mperf.split.hi); | ||
306 | shift_count = fls(h); | ||
307 | |||
308 | cur.aperf.whole >>= shift_count; | ||
309 | cur.mperf.whole >>= shift_count; | ||
310 | } | ||
311 | |||
312 | if (((unsigned long)(-1) / 100) < cur.aperf.split.lo) { | ||
313 | int shift_count = 7; | ||
314 | cur.aperf.split.lo >>= shift_count; | ||
315 | cur.mperf.split.lo >>= shift_count; | ||
316 | } | ||
317 | |||
318 | if (cur.aperf.split.lo && cur.mperf.split.lo) | ||
319 | perf_percent = (cur.aperf.split.lo * 100) / cur.mperf.split.lo; | ||
320 | else | ||
321 | perf_percent = 0; | ||
322 | |||
323 | #else | ||
324 | if (unlikely(((unsigned long)(-1) / 100) < cur.aperf.whole)) { | ||
325 | int shift_count = 7; | ||
326 | cur.aperf.whole >>= shift_count; | ||
327 | cur.mperf.whole >>= shift_count; | ||
328 | } | ||
329 | |||
330 | if (cur.aperf.whole && cur.mperf.whole) | ||
331 | perf_percent = (cur.aperf.whole * 100) / cur.mperf.whole; | ||
332 | else | ||
333 | perf_percent = 0; | ||
334 | |||
335 | #endif | ||
336 | 275 | ||
337 | retval = (policy->cpuinfo.max_freq * perf_percent) / 100; | 276 | retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; |
338 | 277 | ||
339 | return retval; | 278 | return retval; |
340 | } | 279 | } |