1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/init.h> |
3 | #include <linux/kthread.h> |
4 | #include <linux/hrtimer.h> |
5 | #include <linux/fs.h> |
6 | #include <linux/debugfs.h> |
7 | #include <linux/export.h> |
8 | #include <linux/spinlock.h> |
9 | #include <asm/debug.h> |
10 | |
11 | static int ss_get(void *data, u64 *val) |
12 | { |
13 | ktime_t start, finish; |
14 | int loops; |
15 | int cont; |
16 | DEFINE_RAW_SPINLOCK(ss_spin); |
17 | |
18 | loops = 1000000; |
19 | cont = 1; |
20 | |
21 | start = ktime_get(); |
22 | |
23 | while (cont) { |
24 | raw_spin_lock(&ss_spin); |
25 | loops--; |
26 | if (loops == 0) |
27 | cont = 0; |
28 | raw_spin_unlock(&ss_spin); |
29 | } |
30 | |
31 | finish = ktime_get(); |
32 | |
33 | *val = ktime_us_delta(later: finish, earlier: start); |
34 | |
35 | return 0; |
36 | } |
37 | |
38 | DEFINE_DEBUGFS_ATTRIBUTE(fops_ss, ss_get, NULL, "%llu\n" ); |
39 | |
40 | |
41 | |
42 | struct spin_multi_state { |
43 | raw_spinlock_t lock; |
44 | atomic_t start_wait; |
45 | atomic_t enter_wait; |
46 | atomic_t exit_wait; |
47 | int loops; |
48 | }; |
49 | |
50 | struct spin_multi_per_thread { |
51 | struct spin_multi_state *state; |
52 | ktime_t start; |
53 | }; |
54 | |
55 | static int multi_other(void *data) |
56 | { |
57 | int loops; |
58 | int cont; |
59 | struct spin_multi_per_thread *pt = data; |
60 | struct spin_multi_state *s = pt->state; |
61 | |
62 | loops = s->loops; |
63 | cont = 1; |
64 | |
65 | atomic_dec(v: &s->enter_wait); |
66 | |
67 | while (atomic_read(v: &s->enter_wait)) |
68 | ; /* spin */ |
69 | |
70 | pt->start = ktime_get(); |
71 | |
72 | atomic_dec(v: &s->start_wait); |
73 | |
74 | while (atomic_read(v: &s->start_wait)) |
75 | ; /* spin */ |
76 | |
77 | while (cont) { |
78 | raw_spin_lock(&s->lock); |
79 | loops--; |
80 | if (loops == 0) |
81 | cont = 0; |
82 | raw_spin_unlock(&s->lock); |
83 | } |
84 | |
85 | atomic_dec(v: &s->exit_wait); |
86 | while (atomic_read(v: &s->exit_wait)) |
87 | ; /* spin */ |
88 | return 0; |
89 | } |
90 | |
91 | static int multi_get(void *data, u64 *val) |
92 | { |
93 | ktime_t finish; |
94 | struct spin_multi_state ms; |
95 | struct spin_multi_per_thread t1, t2; |
96 | |
97 | ms.lock = __RAW_SPIN_LOCK_UNLOCKED("multi_get" ); |
98 | ms.loops = 1000000; |
99 | |
100 | atomic_set(v: &ms.start_wait, i: 2); |
101 | atomic_set(v: &ms.enter_wait, i: 2); |
102 | atomic_set(v: &ms.exit_wait, i: 2); |
103 | t1.state = &ms; |
104 | t2.state = &ms; |
105 | |
106 | kthread_run(multi_other, &t2, "multi_get" ); |
107 | |
108 | multi_other(data: &t1); |
109 | |
110 | finish = ktime_get(); |
111 | |
112 | *val = ktime_us_delta(later: finish, earlier: t1.start); |
113 | |
114 | return 0; |
115 | } |
116 | |
117 | DEFINE_DEBUGFS_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n" ); |
118 | |
119 | static int __init spinlock_test(void) |
120 | { |
121 | debugfs_create_file_unsafe(name: "spin_single" , S_IRUGO, parent: mips_debugfs_dir, NULL, |
122 | fops: &fops_ss); |
123 | debugfs_create_file_unsafe(name: "spin_multi" , S_IRUGO, parent: mips_debugfs_dir, NULL, |
124 | fops: &fops_multi); |
125 | return 0; |
126 | } |
127 | device_initcall(spinlock_test); |
128 | |