Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Real Time Clock Driver Test Program
0004  *
0005  * Copyright (c) 2018 Alexandre Belloni <alexandre.belloni@bootlin.com>
0006  */
0007 
0008 #include <errno.h>
0009 #include <fcntl.h>
0010 #include <linux/rtc.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <sys/ioctl.h>
0014 #include <sys/time.h>
0015 #include <sys/types.h>
0016 #include <time.h>
0017 #include <unistd.h>
0018 
0019 #include "../kselftest_harness.h"
0020 
0021 #define NUM_UIE 3
0022 #define ALARM_DELTA 3
0023 #define READ_LOOP_DURATION_SEC 30
0024 #define READ_LOOP_SLEEP_MS 11
0025 
0026 static char *rtc_file = "/dev/rtc0";
0027 
0028 FIXTURE(rtc) {
0029     int fd;
0030 };
0031 
0032 FIXTURE_SETUP(rtc) {
0033     self->fd = open(rtc_file, O_RDONLY);
0034     ASSERT_NE(-1, self->fd);
0035 }
0036 
0037 FIXTURE_TEARDOWN(rtc) {
0038     close(self->fd);
0039 }
0040 
0041 TEST_F(rtc, date_read) {
0042     int rc;
0043     struct rtc_time rtc_tm;
0044 
0045     /* Read the RTC time/date */
0046     rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
0047     ASSERT_NE(-1, rc);
0048 
0049     TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
0050            rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
0051            rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
0052 }
0053 
0054 static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
0055 {
0056     struct tm tm_time = {
0057            .tm_sec = rtc_time->tm_sec,
0058            .tm_min = rtc_time->tm_min,
0059            .tm_hour = rtc_time->tm_hour,
0060            .tm_mday = rtc_time->tm_mday,
0061            .tm_mon = rtc_time->tm_mon,
0062            .tm_year = rtc_time->tm_year,
0063     };
0064 
0065     return mktime(&tm_time);
0066 }
0067 
0068 static void nanosleep_with_retries(long ns)
0069 {
0070     struct timespec req = {
0071         .tv_sec = 0,
0072         .tv_nsec = ns,
0073     };
0074     struct timespec rem;
0075 
0076     while (nanosleep(&req, &rem) != 0) {
0077         req.tv_sec = rem.tv_sec;
0078         req.tv_nsec = rem.tv_nsec;
0079     }
0080 }
0081 
0082 TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
0083     int rc;
0084     long iter_count = 0;
0085     struct rtc_time rtc_tm;
0086     time_t start_rtc_read, prev_rtc_read;
0087 
0088     TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
0089            READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
0090 
0091     rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
0092     ASSERT_NE(-1, rc);
0093     start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
0094     prev_rtc_read = start_rtc_read;
0095 
0096     do  {
0097         time_t rtc_read;
0098 
0099         rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
0100         ASSERT_NE(-1, rc);
0101 
0102         rtc_read = rtc_time_to_timestamp(&rtc_tm);
0103         /* Time should not go backwards */
0104         ASSERT_LE(prev_rtc_read, rtc_read);
0105         /* Time should not increase more then 1s at a time */
0106         ASSERT_GE(prev_rtc_read + 1, rtc_read);
0107 
0108         /* Sleep 11ms to avoid killing / overheating the RTC */
0109         nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
0110 
0111         prev_rtc_read = rtc_read;
0112         iter_count++;
0113     } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
0114 
0115     TH_LOG("Performed %ld RTC time reads.", iter_count);
0116 }
0117 
0118 TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
0119     int i, rc, irq = 0;
0120     unsigned long data;
0121 
0122     /* Turn on update interrupts */
0123     rc = ioctl(self->fd, RTC_UIE_ON, 0);
0124     if (rc == -1) {
0125         ASSERT_EQ(EINVAL, errno);
0126         TH_LOG("skip update IRQs not supported.");
0127         return;
0128     }
0129 
0130     for (i = 0; i < NUM_UIE; i++) {
0131         /* This read will block */
0132         rc = read(self->fd, &data, sizeof(data));
0133         ASSERT_NE(-1, rc);
0134         irq++;
0135     }
0136 
0137     EXPECT_EQ(NUM_UIE, irq);
0138 
0139     rc = ioctl(self->fd, RTC_UIE_OFF, 0);
0140     ASSERT_NE(-1, rc);
0141 }
0142 
0143 TEST_F(rtc, uie_select) {
0144     int i, rc, irq = 0;
0145     unsigned long data;
0146 
0147     /* Turn on update interrupts */
0148     rc = ioctl(self->fd, RTC_UIE_ON, 0);
0149     if (rc == -1) {
0150         ASSERT_EQ(EINVAL, errno);
0151         TH_LOG("skip update IRQs not supported.");
0152         return;
0153     }
0154 
0155     for (i = 0; i < NUM_UIE; i++) {
0156         struct timeval tv = { .tv_sec = 2 };
0157         fd_set readfds;
0158 
0159         FD_ZERO(&readfds);
0160         FD_SET(self->fd, &readfds);
0161         /* The select will wait until an RTC interrupt happens. */
0162         rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0163         ASSERT_NE(-1, rc);
0164         ASSERT_NE(0, rc);
0165 
0166         /* This read won't block */
0167         rc = read(self->fd, &data, sizeof(unsigned long));
0168         ASSERT_NE(-1, rc);
0169         irq++;
0170     }
0171 
0172     EXPECT_EQ(NUM_UIE, irq);
0173 
0174     rc = ioctl(self->fd, RTC_UIE_OFF, 0);
0175     ASSERT_NE(-1, rc);
0176 }
0177 
0178 TEST_F(rtc, alarm_alm_set) {
0179     struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
0180     unsigned long data;
0181     struct rtc_time tm;
0182     fd_set readfds;
0183     time_t secs, new;
0184     int rc;
0185 
0186     rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0187     ASSERT_NE(-1, rc);
0188 
0189     secs = timegm((struct tm *)&tm) + ALARM_DELTA;
0190     gmtime_r(&secs, (struct tm *)&tm);
0191 
0192     rc = ioctl(self->fd, RTC_ALM_SET, &tm);
0193     if (rc == -1) {
0194         ASSERT_EQ(EINVAL, errno);
0195         TH_LOG("skip alarms are not supported.");
0196         return;
0197     }
0198 
0199     rc = ioctl(self->fd, RTC_ALM_READ, &tm);
0200     ASSERT_NE(-1, rc);
0201 
0202     TH_LOG("Alarm time now set to %02d:%02d:%02d.",
0203            tm.tm_hour, tm.tm_min, tm.tm_sec);
0204 
0205     /* Enable alarm interrupts */
0206     rc = ioctl(self->fd, RTC_AIE_ON, 0);
0207     ASSERT_NE(-1, rc);
0208 
0209     FD_ZERO(&readfds);
0210     FD_SET(self->fd, &readfds);
0211 
0212     rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0213     ASSERT_NE(-1, rc);
0214     ASSERT_NE(0, rc);
0215 
0216     /* Disable alarm interrupts */
0217     rc = ioctl(self->fd, RTC_AIE_OFF, 0);
0218     ASSERT_NE(-1, rc);
0219 
0220     rc = read(self->fd, &data, sizeof(unsigned long));
0221     ASSERT_NE(-1, rc);
0222     TH_LOG("data: %lx", data);
0223 
0224     rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0225     ASSERT_NE(-1, rc);
0226 
0227     new = timegm((struct tm *)&tm);
0228     ASSERT_EQ(new, secs);
0229 }
0230 
0231 TEST_F(rtc, alarm_wkalm_set) {
0232     struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
0233     struct rtc_wkalrm alarm = { 0 };
0234     struct rtc_time tm;
0235     unsigned long data;
0236     fd_set readfds;
0237     time_t secs, new;
0238     int rc;
0239 
0240     rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
0241     ASSERT_NE(-1, rc);
0242 
0243     secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
0244     gmtime_r(&secs, (struct tm *)&alarm.time);
0245 
0246     alarm.enabled = 1;
0247 
0248     rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
0249     if (rc == -1) {
0250         ASSERT_EQ(EINVAL, errno);
0251         TH_LOG("skip alarms are not supported.");
0252         return;
0253     }
0254 
0255     rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
0256     ASSERT_NE(-1, rc);
0257 
0258     TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
0259            alarm.time.tm_mday, alarm.time.tm_mon + 1,
0260            alarm.time.tm_year + 1900, alarm.time.tm_hour,
0261            alarm.time.tm_min, alarm.time.tm_sec);
0262 
0263     FD_ZERO(&readfds);
0264     FD_SET(self->fd, &readfds);
0265 
0266     rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0267     ASSERT_NE(-1, rc);
0268     ASSERT_NE(0, rc);
0269 
0270     rc = read(self->fd, &data, sizeof(unsigned long));
0271     ASSERT_NE(-1, rc);
0272 
0273     rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0274     ASSERT_NE(-1, rc);
0275 
0276     new = timegm((struct tm *)&tm);
0277     ASSERT_EQ(new, secs);
0278 }
0279 
0280 TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
0281     struct timeval tv = { .tv_sec = 62 };
0282     unsigned long data;
0283     struct rtc_time tm;
0284     fd_set readfds;
0285     time_t secs, new;
0286     int rc;
0287 
0288     rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0289     ASSERT_NE(-1, rc);
0290 
0291     secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
0292     gmtime_r(&secs, (struct tm *)&tm);
0293 
0294     rc = ioctl(self->fd, RTC_ALM_SET, &tm);
0295     if (rc == -1) {
0296         ASSERT_EQ(EINVAL, errno);
0297         TH_LOG("skip alarms are not supported.");
0298         return;
0299     }
0300 
0301     rc = ioctl(self->fd, RTC_ALM_READ, &tm);
0302     ASSERT_NE(-1, rc);
0303 
0304     TH_LOG("Alarm time now set to %02d:%02d:%02d.",
0305            tm.tm_hour, tm.tm_min, tm.tm_sec);
0306 
0307     /* Enable alarm interrupts */
0308     rc = ioctl(self->fd, RTC_AIE_ON, 0);
0309     ASSERT_NE(-1, rc);
0310 
0311     FD_ZERO(&readfds);
0312     FD_SET(self->fd, &readfds);
0313 
0314     rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0315     ASSERT_NE(-1, rc);
0316     ASSERT_NE(0, rc);
0317 
0318     /* Disable alarm interrupts */
0319     rc = ioctl(self->fd, RTC_AIE_OFF, 0);
0320     ASSERT_NE(-1, rc);
0321 
0322     rc = read(self->fd, &data, sizeof(unsigned long));
0323     ASSERT_NE(-1, rc);
0324     TH_LOG("data: %lx", data);
0325 
0326     rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0327     ASSERT_NE(-1, rc);
0328 
0329     new = timegm((struct tm *)&tm);
0330     ASSERT_EQ(new, secs);
0331 }
0332 
0333 TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
0334     struct timeval tv = { .tv_sec = 62 };
0335     struct rtc_wkalrm alarm = { 0 };
0336     struct rtc_time tm;
0337     unsigned long data;
0338     fd_set readfds;
0339     time_t secs, new;
0340     int rc;
0341 
0342     rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
0343     ASSERT_NE(-1, rc);
0344 
0345     secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
0346     gmtime_r(&secs, (struct tm *)&alarm.time);
0347 
0348     alarm.enabled = 1;
0349 
0350     rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
0351     if (rc == -1) {
0352         ASSERT_EQ(EINVAL, errno);
0353         TH_LOG("skip alarms are not supported.");
0354         return;
0355     }
0356 
0357     rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
0358     ASSERT_NE(-1, rc);
0359 
0360     TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
0361            alarm.time.tm_mday, alarm.time.tm_mon + 1,
0362            alarm.time.tm_year + 1900, alarm.time.tm_hour,
0363            alarm.time.tm_min, alarm.time.tm_sec);
0364 
0365     FD_ZERO(&readfds);
0366     FD_SET(self->fd, &readfds);
0367 
0368     rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
0369     ASSERT_NE(-1, rc);
0370     ASSERT_NE(0, rc);
0371 
0372     rc = read(self->fd, &data, sizeof(unsigned long));
0373     ASSERT_NE(-1, rc);
0374 
0375     rc = ioctl(self->fd, RTC_RD_TIME, &tm);
0376     ASSERT_NE(-1, rc);
0377 
0378     new = timegm((struct tm *)&tm);
0379     ASSERT_EQ(new, secs);
0380 }
0381 
0382 static void __attribute__((constructor))
0383 __constructor_order_last(void)
0384 {
0385     if (!__constructor_order)
0386         __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
0387 }
0388 
0389 int main(int argc, char **argv)
0390 {
0391     switch (argc) {
0392     case 2:
0393         rtc_file = argv[1];
0394         /* FALLTHROUGH */
0395     case 1:
0396         break;
0397     default:
0398         fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
0399         return 1;
0400     }
0401 
0402     return test_harness_run(argc, argv);
0403 }