aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2013-04-25 16:31:43 -0400
committerThomas Gleixner <tglx@linutronix.de>2013-05-16 05:09:14 -0400
commit5d33b883aed81c6fbcd09c6f7c3619eee850a7e2 (patch)
treea9bcc623b0ecc99bf9fc7f2b30be5a8a2a56bc6d /kernel/time
parentfc1f7d5606487ae28d6c84e95401952927d7379e (diff)
clocksource: Always verify highres capability
If a clocksource has a (wrong) high rating, but can't be used as a timebase for oneshot tick mode, it is unconditionally selected even when the system is already in oneshot tick mode. This causes full system failure. Verify the clocksource selection against the oneshot mode. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: John Stultz <john.stultz@linaro.org> Cc: Magnus Damm <magnus.damm@gmail.com> Link: http://lkml.kernel.org/r/20130425143435.635040849@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/clocksource.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index c9583382141a..dda5c7130d93 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -553,6 +553,26 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
553 553
554#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET 554#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
555 555
556static struct clocksource *clocksource_find_best(bool oneshot)
557{
558 struct clocksource *cs;
559
560 if (!finished_booting || list_empty(&clocksource_list))
561 return NULL;
562
563 /*
564 * We pick the clocksource with the highest rating. If oneshot
565 * mode is active, we pick the highres valid clocksource with
566 * the best rating.
567 */
568 list_for_each_entry(cs, &clocksource_list, list) {
569 if (oneshot && !(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES))
570 continue;
571 return cs;
572 }
573 return NULL;
574}
575
556/** 576/**
557 * clocksource_select - Select the best clocksource available 577 * clocksource_select - Select the best clocksource available
558 * 578 *
@@ -563,12 +583,14 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
563 */ 583 */
564static void clocksource_select(void) 584static void clocksource_select(void)
565{ 585{
586 bool oneshot = tick_oneshot_mode_active();
566 struct clocksource *best, *cs; 587 struct clocksource *best, *cs;
567 588
568 if (!finished_booting || list_empty(&clocksource_list)) 589 /* Find the best suitable clocksource */
590 best = clocksource_find_best(oneshot);
591 if (!best)
569 return; 592 return;
570 /* First clocksource on the list has the best rating. */ 593
571 best = list_first_entry(&clocksource_list, struct clocksource, list);
572 /* Check for the override clocksource. */ 594 /* Check for the override clocksource. */
573 list_for_each_entry(cs, &clocksource_list, list) { 595 list_for_each_entry(cs, &clocksource_list, list) {
574 if (strcmp(cs->name, override_name) != 0) 596 if (strcmp(cs->name, override_name) != 0)
@@ -578,8 +600,7 @@ static void clocksource_select(void)
578 * capable clocksource if the tick code is in oneshot 600 * capable clocksource if the tick code is in oneshot
579 * mode (highres or nohz) 601 * mode (highres or nohz)
580 */ 602 */
581 if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && 603 if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && oneshot) {
582 tick_oneshot_mode_active()) {
583 /* Override clocksource cannot be used. */ 604 /* Override clocksource cannot be used. */
584 printk(KERN_WARNING "Override clocksource %s is not " 605 printk(KERN_WARNING "Override clocksource %s is not "
585 "HRT compatible. Cannot switch while in " 606 "HRT compatible. Cannot switch while in "