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 | |
| 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>
| -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 | ||
