clocksource-wdtest.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Unit test for the clocksource watchdog.
  4. *
  5. * Copyright (C) 2021 Facebook, Inc.
  6. *
  7. * Author: Paul E. McKenney <[email protected]>
  8. */
  9. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10. #include <linux/device.h>
  11. #include <linux/clocksource.h>
  12. #include <linux/init.h>
  13. #include <linux/module.h>
  14. #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
  15. #include <linux/tick.h>
  16. #include <linux/kthread.h>
  17. #include <linux/delay.h>
  18. #include <linux/prandom.h>
  19. #include <linux/cpu.h>
  20. #include "tick-internal.h"
  21. MODULE_LICENSE("GPL");
  22. MODULE_AUTHOR("Paul E. McKenney <[email protected]>");
  23. static int holdoff = IS_BUILTIN(CONFIG_TEST_CLOCKSOURCE_WATCHDOG) ? 10 : 0;
  24. module_param(holdoff, int, 0444);
  25. MODULE_PARM_DESC(holdoff, "Time to wait to start test (s).");
  26. /* Watchdog kthread's task_struct pointer for debug purposes. */
  27. static struct task_struct *wdtest_task;
  28. static u64 wdtest_jiffies_read(struct clocksource *cs)
  29. {
  30. return (u64)jiffies;
  31. }
  32. static struct clocksource clocksource_wdtest_jiffies = {
  33. .name = "wdtest-jiffies",
  34. .rating = 1, /* lowest valid rating*/
  35. .uncertainty_margin = TICK_NSEC,
  36. .read = wdtest_jiffies_read,
  37. .mask = CLOCKSOURCE_MASK(32),
  38. .flags = CLOCK_SOURCE_MUST_VERIFY,
  39. .mult = TICK_NSEC << JIFFIES_SHIFT, /* details above */
  40. .shift = JIFFIES_SHIFT,
  41. .max_cycles = 10,
  42. };
  43. static int wdtest_ktime_read_ndelays;
  44. static bool wdtest_ktime_read_fuzz;
  45. static u64 wdtest_ktime_read(struct clocksource *cs)
  46. {
  47. int wkrn = READ_ONCE(wdtest_ktime_read_ndelays);
  48. static int sign = 1;
  49. u64 ret;
  50. if (wkrn) {
  51. udelay(cs->uncertainty_margin / 250);
  52. WRITE_ONCE(wdtest_ktime_read_ndelays, wkrn - 1);
  53. }
  54. ret = ktime_get_real_fast_ns();
  55. if (READ_ONCE(wdtest_ktime_read_fuzz)) {
  56. sign = -sign;
  57. ret = ret + sign * 100 * NSEC_PER_MSEC;
  58. }
  59. return ret;
  60. }
  61. static void wdtest_ktime_cs_mark_unstable(struct clocksource *cs)
  62. {
  63. pr_info("--- Marking %s unstable due to clocksource watchdog.\n", cs->name);
  64. }
  65. #define KTIME_FLAGS (CLOCK_SOURCE_IS_CONTINUOUS | \
  66. CLOCK_SOURCE_VALID_FOR_HRES | \
  67. CLOCK_SOURCE_MUST_VERIFY | \
  68. CLOCK_SOURCE_VERIFY_PERCPU)
  69. static struct clocksource clocksource_wdtest_ktime = {
  70. .name = "wdtest-ktime",
  71. .rating = 300,
  72. .read = wdtest_ktime_read,
  73. .mask = CLOCKSOURCE_MASK(64),
  74. .flags = KTIME_FLAGS,
  75. .mark_unstable = wdtest_ktime_cs_mark_unstable,
  76. .list = LIST_HEAD_INIT(clocksource_wdtest_ktime.list),
  77. };
  78. /* Reset the clocksource if needed. */
  79. static void wdtest_ktime_clocksource_reset(void)
  80. {
  81. if (clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE) {
  82. clocksource_unregister(&clocksource_wdtest_ktime);
  83. clocksource_wdtest_ktime.flags = KTIME_FLAGS;
  84. schedule_timeout_uninterruptible(HZ / 10);
  85. clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000);
  86. }
  87. }
  88. /* Run the specified series of watchdog tests. */
  89. static int wdtest_func(void *arg)
  90. {
  91. unsigned long j1, j2;
  92. char *s;
  93. int i;
  94. schedule_timeout_uninterruptible(holdoff * HZ);
  95. /*
  96. * Verify that jiffies-like clocksources get the manually
  97. * specified uncertainty margin.
  98. */
  99. pr_info("--- Verify jiffies-like uncertainty margin.\n");
  100. __clocksource_register(&clocksource_wdtest_jiffies);
  101. WARN_ON_ONCE(clocksource_wdtest_jiffies.uncertainty_margin != TICK_NSEC);
  102. j1 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies);
  103. schedule_timeout_uninterruptible(HZ);
  104. j2 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies);
  105. WARN_ON_ONCE(j1 == j2);
  106. clocksource_unregister(&clocksource_wdtest_jiffies);
  107. /*
  108. * Verify that tsc-like clocksources are assigned a reasonable
  109. * uncertainty margin.
  110. */
  111. pr_info("--- Verify tsc-like uncertainty margin.\n");
  112. clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000);
  113. WARN_ON_ONCE(clocksource_wdtest_ktime.uncertainty_margin < NSEC_PER_USEC);
  114. j1 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime);
  115. udelay(1);
  116. j2 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime);
  117. pr_info("--- tsc-like times: %lu - %lu = %lu.\n", j2, j1, j2 - j1);
  118. WARN_ON_ONCE(time_before(j2, j1 + NSEC_PER_USEC));
  119. /* Verify tsc-like stability with various numbers of errors injected. */
  120. for (i = 0; i <= max_cswd_read_retries + 1; i++) {
  121. if (i <= 1 && i < max_cswd_read_retries)
  122. s = "";
  123. else if (i <= max_cswd_read_retries)
  124. s = ", expect message";
  125. else
  126. s = ", expect clock skew";
  127. pr_info("--- Watchdog with %dx error injection, %lu retries%s.\n", i, max_cswd_read_retries, s);
  128. WRITE_ONCE(wdtest_ktime_read_ndelays, i);
  129. schedule_timeout_uninterruptible(2 * HZ);
  130. WARN_ON_ONCE(READ_ONCE(wdtest_ktime_read_ndelays));
  131. WARN_ON_ONCE((i <= max_cswd_read_retries) !=
  132. !(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE));
  133. wdtest_ktime_clocksource_reset();
  134. }
  135. /* Verify tsc-like stability with clock-value-fuzz error injection. */
  136. pr_info("--- Watchdog clock-value-fuzz error injection, expect clock skew and per-CPU mismatches.\n");
  137. WRITE_ONCE(wdtest_ktime_read_fuzz, true);
  138. schedule_timeout_uninterruptible(2 * HZ);
  139. WARN_ON_ONCE(!(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE));
  140. clocksource_verify_percpu(&clocksource_wdtest_ktime);
  141. WRITE_ONCE(wdtest_ktime_read_fuzz, false);
  142. clocksource_unregister(&clocksource_wdtest_ktime);
  143. pr_info("--- Done with test.\n");
  144. return 0;
  145. }
  146. static void wdtest_print_module_parms(void)
  147. {
  148. pr_alert("--- holdoff=%d\n", holdoff);
  149. }
  150. /* Cleanup function. */
  151. static void clocksource_wdtest_cleanup(void)
  152. {
  153. }
  154. static int __init clocksource_wdtest_init(void)
  155. {
  156. int ret = 0;
  157. wdtest_print_module_parms();
  158. /* Create watchdog-test task. */
  159. wdtest_task = kthread_run(wdtest_func, NULL, "wdtest");
  160. if (IS_ERR(wdtest_task)) {
  161. ret = PTR_ERR(wdtest_task);
  162. pr_warn("%s: Failed to create wdtest kthread.\n", __func__);
  163. wdtest_task = NULL;
  164. return ret;
  165. }
  166. return 0;
  167. }
  168. module_init(clocksource_wdtest_init);
  169. module_exit(clocksource_wdtest_cleanup);