^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * udelay() test kernel module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Test is executed by writing and reading to /sys/kernel/debug/udelay_test
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Tests are configured by writing: USECS ITERATIONS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Tests are executed by reading from the same file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Specifying usecs of 0 or negative values will run multiples tests.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2014 Google, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/ktime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define DEFAULT_ITERATIONS 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define DEBUGFS_FILENAME "udelay_test"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static DEFINE_MUTEX(udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static struct dentry *udelay_test_debugfs_file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static int udelay_test_usecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static int udelay_test_iterations = DEFAULT_ITERATIONS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static int udelay_test_single(struct seq_file *s, int usecs, uint32_t iters)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int min = 0, max = 0, fail_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) uint64_t sum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) uint64_t avg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* Allow udelay to be up to 0.5% fast */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int allowed_error_ns = usecs * 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) for (i = 0; i < iters; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) s64 kt1, kt2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int time_passed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) kt1 = ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) udelay(usecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) kt2 = ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) time_passed = kt2 - kt1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (i == 0 || time_passed < min)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) min = time_passed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (i == 0 || time_passed > max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) max = time_passed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if ((time_passed + allowed_error_ns) / 1000 < usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) ++fail_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) WARN_ON(time_passed < 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) sum += time_passed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) avg = sum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) do_div(avg, iters);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) seq_printf(s, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) usecs, iters, usecs * 1000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) (usecs * 1000) - allowed_error_ns, min, avg, max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (fail_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) seq_printf(s, " FAIL=%d", fail_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) seq_puts(s, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static int udelay_test_show(struct seq_file *s, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int usecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int iters;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) mutex_lock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) usecs = udelay_test_usecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) iters = udelay_test_iterations;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) mutex_unlock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (usecs > 0 && iters > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return udelay_test_single(s, usecs, iters);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) } else if (usecs == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct timespec64 ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ktime_get_ts64(&ts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) seq_printf(s, "udelay() test (lpj=%ld kt=%lld.%09ld)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) loops_per_jiffy, (s64)ts.tv_sec, ts.tv_nsec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) seq_puts(s, "usage:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) seq_puts(s, "echo USECS [ITERS] > " DEBUGFS_FILENAME "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) seq_puts(s, "cat " DEBUGFS_FILENAME "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int udelay_test_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return single_open(file, udelay_test_show, inode->i_private);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static ssize_t udelay_test_write(struct file *file, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) size_t count, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) char lbuf[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int usecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int iters;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (count >= sizeof(lbuf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (copy_from_user(lbuf, buf, count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) lbuf[count] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ret = sscanf(lbuf, "%d %d", &usecs, &iters);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (ret < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) else if (ret < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) iters = DEFAULT_ITERATIONS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) mutex_lock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) udelay_test_usecs = usecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) udelay_test_iterations = iters;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mutex_unlock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static const struct file_operations udelay_test_debugfs_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .open = udelay_test_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .read = seq_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .write = udelay_test_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .llseek = seq_lseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .release = single_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int __init udelay_test_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) mutex_lock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) udelay_test_debugfs_file = debugfs_create_file(DEBUGFS_FILENAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) S_IRUSR, NULL, NULL, &udelay_test_debugfs_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) mutex_unlock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) module_init(udelay_test_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static void __exit udelay_test_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) mutex_lock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) debugfs_remove(udelay_test_debugfs_file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) mutex_unlock(&udelay_test_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) module_exit(udelay_test_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) MODULE_LICENSE("GPL");