aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-09-14 13:49:02 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-09-14 15:59:32 -0400
commit54a6bc0b071c50150bc6d1da16c2cd9a963e288c (patch)
tree87b576e31db14f6d57b0d8ed97743ab9779de30e
parente6c733050faa93ce616bfedccd279ab12cffdd7b (diff)
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: Thomas Gleixner <tglx@linutronix.de> LKML-Reference: <new-submission> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--kernel/time/clocksource.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 2c2e5ba1453d..09113347d328 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -121,6 +121,7 @@ static struct clocksource *curr_clocksource;
121static LIST_HEAD(clocksource_list); 121static LIST_HEAD(clocksource_list);
122static DEFINE_MUTEX(clocksource_mutex); 122static DEFINE_MUTEX(clocksource_mutex);
123static char override_name[32]; 123static char override_name[32];
124static int finished_booting;
124 125
125#ifdef CONFIG_CLOCKSOURCE_WATCHDOG 126#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
126static void clocksource_watchdog_work(struct work_struct *work); 127static void clocksource_watchdog_work(struct work_struct *work);
@@ -155,7 +156,8 @@ static void __clocksource_unstable(struct clocksource *cs)
155{ 156{
156 cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); 157 cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG);
157 cs->flags |= CLOCK_SOURCE_UNSTABLE; 158 cs->flags |= CLOCK_SOURCE_UNSTABLE;
158 schedule_work(&watchdog_work); 159 if (finished_booting)
160 schedule_work(&watchdog_work);
159} 161}
160 162
161static void clocksource_unstable(struct clocksource *cs, int64_t delta) 163static void clocksource_unstable(struct clocksource *cs, int64_t delta)
@@ -207,7 +209,8 @@ static void clocksource_watchdog(unsigned long data)
207 209
208 /* Clocksource already marked unstable? */ 210 /* Clocksource already marked unstable? */
209 if (cs->flags & CLOCK_SOURCE_UNSTABLE) { 211 if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
210 schedule_work(&watchdog_work); 212 if (finished_booting)
213 schedule_work(&watchdog_work);
211 continue; 214 continue;
212 } 215 }
213 216
@@ -380,6 +383,7 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs)
380 383
381static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { } 384static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }
382static inline void clocksource_resume_watchdog(void) { } 385static inline void clocksource_resume_watchdog(void) { }
386static inline int clocksource_watchdog_kthread(void *data) { return 0; }
383 387
384#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */ 388#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
385 389
@@ -415,8 +419,6 @@ void clocksource_touch_watchdog(void)
415 419
416#ifdef CONFIG_GENERIC_TIME 420#ifdef CONFIG_GENERIC_TIME
417 421
418static int finished_booting;
419
420/** 422/**
421 * clocksource_select - Select the best clocksource available 423 * clocksource_select - Select the best clocksource available
422 * 424 *
@@ -461,6 +463,12 @@ static void clocksource_select(void)
461 } 463 }
462} 464}
463 465
466#else /* CONFIG_GENERIC_TIME */
467
468static inline void clocksource_select(void) { }
469
470#endif
471
464/* 472/*
465 * clocksource_done_booting - Called near the end of core bootup 473 * clocksource_done_booting - Called near the end of core bootup
466 * 474 *
@@ -471,6 +479,12 @@ static void clocksource_select(void)
471static int __init clocksource_done_booting(void) 479static int __init clocksource_done_booting(void)
472{ 480{
473 finished_booting = 1; 481 finished_booting = 1;
482
483 /*
484 * Run the watchdog first to eliminate unstable clock sources
485 */
486 clocksource_watchdog_kthread(NULL);
487
474 mutex_lock(&clocksource_mutex); 488 mutex_lock(&clocksource_mutex);
475 clocksource_select(); 489 clocksource_select();
476 mutex_unlock(&clocksource_mutex); 490 mutex_unlock(&clocksource_mutex);
@@ -478,12 +492,6 @@ static int __init clocksource_done_booting(void)
478} 492}
479fs_initcall(clocksource_done_booting); 493fs_initcall(clocksource_done_booting);
480 494
481#else /* CONFIG_GENERIC_TIME */
482
483static inline void clocksource_select(void) { }
484
485#endif
486
487/* 495/*
488 * Enqueue the clocksource sorted by rating 496 * Enqueue the clocksource sorted by rating
489 */ 497 */