162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Based on arch/arm/include/asm/atomic.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1996 Russell King. 662306a36Sopenharmony_ci * Copyright (C) 2002 Deep Blue Solutions Ltd. 762306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifndef __ASM_ATOMIC_LSE_H 1162306a36Sopenharmony_ci#define __ASM_ATOMIC_LSE_H 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define ATOMIC_OP(op, asm_op) \ 1462306a36Sopenharmony_cistatic __always_inline void \ 1562306a36Sopenharmony_ci__lse_atomic_##op(int i, atomic_t *v) \ 1662306a36Sopenharmony_ci{ \ 1762306a36Sopenharmony_ci asm volatile( \ 1862306a36Sopenharmony_ci __LSE_PREAMBLE \ 1962306a36Sopenharmony_ci " " #asm_op " %w[i], %[v]\n" \ 2062306a36Sopenharmony_ci : [v] "+Q" (v->counter) \ 2162306a36Sopenharmony_ci : [i] "r" (i)); \ 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciATOMIC_OP(andnot, stclr) 2562306a36Sopenharmony_ciATOMIC_OP(or, stset) 2662306a36Sopenharmony_ciATOMIC_OP(xor, steor) 2762306a36Sopenharmony_ciATOMIC_OP(add, stadd) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic __always_inline void __lse_atomic_sub(int i, atomic_t *v) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci __lse_atomic_add(-i, v); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#undef ATOMIC_OP 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(name, mb, op, asm_op, cl...) \ 3762306a36Sopenharmony_cistatic __always_inline int \ 3862306a36Sopenharmony_ci__lse_atomic_fetch_##op##name(int i, atomic_t *v) \ 3962306a36Sopenharmony_ci{ \ 4062306a36Sopenharmony_ci int old; \ 4162306a36Sopenharmony_ci \ 4262306a36Sopenharmony_ci asm volatile( \ 4362306a36Sopenharmony_ci __LSE_PREAMBLE \ 4462306a36Sopenharmony_ci " " #asm_op #mb " %w[i], %w[old], %[v]" \ 4562306a36Sopenharmony_ci : [v] "+Q" (v->counter), \ 4662306a36Sopenharmony_ci [old] "=r" (old) \ 4762306a36Sopenharmony_ci : [i] "r" (i) \ 4862306a36Sopenharmony_ci : cl); \ 4962306a36Sopenharmony_ci \ 5062306a36Sopenharmony_ci return old; \ 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define ATOMIC_FETCH_OPS(op, asm_op) \ 5462306a36Sopenharmony_ci ATOMIC_FETCH_OP(_relaxed, , op, asm_op) \ 5562306a36Sopenharmony_ci ATOMIC_FETCH_OP(_acquire, a, op, asm_op, "memory") \ 5662306a36Sopenharmony_ci ATOMIC_FETCH_OP(_release, l, op, asm_op, "memory") \ 5762306a36Sopenharmony_ci ATOMIC_FETCH_OP( , al, op, asm_op, "memory") 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciATOMIC_FETCH_OPS(andnot, ldclr) 6062306a36Sopenharmony_ciATOMIC_FETCH_OPS(or, ldset) 6162306a36Sopenharmony_ciATOMIC_FETCH_OPS(xor, ldeor) 6262306a36Sopenharmony_ciATOMIC_FETCH_OPS(add, ldadd) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP 6562306a36Sopenharmony_ci#undef ATOMIC_FETCH_OPS 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define ATOMIC_FETCH_OP_SUB(name) \ 6862306a36Sopenharmony_cistatic __always_inline int \ 6962306a36Sopenharmony_ci__lse_atomic_fetch_sub##name(int i, atomic_t *v) \ 7062306a36Sopenharmony_ci{ \ 7162306a36Sopenharmony_ci return __lse_atomic_fetch_add##name(-i, v); \ 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciATOMIC_FETCH_OP_SUB(_relaxed) 7562306a36Sopenharmony_ciATOMIC_FETCH_OP_SUB(_acquire) 7662306a36Sopenharmony_ciATOMIC_FETCH_OP_SUB(_release) 7762306a36Sopenharmony_ciATOMIC_FETCH_OP_SUB( ) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP_SUB 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define ATOMIC_OP_ADD_SUB_RETURN(name) \ 8262306a36Sopenharmony_cistatic __always_inline int \ 8362306a36Sopenharmony_ci__lse_atomic_add_return##name(int i, atomic_t *v) \ 8462306a36Sopenharmony_ci{ \ 8562306a36Sopenharmony_ci return __lse_atomic_fetch_add##name(i, v) + i; \ 8662306a36Sopenharmony_ci} \ 8762306a36Sopenharmony_ci \ 8862306a36Sopenharmony_cistatic __always_inline int \ 8962306a36Sopenharmony_ci__lse_atomic_sub_return##name(int i, atomic_t *v) \ 9062306a36Sopenharmony_ci{ \ 9162306a36Sopenharmony_ci return __lse_atomic_fetch_sub(i, v) - i; \ 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciATOMIC_OP_ADD_SUB_RETURN(_relaxed) 9562306a36Sopenharmony_ciATOMIC_OP_ADD_SUB_RETURN(_acquire) 9662306a36Sopenharmony_ciATOMIC_OP_ADD_SUB_RETURN(_release) 9762306a36Sopenharmony_ciATOMIC_OP_ADD_SUB_RETURN( ) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#undef ATOMIC_OP_ADD_SUB_RETURN 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic __always_inline void __lse_atomic_and(int i, atomic_t *v) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return __lse_atomic_andnot(~i, v); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define ATOMIC_FETCH_OP_AND(name, mb, cl...) \ 10762306a36Sopenharmony_cistatic __always_inline int \ 10862306a36Sopenharmony_ci__lse_atomic_fetch_and##name(int i, atomic_t *v) \ 10962306a36Sopenharmony_ci{ \ 11062306a36Sopenharmony_ci return __lse_atomic_fetch_andnot##name(~i, v); \ 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciATOMIC_FETCH_OP_AND(_relaxed, ) 11462306a36Sopenharmony_ciATOMIC_FETCH_OP_AND(_acquire, a, "memory") 11562306a36Sopenharmony_ciATOMIC_FETCH_OP_AND(_release, l, "memory") 11662306a36Sopenharmony_ciATOMIC_FETCH_OP_AND( , al, "memory") 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP_AND 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define ATOMIC64_OP(op, asm_op) \ 12162306a36Sopenharmony_cistatic __always_inline void \ 12262306a36Sopenharmony_ci__lse_atomic64_##op(s64 i, atomic64_t *v) \ 12362306a36Sopenharmony_ci{ \ 12462306a36Sopenharmony_ci asm volatile( \ 12562306a36Sopenharmony_ci __LSE_PREAMBLE \ 12662306a36Sopenharmony_ci " " #asm_op " %[i], %[v]\n" \ 12762306a36Sopenharmony_ci : [v] "+Q" (v->counter) \ 12862306a36Sopenharmony_ci : [i] "r" (i)); \ 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciATOMIC64_OP(andnot, stclr) 13262306a36Sopenharmony_ciATOMIC64_OP(or, stset) 13362306a36Sopenharmony_ciATOMIC64_OP(xor, steor) 13462306a36Sopenharmony_ciATOMIC64_OP(add, stadd) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic __always_inline void __lse_atomic64_sub(s64 i, atomic64_t *v) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci __lse_atomic64_add(-i, v); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#undef ATOMIC64_OP 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define ATOMIC64_FETCH_OP(name, mb, op, asm_op, cl...) \ 14462306a36Sopenharmony_cistatic __always_inline long \ 14562306a36Sopenharmony_ci__lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v) \ 14662306a36Sopenharmony_ci{ \ 14762306a36Sopenharmony_ci s64 old; \ 14862306a36Sopenharmony_ci \ 14962306a36Sopenharmony_ci asm volatile( \ 15062306a36Sopenharmony_ci __LSE_PREAMBLE \ 15162306a36Sopenharmony_ci " " #asm_op #mb " %[i], %[old], %[v]" \ 15262306a36Sopenharmony_ci : [v] "+Q" (v->counter), \ 15362306a36Sopenharmony_ci [old] "=r" (old) \ 15462306a36Sopenharmony_ci : [i] "r" (i) \ 15562306a36Sopenharmony_ci : cl); \ 15662306a36Sopenharmony_ci \ 15762306a36Sopenharmony_ci return old; \ 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define ATOMIC64_FETCH_OPS(op, asm_op) \ 16162306a36Sopenharmony_ci ATOMIC64_FETCH_OP(_relaxed, , op, asm_op) \ 16262306a36Sopenharmony_ci ATOMIC64_FETCH_OP(_acquire, a, op, asm_op, "memory") \ 16362306a36Sopenharmony_ci ATOMIC64_FETCH_OP(_release, l, op, asm_op, "memory") \ 16462306a36Sopenharmony_ci ATOMIC64_FETCH_OP( , al, op, asm_op, "memory") 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciATOMIC64_FETCH_OPS(andnot, ldclr) 16762306a36Sopenharmony_ciATOMIC64_FETCH_OPS(or, ldset) 16862306a36Sopenharmony_ciATOMIC64_FETCH_OPS(xor, ldeor) 16962306a36Sopenharmony_ciATOMIC64_FETCH_OPS(add, ldadd) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#undef ATOMIC64_FETCH_OP 17262306a36Sopenharmony_ci#undef ATOMIC64_FETCH_OPS 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define ATOMIC64_FETCH_OP_SUB(name) \ 17562306a36Sopenharmony_cistatic __always_inline long \ 17662306a36Sopenharmony_ci__lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \ 17762306a36Sopenharmony_ci{ \ 17862306a36Sopenharmony_ci return __lse_atomic64_fetch_add##name(-i, v); \ 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciATOMIC64_FETCH_OP_SUB(_relaxed) 18262306a36Sopenharmony_ciATOMIC64_FETCH_OP_SUB(_acquire) 18362306a36Sopenharmony_ciATOMIC64_FETCH_OP_SUB(_release) 18462306a36Sopenharmony_ciATOMIC64_FETCH_OP_SUB( ) 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#undef ATOMIC64_FETCH_OP_SUB 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci#define ATOMIC64_OP_ADD_SUB_RETURN(name) \ 18962306a36Sopenharmony_cistatic __always_inline long \ 19062306a36Sopenharmony_ci__lse_atomic64_add_return##name(s64 i, atomic64_t *v) \ 19162306a36Sopenharmony_ci{ \ 19262306a36Sopenharmony_ci return __lse_atomic64_fetch_add##name(i, v) + i; \ 19362306a36Sopenharmony_ci} \ 19462306a36Sopenharmony_ci \ 19562306a36Sopenharmony_cistatic __always_inline long \ 19662306a36Sopenharmony_ci__lse_atomic64_sub_return##name(s64 i, atomic64_t *v) \ 19762306a36Sopenharmony_ci{ \ 19862306a36Sopenharmony_ci return __lse_atomic64_fetch_sub##name(i, v) - i; \ 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciATOMIC64_OP_ADD_SUB_RETURN(_relaxed) 20262306a36Sopenharmony_ciATOMIC64_OP_ADD_SUB_RETURN(_acquire) 20362306a36Sopenharmony_ciATOMIC64_OP_ADD_SUB_RETURN(_release) 20462306a36Sopenharmony_ciATOMIC64_OP_ADD_SUB_RETURN( ) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#undef ATOMIC64_OP_ADD_SUB_RETURN 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic __always_inline void __lse_atomic64_and(s64 i, atomic64_t *v) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci return __lse_atomic64_andnot(~i, v); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci#define ATOMIC64_FETCH_OP_AND(name, mb, cl...) \ 21462306a36Sopenharmony_cistatic __always_inline long \ 21562306a36Sopenharmony_ci__lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \ 21662306a36Sopenharmony_ci{ \ 21762306a36Sopenharmony_ci return __lse_atomic64_fetch_andnot##name(~i, v); \ 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciATOMIC64_FETCH_OP_AND(_relaxed, ) 22162306a36Sopenharmony_ciATOMIC64_FETCH_OP_AND(_acquire, a, "memory") 22262306a36Sopenharmony_ciATOMIC64_FETCH_OP_AND(_release, l, "memory") 22362306a36Sopenharmony_ciATOMIC64_FETCH_OP_AND( , al, "memory") 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci#undef ATOMIC64_FETCH_OP_AND 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic __always_inline s64 __lse_atomic64_dec_if_positive(atomic64_t *v) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci unsigned long tmp; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci asm volatile( 23262306a36Sopenharmony_ci __LSE_PREAMBLE 23362306a36Sopenharmony_ci "1: ldr %x[tmp], %[v]\n" 23462306a36Sopenharmony_ci " subs %[ret], %x[tmp], #1\n" 23562306a36Sopenharmony_ci " b.lt 2f\n" 23662306a36Sopenharmony_ci " casal %x[tmp], %[ret], %[v]\n" 23762306a36Sopenharmony_ci " sub %x[tmp], %x[tmp], #1\n" 23862306a36Sopenharmony_ci " sub %x[tmp], %x[tmp], %[ret]\n" 23962306a36Sopenharmony_ci " cbnz %x[tmp], 1b\n" 24062306a36Sopenharmony_ci "2:" 24162306a36Sopenharmony_ci : [ret] "+&r" (v), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) 24262306a36Sopenharmony_ci : 24362306a36Sopenharmony_ci : "cc", "memory"); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return (long)v; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci#define __CMPXCHG_CASE(w, sfx, name, sz, mb, cl...) \ 24962306a36Sopenharmony_cistatic __always_inline u##sz \ 25062306a36Sopenharmony_ci__lse__cmpxchg_case_##name##sz(volatile void *ptr, \ 25162306a36Sopenharmony_ci u##sz old, \ 25262306a36Sopenharmony_ci u##sz new) \ 25362306a36Sopenharmony_ci{ \ 25462306a36Sopenharmony_ci asm volatile( \ 25562306a36Sopenharmony_ci __LSE_PREAMBLE \ 25662306a36Sopenharmony_ci " cas" #mb #sfx " %" #w "[old], %" #w "[new], %[v]\n" \ 25762306a36Sopenharmony_ci : [v] "+Q" (*(u##sz *)ptr), \ 25862306a36Sopenharmony_ci [old] "+r" (old) \ 25962306a36Sopenharmony_ci : [new] "rZ" (new) \ 26062306a36Sopenharmony_ci : cl); \ 26162306a36Sopenharmony_ci \ 26262306a36Sopenharmony_ci return old; \ 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci__CMPXCHG_CASE(w, b, , 8, ) 26662306a36Sopenharmony_ci__CMPXCHG_CASE(w, h, , 16, ) 26762306a36Sopenharmony_ci__CMPXCHG_CASE(w, , , 32, ) 26862306a36Sopenharmony_ci__CMPXCHG_CASE(x, , , 64, ) 26962306a36Sopenharmony_ci__CMPXCHG_CASE(w, b, acq_, 8, a, "memory") 27062306a36Sopenharmony_ci__CMPXCHG_CASE(w, h, acq_, 16, a, "memory") 27162306a36Sopenharmony_ci__CMPXCHG_CASE(w, , acq_, 32, a, "memory") 27262306a36Sopenharmony_ci__CMPXCHG_CASE(x, , acq_, 64, a, "memory") 27362306a36Sopenharmony_ci__CMPXCHG_CASE(w, b, rel_, 8, l, "memory") 27462306a36Sopenharmony_ci__CMPXCHG_CASE(w, h, rel_, 16, l, "memory") 27562306a36Sopenharmony_ci__CMPXCHG_CASE(w, , rel_, 32, l, "memory") 27662306a36Sopenharmony_ci__CMPXCHG_CASE(x, , rel_, 64, l, "memory") 27762306a36Sopenharmony_ci__CMPXCHG_CASE(w, b, mb_, 8, al, "memory") 27862306a36Sopenharmony_ci__CMPXCHG_CASE(w, h, mb_, 16, al, "memory") 27962306a36Sopenharmony_ci__CMPXCHG_CASE(w, , mb_, 32, al, "memory") 28062306a36Sopenharmony_ci__CMPXCHG_CASE(x, , mb_, 64, al, "memory") 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci#undef __CMPXCHG_CASE 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci#define __CMPXCHG128(name, mb, cl...) \ 28562306a36Sopenharmony_cistatic __always_inline u128 \ 28662306a36Sopenharmony_ci__lse__cmpxchg128##name(volatile u128 *ptr, u128 old, u128 new) \ 28762306a36Sopenharmony_ci{ \ 28862306a36Sopenharmony_ci union __u128_halves r, o = { .full = (old) }, \ 28962306a36Sopenharmony_ci n = { .full = (new) }; \ 29062306a36Sopenharmony_ci register unsigned long x0 asm ("x0") = o.low; \ 29162306a36Sopenharmony_ci register unsigned long x1 asm ("x1") = o.high; \ 29262306a36Sopenharmony_ci register unsigned long x2 asm ("x2") = n.low; \ 29362306a36Sopenharmony_ci register unsigned long x3 asm ("x3") = n.high; \ 29462306a36Sopenharmony_ci register unsigned long x4 asm ("x4") = (unsigned long)ptr; \ 29562306a36Sopenharmony_ci \ 29662306a36Sopenharmony_ci asm volatile( \ 29762306a36Sopenharmony_ci __LSE_PREAMBLE \ 29862306a36Sopenharmony_ci " casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\ 29962306a36Sopenharmony_ci : [old1] "+&r" (x0), [old2] "+&r" (x1), \ 30062306a36Sopenharmony_ci [v] "+Q" (*(u128 *)ptr) \ 30162306a36Sopenharmony_ci : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ 30262306a36Sopenharmony_ci [oldval1] "r" (o.low), [oldval2] "r" (o.high) \ 30362306a36Sopenharmony_ci : cl); \ 30462306a36Sopenharmony_ci \ 30562306a36Sopenharmony_ci r.low = x0; r.high = x1; \ 30662306a36Sopenharmony_ci \ 30762306a36Sopenharmony_ci return r.full; \ 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci__CMPXCHG128( , ) 31162306a36Sopenharmony_ci__CMPXCHG128(_mb, al, "memory") 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci#undef __CMPXCHG128 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci#endif /* __ASM_ATOMIC_LSE_H */ 316