diff options
Diffstat (limited to 'tools/testing/selftests/timers/rtcpie.c')
-rw-r--r-- | tools/testing/selftests/timers/rtcpie.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/tools/testing/selftests/timers/rtcpie.c b/tools/testing/selftests/timers/rtcpie.c new file mode 100644 index 000000000000..47b5bad1b393 --- /dev/null +++ b/tools/testing/selftests/timers/rtcpie.c | |||
@@ -0,0 +1,134 @@ | |||
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 | } | ||