diff options
| -rw-r--r-- | arch/i386/kernel/time.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 6f333e7fb23c..1302e4ab3c4f 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
| @@ -270,16 +270,19 @@ void notify_arch_cmos_timer(void) | |||
| 270 | mod_timer(&sync_cmos_timer, jiffies + 1); | 270 | mod_timer(&sync_cmos_timer, jiffies + 1); |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | static long clock_cmos_diff, sleep_start; | 273 | static long clock_cmos_diff; |
| 274 | static unsigned long sleep_start; | ||
| 274 | 275 | ||
| 275 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | 276 | static int timer_suspend(struct sys_device *dev, pm_message_t state) |
| 276 | { | 277 | { |
| 277 | /* | 278 | /* |
| 278 | * Estimate time zone so that set_time can update the clock | 279 | * Estimate time zone so that set_time can update the clock |
| 279 | */ | 280 | */ |
| 280 | clock_cmos_diff = -get_cmos_time(); | 281 | unsigned long ctime = get_cmos_time(); |
| 282 | |||
| 283 | clock_cmos_diff = -ctime; | ||
| 281 | clock_cmos_diff += get_seconds(); | 284 | clock_cmos_diff += get_seconds(); |
| 282 | sleep_start = get_cmos_time(); | 285 | sleep_start = ctime; |
| 283 | return 0; | 286 | return 0; |
| 284 | } | 287 | } |
| 285 | 288 | ||
| @@ -287,16 +290,25 @@ static int timer_resume(struct sys_device *dev) | |||
| 287 | { | 290 | { |
| 288 | unsigned long flags; | 291 | unsigned long flags; |
| 289 | unsigned long sec; | 292 | unsigned long sec; |
| 290 | unsigned long sleep_length; | 293 | unsigned long ctime = get_cmos_time(); |
| 294 | long sleep_length = (ctime - sleep_start) * HZ; | ||
| 291 | struct timespec ts; | 295 | struct timespec ts; |
| 296 | |||
| 297 | if (sleep_length < 0) { | ||
| 298 | printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n"); | ||
| 299 | /* The time after the resume must not be earlier than the time | ||
| 300 | * before the suspend or some nasty things will happen | ||
| 301 | */ | ||
| 302 | sleep_length = 0; | ||
| 303 | ctime = sleep_start; | ||
| 304 | } | ||
| 292 | #ifdef CONFIG_HPET_TIMER | 305 | #ifdef CONFIG_HPET_TIMER |
| 293 | if (is_hpet_enabled()) | 306 | if (is_hpet_enabled()) |
| 294 | hpet_reenable(); | 307 | hpet_reenable(); |
| 295 | #endif | 308 | #endif |
| 296 | setup_pit_timer(); | 309 | setup_pit_timer(); |
| 297 | sec = get_cmos_time() + clock_cmos_diff; | ||
| 298 | sleep_length = (get_cmos_time() - sleep_start) * HZ; | ||
| 299 | 310 | ||
| 311 | sec = ctime + clock_cmos_diff; | ||
| 300 | ts.tv_sec = sec; | 312 | ts.tv_sec = sec; |
| 301 | ts.tv_nsec = 0; | 313 | ts.tv_nsec = 0; |
| 302 | do_settimeofday(&ts); | 314 | do_settimeofday(&ts); |
