xref: /linux/lib/atomic64_test.c (revision 978e5a36)
186a89380SLuca Barbieri /*
286a89380SLuca Barbieri  * Testsuite for atomic64_t functions
386a89380SLuca Barbieri  *
486a89380SLuca Barbieri  * Copyright © 2010  Luca Barbieri
586a89380SLuca Barbieri  *
686a89380SLuca Barbieri  * This program is free software; you can redistribute it and/or modify
786a89380SLuca Barbieri  * it under the terms of the GNU General Public License as published by
886a89380SLuca Barbieri  * the Free Software Foundation; either version 2 of the License, or
986a89380SLuca Barbieri  * (at your option) any later version.
1086a89380SLuca Barbieri  */
11b3b16d28SFabian Frederick 
12b3b16d28SFabian Frederick #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13b3b16d28SFabian Frederick 
1486a89380SLuca Barbieri #include <linux/init.h>
1550af5eadSPaul Gortmaker #include <linux/bug.h>
160dbdd1bfSPeter Huewe #include <linux/kernel.h>
1760063497SArun Sharma #include <linux/atomic.h>
1886a89380SLuca Barbieri 
1941b9e9fcSPeter Zijlstra #define TEST(bit, op, c_op, val)				\
2041b9e9fcSPeter Zijlstra do {								\
2141b9e9fcSPeter Zijlstra 	atomic##bit##_set(&v, v0);				\
2241b9e9fcSPeter Zijlstra 	r = v0;							\
2341b9e9fcSPeter Zijlstra 	atomic##bit##_##op(val, &v);				\
2441b9e9fcSPeter Zijlstra 	r c_op val;						\
2541b9e9fcSPeter Zijlstra 	WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n",	\
2641b9e9fcSPeter Zijlstra 		(unsigned long long)atomic##bit##_read(&v),	\
2741b9e9fcSPeter Zijlstra 		(unsigned long long)r);				\
2841b9e9fcSPeter Zijlstra } while (0)
2941b9e9fcSPeter Zijlstra 
30*978e5a36SBoqun Feng /*
31*978e5a36SBoqun Feng  * Test for a atomic operation family,
32*978e5a36SBoqun Feng  * @test should be a macro accepting parameters (bit, op, ...)
33*978e5a36SBoqun Feng  */
34*978e5a36SBoqun Feng 
35*978e5a36SBoqun Feng #define FAMILY_TEST(test, bit, op, args...)	\
36*978e5a36SBoqun Feng do {						\
37*978e5a36SBoqun Feng 	test(bit, op, ##args);		\
38*978e5a36SBoqun Feng 	test(bit, op##_acquire, ##args);	\
39*978e5a36SBoqun Feng 	test(bit, op##_release, ##args);	\
40*978e5a36SBoqun Feng 	test(bit, op##_relaxed, ##args);	\
41*978e5a36SBoqun Feng } while (0)
42*978e5a36SBoqun Feng 
43*978e5a36SBoqun Feng #define TEST_RETURN(bit, op, c_op, val)				\
44*978e5a36SBoqun Feng do {								\
45*978e5a36SBoqun Feng 	atomic##bit##_set(&v, v0);				\
46*978e5a36SBoqun Feng 	r = v0;							\
47*978e5a36SBoqun Feng 	r c_op val;						\
48*978e5a36SBoqun Feng 	BUG_ON(atomic##bit##_##op(val, &v) != r);		\
49*978e5a36SBoqun Feng 	BUG_ON(atomic##bit##_read(&v) != r);			\
50*978e5a36SBoqun Feng } while (0)
51*978e5a36SBoqun Feng 
52*978e5a36SBoqun Feng #define RETURN_FAMILY_TEST(bit, op, c_op, val)			\
53*978e5a36SBoqun Feng do {								\
54*978e5a36SBoqun Feng 	FAMILY_TEST(TEST_RETURN, bit, op, c_op, val);		\
55*978e5a36SBoqun Feng } while (0)
56*978e5a36SBoqun Feng 
57*978e5a36SBoqun Feng #define TEST_ARGS(bit, op, init, ret, expect, args...)		\
58*978e5a36SBoqun Feng do {								\
59*978e5a36SBoqun Feng 	atomic##bit##_set(&v, init);				\
60*978e5a36SBoqun Feng 	BUG_ON(atomic##bit##_##op(&v, ##args) != ret);		\
61*978e5a36SBoqun Feng 	BUG_ON(atomic##bit##_read(&v) != expect);		\
62*978e5a36SBoqun Feng } while (0)
63*978e5a36SBoqun Feng 
64*978e5a36SBoqun Feng #define XCHG_FAMILY_TEST(bit, init, new)				\
65*978e5a36SBoqun Feng do {									\
66*978e5a36SBoqun Feng 	FAMILY_TEST(TEST_ARGS, bit, xchg, init, init, new, new);	\
67*978e5a36SBoqun Feng } while (0)
68*978e5a36SBoqun Feng 
69*978e5a36SBoqun Feng #define CMPXCHG_FAMILY_TEST(bit, init, new, wrong)			\
70*978e5a36SBoqun Feng do {									\
71*978e5a36SBoqun Feng 	FAMILY_TEST(TEST_ARGS, bit, cmpxchg, 				\
72*978e5a36SBoqun Feng 			init, init, new, init, new);			\
73*978e5a36SBoqun Feng 	FAMILY_TEST(TEST_ARGS, bit, cmpxchg,				\
74*978e5a36SBoqun Feng 			init, init, init, wrong, new);			\
75*978e5a36SBoqun Feng } while (0)
76*978e5a36SBoqun Feng 
77*978e5a36SBoqun Feng #define INC_RETURN_FAMILY_TEST(bit, i)			\
78*978e5a36SBoqun Feng do {							\
79*978e5a36SBoqun Feng 	FAMILY_TEST(TEST_ARGS, bit, inc_return,		\
80*978e5a36SBoqun Feng 			i, (i) + one, (i) + one);	\
81*978e5a36SBoqun Feng } while (0)
82*978e5a36SBoqun Feng 
83*978e5a36SBoqun Feng #define DEC_RETURN_FAMILY_TEST(bit, i)			\
84*978e5a36SBoqun Feng do {							\
85*978e5a36SBoqun Feng 	FAMILY_TEST(TEST_ARGS, bit, dec_return,		\
86*978e5a36SBoqun Feng 			i, (i) - one, (i) - one);	\
87*978e5a36SBoqun Feng } while (0)
88*978e5a36SBoqun Feng 
8941b9e9fcSPeter Zijlstra static __init void test_atomic(void)
9041b9e9fcSPeter Zijlstra {
9141b9e9fcSPeter Zijlstra 	int v0 = 0xaaa31337;
9241b9e9fcSPeter Zijlstra 	int v1 = 0xdeadbeef;
9341b9e9fcSPeter Zijlstra 	int onestwos = 0x11112222;
9441b9e9fcSPeter Zijlstra 	int one = 1;
9541b9e9fcSPeter Zijlstra 
9641b9e9fcSPeter Zijlstra 	atomic_t v;
9741b9e9fcSPeter Zijlstra 	int r;
9841b9e9fcSPeter Zijlstra 
9941b9e9fcSPeter Zijlstra 	TEST(, add, +=, onestwos);
10041b9e9fcSPeter Zijlstra 	TEST(, add, +=, -one);
10141b9e9fcSPeter Zijlstra 	TEST(, sub, -=, onestwos);
10241b9e9fcSPeter Zijlstra 	TEST(, sub, -=, -one);
10341b9e9fcSPeter Zijlstra 	TEST(, or, |=, v1);
10441b9e9fcSPeter Zijlstra 	TEST(, and, &=, v1);
10541b9e9fcSPeter Zijlstra 	TEST(, xor, ^=, v1);
10641b9e9fcSPeter Zijlstra 	TEST(, andnot, &= ~, v1);
107*978e5a36SBoqun Feng 
108*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(, add_return, +=, onestwos);
109*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(, add_return, +=, -one);
110*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(, sub_return, -=, onestwos);
111*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(, sub_return, -=, -one);
112*978e5a36SBoqun Feng 
113*978e5a36SBoqun Feng 	INC_RETURN_FAMILY_TEST(, v0);
114*978e5a36SBoqun Feng 	DEC_RETURN_FAMILY_TEST(, v0);
115*978e5a36SBoqun Feng 
116*978e5a36SBoqun Feng 	XCHG_FAMILY_TEST(, v0, v1);
117*978e5a36SBoqun Feng 	CMPXCHG_FAMILY_TEST(, v0, v1, onestwos);
118*978e5a36SBoqun Feng 
11941b9e9fcSPeter Zijlstra }
12041b9e9fcSPeter Zijlstra 
12186a89380SLuca Barbieri #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
12241b9e9fcSPeter Zijlstra static __init void test_atomic64(void)
12386a89380SLuca Barbieri {
12486a89380SLuca Barbieri 	long long v0 = 0xaaa31337c001d00dLL;
12586a89380SLuca Barbieri 	long long v1 = 0xdeadbeefdeafcafeLL;
12686a89380SLuca Barbieri 	long long v2 = 0xfaceabadf00df001LL;
12786a89380SLuca Barbieri 	long long onestwos = 0x1111111122222222LL;
12886a89380SLuca Barbieri 	long long one = 1LL;
12986a89380SLuca Barbieri 
13086a89380SLuca Barbieri 	atomic64_t v = ATOMIC64_INIT(v0);
13186a89380SLuca Barbieri 	long long r = v0;
13286a89380SLuca Barbieri 	BUG_ON(v.counter != r);
13386a89380SLuca Barbieri 
13486a89380SLuca Barbieri 	atomic64_set(&v, v1);
13586a89380SLuca Barbieri 	r = v1;
13686a89380SLuca Barbieri 	BUG_ON(v.counter != r);
13786a89380SLuca Barbieri 	BUG_ON(atomic64_read(&v) != r);
13886a89380SLuca Barbieri 
13941b9e9fcSPeter Zijlstra 	TEST(64, add, +=, onestwos);
14041b9e9fcSPeter Zijlstra 	TEST(64, add, +=, -one);
14141b9e9fcSPeter Zijlstra 	TEST(64, sub, -=, onestwos);
14241b9e9fcSPeter Zijlstra 	TEST(64, sub, -=, -one);
14341b9e9fcSPeter Zijlstra 	TEST(64, or, |=, v1);
14441b9e9fcSPeter Zijlstra 	TEST(64, and, &=, v1);
14541b9e9fcSPeter Zijlstra 	TEST(64, xor, ^=, v1);
14641b9e9fcSPeter Zijlstra 	TEST(64, andnot, &= ~, v1);
14786a89380SLuca Barbieri 
148*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(64, add_return, +=, onestwos);
149*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(64, add_return, +=, -one);
150*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(64, sub_return, -=, onestwos);
151*978e5a36SBoqun Feng 	RETURN_FAMILY_TEST(64, sub_return, -=, -one);
15286a89380SLuca Barbieri 
15386a89380SLuca Barbieri 	INIT(v0);
15486a89380SLuca Barbieri 	atomic64_inc(&v);
15586a89380SLuca Barbieri 	r += one;
15686a89380SLuca Barbieri 	BUG_ON(v.counter != r);
15786a89380SLuca Barbieri 
15886a89380SLuca Barbieri 	INIT(v0);
15986a89380SLuca Barbieri 	atomic64_dec(&v);
16086a89380SLuca Barbieri 	r -= one;
16186a89380SLuca Barbieri 	BUG_ON(v.counter != r);
16286a89380SLuca Barbieri 
163*978e5a36SBoqun Feng 	INC_RETURN_FAMILY_TEST(64, v0);
164*978e5a36SBoqun Feng 	DEC_RETURN_FAMILY_TEST(64, v0);
16586a89380SLuca Barbieri 
166*978e5a36SBoqun Feng 	XCHG_FAMILY_TEST(64, v0, v1);
167*978e5a36SBoqun Feng 	CMPXCHG_FAMILY_TEST(64, v0, v1, v2);
16886a89380SLuca Barbieri 
16986a89380SLuca Barbieri 	INIT(v0);
1709efbcd59SLuca Barbieri 	BUG_ON(atomic64_add_unless(&v, one, v0));
17186a89380SLuca Barbieri 	BUG_ON(v.counter != r);
17286a89380SLuca Barbieri 
17386a89380SLuca Barbieri 	INIT(v0);
1749efbcd59SLuca Barbieri 	BUG_ON(!atomic64_add_unless(&v, one, v1));
17586a89380SLuca Barbieri 	r += one;
17686a89380SLuca Barbieri 	BUG_ON(v.counter != r);
17786a89380SLuca Barbieri 
1787463449bSCatalin Marinas #ifdef CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
17986a89380SLuca Barbieri 	INIT(onestwos);
18086a89380SLuca Barbieri 	BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
18186a89380SLuca Barbieri 	r -= one;
18286a89380SLuca Barbieri 	BUG_ON(v.counter != r);
18386a89380SLuca Barbieri 
18486a89380SLuca Barbieri 	INIT(0);
18586a89380SLuca Barbieri 	BUG_ON(atomic64_dec_if_positive(&v) != -one);
18686a89380SLuca Barbieri 	BUG_ON(v.counter != r);
18786a89380SLuca Barbieri 
18886a89380SLuca Barbieri 	INIT(-one);
18986a89380SLuca Barbieri 	BUG_ON(atomic64_dec_if_positive(&v) != (-one - one));
19086a89380SLuca Barbieri 	BUG_ON(v.counter != r);
1918f4f202bSLuca Barbieri #else
1927463449bSCatalin Marinas #warning Please implement atomic64_dec_if_positive for your architecture and select the above Kconfig symbol
1938f4f202bSLuca Barbieri #endif
19486a89380SLuca Barbieri 
19586a89380SLuca Barbieri 	INIT(onestwos);
19625a304f2SLuca Barbieri 	BUG_ON(!atomic64_inc_not_zero(&v));
19786a89380SLuca Barbieri 	r += one;
19886a89380SLuca Barbieri 	BUG_ON(v.counter != r);
19986a89380SLuca Barbieri 
20086a89380SLuca Barbieri 	INIT(0);
20125a304f2SLuca Barbieri 	BUG_ON(atomic64_inc_not_zero(&v));
20286a89380SLuca Barbieri 	BUG_ON(v.counter != r);
20386a89380SLuca Barbieri 
20486a89380SLuca Barbieri 	INIT(-one);
20525a304f2SLuca Barbieri 	BUG_ON(!atomic64_inc_not_zero(&v));
20686a89380SLuca Barbieri 	r += one;
20786a89380SLuca Barbieri 	BUG_ON(v.counter != r);
20841b9e9fcSPeter Zijlstra }
20941b9e9fcSPeter Zijlstra 
21041b9e9fcSPeter Zijlstra static __init int test_atomics(void)
21141b9e9fcSPeter Zijlstra {
21241b9e9fcSPeter Zijlstra 	test_atomic();
21341b9e9fcSPeter Zijlstra 	test_atomic64();
21486a89380SLuca Barbieri 
21586a89380SLuca Barbieri #ifdef CONFIG_X86
216b3b16d28SFabian Frederick 	pr_info("passed for %s platform %s CX8 and %s SSE\n",
217a5c9161fSH. Peter Anvin #ifdef CONFIG_X86_64
218a5c9161fSH. Peter Anvin 		"x86-64",
219a5c9161fSH. Peter Anvin #elif defined(CONFIG_X86_CMPXCHG64)
220a5c9161fSH. Peter Anvin 		"i586+",
22186a89380SLuca Barbieri #else
222a5c9161fSH. Peter Anvin 		"i386+",
22386a89380SLuca Barbieri #endif
22486a89380SLuca Barbieri 	       boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without",
22586a89380SLuca Barbieri 	       boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without");
22686a89380SLuca Barbieri #else
227b3b16d28SFabian Frederick 	pr_info("passed\n");
22886a89380SLuca Barbieri #endif
22986a89380SLuca Barbieri 
23086a89380SLuca Barbieri 	return 0;
23186a89380SLuca Barbieri }
23286a89380SLuca Barbieri 
23341b9e9fcSPeter Zijlstra core_initcall(test_atomics);
234