xref: /linux/tools/testing/selftests/rtc/rtctest.c (revision 5916a6fbc0a5ccff977f56ca86af3d2750fb1cce)
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, &param);
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