GNU Linux-libre 5.4.274-gnu1
[releases.git] / arch / xtensa / include / asm / atomic.h
1 /*
2  * include/asm-xtensa/atomic.h
3  *
4  * Atomic operations that C can't guarantee us.  Useful for resource counting..
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  *
10  * Copyright (C) 2001 - 2008 Tensilica Inc.
11  */
12
13 #ifndef _XTENSA_ATOMIC_H
14 #define _XTENSA_ATOMIC_H
15
16 #include <linux/stringify.h>
17 #include <linux/types.h>
18 #include <asm/processor.h>
19 #include <asm/cmpxchg.h>
20 #include <asm/barrier.h>
21
22 #define ATOMIC_INIT(i)  { (i) }
23
24 /*
25  * This Xtensa implementation assumes that the right mechanism
26  * for exclusion is for locking interrupts to level EXCM_LEVEL.
27  *
28  * Locking interrupts looks like this:
29  *
30  *    rsil a15, TOPLEVEL
31  *    <code>
32  *    wsr  a15, PS
33  *    rsync
34  *
35  * Note that a15 is used here because the register allocation
36  * done by the compiler is not guaranteed and a window overflow
37  * may not occur between the rsil and wsr instructions. By using
38  * a15 in the rsil, the machine is guaranteed to be in a state
39  * where no register reference will cause an overflow.
40  */
41
42 /**
43  * atomic_read - read atomic variable
44  * @v: pointer of type atomic_t
45  *
46  * Atomically reads the value of @v.
47  */
48 #define atomic_read(v)          READ_ONCE((v)->counter)
49
50 /**
51  * atomic_set - set atomic variable
52  * @v: pointer of type atomic_t
53  * @i: required value
54  *
55  * Atomically sets the value of @v to @i.
56  */
57 #define atomic_set(v,i)         WRITE_ONCE((v)->counter, (i))
58
59 #if XCHAL_HAVE_EXCLUSIVE
60 #define ATOMIC_OP(op)                                                   \
61 static inline void atomic_##op(int i, atomic_t *v)                      \
62 {                                                                       \
63         unsigned long tmp;                                              \
64         int result;                                                     \
65                                                                         \
66         __asm__ __volatile__(                                           \
67                         "1:     l32ex   %1, %3\n"                       \
68                         "       " #op " %0, %1, %2\n"                   \
69                         "       s32ex   %0, %3\n"                       \
70                         "       getex   %0\n"                           \
71                         "       beqz    %0, 1b\n"                       \
72                         : "=&a" (result), "=&a" (tmp)                   \
73                         : "a" (i), "a" (v)                              \
74                         : "memory"                                      \
75                         );                                              \
76 }                                                                       \
77
78 #define ATOMIC_OP_RETURN(op)                                            \
79 static inline int atomic_##op##_return(int i, atomic_t *v)              \
80 {                                                                       \
81         unsigned long tmp;                                              \
82         int result;                                                     \
83                                                                         \
84         __asm__ __volatile__(                                           \
85                         "1:     l32ex   %1, %3\n"                       \
86                         "       " #op " %0, %1, %2\n"                   \
87                         "       s32ex   %0, %3\n"                       \
88                         "       getex   %0\n"                           \
89                         "       beqz    %0, 1b\n"                       \
90                         "       " #op " %0, %1, %2\n"                   \
91                         : "=&a" (result), "=&a" (tmp)                   \
92                         : "a" (i), "a" (v)                              \
93                         : "memory"                                      \
94                         );                                              \
95                                                                         \
96         return result;                                                  \
97 }
98
99 #define ATOMIC_FETCH_OP(op)                                             \
100 static inline int atomic_fetch_##op(int i, atomic_t *v)                 \
101 {                                                                       \
102         unsigned long tmp;                                              \
103         int result;                                                     \
104                                                                         \
105         __asm__ __volatile__(                                           \
106                         "1:     l32ex   %1, %3\n"                       \
107                         "       " #op " %0, %1, %2\n"                   \
108                         "       s32ex   %0, %3\n"                       \
109                         "       getex   %0\n"                           \
110                         "       beqz    %0, 1b\n"                       \
111                         : "=&a" (result), "=&a" (tmp)                   \
112                         : "a" (i), "a" (v)                              \
113                         : "memory"                                      \
114                         );                                              \
115                                                                         \
116         return tmp;                                                     \
117 }
118
119 #elif XCHAL_HAVE_S32C1I
120 #define ATOMIC_OP(op)                                                   \
121 static inline void atomic_##op(int i, atomic_t * v)                     \
122 {                                                                       \
123         unsigned long tmp;                                              \
124         int result;                                                     \
125                                                                         \
126         __asm__ __volatile__(                                           \
127                         "1:     l32i    %1, %3, 0\n"                    \
128                         "       wsr     %1, scompare1\n"                \
129                         "       " #op " %0, %1, %2\n"                   \
130                         "       s32c1i  %0, %3, 0\n"                    \
131                         "       bne     %0, %1, 1b\n"                   \
132                         : "=&a" (result), "=&a" (tmp)                   \
133                         : "a" (i), "a" (v)                              \
134                         : "memory"                                      \
135                         );                                              \
136 }                                                                       \
137
138 #define ATOMIC_OP_RETURN(op)                                            \
139 static inline int atomic_##op##_return(int i, atomic_t * v)             \
140 {                                                                       \
141         unsigned long tmp;                                              \
142         int result;                                                     \
143                                                                         \
144         __asm__ __volatile__(                                           \
145                         "1:     l32i    %1, %3, 0\n"                    \
146                         "       wsr     %1, scompare1\n"                \
147                         "       " #op " %0, %1, %2\n"                   \
148                         "       s32c1i  %0, %3, 0\n"                    \
149                         "       bne     %0, %1, 1b\n"                   \
150                         "       " #op " %0, %0, %2\n"                   \
151                         : "=&a" (result), "=&a" (tmp)                   \
152                         : "a" (i), "a" (v)                              \
153                         : "memory"                                      \
154                         );                                              \
155                                                                         \
156         return result;                                                  \
157 }
158
159 #define ATOMIC_FETCH_OP(op)                                             \
160 static inline int atomic_fetch_##op(int i, atomic_t * v)                \
161 {                                                                       \
162         unsigned long tmp;                                              \
163         int result;                                                     \
164                                                                         \
165         __asm__ __volatile__(                                           \
166                         "1:     l32i    %1, %3, 0\n"                    \
167                         "       wsr     %1, scompare1\n"                \
168                         "       " #op " %0, %1, %2\n"                   \
169                         "       s32c1i  %0, %3, 0\n"                    \
170                         "       bne     %0, %1, 1b\n"                   \
171                         : "=&a" (result), "=&a" (tmp)                   \
172                         : "a" (i), "a" (v)                              \
173                         : "memory"                                      \
174                         );                                              \
175                                                                         \
176         return result;                                                  \
177 }
178
179 #else /* XCHAL_HAVE_S32C1I */
180
181 #define ATOMIC_OP(op)                                                   \
182 static inline void atomic_##op(int i, atomic_t * v)                     \
183 {                                                                       \
184         unsigned int vval;                                              \
185                                                                         \
186         __asm__ __volatile__(                                           \
187                         "       rsil    a15, "__stringify(TOPLEVEL)"\n"\
188                         "       l32i    %0, %2, 0\n"                    \
189                         "       " #op " %0, %0, %1\n"                   \
190                         "       s32i    %0, %2, 0\n"                    \
191                         "       wsr     a15, ps\n"                      \
192                         "       rsync\n"                                \
193                         : "=&a" (vval)                                  \
194                         : "a" (i), "a" (v)                              \
195                         : "a15", "memory"                               \
196                         );                                              \
197 }                                                                       \
198
199 #define ATOMIC_OP_RETURN(op)                                            \
200 static inline int atomic_##op##_return(int i, atomic_t * v)             \
201 {                                                                       \
202         unsigned int vval;                                              \
203                                                                         \
204         __asm__ __volatile__(                                           \
205                         "       rsil    a15,"__stringify(TOPLEVEL)"\n"  \
206                         "       l32i    %0, %2, 0\n"                    \
207                         "       " #op " %0, %0, %1\n"                   \
208                         "       s32i    %0, %2, 0\n"                    \
209                         "       wsr     a15, ps\n"                      \
210                         "       rsync\n"                                \
211                         : "=&a" (vval)                                  \
212                         : "a" (i), "a" (v)                              \
213                         : "a15", "memory"                               \
214                         );                                              \
215                                                                         \
216         return vval;                                                    \
217 }
218
219 #define ATOMIC_FETCH_OP(op)                                             \
220 static inline int atomic_fetch_##op(int i, atomic_t * v)                \
221 {                                                                       \
222         unsigned int tmp, vval;                                         \
223                                                                         \
224         __asm__ __volatile__(                                           \
225                         "       rsil    a15,"__stringify(TOPLEVEL)"\n"  \
226                         "       l32i    %0, %3, 0\n"                    \
227                         "       " #op " %1, %0, %2\n"                   \
228                         "       s32i    %1, %3, 0\n"                    \
229                         "       wsr     a15, ps\n"                      \
230                         "       rsync\n"                                \
231                         : "=&a" (vval), "=&a" (tmp)                     \
232                         : "a" (i), "a" (v)                              \
233                         : "a15", "memory"                               \
234                         );                                              \
235                                                                         \
236         return vval;                                                    \
237 }
238
239 #endif /* XCHAL_HAVE_S32C1I */
240
241 #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op)
242
243 ATOMIC_OPS(add)
244 ATOMIC_OPS(sub)
245
246 #undef ATOMIC_OPS
247 #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
248
249 ATOMIC_OPS(and)
250 ATOMIC_OPS(or)
251 ATOMIC_OPS(xor)
252
253 #undef ATOMIC_OPS
254 #undef ATOMIC_FETCH_OP
255 #undef ATOMIC_OP_RETURN
256 #undef ATOMIC_OP
257
258 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
259 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
260
261 #endif /* _XTENSA_ATOMIC_H */