diff options
author | John Stultz <johnstul@us.ibm.com> | 2007-02-16 04:27:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:57 -0500 |
commit | c1d370e167d66b10bca3b602d3740405469383de (patch) | |
tree | 493ed9821cad0b2b035337da152cc11cc2223eb1 /arch/i386/kernel/time.c | |
parent | 411187fb05cd11676b0979d9fbf3291db69dbce2 (diff) |
[PATCH] i386: use GTOD persistent clock support
Persistent clock support: do proper timekeeping across suspend/resume, i386
arch support.
[bunk@stusta.de: cleanup]
Build-fixes-from: Andrew Morton <akpm@osdl.org>
Signed-off-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Cc: Roman Zippel <zippel@linux-m68k.org>
Cc: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386/kernel/time.c')
-rw-r--r-- | arch/i386/kernel/time.c | 54 |
1 files changed, 1 insertions, 53 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index a4f67a6e6821..044c17572eef 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -212,7 +212,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
212 | } | 212 | } |
213 | 213 | ||
214 | /* not static: needed by APM */ | 214 | /* not static: needed by APM */ |
215 | unsigned long get_cmos_time(void) | 215 | unsigned long read_persistent_clock(void) |
216 | { | 216 | { |
217 | unsigned long retval; | 217 | unsigned long retval; |
218 | unsigned long flags; | 218 | unsigned long flags; |
@@ -225,7 +225,6 @@ unsigned long get_cmos_time(void) | |||
225 | 225 | ||
226 | return retval; | 226 | return retval; |
227 | } | 227 | } |
228 | EXPORT_SYMBOL(get_cmos_time); | ||
229 | 228 | ||
230 | static void sync_cmos_clock(unsigned long dummy); | 229 | static void sync_cmos_clock(unsigned long dummy); |
231 | 230 | ||
@@ -278,58 +277,19 @@ void notify_arch_cmos_timer(void) | |||
278 | mod_timer(&sync_cmos_timer, jiffies + 1); | 277 | mod_timer(&sync_cmos_timer, jiffies + 1); |
279 | } | 278 | } |
280 | 279 | ||
281 | static long clock_cmos_diff; | ||
282 | static unsigned long sleep_start; | ||
283 | |||
284 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | ||
285 | { | ||
286 | /* | ||
287 | * Estimate time zone so that set_time can update the clock | ||
288 | */ | ||
289 | unsigned long ctime = get_cmos_time(); | ||
290 | |||
291 | clock_cmos_diff = -ctime; | ||
292 | clock_cmos_diff += get_seconds(); | ||
293 | sleep_start = ctime; | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int timer_resume(struct sys_device *dev) | 280 | static int timer_resume(struct sys_device *dev) |
298 | { | 281 | { |
299 | unsigned long flags; | ||
300 | unsigned long sec; | ||
301 | unsigned long ctime = get_cmos_time(); | ||
302 | long sleep_length = (ctime - sleep_start) * HZ; | ||
303 | struct timespec ts; | ||
304 | |||
305 | if (sleep_length < 0) { | ||
306 | printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n"); | ||
307 | /* The time after the resume must not be earlier than the time | ||
308 | * before the suspend or some nasty things will happen | ||
309 | */ | ||
310 | sleep_length = 0; | ||
311 | ctime = sleep_start; | ||
312 | } | ||
313 | #ifdef CONFIG_HPET_TIMER | 282 | #ifdef CONFIG_HPET_TIMER |
314 | if (is_hpet_enabled()) | 283 | if (is_hpet_enabled()) |
315 | hpet_reenable(); | 284 | hpet_reenable(); |
316 | #endif | 285 | #endif |
317 | setup_pit_timer(); | 286 | setup_pit_timer(); |
318 | |||
319 | sec = ctime + clock_cmos_diff; | ||
320 | ts.tv_sec = sec; | ||
321 | ts.tv_nsec = 0; | ||
322 | do_settimeofday(&ts); | ||
323 | write_seqlock_irqsave(&xtime_lock, flags); | ||
324 | jiffies_64 += sleep_length; | ||
325 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
326 | touch_softlockup_watchdog(); | 287 | touch_softlockup_watchdog(); |
327 | return 0; | 288 | return 0; |
328 | } | 289 | } |
329 | 290 | ||
330 | static struct sysdev_class timer_sysclass = { | 291 | static struct sysdev_class timer_sysclass = { |
331 | .resume = timer_resume, | 292 | .resume = timer_resume, |
332 | .suspend = timer_suspend, | ||
333 | set_kset_name("timer"), | 293 | set_kset_name("timer"), |
334 | }; | 294 | }; |
335 | 295 | ||
@@ -355,12 +315,6 @@ extern void (*late_time_init)(void); | |||
355 | /* Duplicate of time_init() below, with hpet_enable part added */ | 315 | /* Duplicate of time_init() below, with hpet_enable part added */ |
356 | static void __init hpet_time_init(void) | 316 | static void __init hpet_time_init(void) |
357 | { | 317 | { |
358 | struct timespec ts; | ||
359 | ts.tv_sec = get_cmos_time(); | ||
360 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
361 | |||
362 | do_settimeofday(&ts); | ||
363 | |||
364 | if ((hpet_enable() >= 0) && hpet_use_timer) { | 318 | if ((hpet_enable() >= 0) && hpet_use_timer) { |
365 | printk("Using HPET for base-timer\n"); | 319 | printk("Using HPET for base-timer\n"); |
366 | } | 320 | } |
@@ -371,7 +325,6 @@ static void __init hpet_time_init(void) | |||
371 | 325 | ||
372 | void __init time_init(void) | 326 | void __init time_init(void) |
373 | { | 327 | { |
374 | struct timespec ts; | ||
375 | #ifdef CONFIG_HPET_TIMER | 328 | #ifdef CONFIG_HPET_TIMER |
376 | if (is_hpet_capable()) { | 329 | if (is_hpet_capable()) { |
377 | /* | 330 | /* |
@@ -382,10 +335,5 @@ void __init time_init(void) | |||
382 | return; | 335 | return; |
383 | } | 336 | } |
384 | #endif | 337 | #endif |
385 | ts.tv_sec = get_cmos_time(); | ||
386 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
387 | |||
388 | do_settimeofday(&ts); | ||
389 | |||
390 | do_time_init(); | 338 | do_time_init(); |
391 | } | 339 | } |