18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_ATOMIC_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_ATOMIC_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/compiler.h> 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <asm/alternative.h> 88c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 98c2ecf20Sopenharmony_ci#include <asm/rmwcc.h> 108c2ecf20Sopenharmony_ci#include <asm/barrier.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* 138c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us. Useful for 148c2ecf20Sopenharmony_ci * resource counting etc.. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/** 188c2ecf20Sopenharmony_ci * arch_atomic_read - read atomic variable 198c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Atomically reads the value of @v. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_read(const atomic_t *v) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci /* 268c2ecf20Sopenharmony_ci * Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here, 278c2ecf20Sopenharmony_ci * it's non-inlined function that increases binary size and stack usage. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci return __READ_ONCE((v)->counter); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/** 338c2ecf20Sopenharmony_ci * arch_atomic_set - set atomic variable 348c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 358c2ecf20Sopenharmony_ci * @i: required value 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Atomically sets the value of @v to @i. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_set(atomic_t *v, int i) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci __WRITE_ONCE(v->counter, i); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/** 458c2ecf20Sopenharmony_ci * arch_atomic_add - add integer to atomic variable 468c2ecf20Sopenharmony_ci * @i: integer value to add 478c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * Atomically adds @i to @v. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_add(int i, atomic_t *v) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci asm volatile(LOCK_PREFIX "addl %1,%0" 548c2ecf20Sopenharmony_ci : "+m" (v->counter) 558c2ecf20Sopenharmony_ci : "ir" (i) : "memory"); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * arch_atomic_sub - subtract integer from atomic variable 608c2ecf20Sopenharmony_ci * @i: integer value to subtract 618c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * Atomically subtracts @i from @v. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_sub(int i, atomic_t *v) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci asm volatile(LOCK_PREFIX "subl %1,%0" 688c2ecf20Sopenharmony_ci : "+m" (v->counter) 698c2ecf20Sopenharmony_ci : "ir" (i) : "memory"); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/** 738c2ecf20Sopenharmony_ci * arch_atomic_sub_and_test - subtract value from variable and test result 748c2ecf20Sopenharmony_ci * @i: integer value to subtract 758c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * Atomically subtracts @i from @v and returns 788c2ecf20Sopenharmony_ci * true if the result is zero, or false for all 798c2ecf20Sopenharmony_ci * other cases. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistatic __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci return GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, e, "er", i); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci#define arch_atomic_sub_and_test arch_atomic_sub_and_test 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * arch_atomic_inc - increment atomic variable 898c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * Atomically increments @v by 1. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_inc(atomic_t *v) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci asm volatile(LOCK_PREFIX "incl %0" 968c2ecf20Sopenharmony_ci : "+m" (v->counter) :: "memory"); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci#define arch_atomic_inc arch_atomic_inc 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/** 1018c2ecf20Sopenharmony_ci * arch_atomic_dec - decrement atomic variable 1028c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * Atomically decrements @v by 1. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_dec(atomic_t *v) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci asm volatile(LOCK_PREFIX "decl %0" 1098c2ecf20Sopenharmony_ci : "+m" (v->counter) :: "memory"); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci#define arch_atomic_dec arch_atomic_dec 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/** 1148c2ecf20Sopenharmony_ci * arch_atomic_dec_and_test - decrement and test 1158c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Atomically decrements @v by 1 and 1188c2ecf20Sopenharmony_ci * returns true if the result is 0, or false for all other 1198c2ecf20Sopenharmony_ci * cases. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistatic __always_inline bool arch_atomic_dec_and_test(atomic_t *v) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci return GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, e); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci#define arch_atomic_dec_and_test arch_atomic_dec_and_test 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/** 1288c2ecf20Sopenharmony_ci * arch_atomic_inc_and_test - increment and test 1298c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * Atomically increments @v by 1 1328c2ecf20Sopenharmony_ci * and returns true if the result is zero, or false for all 1338c2ecf20Sopenharmony_ci * other cases. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_cistatic __always_inline bool arch_atomic_inc_and_test(atomic_t *v) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci return GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, e); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci#define arch_atomic_inc_and_test arch_atomic_inc_and_test 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/** 1428c2ecf20Sopenharmony_ci * arch_atomic_add_negative - add and test if negative 1438c2ecf20Sopenharmony_ci * @i: integer value to add 1448c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * Atomically adds @i to @v and returns true 1478c2ecf20Sopenharmony_ci * if the result is negative, or false when 1488c2ecf20Sopenharmony_ci * result is greater than or equal to zero. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic __always_inline bool arch_atomic_add_negative(int i, atomic_t *v) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, s, "er", i); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci#define arch_atomic_add_negative arch_atomic_add_negative 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/** 1578c2ecf20Sopenharmony_ci * arch_atomic_add_return - add integer and return 1588c2ecf20Sopenharmony_ci * @i: integer value to add 1598c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * Atomically adds @i to @v and returns @i + @v 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_add_return(int i, atomic_t *v) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci return i + xadd(&v->counter, i); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci#define arch_atomic_add_return arch_atomic_add_return 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/** 1708c2ecf20Sopenharmony_ci * arch_atomic_sub_return - subtract integer and return 1718c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 1728c2ecf20Sopenharmony_ci * @i: integer value to subtract 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Atomically subtracts @i from @v and returns @v - @i 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_sub_return(int i, atomic_t *v) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return arch_atomic_add_return(-i, v); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci#define arch_atomic_sub_return arch_atomic_sub_return 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_fetch_add(int i, atomic_t *v) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci return xadd(&v->counter, i); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci#define arch_atomic_fetch_add arch_atomic_fetch_add 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_fetch_sub(int i, atomic_t *v) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci return xadd(&v->counter, -i); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci#define arch_atomic_fetch_sub arch_atomic_fetch_sub 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci return arch_cmpxchg(&v->counter, old, new); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci#define arch_atomic_cmpxchg arch_atomic_cmpxchg 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci return try_cmpxchg(&v->counter, old, new); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci#define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_xchg(atomic_t *v, int new) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci return arch_xchg(&v->counter, new); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci#define arch_atomic_xchg arch_atomic_xchg 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_and(int i, atomic_t *v) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci asm volatile(LOCK_PREFIX "andl %1,%0" 2158c2ecf20Sopenharmony_ci : "+m" (v->counter) 2168c2ecf20Sopenharmony_ci : "ir" (i) 2178c2ecf20Sopenharmony_ci : "memory"); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_fetch_and(int i, atomic_t *v) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int val = arch_atomic_read(v); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci do { } while (!arch_atomic_try_cmpxchg(v, &val, val & i)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return val; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci#define arch_atomic_fetch_and arch_atomic_fetch_and 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_or(int i, atomic_t *v) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci asm volatile(LOCK_PREFIX "orl %1,%0" 2338c2ecf20Sopenharmony_ci : "+m" (v->counter) 2348c2ecf20Sopenharmony_ci : "ir" (i) 2358c2ecf20Sopenharmony_ci : "memory"); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_fetch_or(int i, atomic_t *v) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci int val = arch_atomic_read(v); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci do { } while (!arch_atomic_try_cmpxchg(v, &val, val | i)); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return val; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci#define arch_atomic_fetch_or arch_atomic_fetch_or 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic __always_inline void arch_atomic_xor(int i, atomic_t *v) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci asm volatile(LOCK_PREFIX "xorl %1,%0" 2518c2ecf20Sopenharmony_ci : "+m" (v->counter) 2528c2ecf20Sopenharmony_ci : "ir" (i) 2538c2ecf20Sopenharmony_ci : "memory"); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic __always_inline int arch_atomic_fetch_xor(int i, atomic_t *v) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci int val = arch_atomic_read(v); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci do { } while (!arch_atomic_try_cmpxchg(v, &val, val ^ i)); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return val; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci#define arch_atomic_fetch_xor arch_atomic_fetch_xor 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 2678c2ecf20Sopenharmony_ci# include <asm/atomic64_32.h> 2688c2ecf20Sopenharmony_ci#else 2698c2ecf20Sopenharmony_ci# include <asm/atomic64_64.h> 2708c2ecf20Sopenharmony_ci#endif 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci#define ARCH_ATOMIC 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#endif /* _ASM_X86_ATOMIC_H */ 275