aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArve Hjønnevåg <arve@android.com>2011-11-22 21:24:51 -0500
committerJohn Stultz <john.stultz@linaro.org>2011-11-22 22:25:56 -0500
commit6a8943d9ec2567572fca25cf69ad45844d0141a3 (patch)
treed14768e0747bd4b44fb00131c9c79713033c51c5
parentc0afabd3d553c521e003779c127143ffde55a16f (diff)
rtc: Fix some bugs that allowed accumulating time drift in suspend/resume
The current code checks if abs(delta_delta.tv_sec) is greater or equal to two before it discards the old delta value, but this can trigger at close to -1 seconds since -1.000000001 seconds is stored as tv_sec -2 and tv_nsec 999999999 in a normalized timespec. rtc_resume had an early return check if the rtc value had not changed since rtc_suspend. This effectivly stops time for the duration of the short sleep. Check if sleep_time is positive after all the adjustments have been applied instead since this allows the old_system adjustment in rtc_suspend to have an effect even for short sleep cycles. CC: stable@kernel.org Signed-off-by: Arve Hjønnevåg <arve@android.com> Signed-off-by: John Stultz <john.stultz@linaro.org>
-rw-r--r--drivers/rtc/class.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 01a7df5317c1..b82a1554cdc1 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -66,7 +66,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg)
66 */ 66 */
67 delta = timespec_sub(old_system, old_rtc); 67 delta = timespec_sub(old_system, old_rtc);
68 delta_delta = timespec_sub(delta, old_delta); 68 delta_delta = timespec_sub(delta, old_delta);
69 if (abs(delta_delta.tv_sec) >= 2) { 69 if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
70 /* 70 /*
71 * if delta_delta is too large, assume time correction 71 * if delta_delta is too large, assume time correction
72 * has occured and set old_delta to the current delta. 72 * has occured and set old_delta to the current delta.
@@ -100,9 +100,8 @@ static int rtc_resume(struct device *dev)
100 rtc_tm_to_time(&tm, &new_rtc.tv_sec); 100 rtc_tm_to_time(&tm, &new_rtc.tv_sec);
101 new_rtc.tv_nsec = 0; 101 new_rtc.tv_nsec = 0;
102 102
103 if (new_rtc.tv_sec <= old_rtc.tv_sec) { 103 if (new_rtc.tv_sec < old_rtc.tv_sec) {
104 if (new_rtc.tv_sec < old_rtc.tv_sec) 104 pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
105 pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
106 return 0; 105 return 0;
107 } 106 }
108 107
@@ -119,7 +118,8 @@ static int rtc_resume(struct device *dev)
119 sleep_time = timespec_sub(sleep_time, 118 sleep_time = timespec_sub(sleep_time,
120 timespec_sub(new_system, old_system)); 119 timespec_sub(new_system, old_system));
121 120
122 timekeeping_inject_sleeptime(&sleep_time); 121 if (sleep_time.tv_sec >= 0)
122 timekeeping_inject_sleeptime(&sleep_time);
123 return 0; 123 return 0;
124} 124}
125 125