mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
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>
This commit is contained in:
parent
07862c1cd6
commit
14d0e347ea
@ -72,6 +72,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
|
|||||||
} else
|
} else
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
|
pm_stay_awake(rtc->dev.parent);
|
||||||
mutex_unlock(&rtc->ops_lock);
|
mutex_unlock(&rtc->ops_lock);
|
||||||
/* A timer might have just expired */
|
/* A timer might have just expired */
|
||||||
schedule_work(&rtc->irqwork);
|
schedule_work(&rtc->irqwork);
|
||||||
@ -113,6 +114,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
|
|||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm_stay_awake(rtc->dev.parent);
|
||||||
mutex_unlock(&rtc->ops_lock);
|
mutex_unlock(&rtc->ops_lock);
|
||||||
/* A timer might have just expired */
|
/* A timer might have just expired */
|
||||||
schedule_work(&rtc->irqwork);
|
schedule_work(&rtc->irqwork);
|
||||||
@ -771,9 +773,10 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
|||||||
alarm.time = rtc_ktime_to_tm(timer->node.expires);
|
alarm.time = rtc_ktime_to_tm(timer->node.expires);
|
||||||
alarm.enabled = 1;
|
alarm.enabled = 1;
|
||||||
err = __rtc_set_alarm(rtc, &alarm);
|
err = __rtc_set_alarm(rtc, &alarm);
|
||||||
if (err == -ETIME)
|
if (err == -ETIME) {
|
||||||
|
pm_stay_awake(rtc->dev.parent);
|
||||||
schedule_work(&rtc->irqwork);
|
schedule_work(&rtc->irqwork);
|
||||||
else if (err) {
|
} else if (err) {
|
||||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||||
timer->enabled = 0;
|
timer->enabled = 0;
|
||||||
return err;
|
return err;
|
||||||
@ -818,8 +821,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
|
|||||||
alarm.time = rtc_ktime_to_tm(next->expires);
|
alarm.time = rtc_ktime_to_tm(next->expires);
|
||||||
alarm.enabled = 1;
|
alarm.enabled = 1;
|
||||||
err = __rtc_set_alarm(rtc, &alarm);
|
err = __rtc_set_alarm(rtc, &alarm);
|
||||||
if (err == -ETIME)
|
if (err == -ETIME) {
|
||||||
|
pm_stay_awake(rtc->dev.parent);
|
||||||
schedule_work(&rtc->irqwork);
|
schedule_work(&rtc->irqwork);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,7 +850,6 @@ void rtc_timer_do_work(struct work_struct *work)
|
|||||||
|
|
||||||
mutex_lock(&rtc->ops_lock);
|
mutex_lock(&rtc->ops_lock);
|
||||||
again:
|
again:
|
||||||
pm_relax(rtc->dev.parent);
|
|
||||||
__rtc_read_time(rtc, &tm);
|
__rtc_read_time(rtc, &tm);
|
||||||
now = rtc_tm_to_ktime(tm);
|
now = rtc_tm_to_ktime(tm);
|
||||||
while ((next = timerqueue_getnext(&rtc->timerqueue))) {
|
while ((next = timerqueue_getnext(&rtc->timerqueue))) {
|
||||||
@ -880,6 +884,7 @@ again:
|
|||||||
} else
|
} else
|
||||||
rtc_alarm_disable(rtc);
|
rtc_alarm_disable(rtc);
|
||||||
|
|
||||||
|
pm_relax(rtc->dev.parent);
|
||||||
mutex_unlock(&rtc->ops_lock);
|
mutex_unlock(&rtc->ops_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user