aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlexandre Belloni2021-11-07 23:54:46 +0100
committerAlexandre Belloni2021-11-10 00:45:56 +0100
commitd87f741dddabd670a82bccf94ac73cec80209bc0 (patch)
tree8dc414966bd5e15e5927c406e34c94cc834f26e6 /drivers
parent72e4ee638d8e1d7d80079c37ec8641fec0d63016 (diff)
rtc: handle alarms with a minute resolution
Handle alarms with a minute resolution in the core. Until now drivers have been open coding the seconds part removal and have been doing that wrongly. Most of them are rounding up which means the allow the system to miss deadlines. So, round down and let __rtc_set_alarm return immediately if the time has already passed. Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Link: https://lore.kernel.org/r/20211107225458.111068-1-alexandre.belloni@bootlin.com
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/interface.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index d005623e6eb3..d8e835798153 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -423,6 +423,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
if (err)
return err;
now = rtc_tm_to_time64(&tm);
+
if (scheduled <= now)
return -ETIME;
/*
@@ -447,6 +448,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
+ ktime_t alarm_time;
int err;
if (!rtc->ops)
@@ -468,7 +470,15 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
if (rtc->aie_timer.enabled)
rtc_timer_remove(rtc, &rtc->aie_timer);
- rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
+ alarm_time = rtc_tm_to_ktime(alarm->time);
+ /*
+ * Round down so we never miss a deadline, checking for past deadline is
+ * done in __rtc_set_alarm
+ */
+ if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features))
+ alarm_time = ktime_sub_ns(alarm_time, (u64)alarm->time.tm_sec * NSEC_PER_SEC);
+
+ rtc->aie_timer.node.expires = alarm_time;
rtc->aie_timer.period = 0;
if (alarm->enabled)
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);