Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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) \
61static inline void atomic_##op(int i, atomic_t *v) \
62{ \
63 unsigned long tmp; \
64 int result; \
65 \
66 __asm__ __volatile__( \
67 "1: l32ex %[tmp], %[addr]\n" \
68 " " #op " %[result], %[tmp], %[i]\n" \
69 " s32ex %[result], %[addr]\n" \
70 " getex %[result]\n" \
71 " beqz %[result], 1b\n" \
72 : [result] "=&a" (result), [tmp] "=&a" (tmp) \
73 : [i] "a" (i), [addr] "a" (v) \
74 : "memory" \
75 ); \
76} \
77
78#define ATOMIC_OP_RETURN(op) \
79static 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 %[tmp], %[addr]\n" \
86 " " #op " %[result], %[tmp], %[i]\n" \
87 " s32ex %[result], %[addr]\n" \
88 " getex %[result]\n" \
89 " beqz %[result], 1b\n" \
90 " " #op " %[result], %[tmp], %[i]\n" \
91 : [result] "=&a" (result), [tmp] "=&a" (tmp) \
92 : [i] "a" (i), [addr] "a" (v) \
93 : "memory" \
94 ); \
95 \
96 return result; \
97}
98
99#define ATOMIC_FETCH_OP(op) \
100static 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 %[tmp], %[addr]\n" \
107 " " #op " %[result], %[tmp], %[i]\n" \
108 " s32ex %[result], %[addr]\n" \
109 " getex %[result]\n" \
110 " beqz %[result], 1b\n" \
111 : [result] "=&a" (result), [tmp] "=&a" (tmp) \
112 : [i] "a" (i), [addr] "a" (v) \
113 : "memory" \
114 ); \
115 \
116 return tmp; \
117}
118
119#elif XCHAL_HAVE_S32C1I
120#define ATOMIC_OP(op) \
121static inline void atomic_##op(int i, atomic_t * v) \
122{ \
123 unsigned long tmp; \
124 int result; \
125 \
126 __asm__ __volatile__( \
127 "1: l32i %[tmp], %[mem]\n" \
128 " wsr %[tmp], scompare1\n" \
129 " " #op " %[result], %[tmp], %[i]\n" \
130 " s32c1i %[result], %[mem]\n" \
131 " bne %[result], %[tmp], 1b\n" \
132 : [result] "=&a" (result), [tmp] "=&a" (tmp), \
133 [mem] "+m" (*v) \
134 : [i] "a" (i) \
135 : "memory" \
136 ); \
137} \
138
139#define ATOMIC_OP_RETURN(op) \
140static inline int atomic_##op##_return(int i, atomic_t * v) \
141{ \
142 unsigned long tmp; \
143 int result; \
144 \
145 __asm__ __volatile__( \
146 "1: l32i %[tmp], %[mem]\n" \
147 " wsr %[tmp], scompare1\n" \
148 " " #op " %[result], %[tmp], %[i]\n" \
149 " s32c1i %[result], %[mem]\n" \
150 " bne %[result], %[tmp], 1b\n" \
151 " " #op " %[result], %[result], %[i]\n" \
152 : [result] "=&a" (result), [tmp] "=&a" (tmp), \
153 [mem] "+m" (*v) \
154 : [i] "a" (i) \
155 : "memory" \
156 ); \
157 \
158 return result; \
159}
160
161#define ATOMIC_FETCH_OP(op) \
162static inline int atomic_fetch_##op(int i, atomic_t * v) \
163{ \
164 unsigned long tmp; \
165 int result; \
166 \
167 __asm__ __volatile__( \
168 "1: l32i %[tmp], %[mem]\n" \
169 " wsr %[tmp], scompare1\n" \
170 " " #op " %[result], %[tmp], %[i]\n" \
171 " s32c1i %[result], %[mem]\n" \
172 " bne %[result], %[tmp], 1b\n" \
173 : [result] "=&a" (result), [tmp] "=&a" (tmp), \
174 [mem] "+m" (*v) \
175 : [i] "a" (i) \
176 : "memory" \
177 ); \
178 \
179 return result; \
180}
181
182#else /* XCHAL_HAVE_S32C1I */
183
184#define ATOMIC_OP(op) \
185static inline void atomic_##op(int i, atomic_t * v) \
186{ \
187 unsigned int vval; \
188 \
189 __asm__ __volatile__( \
190 " rsil a15, "__stringify(TOPLEVEL)"\n" \
191 " l32i %[result], %[mem]\n" \
192 " " #op " %[result], %[result], %[i]\n" \
193 " s32i %[result], %[mem]\n" \
194 " wsr a15, ps\n" \
195 " rsync\n" \
196 : [result] "=&a" (vval), [mem] "+m" (*v) \
197 : [i] "a" (i) \
198 : "a15", "memory" \
199 ); \
200} \
201
202#define ATOMIC_OP_RETURN(op) \
203static inline int atomic_##op##_return(int i, atomic_t * v) \
204{ \
205 unsigned int vval; \
206 \
207 __asm__ __volatile__( \
208 " rsil a15,"__stringify(TOPLEVEL)"\n" \
209 " l32i %[result], %[mem]\n" \
210 " " #op " %[result], %[result], %[i]\n" \
211 " s32i %[result], %[mem]\n" \
212 " wsr a15, ps\n" \
213 " rsync\n" \
214 : [result] "=&a" (vval), [mem] "+m" (*v) \
215 : [i] "a" (i) \
216 : "a15", "memory" \
217 ); \
218 \
219 return vval; \
220}
221
222#define ATOMIC_FETCH_OP(op) \
223static inline int atomic_fetch_##op(int i, atomic_t * v) \
224{ \
225 unsigned int tmp, vval; \
226 \
227 __asm__ __volatile__( \
228 " rsil a15,"__stringify(TOPLEVEL)"\n" \
229 " l32i %[result], %[mem]\n" \
230 " " #op " %[tmp], %[result], %[i]\n" \
231 " s32i %[tmp], %[mem]\n" \
232 " wsr a15, ps\n" \
233 " rsync\n" \
234 : [result] "=&a" (vval), [tmp] "=&a" (tmp), \
235 [mem] "+m" (*v) \
236 : [i] "a" (i) \
237 : "a15", "memory" \
238 ); \
239 \
240 return vval; \
241}
242
243#endif /* XCHAL_HAVE_S32C1I */
244
245#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op)
246
247ATOMIC_OPS(add)
248ATOMIC_OPS(sub)
249
250#undef ATOMIC_OPS
251#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
252
253ATOMIC_OPS(and)
254ATOMIC_OPS(or)
255ATOMIC_OPS(xor)
256
257#undef ATOMIC_OPS
258#undef ATOMIC_FETCH_OP
259#undef ATOMIC_OP_RETURN
260#undef ATOMIC_OP
261
262#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
263#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
264
265#endif /* _XTENSA_ATOMIC_H */