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