summaryrefslogtreecommitdiff
path: root/kernel/time
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2013-04-25 20:31:43 +0000
committerThomas Gleixner <tglx@linutronix.de>2013-05-16 11:09:14 +0200
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 c9583382141..dda5c7130d9 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -553,6 +553,26 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
#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
*
@@ -563,12 +583,14 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
*/
static void clocksource_select(void)
{
+ bool oneshot = tick_oneshot_mode_active();
struct clocksource *best, *cs;
- if (!finished_booting || list_empty(&clocksource_list))
+ /* Find the best suitable clocksource */
+ best = clocksource_find_best(oneshot);
+ if (!best)
return;
- /* First clocksource on the list has the best rating. */
- best = list_first_entry(&clocksource_list, struct clocksource, list);
+
/* Check for the override clocksource. */
list_for_each_entry(cs, &clocksource_list, list) {
if (strcmp(cs->name, override_name) != 0)
@@ -578,8 +600,7 @@ static void clocksource_select(void)
* capable clocksource if the tick code is in oneshot
* mode (highres or nohz)
*/
- if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) &&
- tick_oneshot_mode_active()) {
+ if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && oneshot) {
/* Override clocksource cannot be used. */
printk(KERN_WARNING "Override clocksource %s is not "
"HRT compatible. Cannot switch while in "