]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - arch/mn10300/include/asm/atomic.h
041b9d69d86c63acf475e48a4c2c7263c1a722a4
[mirror_ubuntu-bionic-kernel.git] / arch / mn10300 / include / asm / atomic.h
1 /* MN10300 Atomic counter operations
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11 #ifndef _ASM_ATOMIC_H
12 #define _ASM_ATOMIC_H
13
14 #include <asm/irqflags.h>
15
16 #ifndef __ASSEMBLY__
17
18 #ifdef CONFIG_SMP
19 #ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
20 static inline
21 unsigned long __xchg(volatile unsigned long *m, unsigned long val)
22 {
23 unsigned long status;
24 unsigned long oldval;
25
26 asm volatile(
27 "1: mov %4,(_AAR,%3) \n"
28 " mov (_ADR,%3),%1 \n"
29 " mov %5,(_ADR,%3) \n"
30 " mov (_ADR,%3),%0 \n" /* flush */
31 " mov (_ASR,%3),%0 \n"
32 " or %0,%0 \n"
33 " bne 1b \n"
34 : "=&r"(status), "=&r"(oldval), "=m"(*m)
35 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
36 : "memory", "cc");
37
38 return oldval;
39 }
40
41 static inline unsigned long __cmpxchg(volatile unsigned long *m,
42 unsigned long old, unsigned long new)
43 {
44 unsigned long status;
45 unsigned long oldval;
46
47 asm volatile(
48 "1: mov %4,(_AAR,%3) \n"
49 " mov (_ADR,%3),%1 \n"
50 " cmp %5,%1 \n"
51 " bne 2f \n"
52 " mov %6,(_ADR,%3) \n"
53 "2: mov (_ADR,%3),%0 \n" /* flush */
54 " mov (_ASR,%3),%0 \n"
55 " or %0,%0 \n"
56 " bne 1b \n"
57 : "=&r"(status), "=&r"(oldval), "=m"(*m)
58 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
59 "r"(old), "r"(new)
60 : "memory", "cc");
61
62 return oldval;
63 }
64 #else /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
65 #error "No SMP atomic operation support!"
66 #endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
67
68 #else /* CONFIG_SMP */
69
70 /*
71 * Emulate xchg for non-SMP MN10300
72 */
73 struct __xchg_dummy { unsigned long a[100]; };
74 #define __xg(x) ((struct __xchg_dummy *)(x))
75
76 static inline
77 unsigned long __xchg(volatile unsigned long *m, unsigned long val)
78 {
79 unsigned long oldval;
80 unsigned long flags;
81
82 flags = arch_local_cli_save();
83 oldval = *m;
84 *m = val;
85 arch_local_irq_restore(flags);
86 return oldval;
87 }
88
89 /*
90 * Emulate cmpxchg for non-SMP MN10300
91 */
92 static inline unsigned long __cmpxchg(volatile unsigned long *m,
93 unsigned long old, unsigned long new)
94 {
95 unsigned long oldval;
96 unsigned long flags;
97
98 flags = arch_local_cli_save();
99 oldval = *m;
100 if (oldval == old)
101 *m = new;
102 arch_local_irq_restore(flags);
103 return oldval;
104 }
105
106 #endif /* CONFIG_SMP */
107
108 #define xchg(ptr, v) \
109 ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \
110 (unsigned long)(v)))
111
112 #define cmpxchg(ptr, o, n) \
113 ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
114 (unsigned long)(o), \
115 (unsigned long)(n)))
116
117 #define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v)))
118 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
119
120 #endif /* !__ASSEMBLY__ */
121
122 #ifndef CONFIG_SMP
123 #include <asm-generic/atomic.h>
124 #else
125
126 /*
127 * Atomic operations that C can't guarantee us. Useful for
128 * resource counting etc..
129 */
130
131 #define ATOMIC_INIT(i) { (i) }
132
133 #ifdef __KERNEL__
134
135 /**
136 * atomic_read - read atomic variable
137 * @v: pointer of type atomic_t
138 *
139 * Atomically reads the value of @v. Note that the guaranteed
140 * useful range of an atomic_t is only 24 bits.
141 */
142 #define atomic_read(v) (ACCESS_ONCE((v)->counter))
143
144 /**
145 * atomic_set - set atomic variable
146 * @v: pointer of type atomic_t
147 * @i: required value
148 *
149 * Atomically sets the value of @v to @i. Note that the guaranteed
150 * useful range of an atomic_t is only 24 bits.
151 */
152 #define atomic_set(v, i) (((v)->counter) = (i))
153
154 /**
155 * atomic_add_return - add integer to atomic variable
156 * @i: integer value to add
157 * @v: pointer of type atomic_t
158 *
159 * Atomically adds @i to @v and returns the result
160 * Note that the guaranteed useful range of an atomic_t is only 24 bits.
161 */
162 static inline int atomic_add_return(int i, atomic_t *v)
163 {
164 int retval;
165 #ifdef CONFIG_SMP
166 int status;
167
168 asm volatile(
169 "1: mov %4,(_AAR,%3) \n"
170 " mov (_ADR,%3),%1 \n"
171 " add %5,%1 \n"
172 " mov %1,(_ADR,%3) \n"
173 " mov (_ADR,%3),%0 \n" /* flush */
174 " mov (_ASR,%3),%0 \n"
175 " or %0,%0 \n"
176 " bne 1b \n"
177 : "=&r"(status), "=&r"(retval), "=m"(v->counter)
178 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
179 : "memory", "cc");
180
181 #else
182 unsigned long flags;
183
184 flags = arch_local_cli_save();
185 retval = v->counter;
186 retval += i;
187 v->counter = retval;
188 arch_local_irq_restore(flags);
189 #endif
190 return retval;
191 }
192
193 /**
194 * atomic_sub_return - subtract integer from atomic variable
195 * @i: integer value to subtract
196 * @v: pointer of type atomic_t
197 *
198 * Atomically subtracts @i from @v and returns the result
199 * Note that the guaranteed useful range of an atomic_t is only 24 bits.
200 */
201 static inline int atomic_sub_return(int i, atomic_t *v)
202 {
203 int retval;
204 #ifdef CONFIG_SMP
205 int status;
206
207 asm volatile(
208 "1: mov %4,(_AAR,%3) \n"
209 " mov (_ADR,%3),%1 \n"
210 " sub %5,%1 \n"
211 " mov %1,(_ADR,%3) \n"
212 " mov (_ADR,%3),%0 \n" /* flush */
213 " mov (_ASR,%3),%0 \n"
214 " or %0,%0 \n"
215 " bne 1b \n"
216 : "=&r"(status), "=&r"(retval), "=m"(v->counter)
217 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
218 : "memory", "cc");
219
220 #else
221 unsigned long flags;
222 flags = arch_local_cli_save();
223 retval = v->counter;
224 retval -= i;
225 v->counter = retval;
226 arch_local_irq_restore(flags);
227 #endif
228 return retval;
229 }
230
231 static inline int atomic_add_negative(int i, atomic_t *v)
232 {
233 return atomic_add_return(i, v) < 0;
234 }
235
236 static inline void atomic_add(int i, atomic_t *v)
237 {
238 atomic_add_return(i, v);
239 }
240
241 static inline void atomic_sub(int i, atomic_t *v)
242 {
243 atomic_sub_return(i, v);
244 }
245
246 static inline void atomic_inc(atomic_t *v)
247 {
248 atomic_add_return(1, v);
249 }
250
251 static inline void atomic_dec(atomic_t *v)
252 {
253 atomic_sub_return(1, v);
254 }
255
256 #define atomic_dec_return(v) atomic_sub_return(1, (v))
257 #define atomic_inc_return(v) atomic_add_return(1, (v))
258
259 #define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
260 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
261 #define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
262
263 #define atomic_add_unless(v, a, u) \
264 ({ \
265 int c, old; \
266 c = atomic_read(v); \
267 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
268 c = old; \
269 c != (u); \
270 })
271
272
273 /**
274 * atomic_clear_mask - Atomically clear bits in memory
275 * @mask: Mask of the bits to be cleared
276 * @v: pointer to word in memory
277 *
278 * Atomically clears the bits set in mask from the memory word specified.
279 */
280 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
281 {
282 #ifdef CONFIG_SMP
283 int status;
284
285 asm volatile(
286 "1: mov %3,(_AAR,%2) \n"
287 " mov (_ADR,%2),%0 \n"
288 " and %4,%0 \n"
289 " mov %0,(_ADR,%2) \n"
290 " mov (_ADR,%2),%0 \n" /* flush */
291 " mov (_ASR,%2),%0 \n"
292 " or %0,%0 \n"
293 " bne 1b \n"
294 : "=&r"(status), "=m"(*addr)
295 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask)
296 : "memory", "cc");
297 #else
298 unsigned long flags;
299
300 mask = ~mask;
301 flags = arch_local_cli_save();
302 *addr &= mask;
303 arch_local_irq_restore(flags);
304 #endif
305 }
306
307 /**
308 * atomic_set_mask - Atomically set bits in memory
309 * @mask: Mask of the bits to be set
310 * @v: pointer to word in memory
311 *
312 * Atomically sets the bits set in mask from the memory word specified.
313 */
314 static inline void atomic_set_mask(unsigned long mask, unsigned long *addr)
315 {
316 #ifdef CONFIG_SMP
317 int status;
318
319 asm volatile(
320 "1: mov %3,(_AAR,%2) \n"
321 " mov (_ADR,%2),%0 \n"
322 " or %4,%0 \n"
323 " mov %0,(_ADR,%2) \n"
324 " mov (_ADR,%2),%0 \n" /* flush */
325 " mov (_ASR,%2),%0 \n"
326 " or %0,%0 \n"
327 " bne 1b \n"
328 : "=&r"(status), "=m"(*addr)
329 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask)
330 : "memory", "cc");
331 #else
332 unsigned long flags;
333
334 flags = arch_local_cli_save();
335 *addr |= mask;
336 arch_local_irq_restore(flags);
337 #endif
338 }
339
340 /* Atomic operations are already serializing on MN10300??? */
341 #define smp_mb__before_atomic_dec() barrier()
342 #define smp_mb__after_atomic_dec() barrier()
343 #define smp_mb__before_atomic_inc() barrier()
344 #define smp_mb__after_atomic_inc() barrier()
345
346 #include <asm-generic/atomic-long.h>
347
348 #endif /* __KERNEL__ */
349 #endif /* CONFIG_SMP */
350 #endif /* _ASM_ATOMIC_H */