diff options
Diffstat (limited to 'arch/i386/kernel/time.c')
-rw-r--r-- | arch/i386/kernel/time.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 5af802ef00b2..86944acfb647 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -285,16 +285,19 @@ void notify_arch_cmos_timer(void) | |||
285 | mod_timer(&sync_cmos_timer, jiffies + 1); | 285 | mod_timer(&sync_cmos_timer, jiffies + 1); |
286 | } | 286 | } |
287 | 287 | ||
288 | static long clock_cmos_diff, sleep_start; | 288 | static long clock_cmos_diff; |
289 | static unsigned long sleep_start; | ||
289 | 290 | ||
290 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | 291 | static int timer_suspend(struct sys_device *dev, pm_message_t state) |
291 | { | 292 | { |
292 | /* | 293 | /* |
293 | * Estimate time zone so that set_time can update the clock | 294 | * Estimate time zone so that set_time can update the clock |
294 | */ | 295 | */ |
295 | clock_cmos_diff = -get_cmos_time(); | 296 | unsigned long ctime = get_cmos_time(); |
297 | |||
298 | clock_cmos_diff = -ctime; | ||
296 | clock_cmos_diff += get_seconds(); | 299 | clock_cmos_diff += get_seconds(); |
297 | sleep_start = get_cmos_time(); | 300 | sleep_start = ctime; |
298 | return 0; | 301 | return 0; |
299 | } | 302 | } |
300 | 303 | ||
@@ -302,18 +305,29 @@ static int timer_resume(struct sys_device *dev) | |||
302 | { | 305 | { |
303 | unsigned long flags; | 306 | unsigned long flags; |
304 | unsigned long sec; | 307 | unsigned long sec; |
305 | unsigned long sleep_length; | 308 | unsigned long ctime = get_cmos_time(); |
306 | 309 | long sleep_length = (ctime - sleep_start) * HZ; | |
310 | struct timespec ts; | ||
311 | |||
312 | if (sleep_length < 0) { | ||
313 | printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n"); | ||
314 | /* The time after the resume must not be earlier than the time | ||
315 | * before the suspend or some nasty things will happen | ||
316 | */ | ||
317 | sleep_length = 0; | ||
318 | ctime = sleep_start; | ||
319 | } | ||
307 | #ifdef CONFIG_HPET_TIMER | 320 | #ifdef CONFIG_HPET_TIMER |
308 | if (is_hpet_enabled()) | 321 | if (is_hpet_enabled()) |
309 | hpet_reenable(); | 322 | hpet_reenable(); |
310 | #endif | 323 | #endif |
311 | setup_pit_timer(); | 324 | setup_pit_timer(); |
312 | sec = get_cmos_time() + clock_cmos_diff; | 325 | |
313 | sleep_length = (get_cmos_time() - sleep_start) * HZ; | 326 | sec = ctime + clock_cmos_diff; |
327 | ts.tv_sec = sec; | ||
328 | ts.tv_nsec = 0; | ||
329 | do_settimeofday(&ts); | ||
314 | write_seqlock_irqsave(&xtime_lock, flags); | 330 | write_seqlock_irqsave(&xtime_lock, flags); |
315 | xtime.tv_sec = sec; | ||
316 | xtime.tv_nsec = 0; | ||
317 | jiffies_64 += sleep_length; | 331 | jiffies_64 += sleep_length; |
318 | wall_jiffies += sleep_length; | 332 | wall_jiffies += sleep_length; |
319 | write_sequnlock_irqrestore(&xtime_lock, flags); | 333 | write_sequnlock_irqrestore(&xtime_lock, flags); |
@@ -349,10 +363,11 @@ extern void (*late_time_init)(void); | |||
349 | /* Duplicate of time_init() below, with hpet_enable part added */ | 363 | /* Duplicate of time_init() below, with hpet_enable part added */ |
350 | static void __init hpet_time_init(void) | 364 | static void __init hpet_time_init(void) |
351 | { | 365 | { |
352 | xtime.tv_sec = get_cmos_time(); | 366 | struct timespec ts; |
353 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 367 | ts.tv_sec = get_cmos_time(); |
354 | set_normalized_timespec(&wall_to_monotonic, | 368 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); |
355 | -xtime.tv_sec, -xtime.tv_nsec); | 369 | |
370 | do_settimeofday(&ts); | ||
356 | 371 | ||
357 | if ((hpet_enable() >= 0) && hpet_use_timer) { | 372 | if ((hpet_enable() >= 0) && hpet_use_timer) { |
358 | printk("Using HPET for base-timer\n"); | 373 | printk("Using HPET for base-timer\n"); |
@@ -364,6 +379,7 @@ static void __init hpet_time_init(void) | |||
364 | 379 | ||
365 | void __init time_init(void) | 380 | void __init time_init(void) |
366 | { | 381 | { |
382 | struct timespec ts; | ||
367 | #ifdef CONFIG_HPET_TIMER | 383 | #ifdef CONFIG_HPET_TIMER |
368 | if (is_hpet_capable()) { | 384 | if (is_hpet_capable()) { |
369 | /* | 385 | /* |
@@ -374,10 +390,10 @@ void __init time_init(void) | |||
374 | return; | 390 | return; |
375 | } | 391 | } |
376 | #endif | 392 | #endif |
377 | xtime.tv_sec = get_cmos_time(); | 393 | ts.tv_sec = get_cmos_time(); |
378 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 394 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); |
379 | set_normalized_timespec(&wall_to_monotonic, | 395 | |
380 | -xtime.tv_sec, -xtime.tv_nsec); | 396 | do_settimeofday(&ts); |
381 | 397 | ||
382 | time_init_hook(); | 398 | time_init_hook(); |
383 | } | 399 | } |