blob: b9a8f8461262b1ce045355ce811d5a9c500b27aa [file] [log] [blame]
Mark Salter4f81ca12010-10-27 17:28:52 +01001/* 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
20static inline
21unsigned 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
41static 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 */
73struct __xchg_dummy { unsigned long a[100]; };
74#define __xg(x) ((struct __xchg_dummy *)(x))
75
76static inline
77unsigned 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 */
92static 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
Mathieu Desnoyers366831612010-05-24 14:32:56 -0700123#include <asm-generic/atomic.h>
Mark Salter4f81ca12010-10-27 17:28:52 +0100124#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 */
David Howellsaf794202011-03-14 14:49:44 +0000142#define atomic_read(v) (ACCESS_ONCE((v)->counter))
Mark Salter4f81ca12010-10-27 17:28:52 +0100143
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 */
162static 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 */
201static 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
231static inline int atomic_add_negative(int i, atomic_t *v)
232{
233 return atomic_add_return(i, v) < 0;
234}
235
236static inline void atomic_add(int i, atomic_t *v)
237{
238 atomic_add_return(i, v);
239}
240
241static inline void atomic_sub(int i, atomic_t *v)
242{
243 atomic_sub_return(i, v);
244}
245
246static inline void atomic_inc(atomic_t *v)
247{
248 atomic_add_return(1, v);
249}
250
251static 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
Arun Sharmaf24219b2011-07-26 16:09:07 -0700263#define __atomic_add_unless(v, a, u) \
Mark Salter4f81ca12010-10-27 17:28:52 +0100264({ \
265 int c, old; \
266 c = atomic_read(v); \
267 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
268 c = old; \
Arun Sharmaf24219b2011-07-26 16:09:07 -0700269 c; \
Mark Salter4f81ca12010-10-27 17:28:52 +0100270})
271
Mark Salter4f81ca12010-10-27 17:28:52 +0100272
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 */
280static 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 */
314static 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
Mark Salter4f81ca12010-10-27 17:28:52 +0100346#endif /* __KERNEL__ */
347#endif /* CONFIG_SMP */
348#endif /* _ASM_ATOMIC_H */