aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-06-12 05:29:27 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-06-13 06:00:26 -0400
commitcd6d95d8449b7c9f415f26041e9ae173d387b6bd (patch)
treeddd1f2d6436f398419045b3e0ee860c01523cfea
parent3f68535adad8dd89499505a65fb25d0e02d118cc (diff)
clocksource: prevent selection of low resolution clocksourse also for nohz=on
commit 3f68535adad (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: Luming Yu <luming.yu@gmail.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/hrtimer.h2
-rw-r--r--include/linux/tick.h3
-rw-r--r--kernel/hrtimer.c4
-rw-r--r--kernel/time/clocksource.c18
-rw-r--r--kernel/time/tick-oneshot.c17
5 files changed, 33 insertions, 11 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 58021b0c396d..0d2f7c8a33d6 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -305,7 +305,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
305 305
306extern ktime_t ktime_get(void); 306extern ktime_t ktime_get(void);
307extern ktime_t ktime_get_real(void); 307extern ktime_t ktime_get_real(void);
308extern int hrtimer_hres_active(void); 308
309 309
310DECLARE_PER_CPU(struct tick_device, tick_cpu_device); 310DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
311 311
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);
97extern int tick_check_oneshot_change(int allow_nohz); 97extern int tick_check_oneshot_change(int allow_nohz);
98extern struct tick_sched *tick_get_tick_sched(int cpu); 98extern struct tick_sched *tick_get_tick_sched(int cpu);
99extern void tick_check_idle(int cpu); 99extern void tick_check_idle(int cpu);
100extern int tick_oneshot_mode_active(void);
100# else 101# else
101static inline void tick_clock_notify(void) { } 102static inline void tick_clock_notify(void) { }
102static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } 103static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
103static inline void tick_check_idle(int cpu) { } 104static inline void tick_check_idle(int cpu) { }
105static 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) { }
109static inline void tick_clock_notify(void) { } 111static inline void tick_clock_notify(void) { }
110static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } 112static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
111static inline void tick_check_idle(int cpu) { } 113static inline void tick_check_idle(int cpu) { }
114static 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/hrtimer.c b/kernel/hrtimer.c
index 1a70c18cdffe..cb8a15c19583 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -476,7 +476,7 @@ static inline int hrtimer_is_hres_enabled(void)
476/* 476/*
477 * Is the high resolution mode active ? 477 * Is the high resolution mode active ?
478 */ 478 */
479int hrtimer_hres_active(void) 479static inline int hrtimer_hres_active(void)
480{ 480{
481 return __get_cpu_var(hrtimer_bases).hres_active; 481 return __get_cpu_var(hrtimer_bases).hres_active;
482} 482}
@@ -704,7 +704,7 @@ static int hrtimer_switch_to_hres(void)
704 704
705#else 705#else
706 706
707int hrtimer_hres_active(void) { return 0; } 707static inline int hrtimer_hres_active(void) { return 0; }
708static inline int hrtimer_is_hres_enabled(void) { return 0; } 708static inline int hrtimer_is_hres_enabled(void) { return 0; }
709static inline int hrtimer_switch_to_hres(void) { return 0; } 709static inline int hrtimer_switch_to_hres(void) { return 0; }
710static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } 710static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { }
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 18b9f5da4ee9..592bf584d1d2 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -30,7 +30,6 @@
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ 31#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
32#include <linux/tick.h> 32#include <linux/tick.h>
33#include <linux/hrtimer.h>
34 33
35void timecounter_init(struct timecounter *tc, 34void timecounter_init(struct timecounter *tc,
36 const struct cyclecounter *cc, 35 const struct cyclecounter *cc,
@@ -511,13 +510,13 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev,
511 } 510 }
512 511
513 /* 512 /*
514 * Check to make sure we don't switch to a non-HRT usable 513 * Check to make sure we don't switch to a non-highres capable
515 * clocksource if HRT is enabled and running 514 * clocksource if the tick code is in oneshot mode (highres or nohz)
516 */ 515 */
517 if (hrtimer_hres_active() && 516 if (tick_oneshot_mode_active() &&
518 !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) { 517 !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) {
519 printk(KERN_WARNING "%s clocksource is not HRT compatible. " 518 printk(KERN_WARNING "%s clocksource is not HRT compatible. "
520 "Cannot switch while in HRT mode\n", ovr->name); 519 "Cannot switch while in HRT/NOHZ mode\n", ovr->name);
521 ovr = NULL; 520 ovr = NULL;
522 override_name[0] = 0; 521 override_name[0] = 0;
523 } 522 }
@@ -550,9 +549,12 @@ sysfs_show_available_clocksources(struct sys_device *dev,
550 549
551 spin_lock_irq(&clocksource_lock); 550 spin_lock_irq(&clocksource_lock);
552 list_for_each_entry(src, &clocksource_list, list) { 551 list_for_each_entry(src, &clocksource_list, list) {
553 /* Don't show non-HRES clocksource if HRES is enabled */ 552 /*
554 if (!hrtimer_hres_active() || 553 * Don't show non-HRES clocksource if the tick code is
555 (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) 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))
556 count += snprintf(buf + count, 558 count += snprintf(buf + count,
557 max((ssize_t)PAGE_SIZE - count, (ssize_t)0), 559 max((ssize_t)PAGE_SIZE - count, (ssize_t)0),
558 "%s ", src->name); 560 "%s ", src->name);
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 */
136int 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