diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-09-23 17:57:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-09-23 17:57:36 -0400 |
| commit | 8553f321e0fd29821135ac4797b5f37bf80ae2e9 (patch) | |
| tree | fa64ef70c4e503f62a09b56b792bb63b791aa121 /kernel | |
| parent | be3be8905854d2fcf6030f1da9ebc221e9e2c5f1 (diff) | |
| parent | f8e256c687eb53850685747757c8d75e58756e15 (diff) | |
Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
timers: fix build error in !oneshot case
x86: c1e_idle: don't mark TSC unstable if CPU has invariant TSC
x86: prevent C-states hang on AMD C1E enabled machines
clockevents: prevent mode mismatch on cpu online
clockevents: check broadcast device not tick device
clockevents: prevent stale tick_next_period for onlining CPUs
x86: prevent stale state of c1e_mask across CPU offline/online
clockevents: prevent cpu online to interfere with nohz
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/time/tick-broadcast.c | 12 | ||||
| -rw-r--r-- | kernel/time/tick-common.c | 10 | ||||
| -rw-r--r-- | kernel/time/tick-internal.h | 7 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 11 |
4 files changed, 30 insertions, 10 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index f1f3eee28113..bd7034542399 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
| @@ -235,7 +235,7 @@ static void tick_do_broadcast_on_off(void *why) | |||
| 235 | case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: | 235 | case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: |
| 236 | if (!cpu_isset(cpu, tick_broadcast_mask)) { | 236 | if (!cpu_isset(cpu, tick_broadcast_mask)) { |
| 237 | cpu_set(cpu, tick_broadcast_mask); | 237 | cpu_set(cpu, tick_broadcast_mask); |
| 238 | if (td->mode == TICKDEV_MODE_PERIODIC) | 238 | if (bc->mode == TICKDEV_MODE_PERIODIC) |
| 239 | clockevents_shutdown(dev); | 239 | clockevents_shutdown(dev); |
| 240 | } | 240 | } |
| 241 | if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE) | 241 | if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE) |
| @@ -245,7 +245,7 @@ static void tick_do_broadcast_on_off(void *why) | |||
| 245 | if (!tick_broadcast_force && | 245 | if (!tick_broadcast_force && |
| 246 | cpu_isset(cpu, tick_broadcast_mask)) { | 246 | cpu_isset(cpu, tick_broadcast_mask)) { |
| 247 | cpu_clear(cpu, tick_broadcast_mask); | 247 | cpu_clear(cpu, tick_broadcast_mask); |
| 248 | if (td->mode == TICKDEV_MODE_PERIODIC) | 248 | if (bc->mode == TICKDEV_MODE_PERIODIC) |
| 249 | tick_setup_periodic(dev, 0); | 249 | tick_setup_periodic(dev, 0); |
| 250 | } | 250 | } |
| 251 | break; | 251 | break; |
| @@ -575,4 +575,12 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup) | |||
| 575 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); | 575 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); |
| 576 | } | 576 | } |
| 577 | 577 | ||
| 578 | /* | ||
| 579 | * Check, whether the broadcast device is in one shot mode | ||
| 580 | */ | ||
| 581 | int tick_broadcast_oneshot_active(void) | ||
| 582 | { | ||
| 583 | return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT; | ||
| 584 | } | ||
| 585 | |||
| 578 | #endif | 586 | #endif |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 019315ebf9de..df12434b43ca 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
| @@ -33,7 +33,7 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device); | |||
| 33 | */ | 33 | */ |
| 34 | ktime_t tick_next_period; | 34 | ktime_t tick_next_period; |
| 35 | ktime_t tick_period; | 35 | ktime_t tick_period; |
| 36 | int tick_do_timer_cpu __read_mostly = -1; | 36 | int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT; |
| 37 | DEFINE_SPINLOCK(tick_device_lock); | 37 | DEFINE_SPINLOCK(tick_device_lock); |
| 38 | 38 | ||
| 39 | /* | 39 | /* |
| @@ -109,7 +109,8 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast) | |||
| 109 | if (!tick_device_is_functional(dev)) | 109 | if (!tick_device_is_functional(dev)) |
| 110 | return; | 110 | return; |
| 111 | 111 | ||
| 112 | if (dev->features & CLOCK_EVT_FEAT_PERIODIC) { | 112 | if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) && |
| 113 | !tick_broadcast_oneshot_active()) { | ||
| 113 | clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC); | 114 | clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC); |
| 114 | } else { | 115 | } else { |
| 115 | unsigned long seq; | 116 | unsigned long seq; |
| @@ -148,7 +149,7 @@ static void tick_setup_device(struct tick_device *td, | |||
| 148 | * If no cpu took the do_timer update, assign it to | 149 | * If no cpu took the do_timer update, assign it to |
| 149 | * this cpu: | 150 | * this cpu: |
| 150 | */ | 151 | */ |
| 151 | if (tick_do_timer_cpu == -1) { | 152 | if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) { |
| 152 | tick_do_timer_cpu = cpu; | 153 | tick_do_timer_cpu = cpu; |
| 153 | tick_next_period = ktime_get(); | 154 | tick_next_period = ktime_get(); |
| 154 | tick_period = ktime_set(0, NSEC_PER_SEC / HZ); | 155 | tick_period = ktime_set(0, NSEC_PER_SEC / HZ); |
| @@ -300,7 +301,8 @@ static void tick_shutdown(unsigned int *cpup) | |||
| 300 | if (*cpup == tick_do_timer_cpu) { | 301 | if (*cpup == tick_do_timer_cpu) { |
| 301 | int cpu = first_cpu(cpu_online_map); | 302 | int cpu = first_cpu(cpu_online_map); |
| 302 | 303 | ||
| 303 | tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : -1; | 304 | tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : |
| 305 | TICK_DO_TIMER_NONE; | ||
| 304 | } | 306 | } |
| 305 | spin_unlock_irqrestore(&tick_device_lock, flags); | 307 | spin_unlock_irqrestore(&tick_device_lock, flags); |
| 306 | } | 308 | } |
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 6e9db9734aa6..469248782c23 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * tick internal variable and functions used by low/high res code | 2 | * tick internal variable and functions used by low/high res code |
| 3 | */ | 3 | */ |
| 4 | |||
| 5 | #define TICK_DO_TIMER_NONE -1 | ||
| 6 | #define TICK_DO_TIMER_BOOT -2 | ||
| 7 | |||
| 4 | DECLARE_PER_CPU(struct tick_device, tick_cpu_device); | 8 | DECLARE_PER_CPU(struct tick_device, tick_cpu_device); |
| 5 | extern spinlock_t tick_device_lock; | 9 | extern spinlock_t tick_device_lock; |
| 6 | extern ktime_t tick_next_period; | 10 | extern ktime_t tick_next_period; |
| @@ -31,6 +35,7 @@ extern void tick_broadcast_oneshot_control(unsigned long reason); | |||
| 31 | extern void tick_broadcast_switch_to_oneshot(void); | 35 | extern void tick_broadcast_switch_to_oneshot(void); |
| 32 | extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup); | 36 | extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup); |
| 33 | extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc); | 37 | extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc); |
| 38 | extern int tick_broadcast_oneshot_active(void); | ||
| 34 | # else /* BROADCAST */ | 39 | # else /* BROADCAST */ |
| 35 | static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) | 40 | static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) |
| 36 | { | 41 | { |
| @@ -39,6 +44,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) | |||
| 39 | static inline void tick_broadcast_oneshot_control(unsigned long reason) { } | 44 | static inline void tick_broadcast_oneshot_control(unsigned long reason) { } |
| 40 | static inline void tick_broadcast_switch_to_oneshot(void) { } | 45 | static inline void tick_broadcast_switch_to_oneshot(void) { } |
| 41 | static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } | 46 | static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } |
| 47 | static inline int tick_broadcast_oneshot_active(void) { return 0; } | ||
| 42 | # endif /* !BROADCAST */ | 48 | # endif /* !BROADCAST */ |
| 43 | 49 | ||
| 44 | #else /* !ONESHOT */ | 50 | #else /* !ONESHOT */ |
| @@ -68,6 +74,7 @@ static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc) | |||
| 68 | { | 74 | { |
| 69 | return 0; | 75 | return 0; |
| 70 | } | 76 | } |
| 77 | static inline int tick_broadcast_oneshot_active(void) { return 0; } | ||
| 71 | #endif /* !TICK_ONESHOT */ | 78 | #endif /* !TICK_ONESHOT */ |
| 72 | 79 | ||
| 73 | /* | 80 | /* |
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index a87b0468568b..39019b3f7621 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
| @@ -75,6 +75,9 @@ static void tick_do_update_jiffies64(ktime_t now) | |||
| 75 | incr * ticks); | 75 | incr * ticks); |
| 76 | } | 76 | } |
| 77 | do_timer(++ticks); | 77 | do_timer(++ticks); |
| 78 | |||
| 79 | /* Keep the tick_next_period variable up to date */ | ||
| 80 | tick_next_period = ktime_add(last_jiffies_update, tick_period); | ||
| 78 | } | 81 | } |
| 79 | write_sequnlock(&xtime_lock); | 82 | write_sequnlock(&xtime_lock); |
| 80 | } | 83 | } |
| @@ -221,7 +224,7 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
| 221 | */ | 224 | */ |
| 222 | if (unlikely(!cpu_online(cpu))) { | 225 | if (unlikely(!cpu_online(cpu))) { |
| 223 | if (cpu == tick_do_timer_cpu) | 226 | if (cpu == tick_do_timer_cpu) |
| 224 | tick_do_timer_cpu = -1; | 227 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; |
| 225 | } | 228 | } |
| 226 | 229 | ||
| 227 | if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) | 230 | if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) |
| @@ -303,7 +306,7 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
| 303 | * invoked. | 306 | * invoked. |
| 304 | */ | 307 | */ |
| 305 | if (cpu == tick_do_timer_cpu) | 308 | if (cpu == tick_do_timer_cpu) |
| 306 | tick_do_timer_cpu = -1; | 309 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; |
| 307 | 310 | ||
| 308 | ts->idle_sleeps++; | 311 | ts->idle_sleeps++; |
| 309 | 312 | ||
| @@ -468,7 +471,7 @@ static void tick_nohz_handler(struct clock_event_device *dev) | |||
| 468 | * this duty, then the jiffies update is still serialized by | 471 | * this duty, then the jiffies update is still serialized by |
| 469 | * xtime_lock. | 472 | * xtime_lock. |
| 470 | */ | 473 | */ |
| 471 | if (unlikely(tick_do_timer_cpu == -1)) | 474 | if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) |
| 472 | tick_do_timer_cpu = cpu; | 475 | tick_do_timer_cpu = cpu; |
| 473 | 476 | ||
| 474 | /* Check, if the jiffies need an update */ | 477 | /* Check, if the jiffies need an update */ |
| @@ -570,7 +573,7 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) | |||
| 570 | * this duty, then the jiffies update is still serialized by | 573 | * this duty, then the jiffies update is still serialized by |
| 571 | * xtime_lock. | 574 | * xtime_lock. |
| 572 | */ | 575 | */ |
| 573 | if (unlikely(tick_do_timer_cpu == -1)) | 576 | if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) |
| 574 | tick_do_timer_cpu = cpu; | 577 | tick_do_timer_cpu = cpu; |
| 575 | #endif | 578 | #endif |
| 576 | 579 | ||
