diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d8362cf..e150946 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -473,6 +473,14 @@ and is between 256 and 4096 characters. It is defined in the file [SPARC64] tick [X86-64] hpet,tsc + force_tsc_stable=1 + Force the TSC to be treated as a stable clocksource, + even if the rate-watchdog code would otherwise treat + it as unstable. If you see + 'Clocksource tsc unstable (delta = [num])' in your logs + but have reason to think your TSC is OK, then you may + want to try this option. + clearcpuid=BITNUM [X86] Disable CPUID feature X for the kernel. See arch/x86/include/asm/cpufeature.h for the valid bit diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index ca89e15..4788727 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -54,6 +54,7 @@ static LIST_HEAD(clocksource_list); static DEFINE_SPINLOCK(clocksource_lock); static char override_name[32]; static int finished_booting; +static int force_tsc_stable; /* clocksource_done_booting - Called near the end of core bootup * @@ -82,16 +83,29 @@ static unsigned long watchdog_resumed; #define WATCHDOG_INTERVAL (HZ >> 1) #define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4) +static int __init parse_force_tsc_stable(char *arg) +{ + force_tsc_stable = 1; + return 0; +} +early_param("force_tsc_stable", parse_force_tsc_stable); + + static void clocksource_ratewd(struct clocksource *cs, int64_t delta) { if (delta > -WATCHDOG_THRESHOLD && delta < WATCHDOG_THRESHOLD) return; - printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", - cs->name, delta); - cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); - clocksource_change_rating(cs, 0); - list_del(&cs->wd_list); + if (force_tsc_stable && (strcmp(cs->name, "tsc") == 0)) + printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns). Ignoring instability.\n", + cs->name, delta); + else { + printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", + cs->name, delta); + cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); + clocksource_change_rating(cs, 0); + list_del(&cs->wd_list); + } } static void clocksource_watchdog(unsigned long data)