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