18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us. Useful for 48c2ecf20Sopenharmony_ci * resource counting etc.. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * But use these as seldom as possible since they are much more slower 78c2ecf20Sopenharmony_ci * than regular operations. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 108c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 118c2ecf20Sopenharmony_ci * for more details. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright (C) 2020 Loongson Technology Corporation Limited 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci#ifndef _ASM_ATOMIC_H 168c2ecf20Sopenharmony_ci#define _ASM_ATOMIC_H 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <asm/barrier.h> 208c2ecf20Sopenharmony_ci#include <asm/cpu-features.h> 218c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#if __SIZEOF_LONG__ == 4 248c2ecf20Sopenharmony_ci#define __LL "ll.w " 258c2ecf20Sopenharmony_ci#define __SC "sc.w " 268c2ecf20Sopenharmony_ci#define __AMADD "amadd.w " 278c2ecf20Sopenharmony_ci#define __AMAND_DB "amand_db.w " 288c2ecf20Sopenharmony_ci#define __AMOR_DB "amor_db.w " 298c2ecf20Sopenharmony_ci#define __AMXOR_DB "amxor_db.w " 308c2ecf20Sopenharmony_ci#elif __SIZEOF_LONG__ == 8 318c2ecf20Sopenharmony_ci#define __LL "ll.d " 328c2ecf20Sopenharmony_ci#define __SC "sc.d " 338c2ecf20Sopenharmony_ci#define __AMADD "amadd.d " 348c2ecf20Sopenharmony_ci#define __AMAND_DB "amand_db.d " 358c2ecf20Sopenharmony_ci#define __AMOR_DB "amor_db.d " 368c2ecf20Sopenharmony_ci#define __AMXOR_DB "amxor_db.d " 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define ATOMIC_INIT(i) { (i) } 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * atomic_read - read atomic variable 438c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Atomically reads the value of @v. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define atomic_read(v) READ_ONCE((v)->counter) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * atomic_set - set atomic variable 518c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 528c2ecf20Sopenharmony_ci * @i: required value 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Atomically sets the value of @v to @i. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci#define atomic_set(v, i) WRITE_ONCE((v)->counter, (i)) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, I, asm_op) \ 598c2ecf20Sopenharmony_cistatic __inline__ void atomic_##op(int i, atomic_t * v) \ 608c2ecf20Sopenharmony_ci{ \ 618c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 628c2ecf20Sopenharmony_ci "am"#asm_op".w" " $zero, %1, %0 \n" \ 638c2ecf20Sopenharmony_ci : "+ZB" (v->counter) \ 648c2ecf20Sopenharmony_ci : "r" (I) \ 658c2ecf20Sopenharmony_ci : "memory"); \ 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \ 698c2ecf20Sopenharmony_cistatic __inline__ int atomic_##op##_return##suffix(int i, atomic_t * v) \ 708c2ecf20Sopenharmony_ci{ \ 718c2ecf20Sopenharmony_ci int result; \ 728c2ecf20Sopenharmony_ci \ 738c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 748c2ecf20Sopenharmony_ci "am"#asm_op#mb".w" " %1, %2, %0 \n" \ 758c2ecf20Sopenharmony_ci : "+ZB" (v->counter), "=&r" (result) \ 768c2ecf20Sopenharmony_ci : "r" (I) \ 778c2ecf20Sopenharmony_ci : "memory"); \ 788c2ecf20Sopenharmony_ci \ 798c2ecf20Sopenharmony_ci return result c_op I; \ 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, I, asm_op, mb, suffix) \ 838c2ecf20Sopenharmony_cistatic __inline__ int atomic_fetch_##op##suffix(int i, atomic_t * v) \ 848c2ecf20Sopenharmony_ci{ \ 858c2ecf20Sopenharmony_ci int result; \ 868c2ecf20Sopenharmony_ci \ 878c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 888c2ecf20Sopenharmony_ci "am"#asm_op#mb".w" " %1, %2, %0 \n" \ 898c2ecf20Sopenharmony_ci : "+ZB" (v->counter), "=&r" (result) \ 908c2ecf20Sopenharmony_ci : "r" (I) \ 918c2ecf20Sopenharmony_ci : "memory"); \ 928c2ecf20Sopenharmony_ci \ 938c2ecf20Sopenharmony_ci return result; \ 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, I, asm_op, c_op) \ 978c2ecf20Sopenharmony_ci ATOMIC_OP(op, I, asm_op) \ 988c2ecf20Sopenharmony_ci ATOMIC_OP_RETURN(op, I, asm_op, c_op, _db, ) \ 998c2ecf20Sopenharmony_ci ATOMIC_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \ 1008c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \ 1018c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciATOMIC_OPS(add, i, add, +) 1048c2ecf20Sopenharmony_ciATOMIC_OPS(sub, -i, add, +) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define atomic_add_return atomic_add_return 1078c2ecf20Sopenharmony_ci#define atomic_add_return_acquire atomic_add_return 1088c2ecf20Sopenharmony_ci#define atomic_add_return_release atomic_add_return 1098c2ecf20Sopenharmony_ci#define atomic_add_return_relaxed atomic_add_return_relaxed 1108c2ecf20Sopenharmony_ci#define atomic_sub_return atomic_sub_return 1118c2ecf20Sopenharmony_ci#define atomic_sub_return_acquire atomic_sub_return 1128c2ecf20Sopenharmony_ci#define atomic_sub_return_release atomic_sub_return 1138c2ecf20Sopenharmony_ci#define atomic_sub_return_relaxed atomic_sub_return_relaxed 1148c2ecf20Sopenharmony_ci#define atomic_fetch_add atomic_fetch_add 1158c2ecf20Sopenharmony_ci#define atomic_fetch_add_acquire atomic_fetch_add 1168c2ecf20Sopenharmony_ci#define atomic_fetch_add_release atomic_fetch_add 1178c2ecf20Sopenharmony_ci#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed 1188c2ecf20Sopenharmony_ci#define atomic_fetch_sub atomic_fetch_sub 1198c2ecf20Sopenharmony_ci#define atomic_fetch_sub_acquire atomic_fetch_sub 1208c2ecf20Sopenharmony_ci#define atomic_fetch_sub_release atomic_fetch_sub 1218c2ecf20Sopenharmony_ci#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, I, asm_op) \ 1268c2ecf20Sopenharmony_ci ATOMIC_OP(op, I, asm_op) \ 1278c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \ 1288c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciATOMIC_OPS(and, i, and) 1318c2ecf20Sopenharmony_ciATOMIC_OPS(or, i, or) 1328c2ecf20Sopenharmony_ciATOMIC_OPS(xor, i, xor) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define atomic_fetch_and atomic_fetch_and 1358c2ecf20Sopenharmony_ci#define atomic_fetch_and_acquire atomic_fetch_and 1368c2ecf20Sopenharmony_ci#define atomic_fetch_and_release atomic_fetch_and 1378c2ecf20Sopenharmony_ci#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed 1388c2ecf20Sopenharmony_ci#define atomic_fetch_or atomic_fetch_or 1398c2ecf20Sopenharmony_ci#define atomic_fetch_or_acquire atomic_fetch_or 1408c2ecf20Sopenharmony_ci#define atomic_fetch_or_release atomic_fetch_or 1418c2ecf20Sopenharmony_ci#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed 1428c2ecf20Sopenharmony_ci#define atomic_fetch_xor atomic_fetch_xor 1438c2ecf20Sopenharmony_ci#define atomic_fetch_xor_acquire atomic_fetch_xor 1448c2ecf20Sopenharmony_ci#define atomic_fetch_xor_release atomic_fetch_xor 1458c2ecf20Sopenharmony_ci#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 1488c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP 1498c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN 1508c2ecf20Sopenharmony_ci#undef ATOMIC_OP 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci int prev, rc; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 1578c2ecf20Sopenharmony_ci "0: ll.w %[p], %[c]\n" 1588c2ecf20Sopenharmony_ci " beq %[p], %[u], 1f\n" 1598c2ecf20Sopenharmony_ci " add.w %[rc], %[p], %[a]\n" 1608c2ecf20Sopenharmony_ci " sc.w %[rc], %[c]\n" 1618c2ecf20Sopenharmony_ci " beqz %[rc], 0b\n" 1628c2ecf20Sopenharmony_ci " b 2f\n" 1638c2ecf20Sopenharmony_ci "1:\n" 1648c2ecf20Sopenharmony_ci __WEAK_LLSC_MB 1658c2ecf20Sopenharmony_ci "2:\n" 1668c2ecf20Sopenharmony_ci : [p]"=&r" (prev), [rc]"=&r" (rc), 1678c2ecf20Sopenharmony_ci [c]"=ZB" (v->counter) 1688c2ecf20Sopenharmony_ci : [a]"r" (a), [u]"r" (u) 1698c2ecf20Sopenharmony_ci : "memory"); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return prev; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci#define atomic_fetch_add_unless atomic_fetch_add_unless 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * atomic_sub_if_positive - conditionally subtract integer from atomic variable 1778c2ecf20Sopenharmony_ci * @i: integer value to subtract 1788c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * Atomically test @v and subtract @i if @v is greater or equal than @i. 1818c2ecf20Sopenharmony_ci * The function returns the old value of @v minus @i. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_cistatic __inline__ int atomic_sub_if_positive(int i, atomic_t * v) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int result; 1868c2ecf20Sopenharmony_ci int temp; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (__builtin_constant_p(i)) { 1898c2ecf20Sopenharmony_ci __asm__ __volatile__( 1908c2ecf20Sopenharmony_ci "1: ll.w %1, %2 # atomic_sub_if_positive\n" 1918c2ecf20Sopenharmony_ci " addi.w %0, %1, %3 \n" 1928c2ecf20Sopenharmony_ci " or %1, %0, $zero \n" 1938c2ecf20Sopenharmony_ci " blt %0, $zero, 2f \n" 1948c2ecf20Sopenharmony_ci " sc.w %1, %2 \n" 1958c2ecf20Sopenharmony_ci " beq $zero, %1, 1b \n" 1968c2ecf20Sopenharmony_ci "2: \n" 1978c2ecf20Sopenharmony_ci __WEAK_LLSC_MB 1988c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (temp), "+ZC" (v->counter) 1998c2ecf20Sopenharmony_ci : "I" (-i)); 2008c2ecf20Sopenharmony_ci } else { 2018c2ecf20Sopenharmony_ci __asm__ __volatile__( 2028c2ecf20Sopenharmony_ci "1: ll.w %1, %2 # atomic_sub_if_positive\n" 2038c2ecf20Sopenharmony_ci " sub.w %0, %1, %3 \n" 2048c2ecf20Sopenharmony_ci " or %1, %0, $zero \n" 2058c2ecf20Sopenharmony_ci " blt %0, $zero, 2f \n" 2068c2ecf20Sopenharmony_ci " sc.w %1, %2 \n" 2078c2ecf20Sopenharmony_ci " beq $zero, %1, 1b \n" 2088c2ecf20Sopenharmony_ci "2: \n" 2098c2ecf20Sopenharmony_ci __WEAK_LLSC_MB 2108c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (temp), "+ZC" (v->counter) 2118c2ecf20Sopenharmony_ci : "r" (i)); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return result; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) 2188c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* 2218c2ecf20Sopenharmony_ci * atomic_dec_if_positive - decrement by 1 if old value positive 2228c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci#define ATOMIC64_INIT(i) { (i) } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* 2318c2ecf20Sopenharmony_ci * atomic64_read - read atomic variable 2328c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci#define atomic64_read(v) READ_ONCE((v)->counter) 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * atomic64_set - set atomic variable 2398c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t 2408c2ecf20Sopenharmony_ci * @i: required value 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci#define atomic64_set(v, i) WRITE_ONCE((v)->counter, (i)) 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op, I, asm_op) \ 2458c2ecf20Sopenharmony_cistatic __inline__ void atomic64_##op(long i, atomic64_t * v) \ 2468c2ecf20Sopenharmony_ci{ \ 2478c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 2488c2ecf20Sopenharmony_ci "am"#asm_op".d " " $zero, %1, %0 \n" \ 2498c2ecf20Sopenharmony_ci : "+ZB" (v->counter) \ 2508c2ecf20Sopenharmony_ci : "r" (I) \ 2518c2ecf20Sopenharmony_ci : "memory"); \ 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#define ATOMIC64_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \ 2558c2ecf20Sopenharmony_cistatic __inline__ long atomic64_##op##_return##suffix(long i, atomic64_t * v) \ 2568c2ecf20Sopenharmony_ci{ \ 2578c2ecf20Sopenharmony_ci long result; \ 2588c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 2598c2ecf20Sopenharmony_ci "am"#asm_op#mb".d " " %1, %2, %0 \n" \ 2608c2ecf20Sopenharmony_ci : "+ZB" (v->counter), "=&r" (result) \ 2618c2ecf20Sopenharmony_ci : "r" (I) \ 2628c2ecf20Sopenharmony_ci : "memory"); \ 2638c2ecf20Sopenharmony_ci \ 2648c2ecf20Sopenharmony_ci return result c_op I; \ 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP(op, I, asm_op, mb, suffix) \ 2688c2ecf20Sopenharmony_cistatic __inline__ long atomic64_fetch_##op##suffix(long i, atomic64_t * v) \ 2698c2ecf20Sopenharmony_ci{ \ 2708c2ecf20Sopenharmony_ci long result; \ 2718c2ecf20Sopenharmony_ci \ 2728c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 2738c2ecf20Sopenharmony_ci "am"#asm_op#mb".d " " %1, %2, %0 \n" \ 2748c2ecf20Sopenharmony_ci : "+ZB" (v->counter), "=&r" (result) \ 2758c2ecf20Sopenharmony_ci : "r" (I) \ 2768c2ecf20Sopenharmony_ci : "memory"); \ 2778c2ecf20Sopenharmony_ci \ 2788c2ecf20Sopenharmony_ci return result; \ 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, I, asm_op, c_op) \ 2828c2ecf20Sopenharmony_ci ATOMIC64_OP(op, I, asm_op) \ 2838c2ecf20Sopenharmony_ci ATOMIC64_OP_RETURN(op, I, asm_op, c_op, _db, ) \ 2848c2ecf20Sopenharmony_ci ATOMIC64_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \ 2858c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \ 2868c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed) 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ciATOMIC64_OPS(add, i, add, +) 2898c2ecf20Sopenharmony_ciATOMIC64_OPS(sub, -i, add, +) 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci#define atomic64_add_return atomic64_add_return 2928c2ecf20Sopenharmony_ci#define atomic64_add_return_acquire atomic64_add_return 2938c2ecf20Sopenharmony_ci#define atomic64_add_return_release atomic64_add_return 2948c2ecf20Sopenharmony_ci#define atomic64_add_return_relaxed atomic64_add_return_relaxed 2958c2ecf20Sopenharmony_ci#define atomic64_sub_return atomic64_sub_return 2968c2ecf20Sopenharmony_ci#define atomic64_sub_return_acquire atomic64_sub_return 2978c2ecf20Sopenharmony_ci#define atomic64_sub_return_release atomic64_sub_return 2988c2ecf20Sopenharmony_ci#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed 2998c2ecf20Sopenharmony_ci#define atomic64_fetch_add atomic64_fetch_add 3008c2ecf20Sopenharmony_ci#define atomic64_fetch_add_acquire atomic64_fetch_add 3018c2ecf20Sopenharmony_ci#define atomic64_fetch_add_release atomic64_fetch_add 3028c2ecf20Sopenharmony_ci#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed 3038c2ecf20Sopenharmony_ci#define atomic64_fetch_sub atomic64_fetch_sub 3048c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_acquire atomic64_fetch_sub 3058c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_release atomic64_fetch_sub 3068c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, I, asm_op) \ 3118c2ecf20Sopenharmony_ci ATOMIC64_OP(op, I, asm_op) \ 3128c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \ 3138c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed) 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ciATOMIC64_OPS(and, i, and) 3168c2ecf20Sopenharmony_ciATOMIC64_OPS(or, i, or) 3178c2ecf20Sopenharmony_ciATOMIC64_OPS(xor, i, xor) 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci#define atomic64_fetch_and atomic64_fetch_and 3208c2ecf20Sopenharmony_ci#define atomic64_fetch_and_acquire atomic64_fetch_and 3218c2ecf20Sopenharmony_ci#define atomic64_fetch_and_release atomic64_fetch_and 3228c2ecf20Sopenharmony_ci#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed 3238c2ecf20Sopenharmony_ci#define atomic64_fetch_or atomic64_fetch_or 3248c2ecf20Sopenharmony_ci#define atomic64_fetch_or_acquire atomic64_fetch_or 3258c2ecf20Sopenharmony_ci#define atomic64_fetch_or_release atomic64_fetch_or 3268c2ecf20Sopenharmony_ci#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed 3278c2ecf20Sopenharmony_ci#define atomic64_fetch_xor atomic64_fetch_xor 3288c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_acquire atomic64_fetch_xor 3298c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_release atomic64_fetch_xor 3308c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS 3338c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP 3348c2ecf20Sopenharmony_ci#undef ATOMIC64_OP_RETURN 3358c2ecf20Sopenharmony_ci#undef ATOMIC64_OP 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci long prev, rc; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 3428c2ecf20Sopenharmony_ci "0: ll.d %[p], %[c]\n" 3438c2ecf20Sopenharmony_ci " beq %[p], %[u], 1f\n" 3448c2ecf20Sopenharmony_ci " add.d %[rc], %[p], %[a]\n" 3458c2ecf20Sopenharmony_ci " sc.d %[rc], %[c]\n" 3468c2ecf20Sopenharmony_ci " beqz %[rc], 0b\n" 3478c2ecf20Sopenharmony_ci " b 2f\n" 3488c2ecf20Sopenharmony_ci "1:\n" 3498c2ecf20Sopenharmony_ci __WEAK_LLSC_MB 3508c2ecf20Sopenharmony_ci "2:\n" 3518c2ecf20Sopenharmony_ci : [p]"=&r" (prev), [rc]"=&r" (rc), 3528c2ecf20Sopenharmony_ci [c] "=ZB" (v->counter) 3538c2ecf20Sopenharmony_ci : [a]"r" (a), [u]"r" (u) 3548c2ecf20Sopenharmony_ci : "memory"); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return prev; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci#define atomic64_fetch_add_unless atomic64_fetch_add_unless 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* 3618c2ecf20Sopenharmony_ci * atomic64_sub_if_positive - conditionally subtract integer from atomic 3628c2ecf20Sopenharmony_ci * variable 3638c2ecf20Sopenharmony_ci * @i: integer value to subtract 3648c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t 3658c2ecf20Sopenharmony_ci * 3668c2ecf20Sopenharmony_ci * Atomically test @v and subtract @i if @v is greater or equal than @i. 3678c2ecf20Sopenharmony_ci * The function returns the old value of @v minus @i. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_cistatic __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci long result; 3728c2ecf20Sopenharmony_ci long temp; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (__builtin_constant_p(i)) { 3758c2ecf20Sopenharmony_ci __asm__ __volatile__( 3768c2ecf20Sopenharmony_ci "1: ll.d %1, %2 # atomic64_sub_if_positive \n" 3778c2ecf20Sopenharmony_ci " addi.d %0, %1, %3 \n" 3788c2ecf20Sopenharmony_ci " or %1, %0, $zero \n" 3798c2ecf20Sopenharmony_ci " blt %0, $zero, 2f \n" 3808c2ecf20Sopenharmony_ci " sc.d %1, %2 \n" 3818c2ecf20Sopenharmony_ci " beq %1, $zero, 1b \n" 3828c2ecf20Sopenharmony_ci "2: \n" 3838c2ecf20Sopenharmony_ci __WEAK_LLSC_MB 3848c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (temp), "+ZC" (v->counter) 3858c2ecf20Sopenharmony_ci : "I" (-i)); 3868c2ecf20Sopenharmony_ci } else { 3878c2ecf20Sopenharmony_ci __asm__ __volatile__( 3888c2ecf20Sopenharmony_ci "1: ll.d %1, %2 # atomic64_sub_if_positive \n" 3898c2ecf20Sopenharmony_ci " sub.d %0, %1, %3 \n" 3908c2ecf20Sopenharmony_ci " or %1, %0, $zero \n" 3918c2ecf20Sopenharmony_ci " blt %0, $zero, 2f \n" 3928c2ecf20Sopenharmony_ci " sc.d %1, %2 \n" 3938c2ecf20Sopenharmony_ci " beq %1, $zero, 1b \n" 3948c2ecf20Sopenharmony_ci "2: \n" 3958c2ecf20Sopenharmony_ci __WEAK_LLSC_MB 3968c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (temp), "+ZC" (v->counter) 3978c2ecf20Sopenharmony_ci : "r" (i)); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return result; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci#define atomic64_cmpxchg(v, o, n) \ 4048c2ecf20Sopenharmony_ci ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) 4058c2ecf20Sopenharmony_ci#define atomic64_xchg(v, new) (xchg(&((v)->counter), (new))) 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci/* 4088c2ecf20Sopenharmony_ci * atomic64_dec_if_positive - decrement by 1 if old value positive 4098c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci#define atomic64_dec_if_positive(v) atomic64_sub_if_positive(1, v) 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci#endif /* CONFIG_64BIT */ 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci#endif /* _ASM_ATOMIC_H */ 416