root/tools/testing/selftests/timers/rtcpie.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. main

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Real Time Clock Periodic Interrupt test program
   4  *
   5  * Since commit 6610e0893b8bc ("RTC: Rework RTC code to use timerqueue for
   6  * events"), PIE are completely handled using hrtimers, without actually using
   7  * any underlying hardware RTC.
   8  *
   9  */
  10 
  11 #include <stdio.h>
  12 #include <linux/rtc.h>
  13 #include <sys/ioctl.h>
  14 #include <sys/time.h>
  15 #include <sys/types.h>
  16 #include <fcntl.h>
  17 #include <unistd.h>
  18 #include <stdlib.h>
  19 #include <errno.h>
  20 
  21 /*
  22  * This expects the new RTC class driver framework, working with
  23  * clocks that will often not be clones of what the PC-AT had.
  24  * Use the command line to specify another RTC if you need one.
  25  */
  26 static const char default_rtc[] = "/dev/rtc0";
  27 
  28 int main(int argc, char **argv)
  29 {
  30         int i, fd, retval, irqcount = 0;
  31         unsigned long tmp, data, old_pie_rate;
  32         const char *rtc = default_rtc;
  33         struct timeval start, end, diff;
  34 
  35         switch (argc) {
  36         case 2:
  37                 rtc = argv[1];
  38                 /* FALLTHROUGH */
  39         case 1:
  40                 break;
  41         default:
  42                 fprintf(stderr, "usage:  rtctest [rtcdev] [d]\n");
  43                 return 1;
  44         }
  45 
  46         fd = open(rtc, O_RDONLY);
  47 
  48         if (fd ==  -1) {
  49                 perror(rtc);
  50                 exit(errno);
  51         }
  52 
  53         /* Read periodic IRQ rate */
  54         retval = ioctl(fd, RTC_IRQP_READ, &old_pie_rate);
  55         if (retval == -1) {
  56                 /* not all RTCs support periodic IRQs */
  57                 if (errno == EINVAL) {
  58                         fprintf(stderr, "\nNo periodic IRQ support\n");
  59                         goto done;
  60                 }
  61                 perror("RTC_IRQP_READ ioctl");
  62                 exit(errno);
  63         }
  64         fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", old_pie_rate);
  65 
  66         fprintf(stderr, "Counting 20 interrupts at:");
  67         fflush(stderr);
  68 
  69         /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
  70         for (tmp=2; tmp<=64; tmp*=2) {
  71 
  72                 retval = ioctl(fd, RTC_IRQP_SET, tmp);
  73                 if (retval == -1) {
  74                         /* not all RTCs can change their periodic IRQ rate */
  75                         if (errno == EINVAL) {
  76                                 fprintf(stderr,
  77                                         "\n...Periodic IRQ rate is fixed\n");
  78                                 goto done;
  79                         }
  80                         perror("RTC_IRQP_SET ioctl");
  81                         exit(errno);
  82                 }
  83 
  84                 fprintf(stderr, "\n%ldHz:\t", tmp);
  85                 fflush(stderr);
  86 
  87                 /* Enable periodic interrupts */
  88                 retval = ioctl(fd, RTC_PIE_ON, 0);
  89                 if (retval == -1) {
  90                         perror("RTC_PIE_ON ioctl");
  91                         exit(errno);
  92                 }
  93 
  94                 for (i=1; i<21; i++) {
  95                         gettimeofday(&start, NULL);
  96                         /* This blocks */
  97                         retval = read(fd, &data, sizeof(unsigned long));
  98                         if (retval == -1) {
  99                                 perror("read");
 100                                 exit(errno);
 101                         }
 102                         gettimeofday(&end, NULL);
 103                         timersub(&end, &start, &diff);
 104                         if (diff.tv_sec > 0 ||
 105                             diff.tv_usec > ((1000000L / tmp) * 1.10)) {
 106                                 fprintf(stderr, "\nPIE delta error: %ld.%06ld should be close to 0.%06ld\n",
 107                                        diff.tv_sec, diff.tv_usec,
 108                                        (1000000L / tmp));
 109                                 fflush(stdout);
 110                                 exit(-1);
 111                         }
 112 
 113                         fprintf(stderr, " %d",i);
 114                         fflush(stderr);
 115                         irqcount++;
 116                 }
 117 
 118                 /* Disable periodic interrupts */
 119                 retval = ioctl(fd, RTC_PIE_OFF, 0);
 120                 if (retval == -1) {
 121                         perror("RTC_PIE_OFF ioctl");
 122                         exit(errno);
 123                 }
 124         }
 125 
 126 done:
 127         ioctl(fd, RTC_IRQP_SET, old_pie_rate);
 128 
 129         fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
 130 
 131         close(fd);
 132 
 133         return 0;
 134 }

/* [<][>][^][v][top][bottom][index][help] */