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 #define TEST(bit, op, c_op, val) \ 20 do { \ 21 atomic##bit##_set(&v, v0); \ 22 r = v0; \ 23 atomic##bit##_##op(val, &v); \ 24 r c_op val; \ 25 WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n", \ 26 (unsigned long long)atomic##bit##_read(&v), \ 27 (unsigned long long)r); \ 28 } while (0) 29 30 static __init void test_atomic(void) 31 { 32 int v0 = 0xaaa31337; 33 int v1 = 0xdeadbeef; 34 int onestwos = 0x11112222; 35 int one = 1; 36 37 atomic_t v; 38 int r; 39 40 TEST(, add, +=, onestwos); 41 TEST(, add, +=, -one); 42 TEST(, sub, -=, onestwos); 43 TEST(, sub, -=, -one); 44 TEST(, or, |=, v1); 45 TEST(, and, &=, v1); 46 TEST(, xor, ^=, v1); 47 TEST(, andnot, &= ~, v1); 48 } 49 50 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0) 51 static __init void test_atomic64(void) 52 { 53 long long v0 = 0xaaa31337c001d00dLL; 54 long long v1 = 0xdeadbeefdeafcafeLL; 55 long long v2 = 0xfaceabadf00df001LL; 56 long long onestwos = 0x1111111122222222LL; 57 long long one = 1LL; 58 59 atomic64_t v = ATOMIC64_INIT(v0); 60 long long r = v0; 61 BUG_ON(v.counter != r); 62 63 atomic64_set(&v, v1); 64 r = v1; 65 BUG_ON(v.counter != r); 66 BUG_ON(atomic64_read(&v) != r); 67 68 TEST(64, add, +=, onestwos); 69 TEST(64, add, +=, -one); 70 TEST(64, sub, -=, onestwos); 71 TEST(64, sub, -=, -one); 72 TEST(64, or, |=, v1); 73 TEST(64, and, &=, v1); 74 TEST(64, xor, ^=, v1); 75 TEST(64, andnot, &= ~, v1); 76 77 INIT(v0); 78 r += onestwos; 79 BUG_ON(atomic64_add_return(onestwos, &v) != r); 80 BUG_ON(v.counter != r); 81 82 INIT(v0); 83 r += -one; 84 BUG_ON(atomic64_add_return(-one, &v) != r); 85 BUG_ON(v.counter != r); 86 87 INIT(v0); 88 r -= onestwos; 89 BUG_ON(atomic64_sub_return(onestwos, &v) != r); 90 BUG_ON(v.counter != r); 91 92 INIT(v0); 93 r -= -one; 94 BUG_ON(atomic64_sub_return(-one, &v) != r); 95 BUG_ON(v.counter != r); 96 97 INIT(v0); 98 atomic64_inc(&v); 99 r += one; 100 BUG_ON(v.counter != r); 101 102 INIT(v0); 103 r += one; 104 BUG_ON(atomic64_inc_return(&v) != r); 105 BUG_ON(v.counter != r); 106 107 INIT(v0); 108 atomic64_dec(&v); 109 r -= one; 110 BUG_ON(v.counter != r); 111 112 INIT(v0); 113 r -= one; 114 BUG_ON(atomic64_dec_return(&v) != r); 115 BUG_ON(v.counter != r); 116 117 INIT(v0); 118 BUG_ON(atomic64_xchg(&v, v1) != v0); 119 r = v1; 120 BUG_ON(v.counter != r); 121 122 INIT(v0); 123 BUG_ON(atomic64_cmpxchg(&v, v0, v1) != v0); 124 r = v1; 125 BUG_ON(v.counter != r); 126 127 INIT(v0); 128 BUG_ON(atomic64_cmpxchg(&v, v2, v1) != v0); 129 BUG_ON(v.counter != r); 130 131 INIT(v0); 132 BUG_ON(atomic64_add_unless(&v, one, v0)); 133 BUG_ON(v.counter != r); 134 135 INIT(v0); 136 BUG_ON(!atomic64_add_unless(&v, one, v1)); 137 r += one; 138 BUG_ON(v.counter != r); 139 140 #ifdef CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 141 INIT(onestwos); 142 BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1)); 143 r -= one; 144 BUG_ON(v.counter != r); 145 146 INIT(0); 147 BUG_ON(atomic64_dec_if_positive(&v) != -one); 148 BUG_ON(v.counter != r); 149 150 INIT(-one); 151 BUG_ON(atomic64_dec_if_positive(&v) != (-one - one)); 152 BUG_ON(v.counter != r); 153 #else 154 #warning Please implement atomic64_dec_if_positive for your architecture and select the above Kconfig symbol 155 #endif 156 157 INIT(onestwos); 158 BUG_ON(!atomic64_inc_not_zero(&v)); 159 r += one; 160 BUG_ON(v.counter != r); 161 162 INIT(0); 163 BUG_ON(atomic64_inc_not_zero(&v)); 164 BUG_ON(v.counter != r); 165 166 INIT(-one); 167 BUG_ON(!atomic64_inc_not_zero(&v)); 168 r += one; 169 BUG_ON(v.counter != r); 170 } 171 172 static __init int test_atomics(void) 173 { 174 test_atomic(); 175 test_atomic64(); 176 177 #ifdef CONFIG_X86 178 pr_info("passed for %s platform %s CX8 and %s SSE\n", 179 #ifdef CONFIG_X86_64 180 "x86-64", 181 #elif defined(CONFIG_X86_CMPXCHG64) 182 "i586+", 183 #else 184 "i386+", 185 #endif 186 boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without", 187 boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without"); 188 #else 189 pr_info("passed\n"); 190 #endif 191 192 return 0; 193 } 194 195 core_initcall(test_atomics); 196