diff options
| -rw-r--r-- | include/linux/tick.h | 3 | ||||
| -rw-r--r-- | kernel/time/clocksource.c | 20 | ||||
| -rw-r--r-- | kernel/time/tick-oneshot.c | 17 |
3 files changed, 39 insertions, 1 deletions
diff --git a/include/linux/tick.h b/include/linux/tick.h index 469b82d88b3b..0482229c07db 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h | |||
| @@ -97,10 +97,12 @@ extern void tick_clock_notify(void); | |||
| 97 | extern int tick_check_oneshot_change(int allow_nohz); | 97 | extern int tick_check_oneshot_change(int allow_nohz); |
| 98 | extern struct tick_sched *tick_get_tick_sched(int cpu); | 98 | extern struct tick_sched *tick_get_tick_sched(int cpu); |
| 99 | extern void tick_check_idle(int cpu); | 99 | extern void tick_check_idle(int cpu); |
| 100 | extern int tick_oneshot_mode_active(void); | ||
| 100 | # else | 101 | # else |
| 101 | static inline void tick_clock_notify(void) { } | 102 | static inline void tick_clock_notify(void) { } |
| 102 | static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } | 103 | static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } |
| 103 | static inline void tick_check_idle(int cpu) { } | 104 | static inline void tick_check_idle(int cpu) { } |
| 105 | static inline int tick_oneshot_mode_active(void) { return 0; } | ||
| 104 | # endif | 106 | # endif |
| 105 | 107 | ||
| 106 | #else /* CONFIG_GENERIC_CLOCKEVENTS */ | 108 | #else /* CONFIG_GENERIC_CLOCKEVENTS */ |
| @@ -109,6 +111,7 @@ static inline void tick_cancel_sched_timer(int cpu) { } | |||
| 109 | static inline void tick_clock_notify(void) { } | 111 | static inline void tick_clock_notify(void) { } |
| 110 | static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } | 112 | static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } |
| 111 | static inline void tick_check_idle(int cpu) { } | 113 | static inline void tick_check_idle(int cpu) { } |
| 114 | static inline int tick_oneshot_mode_active(void) { return 0; } | ||
| 112 | #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ | 115 | #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ |
| 113 | 116 | ||
| 114 | # ifdef CONFIG_NO_HZ | 117 | # ifdef CONFIG_NO_HZ |
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 80189f6f1c5a..592bf584d1d2 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
| @@ -509,6 +509,18 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, | |||
| 509 | } | 509 | } |
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | /* | ||
| 513 | * Check to make sure we don't switch to a non-highres capable | ||
| 514 | * clocksource if the tick code is in oneshot mode (highres or nohz) | ||
| 515 | */ | ||
| 516 | if (tick_oneshot_mode_active() && | ||
| 517 | !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) { | ||
| 518 | printk(KERN_WARNING "%s clocksource is not HRT compatible. " | ||
| 519 | "Cannot switch while in HRT/NOHZ mode\n", ovr->name); | ||
| 520 | ovr = NULL; | ||
| 521 | override_name[0] = 0; | ||
| 522 | } | ||
| 523 | |||
| 512 | /* Reselect, when the override name has changed */ | 524 | /* Reselect, when the override name has changed */ |
| 513 | if (ovr != clocksource_override) { | 525 | if (ovr != clocksource_override) { |
| 514 | clocksource_override = ovr; | 526 | clocksource_override = ovr; |
| @@ -537,7 +549,13 @@ sysfs_show_available_clocksources(struct sys_device *dev, | |||
| 537 | 549 | ||
| 538 | spin_lock_irq(&clocksource_lock); | 550 | spin_lock_irq(&clocksource_lock); |
| 539 | list_for_each_entry(src, &clocksource_list, list) { | 551 | list_for_each_entry(src, &clocksource_list, list) { |
| 540 | count += snprintf(buf + count, | 552 | /* |
| 553 | * Don't show non-HRES clocksource if the tick code is | ||
| 554 | * in one shot mode (highres=on or nohz=on) | ||
| 555 | */ | ||
| 556 | if (!tick_oneshot_mode_active() || | ||
| 557 | (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) | ||
| 558 | count += snprintf(buf + count, | ||
| 541 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), | 559 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), |
| 542 | "%s ", src->name); | 560 | "%s ", src->name); |
| 543 | } | 561 | } |
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 2e8de678e767..a96c0e2b89cf 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c | |||
| @@ -128,6 +128,23 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) | |||
| 128 | return 0; | 128 | return 0; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | /** | ||
| 132 | * tick_check_oneshot_mode - check whether the system is in oneshot mode | ||
| 133 | * | ||
| 134 | * returns 1 when either nohz or highres are enabled. otherwise 0. | ||
| 135 | */ | ||
| 136 | int tick_oneshot_mode_active(void) | ||
| 137 | { | ||
| 138 | unsigned long flags; | ||
| 139 | int ret; | ||
| 140 | |||
| 141 | local_irq_save(flags); | ||
| 142 | ret = __get_cpu_var(tick_cpu_device).mode == TICKDEV_MODE_ONESHOT; | ||
| 143 | local_irq_restore(flags); | ||
| 144 | |||
| 145 | return ret; | ||
| 146 | } | ||
| 147 | |||
| 131 | #ifdef CONFIG_HIGH_RES_TIMERS | 148 | #ifdef CONFIG_HIGH_RES_TIMERS |
| 132 | /** | 149 | /** |
| 133 | * tick_init_highres - switch to high resolution mode | 150 | * tick_init_highres - switch to high resolution mode |
