]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/m32r/include/asm/atomic.h
Merge remote-tracking branch 'input/next'
[karo-tx-linux.git] / arch / m32r / include / asm / atomic.h
1 #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
12 #include <linux/types.h>
13 #include <asm/assembler.h>
14 #include <asm/cmpxchg.h>
15 #include <asm/dcache_clear.h>
16 #include <asm/barrier.h>
17
18 /*
19  * Atomic operations that C can't guarantee us.  Useful for
20  * resource counting etc..
21  */
22
23 #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  */
31 #define atomic_read(v)  READ_ONCE((v)->counter)
32
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) WRITE_ONCE(((v)->counter), (i))
41
42 #ifdef CONFIG_CHIP_M32700_TS1
43 #define __ATOMIC_CLOBBER        , "r4"
44 #else
45 #define __ATOMIC_CLOBBER
46 #endif
47
48 #define ATOMIC_OP(op)                                                   \
49 static __inline__ void atomic_##op(int i, atomic_t *v)                  \
50 {                                                                       \
51         unsigned long flags;                                            \
52         int result;                                                     \
53                                                                         \
54         local_irq_save(flags);                                          \
55         __asm__ __volatile__ (                                          \
56                 "# atomic_" #op "               \n\t"                   \
57                 DCACHE_CLEAR("%0", "r4", "%1")                          \
58                 M32R_LOCK" %0, @%1;             \n\t"                   \
59                 #op " %0, %2;                   \n\t"                   \
60                 M32R_UNLOCK" %0, @%1;           \n\t"                   \
61                 : "=&r" (result)                                        \
62                 : "r" (&v->counter), "r" (i)                            \
63                 : "memory"                                              \
64                 __ATOMIC_CLOBBER                                        \
65         );                                                              \
66         local_irq_restore(flags);                                       \
67 }                                                                       \
68
69 #define ATOMIC_OP_RETURN(op)                                            \
70 static __inline__ int atomic_##op##_return(int i, atomic_t *v)          \
71 {                                                                       \
72         unsigned long flags;                                            \
73         int result;                                                     \
74                                                                         \
75         local_irq_save(flags);                                          \
76         __asm__ __volatile__ (                                          \
77                 "# atomic_" #op "_return        \n\t"                   \
78                 DCACHE_CLEAR("%0", "r4", "%1")                          \
79                 M32R_LOCK" %0, @%1;             \n\t"                   \
80                 #op " %0, %2;                   \n\t"                   \
81                 M32R_UNLOCK" %0, @%1;           \n\t"                   \
82                 : "=&r" (result)                                        \
83                 : "r" (&v->counter), "r" (i)                            \
84                 : "memory"                                              \
85                 __ATOMIC_CLOBBER                                        \
86         );                                                              \
87         local_irq_restore(flags);                                       \
88                                                                         \
89         return result;                                                  \
90 }
91
92 #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
93
94 ATOMIC_OPS(add)
95 ATOMIC_OPS(sub)
96
97 ATOMIC_OP(and)
98 ATOMIC_OP(or)
99 ATOMIC_OP(xor)
100
101 #undef ATOMIC_OPS
102 #undef ATOMIC_OP_RETURN
103 #undef ATOMIC_OP
104
105 /**
106  * atomic_sub_and_test - subtract value from variable and test result
107  * @i: integer value to subtract
108  * @v: pointer of type atomic_t
109  *
110  * Atomically subtracts @i from @v and returns
111  * true if the result is zero, or false for all
112  * other cases.
113  */
114 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
115
116 /**
117  * atomic_inc_return - increment atomic variable and return it
118  * @v: pointer of type atomic_t
119  *
120  * Atomically increments @v by 1 and returns the result.
121  */
122 static __inline__ int atomic_inc_return(atomic_t *v)
123 {
124         unsigned long flags;
125         int result;
126
127         local_irq_save(flags);
128         __asm__ __volatile__ (
129                 "# atomic_inc_return            \n\t"
130                 DCACHE_CLEAR("%0", "r4", "%1")
131                 M32R_LOCK" %0, @%1;             \n\t"
132                 "addi   %0, #1;                 \n\t"
133                 M32R_UNLOCK" %0, @%1;           \n\t"
134                 : "=&r" (result)
135                 : "r" (&v->counter)
136                 : "memory"
137                 __ATOMIC_CLOBBER
138         );
139         local_irq_restore(flags);
140
141         return result;
142 }
143
144 /**
145  * atomic_dec_return - decrement atomic variable and return it
146  * @v: pointer of type atomic_t
147  *
148  * Atomically decrements @v by 1 and returns the result.
149  */
150 static __inline__ int atomic_dec_return(atomic_t *v)
151 {
152         unsigned long flags;
153         int result;
154
155         local_irq_save(flags);
156         __asm__ __volatile__ (
157                 "# atomic_dec_return            \n\t"
158                 DCACHE_CLEAR("%0", "r4", "%1")
159                 M32R_LOCK" %0, @%1;             \n\t"
160                 "addi   %0, #-1;                \n\t"
161                 M32R_UNLOCK" %0, @%1;           \n\t"
162                 : "=&r" (result)
163                 : "r" (&v->counter)
164                 : "memory"
165                 __ATOMIC_CLOBBER
166         );
167         local_irq_restore(flags);
168
169         return result;
170 }
171
172 /**
173  * atomic_inc - increment atomic variable
174  * @v: pointer of type atomic_t
175  *
176  * Atomically increments @v by 1.
177  */
178 #define atomic_inc(v) ((void)atomic_inc_return(v))
179
180 /**
181  * atomic_dec - decrement atomic variable
182  * @v: pointer of type atomic_t
183  *
184  * Atomically decrements @v by 1.
185  */
186 #define atomic_dec(v) ((void)atomic_dec_return(v))
187
188 /**
189  * atomic_inc_and_test - increment and test
190  * @v: pointer of type atomic_t
191  *
192  * Atomically increments @v by 1
193  * and returns true if the result is zero, or false for all
194  * other cases.
195  */
196 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
197
198 /**
199  * atomic_dec_and_test - decrement and test
200  * @v: pointer of type atomic_t
201  *
202  * Atomically decrements @v by 1 and
203  * returns true if the result is 0, or false for all
204  * other cases.
205  */
206 #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
207
208 /**
209  * atomic_add_negative - add and test if negative
210  * @v: pointer of type atomic_t
211  * @i: integer value to add
212  *
213  * Atomically adds @i to @v and returns true
214  * if the result is negative, or false when
215  * result is greater than or equal to zero.
216  */
217 #define atomic_add_negative(i,v) (atomic_add_return((i), (v)) < 0)
218
219 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
220 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
221
222 /**
223  * __atomic_add_unless - add unless the number is a given value
224  * @v: pointer of type atomic_t
225  * @a: the amount to add to v...
226  * @u: ...unless v is equal to u.
227  *
228  * Atomically adds @a to @v, so long as it was not @u.
229  * Returns the old value of @v.
230  */
231 static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
232 {
233         int c, old;
234         c = atomic_read(v);
235         for (;;) {
236                 if (unlikely(c == (u)))
237                         break;
238                 old = atomic_cmpxchg((v), c, c + (a));
239                 if (likely(old == c))
240                         break;
241                 c = old;
242         }
243         return c;
244 }
245
246 #endif  /* _ASM_M32R_ATOMIC_H */