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 edd00f6cee37..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,18 +290,29 @@ 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(); |
291 | 294 | long sleep_length = (ctime - sleep_start) * HZ; | |
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; | 310 | |
298 | sleep_length = (get_cmos_time() - sleep_start) * HZ; | 311 | sec = ctime + clock_cmos_diff; |
312 | ts.tv_sec = sec; | ||
313 | ts.tv_nsec = 0; | ||
314 | do_settimeofday(&ts); | ||
299 | write_seqlock_irqsave(&xtime_lock, flags); | 315 | write_seqlock_irqsave(&xtime_lock, flags); |
300 | xtime.tv_sec = sec; | ||
301 | xtime.tv_nsec = 0; | ||
302 | jiffies_64 += sleep_length; | 316 | jiffies_64 += sleep_length; |
303 | wall_jiffies += sleep_length; | 317 | wall_jiffies += sleep_length; |
304 | write_sequnlock_irqrestore(&xtime_lock, flags); | 318 | write_sequnlock_irqrestore(&xtime_lock, flags); |
@@ -334,10 +348,11 @@ extern void (*late_time_init)(void); | |||
334 | /* Duplicate of time_init() below, with hpet_enable part added */ | 348 | /* Duplicate of time_init() below, with hpet_enable part added */ |
335 | static void __init hpet_time_init(void) | 349 | static void __init hpet_time_init(void) |
336 | { | 350 | { |
337 | xtime.tv_sec = get_cmos_time(); | 351 | struct timespec ts; |
338 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 352 | ts.tv_sec = get_cmos_time(); |
339 | set_normalized_timespec(&wall_to_monotonic, | 353 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); |
340 | -xtime.tv_sec, -xtime.tv_nsec); | 354 | |
355 | do_settimeofday(&ts); | ||
341 | 356 | ||
342 | if ((hpet_enable() >= 0) && hpet_use_timer) { | 357 | if ((hpet_enable() >= 0) && hpet_use_timer) { |
343 | printk("Using HPET for base-timer\n"); | 358 | printk("Using HPET for base-timer\n"); |
@@ -349,6 +364,7 @@ static void __init hpet_time_init(void) | |||
349 | 364 | ||
350 | void __init time_init(void) | 365 | void __init time_init(void) |
351 | { | 366 | { |
367 | struct timespec ts; | ||
352 | #ifdef CONFIG_HPET_TIMER | 368 | #ifdef CONFIG_HPET_TIMER |
353 | if (is_hpet_capable()) { | 369 | if (is_hpet_capable()) { |
354 | /* | 370 | /* |
@@ -359,10 +375,10 @@ void __init time_init(void) | |||
359 | return; | 375 | return; |
360 | } | 376 | } |
361 | #endif | 377 | #endif |
362 | xtime.tv_sec = get_cmos_time(); | 378 | ts.tv_sec = get_cmos_time(); |
363 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 379 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); |
364 | set_normalized_timespec(&wall_to_monotonic, | 380 | |
365 | -xtime.tv_sec, -xtime.tv_nsec); | 381 | do_settimeofday(&ts); |
366 | 382 | ||
367 | time_init_hook(); | 383 | time_init_hook(); |
368 | } | 384 | } |