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 onestwos = 0x1111111122222222LL; 157 long long one = 1LL; 158 159 atomic64_t v = ATOMIC64_INIT(v0); 160 long long r = v0; 161 BUG_ON(v.counter != r); 162 163 atomic64_set(&v, v1); 164 r = v1; 165 BUG_ON(v.counter != r); 166 BUG_ON(atomic64_read(&v) != r); 167 168 TEST(64, add, +=, onestwos); 169 TEST(64, add, +=, -one); 170 TEST(64, sub, -=, onestwos); 171 TEST(64, sub, -=, -one); 172 TEST(64, or, |=, v1); 173 TEST(64, and, &=, v1); 174 TEST(64, xor, ^=, v1); 175 TEST(64, andnot, &= ~, v1); 176 177 RETURN_FAMILY_TEST(64, add_return, +=, onestwos); 178 RETURN_FAMILY_TEST(64, add_return, +=, -one); 179 RETURN_FAMILY_TEST(64, sub_return, -=, onestwos); 180 RETURN_FAMILY_TEST(64, sub_return, -=, -one); 181 182 FETCH_FAMILY_TEST(64, fetch_add, +=, onestwos); 183 FETCH_FAMILY_TEST(64, fetch_add, +=, -one); 184 FETCH_FAMILY_TEST(64, fetch_sub, -=, onestwos); 185 FETCH_FAMILY_TEST(64, fetch_sub, -=, -one); 186 187 FETCH_FAMILY_TEST(64, fetch_or, |=, v1); 188 FETCH_FAMILY_TEST(64, fetch_and, &=, v1); 189 FETCH_FAMILY_TEST(64, fetch_andnot, &= ~, v1); 190 FETCH_FAMILY_TEST(64, fetch_xor, ^=, v1); 191 192 INIT(v0); 193 atomic64_inc(&v); 194 r += one; 195 BUG_ON(v.counter != r); 196 197 INIT(v0); 198 atomic64_dec(&v); 199 r -= one; 200 BUG_ON(v.counter != r); 201 202 INC_RETURN_FAMILY_TEST(64, v0); 203 DEC_RETURN_FAMILY_TEST(64, v0); 204 205 XCHG_FAMILY_TEST(64, v0, v1); 206 CMPXCHG_FAMILY_TEST(64, v0, v1, v2); 207 208 INIT(v0); 209 BUG_ON(atomic64_add_unless(&v, one, v0)); 210 BUG_ON(v.counter != r); 211 212 INIT(v0); 213 BUG_ON(!atomic64_add_unless(&v, one, v1)); 214 r += one; 215 BUG_ON(v.counter != r); 216 217 INIT(onestwos); 218 BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1)); 219 r -= one; 220 BUG_ON(v.counter != r); 221 222 INIT(0); 223 BUG_ON(atomic64_dec_if_positive(&v) != -one); 224 BUG_ON(v.counter != r); 225 226 INIT(-one); 227 BUG_ON(atomic64_dec_if_positive(&v) != (-one - one)); 228 BUG_ON(v.counter != r); 229 230 INIT(onestwos); 231 BUG_ON(!atomic64_inc_not_zero(&v)); 232 r += one; 233 BUG_ON(v.counter != r); 234 235 INIT(0); 236 BUG_ON(atomic64_inc_not_zero(&v)); 237 BUG_ON(v.counter != r); 238 239 INIT(-one); 240 BUG_ON(!atomic64_inc_not_zero(&v)); 241 r += one; 242 BUG_ON(v.counter != r); 243 } 244 245 static __init int test_atomics_init(void) 246 { 247 test_atomic(); 248 test_atomic64(); 249 250 #ifdef CONFIG_X86 251 pr_info("passed for %s platform %s CX8 and %s SSE\n", 252 #ifdef CONFIG_X86_64 253 "x86-64", 254 #elif defined(CONFIG_X86_CMPXCHG64) 255 "i586+", 256 #else 257 "i386+", 258 #endif 259 boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without", 260 boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without"); 261 #else 262 pr_info("passed\n"); 263 #endif 264 265 return 0; 266 } 267 268 static __exit void test_atomics_exit(void) {} 269 270 module_init(test_atomics_init); 271 module_exit(test_atomics_exit); 272 273 MODULE_LICENSE("GPL"); 274