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 enum rtc_alarm_state {
29 RTC_ALARM_UNKNOWN,
30 RTC_ALARM_ENABLED,
31 RTC_ALARM_DISABLED,
32 RTC_ALARM_RES_MINUTE,
33 };
34
FIXTURE(rtc)35 FIXTURE(rtc) {
36 int fd;
37 };
38
FIXTURE_SETUP(rtc)39 FIXTURE_SETUP(rtc) {
40 self->fd = open(rtc_file, O_RDONLY);
41 }
42
FIXTURE_TEARDOWN(rtc)43 FIXTURE_TEARDOWN(rtc) {
44 close(self->fd);
45 }
46
TEST_F(rtc,date_read)47 TEST_F(rtc, date_read) {
48 int rc;
49 struct rtc_time rtc_tm;
50
51 if (self->fd == -1 && errno == ENOENT)
52 SKIP(return, "Skipping test since %s does not exist", rtc_file);
53 ASSERT_NE(-1, self->fd);
54
55 /* Read the RTC time/date */
56 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
57 ASSERT_NE(-1, rc);
58
59 TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
60 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
61 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
62 }
63
rtc_time_to_timestamp(struct rtc_time * rtc_time)64 static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
65 {
66 struct tm tm_time = {
67 .tm_sec = rtc_time->tm_sec,
68 .tm_min = rtc_time->tm_min,
69 .tm_hour = rtc_time->tm_hour,
70 .tm_mday = rtc_time->tm_mday,
71 .tm_mon = rtc_time->tm_mon,
72 .tm_year = rtc_time->tm_year,
73 };
74
75 return mktime(&tm_time);
76 }
77
nanosleep_with_retries(long ns)78 static void nanosleep_with_retries(long ns)
79 {
80 struct timespec req = {
81 .tv_sec = 0,
82 .tv_nsec = ns,
83 };
84 struct timespec rem;
85
86 while (nanosleep(&req, &rem) != 0) {
87 req.tv_sec = rem.tv_sec;
88 req.tv_nsec = rem.tv_nsec;
89 }
90 }
91
get_rtc_alarm_state(int fd,int need_seconds)92 static enum rtc_alarm_state get_rtc_alarm_state(int fd, int need_seconds)
93 {
94 struct rtc_param param = { 0 };
95 int rc;
96
97 /* Validate kernel reflects unsupported RTC alarm state */
98 param.param = RTC_PARAM_FEATURES;
99 param.index = 0;
100 rc = ioctl(fd, RTC_PARAM_GET, ¶m);
101 if (rc < 0)
102 return RTC_ALARM_UNKNOWN;
103
104 if ((param.uvalue & _BITUL(RTC_FEATURE_ALARM)) == 0)
105 return RTC_ALARM_DISABLED;
106
107 /* Check if alarm has desired granularity */
108 if (need_seconds && (param.uvalue & _BITUL(RTC_FEATURE_ALARM_RES_MINUTE)))
109 return RTC_ALARM_RES_MINUTE;
110
111 return RTC_ALARM_ENABLED;
112 }
113
114 TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
115 int rc;
116 long iter_count = 0;
117 struct rtc_time rtc_tm;
118 time_t start_rtc_read, prev_rtc_read;
119
120 if (self->fd == -1 && errno == ENOENT)
121 SKIP(return, "Skipping test since %s does not exist", rtc_file);
122 ASSERT_NE(-1, self->fd);
123
124 TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
125 READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
126
127 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
128 ASSERT_NE(-1, rc);
129 start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
130 prev_rtc_read = start_rtc_read;
131
132 do {
133 time_t rtc_read;
134
135 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
136 ASSERT_NE(-1, rc);
137
138 rtc_read = rtc_time_to_timestamp(&rtc_tm);
139 /* Time should not go backwards */
140 ASSERT_LE(prev_rtc_read, rtc_read);
141 /* Time should not increase more then 1s at a time */
142 ASSERT_GE(prev_rtc_read + 1, rtc_read);
143
144 /* Sleep 11ms to avoid killing / overheating the RTC */
145 nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
146
147 prev_rtc_read = rtc_read;
148 iter_count++;
149 } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
150
151 TH_LOG("Performed %ld RTC time reads.", iter_count);
152 }
153
154 TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
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 /* This read will block */
172 rc = read(self->fd, &data, sizeof(data));
173 ASSERT_NE(-1, rc);
174 irq++;
175 }
176
177 EXPECT_EQ(NUM_UIE, irq);
178
179 rc = ioctl(self->fd, RTC_UIE_OFF, 0);
180 ASSERT_NE(-1, rc);
181 }
182
TEST_F(rtc,uie_select)183 TEST_F(rtc, uie_select) {
184 int i, rc, irq = 0;
185 unsigned long data;
186
187 if (self->fd == -1 && errno == ENOENT)
188 SKIP(return, "Skipping test since %s does not exist", rtc_file);
189 ASSERT_NE(-1, self->fd);
190
191 /* Turn on update interrupts */
192 rc = ioctl(self->fd, RTC_UIE_ON, 0);
193 if (rc == -1) {
194 ASSERT_EQ(EINVAL, errno);
195 TH_LOG("skip update IRQs not supported.");
196 return;
197 }
198
199 for (i = 0; i < NUM_UIE; i++) {
200 struct timeval tv = { .tv_sec = 2 };
201 fd_set readfds;
202
203 FD_ZERO(&readfds);
204 FD_SET(self->fd, &readfds);
205 /* The select will wait until an RTC interrupt happens. */
206 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
207 ASSERT_NE(-1, rc);
208 ASSERT_NE(0, rc);
209
210 /* This read won't block */
211 rc = read(self->fd, &data, sizeof(unsigned long));
212 ASSERT_NE(-1, rc);
213 irq++;
214 }
215
216 EXPECT_EQ(NUM_UIE, irq);
217
218 rc = ioctl(self->fd, RTC_UIE_OFF, 0);
219 ASSERT_NE(-1, rc);
220 }
221
TEST_F(rtc,alarm_alm_set)222 TEST_F(rtc, alarm_alm_set) {
223 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
224 unsigned long data;
225 struct rtc_time tm;
226 fd_set readfds;
227 time_t secs, new;
228 int rc;
229 enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
230
231 if (self->fd == -1 && errno == ENOENT)
232 SKIP(return, "Skipping test since %s does not exist", rtc_file);
233 ASSERT_NE(-1, self->fd);
234
235 alarm_state = get_rtc_alarm_state(self->fd, 1);
236 if (alarm_state == RTC_ALARM_DISABLED)
237 SKIP(return, "Skipping test since alarms are not supported.");
238 if (alarm_state == RTC_ALARM_RES_MINUTE)
239 SKIP(return, "Skipping test since alarms has only minute granularity.");
240
241 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
242 ASSERT_NE(-1, rc);
243
244 secs = timegm((struct tm *)&tm) + ALARM_DELTA;
245 gmtime_r(&secs, (struct tm *)&tm);
246
247 rc = ioctl(self->fd, RTC_ALM_SET, &tm);
248 if (rc == -1) {
249 /*
250 * Report error if rtc alarm was enabled. Fallback to check ioctl
251 * error number if rtc alarm state is unknown.
252 */
253 ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
254 ASSERT_EQ(EINVAL, errno);
255 TH_LOG("skip alarms are not supported.");
256 return;
257 }
258
259 rc = ioctl(self->fd, RTC_ALM_READ, &tm);
260 ASSERT_NE(-1, rc);
261
262 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
263 tm.tm_hour, tm.tm_min, tm.tm_sec);
264
265 /* Enable alarm interrupts */
266 rc = ioctl(self->fd, RTC_AIE_ON, 0);
267 ASSERT_NE(-1, rc);
268
269 FD_ZERO(&readfds);
270 FD_SET(self->fd, &readfds);
271
272 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
273 ASSERT_NE(-1, rc);
274 ASSERT_NE(0, rc);
275
276 /* Disable alarm interrupts */
277 rc = ioctl(self->fd, RTC_AIE_OFF, 0);
278 ASSERT_NE(-1, rc);
279
280 rc = read(self->fd, &data, sizeof(unsigned long));
281 ASSERT_NE(-1, rc);
282 TH_LOG("data: %lx", data);
283
284 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
285 ASSERT_NE(-1, rc);
286
287 new = timegm((struct tm *)&tm);
288 ASSERT_EQ(new, secs);
289 }
290
TEST_F(rtc,alarm_wkalm_set)291 TEST_F(rtc, alarm_wkalm_set) {
292 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
293 struct rtc_wkalrm alarm = { 0 };
294 struct rtc_time tm;
295 unsigned long data;
296 fd_set readfds;
297 time_t secs, new;
298 int rc;
299 enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
300
301 if (self->fd == -1 && errno == ENOENT)
302 SKIP(return, "Skipping test since %s does not exist", rtc_file);
303 ASSERT_NE(-1, self->fd);
304
305 alarm_state = get_rtc_alarm_state(self->fd, 1);
306 if (alarm_state == RTC_ALARM_DISABLED)
307 SKIP(return, "Skipping test since alarms are not supported.");
308 if (alarm_state == RTC_ALARM_RES_MINUTE)
309 SKIP(return, "Skipping test since alarms has only minute granularity.");
310
311 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
312 ASSERT_NE(-1, rc);
313
314 secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
315 gmtime_r(&secs, (struct tm *)&alarm.time);
316
317 alarm.enabled = 1;
318
319 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
320 if (rc == -1) {
321 /*
322 * Report error if rtc alarm was enabled. Fallback to check ioctl
323 * error number if rtc alarm state is unknown.
324 */
325 ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
326 ASSERT_EQ(EINVAL, errno);
327 TH_LOG("skip alarms are not supported.");
328 return;
329 }
330
331 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
332 ASSERT_NE(-1, rc);
333
334 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
335 alarm.time.tm_mday, alarm.time.tm_mon + 1,
336 alarm.time.tm_year + 1900, alarm.time.tm_hour,
337 alarm.time.tm_min, alarm.time.tm_sec);
338
339 FD_ZERO(&readfds);
340 FD_SET(self->fd, &readfds);
341
342 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
343 ASSERT_NE(-1, rc);
344 ASSERT_NE(0, rc);
345
346 rc = read(self->fd, &data, sizeof(unsigned long));
347 ASSERT_NE(-1, rc);
348
349 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
350 ASSERT_NE(-1, rc);
351
352 new = timegm((struct tm *)&tm);
353 ASSERT_EQ(new, secs);
354 }
355
356 TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
357 struct timeval tv = { .tv_sec = 62 };
358 unsigned long data;
359 struct rtc_time tm;
360 fd_set readfds;
361 time_t secs, new;
362 int rc;
363 enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
364
365 if (self->fd == -1 && errno == ENOENT)
366 SKIP(return, "Skipping test since %s does not exist", rtc_file);
367 ASSERT_NE(-1, self->fd);
368
369 alarm_state = get_rtc_alarm_state(self->fd, 0);
370 if (alarm_state == RTC_ALARM_DISABLED)
371 SKIP(return, "Skipping test since alarms are not supported.");
372
373 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
374 ASSERT_NE(-1, rc);
375
376 secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
377 gmtime_r(&secs, (struct tm *)&tm);
378
379 rc = ioctl(self->fd, RTC_ALM_SET, &tm);
380 if (rc == -1) {
381 /*
382 * Report error if rtc alarm was enabled. Fallback to check ioctl
383 * error number if rtc alarm state is unknown.
384 */
385 ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
386 ASSERT_EQ(EINVAL, errno);
387 TH_LOG("skip alarms are not supported.");
388 return;
389 }
390
391 rc = ioctl(self->fd, RTC_ALM_READ, &tm);
392 ASSERT_NE(-1, rc);
393
394 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
395 tm.tm_hour, tm.tm_min, tm.tm_sec);
396
397 /* Enable alarm interrupts */
398 rc = ioctl(self->fd, RTC_AIE_ON, 0);
399 ASSERT_NE(-1, rc);
400
401 FD_ZERO(&readfds);
402 FD_SET(self->fd, &readfds);
403
404 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
405 ASSERT_NE(-1, rc);
406 ASSERT_NE(0, rc);
407
408 /* Disable alarm interrupts */
409 rc = ioctl(self->fd, RTC_AIE_OFF, 0);
410 ASSERT_NE(-1, rc);
411
412 rc = read(self->fd, &data, sizeof(unsigned long));
413 ASSERT_NE(-1, rc);
414 TH_LOG("data: %lx", data);
415
416 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
417 ASSERT_NE(-1, rc);
418
419 new = timegm((struct tm *)&tm);
420 ASSERT_EQ(new, secs);
421 }
422
423 TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
424 struct timeval tv = { .tv_sec = 62 };
425 struct rtc_wkalrm alarm = { 0 };
426 struct rtc_time tm;
427 unsigned long data;
428 fd_set readfds;
429 time_t secs, new;
430 int rc;
431 enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
432
433 if (self->fd == -1 && errno == ENOENT)
434 SKIP(return, "Skipping test since %s does not exist", rtc_file);
435 ASSERT_NE(-1, self->fd);
436
437 alarm_state = get_rtc_alarm_state(self->fd, 0);
438 if (alarm_state == RTC_ALARM_DISABLED)
439 SKIP(return, "Skipping test since alarms are not supported.");
440
441 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
442 ASSERT_NE(-1, rc);
443
444 secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
445 gmtime_r(&secs, (struct tm *)&alarm.time);
446
447 alarm.enabled = 1;
448
449 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
450 if (rc == -1) {
451 /*
452 * Report error if rtc alarm was enabled. Fallback to check ioctl
453 * error number if rtc alarm state is unknown.
454 */
455 ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
456 ASSERT_EQ(EINVAL, errno);
457 TH_LOG("skip alarms are not supported.");
458 return;
459 }
460
461 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
462 ASSERT_NE(-1, rc);
463
464 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
465 alarm.time.tm_mday, alarm.time.tm_mon + 1,
466 alarm.time.tm_year + 1900, alarm.time.tm_hour,
467 alarm.time.tm_min, alarm.time.tm_sec);
468
469 FD_ZERO(&readfds);
470 FD_SET(self->fd, &readfds);
471
472 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
473 ASSERT_NE(-1, rc);
474 ASSERT_NE(0, rc);
475
476 rc = read(self->fd, &data, sizeof(unsigned long));
477 ASSERT_NE(-1, rc);
478
479 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
480 ASSERT_NE(-1, rc);
481
482 new = timegm((struct tm *)&tm);
483 ASSERT_EQ(new, secs);
484 }
485
main(int argc,char ** argv)486 int main(int argc, char **argv)
487 {
488 int ret = -1;
489
490 switch (argc) {
491 case 2:
492 rtc_file = argv[1];
493 /* FALLTHROUGH */
494 case 1:
495 break;
496 default:
497 fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
498 return 1;
499 }
500
501 /* Run the test if rtc_file is accessible */
502 if (access(rtc_file, R_OK) == 0)
503 ret = test_harness_run(argc, argv);
504 else
505 ksft_exit_skip("[SKIP]: Cannot access rtc file %s - Exiting\n",
506 rtc_file);
507
508 return ret;
509 }
510