[PATCH] rtc: mc146818: Use hours for checking RTC availability

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To prevent an infinite loop, it is necessary to ascertain the RTC is
present. Previous code was checking if bit 6 in register 0x0D is
cleared. This caused a false negative on a motherboard with an AMD SB710
southbridge; according to the specification [1], bit 6 of register 0x0D
on this chipset is a scratchbit.

Use the RTC_HOURS register instead, which is expected to contain a value
not larger then 24, in BCD format.

Caveat: when I was playing with
        while true; do cat /sys/class/rtc/rtc0/time; done
I sometimes triggered this mechanism on my HP laptop. It appears that
CMOS_READ(RTC_VALID) was sometimes reading the number of seconds from
previous loop iteration. This happens very rarely, though, and this patch
does not make it any more likely.

[1] AMD SB700/710/750 Register Reference Guide, page 308,
https://developer.amd.com/wordpress/media/2012/10/43009_sb7xx_rrg_pub_1.00.pdf

Fixes: 211e5db19d15 ("rtc: mc146818: Detect and handle broken RTCs")
Fixes: ebb22a059436 ("rtc: mc146818: Dont test for bit 0-5 in Register D")
Signed-off-by: Mateusz Jończyk <mat.jonczyk@xxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Alessandro Zummo <a.zummo@xxxxxxxxxxxx>
Cc: Alexandre Belloni <alexandre.belloni@xxxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
---
 drivers/rtc/rtc-cmos.c         |  6 +++---
 drivers/rtc/rtc-mc146818-lib.c | 10 ++++++++--
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 670fd8a2970e..b0102fb31b3f 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -798,10 +798,10 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 
 	spin_lock_irq(&rtc_lock);
 
-	/* Ensure that the RTC is accessible. Bit 6 must be 0! */
-	if ((CMOS_READ(RTC_VALID) & 0x40) != 0) {
+	/* Ensure that the RTC is accessible (RTC_HOURS is in BCD format) */
+	if (CMOS_READ(RTC_HOURS) > 0x24) {
 		spin_unlock_irq(&rtc_lock);
-		dev_warn(dev, "not accessible\n");
+		dev_warn(dev, "not accessible or not working correctly\n");
 		retval = -ENXIO;
 		goto cleanup1;
 	}
diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c
index dcfaf09946ee..1d69c3c13257 100644
--- a/drivers/rtc/rtc-mc146818-lib.c
+++ b/drivers/rtc/rtc-mc146818-lib.c
@@ -21,9 +21,15 @@ unsigned int mc146818_get_time(struct rtc_time *time)
 
 again:
 	spin_lock_irqsave(&rtc_lock, flags);
-	/* Ensure that the RTC is accessible. Bit 6 must be 0! */
-	if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x40) != 0)) {
+
+	/*
+	 * Ensure that the RTC is accessible, to avoid an infinite loop.
+	 * RTC_HOURS is in BCD format.
+	 */
+	if (CMOS_READ(RTC_HOURS) > 0x24) {
 		spin_unlock_irqrestore(&rtc_lock, flags);
+		pr_warn_once("Real-time clock is not accessible or not "
+				"working correctly\n");
 		memset(time, 0xff, sizeof(*time));
 		return 0;
 	}
-- 
2.25.1




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux