linux/arch/x86/include/asm/atomic64_64.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ASM_X86_ATOMIC64_64_H
   3#define _ASM_X86_ATOMIC64_64_H
   4
   5#include <linux/types.h>
   6#include <asm/alternative.h>
   7#include <asm/cmpxchg.h>
   8
   9/* The 64-bit atomic type */
  10
  11#define ATOMIC64_INIT(i)        { (i) }
  12
  13/**
  14 * atomic64_read - read atomic64 variable
  15 * @v: pointer of type atomic64_t
  16 *
  17 * Atomically reads the value of @v.
  18 * Doesn't imply a read memory barrier.
  19 */
  20static inline long atomic64_read(const atomic64_t *v)
  21{
  22        return READ_ONCE((v)->counter);
  23}
  24
  25/**
  26 * atomic64_set - set atomic64 variable
  27 * @v: pointer to type atomic64_t
  28 * @i: required value
  29 *
  30 * Atomically sets the value of @v to @i.
  31 */
  32static inline void atomic64_set(atomic64_t *v, long i)
  33{
  34        WRITE_ONCE(v->counter, i);
  35}
  36
  37/**
  38 * atomic64_add - add integer to atomic64 variable
  39 * @i: integer value to add
  40 * @v: pointer to type atomic64_t
  41 *
  42 * Atomically adds @i to @v.
  43 */
  44static __always_inline void atomic64_add(long i, atomic64_t *v)
  45{
  46        asm volatile(LOCK_PREFIX "addq %1,%0"
  47                     : "=m" (v->counter)
  48                     : "er" (i), "m" (v->counter));
  49}
  50
  51/**
  52 * atomic64_sub - subtract the atomic64 variable
  53 * @i: integer value to subtract
  54 * @v: pointer to type atomic64_t
  55 *
  56 * Atomically subtracts @i from @v.
  57 */
  58static inline void atomic64_sub(long i, atomic64_t *v)
  59{
  60        asm volatile(LOCK_PREFIX "subq %1,%0"
  61                     : "=m" (v->counter)
  62                     : "er" (i), "m" (v->counter));
  63}
  64
  65/**
  66 * atomic64_sub_and_test - subtract value from variable and test result
  67 * @i: integer value to subtract
  68 * @v: pointer to type atomic64_t
  69 *
  70 * Atomically subtracts @i from @v and returns
  71 * true if the result is zero, or false for all
  72 * other cases.
  73 */
  74static inline bool atomic64_sub_and_test(long i, atomic64_t *v)
  75{
  76        GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", e);
  77}
  78
  79/**
  80 * atomic64_inc - increment atomic64 variable
  81 * @v: pointer to type atomic64_t
  82 *
  83 * Atomically increments @v by 1.
  84 */
  85static __always_inline void atomic64_inc(atomic64_t *v)
  86{
  87        asm volatile(LOCK_PREFIX "incq %0"
  88                     : "=m" (v->counter)
  89                     : "m" (v->counter));
  90}
  91
  92/**
  93 * atomic64_dec - decrement atomic64 variable
  94 * @v: pointer to type atomic64_t
  95 *
  96 * Atomically decrements @v by 1.
  97 */
  98static __always_inline void atomic64_dec(atomic64_t *v)
  99{
 100        asm volatile(LOCK_PREFIX "decq %0"
 101                     : "=m" (v->counter)
 102                     : "m" (v->counter));
 103}
 104
 105/**
 106 * atomic64_dec_and_test - decrement and test
 107 * @v: pointer to type atomic64_t
 108 *
 109 * Atomically decrements @v by 1 and
 110 * returns true if the result is 0, or false for all other
 111 * cases.
 112 */
 113static inline bool atomic64_dec_and_test(atomic64_t *v)
 114{
 115        GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, "%0", e);
 116}
 117
 118/**
 119 * atomic64_inc_and_test - increment and test
 120 * @v: pointer to type atomic64_t
 121 *
 122 * Atomically increments @v by 1
 123 * and returns true if the result is zero, or false for all
 124 * other cases.
 125 */
 126static inline bool atomic64_inc_and_test(atomic64_t *v)
 127{
 128        GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, "%0", e);
 129}
 130
 131/**
 132 * atomic64_add_negative - add and test if negative
 133 * @i: integer value to add
 134 * @v: pointer to type atomic64_t
 135 *
 136 * Atomically adds @i to @v and returns true
 137 * if the result is negative, or false when
 138 * result is greater than or equal to zero.
 139 */
 140static inline bool atomic64_add_negative(long i, atomic64_t *v)
 141{
 142        GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", s);
 143}
 144
 145/**
 146 * atomic64_add_return - add and return
 147 * @i: integer value to add
 148 * @v: pointer to type atomic64_t
 149 *
 150 * Atomically adds @i to @v and returns @i + @v
 151 */
 152static __always_inline long atomic64_add_return(long i, atomic64_t *v)
 153{
 154        return i + xadd(&v->counter, i);
 155}
 156
 157static inline long atomic64_sub_return(long i, atomic64_t *v)
 158{
 159        return atomic64_add_return(-i, v);
 160}
 161
 162static inline long atomic64_fetch_add(long i, atomic64_t *v)
 163{
 164        return xadd(&v->counter, i);
 165}
 166
 167static inline long atomic64_fetch_sub(long i, atomic64_t *v)
 168{
 169        return xadd(&v->counter, -i);
 170}
 171
 172#define atomic64_inc_return(v)  (atomic64_add_return(1, (v)))
 173#define atomic64_dec_return(v)  (atomic64_sub_return(1, (v)))
 174
 175static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new)
 176{
 177        return cmpxchg(&v->counter, old, new);
 178}
 179
 180#define atomic64_try_cmpxchg atomic64_try_cmpxchg
 181static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, long new)
 182{
 183        return try_cmpxchg(&v->counter, old, new);
 184}
 185
 186static inline long atomic64_xchg(atomic64_t *v, long new)
 187{
 188        return xchg(&v->counter, new);
 189}
 190
 191/**
 192 * atomic64_add_unless - add unless the number is a given value
 193 * @v: pointer of type atomic64_t
 194 * @a: the amount to add to v...
 195 * @u: ...unless v is equal to u.
 196 *
 197 * Atomically adds @a to @v, so long as it was not @u.
 198 * Returns the old value of @v.
 199 */
 200static inline bool atomic64_add_unless(atomic64_t *v, long a, long u)
 201{
 202        s64 c = atomic64_read(v);
 203        do {
 204                if (unlikely(c == u))
 205                        return false;
 206        } while (!atomic64_try_cmpxchg(v, &c, c + a));
 207        return true;
 208}
 209
 210#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 211
 212/*
 213 * atomic64_dec_if_positive - decrement by 1 if old value positive
 214 * @v: pointer of type atomic_t
 215 *
 216 * The function returns the old value of *v minus 1, even if
 217 * the atomic variable, v, was not decremented.
 218 */
 219static inline long atomic64_dec_if_positive(atomic64_t *v)
 220{
 221        s64 dec, c = atomic64_read(v);
 222        do {
 223                dec = c - 1;
 224                if (unlikely(dec < 0))
 225                        break;
 226        } while (!atomic64_try_cmpxchg(v, &c, dec));
 227        return dec;
 228}
 229
 230static inline void atomic64_and(long i, atomic64_t *v)
 231{
 232        asm volatile(LOCK_PREFIX "andq %1,%0"
 233                        : "+m" (v->counter)
 234                        : "er" (i)
 235                        : "memory");
 236}
 237
 238static inline long atomic64_fetch_and(long i, atomic64_t *v)
 239{
 240        s64 val = atomic64_read(v);
 241
 242        do {
 243        } while (!atomic64_try_cmpxchg(v, &val, val & i));
 244        return val;
 245}
 246
 247static inline void atomic64_or(long i, atomic64_t *v)
 248{
 249        asm volatile(LOCK_PREFIX "orq %1,%0"
 250                        : "+m" (v->counter)
 251                        : "er" (i)
 252                        : "memory");
 253}
 254
 255static inline long atomic64_fetch_or(long i, atomic64_t *v)
 256{
 257        s64 val = atomic64_read(v);
 258
 259        do {
 260        } while (!atomic64_try_cmpxchg(v, &val, val | i));
 261        return val;
 262}
 263
 264static inline void atomic64_xor(long i, atomic64_t *v)
 265{
 266        asm volatile(LOCK_PREFIX "xorq %1,%0"
 267                        : "+m" (v->counter)
 268                        : "er" (i)
 269                        : "memory");
 270}
 271
 272static inline long atomic64_fetch_xor(long i, atomic64_t *v)
 273{
 274        s64 val = atomic64_read(v);
 275
 276        do {
 277        } while (!atomic64_try_cmpxchg(v, &val, val ^ i));
 278        return val;
 279}
 280
 281#endif /* _ASM_X86_ATOMIC64_64_H */
 282