rtcpie.c 3.0 KB

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