aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Stultz <johnstul@us.ibm.com>2007-02-16 04:27:30 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-16 11:13:57 -0500
commit411187fb05cd11676b0979d9fbf3291db69dbce2 (patch)
tree6202ca36868ab47edf737de81c7b7c4841228ab3
parent9f907c0144496e464bd5ed5a99a51227d63a9c0b (diff)
[PATCH] GTOD: persistent clock support
Persistent clock support: do proper timekeeping across suspend/resume. [bunk@stusta.de: cleanup] 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>
-rw-r--r--include/linux/hrtimer.h3
-rw-r--r--include/linux/time.h1
-rw-r--r--kernel/hrtimer.c8
-rw-r--r--kernel/timer.c39
4 files changed, 50 insertions, 1 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index fca93025ab51..660d91dea78c 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -146,6 +146,9 @@ extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
146/* Soft interrupt function to run the hrtimer queues: */ 146/* Soft interrupt function to run the hrtimer queues: */
147extern void hrtimer_run_queues(void); 147extern void hrtimer_run_queues(void);
148 148
149/* Resume notification */
150void hrtimer_notify_resume(void);
151
149/* Bootup initialization: */ 152/* Bootup initialization: */
150extern void __init hrtimers_init(void); 153extern void __init hrtimers_init(void);
151 154
diff --git a/include/linux/time.h b/include/linux/time.h
index eceb1a59b078..8ea8dea713c7 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -92,6 +92,7 @@ extern struct timespec xtime;
92extern struct timespec wall_to_monotonic; 92extern struct timespec wall_to_monotonic;
93extern seqlock_t xtime_lock __attribute__((weak)); 93extern seqlock_t xtime_lock __attribute__((weak));
94 94
95extern unsigned long read_persistent_clock(void);
95void timekeeping_init(void); 96void timekeeping_init(void);
96 97
97static inline unsigned long get_seconds(void) 98static inline unsigned long get_seconds(void)
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 80666f6cd4f9..c0fdb9b6d296 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -292,6 +292,14 @@ static unsigned long ktime_divns(const ktime_t kt, s64 div)
292#endif /* BITS_PER_LONG >= 64 */ 292#endif /* BITS_PER_LONG >= 64 */
293 293
294/* 294/*
295 * Timekeeping resumed notification
296 */
297void hrtimer_notify_resume(void)
298{
299 clock_was_set();
300}
301
302/*
295 * Counterpart to lock_timer_base above: 303 * Counterpart to lock_timer_base above:
296 */ 304 */
297static inline 305static inline
diff --git a/kernel/timer.c b/kernel/timer.c
index 4f9cc2a48beb..8f4bf1e6a3ed 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -878,12 +878,27 @@ int timekeeping_is_continuous(void)
878 return ret; 878 return ret;
879} 879}
880 880
881/**
882 * read_persistent_clock - Return time in seconds from the persistent clock.
883 *
884 * Weak dummy function for arches that do not yet support it.
885 * Returns seconds from epoch using the battery backed persistent clock.
886 * Returns zero if unsupported.
887 *
888 * XXX - Do be sure to remove it once all arches implement it.
889 */
890unsigned long __attribute__((weak)) read_persistent_clock(void)
891{
892 return 0;
893}
894
881/* 895/*
882 * timekeeping_init - Initializes the clocksource and common timekeeping values 896 * timekeeping_init - Initializes the clocksource and common timekeeping values
883 */ 897 */
884void __init timekeeping_init(void) 898void __init timekeeping_init(void)
885{ 899{
886 unsigned long flags; 900 unsigned long flags;
901 unsigned long sec = read_persistent_clock();
887 902
888 write_seqlock_irqsave(&xtime_lock, flags); 903 write_seqlock_irqsave(&xtime_lock, flags);
889 904
@@ -893,11 +908,20 @@ void __init timekeeping_init(void)
893 clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH); 908 clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
894 clock->cycle_last = clocksource_read(clock); 909 clock->cycle_last = clocksource_read(clock);
895 910
911 xtime.tv_sec = sec;
912 xtime.tv_nsec = 0;
913 set_normalized_timespec(&wall_to_monotonic,
914 -xtime.tv_sec, -xtime.tv_nsec);
915
896 write_sequnlock_irqrestore(&xtime_lock, flags); 916 write_sequnlock_irqrestore(&xtime_lock, flags);
897} 917}
898 918
899 919
920/* flag for if timekeeping is suspended */
900static int timekeeping_suspended; 921static int timekeeping_suspended;
922/* time in seconds when suspend began */
923static unsigned long timekeeping_suspend_time;
924
901/** 925/**
902 * timekeeping_resume - Resumes the generic timekeeping subsystem. 926 * timekeeping_resume - Resumes the generic timekeeping subsystem.
903 * @dev: unused 927 * @dev: unused
@@ -909,13 +933,25 @@ static int timekeeping_suspended;
909static int timekeeping_resume(struct sys_device *dev) 933static int timekeeping_resume(struct sys_device *dev)
910{ 934{
911 unsigned long flags; 935 unsigned long flags;
936 unsigned long now = read_persistent_clock();
912 937
913 write_seqlock_irqsave(&xtime_lock, flags); 938 write_seqlock_irqsave(&xtime_lock, flags);
914 /* restart the last cycle value */ 939
940 if (now && (now > timekeeping_suspend_time)) {
941 unsigned long sleep_length = now - timekeeping_suspend_time;
942
943 xtime.tv_sec += sleep_length;
944 wall_to_monotonic.tv_sec -= sleep_length;
945 }
946 /* re-base the last cycle value */
915 clock->cycle_last = clocksource_read(clock); 947 clock->cycle_last = clocksource_read(clock);
916 clock->error = 0; 948 clock->error = 0;
917 timekeeping_suspended = 0; 949 timekeeping_suspended = 0;
918 write_sequnlock_irqrestore(&xtime_lock, flags); 950 write_sequnlock_irqrestore(&xtime_lock, flags);
951
952 touch_softlockup_watchdog();
953 hrtimer_notify_resume();
954
919 return 0; 955 return 0;
920} 956}
921 957
@@ -925,6 +961,7 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
925 961
926 write_seqlock_irqsave(&xtime_lock, flags); 962 write_seqlock_irqsave(&xtime_lock, flags);
927 timekeeping_suspended = 1; 963 timekeeping_suspended = 1;
964 timekeeping_suspend_time = read_persistent_clock();
928 write_sequnlock_irqrestore(&xtime_lock, flags); 965 write_sequnlock_irqrestore(&xtime_lock, flags);
929 return 0; 966 return 0;
930} 967}