From eaa6ef563d1a60fbfe6c128bf8fdb74405035b0c Mon Sep 17 00:00:00 2001 From: Emmanuel Nicolet Date: Fri, 27 Sep 2019 13:04:46 +0200 Subject: rtc: interface: use timeu64_t for range_max For rtc drivers where rtc->range_max is set U64_MAX, like the PS3 rtc, rtc_valid_range() always returns -ERANGE. This is because the local variable range_max has type time64_t, so the test if (time < range_min || time > range_max) return -ERANGE; becomes (time < range_min || time > -1), which always evaluates to true. timeu64_t should be used, since it's the type of rtc->range_max. Signed-off-by: Emmanuel Nicolet Link: https://lore.kernel.org/r/20190927110446.GA6289@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc/interface.c') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index c93ef33b01d3..eea700723976 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -70,7 +70,7 @@ static int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm) time64_t time = rtc_tm_to_time64(tm); time64_t range_min = rtc->set_start_time ? rtc->start_secs : rtc->range_min; - time64_t range_max = rtc->set_start_time ? + timeu64_t range_max = rtc->set_start_time ? (rtc->start_secs + rtc->range_max - rtc->range_min) : rtc->range_max; -- cgit v1.2.3 From 7e7c005b4b1f1f169bcc4b2c3a40085ecc663df2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 21 Oct 2019 01:13:20 +0200 Subject: rtc: disable uie before setting time and enable after When setting the time in the future with the uie timer enabled, rtc_timer_do_work will loop for a while because the expiration of the uie timer was way before the current RTC time and a new timer will be enqueued until the current rtc time is reached. If the uie timer is enabled, disable it before setting the time and enable it after expiring current timers (which may actually be an alarm). This is the safest thing to do to ensure the uie timer is still synchronized with the RTC, especially in the UIE emulation case. Reported-by: syzbot+08116743f8ad6f9a6de7@syzkaller.appspotmail.com Fixes: 6610e0893b8b ("RTC: Rework RTC code to use timerqueue for events") Link: https://lore.kernel.org/r/20191020231320.8191-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/rtc/interface.c') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index eea700723976..f8b7c004d6ec 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -125,7 +125,7 @@ EXPORT_SYMBOL_GPL(rtc_read_time); int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) { - int err; + int err, uie; err = rtc_valid_tm(tm); if (err != 0) @@ -137,6 +137,17 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) rtc_subtract_offset(rtc, tm); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + uie = rtc->uie_rtctimer.enabled || rtc->uie_irq_active; +#else + uie = rtc->uie_rtctimer.enabled; +#endif + if (uie) { + err = rtc_update_irq_enable(rtc, 0); + if (err) + return err; + } + err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; @@ -153,6 +164,12 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) /* A timer might have just expired */ schedule_work(&rtc->irqwork); + if (uie) { + err = rtc_update_irq_enable(rtc, 1); + if (err) + return err; + } + trace_rtc_set_time(rtc_tm_to_time64(tm), err); return err; } -- cgit v1.2.3 From 3e74ddaa7ca06f4c41bc3c83286534cb7ebc90eb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 21 Oct 2019 17:56:31 +0200 Subject: rtc: disallow update interrupts when time is invalid Never enable update interrupts when the time set on the rtc is invalid. In that case, also avoid enabling the emulation because it will fail for the same reason. Link: https://lore.kernel.org/r/20191021155631.3342-2-alexandre.belloni@bootlin.com Link: https://lore.kernel.org/r/CA+ASDXMarBG5C1Kz42B9i_iVZ1=i6GgH9Yja2cdmSueKD_As_g@mail.gmail.com Reported-by: Jeffy Chen Reported-by: Brian Norris Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/rtc/interface.c') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index f8b7c004d6ec..bd8034b7bc93 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -545,7 +545,7 @@ EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) { - int err; + int rc = 0, err; err = mutex_lock_interruptible(&rtc->ops_lock); if (err) @@ -570,7 +570,9 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) struct rtc_time tm; ktime_t now, onesec; - __rtc_read_time(rtc, &tm); + rc = __rtc_read_time(rtc, &tm); + if (rc) + goto out; onesec = ktime_set(1, 0); now = rtc_tm_to_ktime(tm); rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); @@ -582,6 +584,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) out: mutex_unlock(&rtc->ops_lock); + + /* + * __rtc_read_time() failed, this probably means that the RTC time has + * never been set or less probably there is a transient error on the + * bus. In any case, avoid enabling emulation has this will fail when + * reading the time too. + */ + if (rc) + return rc; + #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL /* * Enable emulation if the driver returned -EINVAL to signal that it has -- cgit v1.2.3 From 55dcf7a21dbcc743a0b39e01916f5d006736b1e1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 27 Nov 2019 09:29:32 +0100 Subject: rtc: interface: fix kerneldoc comments Fix kerneldoc warnings: drivers/rtc/interface.c:619: warning: Function parameter or member 'num' not described in 'rtc_handle_legacy_irq' drivers/rtc/interface.c:619: warning: Function parameter or member 'mode' not described in 'rtc_handle_legacy_irq' drivers/rtc/interface.c:804: warning: Function parameter or member 'rtc' not described in 'rtc_timer_enqueue' drivers/rtc/interface.c:804: warning: Function parameter or member 'timer' not described in 'rtc_timer_enqueue' drivers/rtc/interface.c:864: warning: Function parameter or member 'rtc' not described in 'rtc_timer_remove' drivers/rtc/interface.c:864: warning: Function parameter or member 'timer' not described in 'rtc_timer_remove' drivers/rtc/interface.c:900: warning: Function parameter or member 'work' not described in 'rtc_timer_do_work' drivers/rtc/interface.c:1035: warning: Function parameter or member 'rtc' not described in 'rtc_read_offset' drivers/rtc/interface.c:1035: warning: Function parameter or member 'offset' not described in 'rtc_read_offset' drivers/rtc/interface.c:1070: warning: Function parameter or member 'rtc' not described in 'rtc_set_offset' drivers/rtc/interface.c:1070: warning: Function parameter or member 'offset' not described in 'rtc_set_offset' Link: https://lore.kernel.org/r/20191127082932.666869-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/rtc/interface.c') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index bd8034b7bc93..794a4f036b99 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -610,6 +610,8 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); /** * rtc_handle_legacy_irq - AIE, UIE and PIE event hook * @rtc: pointer to the rtc device + * @num: number of occurence of the event + * @mode: type of the event, RTC_AF, RTC_UF of RTC_PF * * This function is called when an AIE, UIE or PIE mode interrupt * has occurred (or been emulated). @@ -790,8 +792,8 @@ int rtc_irq_set_freq(struct rtc_device *rtc, int freq) /** * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue - * @rtc rtc device - * @timer timer being added. + * @rtc: rtc device + * @timer: timer being added. * * Enqueues a timer onto the rtc devices timerqueue and sets * the next alarm event appropriately. @@ -850,8 +852,8 @@ static void rtc_alarm_disable(struct rtc_device *rtc) /** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue - * @rtc rtc device - * @timer timer being removed. + * @rtc: rtc device + * @timer: timer being removed. * * Removes a timer onto the rtc devices timerqueue and sets * the next alarm event appropriately. @@ -888,8 +890,7 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) /** * rtc_timer_do_work - Expires rtc timers - * @rtc rtc device - * @timer timer being removed. + * @work: work item * * Expires rtc timers. Reprograms next alarm event if needed. * Called via worktask. @@ -1022,8 +1023,8 @@ void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer) /** * rtc_read_offset - Read the amount of rtc offset in parts per billion - * @ rtc: rtc device to be used - * @ offset: the offset in parts per billion + * @rtc: rtc device to be used + * @offset: the offset in parts per billion * * see below for details. * @@ -1051,8 +1052,8 @@ int rtc_read_offset(struct rtc_device *rtc, long *offset) /** * rtc_set_offset - Adjusts the duration of the average second - * @ rtc: rtc device to be used - * @ offset: the offset in parts per billion + * @rtc: rtc device to be used + * @offset: the offset in parts per billion * * Some rtc's allow an adjustment to the average duration of a second * to compensate for differences in the actual clock rate due to temperature, -- cgit v1.2.3