Commit 54a6bc0b authored by Thomas Gleixner's avatar Thomas Gleixner

clocksource: Delay clocksource down rating to late boot

The down rating of clock sources in the early boot process via the
clock source watchdog mechanism can happen way before the per cpu
event queues are initialized. This leads to a boot crash on x86 when
the TSC is marked unstable in the SMP bring up.

The selection of a clock source for time keeping happens in the late
boot process so we can safely delay the list manipulation until
clocksource_done_booting() is called.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
LKML-Reference: <new-submission>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
parent e6c73305
...@@ -121,6 +121,7 @@ static struct clocksource *curr_clocksource; ...@@ -121,6 +121,7 @@ static struct clocksource *curr_clocksource;
static LIST_HEAD(clocksource_list); static LIST_HEAD(clocksource_list);
static DEFINE_MUTEX(clocksource_mutex); static DEFINE_MUTEX(clocksource_mutex);
static char override_name[32]; static char override_name[32];
static int finished_booting;
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
static void clocksource_watchdog_work(struct work_struct *work); static void clocksource_watchdog_work(struct work_struct *work);
...@@ -155,7 +156,8 @@ static void __clocksource_unstable(struct clocksource *cs) ...@@ -155,7 +156,8 @@ static void __clocksource_unstable(struct clocksource *cs)
{ {
cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG);
cs->flags |= CLOCK_SOURCE_UNSTABLE; cs->flags |= CLOCK_SOURCE_UNSTABLE;
schedule_work(&watchdog_work); if (finished_booting)
schedule_work(&watchdog_work);
} }
static void clocksource_unstable(struct clocksource *cs, int64_t delta) static void clocksource_unstable(struct clocksource *cs, int64_t delta)
...@@ -207,7 +209,8 @@ static void clocksource_watchdog(unsigned long data) ...@@ -207,7 +209,8 @@ static void clocksource_watchdog(unsigned long data)
/* Clocksource already marked unstable? */ /* Clocksource already marked unstable? */
if (cs->flags & CLOCK_SOURCE_UNSTABLE) { if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
schedule_work(&watchdog_work); if (finished_booting)
schedule_work(&watchdog_work);
continue; continue;
} }
...@@ -380,6 +383,7 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs) ...@@ -380,6 +383,7 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs)
static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { } static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }
static inline void clocksource_resume_watchdog(void) { } static inline void clocksource_resume_watchdog(void) { }
static inline int clocksource_watchdog_kthread(void *data) { return 0; }
#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */ #endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
...@@ -415,8 +419,6 @@ void clocksource_touch_watchdog(void) ...@@ -415,8 +419,6 @@ void clocksource_touch_watchdog(void)
#ifdef CONFIG_GENERIC_TIME #ifdef CONFIG_GENERIC_TIME
static int finished_booting;
/** /**
* clocksource_select - Select the best clocksource available * clocksource_select - Select the best clocksource available
* *
...@@ -461,6 +463,12 @@ static void clocksource_select(void) ...@@ -461,6 +463,12 @@ static void clocksource_select(void)
} }
} }
#else /* CONFIG_GENERIC_TIME */
static inline void clocksource_select(void) { }
#endif
/* /*
* clocksource_done_booting - Called near the end of core bootup * clocksource_done_booting - Called near the end of core bootup
* *
...@@ -471,6 +479,12 @@ static void clocksource_select(void) ...@@ -471,6 +479,12 @@ static void clocksource_select(void)
static int __init clocksource_done_booting(void) static int __init clocksource_done_booting(void)
{ {
finished_booting = 1; finished_booting = 1;
/*
* Run the watchdog first to eliminate unstable clock sources
*/
clocksource_watchdog_kthread(NULL);
mutex_lock(&clocksource_mutex); mutex_lock(&clocksource_mutex);
clocksource_select(); clocksource_select();
mutex_unlock(&clocksource_mutex); mutex_unlock(&clocksource_mutex);
...@@ -478,12 +492,6 @@ static int __init clocksource_done_booting(void) ...@@ -478,12 +492,6 @@ static int __init clocksource_done_booting(void)
} }
fs_initcall(clocksource_done_booting); fs_initcall(clocksource_done_booting);
#else /* CONFIG_GENERIC_TIME */
static inline void clocksource_select(void) { }
#endif
/* /*
* Enqueue the clocksource sorted by rating * Enqueue the clocksource sorted by rating
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment