18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/include/asm/atomic.h 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1996 Russell King. 68c2ecf20Sopenharmony_ci * Copyright (C) 2002 Deep Blue Solutions Ltd. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#ifndef __ASM_ARM_ATOMIC_H 98c2ecf20Sopenharmony_ci#define __ASM_ARM_ATOMIC_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/compiler.h> 128c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/irqflags.h> 158c2ecf20Sopenharmony_ci#include <asm/barrier.h> 168c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#ifdef __KERNEL__ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * On ARM, ordinary assignment (str instruction) doesn't clear the local 228c2ecf20Sopenharmony_ci * strex/ldrex monitor on some implementations. The reason we can use it for 238c2ecf20Sopenharmony_ci * atomic_set() is the clrex or dummy strex done on every exception return. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci#define atomic_read(v) READ_ONCE((v)->counter) 268c2ecf20Sopenharmony_ci#define atomic_set(v,i) WRITE_ONCE(((v)->counter), (i)) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * ARMv6 UP and SMP safe atomic ops. We use load exclusive and 328c2ecf20Sopenharmony_ci * store exclusive to ensure that these are atomic. We may loop 338c2ecf20Sopenharmony_ci * to ensure that the update happens. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, c_op, asm_op) \ 378c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v) \ 388c2ecf20Sopenharmony_ci{ \ 398c2ecf20Sopenharmony_ci unsigned long tmp; \ 408c2ecf20Sopenharmony_ci int result; \ 418c2ecf20Sopenharmony_ci \ 428c2ecf20Sopenharmony_ci prefetchw(&v->counter); \ 438c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic_" #op "\n" \ 448c2ecf20Sopenharmony_ci"1: ldrex %0, [%3]\n" \ 458c2ecf20Sopenharmony_ci" " #asm_op " %0, %0, %4\n" \ 468c2ecf20Sopenharmony_ci" strex %1, %0, [%3]\n" \ 478c2ecf20Sopenharmony_ci" teq %1, #0\n" \ 488c2ecf20Sopenharmony_ci" bne 1b" \ 498c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ 508c2ecf20Sopenharmony_ci : "r" (&v->counter), "Ir" (i) \ 518c2ecf20Sopenharmony_ci : "cc"); \ 528c2ecf20Sopenharmony_ci} \ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ 558c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return_relaxed(int i, atomic_t *v) \ 568c2ecf20Sopenharmony_ci{ \ 578c2ecf20Sopenharmony_ci unsigned long tmp; \ 588c2ecf20Sopenharmony_ci int result; \ 598c2ecf20Sopenharmony_ci \ 608c2ecf20Sopenharmony_ci prefetchw(&v->counter); \ 618c2ecf20Sopenharmony_ci \ 628c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic_" #op "_return\n" \ 638c2ecf20Sopenharmony_ci"1: ldrex %0, [%3]\n" \ 648c2ecf20Sopenharmony_ci" " #asm_op " %0, %0, %4\n" \ 658c2ecf20Sopenharmony_ci" strex %1, %0, [%3]\n" \ 668c2ecf20Sopenharmony_ci" teq %1, #0\n" \ 678c2ecf20Sopenharmony_ci" bne 1b" \ 688c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ 698c2ecf20Sopenharmony_ci : "r" (&v->counter), "Ir" (i) \ 708c2ecf20Sopenharmony_ci : "cc"); \ 718c2ecf20Sopenharmony_ci \ 728c2ecf20Sopenharmony_ci return result; \ 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ 768c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v) \ 778c2ecf20Sopenharmony_ci{ \ 788c2ecf20Sopenharmony_ci unsigned long tmp; \ 798c2ecf20Sopenharmony_ci int result, val; \ 808c2ecf20Sopenharmony_ci \ 818c2ecf20Sopenharmony_ci prefetchw(&v->counter); \ 828c2ecf20Sopenharmony_ci \ 838c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic_fetch_" #op "\n" \ 848c2ecf20Sopenharmony_ci"1: ldrex %0, [%4]\n" \ 858c2ecf20Sopenharmony_ci" " #asm_op " %1, %0, %5\n" \ 868c2ecf20Sopenharmony_ci" strex %2, %1, [%4]\n" \ 878c2ecf20Sopenharmony_ci" teq %2, #0\n" \ 888c2ecf20Sopenharmony_ci" bne 1b" \ 898c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Qo" (v->counter) \ 908c2ecf20Sopenharmony_ci : "r" (&v->counter), "Ir" (i) \ 918c2ecf20Sopenharmony_ci : "cc"); \ 928c2ecf20Sopenharmony_ci \ 938c2ecf20Sopenharmony_ci return result; \ 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define atomic_add_return_relaxed atomic_add_return_relaxed 978c2ecf20Sopenharmony_ci#define atomic_sub_return_relaxed atomic_sub_return_relaxed 988c2ecf20Sopenharmony_ci#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed 998c2ecf20Sopenharmony_ci#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed 1028c2ecf20Sopenharmony_ci#define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed 1038c2ecf20Sopenharmony_ci#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed 1048c2ecf20Sopenharmony_ci#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic inline int atomic_cmpxchg_relaxed(atomic_t *ptr, int old, int new) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int oldval; 1098c2ecf20Sopenharmony_ci unsigned long res; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci prefetchw(&ptr->counter); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci do { 1148c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic_cmpxchg\n" 1158c2ecf20Sopenharmony_ci "ldrex %1, [%3]\n" 1168c2ecf20Sopenharmony_ci "mov %0, #0\n" 1178c2ecf20Sopenharmony_ci "teq %1, %4\n" 1188c2ecf20Sopenharmony_ci "strexeq %0, %5, [%3]\n" 1198c2ecf20Sopenharmony_ci : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) 1208c2ecf20Sopenharmony_ci : "r" (&ptr->counter), "Ir" (old), "r" (new) 1218c2ecf20Sopenharmony_ci : "cc"); 1228c2ecf20Sopenharmony_ci } while (res); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return oldval; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci#define atomic_cmpxchg_relaxed atomic_cmpxchg_relaxed 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic inline int atomic_fetch_add_unless(atomic_t *v, int a, int u) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci int oldval, newval; 1318c2ecf20Sopenharmony_ci unsigned long tmp; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci smp_mb(); 1348c2ecf20Sopenharmony_ci prefetchw(&v->counter); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci __asm__ __volatile__ ("@ atomic_add_unless\n" 1378c2ecf20Sopenharmony_ci"1: ldrex %0, [%4]\n" 1388c2ecf20Sopenharmony_ci" teq %0, %5\n" 1398c2ecf20Sopenharmony_ci" beq 2f\n" 1408c2ecf20Sopenharmony_ci" add %1, %0, %6\n" 1418c2ecf20Sopenharmony_ci" strex %2, %1, [%4]\n" 1428c2ecf20Sopenharmony_ci" teq %2, #0\n" 1438c2ecf20Sopenharmony_ci" bne 1b\n" 1448c2ecf20Sopenharmony_ci"2:" 1458c2ecf20Sopenharmony_ci : "=&r" (oldval), "=&r" (newval), "=&r" (tmp), "+Qo" (v->counter) 1468c2ecf20Sopenharmony_ci : "r" (&v->counter), "r" (u), "r" (a) 1478c2ecf20Sopenharmony_ci : "cc"); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (oldval != u) 1508c2ecf20Sopenharmony_ci smp_mb(); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return oldval; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci#define atomic_fetch_add_unless atomic_fetch_add_unless 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#else /* ARM_ARCH_6 */ 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 1598c2ecf20Sopenharmony_ci#error SMP not supported on pre-ARMv6 CPUs 1608c2ecf20Sopenharmony_ci#endif 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, c_op, asm_op) \ 1638c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v) \ 1648c2ecf20Sopenharmony_ci{ \ 1658c2ecf20Sopenharmony_ci unsigned long flags; \ 1668c2ecf20Sopenharmony_ci \ 1678c2ecf20Sopenharmony_ci raw_local_irq_save(flags); \ 1688c2ecf20Sopenharmony_ci v->counter c_op i; \ 1698c2ecf20Sopenharmony_ci raw_local_irq_restore(flags); \ 1708c2ecf20Sopenharmony_ci} \ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ 1738c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v) \ 1748c2ecf20Sopenharmony_ci{ \ 1758c2ecf20Sopenharmony_ci unsigned long flags; \ 1768c2ecf20Sopenharmony_ci int val; \ 1778c2ecf20Sopenharmony_ci \ 1788c2ecf20Sopenharmony_ci raw_local_irq_save(flags); \ 1798c2ecf20Sopenharmony_ci v->counter c_op i; \ 1808c2ecf20Sopenharmony_ci val = v->counter; \ 1818c2ecf20Sopenharmony_ci raw_local_irq_restore(flags); \ 1828c2ecf20Sopenharmony_ci \ 1838c2ecf20Sopenharmony_ci return val; \ 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ 1878c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v) \ 1888c2ecf20Sopenharmony_ci{ \ 1898c2ecf20Sopenharmony_ci unsigned long flags; \ 1908c2ecf20Sopenharmony_ci int val; \ 1918c2ecf20Sopenharmony_ci \ 1928c2ecf20Sopenharmony_ci raw_local_irq_save(flags); \ 1938c2ecf20Sopenharmony_ci val = v->counter; \ 1948c2ecf20Sopenharmony_ci v->counter c_op i; \ 1958c2ecf20Sopenharmony_ci raw_local_irq_restore(flags); \ 1968c2ecf20Sopenharmony_ci \ 1978c2ecf20Sopenharmony_ci return val; \ 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic inline int atomic_cmpxchg(atomic_t *v, int old, int new) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci int ret; 2038c2ecf20Sopenharmony_ci unsigned long flags; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci raw_local_irq_save(flags); 2068c2ecf20Sopenharmony_ci ret = v->counter; 2078c2ecf20Sopenharmony_ci if (likely(ret == old)) 2088c2ecf20Sopenharmony_ci v->counter = new; 2098c2ecf20Sopenharmony_ci raw_local_irq_restore(flags); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci#define atomic_fetch_andnot atomic_fetch_andnot 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, c_op, asm_op) \ 2198c2ecf20Sopenharmony_ci ATOMIC_OP(op, c_op, asm_op) \ 2208c2ecf20Sopenharmony_ci ATOMIC_OP_RETURN(op, c_op, asm_op) \ 2218c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, c_op, asm_op) 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciATOMIC_OPS(add, +=, add) 2248c2ecf20Sopenharmony_ciATOMIC_OPS(sub, -=, sub) 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#define atomic_andnot atomic_andnot 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 2298c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, c_op, asm_op) \ 2308c2ecf20Sopenharmony_ci ATOMIC_OP(op, c_op, asm_op) \ 2318c2ecf20Sopenharmony_ci ATOMIC_FETCH_OP(op, c_op, asm_op) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciATOMIC_OPS(and, &=, and) 2348c2ecf20Sopenharmony_ciATOMIC_OPS(andnot, &= ~, bic) 2358c2ecf20Sopenharmony_ciATOMIC_OPS(or, |=, orr) 2368c2ecf20Sopenharmony_ciATOMIC_OPS(xor, ^=, eor) 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 2398c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP 2408c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN 2418c2ecf20Sopenharmony_ci#undef ATOMIC_OP 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci#ifndef CONFIG_GENERIC_ATOMIC64 2468c2ecf20Sopenharmony_citypedef struct { 2478c2ecf20Sopenharmony_ci s64 counter; 2488c2ecf20Sopenharmony_ci} atomic64_t; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci#define ATOMIC64_INIT(i) { (i) } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_LPAE 2538c2ecf20Sopenharmony_cistatic inline s64 atomic64_read(const atomic64_t *v) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci s64 result; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_read\n" 2588c2ecf20Sopenharmony_ci" ldrd %0, %H0, [%1]" 2598c2ecf20Sopenharmony_ci : "=&r" (result) 2608c2ecf20Sopenharmony_ci : "r" (&v->counter), "Qo" (v->counter) 2618c2ecf20Sopenharmony_ci ); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return result; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic inline void atomic64_set(atomic64_t *v, s64 i) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_set\n" 2698c2ecf20Sopenharmony_ci" strd %2, %H2, [%1]" 2708c2ecf20Sopenharmony_ci : "=Qo" (v->counter) 2718c2ecf20Sopenharmony_ci : "r" (&v->counter), "r" (i) 2728c2ecf20Sopenharmony_ci ); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci#else 2758c2ecf20Sopenharmony_cistatic inline s64 atomic64_read(const atomic64_t *v) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci s64 result; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_read\n" 2808c2ecf20Sopenharmony_ci" ldrexd %0, %H0, [%1]" 2818c2ecf20Sopenharmony_ci : "=&r" (result) 2828c2ecf20Sopenharmony_ci : "r" (&v->counter), "Qo" (v->counter) 2838c2ecf20Sopenharmony_ci ); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return result; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic inline void atomic64_set(atomic64_t *v, s64 i) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci s64 tmp; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci prefetchw(&v->counter); 2938c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_set\n" 2948c2ecf20Sopenharmony_ci"1: ldrexd %0, %H0, [%2]\n" 2958c2ecf20Sopenharmony_ci" strexd %0, %3, %H3, [%2]\n" 2968c2ecf20Sopenharmony_ci" teq %0, #0\n" 2978c2ecf20Sopenharmony_ci" bne 1b" 2988c2ecf20Sopenharmony_ci : "=&r" (tmp), "=Qo" (v->counter) 2998c2ecf20Sopenharmony_ci : "r" (&v->counter), "r" (i) 3008c2ecf20Sopenharmony_ci : "cc"); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci#endif 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op, op1, op2) \ 3058c2ecf20Sopenharmony_cistatic inline void atomic64_##op(s64 i, atomic64_t *v) \ 3068c2ecf20Sopenharmony_ci{ \ 3078c2ecf20Sopenharmony_ci s64 result; \ 3088c2ecf20Sopenharmony_ci unsigned long tmp; \ 3098c2ecf20Sopenharmony_ci \ 3108c2ecf20Sopenharmony_ci prefetchw(&v->counter); \ 3118c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_" #op "\n" \ 3128c2ecf20Sopenharmony_ci"1: ldrexd %0, %H0, [%3]\n" \ 3138c2ecf20Sopenharmony_ci" " #op1 " %Q0, %Q0, %Q4\n" \ 3148c2ecf20Sopenharmony_ci" " #op2 " %R0, %R0, %R4\n" \ 3158c2ecf20Sopenharmony_ci" strexd %1, %0, %H0, [%3]\n" \ 3168c2ecf20Sopenharmony_ci" teq %1, #0\n" \ 3178c2ecf20Sopenharmony_ci" bne 1b" \ 3188c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ 3198c2ecf20Sopenharmony_ci : "r" (&v->counter), "r" (i) \ 3208c2ecf20Sopenharmony_ci : "cc"); \ 3218c2ecf20Sopenharmony_ci} \ 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#define ATOMIC64_OP_RETURN(op, op1, op2) \ 3248c2ecf20Sopenharmony_cistatic inline s64 \ 3258c2ecf20Sopenharmony_ciatomic64_##op##_return_relaxed(s64 i, atomic64_t *v) \ 3268c2ecf20Sopenharmony_ci{ \ 3278c2ecf20Sopenharmony_ci s64 result; \ 3288c2ecf20Sopenharmony_ci unsigned long tmp; \ 3298c2ecf20Sopenharmony_ci \ 3308c2ecf20Sopenharmony_ci prefetchw(&v->counter); \ 3318c2ecf20Sopenharmony_ci \ 3328c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_" #op "_return\n" \ 3338c2ecf20Sopenharmony_ci"1: ldrexd %0, %H0, [%3]\n" \ 3348c2ecf20Sopenharmony_ci" " #op1 " %Q0, %Q0, %Q4\n" \ 3358c2ecf20Sopenharmony_ci" " #op2 " %R0, %R0, %R4\n" \ 3368c2ecf20Sopenharmony_ci" strexd %1, %0, %H0, [%3]\n" \ 3378c2ecf20Sopenharmony_ci" teq %1, #0\n" \ 3388c2ecf20Sopenharmony_ci" bne 1b" \ 3398c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ 3408c2ecf20Sopenharmony_ci : "r" (&v->counter), "r" (i) \ 3418c2ecf20Sopenharmony_ci : "cc"); \ 3428c2ecf20Sopenharmony_ci \ 3438c2ecf20Sopenharmony_ci return result; \ 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP(op, op1, op2) \ 3478c2ecf20Sopenharmony_cistatic inline s64 \ 3488c2ecf20Sopenharmony_ciatomic64_fetch_##op##_relaxed(s64 i, atomic64_t *v) \ 3498c2ecf20Sopenharmony_ci{ \ 3508c2ecf20Sopenharmony_ci s64 result, val; \ 3518c2ecf20Sopenharmony_ci unsigned long tmp; \ 3528c2ecf20Sopenharmony_ci \ 3538c2ecf20Sopenharmony_ci prefetchw(&v->counter); \ 3548c2ecf20Sopenharmony_ci \ 3558c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_fetch_" #op "\n" \ 3568c2ecf20Sopenharmony_ci"1: ldrexd %0, %H0, [%4]\n" \ 3578c2ecf20Sopenharmony_ci" " #op1 " %Q1, %Q0, %Q5\n" \ 3588c2ecf20Sopenharmony_ci" " #op2 " %R1, %R0, %R5\n" \ 3598c2ecf20Sopenharmony_ci" strexd %2, %1, %H1, [%4]\n" \ 3608c2ecf20Sopenharmony_ci" teq %2, #0\n" \ 3618c2ecf20Sopenharmony_ci" bne 1b" \ 3628c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Qo" (v->counter) \ 3638c2ecf20Sopenharmony_ci : "r" (&v->counter), "r" (i) \ 3648c2ecf20Sopenharmony_ci : "cc"); \ 3658c2ecf20Sopenharmony_ci \ 3668c2ecf20Sopenharmony_ci return result; \ 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, op1, op2) \ 3708c2ecf20Sopenharmony_ci ATOMIC64_OP(op, op1, op2) \ 3718c2ecf20Sopenharmony_ci ATOMIC64_OP_RETURN(op, op1, op2) \ 3728c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, op1, op2) 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ciATOMIC64_OPS(add, adds, adc) 3758c2ecf20Sopenharmony_ciATOMIC64_OPS(sub, subs, sbc) 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci#define atomic64_add_return_relaxed atomic64_add_return_relaxed 3788c2ecf20Sopenharmony_ci#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed 3798c2ecf20Sopenharmony_ci#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed 3808c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS 3838c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, op1, op2) \ 3848c2ecf20Sopenharmony_ci ATOMIC64_OP(op, op1, op2) \ 3858c2ecf20Sopenharmony_ci ATOMIC64_FETCH_OP(op, op1, op2) 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci#define atomic64_andnot atomic64_andnot 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ciATOMIC64_OPS(and, and, and) 3908c2ecf20Sopenharmony_ciATOMIC64_OPS(andnot, bic, bic) 3918c2ecf20Sopenharmony_ciATOMIC64_OPS(or, orr, orr) 3928c2ecf20Sopenharmony_ciATOMIC64_OPS(xor, eor, eor) 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed 3958c2ecf20Sopenharmony_ci#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed 3968c2ecf20Sopenharmony_ci#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed 3978c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS 4008c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP 4018c2ecf20Sopenharmony_ci#undef ATOMIC64_OP_RETURN 4028c2ecf20Sopenharmony_ci#undef ATOMIC64_OP 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic inline s64 atomic64_cmpxchg_relaxed(atomic64_t *ptr, s64 old, s64 new) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci s64 oldval; 4078c2ecf20Sopenharmony_ci unsigned long res; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci prefetchw(&ptr->counter); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci do { 4128c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_cmpxchg\n" 4138c2ecf20Sopenharmony_ci "ldrexd %1, %H1, [%3]\n" 4148c2ecf20Sopenharmony_ci "mov %0, #0\n" 4158c2ecf20Sopenharmony_ci "teq %1, %4\n" 4168c2ecf20Sopenharmony_ci "teqeq %H1, %H4\n" 4178c2ecf20Sopenharmony_ci "strexdeq %0, %5, %H5, [%3]" 4188c2ecf20Sopenharmony_ci : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) 4198c2ecf20Sopenharmony_ci : "r" (&ptr->counter), "r" (old), "r" (new) 4208c2ecf20Sopenharmony_ci : "cc"); 4218c2ecf20Sopenharmony_ci } while (res); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return oldval; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci#define atomic64_cmpxchg_relaxed atomic64_cmpxchg_relaxed 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic inline s64 atomic64_xchg_relaxed(atomic64_t *ptr, s64 new) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci s64 result; 4308c2ecf20Sopenharmony_ci unsigned long tmp; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci prefetchw(&ptr->counter); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_xchg\n" 4358c2ecf20Sopenharmony_ci"1: ldrexd %0, %H0, [%3]\n" 4368c2ecf20Sopenharmony_ci" strexd %1, %4, %H4, [%3]\n" 4378c2ecf20Sopenharmony_ci" teq %1, #0\n" 4388c2ecf20Sopenharmony_ci" bne 1b" 4398c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (tmp), "+Qo" (ptr->counter) 4408c2ecf20Sopenharmony_ci : "r" (&ptr->counter), "r" (new) 4418c2ecf20Sopenharmony_ci : "cc"); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return result; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci#define atomic64_xchg_relaxed atomic64_xchg_relaxed 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic inline s64 atomic64_dec_if_positive(atomic64_t *v) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci s64 result; 4508c2ecf20Sopenharmony_ci unsigned long tmp; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci smp_mb(); 4538c2ecf20Sopenharmony_ci prefetchw(&v->counter); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_dec_if_positive\n" 4568c2ecf20Sopenharmony_ci"1: ldrexd %0, %H0, [%3]\n" 4578c2ecf20Sopenharmony_ci" subs %Q0, %Q0, #1\n" 4588c2ecf20Sopenharmony_ci" sbc %R0, %R0, #0\n" 4598c2ecf20Sopenharmony_ci" teq %R0, #0\n" 4608c2ecf20Sopenharmony_ci" bmi 2f\n" 4618c2ecf20Sopenharmony_ci" strexd %1, %0, %H0, [%3]\n" 4628c2ecf20Sopenharmony_ci" teq %1, #0\n" 4638c2ecf20Sopenharmony_ci" bne 1b\n" 4648c2ecf20Sopenharmony_ci"2:" 4658c2ecf20Sopenharmony_ci : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) 4668c2ecf20Sopenharmony_ci : "r" (&v->counter) 4678c2ecf20Sopenharmony_ci : "cc"); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci smp_mb(); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return result; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci#define atomic64_dec_if_positive atomic64_dec_if_positive 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci s64 oldval, newval; 4788c2ecf20Sopenharmony_ci unsigned long tmp; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci smp_mb(); 4818c2ecf20Sopenharmony_ci prefetchw(&v->counter); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci __asm__ __volatile__("@ atomic64_add_unless\n" 4848c2ecf20Sopenharmony_ci"1: ldrexd %0, %H0, [%4]\n" 4858c2ecf20Sopenharmony_ci" teq %0, %5\n" 4868c2ecf20Sopenharmony_ci" teqeq %H0, %H5\n" 4878c2ecf20Sopenharmony_ci" beq 2f\n" 4888c2ecf20Sopenharmony_ci" adds %Q1, %Q0, %Q6\n" 4898c2ecf20Sopenharmony_ci" adc %R1, %R0, %R6\n" 4908c2ecf20Sopenharmony_ci" strexd %2, %1, %H1, [%4]\n" 4918c2ecf20Sopenharmony_ci" teq %2, #0\n" 4928c2ecf20Sopenharmony_ci" bne 1b\n" 4938c2ecf20Sopenharmony_ci"2:" 4948c2ecf20Sopenharmony_ci : "=&r" (oldval), "=&r" (newval), "=&r" (tmp), "+Qo" (v->counter) 4958c2ecf20Sopenharmony_ci : "r" (&v->counter), "r" (u), "r" (a) 4968c2ecf20Sopenharmony_ci : "cc"); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (oldval != u) 4998c2ecf20Sopenharmony_ci smp_mb(); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return oldval; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci#define atomic64_fetch_add_unless atomic64_fetch_add_unless 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci#endif /* !CONFIG_GENERIC_ATOMIC64 */ 5068c2ecf20Sopenharmony_ci#endif 5078c2ecf20Sopenharmony_ci#endif 508