aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2006-07-14 03:24:17 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-15 00:53:54 -0400
commit3e143475c22036847f898d7e76ba337c1d7dbf6f (patch)
tree4bbd8f322f6a1cd43be409393742967234d23151 /kernel
parent635adb6cd25c8f816c9017a0a0349cd389eafcd3 (diff)
[PATCH] improve timekeeping resume robustness
Resolve problems seen w/ APM suspend. Due to resume initialization ordering, its possible we could get a timer interrupt before the timekeeping resume() function is called. This patch ensures we don't do any timekeeping accounting before we're fully resumed. (akpm: fixes the machine-freezes-on-APM-resume bug) Signed-off-by: John Stultz <johnstul@us.ibm.com> Cc: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/timer.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index acfa557e685b..05809c2e2fd6 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -969,6 +969,7 @@ void __init timekeeping_init(void)
969} 969}
970 970
971 971
972static int timekeeping_suspended;
972/* 973/*
973 * timekeeping_resume - Resumes the generic timekeeping subsystem. 974 * timekeeping_resume - Resumes the generic timekeeping subsystem.
974 * @dev: unused 975 * @dev: unused
@@ -984,6 +985,18 @@ static int timekeeping_resume(struct sys_device *dev)
984 write_seqlock_irqsave(&xtime_lock, flags); 985 write_seqlock_irqsave(&xtime_lock, flags);
985 /* restart the last cycle value */ 986 /* restart the last cycle value */
986 clock->cycle_last = clocksource_read(clock); 987 clock->cycle_last = clocksource_read(clock);
988 clock->error = 0;
989 timekeeping_suspended = 0;
990 write_sequnlock_irqrestore(&xtime_lock, flags);
991 return 0;
992}
993
994static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
995{
996 unsigned long flags;
997
998 write_seqlock_irqsave(&xtime_lock, flags);
999 timekeeping_suspended = 1;
987 write_sequnlock_irqrestore(&xtime_lock, flags); 1000 write_sequnlock_irqrestore(&xtime_lock, flags);
988 return 0; 1001 return 0;
989} 1002}
@@ -991,6 +1004,7 @@ static int timekeeping_resume(struct sys_device *dev)
991/* sysfs resume/suspend bits for timekeeping */ 1004/* sysfs resume/suspend bits for timekeeping */
992static struct sysdev_class timekeeping_sysclass = { 1005static struct sysdev_class timekeeping_sysclass = {
993 .resume = timekeeping_resume, 1006 .resume = timekeeping_resume,
1007 .suspend = timekeeping_suspend,
994 set_kset_name("timekeeping"), 1008 set_kset_name("timekeeping"),
995}; 1009};
996 1010
@@ -1101,13 +1115,16 @@ static void update_wall_time(void)
1101{ 1115{
1102 cycle_t offset; 1116 cycle_t offset;
1103 1117
1104 clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift; 1118 /* Make sure we're fully resumed: */
1119 if (unlikely(timekeeping_suspended))
1120 return;
1105 1121
1106#ifdef CONFIG_GENERIC_TIME 1122#ifdef CONFIG_GENERIC_TIME
1107 offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask; 1123 offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
1108#else 1124#else
1109 offset = clock->cycle_interval; 1125 offset = clock->cycle_interval;
1110#endif 1126#endif
1127 clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
1111 1128
1112 /* normally this loop will run just once, however in the 1129 /* normally this loop will run just once, however in the
1113 * case of lost or late ticks, it will accumulate correctly. 1130 * case of lost or late ticks, it will accumulate correctly.