aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-09-02 05:49:52 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-15 10:51:26 -0400
commit5cbc19a983141729d716be17197028434127b376 (patch)
treecabde63550658a141404fe85fbf23d3ab735481e /arch
parenta8303aaf2b2f74714db6d204ab4fcb810942664e (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>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/processor.h30
-rw-r--r--arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c79
2 files changed, 39 insertions, 70 deletions
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index e08ea043e085..4ae2ccfed638 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,
1020extern int get_tsc_mode(unsigned long adr); 1021extern int get_tsc_mode(unsigned long adr);
1021extern int set_tsc_mode(unsigned int val); 1022extern int set_tsc_mode(unsigned int val);
1022 1023
1024struct aperfmperf {
1025 u64 aperf, mperf;
1026};
1027
1028static 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
1038static inline
1039unsigned 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 509e6a7db719..4109679863c1 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
71static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data); 71static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data);
72 72
73struct acpi_msr_data { 73static DEFINE_PER_CPU(struct aperfmperf, old_perf);
74 u64 saved_aperf, saved_mperf;
75};
76
77static DEFINE_PER_CPU(struct acpi_msr_data, msr_data);
78 74
79DEFINE_TRACE(power_mark); 75DEFINE_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
246struct 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 */
257static void read_measured_perf_ctrs(void *_cur) 243static 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)
278static unsigned int get_measured_perf(struct cpufreq_policy *policy, 263static 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}