linux/lib/atomic64_test.c
<<
>>
Prefs
   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)                                \
  24do {                                                            \
  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...)     \
  40do {                                            \
  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)                         \
  48do {                                                            \
  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)                  \
  57do {                                                            \
  58        FAMILY_TEST(TEST_RETURN, bit, op, c_op, val);           \
  59} while (0)
  60
  61#define TEST_ARGS(bit, op, init, ret, expect, args...)          \
  62do {                                                            \
  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)                                \
  69do {                                                                    \
  70        FAMILY_TEST(TEST_ARGS, bit, xchg, init, init, new, new);        \
  71} while (0)
  72
  73#define CMPXCHG_FAMILY_TEST(bit, init, new, wrong)                      \
  74do {                                                                    \
  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)                  \
  82do {                                                    \
  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)                  \
  88do {                                                    \
  89        FAMILY_TEST(TEST_ARGS, bit, dec_return,         \
  90                        i, (i) - one, (i) - one);       \
  91} while (0)
  92
  93static __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)
 126static __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
 214static __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
 237core_initcall(test_atomics);
 238