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

selftests/rtc: continuously read RTC in a loop for 30s

Some problems with reading the RTC time may happen rarely, for example
while the RTC is updating. So read the RTC many times to catch these
problems. For example, a previous attempt for my
commit ea6fa4961aab ("rtc: mc146818-lib: fix RTC presence check")
was incorrect and would have triggered this selftest.

To avoid the risk of damaging the hardware, wait 11ms before consecutive
reads.

In rtc_time_to_timestamp I copied values manually instead of casting -
just to be on the safe side. The 11ms wait period was chosen so that it is
not a divisor of 1000ms.

Signed-off-by: Mateusz Jończyk <mat.jonczyk@o2.pl>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Mateusz Jończyk and committed by
Shuah Khan
2aaa36e9 1900be28

+67 -1
+66
tools/testing/selftests/rtc/rtctest.c
··· 20 20 21 21 #define NUM_UIE 3 22 22 #define ALARM_DELTA 3 23 + #define READ_LOOP_DURATION_SEC 30 24 + #define READ_LOOP_SLEEP_MS 11 23 25 24 26 static char *rtc_file = "/dev/rtc0"; 25 27 ··· 49 47 TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.", 50 48 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, 51 49 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 50 + } 51 + 52 + static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time) 53 + { 54 + struct tm tm_time = { 55 + .tm_sec = rtc_time->tm_sec, 56 + .tm_min = rtc_time->tm_min, 57 + .tm_hour = rtc_time->tm_hour, 58 + .tm_mday = rtc_time->tm_mday, 59 + .tm_mon = rtc_time->tm_mon, 60 + .tm_year = rtc_time->tm_year, 61 + }; 62 + 63 + return mktime(&tm_time); 64 + } 65 + 66 + static void nanosleep_with_retries(long ns) 67 + { 68 + struct timespec req = { 69 + .tv_sec = 0, 70 + .tv_nsec = ns, 71 + }; 72 + struct timespec rem; 73 + 74 + while (nanosleep(&req, &rem) != 0) { 75 + req.tv_sec = rem.tv_sec; 76 + req.tv_nsec = rem.tv_nsec; 77 + } 78 + } 79 + 80 + TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) { 81 + int rc; 82 + long iter_count = 0; 83 + struct rtc_time rtc_tm; 84 + time_t start_rtc_read, prev_rtc_read; 85 + 86 + TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).", 87 + READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS); 88 + 89 + rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 90 + ASSERT_NE(-1, rc); 91 + start_rtc_read = rtc_time_to_timestamp(&rtc_tm); 92 + prev_rtc_read = start_rtc_read; 93 + 94 + do { 95 + time_t rtc_read; 96 + 97 + rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 98 + ASSERT_NE(-1, rc); 99 + 100 + rtc_read = rtc_time_to_timestamp(&rtc_tm); 101 + /* Time should not go backwards */ 102 + ASSERT_LE(prev_rtc_read, rtc_read); 103 + /* Time should not increase more then 1s at a time */ 104 + ASSERT_GE(prev_rtc_read + 1, rtc_read); 105 + 106 + /* Sleep 11ms to avoid killing / overheating the RTC */ 107 + nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000); 108 + 109 + prev_rtc_read = rtc_read; 110 + iter_count++; 111 + } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC); 112 + 113 + TH_LOG("Performed %ld RTC time reads.", iter_count); 52 114 } 53 115 54 116 TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
+1 -1
tools/testing/selftests/rtc/settings
··· 1 - timeout=180 1 + timeout=210