diff options
author | John Stultz <john.stultz@linaro.org> | 2012-01-05 18:21:19 -0500 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2012-01-26 22:41:30 -0500 |
commit | bd729d72b428261f2975360e0c117d7d7a2cd6e8 (patch) | |
tree | 73ebfff880ba7d96cb5d82e0811b0476ab310c16 /drivers/rtc | |
parent | a99cbf6b43a7b3b15f6139b2d9ac4ecceccd3c99 (diff) |
rtc: Avoid setting alarm to a time in the past
In some cases at boot up, the RTC alarm may be set in the past,
but still have the enabled flag on. This was causing problems,
because we would then enqueue the alarm into the timerqueue,
but it would never fire. This would clog up the timerqueue
and keep other alarms from working.
The fix is to check the alarm against the current rtc time at
boot and avoid enqueueing the alarm if it is in the past.
Reported-by: NeilBrown <neilb@suse.de>
Tested-by: NeilBrown <neilb@suse.de>
Tested-by: Sander Eikelenboom <linux@eikelenboom.it>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/interface.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8a1c031391d6..c55a16041b6e 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
@@ -380,18 +380,27 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm); | |||
380 | int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 380 | int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
381 | { | 381 | { |
382 | int err; | 382 | int err; |
383 | struct rtc_time now; | ||
383 | 384 | ||
384 | err = rtc_valid_tm(&alarm->time); | 385 | err = rtc_valid_tm(&alarm->time); |
385 | if (err != 0) | 386 | if (err != 0) |
386 | return err; | 387 | return err; |
387 | 388 | ||
389 | err = rtc_read_time(rtc, &now); | ||
390 | if (err) | ||
391 | return err; | ||
392 | |||
388 | err = mutex_lock_interruptible(&rtc->ops_lock); | 393 | err = mutex_lock_interruptible(&rtc->ops_lock); |
389 | if (err) | 394 | if (err) |
390 | return err; | 395 | return err; |
391 | 396 | ||
392 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); | 397 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); |
393 | rtc->aie_timer.period = ktime_set(0, 0); | 398 | rtc->aie_timer.period = ktime_set(0, 0); |
394 | if (alarm->enabled) { | 399 | |
400 | /* Alarm has to be enabled & in the futrure for us to enqueue it */ | ||
401 | if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 < | ||
402 | rtc->aie_timer.node.expires.tv64)) { | ||
403 | |||
395 | rtc->aie_timer.enabled = 1; | 404 | rtc->aie_timer.enabled = 1; |
396 | timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); | 405 | timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); |
397 | } | 406 | } |