Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: Check return value from mc146818_get_time()

There are 4 users of mc146818_get_time() and none of them was checking
the return value from this function. Change this.

Print the appropriate warnings in callers of mc146818_get_time() instead
of in the function mc146818_get_time() itself, in order not to add
strings to rtc-mc146818-lib.c, which is kind of a library.

The callers of alpha_rtc_read_time() and cmos_read_time() may use the
contents of (struct rtc_time *) even when the functions return a failure
code. Therefore, set the contents of (struct rtc_time *) to 0x00,
which looks more sensible then 0xff and aligns with the (possibly
stale?) comment in cmos_read_time:

/*
* If pm_trace abused the RTC for storage, set the timespec to 0,
* which tells the caller that this RTC value is unusable.
*/

For consistency, do this in mc146818_get_time().

Note: hpet_rtc_interrupt() may call mc146818_get_time() many times a
second. It is very unlikely, though, that the RTC suddenly stops
working and mc146818_get_time() would consistently fail.

Only compile-tested on alpha.

Signed-off-by: Mateusz Jończyk <mat.jonczyk@o2.pl>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Matt Turner <mattst88@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: linux-alpha@vger.kernel.org
Cc: x86@kernel.org
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20211210200131.153887-4-mat.jonczyk@o2.pl

authored by

Mateusz Jończyk and committed by
Alexandre Belloni
0dd8d6cb d35786b3

+26 -6
+6 -1
arch/alpha/kernel/rtc.c
··· 80 80 static int 81 81 alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) 82 82 { 83 - mc146818_get_time(tm); 83 + int ret = mc146818_get_time(tm); 84 + 85 + if (ret < 0) { 86 + dev_err_ratelimited(dev, "unable to read current time\n"); 87 + return ret; 88 + } 84 89 85 90 /* Adjust for non-default epochs. It's easier to depend on the 86 91 generic __get_rtc_time and adjust the epoch here than create
+6 -2
arch/x86/kernel/hpet.c
··· 1435 1435 hpet_rtc_timer_reinit(); 1436 1436 memset(&curr_time, 0, sizeof(struct rtc_time)); 1437 1437 1438 - if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) 1439 - mc146818_get_time(&curr_time); 1438 + if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) { 1439 + if (unlikely(mc146818_get_time(&curr_time) < 0)) { 1440 + pr_err_ratelimited("unable to read current time from RTC\n"); 1441 + return IRQ_HANDLED; 1442 + } 1443 + } 1440 1444 1441 1445 if (hpet_rtc_flags & RTC_UIE && 1442 1446 curr_time.tm_sec != hpet_prev_update_sec) {
+5 -1
drivers/base/power/trace.c
··· 120 120 struct rtc_time time; 121 121 unsigned int val; 122 122 123 - mc146818_get_time(&time); 123 + if (mc146818_get_time(&time) < 0) { 124 + pr_err("Unable to read current time from RTC\n"); 125 + return 0; 126 + } 127 + 124 128 pr_info("RTC time: %ptRt, date: %ptRd\n", &time, &time); 125 129 val = time.tm_year; /* 100 years */ 126 130 if (val > 100)
+8 -1
drivers/rtc/rtc-cmos.c
··· 222 222 223 223 static int cmos_read_time(struct device *dev, struct rtc_time *t) 224 224 { 225 + int ret; 226 + 225 227 /* 226 228 * If pm_trace abused the RTC for storage, set the timespec to 0, 227 229 * which tells the caller that this RTC value is unusable. ··· 231 229 if (!pm_trace_rtc_valid()) 232 230 return -EIO; 233 231 234 - mc146818_get_time(t); 232 + ret = mc146818_get_time(t); 233 + if (ret < 0) { 234 + dev_err_ratelimited(dev, "unable to read current time\n"); 235 + return ret; 236 + } 237 + 235 238 return 0; 236 239 } 237 240
+1 -1
drivers/rtc/rtc-mc146818-lib.c
··· 24 24 /* Ensure that the RTC is accessible. Bit 6 must be 0! */ 25 25 if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x40) != 0)) { 26 26 spin_unlock_irqrestore(&rtc_lock, flags); 27 - memset(time, 0xff, sizeof(*time)); 27 + memset(time, 0, sizeof(*time)); 28 28 return -EIO; 29 29 } 30 30