aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-09-26 02:32:57 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:49:04 -0400
commit7d145aa3abf4d96c91f37c012facd5cfbb9010d1 (patch)
tree2ce0d857a23844b8501111f8e43c8ae91289e682
parente1da95ae38afdcda83328300c4aed755d9fc01a6 (diff)
[PATCH] i386: Detect clock skew during suspend
Detect the situations in which the time after a resume from disk would be earlier than the time before the suspend and prevent them from happening on i386. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: John Stultz <johnstul@us.ibm.com> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/i386/kernel/time.c24
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
273static long clock_cmos_diff, sleep_start; 273static long clock_cmos_diff;
274static unsigned long sleep_start;
274 275
275static int timer_suspend(struct sys_device *dev, pm_message_t state) 276static 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);