Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Real Time Clock Periodic Interrupt test program
0004  *
0005  * Since commit 6610e0893b8bc ("RTC: Rework RTC code to use timerqueue for
0006  * events"), PIE are completely handled using hrtimers, without actually using
0007  * any underlying hardware RTC.
0008  *
0009  */
0010 
0011 #include <stdio.h>
0012 #include <linux/rtc.h>
0013 #include <sys/ioctl.h>
0014 #include <sys/time.h>
0015 #include <sys/types.h>
0016 #include <fcntl.h>
0017 #include <unistd.h>
0018 #include <stdlib.h>
0019 #include <errno.h>
0020 
0021 #include "../kselftest.h"
0022 
0023 /*
0024  * This expects the new RTC class driver framework, working with
0025  * clocks that will often not be clones of what the PC-AT had.
0026  * Use the command line to specify another RTC if you need one.
0027  */
0028 static const char default_rtc[] = "/dev/rtc0";
0029 
0030 int main(int argc, char **argv)
0031 {
0032     int i, fd, retval, irqcount = 0;
0033     unsigned long tmp, data, old_pie_rate;
0034     const char *rtc = default_rtc;
0035     struct timeval start, end, diff;
0036 
0037     switch (argc) {
0038     case 2:
0039         rtc = argv[1];
0040         break;
0041     case 1:
0042         fd = open(default_rtc, O_RDONLY);
0043         if (fd == -1) {
0044             printf("Default RTC %s does not exist. Test Skipped!\n", default_rtc);
0045             exit(KSFT_SKIP);
0046         }
0047         close(fd);
0048         break;
0049     default:
0050         fprintf(stderr, "usage:  rtctest [rtcdev] [d]\n");
0051         return 1;
0052     }
0053 
0054     fd = open(rtc, O_RDONLY);
0055 
0056     if (fd ==  -1) {
0057         perror(rtc);
0058         exit(errno);
0059     }
0060 
0061     /* Read periodic IRQ rate */
0062     retval = ioctl(fd, RTC_IRQP_READ, &old_pie_rate);
0063     if (retval == -1) {
0064         /* not all RTCs support periodic IRQs */
0065         if (errno == EINVAL) {
0066             fprintf(stderr, "\nNo periodic IRQ support\n");
0067             goto done;
0068         }
0069         perror("RTC_IRQP_READ ioctl");
0070         exit(errno);
0071     }
0072     fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", old_pie_rate);
0073 
0074     fprintf(stderr, "Counting 20 interrupts at:");
0075     fflush(stderr);
0076 
0077     /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
0078     for (tmp=2; tmp<=64; tmp*=2) {
0079 
0080         retval = ioctl(fd, RTC_IRQP_SET, tmp);
0081         if (retval == -1) {
0082             /* not all RTCs can change their periodic IRQ rate */
0083             if (errno == EINVAL) {
0084                 fprintf(stderr,
0085                     "\n...Periodic IRQ rate is fixed\n");
0086                 goto done;
0087             }
0088             perror("RTC_IRQP_SET ioctl");
0089             exit(errno);
0090         }
0091 
0092         fprintf(stderr, "\n%ldHz:\t", tmp);
0093         fflush(stderr);
0094 
0095         /* Enable periodic interrupts */
0096         retval = ioctl(fd, RTC_PIE_ON, 0);
0097         if (retval == -1) {
0098             perror("RTC_PIE_ON ioctl");
0099             exit(errno);
0100         }
0101 
0102         for (i=1; i<21; i++) {
0103             gettimeofday(&start, NULL);
0104             /* This blocks */
0105             retval = read(fd, &data, sizeof(unsigned long));
0106             if (retval == -1) {
0107                 perror("read");
0108                 exit(errno);
0109             }
0110             gettimeofday(&end, NULL);
0111             timersub(&end, &start, &diff);
0112             if (diff.tv_sec > 0 ||
0113                 diff.tv_usec > ((1000000L / tmp) * 1.10)) {
0114                 fprintf(stderr, "\nPIE delta error: %ld.%06ld should be close to 0.%06ld\n",
0115                        diff.tv_sec, diff.tv_usec,
0116                        (1000000L / tmp));
0117                 fflush(stdout);
0118                 exit(-1);
0119             }
0120 
0121             fprintf(stderr, " %d",i);
0122             fflush(stderr);
0123             irqcount++;
0124         }
0125 
0126         /* Disable periodic interrupts */
0127         retval = ioctl(fd, RTC_PIE_OFF, 0);
0128         if (retval == -1) {
0129             perror("RTC_PIE_OFF ioctl");
0130             exit(errno);
0131         }
0132     }
0133 
0134 done:
0135     ioctl(fd, RTC_IRQP_SET, old_pie_rate);
0136 
0137     fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
0138 
0139     close(fd);
0140 
0141     return 0;
0142 }