diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2007-03-06 02:25:42 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-06 12:30:24 -0500 |
| commit | 6321dd60c76b2e12383bc06046288b15397ed3a0 (patch) | |
| tree | 4cea63e69ce4f6f5f7f94fc6905063efdde7974e | |
| parent | c3442e296517aee733d62fc3fe03211598902c7d (diff) | |
[PATCH] Save/restore periodic tick information over suspend/resume
The programming of periodic tick devices needs to be saved/restored
across suspend/resume - otherwise we might end up with a system coming
up that relies on getting a PIT (or HPET) interrupt, while those devices
default to 'no interrupts' after powerup. (To confuse things it worked
to a certain degree on some systems because the lapic gets initialized
as a side-effect of SMP bootup.)
This suspend / resume thing was dropped unintentionally during the
last-minute -mm code reshuffling.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | kernel/time/tick-broadcast.c | 36 | ||||
| -rw-r--r-- | kernel/time/tick-common.c | 32 | ||||
| -rw-r--r-- | kernel/time/tick-internal.h | 4 | ||||
| -rw-r--r-- | kernel/timer.c | 6 |
4 files changed, 78 insertions, 0 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 12b3efeb9f6f..5567745470f7 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
| @@ -284,6 +284,42 @@ void tick_shutdown_broadcast(unsigned int *cpup) | |||
| 284 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); | 284 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | void tick_suspend_broadcast(void) | ||
| 288 | { | ||
| 289 | struct clock_event_device *bc; | ||
| 290 | unsigned long flags; | ||
| 291 | |||
| 292 | spin_lock_irqsave(&tick_broadcast_lock, flags); | ||
| 293 | |||
| 294 | bc = tick_broadcast_device.evtdev; | ||
| 295 | if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) | ||
| 296 | clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); | ||
| 297 | |||
| 298 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); | ||
| 299 | } | ||
| 300 | |||
| 301 | int tick_resume_broadcast(void) | ||
| 302 | { | ||
| 303 | struct clock_event_device *bc; | ||
| 304 | unsigned long flags; | ||
| 305 | int broadcast = 0; | ||
| 306 | |||
| 307 | spin_lock_irqsave(&tick_broadcast_lock, flags); | ||
| 308 | |||
| 309 | bc = tick_broadcast_device.evtdev; | ||
| 310 | if (bc) { | ||
| 311 | if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC && | ||
| 312 | !cpus_empty(tick_broadcast_mask)) | ||
| 313 | tick_broadcast_start_periodic(bc); | ||
| 314 | |||
| 315 | broadcast = cpu_isset(smp_processor_id(), tick_broadcast_mask); | ||
| 316 | } | ||
| 317 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); | ||
| 318 | |||
| 319 | return broadcast; | ||
| 320 | } | ||
| 321 | |||
| 322 | |||
| 287 | #ifdef CONFIG_TICK_ONESHOT | 323 | #ifdef CONFIG_TICK_ONESHOT |
| 288 | 324 | ||
| 289 | static cpumask_t tick_broadcast_oneshot_mask; | 325 | static cpumask_t tick_broadcast_oneshot_mask; |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 0986a2bfab49..43ba1bdec14c 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
| @@ -298,6 +298,28 @@ static void tick_shutdown(unsigned int *cpup) | |||
| 298 | spin_unlock_irqrestore(&tick_device_lock, flags); | 298 | spin_unlock_irqrestore(&tick_device_lock, flags); |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | static void tick_suspend_periodic(void) | ||
| 302 | { | ||
| 303 | struct tick_device *td = &__get_cpu_var(tick_cpu_device); | ||
| 304 | unsigned long flags; | ||
| 305 | |||
| 306 | spin_lock_irqsave(&tick_device_lock, flags); | ||
| 307 | if (td->mode == TICKDEV_MODE_PERIODIC) | ||
| 308 | clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_SHUTDOWN); | ||
| 309 | spin_unlock_irqrestore(&tick_device_lock, flags); | ||
| 310 | } | ||
| 311 | |||
| 312 | static void tick_resume_periodic(void) | ||
| 313 | { | ||
| 314 | struct tick_device *td = &__get_cpu_var(tick_cpu_device); | ||
| 315 | unsigned long flags; | ||
| 316 | |||
| 317 | spin_lock_irqsave(&tick_device_lock, flags); | ||
| 318 | if (td->mode == TICKDEV_MODE_PERIODIC) | ||
| 319 | tick_setup_periodic(td->evtdev, 0); | ||
| 320 | spin_unlock_irqrestore(&tick_device_lock, flags); | ||
| 321 | } | ||
| 322 | |||
| 301 | /* | 323 | /* |
| 302 | * Notification about clock event devices | 324 | * Notification about clock event devices |
| 303 | */ | 325 | */ |
| @@ -325,6 +347,16 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason, | |||
| 325 | tick_shutdown(dev); | 347 | tick_shutdown(dev); |
| 326 | break; | 348 | break; |
| 327 | 349 | ||
| 350 | case CLOCK_EVT_NOTIFY_SUSPEND: | ||
| 351 | tick_suspend_periodic(); | ||
| 352 | tick_suspend_broadcast(); | ||
| 353 | break; | ||
| 354 | |||
| 355 | case CLOCK_EVT_NOTIFY_RESUME: | ||
| 356 | if (!tick_resume_broadcast()) | ||
| 357 | tick_resume_periodic(); | ||
| 358 | break; | ||
| 359 | |||
| 328 | default: | 360 | default: |
| 329 | break; | 361 | break; |
| 330 | } | 362 | } |
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 54861a0f29ff..75890efd24ff 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h | |||
| @@ -67,6 +67,8 @@ extern int tick_check_broadcast_device(struct clock_event_device *dev); | |||
| 67 | extern int tick_is_broadcast_device(struct clock_event_device *dev); | 67 | extern int tick_is_broadcast_device(struct clock_event_device *dev); |
| 68 | extern void tick_broadcast_on_off(unsigned long reason, int *oncpu); | 68 | extern void tick_broadcast_on_off(unsigned long reason, int *oncpu); |
| 69 | extern void tick_shutdown_broadcast(unsigned int *cpup); | 69 | extern void tick_shutdown_broadcast(unsigned int *cpup); |
| 70 | extern void tick_suspend_broadcast(void); | ||
| 71 | extern int tick_resume_broadcast(void); | ||
| 70 | 72 | ||
| 71 | extern void | 73 | extern void |
| 72 | tick_set_periodic_handler(struct clock_event_device *dev, int broadcast); | 74 | tick_set_periodic_handler(struct clock_event_device *dev, int broadcast); |
| @@ -90,6 +92,8 @@ static inline int tick_device_uses_broadcast(struct clock_event_device *dev, | |||
| 90 | static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { } | 92 | static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { } |
| 91 | static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { } | 93 | static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { } |
| 92 | static inline void tick_shutdown_broadcast(unsigned int *cpup) { } | 94 | static inline void tick_shutdown_broadcast(unsigned int *cpup) { } |
| 95 | static inline void tick_suspend_broadcast(void) { } | ||
| 96 | static inline int tick_resume_broadcast(void) { return 0; } | ||
| 93 | 97 | ||
| 94 | /* | 98 | /* |
| 95 | * Set the periodic handler in non broadcast mode | 99 | * Set the periodic handler in non broadcast mode |
diff --git a/kernel/timer.c b/kernel/timer.c index 8ad384253ef2..ee0a2da4aab3 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
| @@ -997,6 +997,9 @@ static int timekeeping_resume(struct sys_device *dev) | |||
| 997 | write_sequnlock_irqrestore(&xtime_lock, flags); | 997 | write_sequnlock_irqrestore(&xtime_lock, flags); |
| 998 | 998 | ||
| 999 | touch_softlockup_watchdog(); | 999 | touch_softlockup_watchdog(); |
| 1000 | |||
| 1001 | clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL); | ||
| 1002 | |||
| 1000 | /* Resume hrtimers */ | 1003 | /* Resume hrtimers */ |
| 1001 | clock_was_set(); | 1004 | clock_was_set(); |
| 1002 | 1005 | ||
| @@ -1011,6 +1014,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | |||
| 1011 | timekeeping_suspended = 1; | 1014 | timekeeping_suspended = 1; |
| 1012 | timekeeping_suspend_time = read_persistent_clock(); | 1015 | timekeeping_suspend_time = read_persistent_clock(); |
| 1013 | write_sequnlock_irqrestore(&xtime_lock, flags); | 1016 | write_sequnlock_irqrestore(&xtime_lock, flags); |
| 1017 | |||
| 1018 | clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL); | ||
| 1019 | |||
| 1014 | return 0; | 1020 | return 0; |
| 1015 | } | 1021 | } |
| 1016 | 1022 | ||
