0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009
0010 #include <linux/init.h>
0011 #include <linux/bug.h>
0012 #include <linux/kernel.h>
0013 #include <linux/atomic.h>
0014 #include <linux/module.h>
0015
0016 #ifdef CONFIG_X86
0017 #include <asm/cpufeature.h> /* for boot_cpu_has below */
0018 #endif
0019
0020 #define TEST(bit, op, c_op, val) \
0021 do { \
0022 atomic##bit##_set(&v, v0); \
0023 r = v0; \
0024 atomic##bit##_##op(val, &v); \
0025 r c_op val; \
0026 WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n", \
0027 (unsigned long long)atomic##bit##_read(&v), \
0028 (unsigned long long)r); \
0029 } while (0)
0030
0031
0032
0033
0034
0035
0036 #define FAMILY_TEST(test, bit, op, args...) \
0037 do { \
0038 test(bit, op, ##args); \
0039 test(bit, op##_acquire, ##args); \
0040 test(bit, op##_release, ##args); \
0041 test(bit, op##_relaxed, ##args); \
0042 } while (0)
0043
0044 #define TEST_RETURN(bit, op, c_op, val) \
0045 do { \
0046 atomic##bit##_set(&v, v0); \
0047 r = v0; \
0048 r c_op val; \
0049 BUG_ON(atomic##bit##_##op(val, &v) != r); \
0050 BUG_ON(atomic##bit##_read(&v) != r); \
0051 } while (0)
0052
0053 #define TEST_FETCH(bit, op, c_op, val) \
0054 do { \
0055 atomic##bit##_set(&v, v0); \
0056 r = v0; \
0057 r c_op val; \
0058 BUG_ON(atomic##bit##_##op(val, &v) != v0); \
0059 BUG_ON(atomic##bit##_read(&v) != r); \
0060 } while (0)
0061
0062 #define RETURN_FAMILY_TEST(bit, op, c_op, val) \
0063 do { \
0064 FAMILY_TEST(TEST_RETURN, bit, op, c_op, val); \
0065 } while (0)
0066
0067 #define FETCH_FAMILY_TEST(bit, op, c_op, val) \
0068 do { \
0069 FAMILY_TEST(TEST_FETCH, bit, op, c_op, val); \
0070 } while (0)
0071
0072 #define TEST_ARGS(bit, op, init, ret, expect, args...) \
0073 do { \
0074 atomic##bit##_set(&v, init); \
0075 BUG_ON(atomic##bit##_##op(&v, ##args) != ret); \
0076 BUG_ON(atomic##bit##_read(&v) != expect); \
0077 } while (0)
0078
0079 #define XCHG_FAMILY_TEST(bit, init, new) \
0080 do { \
0081 FAMILY_TEST(TEST_ARGS, bit, xchg, init, init, new, new); \
0082 } while (0)
0083
0084 #define CMPXCHG_FAMILY_TEST(bit, init, new, wrong) \
0085 do { \
0086 FAMILY_TEST(TEST_ARGS, bit, cmpxchg, \
0087 init, init, new, init, new); \
0088 FAMILY_TEST(TEST_ARGS, bit, cmpxchg, \
0089 init, init, init, wrong, new); \
0090 } while (0)
0091
0092 #define INC_RETURN_FAMILY_TEST(bit, i) \
0093 do { \
0094 FAMILY_TEST(TEST_ARGS, bit, inc_return, \
0095 i, (i) + one, (i) + one); \
0096 } while (0)
0097
0098 #define DEC_RETURN_FAMILY_TEST(bit, i) \
0099 do { \
0100 FAMILY_TEST(TEST_ARGS, bit, dec_return, \
0101 i, (i) - one, (i) - one); \
0102 } while (0)
0103
0104 static __init void test_atomic(void)
0105 {
0106 int v0 = 0xaaa31337;
0107 int v1 = 0xdeadbeef;
0108 int onestwos = 0x11112222;
0109 int one = 1;
0110
0111 atomic_t v;
0112 int r;
0113
0114 TEST(, add, +=, onestwos);
0115 TEST(, add, +=, -one);
0116 TEST(, sub, -=, onestwos);
0117 TEST(, sub, -=, -one);
0118 TEST(, or, |=, v1);
0119 TEST(, and, &=, v1);
0120 TEST(, xor, ^=, v1);
0121 TEST(, andnot, &= ~, v1);
0122
0123 RETURN_FAMILY_TEST(, add_return, +=, onestwos);
0124 RETURN_FAMILY_TEST(, add_return, +=, -one);
0125 RETURN_FAMILY_TEST(, sub_return, -=, onestwos);
0126 RETURN_FAMILY_TEST(, sub_return, -=, -one);
0127
0128 FETCH_FAMILY_TEST(, fetch_add, +=, onestwos);
0129 FETCH_FAMILY_TEST(, fetch_add, +=, -one);
0130 FETCH_FAMILY_TEST(, fetch_sub, -=, onestwos);
0131 FETCH_FAMILY_TEST(, fetch_sub, -=, -one);
0132
0133 FETCH_FAMILY_TEST(, fetch_or, |=, v1);
0134 FETCH_FAMILY_TEST(, fetch_and, &=, v1);
0135 FETCH_FAMILY_TEST(, fetch_andnot, &= ~, v1);
0136 FETCH_FAMILY_TEST(, fetch_xor, ^=, v1);
0137
0138 INC_RETURN_FAMILY_TEST(, v0);
0139 DEC_RETURN_FAMILY_TEST(, v0);
0140
0141 XCHG_FAMILY_TEST(, v0, v1);
0142 CMPXCHG_FAMILY_TEST(, v0, v1, onestwos);
0143
0144 }
0145
0146 #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
0147 static __init void test_atomic64(void)
0148 {
0149 long long v0 = 0xaaa31337c001d00dLL;
0150 long long v1 = 0xdeadbeefdeafcafeLL;
0151 long long v2 = 0xfaceabadf00df001LL;
0152 long long v3 = 0x8000000000000000LL;
0153 long long onestwos = 0x1111111122222222LL;
0154 long long one = 1LL;
0155 int r_int;
0156
0157 atomic64_t v = ATOMIC64_INIT(v0);
0158 long long r = v0;
0159 BUG_ON(v.counter != r);
0160
0161 atomic64_set(&v, v1);
0162 r = v1;
0163 BUG_ON(v.counter != r);
0164 BUG_ON(atomic64_read(&v) != r);
0165
0166 TEST(64, add, +=, onestwos);
0167 TEST(64, add, +=, -one);
0168 TEST(64, sub, -=, onestwos);
0169 TEST(64, sub, -=, -one);
0170 TEST(64, or, |=, v1);
0171 TEST(64, and, &=, v1);
0172 TEST(64, xor, ^=, v1);
0173 TEST(64, andnot, &= ~, v1);
0174
0175 RETURN_FAMILY_TEST(64, add_return, +=, onestwos);
0176 RETURN_FAMILY_TEST(64, add_return, +=, -one);
0177 RETURN_FAMILY_TEST(64, sub_return, -=, onestwos);
0178 RETURN_FAMILY_TEST(64, sub_return, -=, -one);
0179
0180 FETCH_FAMILY_TEST(64, fetch_add, +=, onestwos);
0181 FETCH_FAMILY_TEST(64, fetch_add, +=, -one);
0182 FETCH_FAMILY_TEST(64, fetch_sub, -=, onestwos);
0183 FETCH_FAMILY_TEST(64, fetch_sub, -=, -one);
0184
0185 FETCH_FAMILY_TEST(64, fetch_or, |=, v1);
0186 FETCH_FAMILY_TEST(64, fetch_and, &=, v1);
0187 FETCH_FAMILY_TEST(64, fetch_andnot, &= ~, v1);
0188 FETCH_FAMILY_TEST(64, fetch_xor, ^=, v1);
0189
0190 INIT(v0);
0191 atomic64_inc(&v);
0192 r += one;
0193 BUG_ON(v.counter != r);
0194
0195 INIT(v0);
0196 atomic64_dec(&v);
0197 r -= one;
0198 BUG_ON(v.counter != r);
0199
0200 INC_RETURN_FAMILY_TEST(64, v0);
0201 DEC_RETURN_FAMILY_TEST(64, v0);
0202
0203 XCHG_FAMILY_TEST(64, v0, v1);
0204 CMPXCHG_FAMILY_TEST(64, v0, v1, v2);
0205
0206 INIT(v0);
0207 BUG_ON(atomic64_add_unless(&v, one, v0));
0208 BUG_ON(v.counter != r);
0209
0210 INIT(v0);
0211 BUG_ON(!atomic64_add_unless(&v, one, v1));
0212 r += one;
0213 BUG_ON(v.counter != r);
0214
0215 INIT(onestwos);
0216 BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
0217 r -= one;
0218 BUG_ON(v.counter != r);
0219
0220 INIT(0);
0221 BUG_ON(atomic64_dec_if_positive(&v) != -one);
0222 BUG_ON(v.counter != r);
0223
0224 INIT(-one);
0225 BUG_ON(atomic64_dec_if_positive(&v) != (-one - one));
0226 BUG_ON(v.counter != r);
0227
0228 INIT(onestwos);
0229 BUG_ON(!atomic64_inc_not_zero(&v));
0230 r += one;
0231 BUG_ON(v.counter != r);
0232
0233 INIT(0);
0234 BUG_ON(atomic64_inc_not_zero(&v));
0235 BUG_ON(v.counter != r);
0236
0237 INIT(-one);
0238 BUG_ON(!atomic64_inc_not_zero(&v));
0239 r += one;
0240 BUG_ON(v.counter != r);
0241
0242
0243 INIT(v3);
0244 r_int = atomic64_inc_not_zero(&v);
0245 BUG_ON(!r_int);
0246 }
0247
0248 static __init int test_atomics_init(void)
0249 {
0250 test_atomic();
0251 test_atomic64();
0252
0253 #ifdef CONFIG_X86
0254 pr_info("passed for %s platform %s CX8 and %s SSE\n",
0255 #ifdef CONFIG_X86_64
0256 "x86-64",
0257 #elif defined(CONFIG_X86_CMPXCHG64)
0258 "i586+",
0259 #else
0260 "i386+",
0261 #endif
0262 boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without",
0263 boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without");
0264 #else
0265 pr_info("passed\n");
0266 #endif
0267
0268 return 0;
0269 }
0270
0271 static __exit void test_atomics_exit(void) {}
0272
0273 module_init(test_atomics_init);
0274 module_exit(test_atomics_exit);
0275
0276 MODULE_LICENSE("GPL");