162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_X86_LOCAL_H 362306a36Sopenharmony_ci#define _ASM_X86_LOCAL_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/percpu.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/atomic.h> 862306a36Sopenharmony_ci#include <asm/asm.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_citypedef struct { 1162306a36Sopenharmony_ci atomic_long_t a; 1262306a36Sopenharmony_ci} local_t; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define local_read(l) atomic_long_read(&(l)->a) 1762306a36Sopenharmony_ci#define local_set(l, i) atomic_long_set(&(l)->a, (i)) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic inline void local_inc(local_t *l) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci asm volatile(_ASM_INC "%0" 2262306a36Sopenharmony_ci : "+m" (l->a.counter)); 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic inline void local_dec(local_t *l) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci asm volatile(_ASM_DEC "%0" 2862306a36Sopenharmony_ci : "+m" (l->a.counter)); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic inline void local_add(long i, local_t *l) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci asm volatile(_ASM_ADD "%1,%0" 3462306a36Sopenharmony_ci : "+m" (l->a.counter) 3562306a36Sopenharmony_ci : "ir" (i)); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic inline void local_sub(long i, local_t *l) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci asm volatile(_ASM_SUB "%1,%0" 4162306a36Sopenharmony_ci : "+m" (l->a.counter) 4262306a36Sopenharmony_ci : "ir" (i)); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * local_sub_and_test - subtract value from variable and test result 4762306a36Sopenharmony_ci * @i: integer value to subtract 4862306a36Sopenharmony_ci * @l: pointer to type local_t 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Atomically subtracts @i from @l and returns 5162306a36Sopenharmony_ci * true if the result is zero, or false for all 5262306a36Sopenharmony_ci * other cases. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_cistatic inline bool local_sub_and_test(long i, local_t *l) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, e, "er", i); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/** 6062306a36Sopenharmony_ci * local_dec_and_test - decrement and test 6162306a36Sopenharmony_ci * @l: pointer to type local_t 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * Atomically decrements @l by 1 and 6462306a36Sopenharmony_ci * returns true if the result is 0, or false for all other 6562306a36Sopenharmony_ci * cases. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_cistatic inline bool local_dec_and_test(local_t *l) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return GEN_UNARY_RMWcc(_ASM_DEC, l->a.counter, e); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/** 7362306a36Sopenharmony_ci * local_inc_and_test - increment and test 7462306a36Sopenharmony_ci * @l: pointer to type local_t 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * Atomically increments @l by 1 7762306a36Sopenharmony_ci * and returns true if the result is zero, or false for all 7862306a36Sopenharmony_ci * other cases. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistatic inline bool local_inc_and_test(local_t *l) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci return GEN_UNARY_RMWcc(_ASM_INC, l->a.counter, e); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/** 8662306a36Sopenharmony_ci * local_add_negative - add and test if negative 8762306a36Sopenharmony_ci * @i: integer value to add 8862306a36Sopenharmony_ci * @l: pointer to type local_t 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * Atomically adds @i to @l and returns true 9162306a36Sopenharmony_ci * if the result is negative, or false when 9262306a36Sopenharmony_ci * result is greater than or equal to zero. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistatic inline bool local_add_negative(long i, local_t *l) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, s, "er", i); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/** 10062306a36Sopenharmony_ci * local_add_return - add and return 10162306a36Sopenharmony_ci * @i: integer value to add 10262306a36Sopenharmony_ci * @l: pointer to type local_t 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Atomically adds @i to @l and returns @i + @l 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic inline long local_add_return(long i, local_t *l) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci long __i = i; 10962306a36Sopenharmony_ci asm volatile(_ASM_XADD "%0, %1;" 11062306a36Sopenharmony_ci : "+r" (i), "+m" (l->a.counter) 11162306a36Sopenharmony_ci : : "memory"); 11262306a36Sopenharmony_ci return i + __i; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic inline long local_sub_return(long i, local_t *l) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci return local_add_return(-i, l); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define local_inc_return(l) (local_add_return(1, l)) 12162306a36Sopenharmony_ci#define local_dec_return(l) (local_sub_return(1, l)) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic inline long local_cmpxchg(local_t *l, long old, long new) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return cmpxchg_local(&l->a.counter, old, new); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic inline bool local_try_cmpxchg(local_t *l, long *old, long new) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return try_cmpxchg_local(&l->a.counter, 13162306a36Sopenharmony_ci (typeof(l->a.counter) *) old, new); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* Always has a lock prefix */ 13562306a36Sopenharmony_ci#define local_xchg(l, n) (xchg(&((l)->a.counter), (n))) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/** 13862306a36Sopenharmony_ci * local_add_unless - add unless the number is a given value 13962306a36Sopenharmony_ci * @l: pointer of type local_t 14062306a36Sopenharmony_ci * @a: the amount to add to l... 14162306a36Sopenharmony_ci * @u: ...unless l is equal to u. 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * Atomically adds @a to @l, so long as it was not @u. 14462306a36Sopenharmony_ci * Returns non-zero if @l was not @u, and zero otherwise. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci#define local_add_unless(l, a, u) \ 14762306a36Sopenharmony_ci({ \ 14862306a36Sopenharmony_ci long c, old; \ 14962306a36Sopenharmony_ci c = local_read((l)); \ 15062306a36Sopenharmony_ci for (;;) { \ 15162306a36Sopenharmony_ci if (unlikely(c == (u))) \ 15262306a36Sopenharmony_ci break; \ 15362306a36Sopenharmony_ci old = local_cmpxchg((l), c, c + (a)); \ 15462306a36Sopenharmony_ci if (likely(old == c)) \ 15562306a36Sopenharmony_ci break; \ 15662306a36Sopenharmony_ci c = old; \ 15762306a36Sopenharmony_ci } \ 15862306a36Sopenharmony_ci c != (u); \ 15962306a36Sopenharmony_ci}) 16062306a36Sopenharmony_ci#define local_inc_not_zero(l) local_add_unless((l), 1, 0) 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* On x86_32, these are no better than the atomic variants. 16362306a36Sopenharmony_ci * On x86-64 these are better than the atomic variants on SMP kernels 16462306a36Sopenharmony_ci * because they dont use a lock prefix. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci#define __local_inc(l) local_inc(l) 16762306a36Sopenharmony_ci#define __local_dec(l) local_dec(l) 16862306a36Sopenharmony_ci#define __local_add(i, l) local_add((i), (l)) 16962306a36Sopenharmony_ci#define __local_sub(i, l) local_sub((i), (l)) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#endif /* _ASM_X86_LOCAL_H */ 172