Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=411187fb05cd11676b0979d9fbf3291db69dbce2
Commit:     411187fb05cd11676b0979d9fbf3291db69dbce2
Parent:     9f907c0144496e464bd5ed5a99a51227d63a9c0b
Author:     John Stultz <[EMAIL PROTECTED]>
AuthorDate: Fri Feb 16 01:27:30 2007 -0800
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Fri Feb 16 08:13:57 2007 -0800

    [PATCH] GTOD: persistent clock support
    
    Persistent clock support: do proper timekeeping across suspend/resume.
    
    [EMAIL PROTECTED]: cleanup]
    Signed-off-by: John Stultz <[EMAIL PROTECTED]>
    Signed-off-by: Thomas Gleixner <[EMAIL PROTECTED]>
    Signed-off-by: Ingo Molnar <[EMAIL PROTECTED]>
    Cc: Roman Zippel <[EMAIL PROTECTED]>
    Cc: Adrian Bunk <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 include/linux/hrtimer.h |    3 +++
 include/linux/time.h    |    1 +
 kernel/hrtimer.c        |    8 ++++++++
 kernel/timer.c          |   39 ++++++++++++++++++++++++++++++++++++++-
 4 files changed, 50 insertions(+), 1 deletions(-)

diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index fca9302..660d91d 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -146,6 +146,9 @@ extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
 /* Soft interrupt function to run the hrtimer queues: */
 extern void hrtimer_run_queues(void);
 
+/* Resume notification */
+void hrtimer_notify_resume(void);
+
 /* Bootup initialization: */
 extern void __init hrtimers_init(void);
 
diff --git a/include/linux/time.h b/include/linux/time.h
index eceb1a5..8ea8dea 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -92,6 +92,7 @@ extern struct timespec xtime;
 extern struct timespec wall_to_monotonic;
 extern seqlock_t xtime_lock __attribute__((weak));
 
+extern unsigned long read_persistent_clock(void);
 void timekeeping_init(void);
 
 static inline unsigned long get_seconds(void)
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 80666f6..c0fdb9b 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -292,6 +292,14 @@ static unsigned long ktime_divns(const ktime_t kt, s64 div)
 #endif /* BITS_PER_LONG >= 64 */
 
 /*
+ * Timekeeping resumed notification
+ */
+void hrtimer_notify_resume(void)
+{
+       clock_was_set();
+}
+
+/*
  * Counterpart to lock_timer_base above:
  */
 static inline
diff --git a/kernel/timer.c b/kernel/timer.c
index 4f9cc2a..8f4bf1e 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -878,12 +878,27 @@ int timekeeping_is_continuous(void)
        return ret;
 }
 
+/**
+ * read_persistent_clock -  Return time in seconds from the persistent clock.
+ *
+ * Weak dummy function for arches that do not yet support it.
+ * Returns seconds from epoch using the battery backed persistent clock.
+ * Returns zero if unsupported.
+ *
+ *  XXX - Do be sure to remove it once all arches implement it.
+ */
+unsigned long __attribute__((weak)) read_persistent_clock(void)
+{
+       return 0;
+}
+
 /*
  * timekeeping_init - Initializes the clocksource and common timekeeping values
  */
 void __init timekeeping_init(void)
 {
        unsigned long flags;
+       unsigned long sec = read_persistent_clock();
 
        write_seqlock_irqsave(&xtime_lock, flags);
 
@@ -893,11 +908,20 @@ void __init timekeeping_init(void)
        clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
        clock->cycle_last = clocksource_read(clock);
 
+       xtime.tv_sec = sec;
+       xtime.tv_nsec = 0;
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
+
        write_sequnlock_irqrestore(&xtime_lock, flags);
 }
 
 
+/* flag for if timekeeping is suspended */
 static int timekeeping_suspended;
+/* time in seconds when suspend began */
+static unsigned long timekeeping_suspend_time;
+
 /**
  * timekeeping_resume - Resumes the generic timekeeping subsystem.
  * @dev:       unused
@@ -909,13 +933,25 @@ static int timekeeping_suspended;
 static int timekeeping_resume(struct sys_device *dev)
 {
        unsigned long flags;
+       unsigned long now = read_persistent_clock();
 
        write_seqlock_irqsave(&xtime_lock, flags);
-       /* restart the last cycle value */
+
+       if (now && (now > timekeeping_suspend_time)) {
+               unsigned long sleep_length = now - timekeeping_suspend_time;
+
+               xtime.tv_sec += sleep_length;
+               wall_to_monotonic.tv_sec -= sleep_length;
+       }
+       /* re-base the last cycle value */
        clock->cycle_last = clocksource_read(clock);
        clock->error = 0;
        timekeeping_suspended = 0;
        write_sequnlock_irqrestore(&xtime_lock, flags);
+
+       touch_softlockup_watchdog();
+       hrtimer_notify_resume();
+
        return 0;
 }
 
@@ -925,6 +961,7 @@ static int timekeeping_suspend(struct sys_device *dev, 
pm_message_t state)
 
        write_seqlock_irqsave(&xtime_lock, flags);
        timekeeping_suspended = 1;
+       timekeeping_suspend_time = read_persistent_clock();
        write_sequnlock_irqrestore(&xtime_lock, flags);
        return 0;
 }
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to