0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010
0011 #include <linux/device.h>
0012 #include <linux/clocksource.h>
0013 #include <linux/init.h>
0014 #include <linux/module.h>
0015 #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
0016 #include <linux/tick.h>
0017 #include <linux/kthread.h>
0018 #include <linux/delay.h>
0019 #include <linux/prandom.h>
0020 #include <linux/cpu.h>
0021
0022 #include "tick-internal.h"
0023
0024 MODULE_LICENSE("GPL");
0025 MODULE_AUTHOR("Paul E. McKenney <paulmck@kernel.org>");
0026
0027 static int holdoff = IS_BUILTIN(CONFIG_TEST_CLOCKSOURCE_WATCHDOG) ? 10 : 0;
0028 module_param(holdoff, int, 0444);
0029 MODULE_PARM_DESC(holdoff, "Time to wait to start test (s).");
0030
0031
0032 static struct task_struct *wdtest_task;
0033
0034 static u64 wdtest_jiffies_read(struct clocksource *cs)
0035 {
0036 return (u64)jiffies;
0037 }
0038
0039 static struct clocksource clocksource_wdtest_jiffies = {
0040 .name = "wdtest-jiffies",
0041 .rating = 1,
0042 .uncertainty_margin = TICK_NSEC,
0043 .read = wdtest_jiffies_read,
0044 .mask = CLOCKSOURCE_MASK(32),
0045 .flags = CLOCK_SOURCE_MUST_VERIFY,
0046 .mult = TICK_NSEC << JIFFIES_SHIFT,
0047 .shift = JIFFIES_SHIFT,
0048 .max_cycles = 10,
0049 };
0050
0051 static int wdtest_ktime_read_ndelays;
0052 static bool wdtest_ktime_read_fuzz;
0053
0054 static u64 wdtest_ktime_read(struct clocksource *cs)
0055 {
0056 int wkrn = READ_ONCE(wdtest_ktime_read_ndelays);
0057 static int sign = 1;
0058 u64 ret;
0059
0060 if (wkrn) {
0061 udelay(cs->uncertainty_margin / 250);
0062 WRITE_ONCE(wdtest_ktime_read_ndelays, wkrn - 1);
0063 }
0064 ret = ktime_get_real_fast_ns();
0065 if (READ_ONCE(wdtest_ktime_read_fuzz)) {
0066 sign = -sign;
0067 ret = ret + sign * 100 * NSEC_PER_MSEC;
0068 }
0069 return ret;
0070 }
0071
0072 static void wdtest_ktime_cs_mark_unstable(struct clocksource *cs)
0073 {
0074 pr_info("--- Marking %s unstable due to clocksource watchdog.\n", cs->name);
0075 }
0076
0077 #define KTIME_FLAGS (CLOCK_SOURCE_IS_CONTINUOUS | \
0078 CLOCK_SOURCE_VALID_FOR_HRES | \
0079 CLOCK_SOURCE_MUST_VERIFY | \
0080 CLOCK_SOURCE_VERIFY_PERCPU)
0081
0082 static struct clocksource clocksource_wdtest_ktime = {
0083 .name = "wdtest-ktime",
0084 .rating = 300,
0085 .read = wdtest_ktime_read,
0086 .mask = CLOCKSOURCE_MASK(64),
0087 .flags = KTIME_FLAGS,
0088 .mark_unstable = wdtest_ktime_cs_mark_unstable,
0089 .list = LIST_HEAD_INIT(clocksource_wdtest_ktime.list),
0090 };
0091
0092
0093 static void wdtest_ktime_clocksource_reset(void)
0094 {
0095 if (clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE) {
0096 clocksource_unregister(&clocksource_wdtest_ktime);
0097 clocksource_wdtest_ktime.flags = KTIME_FLAGS;
0098 schedule_timeout_uninterruptible(HZ / 10);
0099 clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000);
0100 }
0101 }
0102
0103
0104 static int wdtest_func(void *arg)
0105 {
0106 unsigned long j1, j2;
0107 char *s;
0108 int i;
0109
0110 schedule_timeout_uninterruptible(holdoff * HZ);
0111
0112
0113
0114
0115
0116 pr_info("--- Verify jiffies-like uncertainty margin.\n");
0117 __clocksource_register(&clocksource_wdtest_jiffies);
0118 WARN_ON_ONCE(clocksource_wdtest_jiffies.uncertainty_margin != TICK_NSEC);
0119
0120 j1 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies);
0121 schedule_timeout_uninterruptible(HZ);
0122 j2 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies);
0123 WARN_ON_ONCE(j1 == j2);
0124
0125 clocksource_unregister(&clocksource_wdtest_jiffies);
0126
0127
0128
0129
0130
0131 pr_info("--- Verify tsc-like uncertainty margin.\n");
0132 clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000);
0133 WARN_ON_ONCE(clocksource_wdtest_ktime.uncertainty_margin < NSEC_PER_USEC);
0134
0135 j1 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime);
0136 udelay(1);
0137 j2 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime);
0138 pr_info("--- tsc-like times: %lu - %lu = %lu.\n", j2, j1, j2 - j1);
0139 WARN_ON_ONCE(time_before(j2, j1 + NSEC_PER_USEC));
0140
0141
0142 for (i = 0; i <= max_cswd_read_retries + 1; i++) {
0143 if (i <= 1 && i < max_cswd_read_retries)
0144 s = "";
0145 else if (i <= max_cswd_read_retries)
0146 s = ", expect message";
0147 else
0148 s = ", expect clock skew";
0149 pr_info("--- Watchdog with %dx error injection, %lu retries%s.\n", i, max_cswd_read_retries, s);
0150 WRITE_ONCE(wdtest_ktime_read_ndelays, i);
0151 schedule_timeout_uninterruptible(2 * HZ);
0152 WARN_ON_ONCE(READ_ONCE(wdtest_ktime_read_ndelays));
0153 WARN_ON_ONCE((i <= max_cswd_read_retries) !=
0154 !(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE));
0155 wdtest_ktime_clocksource_reset();
0156 }
0157
0158
0159 pr_info("--- Watchdog clock-value-fuzz error injection, expect clock skew and per-CPU mismatches.\n");
0160 WRITE_ONCE(wdtest_ktime_read_fuzz, true);
0161 schedule_timeout_uninterruptible(2 * HZ);
0162 WARN_ON_ONCE(!(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE));
0163 clocksource_verify_percpu(&clocksource_wdtest_ktime);
0164 WRITE_ONCE(wdtest_ktime_read_fuzz, false);
0165
0166 clocksource_unregister(&clocksource_wdtest_ktime);
0167
0168 pr_info("--- Done with test.\n");
0169 return 0;
0170 }
0171
0172 static void wdtest_print_module_parms(void)
0173 {
0174 pr_alert("--- holdoff=%d\n", holdoff);
0175 }
0176
0177
0178 static void clocksource_wdtest_cleanup(void)
0179 {
0180 }
0181
0182 static int __init clocksource_wdtest_init(void)
0183 {
0184 int ret = 0;
0185
0186 wdtest_print_module_parms();
0187
0188
0189 wdtest_task = kthread_run(wdtest_func, NULL, "wdtest");
0190 if (IS_ERR(wdtest_task)) {
0191 ret = PTR_ERR(wdtest_task);
0192 pr_warn("%s: Failed to create wdtest kthread.\n", __func__);
0193 wdtest_task = NULL;
0194 return ret;
0195 }
0196
0197 return 0;
0198 }
0199
0200 module_init(clocksource_wdtest_init);
0201 module_exit(clocksource_wdtest_cleanup);