diff options
author | Arve Hjønnevåg <arve@android.com> | 2011-11-22 21:24:51 -0500 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2011-11-22 22:25:56 -0500 |
commit | 6a8943d9ec2567572fca25cf69ad45844d0141a3 (patch) | |
tree | d14768e0747bd4b44fb00131c9c79713033c51c5 | |
parent | c0afabd3d553c521e003779c127143ffde55a16f (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.c | 10 |
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 | ||