18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ALPHA_ATOMIC_H 38c2ecf20Sopenharmony_ci#define _ALPHA_ATOMIC_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/types.h> 68c2ecf20Sopenharmony_ci#include <asm/barrier.h> 78c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us. Useful for 118c2ecf20Sopenharmony_ci * resource counting etc... 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * But use these as seldom as possible since they are much slower 148c2ecf20Sopenharmony_ci * than regular operations. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * To ensure dependency ordering is preserved for the _relaxed and 198c2ecf20Sopenharmony_ci * _release atomics, an smp_mb() is unconditionally inserted into the 208c2ecf20Sopenharmony_ci * _relaxed variants, which are used to build the barriered versions. 218c2ecf20Sopenharmony_ci * Avoid redundant back-to-back fences in the _acquire and _fence 228c2ecf20Sopenharmony_ci * versions. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci#define __atomic_acquire_fence() 258c2ecf20Sopenharmony_ci#define __atomic_post_full_fence() 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define ATOMIC64_INIT(i) { (i) } 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define atomic_read(v) READ_ONCE((v)->counter) 308c2ecf20Sopenharmony_ci#define atomic64_read(v) READ_ONCE((v)->counter) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i)) 338c2ecf20Sopenharmony_ci#define atomic64_set(v,i) WRITE_ONCE((v)->counter, (i)) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * To get proper branch prediction for the main line, we must branch 378c2ecf20Sopenharmony_ci * forward to code at the end of this object's .text section, then 388c2ecf20Sopenharmony_ci * branch back to restart the operation. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, asm_op) \ 428c2ecf20Sopenharmony_cistatic __inline__ void atomic_##op(int i, atomic_t * v) \ 438c2ecf20Sopenharmony_ci{ \ 448c2ecf20Sopenharmony_ci unsigned long temp; \ 458c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 468c2ecf20Sopenharmony_ci "1: ldl_l %0,%1\n" \ 478c2ecf20Sopenharmony_ci " " #asm_op " %0,%2,%0\n" \ 488c2ecf20Sopenharmony_ci " stl_c %0,%1\n" \ 498c2ecf20Sopenharmony_ci " beq %0,2f\n" \ 508c2ecf20Sopenharmony_ci ".subsection 2\n" \ 518c2ecf20Sopenharmony_ci "2: br 1b\n" \ 528c2ecf20Sopenharmony_ci ".previous" \ 538c2ecf20Sopenharmony_ci :"=&r" (temp), "=m" (v->counter) \ 548c2ecf20Sopenharmony_ci :"Ir" (i), "m" (v->counter)); \ 558c2ecf20Sopenharmony_ci} \ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, asm_op) \ 588c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return_relaxed(int i, atomic_t *v) \ 598c2ecf20Sopenharmony_ci{ \ 608c2ecf20Sopenharmony_ci long temp, result; \ 618c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 628c2ecf20Sopenharmony_ci "1: ldl_l %0,%1\n" \ 638c2ecf20Sopenharmony_ci " " #asm_op " %0,%3,%2\n" \ 648c2ecf20Sopenharmony_ci " " #asm_op " %0,%3,%0\n" \ 658c2ecf20Sopenharmony_ci " stl_c %0,%1\n" \ 668c2ecf20Sopenharmony_ci " beq %0,2f\n" \ 678c2ecf20Sopenharmony_ci ".subsection 2\n" \ 688c2ecf20Sopenharmony_ci "2: br 1b\n" \ 698c2ecf20Sopenharmony_ci ".previous" \ 708c2ecf20Sopenharmony_ci :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ 718c2ecf20Sopenharmony_ci :"Ir" (i), "m" (v->counter) : "memory"); \ 728c2ecf20Sopenharmony_ci smp_mb(); \ 738c2ecf20Sopenharmony_ci return result; \ 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, asm_op) \ 778c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v) \ 788c2ecf20Sopenharmony_ci{ \ 798c2ecf20Sopenharmony_ci long temp, result; \ 808c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 818c2ecf20Sopenharmony_ci "1: ldl_l %2,%1\n" \ 828c2ecf20Sopenharmony_ci " " #asm_op " %2,%3,%0\n" \ 838c2ecf20Sopenharmony_ci " stl_c %0,%1\n" \ 848c2ecf20Sopenharmony_ci " beq %0,2f\n" \ 858c2ecf20Sopenharmony_ci ".subsection 2\n" \ 868c2ecf20Sopenharmony_ci "2: br 1b\n" \ 878c2ecf20Sopenharmony_ci ".previous" \ 888c2ecf20Sopenharmony_ci :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ 898c2ecf20Sopenharmony_ci :"Ir" (i), "m" (v->counter) : "memory"); \ 908c2ecf20Sopenharmony_ci smp_mb(); \ 918c2ecf20Sopenharmony_ci return result; \ 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op, asm_op) \ 958c2ecf20Sopenharmony_cistatic __inline__ void atomic64_##op(s64 i, atomic64_t * v) \ 968c2ecf20Sopenharmony_ci{ \ 978c2ecf20Sopenharmony_ci s64 temp; \ 988c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 998c2ecf20Sopenharmony_ci "1: ldq_l %0,%1\n" \ 1008c2ecf20Sopenharmony_ci " " #asm_op " %0,%2,%0\n" \ 1018c2ecf20Sopenharmony_ci " stq_c %0,%1\n" \ 1028c2ecf20Sopenharmony_ci " beq %0,2f\n" \ 1038c2ecf20Sopenharmony_ci ".subsection 2\n" \ 1048c2ecf20Sopenharmony_ci "2: br 1b\n" \ 1058c2ecf20Sopenharmony_ci ".previous" \ 1068c2ecf20Sopenharmony_ci :"=&r" (temp), "=m" (v->counter) \ 1078c2ecf20Sopenharmony_ci :"Ir" (i), "m" (v->counter)); \ 1088c2ecf20Sopenharmony_ci} \ 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#define ATOMIC64_OP_RETURN(op, asm_op) \ 1118c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_##op##_return_relaxed(s64 i, atomic64_t * v) \ 1128c2ecf20Sopenharmony_ci{ \ 1138c2ecf20Sopenharmony_ci s64 temp, result; \ 1148c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1158c2ecf20Sopenharmony_ci "1: ldq_l %0,%1\n" \ 1168c2ecf20Sopenharmony_ci " " #asm_op " %0,%3,%2\n" \ 1178c2ecf20Sopenharmony_ci " " #asm_op " %0,%3,%0\n" \ 1188c2ecf20Sopenharmony_ci " stq_c %0,%1\n" \ 1198c2ecf20Sopenharmony_ci " beq %0,2f\n" \ 1208c2ecf20Sopenharmony_ci ".subsection 2\n" \ 1218c2ecf20Sopenharmony_ci "2: br 1b\n" \ 1228c2ecf20Sopenharmony_ci ".previous" \ 1238c2ecf20Sopenharmony_ci :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ 1248c2ecf20Sopenharmony_ci :"Ir" (i), "m" (v->counter) : "memory"); \ 1258c2ecf20Sopenharmony_ci smp_mb(); \ 1268c2ecf20Sopenharmony_ci return result; \ 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP(op, asm_op) \ 1308c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_fetch_##op##_relaxed(s64 i, atomic64_t * v) \ 1318c2ecf20Sopenharmony_ci{ \ 1328c2ecf20Sopenharmony_ci s64 temp, result; \ 1338c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1348c2ecf20Sopenharmony_ci "1: ldq_l %2,%1\n" \ 1358c2ecf20Sopenharmony_ci " " #asm_op " %2,%3,%0\n" \ 1368c2ecf20Sopenharmony_ci " stq_c %0,%1\n" \ 1378c2ecf20Sopenharmony_ci " beq %0,2f\n" \ 1388c2ecf20Sopenharmony_ci ".subsection 2\n" \ 1398c2ecf20Sopenharmony_ci "2: br 1b\n" \ 1408c2ecf20Sopenharmony_ci ".previous" \ 1418c2ecf20Sopenharmony_ci :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ 1428c2ecf20Sopenharmony_ci :"Ir" (i), "m" (v->counter) : "memory"); \ 1438c2ecf20Sopenharmony_ci smp_mb(); \ 1448c2ecf20Sopenharmony_ci return result; \ 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op) \ 1488c2ecf20Sopenharmony_ci ATOMIC_OP(op, op##l) \ 1498c2ecf20Sopenharmony_ci ATOMIC_OP_RETURN(op, op##l) \ 1508c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, op##l) \ 1518c2ecf20Sopenharmony_ci ATOMIC64_OP(op, op##q) \ 1528c2ecf20Sopenharmony_ci ATOMIC64_OP_RETURN(op, op##q) \ 1538c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, op##q) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciATOMIC_OPS(add) 1568c2ecf20Sopenharmony_ciATOMIC_OPS(sub) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define atomic_add_return_relaxed atomic_add_return_relaxed 1598c2ecf20Sopenharmony_ci#define atomic_sub_return_relaxed atomic_sub_return_relaxed 1608c2ecf20Sopenharmony_ci#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed 1618c2ecf20Sopenharmony_ci#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#define atomic64_add_return_relaxed atomic64_add_return_relaxed 1648c2ecf20Sopenharmony_ci#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed 1658c2ecf20Sopenharmony_ci#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed 1668c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define atomic_andnot atomic_andnot 1698c2ecf20Sopenharmony_ci#define atomic64_andnot atomic64_andnot 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 1728c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, asm) \ 1738c2ecf20Sopenharmony_ci ATOMIC_OP(op, asm) \ 1748c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, asm) \ 1758c2ecf20Sopenharmony_ci ATOMIC64_OP(op, asm) \ 1768c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, asm) 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciATOMIC_OPS(and, and) 1798c2ecf20Sopenharmony_ciATOMIC_OPS(andnot, bic) 1808c2ecf20Sopenharmony_ciATOMIC_OPS(or, bis) 1818c2ecf20Sopenharmony_ciATOMIC_OPS(xor, xor) 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed 1848c2ecf20Sopenharmony_ci#define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed 1858c2ecf20Sopenharmony_ci#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed 1868c2ecf20Sopenharmony_ci#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed 1898c2ecf20Sopenharmony_ci#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed 1908c2ecf20Sopenharmony_ci#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed 1918c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 1948c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP 1958c2ecf20Sopenharmony_ci#undef ATOMIC64_OP_RETURN 1968c2ecf20Sopenharmony_ci#undef ATOMIC64_OP 1978c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP 1988c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN 1998c2ecf20Sopenharmony_ci#undef ATOMIC_OP 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) 2028c2ecf20Sopenharmony_ci#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) 2058c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/** 2088c2ecf20Sopenharmony_ci * atomic_fetch_add_unless - add unless the number is a given value 2098c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 2108c2ecf20Sopenharmony_ci * @a: the amount to add to v... 2118c2ecf20Sopenharmony_ci * @u: ...unless v is equal to u. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u. 2148c2ecf20Sopenharmony_ci * Returns the old value of @v. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_cistatic __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci int c, new, old; 2198c2ecf20Sopenharmony_ci smp_mb(); 2208c2ecf20Sopenharmony_ci __asm__ __volatile__( 2218c2ecf20Sopenharmony_ci "1: ldl_l %[old],%[mem]\n" 2228c2ecf20Sopenharmony_ci " cmpeq %[old],%[u],%[c]\n" 2238c2ecf20Sopenharmony_ci " addl %[old],%[a],%[new]\n" 2248c2ecf20Sopenharmony_ci " bne %[c],2f\n" 2258c2ecf20Sopenharmony_ci " stl_c %[new],%[mem]\n" 2268c2ecf20Sopenharmony_ci " beq %[new],3f\n" 2278c2ecf20Sopenharmony_ci "2:\n" 2288c2ecf20Sopenharmony_ci ".subsection 2\n" 2298c2ecf20Sopenharmony_ci "3: br 1b\n" 2308c2ecf20Sopenharmony_ci ".previous" 2318c2ecf20Sopenharmony_ci : [old] "=&r"(old), [new] "=&r"(new), [c] "=&r"(c) 2328c2ecf20Sopenharmony_ci : [mem] "m"(*v), [a] "rI"(a), [u] "rI"((long)u) 2338c2ecf20Sopenharmony_ci : "memory"); 2348c2ecf20Sopenharmony_ci smp_mb(); 2358c2ecf20Sopenharmony_ci return old; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci#define atomic_fetch_add_unless atomic_fetch_add_unless 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * atomic64_fetch_add_unless - add unless the number is a given value 2418c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t 2428c2ecf20Sopenharmony_ci * @a: the amount to add to v... 2438c2ecf20Sopenharmony_ci * @u: ...unless v is equal to u. 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u. 2468c2ecf20Sopenharmony_ci * Returns the old value of @v. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci s64 c, new, old; 2518c2ecf20Sopenharmony_ci smp_mb(); 2528c2ecf20Sopenharmony_ci __asm__ __volatile__( 2538c2ecf20Sopenharmony_ci "1: ldq_l %[old],%[mem]\n" 2548c2ecf20Sopenharmony_ci " cmpeq %[old],%[u],%[c]\n" 2558c2ecf20Sopenharmony_ci " addq %[old],%[a],%[new]\n" 2568c2ecf20Sopenharmony_ci " bne %[c],2f\n" 2578c2ecf20Sopenharmony_ci " stq_c %[new],%[mem]\n" 2588c2ecf20Sopenharmony_ci " beq %[new],3f\n" 2598c2ecf20Sopenharmony_ci "2:\n" 2608c2ecf20Sopenharmony_ci ".subsection 2\n" 2618c2ecf20Sopenharmony_ci "3: br 1b\n" 2628c2ecf20Sopenharmony_ci ".previous" 2638c2ecf20Sopenharmony_ci : [old] "=&r"(old), [new] "=&r"(new), [c] "=&r"(c) 2648c2ecf20Sopenharmony_ci : [mem] "m"(*v), [a] "rI"(a), [u] "rI"(u) 2658c2ecf20Sopenharmony_ci : "memory"); 2668c2ecf20Sopenharmony_ci smp_mb(); 2678c2ecf20Sopenharmony_ci return old; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci#define atomic64_fetch_add_unless atomic64_fetch_add_unless 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* 2728c2ecf20Sopenharmony_ci * atomic64_dec_if_positive - decrement by 1 if old value positive 2738c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * The function returns the old value of *v minus 1, even if 2768c2ecf20Sopenharmony_ci * the atomic variable, v, was not decremented. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_cistatic inline s64 atomic64_dec_if_positive(atomic64_t *v) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci s64 old, tmp; 2818c2ecf20Sopenharmony_ci smp_mb(); 2828c2ecf20Sopenharmony_ci __asm__ __volatile__( 2838c2ecf20Sopenharmony_ci "1: ldq_l %[old],%[mem]\n" 2848c2ecf20Sopenharmony_ci " subq %[old],1,%[tmp]\n" 2858c2ecf20Sopenharmony_ci " ble %[old],2f\n" 2868c2ecf20Sopenharmony_ci " stq_c %[tmp],%[mem]\n" 2878c2ecf20Sopenharmony_ci " beq %[tmp],3f\n" 2888c2ecf20Sopenharmony_ci "2:\n" 2898c2ecf20Sopenharmony_ci ".subsection 2\n" 2908c2ecf20Sopenharmony_ci "3: br 1b\n" 2918c2ecf20Sopenharmony_ci ".previous" 2928c2ecf20Sopenharmony_ci : [old] "=&r"(old), [tmp] "=&r"(tmp) 2938c2ecf20Sopenharmony_ci : [mem] "m"(*v) 2948c2ecf20Sopenharmony_ci : "memory"); 2958c2ecf20Sopenharmony_ci smp_mb(); 2968c2ecf20Sopenharmony_ci return old - 1; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci#define atomic64_dec_if_positive atomic64_dec_if_positive 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci#endif /* _ALPHA_ATOMIC_H */ 301