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 by Ralf Baechle
13 *
14 * $Id: atomic.h,v 1.6 1999/07/26 19:42:42 harald Exp $
15 */
16 #ifndef __ASM_ATOMIC_H
17 #define __ASM_ATOMIC_H
18
19 #include <linux/config.h>
20
21 #ifdef CONFIG_SMP
22 typedef struct { volatile int counter; } atomic_t;
23 #else
24 typedef struct { int counter; } atomic_t;
25 #endif
26
27 #ifdef __KERNEL__
28 #define ATOMIC_INIT(i) { (i) }
29
30 #define atomic_read(v) ((v)->counter)
31 #define atomic_set(v,i) ((v)->counter = (i))
32
33 #if !defined(CONFIG_CPU_HAS_LLSC)
34
35 #include <asm/system.h>
36
37 /*
38 * The MIPS I implementation is only atomic with respect to
39 * interrupts. R3000 based multiprocessor machines are rare anyway ...
40 */
41 extern __inline__ void atomic_add(int i, volatile atomic_t * v)
42 {
43 int flags;
44
45 save_flags(flags);
46 cli();
47 v->counter += i;
48 restore_flags(flags);
49 }
50
51 extern __inline__ void atomic_sub(int i, volatile atomic_t * v)
52 {
53 int flags;
54
55 save_flags(flags);
56 cli();
57 v->counter -= i;
58 restore_flags(flags);
59 }
60
61 extern __inline__ int atomic_add_return(int i, atomic_t * v)
62 {
63 int temp, flags;
64
65 save_flags(flags);
66 cli();
67 temp = v->counter;
68 temp += i;
69 v->counter = temp;
70 restore_flags(flags);
71
72 return temp;
73 }
74
75 extern __inline__ int atomic_sub_return(int i, atomic_t * v)
76 {
77 int temp, flags;
78
79 save_flags(flags);
80 cli();
81 temp = v->counter;
82 temp -= i;
83 v->counter = temp;
84 restore_flags(flags);
85
86 return temp;
87 }
88
89 extern __inline__ void atomic_clear_mask(unsigned long mask, unsigned long * v)
90 {
91 unsigned long temp;
92 int flags;
93
94 save_flags(flags);
95 cli();
96 temp = *v;
97 temp &= ~mask;
98 *v = temp;
99 restore_flags(flags);
100
101 return;
102 }
103
104 #else
105
106 /*
107 * ... while for MIPS II and better we can use ll/sc instruction. This
108 * implementation is SMP safe ...
109 */
110
111 /*
112 * Make sure gcc doesn't try to be clever and move things around
113 * on us. We need to use _exactly_ the address the user gave us,
114 * not some alias that contains the same information.
115 */
116 #define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
117
118 extern __inline__ void atomic_add(int i, volatile atomic_t * v)
119 {
120 unsigned long temp;
121
122 __asm__ __volatile__(
123 "1:\tll\t%0,%1\n\t"
124 "addu\t%0,%2\n\t"
125 "sc\t%0,%1\n\t"
126 "beqz\t%0,1b"
127 :"=&r" (temp),
128 "=m" (__atomic_fool_gcc(v))
129 :"Ir" (i),
130 "m" (__atomic_fool_gcc(v)));
131 }
132
133 extern __inline__ void atomic_sub(int i, volatile atomic_t * v)
134 {
135 unsigned long temp;
136
137 __asm__ __volatile__(
138 "1:\tll\t%0,%1\n\t"
139 "subu\t%0,%2\n\t"
140 "sc\t%0,%1\n\t"
141 "beqz\t%0,1b"
142 :"=&r" (temp),
143 "=m" (__atomic_fool_gcc(v))
144 :"Ir" (i),
145 "m" (__atomic_fool_gcc(v)));
146 }
147
148 /*
149 * Same as above, but return the result value
150 */
151 extern __inline__ int atomic_add_return(int i, atomic_t * v)
152 {
153 unsigned long temp, result;
154
155 __asm__ __volatile__(
156 ".set\tnoreorder\n"
157 "1:\tll\t%1,%2\n\t"
158 "addu\t%0,%1,%3\n\t"
159 "sc\t%0,%2\n\t"
160 "beqz\t%0,1b\n\t"
161 "addu\t%0,%1,%3\n\t"
162 ".set\treorder"
163 :"=&r" (result),
164 "=&r" (temp),
165 "=m" (__atomic_fool_gcc(v))
166 :"Ir" (i),
167 "m" (__atomic_fool_gcc(v)));
168
169 return result;
170 }
171
172 extern __inline__ int atomic_sub_return(int i, atomic_t * v)
173 {
174 unsigned long temp, result;
175
176 __asm__ __volatile__(
177 ".set\tnoreorder\n"
178 "1:\tll\t%1,%2\n\t"
179 "subu\t%0,%1,%3\n\t"
180 "sc\t%0,%2\n\t"
181 "beqz\t%0,1b\n\t"
182 "subu\t%0,%1,%3\n\t"
183 ".set\treorder"
184 :"=&r" (result),
185 "=&r" (temp),
186 "=m" (__atomic_fool_gcc(v))
187 :"Ir" (i),
188 "m" (__atomic_fool_gcc(v)));
189
190 return result;
191 }
192 #endif
193
194 #define atomic_dec_return(v) atomic_sub_return(1,(v))
195 #define atomic_inc_return(v) atomic_add_return(1,(v))
196
197 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
198 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
199
200 #define atomic_inc(v) atomic_add(1,(v))
201 #define atomic_dec(v) atomic_sub(1,(v))
202 #endif /* defined(__KERNEL__) */
203
204 #endif /* __ASM_MIPS_ATOMIC_H */
205
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.