aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/tsc.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-08-20 10:27:41 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-08-31 03:35:46 -0400
commit08047c4f1740c7cee75d58e2919d48c09f951649 (patch)
treeffaf378e4be6dec0ef572f30385c1c545c7df494 /arch/x86/kernel/tsc.c
parent454ede7eebf91b92ab1eafe10c6b6ed04de29bf8 (diff)
x86: Move calibrate_cpu to tsc.c
Move the code where it's only user is. Also we need to look whether this hardwired hackery might interfere with perfcounters. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/tsc.c')
-rw-r--r--arch/x86/kernel/tsc.c57
1 files changed, 55 insertions, 2 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 652bc214eebf..97a0bcbad100 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -17,6 +17,7 @@
17#include <asm/time.h> 17#include <asm/time.h>
18#include <asm/delay.h> 18#include <asm/delay.h>
19#include <asm/hypervisor.h> 19#include <asm/hypervisor.h>
20#include <asm/nmi.h>
20 21
21unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */ 22unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */
22EXPORT_SYMBOL(cpu_khz); 23EXPORT_SYMBOL(cpu_khz);
@@ -852,6 +853,60 @@ static void __init init_tsc_clocksource(void)
852 clocksource_register(&clocksource_tsc); 853 clocksource_register(&clocksource_tsc);
853} 854}
854 855
856#ifdef CONFIG_X86_64
857/*
858 * calibrate_cpu is used on systems with fixed rate TSCs to determine
859 * processor frequency
860 */
861#define TICK_COUNT 100000000
862static unsigned long __init calibrate_cpu(void)
863{
864 int tsc_start, tsc_now;
865 int i, no_ctr_free;
866 unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
867 unsigned long flags;
868
869 for (i = 0; i < 4; i++)
870 if (avail_to_resrv_perfctr_nmi_bit(i))
871 break;
872 no_ctr_free = (i == 4);
873 if (no_ctr_free) {
874 WARN(1, KERN_WARNING "Warning: AMD perfctrs busy ... "
875 "cpu_khz value may be incorrect.\n");
876 i = 3;
877 rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
878 wrmsrl(MSR_K7_EVNTSEL3, 0);
879 rdmsrl(MSR_K7_PERFCTR3, pmc3);
880 } else {
881 reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
882 reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
883 }
884 local_irq_save(flags);
885 /* start measuring cycles, incrementing from 0 */
886 wrmsrl(MSR_K7_PERFCTR0 + i, 0);
887 wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
888 rdtscl(tsc_start);
889 do {
890 rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
891 tsc_now = get_cycles();
892 } while ((tsc_now - tsc_start) < TICK_COUNT);
893
894 local_irq_restore(flags);
895 if (no_ctr_free) {
896 wrmsrl(MSR_K7_EVNTSEL3, 0);
897 wrmsrl(MSR_K7_PERFCTR3, pmc3);
898 wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
899 } else {
900 release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
901 release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
902 }
903
904 return pmc_now * tsc_khz / (tsc_now - tsc_start);
905}
906#else
907static inline unsigned long calibrate_cpu(void) { return cpu_khz; }
908#endif
909
855void __init tsc_init(void) 910void __init tsc_init(void)
856{ 911{
857 u64 lpj; 912 u64 lpj;
@@ -870,11 +925,9 @@ void __init tsc_init(void)
870 return; 925 return;
871 } 926 }
872 927
873#ifdef CONFIG_X86_64
874 if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) && 928 if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
875 (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)) 929 (boot_cpu_data.x86_vendor == X86_VENDOR_AMD))
876 cpu_khz = calibrate_cpu(); 930 cpu_khz = calibrate_cpu();
877#endif
878 931
879 printk("Detected %lu.%03lu MHz processor.\n", 932 printk("Detected %lu.%03lu MHz processor.\n",
880 (unsigned long)cpu_khz / 1000, 933 (unsigned long)cpu_khz / 1000,