• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Testsuite for atomic64_t functions
3  *
4  * Copyright © 2010  Luca Barbieri
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11 
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 
14 #include <linux/init.h>
15 #include <linux/bug.h>
16 #include <linux/kernel.h>
17 #include <linux/atomic.h>
18 
19 #ifdef CONFIG_X86
20 #include <asm/cpufeature.h>	/* for boot_cpu_has below */
21 #endif
22 
23 #define TEST(bit, op, c_op, val)				\
24 do {								\
25 	atomic##bit##_set(&v, v0);				\
26 	r = v0;							\
27 	atomic##bit##_##op(val, &v);				\
28 	r c_op val;						\
29 	WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n",	\
30 		(unsigned long long)atomic##bit##_read(&v),	\
31 		(unsigned long long)r);				\
32 } while (0)
33 
test_atomic(void)34 static __init void test_atomic(void)
35 {
36 	int v0 = 0xaaa31337;
37 	int v1 = 0xdeadbeef;
38 	int onestwos = 0x11112222;
39 	int one = 1;
40 
41 	atomic_t v;
42 	int r;
43 
44 	TEST(, add, +=, onestwos);
45 	TEST(, add, +=, -one);
46 	TEST(, sub, -=, onestwos);
47 	TEST(, sub, -=, -one);
48 	TEST(, or, |=, v1);
49 	TEST(, and, &=, v1);
50 	TEST(, xor, ^=, v1);
51 	TEST(, andnot, &= ~, v1);
52 }
53 
54 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
test_atomic64(void)55 static __init void test_atomic64(void)
56 {
57 	long long v0 = 0xaaa31337c001d00dLL;
58 	long long v1 = 0xdeadbeefdeafcafeLL;
59 	long long v2 = 0xfaceabadf00df001LL;
60 	long long onestwos = 0x1111111122222222LL;
61 	long long one = 1LL;
62 
63 	atomic64_t v = ATOMIC64_INIT(v0);
64 	long long r = v0;
65 	BUG_ON(v.counter != r);
66 
67 	atomic64_set(&v, v1);
68 	r = v1;
69 	BUG_ON(v.counter != r);
70 	BUG_ON(atomic64_read(&v) != r);
71 
72 	TEST(64, add, +=, onestwos);
73 	TEST(64, add, +=, -one);
74 	TEST(64, sub, -=, onestwos);
75 	TEST(64, sub, -=, -one);
76 	TEST(64, or, |=, v1);
77 	TEST(64, and, &=, v1);
78 	TEST(64, xor, ^=, v1);
79 	TEST(64, andnot, &= ~, v1);
80 
81 	INIT(v0);
82 	r += onestwos;
83 	BUG_ON(atomic64_add_return(onestwos, &v) != r);
84 	BUG_ON(v.counter != r);
85 
86 	INIT(v0);
87 	r += -one;
88 	BUG_ON(atomic64_add_return(-one, &v) != r);
89 	BUG_ON(v.counter != r);
90 
91 	INIT(v0);
92 	r -= onestwos;
93 	BUG_ON(atomic64_sub_return(onestwos, &v) != r);
94 	BUG_ON(v.counter != r);
95 
96 	INIT(v0);
97 	r -= -one;
98 	BUG_ON(atomic64_sub_return(-one, &v) != r);
99 	BUG_ON(v.counter != r);
100 
101 	INIT(v0);
102 	atomic64_inc(&v);
103 	r += one;
104 	BUG_ON(v.counter != r);
105 
106 	INIT(v0);
107 	r += one;
108 	BUG_ON(atomic64_inc_return(&v) != r);
109 	BUG_ON(v.counter != r);
110 
111 	INIT(v0);
112 	atomic64_dec(&v);
113 	r -= one;
114 	BUG_ON(v.counter != r);
115 
116 	INIT(v0);
117 	r -= one;
118 	BUG_ON(atomic64_dec_return(&v) != r);
119 	BUG_ON(v.counter != r);
120 
121 	INIT(v0);
122 	BUG_ON(atomic64_xchg(&v, v1) != v0);
123 	r = v1;
124 	BUG_ON(v.counter != r);
125 
126 	INIT(v0);
127 	BUG_ON(atomic64_cmpxchg(&v, v0, v1) != v0);
128 	r = v1;
129 	BUG_ON(v.counter != r);
130 
131 	INIT(v0);
132 	BUG_ON(atomic64_cmpxchg(&v, v2, v1) != v0);
133 	BUG_ON(v.counter != r);
134 
135 	INIT(v0);
136 	BUG_ON(atomic64_add_unless(&v, one, v0));
137 	BUG_ON(v.counter != r);
138 
139 	INIT(v0);
140 	BUG_ON(!atomic64_add_unless(&v, one, v1));
141 	r += one;
142 	BUG_ON(v.counter != r);
143 
144 #ifdef CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
145 	INIT(onestwos);
146 	BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
147 	r -= one;
148 	BUG_ON(v.counter != r);
149 
150 	INIT(0);
151 	BUG_ON(atomic64_dec_if_positive(&v) != -one);
152 	BUG_ON(v.counter != r);
153 
154 	INIT(-one);
155 	BUG_ON(atomic64_dec_if_positive(&v) != (-one - one));
156 	BUG_ON(v.counter != r);
157 #else
158 #warning Please implement atomic64_dec_if_positive for your architecture and select the above Kconfig symbol
159 #endif
160 
161 	INIT(onestwos);
162 	BUG_ON(!atomic64_inc_not_zero(&v));
163 	r += one;
164 	BUG_ON(v.counter != r);
165 
166 	INIT(0);
167 	BUG_ON(atomic64_inc_not_zero(&v));
168 	BUG_ON(v.counter != r);
169 
170 	INIT(-one);
171 	BUG_ON(!atomic64_inc_not_zero(&v));
172 	r += one;
173 	BUG_ON(v.counter != r);
174 }
175 
test_atomics(void)176 static __init int test_atomics(void)
177 {
178 	test_atomic();
179 	test_atomic64();
180 
181 #ifdef CONFIG_X86
182 	pr_info("passed for %s platform %s CX8 and %s SSE\n",
183 #ifdef CONFIG_X86_64
184 		"x86-64",
185 #elif defined(CONFIG_X86_CMPXCHG64)
186 		"i586+",
187 #else
188 		"i386+",
189 #endif
190 	       boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without",
191 	       boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without");
192 #else
193 	pr_info("passed\n");
194 #endif
195 
196 	return 0;
197 }
198 
199 core_initcall(test_atomics);
200