^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #ifndef _ASM_X86_LOCAL_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #define _ASM_X86_LOCAL_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/percpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/asm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) typedef struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) atomic_long_t a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) } local_t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define local_read(l) atomic_long_read(&(l)->a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define local_set(l, i) atomic_long_set(&(l)->a, (i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static inline void local_inc(local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) asm volatile(_ASM_INC "%0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) : "+m" (l->a.counter));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static inline void local_dec(local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) asm volatile(_ASM_DEC "%0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) : "+m" (l->a.counter));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static inline void local_add(long i, local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) asm volatile(_ASM_ADD "%1,%0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) : "+m" (l->a.counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) : "ir" (i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static inline void local_sub(long i, local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) asm volatile(_ASM_SUB "%1,%0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) : "+m" (l->a.counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) : "ir" (i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * local_sub_and_test - subtract value from variable and test result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * @i: integer value to subtract
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @l: pointer to type local_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * Atomically subtracts @i from @l and returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * true if the result is zero, or false for all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * other cases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static inline bool local_sub_and_test(long i, local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, e, "er", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * local_dec_and_test - decrement and test
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * @l: pointer to type local_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Atomically decrements @l by 1 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * returns true if the result is 0, or false for all other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * cases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static inline bool local_dec_and_test(local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return GEN_UNARY_RMWcc(_ASM_DEC, l->a.counter, e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * local_inc_and_test - increment and test
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * @l: pointer to type local_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * Atomically increments @l by 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * and returns true if the result is zero, or false for all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * other cases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static inline bool local_inc_and_test(local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return GEN_UNARY_RMWcc(_ASM_INC, l->a.counter, e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * local_add_negative - add and test if negative
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * @i: integer value to add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * @l: pointer to type local_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * Atomically adds @i to @l and returns true
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * if the result is negative, or false when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * result is greater than or equal to zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static inline bool local_add_negative(long i, local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, s, "er", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * local_add_return - add and return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * @i: integer value to add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * @l: pointer to type local_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * Atomically adds @i to @l and returns @i + @l
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static inline long local_add_return(long i, local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) long __i = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) asm volatile(_ASM_XADD "%0, %1;"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) : "+r" (i), "+m" (l->a.counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return i + __i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static inline long local_sub_return(long i, local_t *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return local_add_return(-i, l);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define local_inc_return(l) (local_add_return(1, l))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define local_dec_return(l) (local_sub_return(1, l))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define local_cmpxchg(l, o, n) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) (cmpxchg_local(&((l)->a.counter), (o), (n)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* Always has a lock prefix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * local_add_unless - add unless the number is a given value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * @l: pointer of type local_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * @a: the amount to add to l...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * @u: ...unless l is equal to u.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * Atomically adds @a to @l, so long as it was not @u.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * Returns non-zero if @l was not @u, and zero otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define local_add_unless(l, a, u) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ({ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) long c, old; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) c = local_read((l)); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) for (;;) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (unlikely(c == (u))) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) break; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) old = local_cmpxchg((l), c, c + (a)); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (likely(old == c)) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) break; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) c = old; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) c != (u); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* On x86_32, these are no better than the atomic variants.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * On x86-64 these are better than the atomic variants on SMP kernels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * because they dont use a lock prefix.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #define __local_inc(l) local_inc(l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define __local_dec(l) local_dec(l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define __local_add(i, l) local_add((i), (l))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define __local_sub(i, l) local_sub((i), (l))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #endif /* _ASM_X86_LOCAL_H */