xref: /linux/arch/csky/include/asm/atomic.h (revision 9f771739a04919226081a107167596de75108fbb)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #ifndef __ASM_CSKY_ATOMIC_H
4 #define __ASM_CSKY_ATOMIC_H
5 
6 #ifdef CONFIG_SMP
7 #include <asm-generic/atomic64.h>
8 
9 #include <asm/cmpxchg.h>
10 #include <asm/barrier.h>
11 
12 #define __atomic_acquire_fence()	__bar_brarw()
13 
14 #define __atomic_release_fence()	__bar_brwaw()
15 
16 static __always_inline int arch_atomic_read(const atomic_t *v)
17 {
18 	return READ_ONCE(v->counter);
19 }
20 static __always_inline void arch_atomic_set(atomic_t *v, int i)
21 {
22 	WRITE_ONCE(v->counter, i);
23 }
24 
25 #define ATOMIC_OP(op)							\
26 static __always_inline							\
27 void arch_atomic_##op(int i, atomic_t *v)				\
28 {									\
29 	unsigned long tmp;						\
30 	__asm__ __volatile__ (						\
31 	"1:	ldex.w		%0, (%2)	\n"			\
32 	"	" #op "		%0, %1		\n"			\
33 	"	stex.w		%0, (%2)	\n"			\
34 	"	bez		%0, 1b		\n"			\
35 	: "=&r" (tmp)							\
36 	: "r" (i), "r" (&v->counter)					\
37 	: "memory");							\
38 }
39 
40 ATOMIC_OP(add)
41 ATOMIC_OP(sub)
42 ATOMIC_OP(and)
43 ATOMIC_OP( or)
44 ATOMIC_OP(xor)
45 
46 #undef ATOMIC_OP
47 
48 #define ATOMIC_FETCH_OP(op)						\
49 static __always_inline							\
50 int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v)		\
51 {									\
52 	register int ret, tmp;						\
53 	__asm__ __volatile__ (						\
54 	"1:	ldex.w		%0, (%3) \n"				\
55 	"	mov		%1, %0   \n"				\
56 	"	" #op "		%0, %2   \n"				\
57 	"	stex.w		%0, (%3) \n"				\
58 	"	bez		%0, 1b   \n"				\
59 		: "=&r" (tmp), "=&r" (ret)				\
60 		: "r" (i), "r"(&v->counter) 				\
61 		: "memory");						\
62 	return ret;							\
63 }
64 
65 #define ATOMIC_OP_RETURN(op, c_op)					\
66 static __always_inline							\
67 int arch_atomic_##op##_return_relaxed(int i, atomic_t *v)		\
68 {									\
69 	return arch_atomic_fetch_##op##_relaxed(i, v) c_op i;		\
70 }
71 
72 #define ATOMIC_OPS(op, c_op)						\
73 	ATOMIC_FETCH_OP(op)						\
74 	ATOMIC_OP_RETURN(op, c_op)
75 
76 ATOMIC_OPS(add, +)
77 ATOMIC_OPS(sub, -)
78 
79 #define arch_atomic_fetch_add_relaxed	arch_atomic_fetch_add_relaxed
80 #define arch_atomic_fetch_sub_relaxed	arch_atomic_fetch_sub_relaxed
81 
82 #define arch_atomic_add_return_relaxed	arch_atomic_add_return_relaxed
83 #define arch_atomic_sub_return_relaxed	arch_atomic_sub_return_relaxed
84 
85 #undef ATOMIC_OPS
86 #undef ATOMIC_OP_RETURN
87 
88 #define ATOMIC_OPS(op)							\
89 	ATOMIC_FETCH_OP(op)
90 
91 ATOMIC_OPS(and)
92 ATOMIC_OPS( or)
93 ATOMIC_OPS(xor)
94 
95 #define arch_atomic_fetch_and_relaxed	arch_atomic_fetch_and_relaxed
96 #define arch_atomic_fetch_or_relaxed	arch_atomic_fetch_or_relaxed
97 #define arch_atomic_fetch_xor_relaxed	arch_atomic_fetch_xor_relaxed
98 
99 #undef ATOMIC_OPS
100 
101 #undef ATOMIC_FETCH_OP
102 
103 static __always_inline int
104 arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
105 {
106 	int prev, tmp;
107 
108 	__asm__ __volatile__ (
109 		RELEASE_FENCE
110 		"1:	ldex.w		%0, (%3)	\n"
111 		"	cmpne		%0, %4		\n"
112 		"	bf		2f		\n"
113 		"	mov		%1, %0		\n"
114 		"	add		%1, %2		\n"
115 		"	stex.w		%1, (%3)	\n"
116 		"	bez		%1, 1b		\n"
117 		FULL_FENCE
118 		"2:\n"
119 		: "=&r" (prev), "=&r" (tmp)
120 		: "r" (a), "r" (&v->counter), "r" (u)
121 		: "memory");
122 
123 	return prev;
124 }
125 #define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
126 
127 static __always_inline bool
128 arch_atomic_inc_unless_negative(atomic_t *v)
129 {
130 	int rc, tmp;
131 
132 	__asm__ __volatile__ (
133 		RELEASE_FENCE
134 		"1:	ldex.w		%0, (%2)	\n"
135 		"	movi		%1, 0		\n"
136 		"	blz		%0, 2f		\n"
137 		"	movi		%1, 1		\n"
138 		"	addi		%0, 1		\n"
139 		"	stex.w		%0, (%2)	\n"
140 		"	bez		%0, 1b		\n"
141 		FULL_FENCE
142 		"2:\n"
143 		: "=&r" (tmp), "=&r" (rc)
144 		: "r" (&v->counter)
145 		: "memory");
146 
147 	return tmp ? true : false;
148 
149 }
150 #define arch_atomic_inc_unless_negative arch_atomic_inc_unless_negative
151 
152 static __always_inline bool
153 arch_atomic_dec_unless_positive(atomic_t *v)
154 {
155 	int rc, tmp;
156 
157 	__asm__ __volatile__ (
158 		RELEASE_FENCE
159 		"1:	ldex.w		%0, (%2)	\n"
160 		"	movi		%1, 0		\n"
161 		"	bhz		%0, 2f		\n"
162 		"	movi		%1, 1		\n"
163 		"	subi		%0, 1		\n"
164 		"	stex.w		%0, (%2)	\n"
165 		"	bez		%0, 1b		\n"
166 		FULL_FENCE
167 		"2:\n"
168 		: "=&r" (tmp), "=&r" (rc)
169 		: "r" (&v->counter)
170 		: "memory");
171 
172 	return tmp ? true : false;
173 }
174 #define arch_atomic_dec_unless_positive arch_atomic_dec_unless_positive
175 
176 static __always_inline int
177 arch_atomic_dec_if_positive(atomic_t *v)
178 {
179 	int dec, tmp;
180 
181 	__asm__ __volatile__ (
182 		RELEASE_FENCE
183 		"1:	ldex.w		%0, (%2)	\n"
184 		"	subi		%1, %0, 1	\n"
185 		"	blz		%1, 2f		\n"
186 		"	stex.w		%1, (%2)	\n"
187 		"	bez		%1, 1b		\n"
188 		FULL_FENCE
189 		"2:\n"
190 		: "=&r" (dec), "=&r" (tmp)
191 		: "r" (&v->counter)
192 		: "memory");
193 
194 	return dec - 1;
195 }
196 #define arch_atomic_dec_if_positive arch_atomic_dec_if_positive
197 
198 #else
199 #include <asm-generic/atomic.h>
200 #endif
201 
202 #endif /* __ASM_CSKY_ATOMIC_H */
203