alarmtimer: Avoid unexpected rtc interrupt when system resume from S3
authorzhuo-hao <zhuo-hao.lee@intel.com>
Tue, 17 Nov 2015 12:08:07 +0000 (20:08 +0800)
committerJohn Stultz <john.stultz@linaro.org>
Fri, 4 Dec 2015 06:31:42 +0000 (22:31 -0800)
Before the system go to suspend (S3), if user create a timer
with clockid CLOCK_REALTIME_ALARM/CLOCK_BOOTTIME_ALARM and set a
"large" timeout value to this timer. The function
alarmtimer_suspend will be called to setup a timeout value to
RTC timer to avoid the system sleep over time. However, if the
system wakeup early than RTC timeout, the RTC timer will not be
cleared. And this will cause the hpet_rtc_interrupt come
unexpectedly until the RTC timeout. To fix this problem, just
adding alarmtimer_resume to cancel the RTC timer.

This was noticed because the HPET RTC emulation fires an
interrupt every 16ms(=1/2^DEFAULT_RTC_SHIFT) up to the point
where the alarm time is reached.

This program always hits this situation
(https://lkml.org/lkml/2015/11/8/326), if system wake up earlier
than alarm time.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Stultz <john.stultz@linaro.org>
Signed-off-by: Zhuo-hao Lee <zhuo-hao.lee@intel.com>
[jstultz: Tweak commit subject & formatting slightly]
Signed-off-by: John Stultz <john.stultz@linaro.org>
kernel/time/alarmtimer.c

index 7fbba63..e840ed8 100644 (file)
@@ -271,11 +271,27 @@ static int alarmtimer_suspend(struct device *dev)
                __pm_wakeup_event(ws, MSEC_PER_SEC);
        return ret;
 }
+
+static int alarmtimer_resume(struct device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = alarmtimer_get_rtcdev();
+       if (rtc)
+               rtc_timer_cancel(rtc, &rtctimer);
+       return 0;
+}
+
 #else
 static int alarmtimer_suspend(struct device *dev)
 {
        return 0;
 }
+
+static int alarmtimer_resume(struct device *dev)
+{
+       return 0;
+}
 #endif
 
 static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
@@ -800,6 +816,7 @@ out:
 /* Suspend hook structures */
 static const struct dev_pm_ops alarmtimer_pm_ops = {
        .suspend = alarmtimer_suspend,
+       .resume = alarmtimer_resume,
 };
 
 static struct platform_driver alarmtimer_driver = {