diff options
Diffstat (limited to 'arch/x86/kernel/tsc.c')
-rw-r--r-- | arch/x86/kernel/tsc.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 424093b157d3..599e58168631 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <asm/vgtod.h> | 15 | #include <asm/vgtod.h> |
16 | #include <asm/time.h> | 16 | #include <asm/time.h> |
17 | #include <asm/delay.h> | 17 | #include <asm/delay.h> |
18 | #include <asm/hypervisor.h> | ||
18 | 19 | ||
19 | unsigned int cpu_khz; /* TSC clocks / usec, not used here */ | 20 | unsigned int cpu_khz; /* TSC clocks / usec, not used here */ |
20 | EXPORT_SYMBOL(cpu_khz); | 21 | EXPORT_SYMBOL(cpu_khz); |
@@ -31,6 +32,7 @@ static int tsc_unstable; | |||
31 | erroneous rdtsc usage on !cpu_has_tsc processors */ | 32 | erroneous rdtsc usage on !cpu_has_tsc processors */ |
32 | static int tsc_disabled = -1; | 33 | static int tsc_disabled = -1; |
33 | 34 | ||
35 | static int tsc_clocksource_reliable; | ||
34 | /* | 36 | /* |
35 | * Scheduler clock - returns current time in nanosec units. | 37 | * Scheduler clock - returns current time in nanosec units. |
36 | */ | 38 | */ |
@@ -98,6 +100,15 @@ int __init notsc_setup(char *str) | |||
98 | 100 | ||
99 | __setup("notsc", notsc_setup); | 101 | __setup("notsc", notsc_setup); |
100 | 102 | ||
103 | static int __init tsc_setup(char *str) | ||
104 | { | ||
105 | if (!strcmp(str, "reliable")) | ||
106 | tsc_clocksource_reliable = 1; | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | __setup("tsc=", tsc_setup); | ||
111 | |||
101 | #define MAX_RETRIES 5 | 112 | #define MAX_RETRIES 5 |
102 | #define SMI_TRESHOLD 50000 | 113 | #define SMI_TRESHOLD 50000 |
103 | 114 | ||
@@ -352,9 +363,15 @@ unsigned long native_calibrate_tsc(void) | |||
352 | { | 363 | { |
353 | u64 tsc1, tsc2, delta, ref1, ref2; | 364 | u64 tsc1, tsc2, delta, ref1, ref2; |
354 | unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; | 365 | unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; |
355 | unsigned long flags, latch, ms, fast_calibrate; | 366 | unsigned long flags, latch, ms, fast_calibrate, tsc_khz; |
356 | int hpet = is_hpet_enabled(), i, loopmin; | 367 | int hpet = is_hpet_enabled(), i, loopmin; |
357 | 368 | ||
369 | tsc_khz = get_hypervisor_tsc_freq(); | ||
370 | if (tsc_khz) { | ||
371 | printk(KERN_INFO "TSC: Frequency read from the hypervisor\n"); | ||
372 | return tsc_khz; | ||
373 | } | ||
374 | |||
358 | local_irq_save(flags); | 375 | local_irq_save(flags); |
359 | fast_calibrate = quick_pit_calibrate(); | 376 | fast_calibrate = quick_pit_calibrate(); |
360 | local_irq_restore(flags); | 377 | local_irq_restore(flags); |
@@ -731,24 +748,21 @@ static struct dmi_system_id __initdata bad_tsc_dmi_table[] = { | |||
731 | {} | 748 | {} |
732 | }; | 749 | }; |
733 | 750 | ||
734 | /* | 751 | static void __init check_system_tsc_reliable(void) |
735 | * Geode_LX - the OLPC CPU has a possibly a very reliable TSC | 752 | { |
736 | */ | ||
737 | #ifdef CONFIG_MGEODE_LX | 753 | #ifdef CONFIG_MGEODE_LX |
738 | /* RTSC counts during suspend */ | 754 | /* RTSC counts during suspend */ |
739 | #define RTSC_SUSP 0x100 | 755 | #define RTSC_SUSP 0x100 |
740 | |||
741 | static void __init check_geode_tsc_reliable(void) | ||
742 | { | ||
743 | unsigned long res_low, res_high; | 756 | unsigned long res_low, res_high; |
744 | 757 | ||
745 | rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); | 758 | rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); |
759 | /* Geode_LX - the OLPC CPU has a possibly a very reliable TSC */ | ||
746 | if (res_low & RTSC_SUSP) | 760 | if (res_low & RTSC_SUSP) |
747 | clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; | 761 | tsc_clocksource_reliable = 1; |
748 | } | ||
749 | #else | ||
750 | static inline void check_geode_tsc_reliable(void) { } | ||
751 | #endif | 762 | #endif |
763 | if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) | ||
764 | tsc_clocksource_reliable = 1; | ||
765 | } | ||
752 | 766 | ||
753 | /* | 767 | /* |
754 | * Make an educated guess if the TSC is trustworthy and synchronized | 768 | * Make an educated guess if the TSC is trustworthy and synchronized |
@@ -783,6 +797,8 @@ static void __init init_tsc_clocksource(void) | |||
783 | { | 797 | { |
784 | clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, | 798 | clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, |
785 | clocksource_tsc.shift); | 799 | clocksource_tsc.shift); |
800 | if (tsc_clocksource_reliable) | ||
801 | clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; | ||
786 | /* lower the rating if we already know its unstable: */ | 802 | /* lower the rating if we already know its unstable: */ |
787 | if (check_tsc_unstable()) { | 803 | if (check_tsc_unstable()) { |
788 | clocksource_tsc.rating = 0; | 804 | clocksource_tsc.rating = 0; |
@@ -843,7 +859,7 @@ void __init tsc_init(void) | |||
843 | if (unsynchronized_tsc()) | 859 | if (unsynchronized_tsc()) |
844 | mark_tsc_unstable("TSCs unsynchronized"); | 860 | mark_tsc_unstable("TSCs unsynchronized"); |
845 | 861 | ||
846 | check_geode_tsc_reliable(); | 862 | check_system_tsc_reliable(); |
847 | init_tsc_clocksource(); | 863 | init_tsc_clocksource(); |
848 | } | 864 | } |
849 | 865 | ||