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