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