1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Testsuite for atomic64_t functions 4 * 5 * Copyright © 2010 Luca Barbieri 6 */ 7 8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 10 #include <linux/init.h> 11 #include <linux/bug.h> 12 #include <linux/kernel.h> 13 #include <linux/atomic.h> 14 #include <linux/module.h> 15 16 #ifdef CONFIG_X86 17 #include <asm/cpufeature.h> /* for boot_cpu_has below */ 18 #endif 19 20 #define TEST(bit, op, c_op, val) \ 21 do { \ 22 atomic##bit##_set(&v, v0); \ 23 r = v0; \ 24 atomic##bit##_##op(val, &v); \ 25 r c_op val; \ 26 WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n", \ 27 (unsigned long long)atomic##bit##_read(&v), \ 28 (unsigned long long)r); \ 29 } while (0) 30 31 /* 32 * Test for a atomic operation family, 33 * @test should be a macro accepting parameters (bit, op, ...) 34 */ 35 36 #define FAMILY_TEST(test, bit, op, args...) \ 37 do { \ 38 test(bit, op, ##args); \ 39 test(bit, op##_acquire, ##args); \ 40 test(bit, op##_release, ##args); \ 41 test(bit, op##_relaxed, ##args); \ 42 } while (0) 43 44 #define TEST_RETURN(bit, op, c_op, val) \ 45 do { \ 46 atomic##bit##_set(&v, v0); \ 47 r = v0; \ 48 r c_op val; \ 49 BUG_ON(atomic##bit##_##op(val, &v) != r); \ 50 BUG_ON(atomic##bit##_read(&v) != r); \ 51 } while (0) 52 53 #define TEST_FETCH(bit, op, c_op, val) \ 54 do { \ 55 atomic##bit##_set(&v, v0); \ 56 r = v0; \ 57 r c_op val; \ 58 BUG_ON(atomic##bit##_##op(val, &v) != v0); \ 59 BUG_ON(atomic##bit##_read(&v) != r); \ 60 } while (0) 61 62 #define RETURN_FAMILY_TEST(bit, op, c_op, val) \ 63 do { \ 64 FAMILY_TEST(TEST_RETURN, bit, op, c_op, val); \ 65 } while (0) 66 67 #define FETCH_FAMILY_TEST(bit, op, c_op, val) \ 68 do { \ 69 FAMILY_TEST(TEST_FETCH, bit, op, c_op, val); \ 70 } while (0) 71 72 #define TEST_ARGS(bit, op, init, ret, expect, args...) \ 73 do { \ 74 atomic##bit##_set(&v, init); \ 75 BUG_ON(atomic##bit##_##op(&v, ##args) != ret); \ 76 BUG_ON(atomic##bit##_read(&v) != expect); \ 77 } while (0) 78 79 #define XCHG_FAMILY_TEST(bit, init, new) \ 80 do { \ 81 FAMILY_TEST(TEST_ARGS, bit, xchg, init, init, new, new); \ 82 } while (0) 83 84 #define CMPXCHG_FAMILY_TEST(bit, init, new, wrong) \ 85 do { \ 86 FAMILY_TEST(TEST_ARGS, bit, cmpxchg, \ 87 init, init, new, init, new); \ 88 FAMILY_TEST(TEST_ARGS, bit, cmpxchg, \ 89 init, init, init, wrong, new); \ 90 } while (0) 91 92 #define INC_RETURN_FAMILY_TEST(bit, i) \ 93 do { \ 94 FAMILY_TEST(TEST_ARGS, bit, inc_return, \ 95 i, (i) + one, (i) + one); \ 96 } while (0) 97 98 #define DEC_RETURN_FAMILY_TEST(bit, i) \ 99 do { \ 100 FAMILY_TEST(TEST_ARGS, bit, dec_return, \ 101 i, (i) - one, (i) - one); \ 102 } while (0) 103 104 static __init void test_atomic(void) 105 { 106 int v0 = 0xaaa31337; 107 int v1 = 0xdeadbeef; 108 int onestwos = 0x11112222; 109 int one = 1; 110 111 atomic_t v; 112 int r; 113 114 TEST(, add, +=, onestwos); 115 TEST(, add, +=, -one); 116 TEST(, sub, -=, onestwos); 117 TEST(, sub, -=, -one); 118 TEST(, or, |=, v1); 119 TEST(, and, &=, v1); 120 TEST(, xor, ^=, v1); 121 TEST(, andnot, &= ~, v1); 122 123 RETURN_FAMILY_TEST(, add_return, +=, onestwos); 124 RETURN_FAMILY_TEST(, add_return, +=, -one); 125 RETURN_FAMILY_TEST(, sub_return, -=, onestwos); 126 RETURN_FAMILY_TEST(, sub_return, -=, -one); 127 128 FETCH_FAMILY_TEST(, fetch_add, +=, onestwos); 129 FETCH_FAMILY_TEST(, fetch_add, +=, -one); 130 FETCH_FAMILY_TEST(, fetch_sub, -=, onestwos); 131 FETCH_FAMILY_TEST(, fetch_sub, -=, -one); 132 133 FETCH_FAMILY_TEST(, fetch_or, |=, v1); 134 FETCH_FAMILY_TEST(, fetch_and, &=, v1); 135 FETCH_FAMILY_TEST(, fetch_andnot, &= ~, v1); 136 FETCH_FAMILY_TEST(, fetch_xor, ^=, v1); 137 138 INC_RETURN_FAMILY_TEST(, v0); 139 DEC_RETURN_FAMILY_TEST(, v0); 140 141 XCHG_FAMILY_TEST(, v0, v1); 142 CMPXCHG_FAMILY_TEST(, v0, v1, onestwos); 143 144 } 145 146 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0) 147 static __init void test_atomic64(void) 148 { 149 long long v0 = 0xaaa31337c001d00dLL; 150 long long v1 = 0xdeadbeefdeafcafeLL; 151 long long v2 = 0xfaceabadf00df001LL; 152 long long v3 = 0x8000000000000000LL; 153 long long onestwos = 0x1111111122222222LL; 154 long long one = 1LL; 155 int r_int; 156 157 atomic64_t v = ATOMIC64_INIT(v0); 158 long long r = v0; 159 BUG_ON(v.counter != r); 160 161 atomic64_set(&v, v1); 162 r = v1; 163 BUG_ON(v.counter != r); 164 BUG_ON(atomic64_read(&v) != r); 165 166 TEST(64, add, +=, onestwos); 167 TEST(64, add, +=, -one); 168 TEST(64, sub, -=, onestwos); 169 TEST(64, sub, -=, -one); 170 TEST(64, or, |=, v1); 171 TEST(64, and, &=, v1); 172 TEST(64, xor, ^=, v1); 173 TEST(64, andnot, &= ~, v1); 174 175 RETURN_FAMILY_TEST(64, add_return, +=, onestwos); 176 RETURN_FAMILY_TEST(64, add_return, +=, -one); 177 RETURN_FAMILY_TEST(64, sub_return, -=, onestwos); 178 RETURN_FAMILY_TEST(64, sub_return, -=, -one); 179 180 FETCH_FAMILY_TEST(64, fetch_add, +=, onestwos); 181 FETCH_FAMILY_TEST(64, fetch_add, +=, -one); 182 FETCH_FAMILY_TEST(64, fetch_sub, -=, onestwos); 183 FETCH_FAMILY_TEST(64, fetch_sub, -=, -one); 184 185 FETCH_FAMILY_TEST(64, fetch_or, |=, v1); 186 FETCH_FAMILY_TEST(64, fetch_and, &=, v1); 187 FETCH_FAMILY_TEST(64, fetch_andnot, &= ~, v1); 188 FETCH_FAMILY_TEST(64, fetch_xor, ^=, v1); 189 190 INIT(v0); 191 atomic64_inc(&v); 192 r += one; 193 BUG_ON(v.counter != r); 194 195 INIT(v0); 196 atomic64_dec(&v); 197 r -= one; 198 BUG_ON(v.counter != r); 199 200 INC_RETURN_FAMILY_TEST(64, v0); 201 DEC_RETURN_FAMILY_TEST(64, v0); 202 203 XCHG_FAMILY_TEST(64, v0, v1); 204 CMPXCHG_FAMILY_TEST(64, v0, v1, v2); 205 206 INIT(v0); 207 BUG_ON(atomic64_add_unless(&v, one, v0)); 208 BUG_ON(v.counter != r); 209 210 INIT(v0); 211 BUG_ON(!atomic64_add_unless(&v, one, v1)); 212 r += one; 213 BUG_ON(v.counter != r); 214 215 INIT(onestwos); 216 BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1)); 217 r -= one; 218 BUG_ON(v.counter != r); 219 220 INIT(0); 221 BUG_ON(atomic64_dec_if_positive(&v) != -one); 222 BUG_ON(v.counter != r); 223 224 INIT(-one); 225 BUG_ON(atomic64_dec_if_positive(&v) != (-one - one)); 226 BUG_ON(v.counter != r); 227 228 INIT(onestwos); 229 BUG_ON(!atomic64_inc_not_zero(&v)); 230 r += one; 231 BUG_ON(v.counter != r); 232 233 INIT(0); 234 BUG_ON(atomic64_inc_not_zero(&v)); 235 BUG_ON(v.counter != r); 236 237 INIT(-one); 238 BUG_ON(!atomic64_inc_not_zero(&v)); 239 r += one; 240 BUG_ON(v.counter != r); 241 242 /* Confirm the return value fits in an int, even if the value doesn't */ 243 INIT(v3); 244 r_int = atomic64_inc_not_zero(&v); 245 BUG_ON(!r_int); 246 } 247 248 static __init int test_atomics_init(void) 249 { 250 test_atomic(); 251 test_atomic64(); 252 253 #ifdef CONFIG_X86 254 pr_info("passed for %s platform %s CX8 and %s SSE\n", 255 #ifdef CONFIG_X86_64 256 "x86-64", 257 #elif defined(CONFIG_X86_CMPXCHG64) 258 "i586+", 259 #else 260 "i386+", 261 #endif 262 boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without", 263 boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without"); 264 #else 265 pr_info("passed\n"); 266 #endif 267 268 return 0; 269 } 270 271 static __exit void test_atomics_exit(void) {} 272 273 module_init(test_atomics_init); 274 module_exit(test_atomics_exit); 275 276 MODULE_DESCRIPTION("Testsuite for atomic64_t functions"); 277 MODULE_LICENSE("GPL"); 278