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