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