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 struct dentry
*udelay_test_debugfs_file
;
25 static int udelay_test_usecs
;
26 static int udelay_test_iterations
= DEFAULT_ITERATIONS
;
28 static int udelay_test_single(struct seq_file
*s
, int usecs
, uint32_t iters
)
30 int min
= 0, max
= 0, fail_count
= 0;
34 /* Allow udelay to be up to 0.5% fast */
35 int allowed_error_ns
= usecs
* 5;
37 for (i
= 0; i
< iters
; ++i
) {
44 time_passed
= kt2
- kt1
;
46 if (i
== 0 || time_passed
< min
)
48 if (i
== 0 || time_passed
> max
)
50 if ((time_passed
+ allowed_error_ns
) / 1000 < usecs
)
52 WARN_ON(time_passed
< 0);
58 seq_printf(s
, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d",
59 usecs
, iters
, usecs
* 1000,
60 (usecs
* 1000) - allowed_error_ns
, min
, avg
, max
);
62 seq_printf(s
, " FAIL=%d", fail_count
);
68 static int udelay_test_show(struct seq_file
*s
, void *v
)
74 mutex_lock(&udelay_test_lock
);
75 usecs
= udelay_test_usecs
;
76 iters
= udelay_test_iterations
;
77 mutex_unlock(&udelay_test_lock
);
79 if (usecs
> 0 && iters
> 0) {
80 return udelay_test_single(s
, usecs
, iters
);
81 } else if (usecs
== 0) {
85 seq_printf(s
, "udelay() test (lpj=%ld kt=%lld.%09ld)\n",
86 loops_per_jiffy
, (s64
)ts
.tv_sec
, ts
.tv_nsec
);
87 seq_puts(s
, "usage:\n");
88 seq_puts(s
, "echo USECS [ITERS] > " DEBUGFS_FILENAME
"\n");
89 seq_puts(s
, "cat " DEBUGFS_FILENAME
"\n");
95 static int udelay_test_open(struct inode
*inode
, struct file
*file
)
97 return single_open(file
, udelay_test_show
, inode
->i_private
);
100 static ssize_t
udelay_test_write(struct file
*file
, const char __user
*buf
,
101 size_t count
, loff_t
*pos
)
108 if (count
>= sizeof(lbuf
))
111 if (copy_from_user(lbuf
, buf
, count
))
115 ret
= sscanf(lbuf
, "%d %d", &usecs
, &iters
);
119 iters
= DEFAULT_ITERATIONS
;
121 mutex_lock(&udelay_test_lock
);
122 udelay_test_usecs
= usecs
;
123 udelay_test_iterations
= iters
;
124 mutex_unlock(&udelay_test_lock
);
129 static const struct file_operations udelay_test_debugfs_ops
= {
130 .owner
= THIS_MODULE
,
131 .open
= udelay_test_open
,
133 .write
= udelay_test_write
,
135 .release
= single_release
,
138 static int __init
udelay_test_init(void)
140 mutex_lock(&udelay_test_lock
);
141 udelay_test_debugfs_file
= debugfs_create_file(DEBUGFS_FILENAME
,
142 S_IRUSR
, NULL
, NULL
, &udelay_test_debugfs_ops
);
143 mutex_unlock(&udelay_test_lock
);
148 module_init(udelay_test_init
);
150 static void __exit
udelay_test_exit(void)
152 mutex_lock(&udelay_test_lock
);
153 debugfs_remove(udelay_test_debugfs_file
);
154 mutex_unlock(&udelay_test_lock
);
157 module_exit(udelay_test_exit
);
159 MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
160 MODULE_LICENSE("GPL");