LKML Archive on lore.kernel.org help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de> To: Andrew Morton <akpm@osdl.org> Cc: LKML <linux-kernel@vger.kernel.org>, Ingo Molnar <mingo@elte.hu>, John Stultz <johnstul@us.ibm.com>, Arjan van de Veen <arjan@infradead.org>, Roman Zippel <zippel@linux-m68k.org> Subject: [patch 18/46] clocksource: Add verification (watchdog) helper Date: Tue, 23 Jan 2007 22:01:14 -0000 [thread overview] Message-ID: <20070123211205.541044000@localhost.localdomain> (raw) In-Reply-To: 20070123211159.178138000@localhost.localdomain [-- Attachment #1: clocksource-add-verification-helper.patch --] [-- Type: text/plain, Size: 11075 bytes --] From: Thomas Gleixner <tglx@linutronix.de> The TSC needs to be verified against another clocksource. Instead of using hardwired assumptions of available hardware, provide a generic verification mechanism. The verification uses the best available clocksource and handles the usability for high resolution timers / dynticks of the clocksource which needs to be verified. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/i386/Kconfig | 4 + arch/i386/kernel/tsc.c | 49 ----------------- include/linux/clocksource.h | 15 ++++- kernel/time/clocksource.c | 125 ++++++++++++++++++++++++++++++++++++++++++-- kernel/timer.c | 46 ++++++++-------- 5 files changed, 161 insertions(+), 78 deletions(-) Index: linux-2.6.20-rc4-mm1-bo/arch/i386/kernel/tsc.c =================================================================== --- linux-2.6.20-rc4-mm1-bo.orig/arch/i386/kernel/tsc.c +++ linux-2.6.20-rc4-mm1-bo/arch/i386/kernel/tsc.c @@ -344,49 +344,6 @@ static struct dmi_system_id __initdata b {} }; -#define TSC_FREQ_CHECK_INTERVAL (10*MSEC_PER_SEC) /* 10sec in MS */ -static struct timer_list verify_tsc_freq_timer; - -/* XXX - Probably should add locking */ -static void verify_tsc_freq(unsigned long unused) -{ - static u64 last_tsc; - static unsigned long last_jiffies; - - u64 now_tsc, interval_tsc; - unsigned long now_jiffies, interval_jiffies; - - - if (check_tsc_unstable()) - return; - - rdtscll(now_tsc); - now_jiffies = jiffies; - - if (!last_jiffies) { - goto out; - } - - interval_jiffies = now_jiffies - last_jiffies; - interval_tsc = now_tsc - last_tsc; - interval_tsc *= HZ; - do_div(interval_tsc, cpu_khz*1000); - - if (interval_tsc < (interval_jiffies * 3 / 4)) { - printk("TSC appears to be running slowly. " - "Marking it as unstable\n"); - mark_tsc_unstable(); - return; - } - -out: - last_tsc = now_tsc; - last_jiffies = now_jiffies; - /* set us up to go off on the next interval: */ - mod_timer(&verify_tsc_freq_timer, - jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL)); -} - /* * Make an educated guess if the TSC is trustworthy and synchronized * over all CPUs. @@ -424,12 +381,6 @@ static int __init init_tsc_clocksource(v clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS; } - init_timer(&verify_tsc_freq_timer); - verify_tsc_freq_timer.function = verify_tsc_freq; - verify_tsc_freq_timer.expires = - jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL); - add_timer(&verify_tsc_freq_timer); - return clocksource_register(&clocksource_tsc); } Index: linux-2.6.20-rc4-mm1-bo/include/linux/clocksource.h =================================================================== --- linux-2.6.20-rc4-mm1-bo.orig/include/linux/clocksource.h +++ linux-2.6.20-rc4-mm1-bo/include/linux/clocksource.h @@ -12,11 +12,13 @@ #include <linux/timex.h> #include <linux/time.h> #include <linux/list.h> +#include <linux/timer.h> #include <asm/div64.h> #include <asm/io.h> /* clocksource cycle base type */ typedef u64 cycle_t; +struct clocksource; /** * struct clocksource - hardware abstraction for a free running counter @@ -62,13 +64,22 @@ struct clocksource { cycle_t cycle_last, cycle_interval; u64 xtime_nsec, xtime_interval; s64 error; + +#ifdef CONFIG_CLOCKSOURCE_WATCHDOG + /* Watchdog related data, used by the framework */ + struct list_head wd_list; + cycle_t wd_last; +#endif }; /* * Clock source flags bits:: */ -#define CLOCK_SOURCE_IS_CONTINUOUS 0x01 -#define CLOCK_SOURCE_MUST_VERIFY 0x02 +#define CLOCK_SOURCE_IS_CONTINUOUS 0x01 +#define CLOCK_SOURCE_MUST_VERIFY 0x02 + +#define CLOCK_SOURCE_WATCHDOG 0x10 +#define CLOCK_SOURCE_VALID_FOR_HRES 0x20 /* simplify initialization of mask field */ #define CLOCKSOURCE_MASK(bits) (cycle_t)(bits<64 ? ((1ULL<<bits)-1) : -1) Index: linux-2.6.20-rc4-mm1-bo/kernel/time/clocksource.c =================================================================== --- linux-2.6.20-rc4-mm1-bo.orig/kernel/time/clocksource.c +++ linux-2.6.20-rc4-mm1-bo/kernel/time/clocksource.c @@ -62,9 +62,115 @@ static int __init clocksource_done_booti finished_booting = 1; return 0; } - late_initcall(clocksource_done_booting); +#ifdef CONFIG_CLOCKSOURCE_WATCHDOG +static LIST_HEAD(watchdog_list); +static struct clocksource *watchdog; +static struct timer_list watchdog_timer; +static DEFINE_SPINLOCK(watchdog_lock); +static cycle_t watchdog_last; +/* + * Interval: 0.5sec Treshold: 0.0625s + */ +#define WATCHDOG_INTERVAL (HZ >> 1) +#define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4) + +static void clocksource_ratewd(struct clocksource *cs, int64_t delta) +{ + if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD) + 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); + cs->flags &= ~CLOCK_SOURCE_WATCHDOG; + list_del(&cs->wd_list); +} + +static void clocksource_watchdog(unsigned long data) +{ + struct clocksource *cs, *tmp; + cycle_t csnow, wdnow; + int64_t wd_nsec, cs_nsec; + + spin_lock(&watchdog_lock); + + wdnow = watchdog->read(); + wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask); + watchdog_last = wdnow; + + list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) { + csnow = cs->read(); + /* Initialized ? */ + if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) { + if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && + (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) + cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; + cs->flags |= CLOCK_SOURCE_WATCHDOG; + cs->wd_last = csnow; + } else { + cs_nsec = cyc2ns(cs, (csnow - cs->wd_last) & cs->mask); + cs->wd_last = csnow; + /* Check the delta. Might remove from the list ! */ + clocksource_ratewd(cs, cs_nsec - wd_nsec); + } + } + + if (!list_empty(&watchdog_list)) { + __mod_timer(&watchdog_timer, + watchdog_timer.expires + WATCHDOG_INTERVAL); + } + spin_unlock(&watchdog_lock); +} +static void clocksource_check_watchdog(struct clocksource *cs) +{ + struct clocksource *cse; + unsigned long flags; + + spin_lock_irqsave(&watchdog_lock, flags); + if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) { + int started = !list_empty(&watchdog_list); + + list_add(&cs->wd_list, &watchdog_list); + if (!started && watchdog) { + watchdog_last = watchdog->read(); + watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL; + add_timer(&watchdog_timer); + } + } else if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) { + cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; + + if (!watchdog || cs->rating > watchdog->rating) { + if (watchdog) + del_timer(&watchdog_timer); + watchdog = cs; + init_timer(&watchdog_timer); + watchdog_timer.function = clocksource_watchdog; + + /* Reset watchdog cycles */ + list_for_each_entry(cse, &watchdog_list, wd_list) + cse->flags &= ~CLOCK_SOURCE_WATCHDOG; + /* Start if list is not empty */ + if (!list_empty(&watchdog_list)) { + watchdog_last = watchdog->read(); + watchdog_timer.expires = + jiffies + WATCHDOG_INTERVAL; + add_timer(&watchdog_timer); + } + } + } + spin_unlock_irqrestore(&watchdog_lock, flags); +} +#else +static void clocksource_check_watchdog(struct clocksource *cs) +{ + if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) + cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; +} +#endif + /** * clocksource_get_next - Returns the selected clocksource * @@ -93,13 +199,21 @@ struct clocksource *clocksource_get_next */ static struct clocksource *select_clocksource(void) { + struct clocksource *next; + if (list_empty(&clocksource_list)) return NULL; if (clocksource_override) - return clocksource_override; + next = clocksource_override; + else + next = list_entry(clocksource_list.next, struct clocksource, + list); - return list_entry(clocksource_list.next, struct clocksource, list); + if (next == curr_clocksource) + return NULL; + + return next; } /* @@ -137,13 +251,15 @@ static int clocksource_enqueue(struct cl int clocksource_register(struct clocksource *c) { unsigned long flags; - int ret = 0; + int ret; spin_lock_irqsave(&clocksource_lock, flags); ret = clocksource_enqueue(c); if (!ret) next_clocksource = select_clocksource(); spin_unlock_irqrestore(&clocksource_lock, flags); + if (!ret) + clocksource_check_watchdog(c); return ret; } EXPORT_SYMBOL(clocksource_register); @@ -158,6 +274,7 @@ void clocksource_change_rating(struct cl spin_lock_irqsave(&clocksource_lock, flags); list_del(&cs->list); + cs->rating = rating; clocksource_enqueue(cs); next_clocksource = select_clocksource(); spin_unlock_irqrestore(&clocksource_lock, flags); Index: linux-2.6.20-rc4-mm1-bo/kernel/timer.c =================================================================== --- linux-2.6.20-rc4-mm1-bo.orig/kernel/timer.c +++ linux-2.6.20-rc4-mm1-bo/kernel/timer.c @@ -832,30 +832,34 @@ EXPORT_SYMBOL(do_settimeofday); * * Accumulates current time interval and initializes new clocksource */ -static int change_clocksource(void) +static void change_clocksource(void) { struct clocksource *new; cycle_t now; u64 nsec; + new = clocksource_get_next(); - if (clock != new) { - now = clocksource_read(new); - nsec = __get_nsec_offset(); - timespec_add_ns(&xtime, nsec); - - clock = new; - clock->cycle_last = now; - printk(KERN_INFO "Time: %s clocksource has been installed.\n", - clock->name); - return 1; - } - return 0; + + if (clock == new) + return; + + now = clocksource_read(new); + nsec = __get_nsec_offset(); + timespec_add_ns(&xtime, nsec); + + clock = new; + clock->cycle_last = now; + + clock->error = 0; + clock->xtime_nsec = 0; + clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH); + + hrtimer_clock_notify(); + printk(KERN_INFO "Time: %s clocksource has been installed.\n", + clock->name); } #else -static inline int change_clocksource(void) -{ - return 0; -} +static inline void change_clocksource(void) { } #endif /** @@ -869,7 +873,7 @@ int timekeeping_is_continuous(void) do { seq = read_seqbegin(&xtime_lock); - ret = clock->flags & CLOCK_SOURCE_IS_CONTINUOUS; + ret = clock->flags & CLOCK_SOURCE_VALID_FOR_HRES; } while (read_seqretry(&xtime_lock, seq)); @@ -1122,11 +1126,7 @@ static void update_wall_time(void) clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift; /* check to see if there is a new clocksource to use */ - if (change_clocksource()) { - clock->error = 0; - clock->xtime_nsec = 0; - clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH); - } + change_clocksource(); } /* Index: linux-2.6.20-rc4-mm1-bo/arch/i386/Kconfig =================================================================== --- linux-2.6.20-rc4-mm1-bo.orig/arch/i386/Kconfig +++ linux-2.6.20-rc4-mm1-bo/arch/i386/Kconfig @@ -18,6 +18,10 @@ config GENERIC_TIME bool default y +config CLOCKSOURCE_WATCHDOG + bool + default y + config LOCKDEP_SUPPORT bool default y --
next prev parent reply other threads:[~2007-01-23 22:04 UTC|newest] Thread overview: 78+ messages / expand[flat|nested] mbox.gz Atom feed top 2007-01-23 22:00 [patch 00/46] High resolution timer / dynamic tick update Thomas Gleixner 2007-01-23 22:00 ` [patch 01/46] Add irq flag to disable balancing for an interrupt Thomas Gleixner 2007-01-23 22:00 ` [patch 02/46] Add a functions to handle interrupt affinity setting Thomas Gleixner 2007-01-23 22:00 ` [patch 03/46] [RFC] HZ free ntp Thomas Gleixner 2007-01-23 22:00 ` [patch 04/46] Uninline jiffies.h functions Thomas Gleixner 2007-01-23 22:01 ` [patch 05/46] Thomas Gleixner 2007-01-23 22:01 ` [patch 06/46] Fix timeout overflow with jiffies Thomas Gleixner 2007-01-23 22:01 ` [patch 07/46] GTOD: persistent clock support Thomas Gleixner 2007-01-23 22:01 ` [patch 08/46] i386: use GTOD " Thomas Gleixner 2007-01-23 22:01 ` [patch 09/46] i386 Remove useless code in tsc.c Thomas Gleixner 2007-01-23 22:01 ` [patch 10/46] Simplify the registration of clocksources Thomas Gleixner 2007-01-23 22:01 ` [patch 11/46] x86: rewrite SMP TSC sync code Thomas Gleixner 2007-01-23 22:01 ` [patch 12/46] clocksource: replace is_continuous by a flag field Thomas Gleixner 2007-01-24 11:23 ` [patch] clocksource: fixup is_continous changes in vmitime.c Ingo Molnar 2007-01-24 11:53 ` Thomas Gleixner 2007-01-23 22:01 ` [patch 13/46] clocksource: fixup is_continous changes on ARM Thomas Gleixner 2007-01-23 22:01 ` [patch 14/46] clocksource: fixup is_continous changes on AVR32 Thomas Gleixner 2007-01-23 22:01 ` [patch 15/46] clocksource: fixup is_continous changes on S390 Thomas Gleixner 2007-01-23 22:01 ` [patch 16/46] clocksource: fixup is_continous changes on MIPS Thomas Gleixner 2007-01-23 22:01 ` [patch 17/46] clocksource: Remove the update callback Thomas Gleixner 2007-01-23 22:01 ` Thomas Gleixner [this message] 2007-01-24 15:42 ` [patch] clocksource: add verification (watchdog) helper, fix Ingo Molnar 2007-01-23 22:01 ` [patch 19/46] Mark TSC on GeodeLX reliable Thomas Gleixner 2007-01-23 22:01 ` [patch 20/46] uninline irq_enter() Thomas Gleixner 2007-01-23 22:01 ` [patch 21/46] Fix cascade lookup of next_timer_interrupt Thomas Gleixner 2007-01-23 22:01 ` [patch 22/46] Extend next_timer_interrupt() to use a reference jiffie Thomas Gleixner 2007-01-23 22:01 ` [patch 23/46] hrtimers: namespace and enum cleanup Thomas Gleixner 2007-01-23 22:01 ` [patch 24/46] hrtimers: namespace and enum cleanup vs. git-input Thomas Gleixner 2007-01-23 22:01 ` [patch 25/46] hrtimers: cleanup locking Thomas Gleixner 2007-01-23 22:01 ` [patch 26/46] hrtimers; add state tracking Thomas Gleixner 2007-01-23 22:01 ` [patch 27/46] hrtimers: clean up callback tracking Thomas Gleixner 2007-01-23 22:01 ` [patch 28/46] hrtimers: move and add documentation Thomas Gleixner 2007-01-23 22:01 ` [patch 29/46] ACPI: fix missing include for UP Thomas Gleixner 2007-01-23 22:01 ` [patch 30/46] ACPI keep track of timer broadcasting Thomas Gleixner 2007-01-23 22:01 ` [patch 31/46] Allow early access to the power management timer Thomas Gleixner 2007-01-23 22:01 ` [patch 32/46] i386, apic: clean up the APIC code Thomas Gleixner 2007-01-23 22:01 ` [patch 33/46] clockevents: add core functionality Thomas Gleixner 2007-01-23 22:01 ` [patch 34/46] tick-management: " Thomas Gleixner 2007-01-23 22:01 ` [patch 35/46] tick-management: broadcast functionality Thomas Gleixner 2007-01-23 22:01 ` [patch 36/46] tick-management: dyntick / highres functionality Thomas Gleixner 2007-01-28 2:03 ` [PATCH] high_res_timers: precisely update_process_times; " Karsten Wiese 2007-01-23 22:01 ` [patch 37/46] clockevents: i383 drivers Thomas Gleixner 2007-01-23 22:01 ` [patch 38/46] i386 rework local apic timer calibration Thomas Gleixner 2007-01-23 22:01 ` [patch 39/46] i386 prepare for dyntick Thomas Gleixner 2007-01-23 22:01 ` [patch 40/46] i386 prepare nmi watchdog for dynticks Thomas Gleixner 2007-01-23 22:01 ` [patch 41/46] i386: enable dynticks in kconfig Thomas Gleixner 2007-01-23 22:01 ` [patch 42/46] hrtimers: add high resolution timer support Thomas Gleixner 2007-01-23 22:01 ` [patch 43/46] hrtimers: prevent possible itimer DoS Thomas Gleixner 2007-01-23 22:01 ` [patch 44/46] Add debugging feature /proc/timer_stat Thomas Gleixner 2007-01-23 22:01 ` [patch 45/46] Add debugging feature /proc/timer_list Thomas Gleixner 2007-01-23 22:01 ` [patch 46/46] Add SysRq-Q to print timer_list debug info Thomas Gleixner 2007-01-24 2:16 ` [patch 00/46] High resolution timer / dynamic tick update Daniel Walker 2007-01-24 2:23 ` Andrew Morton 2007-01-24 3:25 ` Daniel Walker 2007-01-24 7:07 ` Ingo Molnar 2007-01-24 9:30 ` Daniel Walker 2007-01-24 9:51 ` Ingo Molnar 2007-01-24 10:23 ` Daniel Walker 2007-01-24 10:29 ` Ingo Molnar 2007-01-24 10:53 ` Daniel Walker 2007-01-24 11:04 ` Ingo Molnar 2007-01-24 11:13 ` Thomas Gleixner 2007-01-24 15:53 ` Daniel Walker [not found] ` <20070124160046.GA24798@elte.hu> 2007-01-24 17:21 ` Daniel Walker [not found] ` <1169655076.19471.241.camel@imap.mvista.com> 2007-01-24 19:38 ` Ingo Molnar 2007-01-24 20:09 ` Daniel Walker 2007-01-24 20:13 ` Ingo Molnar 2007-01-24 19:57 ` john stultz 2007-01-24 20:51 ` Daniel Walker 2007-01-24 21:23 ` john stultz 2007-01-24 21:37 ` Daniel Walker 2007-01-25 6:10 ` Ingo Molnar 2007-01-25 6:37 ` Ingo Molnar 2007-01-25 6:32 ` Ingo Molnar 2007-01-25 16:38 ` Daniel Walker 2007-01-28 2:17 ` Andrew Morton 2007-01-29 21:31 ` john stultz 2007-01-29 21:45 ` john stultz
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20070123211205.541044000@localhost.localdomain \ --to=tglx@linutronix.de \ --cc=akpm@osdl.org \ --cc=arjan@infradead.org \ --cc=johnstul@us.ibm.com \ --cc=linux-kernel@vger.kernel.org \ --cc=mingo@elte.hu \ --cc=zippel@linux-m68k.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).