Before my commit "rtc-cmos: dont touch alarm registers during update", applying this patch and reading the CMOS time like so: while true; do cat /sys/class/rtc/rtc0/time ; sleep 0.5; done produces errors in dmesg. Signed-off-by: Mateusz Jończyk <mat.jonczyk@xxxxx> Cc: Alessandro Zummo <a.zummo@xxxxxxxxxxxx> Cc: Alexandre Belloni <alexandre.belloni@xxxxxxxxxxx> --- drivers/rtc/rtc-cmos.c | 61 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index f353a41dfe8c..c24465f7bed4 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -43,6 +43,9 @@ #include <linux/dmi.h> #endif +#include <linux/ktime.h> +#include <linux/timekeeping.h> + /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <linux/mc146818rtc.h> @@ -220,6 +223,8 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr) /*----------------------------------------------------------------*/ +static void cmos_read_alarm_uip_debugging(struct device *dev); + static int cmos_read_time(struct device *dev, struct rtc_time *t) { /* @@ -234,6 +239,8 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t) * That'll make Y3K compatility (year > 2070) easy! */ mc146818_get_time(t); + + cmos_read_alarm_uip_debugging(dev); return 0; } @@ -348,6 +355,60 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } +static void cmos_read_alarm_uip_debugging(struct device *dev) +{ + unsigned long flags; + unsigned char rtc_uip_baseline, rtc_uip; + struct rtc_wkalrm t_baseline, t; + ktime_t time_start, time_end; + int i; + + spin_lock_irqsave(&rtc_lock, flags); + rtc_uip_baseline = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP; + spin_unlock_irqrestore(&rtc_lock, flags); + + cmos_read_alarm(dev, &t_baseline); + + time_start = ktime_get(); + + for (i = 0; i < 2000; i++) { + spin_lock_irqsave(&rtc_lock, flags); + rtc_uip = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP; + spin_unlock_irqrestore(&rtc_lock, flags); + + cmos_read_alarm(dev, &t); + + if (t_baseline.time.tm_sec != t.time.tm_sec) { + dev_err(dev, + "Inconsistent alarm tm_sec value: %d != %d (RTC_UIP = %d; %d)\n", + t_baseline.time.tm_sec, + t.time.tm_sec, + rtc_uip_baseline, rtc_uip); + } + if (t_baseline.time.tm_min != t.time.tm_min) { + dev_err(dev, + "Inconsistent alarm tm_min value: %d != %d (RTC_UIP = %d; %d)\n", + t_baseline.time.tm_min, + t.time.tm_min, + rtc_uip_baseline, rtc_uip); + } + if (t_baseline.time.tm_hour != t.time.tm_hour) { + dev_err(dev, + "Inconsistent alarm tm_hour value: %d != %d (RTC_UIP = %d; %d)\n", + t_baseline.time.tm_hour, + t.time.tm_hour, + rtc_uip_baseline, rtc_uip); + } + + } + + time_end = ktime_get(); + + pr_info_ratelimited("%s: loop executed in %lld ns\n", + __func__, ktime_to_ns(ktime_sub(time_end, time_start))); +} + + static void cmos_checkintr(struct cmos_rtc *cmos, unsigned char rtc_control) { unsigned char rtc_intr; -- 2.25.1