Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[pandora-kernel.git] / kernel / time / timekeeping.c
index 3d1042f..8969877 100644 (file)
@@ -36,9 +36,17 @@ EXPORT_SYMBOL(xtime_lock);
  * at zero at system boot time, so wall_to_monotonic will be negative,
  * however, we will ALWAYS keep the tv_nsec part positive so we can use
  * the usual normalization.
+ *
+ * wall_to_monotonic is moved after resume from suspend for the monotonic
+ * time not to jump. We need to add total_sleep_time to wall_to_monotonic
+ * to get the real boot based time offset.
+ *
+ * - wall_to_monotonic is no longer the boot time, getboottime must be
+ * used instead.
  */
 struct timespec xtime __attribute__ ((aligned (16)));
 struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
+static unsigned long total_sleep_time;         /* seconds */
 
 EXPORT_SYMBOL(xtime);
 
@@ -251,6 +259,7 @@ void __init timekeeping_init(void)
        xtime.tv_nsec = 0;
        set_normalized_timespec(&wall_to_monotonic,
                -xtime.tv_sec, -xtime.tv_nsec);
+       total_sleep_time = 0;
 
        write_sequnlock_irqrestore(&xtime_lock, flags);
 }
@@ -282,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev)
 
                xtime.tv_sec += sleep_length;
                wall_to_monotonic.tv_sec -= sleep_length;
+               total_sleep_time += sleep_length;
        }
        /* re-base the last cycle value */
        clock->cycle_last = clocksource_read(clock);
@@ -391,7 +401,7 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
  * this is optimized for the most common adjustments of -1,0,1,
  * for other values we can do a bit more work.
  */
-static void clocksource_adjust(struct clocksource *clock, s64 offset)
+static void clocksource_adjust(s64 offset)
 {
        s64 error, interval = clock->cycle_interval;
        int adj;
@@ -466,7 +476,7 @@ void update_wall_time(void)
        }
 
        /* correct the clock when NTP error is too big */
-       clocksource_adjust(clock, offset);
+       clocksource_adjust(offset);
 
        /* store full nanoseconds into xtime */
        xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
@@ -476,3 +486,30 @@ void update_wall_time(void)
        change_clocksource();
        update_vsyscall(&xtime, clock);
 }
+
+/**
+ * getboottime - Return the real time of system boot.
+ * @ts:                pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec.
+ *
+ * This is based on the wall_to_monotonic offset and the total suspend
+ * time. Calls to settimeofday will affect the value returned (which
+ * basically means that however wrong your real time clock is at boot time,
+ * you get the right time here).
+ */
+void getboottime(struct timespec *ts)
+{
+       set_normalized_timespec(ts,
+               - (wall_to_monotonic.tv_sec + total_sleep_time),
+               - wall_to_monotonic.tv_nsec);
+}
+
+/**
+ * monotonic_to_bootbased - Convert the monotonic time to boot based.
+ * @ts:                pointer to the timespec to be converted
+ */
+void monotonic_to_bootbased(struct timespec *ts)
+{
+       ts->tv_sec += total_sleep_time;
+}