1/* SPDX-License-Identifier: GPL-2.0-only */
2
3#ifndef _ASM_ARC_ATOMIC_LLSC_H
4#define _ASM_ARC_ATOMIC_LLSC_H
5
6#define arch_atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
7
8#define ATOMIC_OP(op, asm_op)					\
9static inline void arch_atomic_##op(int i, atomic_t *v)			\
10{									\
11	unsigned int val;						\
12									\
13	__asm__ __volatile__(						\
14	"1:	llock   %[val], [%[ctr]]		\n"		\
15	"	" #asm_op " %[val], %[val], %[i]	\n"		\
16	"	scond   %[val], [%[ctr]]		\n"		\
17	"	bnz     1b				\n"		\
18	: [val]	"=&r"	(val) /* Early clobber to prevent reg reuse */	\
19	: [ctr]	"r"	(&v->counter), /* Not "m": llock only supports reg direct addr mode */	\
20	  [i]	"ir"	(i)						\
21	: "cc", "memory");						\
22}									\
23
24#define ATOMIC_OP_RETURN(op, asm_op)				\
25static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v)	\
26{									\
27	unsigned int val;						\
28									\
29	__asm__ __volatile__(						\
30	"1:	llock   %[val], [%[ctr]]		\n"		\
31	"	" #asm_op " %[val], %[val], %[i]	\n"		\
32	"	scond   %[val], [%[ctr]]		\n"		\
33	"	bnz     1b				\n"		\
34	: [val]	"=&r"	(val)						\
35	: [ctr]	"r"	(&v->counter),					\
36	  [i]	"ir"	(i)						\
37	: "cc", "memory");						\
38									\
39	return val;							\
40}
41
42#define arch_atomic_add_return_relaxed		arch_atomic_add_return_relaxed
43#define arch_atomic_sub_return_relaxed		arch_atomic_sub_return_relaxed
44
45#define ATOMIC_FETCH_OP(op, asm_op)				\
46static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v)	\
47{									\
48	unsigned int val, orig;						\
49									\
50	__asm__ __volatile__(						\
51	"1:	llock   %[orig], [%[ctr]]		\n"		\
52	"	" #asm_op " %[val], %[orig], %[i]	\n"		\
53	"	scond   %[val], [%[ctr]]		\n"		\
54	"	bnz     1b				\n"		\
55	: [val]	"=&r"	(val),						\
56	  [orig] "=&r" (orig)						\
57	: [ctr]	"r"	(&v->counter),					\
58	  [i]	"ir"	(i)						\
59	: "cc", "memory");						\
60									\
61	return orig;							\
62}
63
64#define arch_atomic_fetch_add_relaxed		arch_atomic_fetch_add_relaxed
65#define arch_atomic_fetch_sub_relaxed		arch_atomic_fetch_sub_relaxed
66
67#define arch_atomic_fetch_and_relaxed		arch_atomic_fetch_and_relaxed
68#define arch_atomic_fetch_andnot_relaxed	arch_atomic_fetch_andnot_relaxed
69#define arch_atomic_fetch_or_relaxed		arch_atomic_fetch_or_relaxed
70#define arch_atomic_fetch_xor_relaxed		arch_atomic_fetch_xor_relaxed
71
72#define ATOMIC_OPS(op, asm_op)					\
73	ATOMIC_OP(op, asm_op)					\
74	ATOMIC_OP_RETURN(op, asm_op)				\
75	ATOMIC_FETCH_OP(op, asm_op)
76
77ATOMIC_OPS(add, add)
78ATOMIC_OPS(sub, sub)
79
80#undef ATOMIC_OPS
81#define ATOMIC_OPS(op, asm_op)					\
82	ATOMIC_OP(op, asm_op)					\
83	ATOMIC_FETCH_OP(op, asm_op)
84
85ATOMIC_OPS(and, and)
86ATOMIC_OPS(andnot, bic)
87ATOMIC_OPS(or, or)
88ATOMIC_OPS(xor, xor)
89
90#define arch_atomic_andnot		arch_atomic_andnot
91
92#undef ATOMIC_OPS
93#undef ATOMIC_FETCH_OP
94#undef ATOMIC_OP_RETURN
95#undef ATOMIC_OP
96
97#endif
98