xref: /linux/arch/csky/include/asm/atomic.h (revision 18f90d372cf35b387663f1567de701e5393f6eb5)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #ifndef __ASM_CSKY_ATOMIC_H
4 #define __ASM_CSKY_ATOMIC_H
5 
6 #include <linux/version.h>
7 #include <asm/cmpxchg.h>
8 #include <asm/barrier.h>
9 
10 #ifdef CONFIG_CPU_HAS_LDSTEX
11 
12 #define __atomic_add_unless __atomic_add_unless
13 static inline int __atomic_add_unless(atomic_t *v, int a, int u)
14 {
15 	unsigned long tmp, ret;
16 
17 	smp_mb();
18 
19 	asm volatile (
20 	"1:	ldex.w		%0, (%3) \n"
21 	"	mov		%1, %0   \n"
22 	"	cmpne		%0, %4   \n"
23 	"	bf		2f	 \n"
24 	"	add		%0, %2   \n"
25 	"	stex.w		%0, (%3) \n"
26 	"	bez		%0, 1b   \n"
27 	"2:				 \n"
28 		: "=&r" (tmp), "=&r" (ret)
29 		: "r" (a), "r"(&v->counter), "r"(u)
30 		: "memory");
31 
32 	if (ret != u)
33 		smp_mb();
34 
35 	return ret;
36 }
37 
38 #define ATOMIC_OP(op, c_op)						\
39 static inline void atomic_##op(int i, atomic_t *v)			\
40 {									\
41 	unsigned long tmp;						\
42 									\
43 	asm volatile (							\
44 	"1:	ldex.w		%0, (%2) \n"				\
45 	"	" #op "		%0, %1   \n"				\
46 	"	stex.w		%0, (%2) \n"				\
47 	"	bez		%0, 1b   \n"				\
48 		: "=&r" (tmp)						\
49 		: "r" (i), "r"(&v->counter)				\
50 		: "memory");						\
51 }
52 
53 #define ATOMIC_OP_RETURN(op, c_op)					\
54 static inline int atomic_##op##_return(int i, atomic_t *v)		\
55 {									\
56 	unsigned long tmp, ret;						\
57 									\
58 	smp_mb();							\
59 	asm volatile (							\
60 	"1:	ldex.w		%0, (%3) \n"				\
61 	"	" #op "		%0, %2   \n"				\
62 	"	mov		%1, %0   \n"				\
63 	"	stex.w		%0, (%3) \n"				\
64 	"	bez		%0, 1b   \n"				\
65 		: "=&r" (tmp), "=&r" (ret)				\
66 		: "r" (i), "r"(&v->counter)				\
67 		: "memory");						\
68 	smp_mb();							\
69 									\
70 	return ret;							\
71 }
72 
73 #define ATOMIC_FETCH_OP(op, c_op)					\
74 static inline int atomic_fetch_##op(int i, atomic_t *v)			\
75 {									\
76 	unsigned long tmp, ret;						\
77 									\
78 	smp_mb();							\
79 	asm volatile (							\
80 	"1:	ldex.w		%0, (%3) \n"				\
81 	"	mov		%1, %0   \n"				\
82 	"	" #op "		%0, %2   \n"				\
83 	"	stex.w		%0, (%3) \n"				\
84 	"	bez		%0, 1b   \n"				\
85 		: "=&r" (tmp), "=&r" (ret)				\
86 		: "r" (i), "r"(&v->counter)				\
87 		: "memory");						\
88 	smp_mb();							\
89 									\
90 	return ret;							\
91 }
92 
93 #else /* CONFIG_CPU_HAS_LDSTEX */
94 
95 #include <linux/irqflags.h>
96 
97 #define __atomic_add_unless __atomic_add_unless
98 static inline int __atomic_add_unless(atomic_t *v, int a, int u)
99 {
100 	unsigned long tmp, ret, flags;
101 
102 	raw_local_irq_save(flags);
103 
104 	asm volatile (
105 	"	ldw		%0, (%3) \n"
106 	"	mov		%1, %0   \n"
107 	"	cmpne		%0, %4   \n"
108 	"	bf		2f	 \n"
109 	"	add		%0, %2   \n"
110 	"	stw		%0, (%3) \n"
111 	"2:				 \n"
112 		: "=&r" (tmp), "=&r" (ret)
113 		: "r" (a), "r"(&v->counter), "r"(u)
114 		: "memory");
115 
116 	raw_local_irq_restore(flags);
117 
118 	return ret;
119 }
120 
121 #define ATOMIC_OP(op, c_op)						\
122 static inline void atomic_##op(int i, atomic_t *v)			\
123 {									\
124 	unsigned long tmp, flags;					\
125 									\
126 	raw_local_irq_save(flags);					\
127 									\
128 	asm volatile (							\
129 	"	ldw		%0, (%2) \n"				\
130 	"	" #op "		%0, %1   \n"				\
131 	"	stw		%0, (%2) \n"				\
132 		: "=&r" (tmp)						\
133 		: "r" (i), "r"(&v->counter)				\
134 		: "memory");						\
135 									\
136 	raw_local_irq_restore(flags);					\
137 }
138 
139 #define ATOMIC_OP_RETURN(op, c_op)					\
140 static inline int atomic_##op##_return(int i, atomic_t *v)		\
141 {									\
142 	unsigned long tmp, ret, flags;					\
143 									\
144 	raw_local_irq_save(flags);					\
145 									\
146 	asm volatile (							\
147 	"	ldw		%0, (%3) \n"				\
148 	"	" #op "		%0, %2   \n"				\
149 	"	stw		%0, (%3) \n"				\
150 	"	mov		%1, %0   \n"				\
151 		: "=&r" (tmp), "=&r" (ret)				\
152 		: "r" (i), "r"(&v->counter)				\
153 		: "memory");						\
154 									\
155 	raw_local_irq_restore(flags);					\
156 									\
157 	return ret;							\
158 }
159 
160 #define ATOMIC_FETCH_OP(op, c_op)					\
161 static inline int atomic_fetch_##op(int i, atomic_t *v)			\
162 {									\
163 	unsigned long tmp, ret, flags;					\
164 									\
165 	raw_local_irq_save(flags);					\
166 									\
167 	asm volatile (							\
168 	"	ldw		%0, (%3) \n"				\
169 	"	mov		%1, %0   \n"				\
170 	"	" #op "		%0, %2   \n"				\
171 	"	stw		%0, (%3) \n"				\
172 		: "=&r" (tmp), "=&r" (ret)				\
173 		: "r" (i), "r"(&v->counter)				\
174 		: "memory");						\
175 									\
176 	raw_local_irq_restore(flags);					\
177 									\
178 	return ret;							\
179 }
180 
181 #endif /* CONFIG_CPU_HAS_LDSTEX */
182 
183 #define atomic_add_return atomic_add_return
184 ATOMIC_OP_RETURN(add, +)
185 #define atomic_sub_return atomic_sub_return
186 ATOMIC_OP_RETURN(sub, -)
187 
188 #define atomic_fetch_add atomic_fetch_add
189 ATOMIC_FETCH_OP(add, +)
190 #define atomic_fetch_sub atomic_fetch_sub
191 ATOMIC_FETCH_OP(sub, -)
192 #define atomic_fetch_and atomic_fetch_and
193 ATOMIC_FETCH_OP(and, &)
194 #define atomic_fetch_or atomic_fetch_or
195 ATOMIC_FETCH_OP(or, |)
196 #define atomic_fetch_xor atomic_fetch_xor
197 ATOMIC_FETCH_OP(xor, ^)
198 
199 #define atomic_and atomic_and
200 ATOMIC_OP(and, &)
201 #define atomic_or atomic_or
202 ATOMIC_OP(or, |)
203 #define atomic_xor atomic_xor
204 ATOMIC_OP(xor, ^)
205 
206 #undef ATOMIC_FETCH_OP
207 #undef ATOMIC_OP_RETURN
208 #undef ATOMIC_OP
209 
210 #include <asm-generic/atomic.h>
211 
212 #endif /* __ASM_CSKY_ATOMIC_H */
213