RTC regression
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
----
drivers/rtc/rtc-mpc5121.c +9 -1
@@ -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++;
Quoted 16 lines · Richard Weinberger
Hi!
hwclock calls the
RTC_UIE_ONioctl to wait for a timer tick.
IfRTC_UIE_ONwas successful it opens/dev/rtcXand waits up to 5 seconds usingselect()for a tick.
Some RTC drivers have no support forRTC_UIE_ONand ioctl just returns-EINVAL. Drivers indicated this by settingrtc_class_ops->update_irq_enableto 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: Cleanuprtc_class_ops->update_irq_enable())
rtc_class_ops->update_irq_enablewas removed andrtc_update_irq_enable()is now usingrtc_class_ops->set_alarminstead ofrtc_class_ops->update_irq_enable.
Quoted 6 lines
Some RTC devices (like mpc515x) don't support intervals smaller than one minute.
rtc-mpc5121.cdeals with this by rounding up to one minute.
But now after commit 6610e08RTC_UIE_ONwill no longer return-EINVALand the next tick comes somewhen within the next 60 seconds, because the driver rounded up... hwclock'sselect()is not happy about this and timeouts in most cases.
Thanks for diagnosing and pointing out this issue! I hadn't been aware of such hardware.
Would something like the following be a better generic interface? Basically allow the RTC drivers to flag that UIE is unsupported (much as setting the update_irq_enable to null did prior).
Let me know if this works for you, and I'll look to see what other drivers might be affected here.
thanks
-john
Add generic infrastructure to handle rtc devices that don't support UIE mode.
drivers/rtc/interface.c +5 -0
@@ -458,6 +458,11 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)if (rtc->uie_rtctimer.enabled == enabled) goto out; +if (rtc->uie_unsupported) { + err = -EINVAL ; + goto out; + } +if (enabled) {struct rtc_time tm;ktime_t now, onesec;
drivers/rtc/rtc-mpc5121.c +2 -0
@@ -360,6 +360,8 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op) &mpc5200_rtc_ops, THIS_MODULE); } + rtc->rtc.uie_unsupported =1 ; +if (IS_ERR (rtc->rtc)) { err =PTR_ERR (rtc->rtc); goto out_free_irq;
include/linux/rtc.h +2 -1
@@ -202,7 +202,8 @@ struct rtc_devicestruct hrtimer pie_timer;/* sub second exp, so needs hrtimer */ int pie_enabled;struct work_struct irqwork; - +/* Some hardware can't support UIE mode */ +int uie_unsupported;#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL struct work_struct uie_task;
Richard Weinberger
Tested-byQuoted 34 lines · John Stultz
Quoted 16 lines · Richard Weinberger
Hi!
hwclock calls the
RTC_UIE_ONioctl to wait for a timer tick.
IfRTC_UIE_ONwas successful it opens/dev/rtcXand waits up to 5 seconds usingselect()for a tick.
Some RTC drivers have no support forRTC_UIE_ONand ioctl just returns-EINVAL. Drivers indicated this by settingrtc_class_ops->update_irq_enableto 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: Cleanuprtc_class_ops->update_irq_enable())
rtc_class_ops->update_irq_enablewas removed andrtc_update_irq_enable()is now usingrtc_class_ops->set_alarminstead ofrtc_class_ops->update_irq_enable.Quoted 6 lines
Some RTC devices (like mpc515x) don't support intervals smaller than one minute.
rtc-mpc5121.cdeals with this by rounding up to one minute.
But now after commit 6610e08RTC_UIE_ONwill no longer return-EINVALand the next tick comes somewhen within the next 60 seconds, because the driver rounded up... hwclock'sselect()is not happy about this and timeouts in most cases.Thanks for diagnosing and pointing out this issue! I hadn't been aware of such hardware.
Would something like the following be a better generic interface? Basically allow the RTC drivers to flag that UIE is unsupported (much as setting the
update_irq_enableto null did prior).Let me know if this works for you, and I'll look to see what other drivers might be affected here.
Quoted 7 lines
thanks
-johnAdd generic infrastructure to handle rtc devices that don't support UIE mode.
Signed-off-by John Stultz<[email protected]>
drivers/rtc/rtc-mpc5121.c static int __devinit mpc5121_rtc_probe(struct platform_device *op) · line 364
Quoted 10 lines
drivers/rtc/rtc-mpc5121.c +2
-0@@ -360,6 +360,8 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op) &mpc5200_rtc_ops, THIS_MODULE); } + rtc->rtc.uie_unsupported =1 ; +
Please replace this line by:rtc->rtc->uie_unsupported = 1;
Thanks,
//richard