Patchwork RTC regression

login
register
mail settings
Submitter Richard Weinberger
Date Feb. 29, 2012, 9:41 p.m.
Message ID <4F4E9B71.2010407@nod.at>
Download mbox | patch
Permalink /patch/143823/
State New
Headers show

Comments

Richard Weinberger - Feb. 29, 2012, 9:41 p.m.
Hi!

hwclock calls the RTC_UIE_ON ioctl to wait for a timer tick.
If RTC_UIE_ON was successful it opens /dev/rtcX and waits up to 5 seconds using select()
for a tick.
Some RTC drivers have no support for RTC_UIE_ON and ioctl just returns -EINVAL.
Drivers indicated this by setting rtc_class_ops->update_irq_enable to NULL.
In this case hwclock waits in a busy loop for the next timer tick.

These two commits changed this behavior:
6610e08 (RTC: Rework RTC code to use timerqueue for events)
51ba60c (RTC: Cleanup rtc_class_ops->update_irq_enable())

rtc_class_ops->update_irq_enable was removed and rtc_update_irq_enable()
is now using rtc_class_ops->set_alarm instead of rtc_class_ops->update_irq_enable.

Some RTC devices (like mpc515x) don't support intervals smaller than one
minute.
rtc-mpc5121.c deals with this by rounding up to one minute.
But now after commit 6610e08 RTC_UIE_ON will no longer return -EINVAL and
the next tick comes somewhen within the next 60 seconds, because the driver rounded up...
hwclock's select() is not happy about this and timeouts in most cases.

The attached patch fixes the issue for mpc512x.
set_alarm returns now -EINVAL if the requested interval is less than one minute.
But I'm sure there are more RTC drivers and devices which are unable to handle
such short intervals.
Their RTC_UIE_ON behavior is currently undefined.

Thanks,
//richard

----

Patch

diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index 09ccd8d..dee992c 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -161,10 +161,18 @@  static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+       struct rtc_time now;

        /*
-        * the alarm has no seconds so deal with it
+        * the alarm has no seconds so deal with it:
+        * - return -EINVAL if the interval is < 1 minute
+        * - round up to one minute if it's > 1 minute
         */
+       mpc5121_rtc_read_time(dev, &now);
+       if (alarm->time.tm_min == now.tm_min &&
+               alarm->time.tm_hour == now.tm_hour)
+               return -EINVAL;
+
        if (alarm->time.tm_sec) {
                alarm->time.tm_sec = 0;
                alarm->time.tm_min++;