aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/tsc.c
diff options
context:
space:
mode:
authorAlok Kataria <akataria@vmware.com>2008-10-24 20:22:01 -0400
committerH. Peter Anvin <hpa@zytor.com>2008-11-01 21:59:03 -0400
commit395628ef4ea12ff0748099f145363b5e33c69acb (patch)
treeacc192f65338af801f20a2688366ac5c66dcbc09 /arch/x86/kernel/tsc.c
parenteca0cd028bdf0f6aaceb0d023e9c7501079a7dda (diff)
x86: Skip verification by the watchdog for TSC clocksource.
Impact: Changes timekeeping on Vmware (or with tsc=reliable). This is achieved by resetting the CLOCKSOURCE_MUST_VERIFY flag. We add a tsc=reliable commandline option to enable this. This enables legacy hardware without HPET, LAPIC, or ACPI timers to enter high-resolution timer mode. Along with that have extended this to be used in virtualization environement too. Now we also set this flag if the X86_FEATURE_TSC_RELIABLE bit is set. This is important since there is a wrap-around problem with the acpi_pm timer. The acpi_pm counter is just 24bits and this can overflow in ~4 seconds. With the NO_HZ kernels in virtualized environment, there can be situations when the guest is descheduled for longer duration, as a result we may miss the wrap of the acpi counter. When TSC is used as a clocksource and acpi_pm timer is being used as the watchdog clocksource this error in acpi_pm results in TSC being marked as unstable, and essentially results in time dropping in chunks of 4 seconds whenever this wrap is missed. Since the virtualized TSC is reliable on VMware, we should always use the TSCs clocksource on VMware, so we skip the verfication at runtime, by checking for the feature bit. Since we reset the flag for mgeode systems too, i have combined the mgeode case with the feature bit check. Signed-off-by: Jeff Hansen <jhansen@cardaccess-inc.com> Signed-off-by: Alok N Kataria <akataria@vmware.com> Signed-off-by: Dan Hecht <dhecht@vmware.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel/tsc.c')
-rw-r--r--arch/x86/kernel/tsc.c33
1 files changed, 21 insertions, 12 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 6dbf0bcb44a8..ee01cd96b5e1 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -32,6 +32,7 @@ static int tsc_unstable;
32 erroneous rdtsc usage on !cpu_has_tsc processors */ 32 erroneous rdtsc usage on !cpu_has_tsc processors */
33static int tsc_disabled = -1; 33static int tsc_disabled = -1;
34 34
35static int tsc_clocksource_reliable;
35/* 36/*
36 * Scheduler clock - returns current time in nanosec units. 37 * Scheduler clock - returns current time in nanosec units.
37 */ 38 */
@@ -99,6 +100,15 @@ int __init notsc_setup(char *str)
99 100
100__setup("notsc", notsc_setup); 101__setup("notsc", notsc_setup);
101 102
103static 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
102#define MAX_RETRIES 5 112#define MAX_RETRIES 5
103#define SMI_TRESHOLD 50000 113#define SMI_TRESHOLD 50000
104 114
@@ -738,24 +748,21 @@ static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
738 {} 748 {}
739}; 749};
740 750
741/* 751static void __init check_system_tsc_reliable(void)
742 * Geode_LX - the OLPC CPU has a possibly a very reliable TSC 752{
743 */
744#ifdef CONFIG_MGEODE_LX 753#ifdef CONFIG_MGEODE_LX
745/* RTSC counts during suspend */ 754 /* RTSC counts during suspend */
746#define RTSC_SUSP 0x100 755#define RTSC_SUSP 0x100
747
748static void __init check_geode_tsc_reliable(void)
749{
750 unsigned long res_low, res_high; 756 unsigned long res_low, res_high;
751 757
752 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 */
753 if (res_low & RTSC_SUSP) 760 if (res_low & RTSC_SUSP)
754 clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; 761 tsc_clocksource_reliable = 1;
755}
756#else
757static inline void check_geode_tsc_reliable(void) { }
758#endif 762#endif
763 if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE))
764 tsc_clocksource_reliable = 1;
765}
759 766
760/* 767/*
761 * Make an educated guess if the TSC is trustworthy and synchronized 768 * Make an educated guess if the TSC is trustworthy and synchronized
@@ -790,6 +797,8 @@ static void __init init_tsc_clocksource(void)
790{ 797{
791 clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, 798 clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
792 clocksource_tsc.shift); 799 clocksource_tsc.shift);
800 if (tsc_clocksource_reliable)
801 clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
793 /* lower the rating if we already know its unstable: */ 802 /* lower the rating if we already know its unstable: */
794 if (check_tsc_unstable()) { 803 if (check_tsc_unstable()) {
795 clocksource_tsc.rating = 0; 804 clocksource_tsc.rating = 0;
@@ -850,7 +859,7 @@ void __init tsc_init(void)
850 if (unsynchronized_tsc()) 859 if (unsynchronized_tsc())
851 mark_tsc_unstable("TSCs unsynchronized"); 860 mark_tsc_unstable("TSCs unsynchronized");
852 861
853 check_geode_tsc_reliable(); 862 check_system_tsc_reliable();
854 init_tsc_clocksource(); 863 init_tsc_clocksource();
855} 864}
856 865