Path: blob/master/arch/arc/include/asm/atomic64-arcv2.h
26481 views
/* SPDX-License-Identifier: GPL-2.0-only */12/*3* ARCv2 supports 64-bit exclusive load (LLOCKD) / store (SCONDD)4* - The address HAS to be 64-bit aligned5*/67#ifndef _ASM_ARC_ATOMIC64_ARCV2_H8#define _ASM_ARC_ATOMIC64_ARCV2_H910typedef struct {11s64 __aligned(8) counter;12} atomic64_t;1314#define ATOMIC64_INIT(a) { (a) }1516static inline s64 arch_atomic64_read(const atomic64_t *v)17{18s64 val;1920__asm__ __volatile__(21" ldd %0, [%1] \n"22: "=r"(val)23: "r"(&v->counter));2425return val;26}2728static inline void arch_atomic64_set(atomic64_t *v, s64 a)29{30/*31* This could have been a simple assignment in "C" but would need32* explicit volatile. Otherwise gcc optimizers could elide the store33* which borked atomic64 self-test34* In the inline asm version, memory clobber needed for exact same35* reason, to tell gcc about the store.36*37* This however is not needed for sibling atomic64_add() etc since both38* load/store are explicitly done in inline asm. As long as API is used39* for each access, gcc has no way to optimize away any load/store40*/41__asm__ __volatile__(42" std %0, [%1] \n"43:44: "r"(a), "r"(&v->counter)45: "memory");46}4748#define ATOMIC64_OP(op, op1, op2) \49static inline void arch_atomic64_##op(s64 a, atomic64_t *v) \50{ \51s64 val; \52\53__asm__ __volatile__( \54"1: \n" \55" llockd %0, [%1] \n" \56" " #op1 " %L0, %L0, %L2 \n" \57" " #op2 " %H0, %H0, %H2 \n" \58" scondd %0, [%1] \n" \59" bnz 1b \n" \60: "=&r"(val) \61: "r"(&v->counter), "ir"(a) \62: "cc", "memory"); \63} \6465#define ATOMIC64_OP_RETURN(op, op1, op2) \66static inline s64 arch_atomic64_##op##_return_relaxed(s64 a, atomic64_t *v) \67{ \68s64 val; \69\70__asm__ __volatile__( \71"1: \n" \72" llockd %0, [%1] \n" \73" " #op1 " %L0, %L0, %L2 \n" \74" " #op2 " %H0, %H0, %H2 \n" \75" scondd %0, [%1] \n" \76" bnz 1b \n" \77: [val] "=&r"(val) \78: "r"(&v->counter), "ir"(a) \79: "cc", "memory"); \80\81return val; \82}8384#define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed85#define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed8687#define ATOMIC64_FETCH_OP(op, op1, op2) \88static inline s64 arch_atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v) \89{ \90s64 val, orig; \91\92__asm__ __volatile__( \93"1: \n" \94" llockd %0, [%2] \n" \95" " #op1 " %L1, %L0, %L3 \n" \96" " #op2 " %H1, %H0, %H3 \n" \97" scondd %1, [%2] \n" \98" bnz 1b \n" \99: "=&r"(orig), "=&r"(val) \100: "r"(&v->counter), "ir"(a) \101: "cc", "memory"); \102\103return orig; \104}105106#define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed107#define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed108109#define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed110#define arch_atomic64_fetch_andnot_relaxed arch_atomic64_fetch_andnot_relaxed111#define arch_atomic64_fetch_or_relaxed arch_atomic64_fetch_or_relaxed112#define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed113114#define ATOMIC64_OPS(op, op1, op2) \115ATOMIC64_OP(op, op1, op2) \116ATOMIC64_OP_RETURN(op, op1, op2) \117ATOMIC64_FETCH_OP(op, op1, op2)118119ATOMIC64_OPS(add, add.f, adc)120ATOMIC64_OPS(sub, sub.f, sbc)121122#undef ATOMIC64_OPS123#define ATOMIC64_OPS(op, op1, op2) \124ATOMIC64_OP(op, op1, op2) \125ATOMIC64_FETCH_OP(op, op1, op2)126127ATOMIC64_OPS(and, and, and)128ATOMIC64_OPS(andnot, bic, bic)129ATOMIC64_OPS(or, or, or)130ATOMIC64_OPS(xor, xor, xor)131132#define arch_atomic64_andnot arch_atomic64_andnot133134#undef ATOMIC64_OPS135#undef ATOMIC64_FETCH_OP136#undef ATOMIC64_OP_RETURN137#undef ATOMIC64_OP138139static inline u64 __arch_cmpxchg64_relaxed(volatile void *ptr, u64 old, u64 new)140{141u64 prev;142143__asm__ __volatile__(144"1: llockd %0, [%1] \n"145" brne %L0, %L2, 2f \n"146" brne %H0, %H2, 2f \n"147" scondd %3, [%1] \n"148" bnz 1b \n"149"2: \n"150: "=&r"(prev)151: "r"(ptr), "ir"(old), "r"(new)152: "memory", "cc");153154return prev;155}156#define arch_cmpxchg64_relaxed __arch_cmpxchg64_relaxed157158static inline s64 arch_atomic64_xchg(atomic64_t *ptr, s64 new)159{160s64 prev;161162smp_mb();163164__asm__ __volatile__(165"1: llockd %0, [%1] \n"166" scondd %2, [%1] \n"167" bnz 1b \n"168"2: \n"169: "=&r"(prev)170: "r"(ptr), "r"(new)171: "cc"); /* memory clobber comes from smp_mb() */172173smp_mb();174175return prev;176}177#define arch_atomic64_xchg arch_atomic64_xchg178179static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)180{181s64 val;182183smp_mb();184185__asm__ __volatile__(186"1: llockd %0, [%1] \n"187" sub.f %L0, %L0, 1 # w0 - 1, set C on borrow\n"188" sub.c %H0, %H0, 1 # if C set, w1 - 1\n"189" brlt %H0, 0, 2f \n"190" scondd %0, [%1] \n"191" bnz 1b \n"192"2: \n"193: "=&r"(val)194: "r"(&v->counter)195: "cc"); /* memory clobber comes from smp_mb() */196197smp_mb();198199return val;200}201#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive202203static inline s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)204{205s64 old, temp;206207smp_mb();208209__asm__ __volatile__(210"1: llockd %0, [%2] \n"211" brne %L0, %L4, 2f # continue to add since v != u \n"212" breq.d %H0, %H4, 3f # return since v == u \n"213"2: \n"214" add.f %L1, %L0, %L3 \n"215" adc %H1, %H0, %H3 \n"216" scondd %1, [%2] \n"217" bnz 1b \n"218"3: \n"219: "=&r"(old), "=&r" (temp)220: "r"(&v->counter), "r"(a), "r"(u)221: "cc"); /* memory clobber comes from smp_mb() */222223smp_mb();224225return old;226}227#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless228229#endif230231232