Commit 6a8943d9 authored by Arve Hjønnevåg's avatar Arve Hjønnevåg Committed by John Stultz

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: default avatarArve Hjønnevåg <arve@android.com>
Signed-off-by: default avatarJohn Stultz <john.stultz@linaro.org>
parent c0afabd3
...@@ -66,7 +66,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) ...@@ -66,7 +66,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg)
*/ */
delta = timespec_sub(old_system, old_rtc); delta = timespec_sub(old_system, old_rtc);
delta_delta = timespec_sub(delta, old_delta); delta_delta = timespec_sub(delta, old_delta);
if (abs(delta_delta.tv_sec) >= 2) { if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
/* /*
* if delta_delta is too large, assume time correction * if delta_delta is too large, assume time correction
* has occured and set old_delta to the current delta. * has occured and set old_delta to the current delta.
...@@ -100,9 +100,8 @@ static int rtc_resume(struct device *dev) ...@@ -100,9 +100,8 @@ static int rtc_resume(struct device *dev)
rtc_tm_to_time(&tm, &new_rtc.tv_sec); rtc_tm_to_time(&tm, &new_rtc.tv_sec);
new_rtc.tv_nsec = 0; new_rtc.tv_nsec = 0;
if (new_rtc.tv_sec <= old_rtc.tv_sec) { if (new_rtc.tv_sec < old_rtc.tv_sec) {
if (new_rtc.tv_sec < old_rtc.tv_sec) pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
return 0; return 0;
} }
...@@ -119,7 +118,8 @@ static int rtc_resume(struct device *dev) ...@@ -119,7 +118,8 @@ static int rtc_resume(struct device *dev)
sleep_time = timespec_sub(sleep_time, sleep_time = timespec_sub(sleep_time,
timespec_sub(new_system, old_system)); timespec_sub(new_system, old_system));
timekeeping_inject_sleeptime(&sleep_time); if (sleep_time.tv_sec >= 0)
timekeeping_inject_sleeptime(&sleep_time);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment