Commit 5d33b883 authored by Thomas Gleixner's avatar Thomas Gleixner

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: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarJohn Stultz <john.stultz@linaro.org>
Cc: Magnus Damm <magnus.damm@gmail.com>
Link: http://lkml.kernel.org/r/20130425143435.635040849@linutronix.deSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent fc1f7d56
...@@ -553,6 +553,26 @@ static u64 clocksource_max_deferment(struct clocksource *cs) ...@@ -553,6 +553,26 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET #ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
static struct clocksource *clocksource_find_best(bool oneshot)
{
struct clocksource *cs;
if (!finished_booting || list_empty(&clocksource_list))
return NULL;
/*
* We pick the clocksource with the highest rating. If oneshot
* mode is active, we pick the highres valid clocksource with
* the best rating.
*/
list_for_each_entry(cs, &clocksource_list, list) {
if (oneshot && !(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES))
continue;
return cs;
}
return NULL;
}
/** /**
* clocksource_select - Select the best clocksource available * clocksource_select - Select the best clocksource available
* *
...@@ -563,12 +583,14 @@ static u64 clocksource_max_deferment(struct clocksource *cs) ...@@ -563,12 +583,14 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
*/ */
static void clocksource_select(void) static void clocksource_select(void)
{ {
bool oneshot = tick_oneshot_mode_active();
struct clocksource *best, *cs; struct clocksource *best, *cs;
if (!finished_booting || list_empty(&clocksource_list)) /* Find the best suitable clocksource */
best = clocksource_find_best(oneshot);
if (!best)
return; return;
/* First clocksource on the list has the best rating. */
best = list_first_entry(&clocksource_list, struct clocksource, list);
/* Check for the override clocksource. */ /* Check for the override clocksource. */
list_for_each_entry(cs, &clocksource_list, list) { list_for_each_entry(cs, &clocksource_list, list) {
if (strcmp(cs->name, override_name) != 0) if (strcmp(cs->name, override_name) != 0)
...@@ -578,8 +600,7 @@ static void clocksource_select(void) ...@@ -578,8 +600,7 @@ static void clocksource_select(void)
* capable clocksource if the tick code is in oneshot * capable clocksource if the tick code is in oneshot
* mode (highres or nohz) * mode (highres or nohz)
*/ */
if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && oneshot) {
tick_oneshot_mode_active()) {
/* Override clocksource cannot be used. */ /* Override clocksource cannot be used. */
printk(KERN_WARNING "Override clocksource %s is not " printk(KERN_WARNING "Override clocksource %s is not "
"HRT compatible. Cannot switch while in " "HRT compatible. Cannot switch while in "
......
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