1 // SPDX-License-Identifier: GPL-2.0
3 * udelay() test kernel module
5 * Test is executed by writing and reading to /sys/kernel/debug/udelay_test
6 * Tests are configured by writing: USECS ITERATIONS
7 * Tests are executed by reading from the same file.
8 * Specifying usecs of 0 or negative values will run multiples tests.
10 * Copyright (C) 2014 Google, Inc.
13 #include <linux/debugfs.h>
14 #include <linux/delay.h>
15 #include <linux/ktime.h>
16 #include <linux/module.h>
17 #include <linux/uaccess.h>
19 #define DEFAULT_ITERATIONS 100
21 #define DEBUGFS_FILENAME "udelay_test"
23 static DEFINE_MUTEX(udelay_test_lock
);
24 static int udelay_test_usecs
;
25 static int udelay_test_iterations
= DEFAULT_ITERATIONS
;
27 static int udelay_test_single(struct seq_file
*s
, int usecs
, uint32_t iters
)
29 int min
= 0, max
= 0, fail_count
= 0;
33 /* Allow udelay to be up to 0.5% fast */
34 int allowed_error_ns
= usecs
* 5;
36 for (i
= 0; i
< iters
; ++i
) {
43 time_passed
= kt2
- kt1
;
45 if (i
== 0 || time_passed
< min
)
47 if (i
== 0 || time_passed
> max
)
49 if ((time_passed
+ allowed_error_ns
) / 1000 < usecs
)
51 WARN_ON(time_passed
< 0);
57 seq_printf(s
, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d",
58 usecs
, iters
, usecs
* 1000,
59 (usecs
* 1000) - allowed_error_ns
, min
, avg
, max
);
61 seq_printf(s
, " FAIL=%d", fail_count
);
67 static int udelay_test_show(struct seq_file
*s
, void *v
)
73 mutex_lock(&udelay_test_lock
);
74 usecs
= udelay_test_usecs
;
75 iters
= udelay_test_iterations
;
76 mutex_unlock(&udelay_test_lock
);
78 if (usecs
> 0 && iters
> 0) {
79 return udelay_test_single(s
, usecs
, iters
);
80 } else if (usecs
== 0) {
84 seq_printf(s
, "udelay() test (lpj=%ld kt=%lld.%09ld)\n",
85 loops_per_jiffy
, (s64
)ts
.tv_sec
, ts
.tv_nsec
);
86 seq_puts(s
, "usage:\n");
87 seq_puts(s
, "echo USECS [ITERS] > " DEBUGFS_FILENAME
"\n");
88 seq_puts(s
, "cat " DEBUGFS_FILENAME
"\n");
94 static int udelay_test_open(struct inode
*inode
, struct file
*file
)
96 return single_open(file
, udelay_test_show
, inode
->i_private
);
99 static ssize_t
udelay_test_write(struct file
*file
, const char __user
*buf
,
100 size_t count
, loff_t
*pos
)
107 if (count
>= sizeof(lbuf
))
110 if (copy_from_user(lbuf
, buf
, count
))
114 ret
= sscanf(lbuf
, "%d %d", &usecs
, &iters
);
118 iters
= DEFAULT_ITERATIONS
;
120 mutex_lock(&udelay_test_lock
);
121 udelay_test_usecs
= usecs
;
122 udelay_test_iterations
= iters
;
123 mutex_unlock(&udelay_test_lock
);
128 static const struct file_operations udelay_test_debugfs_ops
= {
129 .owner
= THIS_MODULE
,
130 .open
= udelay_test_open
,
132 .write
= udelay_test_write
,
134 .release
= single_release
,
137 static int __init
udelay_test_init(void)
139 mutex_lock(&udelay_test_lock
);
140 debugfs_create_file(DEBUGFS_FILENAME
, S_IRUSR
, NULL
, NULL
,
141 &udelay_test_debugfs_ops
);
142 mutex_unlock(&udelay_test_lock
);
147 module_init(udelay_test_init
);
149 static void __exit
udelay_test_exit(void)
151 mutex_lock(&udelay_test_lock
);
152 debugfs_lookup_and_remove(DEBUGFS_FILENAME
, NULL
);
153 mutex_unlock(&udelay_test_lock
);
156 module_exit(udelay_test_exit
);
158 MODULE_DESCRIPTION("udelay test module");
159 MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
160 MODULE_LICENSE("GPL");