diff options
author | Shaohua Li <shaohua.li@intel.com> | 2005-09-03 18:57:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:06:18 -0400 |
commit | c3c433e4f33afe255389ba3b1a003dc8deb3de9a (patch) | |
tree | 071304e15e21e0a93c17050000a682f4ae1a98c1 /arch/i386/kernel/time.c | |
parent | 57c4ce3cbfba1bb0da7f37b9328a713cbd5d0919 (diff) |
[PATCH] add suspend/resume for timer
The timers lack .suspend/.resume methods. Because of this, jiffies got a
big compensation after a S3 resume. And then softlockup watchdog reports
an oops. This occured with HPET enabled, but it's also possible for other
timers.
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/time.c')
-rw-r--r-- | arch/i386/kernel/time.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 0ee9dee8af06..6f794a78ee1e 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -383,6 +383,7 @@ void notify_arch_cmos_timer(void) | |||
383 | 383 | ||
384 | static long clock_cmos_diff, sleep_start; | 384 | static long clock_cmos_diff, sleep_start; |
385 | 385 | ||
386 | static struct timer_opts *last_timer; | ||
386 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | 387 | static int timer_suspend(struct sys_device *dev, pm_message_t state) |
387 | { | 388 | { |
388 | /* | 389 | /* |
@@ -391,6 +392,10 @@ static int timer_suspend(struct sys_device *dev, pm_message_t state) | |||
391 | clock_cmos_diff = -get_cmos_time(); | 392 | clock_cmos_diff = -get_cmos_time(); |
392 | clock_cmos_diff += get_seconds(); | 393 | clock_cmos_diff += get_seconds(); |
393 | sleep_start = get_cmos_time(); | 394 | sleep_start = get_cmos_time(); |
395 | last_timer = cur_timer; | ||
396 | cur_timer = &timer_none; | ||
397 | if (last_timer->suspend) | ||
398 | last_timer->suspend(state); | ||
394 | return 0; | 399 | return 0; |
395 | } | 400 | } |
396 | 401 | ||
@@ -404,6 +409,7 @@ static int timer_resume(struct sys_device *dev) | |||
404 | if (is_hpet_enabled()) | 409 | if (is_hpet_enabled()) |
405 | hpet_reenable(); | 410 | hpet_reenable(); |
406 | #endif | 411 | #endif |
412 | setup_pit_timer(); | ||
407 | sec = get_cmos_time() + clock_cmos_diff; | 413 | sec = get_cmos_time() + clock_cmos_diff; |
408 | sleep_length = (get_cmos_time() - sleep_start) * HZ; | 414 | sleep_length = (get_cmos_time() - sleep_start) * HZ; |
409 | write_seqlock_irqsave(&xtime_lock, flags); | 415 | write_seqlock_irqsave(&xtime_lock, flags); |
@@ -412,6 +418,10 @@ static int timer_resume(struct sys_device *dev) | |||
412 | write_sequnlock_irqrestore(&xtime_lock, flags); | 418 | write_sequnlock_irqrestore(&xtime_lock, flags); |
413 | jiffies += sleep_length; | 419 | jiffies += sleep_length; |
414 | wall_jiffies += sleep_length; | 420 | wall_jiffies += sleep_length; |
421 | if (last_timer->resume) | ||
422 | last_timer->resume(); | ||
423 | cur_timer = last_timer; | ||
424 | last_timer = NULL; | ||
415 | return 0; | 425 | return 0; |
416 | } | 426 | } |
417 | 427 | ||