diff options
author | Zoran Markovic <zoran.markovic@linaro.org> | 2013-06-26 19:09:13 -0400 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2013-07-22 12:38:25 -0400 |
commit | 14d0e347ea2db51144a8800d7c7576db96f69983 (patch) | |
tree | fd56f98424f8f9517ba6be8f8de4fb67147fe828 /drivers/rtc/interface.c | |
parent | 07862c1cd6675cde2dd4bd64e64d704ea2185b79 (diff) |
rtc: Keep system awake until all expired RTC timers are handled
Current implementation of RTC interface allows for system suspend to
occur in the following cases:
(a) if a timer is set in the past and rtc_timer_do_work() is scheduled
to handle it, and
(b) if rtc_timer_do_work() is called to handle expired timers whose
handlers implement a preemption point.
A pending suspend request may be honoured in the above cases causing
timer handling to be delayed until after the next resume. This is
undesirable since timer handlers may have time-critical code to execute.
This patch makes sure that the system stays awake until all expired
timers are handled.
Note that all calls to pm_stay_awake() are eventually paired with
the single pm_relax() call in rtc_timer_do_work(), which is launched
using schedule_work().
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Arve Hjonnevag <arve@android.com>
Cc: Todd Poynor <toddpoynor@google.com>
Signed-off-by: Zoran Markovic <zoran.markovic@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'drivers/rtc/interface.c')
-rw-r--r-- | drivers/rtc/interface.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 72c5cdbe0791..544be722937c 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
@@ -72,6 +72,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) | |||
72 | } else | 72 | } else |
73 | err = -EINVAL; | 73 | err = -EINVAL; |
74 | 74 | ||
75 | pm_stay_awake(rtc->dev.parent); | ||
75 | mutex_unlock(&rtc->ops_lock); | 76 | mutex_unlock(&rtc->ops_lock); |
76 | /* A timer might have just expired */ | 77 | /* A timer might have just expired */ |
77 | schedule_work(&rtc->irqwork); | 78 | schedule_work(&rtc->irqwork); |
@@ -113,6 +114,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) | |||
113 | err = -EINVAL; | 114 | err = -EINVAL; |
114 | } | 115 | } |
115 | 116 | ||
117 | pm_stay_awake(rtc->dev.parent); | ||
116 | mutex_unlock(&rtc->ops_lock); | 118 | mutex_unlock(&rtc->ops_lock); |
117 | /* A timer might have just expired */ | 119 | /* A timer might have just expired */ |
118 | schedule_work(&rtc->irqwork); | 120 | schedule_work(&rtc->irqwork); |
@@ -771,9 +773,10 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) | |||
771 | alarm.time = rtc_ktime_to_tm(timer->node.expires); | 773 | alarm.time = rtc_ktime_to_tm(timer->node.expires); |
772 | alarm.enabled = 1; | 774 | alarm.enabled = 1; |
773 | err = __rtc_set_alarm(rtc, &alarm); | 775 | err = __rtc_set_alarm(rtc, &alarm); |
774 | if (err == -ETIME) | 776 | if (err == -ETIME) { |
777 | pm_stay_awake(rtc->dev.parent); | ||
775 | schedule_work(&rtc->irqwork); | 778 | schedule_work(&rtc->irqwork); |
776 | else if (err) { | 779 | } else if (err) { |
777 | timerqueue_del(&rtc->timerqueue, &timer->node); | 780 | timerqueue_del(&rtc->timerqueue, &timer->node); |
778 | timer->enabled = 0; | 781 | timer->enabled = 0; |
779 | return err; | 782 | return err; |
@@ -818,8 +821,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) | |||
818 | alarm.time = rtc_ktime_to_tm(next->expires); | 821 | alarm.time = rtc_ktime_to_tm(next->expires); |
819 | alarm.enabled = 1; | 822 | alarm.enabled = 1; |
820 | err = __rtc_set_alarm(rtc, &alarm); | 823 | err = __rtc_set_alarm(rtc, &alarm); |
821 | if (err == -ETIME) | 824 | if (err == -ETIME) { |
825 | pm_stay_awake(rtc->dev.parent); | ||
822 | schedule_work(&rtc->irqwork); | 826 | schedule_work(&rtc->irqwork); |
827 | } | ||
823 | } | 828 | } |
824 | } | 829 | } |
825 | 830 | ||
@@ -845,7 +850,6 @@ void rtc_timer_do_work(struct work_struct *work) | |||
845 | 850 | ||
846 | mutex_lock(&rtc->ops_lock); | 851 | mutex_lock(&rtc->ops_lock); |
847 | again: | 852 | again: |
848 | pm_relax(rtc->dev.parent); | ||
849 | __rtc_read_time(rtc, &tm); | 853 | __rtc_read_time(rtc, &tm); |
850 | now = rtc_tm_to_ktime(tm); | 854 | now = rtc_tm_to_ktime(tm); |
851 | while ((next = timerqueue_getnext(&rtc->timerqueue))) { | 855 | while ((next = timerqueue_getnext(&rtc->timerqueue))) { |
@@ -880,6 +884,7 @@ again: | |||
880 | } else | 884 | } else |
881 | rtc_alarm_disable(rtc); | 885 | rtc_alarm_disable(rtc); |
882 | 886 | ||
887 | pm_relax(rtc->dev.parent); | ||
883 | mutex_unlock(&rtc->ops_lock); | 888 | mutex_unlock(&rtc->ops_lock); |
884 | } | 889 | } |
885 | 890 | ||