xref: /linux/lib/atomic64_test.c (revision b85d45947951d23cb22d90caecf4c1eb81342c96)
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 #define TEST(bit, op, c_op, val)				\
20 do {								\
21 	atomic##bit##_set(&v, v0);				\
22 	r = v0;							\
23 	atomic##bit##_##op(val, &v);				\
24 	r c_op val;						\
25 	WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n",	\
26 		(unsigned long long)atomic##bit##_read(&v),	\
27 		(unsigned long long)r);				\
28 } while (0)
29 
30 static __init void test_atomic(void)
31 {
32 	int v0 = 0xaaa31337;
33 	int v1 = 0xdeadbeef;
34 	int onestwos = 0x11112222;
35 	int one = 1;
36 
37 	atomic_t v;
38 	int r;
39 
40 	TEST(, add, +=, onestwos);
41 	TEST(, add, +=, -one);
42 	TEST(, sub, -=, onestwos);
43 	TEST(, sub, -=, -one);
44 	TEST(, or, |=, v1);
45 	TEST(, and, &=, v1);
46 	TEST(, xor, ^=, v1);
47 	TEST(, andnot, &= ~, v1);
48 }
49 
50 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
51 static __init void test_atomic64(void)
52 {
53 	long long v0 = 0xaaa31337c001d00dLL;
54 	long long v1 = 0xdeadbeefdeafcafeLL;
55 	long long v2 = 0xfaceabadf00df001LL;
56 	long long onestwos = 0x1111111122222222LL;
57 	long long one = 1LL;
58 
59 	atomic64_t v = ATOMIC64_INIT(v0);
60 	long long r = v0;
61 	BUG_ON(v.counter != r);
62 
63 	atomic64_set(&v, v1);
64 	r = v1;
65 	BUG_ON(v.counter != r);
66 	BUG_ON(atomic64_read(&v) != r);
67 
68 	TEST(64, add, +=, onestwos);
69 	TEST(64, add, +=, -one);
70 	TEST(64, sub, -=, onestwos);
71 	TEST(64, sub, -=, -one);
72 	TEST(64, or, |=, v1);
73 	TEST(64, and, &=, v1);
74 	TEST(64, xor, ^=, v1);
75 	TEST(64, andnot, &= ~, v1);
76 
77 	INIT(v0);
78 	r += onestwos;
79 	BUG_ON(atomic64_add_return(onestwos, &v) != r);
80 	BUG_ON(v.counter != r);
81 
82 	INIT(v0);
83 	r += -one;
84 	BUG_ON(atomic64_add_return(-one, &v) != r);
85 	BUG_ON(v.counter != r);
86 
87 	INIT(v0);
88 	r -= onestwos;
89 	BUG_ON(atomic64_sub_return(onestwos, &v) != r);
90 	BUG_ON(v.counter != r);
91 
92 	INIT(v0);
93 	r -= -one;
94 	BUG_ON(atomic64_sub_return(-one, &v) != r);
95 	BUG_ON(v.counter != r);
96 
97 	INIT(v0);
98 	atomic64_inc(&v);
99 	r += one;
100 	BUG_ON(v.counter != r);
101 
102 	INIT(v0);
103 	r += one;
104 	BUG_ON(atomic64_inc_return(&v) != r);
105 	BUG_ON(v.counter != r);
106 
107 	INIT(v0);
108 	atomic64_dec(&v);
109 	r -= one;
110 	BUG_ON(v.counter != r);
111 
112 	INIT(v0);
113 	r -= one;
114 	BUG_ON(atomic64_dec_return(&v) != r);
115 	BUG_ON(v.counter != r);
116 
117 	INIT(v0);
118 	BUG_ON(atomic64_xchg(&v, v1) != v0);
119 	r = v1;
120 	BUG_ON(v.counter != r);
121 
122 	INIT(v0);
123 	BUG_ON(atomic64_cmpxchg(&v, v0, v1) != v0);
124 	r = v1;
125 	BUG_ON(v.counter != r);
126 
127 	INIT(v0);
128 	BUG_ON(atomic64_cmpxchg(&v, v2, v1) != v0);
129 	BUG_ON(v.counter != r);
130 
131 	INIT(v0);
132 	BUG_ON(atomic64_add_unless(&v, one, v0));
133 	BUG_ON(v.counter != r);
134 
135 	INIT(v0);
136 	BUG_ON(!atomic64_add_unless(&v, one, v1));
137 	r += one;
138 	BUG_ON(v.counter != r);
139 
140 #ifdef CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
141 	INIT(onestwos);
142 	BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
143 	r -= one;
144 	BUG_ON(v.counter != r);
145 
146 	INIT(0);
147 	BUG_ON(atomic64_dec_if_positive(&v) != -one);
148 	BUG_ON(v.counter != r);
149 
150 	INIT(-one);
151 	BUG_ON(atomic64_dec_if_positive(&v) != (-one - one));
152 	BUG_ON(v.counter != r);
153 #else
154 #warning Please implement atomic64_dec_if_positive for your architecture and select the above Kconfig symbol
155 #endif
156 
157 	INIT(onestwos);
158 	BUG_ON(!atomic64_inc_not_zero(&v));
159 	r += one;
160 	BUG_ON(v.counter != r);
161 
162 	INIT(0);
163 	BUG_ON(atomic64_inc_not_zero(&v));
164 	BUG_ON(v.counter != r);
165 
166 	INIT(-one);
167 	BUG_ON(!atomic64_inc_not_zero(&v));
168 	r += one;
169 	BUG_ON(v.counter != r);
170 }
171 
172 static __init int test_atomics(void)
173 {
174 	test_atomic();
175 	test_atomic64();
176 
177 #ifdef CONFIG_X86
178 	pr_info("passed for %s platform %s CX8 and %s SSE\n",
179 #ifdef CONFIG_X86_64
180 		"x86-64",
181 #elif defined(CONFIG_X86_CMPXCHG64)
182 		"i586+",
183 #else
184 		"i386+",
185 #endif
186 	       boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without",
187 	       boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without");
188 #else
189 	pr_info("passed\n");
190 #endif
191 
192 	return 0;
193 }
194 
195 core_initcall(test_atomics);
196