Commit cd6d95d8 authored by Thomas Gleixner's avatar Thomas Gleixner

clocksource: prevent selection of low resolution clocksourse also for nohz=on

commit 3f68535a (clocksource: sanity check sysfs clocksource
changes) prevents selection of non high resolution capable
clocksources when high resolution mode is active, but did not take
into account that the same rules apply for highres=off nohz=on.

Check the tick device mode instead of hrtimer_hres_active() to verify
whether the system needs to be protected from a switch to jiffies or
other non highres capable clock sources.
Reported-by: default avatarLuming Yu <luming.yu@gmail.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 3f68535a
...@@ -305,7 +305,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) ...@@ -305,7 +305,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
extern ktime_t ktime_get(void); extern ktime_t ktime_get(void);
extern ktime_t ktime_get_real(void); extern ktime_t ktime_get_real(void);
extern int hrtimer_hres_active(void);
DECLARE_PER_CPU(struct tick_device, tick_cpu_device); DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
......
...@@ -97,10 +97,12 @@ extern void tick_clock_notify(void); ...@@ -97,10 +97,12 @@ extern void tick_clock_notify(void);
extern int tick_check_oneshot_change(int allow_nohz); extern int tick_check_oneshot_change(int allow_nohz);
extern struct tick_sched *tick_get_tick_sched(int cpu); extern struct tick_sched *tick_get_tick_sched(int cpu);
extern void tick_check_idle(int cpu); extern void tick_check_idle(int cpu);
extern int tick_oneshot_mode_active(void);
# else # else
static inline void tick_clock_notify(void) { } static inline void tick_clock_notify(void) { }
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
static inline void tick_check_idle(int cpu) { } static inline void tick_check_idle(int cpu) { }
static inline int tick_oneshot_mode_active(void) { return 0; }
# endif # endif
#else /* CONFIG_GENERIC_CLOCKEVENTS */ #else /* CONFIG_GENERIC_CLOCKEVENTS */
...@@ -109,6 +111,7 @@ static inline void tick_cancel_sched_timer(int cpu) { } ...@@ -109,6 +111,7 @@ static inline void tick_cancel_sched_timer(int cpu) { }
static inline void tick_clock_notify(void) { } static inline void tick_clock_notify(void) { }
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
static inline void tick_check_idle(int cpu) { } static inline void tick_check_idle(int cpu) { }
static inline int tick_oneshot_mode_active(void) { return 0; }
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */ #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
# ifdef CONFIG_NO_HZ # ifdef CONFIG_NO_HZ
......
...@@ -476,7 +476,7 @@ static inline int hrtimer_is_hres_enabled(void) ...@@ -476,7 +476,7 @@ static inline int hrtimer_is_hres_enabled(void)
/* /*
* Is the high resolution mode active ? * Is the high resolution mode active ?
*/ */
int hrtimer_hres_active(void) static inline int hrtimer_hres_active(void)
{ {
return __get_cpu_var(hrtimer_bases).hres_active; return __get_cpu_var(hrtimer_bases).hres_active;
} }
...@@ -704,7 +704,7 @@ static int hrtimer_switch_to_hres(void) ...@@ -704,7 +704,7 @@ static int hrtimer_switch_to_hres(void)
#else #else
int hrtimer_hres_active(void) { return 0; } static inline int hrtimer_hres_active(void) { return 0; }
static inline int hrtimer_is_hres_enabled(void) { return 0; } static inline int hrtimer_is_hres_enabled(void) { return 0; }
static inline int hrtimer_switch_to_hres(void) { return 0; } static inline int hrtimer_switch_to_hres(void) { return 0; }
static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { }
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/hrtimer.h>
void timecounter_init(struct timecounter *tc, void timecounter_init(struct timecounter *tc,
const struct cyclecounter *cc, const struct cyclecounter *cc,
...@@ -511,13 +510,13 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, ...@@ -511,13 +510,13 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev,
} }
/* /*
* Check to make sure we don't switch to a non-HRT usable * Check to make sure we don't switch to a non-highres capable
* clocksource if HRT is enabled and running * clocksource if the tick code is in oneshot mode (highres or nohz)
*/ */
if (hrtimer_hres_active() && if (tick_oneshot_mode_active() &&
!(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) { !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) {
printk(KERN_WARNING "%s clocksource is not HRT compatible. " printk(KERN_WARNING "%s clocksource is not HRT compatible. "
"Cannot switch while in HRT mode\n", ovr->name); "Cannot switch while in HRT/NOHZ mode\n", ovr->name);
ovr = NULL; ovr = NULL;
override_name[0] = 0; override_name[0] = 0;
} }
...@@ -550,9 +549,12 @@ sysfs_show_available_clocksources(struct sys_device *dev, ...@@ -550,9 +549,12 @@ sysfs_show_available_clocksources(struct sys_device *dev,
spin_lock_irq(&clocksource_lock); spin_lock_irq(&clocksource_lock);
list_for_each_entry(src, &clocksource_list, list) { list_for_each_entry(src, &clocksource_list, list) {
/* Don't show non-HRES clocksource if HRES is enabled */ /*
if (!hrtimer_hres_active() || * Don't show non-HRES clocksource if the tick code is
(src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) * in one shot mode (highres=on or nohz=on)
*/
if (!tick_oneshot_mode_active() ||
(src->flags & CLOCK_SOURCE_VALID_FOR_HRES))
count += snprintf(buf + count, count += snprintf(buf + count,
max((ssize_t)PAGE_SIZE - count, (ssize_t)0), max((ssize_t)PAGE_SIZE - count, (ssize_t)0),
"%s ", src->name); "%s ", src->name);
......
...@@ -128,6 +128,23 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) ...@@ -128,6 +128,23 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
return 0; return 0;
} }
/**
* tick_check_oneshot_mode - check whether the system is in oneshot mode
*
* returns 1 when either nohz or highres are enabled. otherwise 0.
*/
int tick_oneshot_mode_active(void)
{
unsigned long flags;
int ret;
local_irq_save(flags);
ret = __get_cpu_var(tick_cpu_device).mode == TICKDEV_MODE_ONESHOT;
local_irq_restore(flags);
return ret;
}
#ifdef CONFIG_HIGH_RES_TIMERS #ifdef CONFIG_HIGH_RES_TIMERS
/** /**
* tick_init_highres - switch to high resolution mode * tick_init_highres - switch to high resolution mode
......
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