rtcpie.c 3.1 KB

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