blob: 8ad0ed4182a5407d1ace08505dfc805b7e05b24f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#ifndef _ASM_M32R_ATOMIC_H
2#define _ASM_M32R_ATOMIC_H
3
4/*
5 * linux/include/asm-m32r/atomic.h
6 *
7 * M32R version:
8 * Copyright (C) 2001, 2002 Hitoshi Yamamoto
9 * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
10 */
11
Matthew Wilcoxea4354672009-01-06 14:40:39 -080012#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <asm/assembler.h>
David Howellsc9034c32012-03-28 18:30:02 +010014#include <asm/cmpxchg.h>
15#include <asm/dcache_clear.h>
Peter Zijlstra89607d52014-03-13 19:00:36 +010016#include <asm/barrier.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
18/*
19 * Atomic operations that C can't guarantee us. Useful for
20 * resource counting etc..
21 */
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#define ATOMIC_INIT(i) { (i) }
24
25/**
26 * atomic_read - read atomic variable
27 * @v: pointer of type atomic_t
28 *
29 * Atomically reads the value of @v.
30 */
Anton Blanchardf3d46f92010-05-17 14:33:53 +100031#define atomic_read(v) (*(volatile int *)&(v)->counter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33/**
34 * atomic_set - set atomic variable
35 * @v: pointer of type atomic_t
36 * @i: required value
37 *
38 * Atomically sets the value of @v to @i.
39 */
40#define atomic_set(v,i) (((v)->counter) = (i))
41
42/**
43 * atomic_add_return - add integer to atomic variable and return it
44 * @i: integer value to add
45 * @v: pointer of type atomic_t
46 *
47 * Atomically adds @i to @v and return (@i + @v).
48 */
49static __inline__ int atomic_add_return(int i, atomic_t *v)
50{
51 unsigned long flags;
52 int result;
53
54 local_irq_save(flags);
55 __asm__ __volatile__ (
56 "# atomic_add_return \n\t"
57 DCACHE_CLEAR("%0", "r4", "%1")
58 M32R_LOCK" %0, @%1; \n\t"
59 "add %0, %2; \n\t"
60 M32R_UNLOCK" %0, @%1; \n\t"
61 : "=&r" (result)
62 : "r" (&v->counter), "r" (i)
63 : "memory"
64#ifdef CONFIG_CHIP_M32700_TS1
65 , "r4"
66#endif /* CONFIG_CHIP_M32700_TS1 */
67 );
68 local_irq_restore(flags);
69
70 return result;
71}
72
73/**
74 * atomic_sub_return - subtract integer from atomic variable and return it
75 * @i: integer value to subtract
76 * @v: pointer of type atomic_t
77 *
78 * Atomically subtracts @i from @v and return (@v - @i).
79 */
80static __inline__ int atomic_sub_return(int i, atomic_t *v)
81{
82 unsigned long flags;
83 int result;
84
85 local_irq_save(flags);
86 __asm__ __volatile__ (
87 "# atomic_sub_return \n\t"
88 DCACHE_CLEAR("%0", "r4", "%1")
89 M32R_LOCK" %0, @%1; \n\t"
90 "sub %0, %2; \n\t"
91 M32R_UNLOCK" %0, @%1; \n\t"
92 : "=&r" (result)
93 : "r" (&v->counter), "r" (i)
94 : "memory"
95#ifdef CONFIG_CHIP_M32700_TS1
96 , "r4"
97#endif /* CONFIG_CHIP_M32700_TS1 */
98 );
99 local_irq_restore(flags);
100
101 return result;
102}
103
104/**
105 * atomic_add - add integer to atomic variable
106 * @i: integer value to add
107 * @v: pointer of type atomic_t
108 *
109 * Atomically adds @i to @v.
110 */
111#define atomic_add(i,v) ((void) atomic_add_return((i), (v)))
112
113/**
114 * atomic_sub - subtract the atomic variable
115 * @i: integer value to subtract
116 * @v: pointer of type atomic_t
117 *
118 * Atomically subtracts @i from @v.
119 */
120#define atomic_sub(i,v) ((void) atomic_sub_return((i), (v)))
121
122/**
123 * atomic_sub_and_test - subtract value from variable and test result
124 * @i: integer value to subtract
125 * @v: pointer of type atomic_t
126 *
127 * Atomically subtracts @i from @v and returns
128 * true if the result is zero, or false for all
129 * other cases.
130 */
131#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
132
133/**
134 * atomic_inc_return - increment atomic variable and return it
135 * @v: pointer of type atomic_t
136 *
137 * Atomically increments @v by 1 and returns the result.
138 */
139static __inline__ int atomic_inc_return(atomic_t *v)
140{
141 unsigned long flags;
142 int result;
143
144 local_irq_save(flags);
145 __asm__ __volatile__ (
146 "# atomic_inc_return \n\t"
147 DCACHE_CLEAR("%0", "r4", "%1")
148 M32R_LOCK" %0, @%1; \n\t"
149 "addi %0, #1; \n\t"
150 M32R_UNLOCK" %0, @%1; \n\t"
151 : "=&r" (result)
152 : "r" (&v->counter)
153 : "memory"
154#ifdef CONFIG_CHIP_M32700_TS1
155 , "r4"
156#endif /* CONFIG_CHIP_M32700_TS1 */
157 );
158 local_irq_restore(flags);
159
160 return result;
161}
162
163/**
164 * atomic_dec_return - decrement atomic variable and return it
165 * @v: pointer of type atomic_t
166 *
167 * Atomically decrements @v by 1 and returns the result.
168 */
169static __inline__ int atomic_dec_return(atomic_t *v)
170{
171 unsigned long flags;
172 int result;
173
174 local_irq_save(flags);
175 __asm__ __volatile__ (
176 "# atomic_dec_return \n\t"
177 DCACHE_CLEAR("%0", "r4", "%1")
178 M32R_LOCK" %0, @%1; \n\t"
179 "addi %0, #-1; \n\t"
180 M32R_UNLOCK" %0, @%1; \n\t"
181 : "=&r" (result)
182 : "r" (&v->counter)
183 : "memory"
184#ifdef CONFIG_CHIP_M32700_TS1
185 , "r4"
186#endif /* CONFIG_CHIP_M32700_TS1 */
187 );
188 local_irq_restore(flags);
189
190 return result;
191}
192
193/**
194 * atomic_inc - increment atomic variable
195 * @v: pointer of type atomic_t
196 *
197 * Atomically increments @v by 1.
198 */
199#define atomic_inc(v) ((void)atomic_inc_return(v))
200
201/**
202 * atomic_dec - decrement atomic variable
203 * @v: pointer of type atomic_t
204 *
205 * Atomically decrements @v by 1.
206 */
207#define atomic_dec(v) ((void)atomic_dec_return(v))
208
209/**
210 * atomic_inc_and_test - increment and test
211 * @v: pointer of type atomic_t
212 *
213 * Atomically increments @v by 1
214 * and returns true if the result is zero, or false for all
215 * other cases.
216 */
217#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
218
219/**
220 * atomic_dec_and_test - decrement and test
221 * @v: pointer of type atomic_t
222 *
223 * Atomically decrements @v by 1 and
224 * returns true if the result is 0, or false for all
225 * other cases.
226 */
227#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
228
229/**
230 * atomic_add_negative - add and test if negative
231 * @v: pointer of type atomic_t
232 * @i: integer value to add
233 *
234 * Atomically adds @i to @v and returns true
235 * if the result is negative, or false when
236 * result is greater than or equal to zero.
237 */
238#define atomic_add_negative(i,v) (atomic_add_return((i), (v)) < 0)
239
Hirokazu Takata0332db52005-11-28 13:43:59 -0800240#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
Ingo Molnarffbf6702006-01-09 15:59:17 -0800241#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
Hirokazu Takata0332db52005-11-28 13:43:59 -0800242
243/**
Arun Sharmaf24219b2011-07-26 16:09:07 -0700244 * __atomic_add_unless - add unless the number is a given value
Hirokazu Takata0332db52005-11-28 13:43:59 -0800245 * @v: pointer of type atomic_t
246 * @a: the amount to add to v...
247 * @u: ...unless v is equal to u.
248 *
249 * Atomically adds @a to @v, so long as it was not @u.
Arun Sharmaf24219b2011-07-26 16:09:07 -0700250 * Returns the old value of @v.
Hirokazu Takata0332db52005-11-28 13:43:59 -0800251 */
Arun Sharmaf24219b2011-07-26 16:09:07 -0700252static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
Mathieu Desnoyers2856f5e2007-05-08 00:34:38 -0700253{
254 int c, old;
255 c = atomic_read(v);
256 for (;;) {
257 if (unlikely(c == (u)))
258 break;
259 old = atomic_cmpxchg((v), c, c + (a));
260 if (likely(old == c))
261 break;
262 c = old;
263 }
Arun Sharmaf24219b2011-07-26 16:09:07 -0700264 return c;
Mathieu Desnoyers2856f5e2007-05-08 00:34:38 -0700265}
266
Hirokazu Takata0332db52005-11-28 13:43:59 -0800267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *addr)
269{
270 unsigned long flags;
271 unsigned long tmp;
272
273 local_irq_save(flags);
274 __asm__ __volatile__ (
275 "# atomic_clear_mask \n\t"
276 DCACHE_CLEAR("%0", "r5", "%1")
277 M32R_LOCK" %0, @%1; \n\t"
278 "and %0, %2; \n\t"
279 M32R_UNLOCK" %0, @%1; \n\t"
280 : "=&r" (tmp)
281 : "r" (addr), "r" (~mask)
282 : "memory"
283#ifdef CONFIG_CHIP_M32700_TS1
284 , "r5"
285#endif /* CONFIG_CHIP_M32700_TS1 */
286 );
287 local_irq_restore(flags);
288}
289
290static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *addr)
291{
292 unsigned long flags;
293 unsigned long tmp;
294
295 local_irq_save(flags);
296 __asm__ __volatile__ (
297 "# atomic_set_mask \n\t"
298 DCACHE_CLEAR("%0", "r5", "%1")
299 M32R_LOCK" %0, @%1; \n\t"
300 "or %0, %2; \n\t"
301 M32R_UNLOCK" %0, @%1; \n\t"
302 : "=&r" (tmp)
303 : "r" (addr), "r" (mask)
304 : "memory"
305#ifdef CONFIG_CHIP_M32700_TS1
306 , "r5"
307#endif /* CONFIG_CHIP_M32700_TS1 */
308 );
309 local_irq_restore(flags);
310}
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312#endif /* _ASM_M32R_ATOMIC_H */