1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Real Time Clock Driver Test Program 4 * 5 * Copyright (c) 2018 Alexandre Belloni <alexandre.belloni@bootlin.com> 6 */ 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <linux/rtc.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <sys/ioctl.h> 14 #include <sys/time.h> 15 #include <sys/types.h> 16 #include <time.h> 17 #include <unistd.h> 18 19 #include "../kselftest_harness.h" 20 21 #define NUM_UIE 3 22 #define ALARM_DELTA 3 23 #define READ_LOOP_DURATION_SEC 30 24 #define READ_LOOP_SLEEP_MS 11 25 26 static char *rtc_file = "/dev/rtc0"; 27 28 FIXTURE(rtc) { 29 int fd; 30 }; 31 32 FIXTURE_SETUP(rtc) { 33 self->fd = open(rtc_file, O_RDONLY); 34 } 35 36 FIXTURE_TEARDOWN(rtc) { 37 close(self->fd); 38 } 39 40 TEST_F(rtc, date_read) { 41 int rc; 42 struct rtc_time rtc_tm; 43 44 if (self->fd == -1 && errno == ENOENT) 45 SKIP(return, "Skipping test since %s does not exist", rtc_file); 46 ASSERT_NE(-1, self->fd); 47 48 /* Read the RTC time/date */ 49 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 50 ASSERT_NE(-1, rc); 51 52 TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.", 53 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, 54 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 55 } 56 57 static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time) 58 { 59 struct tm tm_time = { 60 .tm_sec = rtc_time->tm_sec, 61 .tm_min = rtc_time->tm_min, 62 .tm_hour = rtc_time->tm_hour, 63 .tm_mday = rtc_time->tm_mday, 64 .tm_mon = rtc_time->tm_mon, 65 .tm_year = rtc_time->tm_year, 66 }; 67 68 return mktime(&tm_time); 69 } 70 71 static void nanosleep_with_retries(long ns) 72 { 73 struct timespec req = { 74 .tv_sec = 0, 75 .tv_nsec = ns, 76 }; 77 struct timespec rem; 78 79 while (nanosleep(&req, &rem) != 0) { 80 req.tv_sec = rem.tv_sec; 81 req.tv_nsec = rem.tv_nsec; 82 } 83 } 84 85 TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) { 86 int rc; 87 long iter_count = 0; 88 struct rtc_time rtc_tm; 89 time_t start_rtc_read, prev_rtc_read; 90 91 if (self->fd == -1 && errno == ENOENT) 92 SKIP(return, "Skipping test since %s does not exist", rtc_file); 93 ASSERT_NE(-1, self->fd); 94 95 TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).", 96 READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS); 97 98 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 99 ASSERT_NE(-1, rc); 100 start_rtc_read = rtc_time_to_timestamp(&rtc_tm); 101 prev_rtc_read = start_rtc_read; 102 103 do { 104 time_t rtc_read; 105 106 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm); 107 ASSERT_NE(-1, rc); 108 109 rtc_read = rtc_time_to_timestamp(&rtc_tm); 110 /* Time should not go backwards */ 111 ASSERT_LE(prev_rtc_read, rtc_read); 112 /* Time should not increase more then 1s at a time */ 113 ASSERT_GE(prev_rtc_read + 1, rtc_read); 114 115 /* Sleep 11ms to avoid killing / overheating the RTC */ 116 nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000); 117 118 prev_rtc_read = rtc_read; 119 iter_count++; 120 } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC); 121 122 TH_LOG("Performed %ld RTC time reads.", iter_count); 123 } 124 125 TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) { 126 int i, rc, irq = 0; 127 unsigned long data; 128 129 if (self->fd == -1 && errno == ENOENT) 130 SKIP(return, "Skipping test since %s does not exist", rtc_file); 131 ASSERT_NE(-1, self->fd); 132 133 /* Turn on update interrupts */ 134 rc = ioctl(self->fd, RTC_UIE_ON, 0); 135 if (rc == -1) { 136 ASSERT_EQ(EINVAL, errno); 137 TH_LOG("skip update IRQs not supported."); 138 return; 139 } 140 141 for (i = 0; i < NUM_UIE; i++) { 142 /* This read will block */ 143 rc = read(self->fd, &data, sizeof(data)); 144 ASSERT_NE(-1, rc); 145 irq++; 146 } 147 148 EXPECT_EQ(NUM_UIE, irq); 149 150 rc = ioctl(self->fd, RTC_UIE_OFF, 0); 151 ASSERT_NE(-1, rc); 152 } 153 154 TEST_F(rtc, uie_select) { 155 int i, rc, irq = 0; 156 unsigned long data; 157 158 if (self->fd == -1 && errno == ENOENT) 159 SKIP(return, "Skipping test since %s does not exist", rtc_file); 160 ASSERT_NE(-1, self->fd); 161 162 /* Turn on update interrupts */ 163 rc = ioctl(self->fd, RTC_UIE_ON, 0); 164 if (rc == -1) { 165 ASSERT_EQ(EINVAL, errno); 166 TH_LOG("skip update IRQs not supported."); 167 return; 168 } 169 170 for (i = 0; i < NUM_UIE; i++) { 171 struct timeval tv = { .tv_sec = 2 }; 172 fd_set readfds; 173 174 FD_ZERO(&readfds); 175 FD_SET(self->fd, &readfds); 176 /* The select will wait until an RTC interrupt happens. */ 177 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 178 ASSERT_NE(-1, rc); 179 ASSERT_NE(0, rc); 180 181 /* This read won't block */ 182 rc = read(self->fd, &data, sizeof(unsigned long)); 183 ASSERT_NE(-1, rc); 184 irq++; 185 } 186 187 EXPECT_EQ(NUM_UIE, irq); 188 189 rc = ioctl(self->fd, RTC_UIE_OFF, 0); 190 ASSERT_NE(-1, rc); 191 } 192 193 TEST_F(rtc, alarm_alm_set) { 194 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 }; 195 unsigned long data; 196 struct rtc_time tm; 197 fd_set readfds; 198 time_t secs, new; 199 int rc; 200 201 if (self->fd == -1 && errno == ENOENT) 202 SKIP(return, "Skipping test since %s does not exist", rtc_file); 203 ASSERT_NE(-1, self->fd); 204 205 rc = ioctl(self->fd, RTC_RD_TIME, &tm); 206 ASSERT_NE(-1, rc); 207 208 secs = timegm((struct tm *)&tm) + ALARM_DELTA; 209 gmtime_r(&secs, (struct tm *)&tm); 210 211 rc = ioctl(self->fd, RTC_ALM_SET, &tm); 212 if (rc == -1) { 213 ASSERT_EQ(EINVAL, errno); 214 TH_LOG("skip alarms are not supported."); 215 return; 216 } 217 218 rc = ioctl(self->fd, RTC_ALM_READ, &tm); 219 ASSERT_NE(-1, rc); 220 221 TH_LOG("Alarm time now set to %02d:%02d:%02d.", 222 tm.tm_hour, tm.tm_min, tm.tm_sec); 223 224 /* Enable alarm interrupts */ 225 rc = ioctl(self->fd, RTC_AIE_ON, 0); 226 ASSERT_NE(-1, rc); 227 228 FD_ZERO(&readfds); 229 FD_SET(self->fd, &readfds); 230 231 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 232 ASSERT_NE(-1, rc); 233 ASSERT_NE(0, rc); 234 235 /* Disable alarm interrupts */ 236 rc = ioctl(self->fd, RTC_AIE_OFF, 0); 237 ASSERT_NE(-1, rc); 238 239 rc = read(self->fd, &data, sizeof(unsigned long)); 240 ASSERT_NE(-1, rc); 241 TH_LOG("data: %lx", data); 242 243 rc = ioctl(self->fd, RTC_RD_TIME, &tm); 244 ASSERT_NE(-1, rc); 245 246 new = timegm((struct tm *)&tm); 247 ASSERT_EQ(new, secs); 248 } 249 250 TEST_F(rtc, alarm_wkalm_set) { 251 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 }; 252 struct rtc_wkalrm alarm = { 0 }; 253 struct rtc_time tm; 254 unsigned long data; 255 fd_set readfds; 256 time_t secs, new; 257 int rc; 258 259 if (self->fd == -1 && errno == ENOENT) 260 SKIP(return, "Skipping test since %s does not exist", rtc_file); 261 ASSERT_NE(-1, self->fd); 262 263 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time); 264 ASSERT_NE(-1, rc); 265 266 secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA; 267 gmtime_r(&secs, (struct tm *)&alarm.time); 268 269 alarm.enabled = 1; 270 271 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm); 272 if (rc == -1) { 273 ASSERT_EQ(EINVAL, errno); 274 TH_LOG("skip alarms are not supported."); 275 return; 276 } 277 278 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm); 279 ASSERT_NE(-1, rc); 280 281 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.", 282 alarm.time.tm_mday, alarm.time.tm_mon + 1, 283 alarm.time.tm_year + 1900, alarm.time.tm_hour, 284 alarm.time.tm_min, alarm.time.tm_sec); 285 286 FD_ZERO(&readfds); 287 FD_SET(self->fd, &readfds); 288 289 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 290 ASSERT_NE(-1, rc); 291 ASSERT_NE(0, rc); 292 293 rc = read(self->fd, &data, sizeof(unsigned long)); 294 ASSERT_NE(-1, rc); 295 296 rc = ioctl(self->fd, RTC_RD_TIME, &tm); 297 ASSERT_NE(-1, rc); 298 299 new = timegm((struct tm *)&tm); 300 ASSERT_EQ(new, secs); 301 } 302 303 TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) { 304 struct timeval tv = { .tv_sec = 62 }; 305 unsigned long data; 306 struct rtc_time tm; 307 fd_set readfds; 308 time_t secs, new; 309 int rc; 310 311 if (self->fd == -1 && errno == ENOENT) 312 SKIP(return, "Skipping test since %s does not exist", rtc_file); 313 ASSERT_NE(-1, self->fd); 314 315 rc = ioctl(self->fd, RTC_RD_TIME, &tm); 316 ASSERT_NE(-1, rc); 317 318 secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec; 319 gmtime_r(&secs, (struct tm *)&tm); 320 321 rc = ioctl(self->fd, RTC_ALM_SET, &tm); 322 if (rc == -1) { 323 ASSERT_EQ(EINVAL, errno); 324 TH_LOG("skip alarms are not supported."); 325 return; 326 } 327 328 rc = ioctl(self->fd, RTC_ALM_READ, &tm); 329 ASSERT_NE(-1, rc); 330 331 TH_LOG("Alarm time now set to %02d:%02d:%02d.", 332 tm.tm_hour, tm.tm_min, tm.tm_sec); 333 334 /* Enable alarm interrupts */ 335 rc = ioctl(self->fd, RTC_AIE_ON, 0); 336 ASSERT_NE(-1, rc); 337 338 FD_ZERO(&readfds); 339 FD_SET(self->fd, &readfds); 340 341 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 342 ASSERT_NE(-1, rc); 343 ASSERT_NE(0, rc); 344 345 /* Disable alarm interrupts */ 346 rc = ioctl(self->fd, RTC_AIE_OFF, 0); 347 ASSERT_NE(-1, rc); 348 349 rc = read(self->fd, &data, sizeof(unsigned long)); 350 ASSERT_NE(-1, rc); 351 TH_LOG("data: %lx", data); 352 353 rc = ioctl(self->fd, RTC_RD_TIME, &tm); 354 ASSERT_NE(-1, rc); 355 356 new = timegm((struct tm *)&tm); 357 ASSERT_EQ(new, secs); 358 } 359 360 TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) { 361 struct timeval tv = { .tv_sec = 62 }; 362 struct rtc_wkalrm alarm = { 0 }; 363 struct rtc_time tm; 364 unsigned long data; 365 fd_set readfds; 366 time_t secs, new; 367 int rc; 368 369 if (self->fd == -1 && errno == ENOENT) 370 SKIP(return, "Skipping test since %s does not exist", rtc_file); 371 ASSERT_NE(-1, self->fd); 372 373 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time); 374 ASSERT_NE(-1, rc); 375 376 secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec; 377 gmtime_r(&secs, (struct tm *)&alarm.time); 378 379 alarm.enabled = 1; 380 381 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm); 382 if (rc == -1) { 383 ASSERT_EQ(EINVAL, errno); 384 TH_LOG("skip alarms are not supported."); 385 return; 386 } 387 388 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm); 389 ASSERT_NE(-1, rc); 390 391 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.", 392 alarm.time.tm_mday, alarm.time.tm_mon + 1, 393 alarm.time.tm_year + 1900, alarm.time.tm_hour, 394 alarm.time.tm_min, alarm.time.tm_sec); 395 396 FD_ZERO(&readfds); 397 FD_SET(self->fd, &readfds); 398 399 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); 400 ASSERT_NE(-1, rc); 401 ASSERT_NE(0, rc); 402 403 rc = read(self->fd, &data, sizeof(unsigned long)); 404 ASSERT_NE(-1, rc); 405 406 rc = ioctl(self->fd, RTC_RD_TIME, &tm); 407 ASSERT_NE(-1, rc); 408 409 new = timegm((struct tm *)&tm); 410 ASSERT_EQ(new, secs); 411 } 412 413 static void __attribute__((constructor)) 414 __constructor_order_last(void) 415 { 416 if (!__constructor_order) 417 __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD; 418 } 419 420 int main(int argc, char **argv) 421 { 422 switch (argc) { 423 case 2: 424 rtc_file = argv[1]; 425 /* FALLTHROUGH */ 426 case 1: 427 break; 428 default: 429 fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]); 430 return 1; 431 } 432 433 return test_harness_run(argc, argv); 434 } 435