|
@@ -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);
|
|
@@ -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;
|
|
|
+}
|