From 44c4b703fa14da37d65d779063c14d8a16cf3dcd Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 31 May 2011 22:53:23 -0700 Subject: [PATCH] --- yaml --- r: 257203 b: refs/heads/master c: cb33217b1b2523895eb328a0b13fb3b1c4000969 h: refs/heads/master i: 257201: 0f88c871f9021ace32ea495d6e6bac1f70a7899d 257199: be1fa33f09a490a93781e1f7785615c074dfdfd4 v: v3 --- [refs] | 2 +- trunk/kernel/time/timekeeping.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 07b3e4516e24..88fa8aaae716 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: cb5de2f8d0306be38f9b377b8a5c56acca7dbc3d +refs/heads/master: cb33217b1b2523895eb328a0b13fb3b1c4000969 diff --git a/trunk/kernel/time/timekeeping.c b/trunk/kernel/time/timekeeping.c index 9d09777a213f..fdc6b887b208 100644 --- a/trunk/kernel/time/timekeeping.c +++ b/trunk/kernel/time/timekeeping.c @@ -692,12 +692,34 @@ static void timekeeping_resume(void) static int timekeeping_suspend(void) { unsigned long flags; + struct timespec delta, delta_delta; + static struct timespec old_delta; read_persistent_clock(&timekeeping_suspend_time); write_seqlock_irqsave(&xtime_lock, flags); timekeeping_forward_now(); timekeeping_suspended = 1; + + /* + * To avoid drift caused by repeated suspend/resumes, + * which each can add ~1 second drift error, + * try to compensate so the difference in system time + * and persistent_clock time stays close to constant. + */ + delta = timespec_sub(xtime, timekeeping_suspend_time); + delta_delta = timespec_sub(delta, old_delta); + if (abs(delta_delta.tv_sec) >= 2) { + /* + * if delta_delta is too large, assume time correction + * has occured and set old_delta to the current delta. + */ + old_delta = delta; + } else { + /* Otherwise try to adjust old_system to compensate */ + timekeeping_suspend_time = + timespec_add(timekeeping_suspend_time, delta_delta); + } write_sequnlock_irqrestore(&xtime_lock, flags); clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);