File: /usr/src/linux/include/asm-mips/atomic.h

1     /*
2      * Atomic operations that C can't guarantee us.  Useful for
3      * resource counting etc..
4      *
5      * But use these as seldom as possible since they are much more slower
6      * than regular operations.
7      *
8      * This file is subject to the terms and conditions of the GNU General Public
9      * License.  See the file "COPYING" in the main directory of this archive
10      * for more details.
11      *
12      * Copyright (C) 1996, 1997, 2000 by Ralf Baechle
13      */
14     #ifndef __ASM_ATOMIC_H
15     #define __ASM_ATOMIC_H
16     
17     #include <linux/config.h>
18     
19     typedef struct { volatile int counter; } atomic_t;
20     
21     #ifdef __KERNEL__
22     #define ATOMIC_INIT(i)    { (i) }
23     
24     /*
25      * atomic_read - read atomic variable
26      * @v: pointer of type atomic_t
27      *
28      * Atomically reads the value of @v.  Note that the guaranteed
29      * useful range of an atomic_t is only 24 bits.
30      */
31     #define atomic_read(v)	((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.  Note that the guaranteed
39      * useful range of an atomic_t is only 24 bits.
40      */
41     #define atomic_set(v,i)	((v)->counter = (i))
42     
43     #ifndef CONFIG_CPU_HAS_LLSC
44     
45     #include <asm/system.h>
46     
47     /*
48      * The MIPS I implementation is only atomic with respect to
49      * interrupts.  R3000 based multiprocessor machines are rare anyway ...
50      *
51      * atomic_add - add integer to atomic variable
52      * @i: integer value to add
53      * @v: pointer of type atomic_t
54      *
55      * Atomically adds @i to @v.  Note that the guaranteed useful range
56      * of an atomic_t is only 24 bits.
57      */
58     extern __inline__ void atomic_add(int i, atomic_t * v)
59     {
60     	int	flags;
61     
62     	save_flags(flags);
63     	cli();
64     	v->counter += i;
65     	restore_flags(flags);
66     }
67     
68     /*
69      * atomic_sub - subtract the atomic variable
70      * @i: integer value to subtract
71      * @v: pointer of type atomic_t
72      *
73      * Atomically subtracts @i from @v.  Note that the guaranteed
74      * useful range of an atomic_t is only 24 bits.
75      */
76     extern __inline__ void atomic_sub(int i, atomic_t * v)
77     {
78     	int	flags;
79     
80     	save_flags(flags);
81     	cli();
82     	v->counter -= i;
83     	restore_flags(flags);
84     }
85     
86     extern __inline__ int atomic_add_return(int i, atomic_t * v)
87     {
88     	int	temp, flags;
89     
90     	save_flags(flags);
91     	cli();
92     	temp = v->counter;
93     	temp += i;
94     	v->counter = temp;
95     	restore_flags(flags);
96     
97     	return temp;
98     }
99     
100     extern __inline__ int atomic_sub_return(int i, atomic_t * v)
101     {
102     	int	temp, flags;
103     
104     	save_flags(flags);
105     	cli();
106     	temp = v->counter;
107     	temp -= i;
108     	v->counter = temp;
109     	restore_flags(flags);
110     
111     	return temp;
112     }
113     
114     #else
115     
116     /*
117      * ... while for MIPS II and better we can use ll/sc instruction.  This
118      * implementation is SMP safe ...
119      */
120     
121     /*
122      * atomic_add - add integer to atomic variable
123      * @i: integer value to add
124      * @v: pointer of type atomic_t
125      *
126      * Atomically adds @i to @v.  Note that the guaranteed useful range
127      * of an atomic_t is only 24 bits.
128      */
129     extern __inline__ void atomic_add(int i, atomic_t * v)
130     {
131     	unsigned long temp;
132     
133     	__asm__ __volatile__(
134     		"1:   ll      %0, %1      # atomic_add\n"
135     		"     addu    %0, %2                  \n"
136     		"     sc      %0, %1                  \n"
137     		"     beqz    %0, 1b                  \n"
138     		: "=&r" (temp), "=m" (v->counter)
139     		: "Ir" (i), "m" (v->counter));
140     }
141     
142     /*
143      * atomic_sub - subtract the atomic variable
144      * @i: integer value to subtract
145      * @v: pointer of type atomic_t
146      *
147      * Atomically subtracts @i from @v.  Note that the guaranteed
148      * useful range of an atomic_t is only 24 bits.
149      */
150     extern __inline__ void atomic_sub(int i, atomic_t * v)
151     {
152     	unsigned long temp;
153     
154     	__asm__ __volatile__(
155     		"1:   ll      %0, %1      # atomic_sub\n"
156     		"     subu    %0, %2                  \n"
157     		"     sc      %0, %1                  \n"
158     		"     beqz    %0, 1b                  \n"
159     		: "=&r" (temp), "=m" (v->counter)
160     		: "Ir" (i), "m" (v->counter));
161     }
162     
163     /*
164      * Same as above, but return the result value
165      */
166     extern __inline__ int atomic_add_return(int i, atomic_t * v)
167     {
168     	unsigned long temp, result;
169     
170     	__asm__ __volatile__(
171     		".set push               # atomic_add_return\n"
172     		".set noreorder                             \n"
173     		"1:   ll      %1, %2                        \n"
174     		"     addu    %0, %1, %3                    \n"
175     		"     sc      %0, %2                        \n"
176     		"     beqz    %0, 1b                        \n"
177     		"     addu    %0, %1, %3                    \n"
178     		".set pop                                   \n"
179     		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
180     		: "Ir" (i), "m" (v->counter)
181     		: "memory");
182     
183     	return result;
184     }
185     
186     extern __inline__ int atomic_sub_return(int i, atomic_t * v)
187     {
188     	unsigned long temp, result;
189     
190     	__asm__ __volatile__(
191     		".set push                                   \n"
192     		".set noreorder           # atomic_sub_return\n"
193     		"1:   ll    %1, %2                           \n"
194     		"     subu  %0, %1, %3                       \n"
195     		"     sc    %0, %2                           \n"
196     		"     beqz  %0, 1b                           \n"
197     		"     subu  %0, %1, %3                       \n"
198     		".set pop                                    \n"
199     		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
200     		: "Ir" (i), "m" (v->counter)
201     		: "memory");
202     
203     	return result;
204     }
205     #endif
206     
207     #define atomic_dec_return(v) atomic_sub_return(1,(v))
208     #define atomic_inc_return(v) atomic_add_return(1,(v))
209     
210     /*
211      * atomic_sub_and_test - subtract value from variable and test result
212      * @i: integer value to subtract
213      * @v: pointer of type atomic_t
214      *
215      * Atomically subtracts @i from @v and returns
216      * true if the result is zero, or false for all
217      * other cases.  Note that the guaranteed
218      * useful range of an atomic_t is only 24 bits.
219      */
220     #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
221     
222     /*
223      * atomic_inc_and_test - increment and test
224      * @v: pointer of type atomic_t
225      *
226      * Atomically increments @v by 1
227      * and returns true if the result is zero, or false for all
228      * other cases.  Note that the guaranteed
229      * useful range of an atomic_t is only 24 bits.
230      */
231     #define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0)
232     
233     /*
234      * atomic_dec_and_test - decrement by 1 and test
235      * @v: pointer of type atomic_t
236      *
237      * Atomically decrements @v by 1 and
238      * returns true if the result is 0, or false for all other
239      * cases.  Note that the guaranteed
240      * useful range of an atomic_t is only 24 bits.
241      */
242     #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
243     
244     /*
245      * atomic_inc - increment atomic variable
246      * @v: pointer of type atomic_t
247      *
248      * Atomically increments @v by 1.  Note that the guaranteed
249      * useful range of an atomic_t is only 24 bits.
250      */
251     #define atomic_inc(v) atomic_add(1,(v))
252     
253     /*
254      * atomic_dec - decrement and test
255      * @v: pointer of type atomic_t
256      *
257      * Atomically decrements @v by 1.  Note that the guaranteed
258      * useful range of an atomic_t is only 24 bits.
259      */
260     #define atomic_dec(v) atomic_sub(1,(v))
261     
262     /*
263      * atomic_add_negative - add and test if negative
264      * @v: pointer of type atomic_t
265      * @i: integer value to add
266      *
267      * Atomically adds @i to @v and returns true
268      * if the result is negative, or false when
269      * result is greater than or equal to zero.  Note that the guaranteed
270      * useful range of an atomic_t is only 24 bits.
271      *
272      * Currently not implemented for MIPS.
273      */
274     
275     /* Atomic operations are already serializing */
276     #define smp_mb__before_atomic_dec()	barrier()
277     #define smp_mb__after_atomic_dec()	barrier()
278     #define smp_mb__before_atomic_inc()	barrier()
279     #define smp_mb__after_atomic_inc()	barrier()
280     
281     #endif /* defined(__KERNEL__) */
282     
283     #endif /* __ASM_ATOMIC_H */
284