xref: /openbmc/linux/arch/alpha/include/asm/atomic.h (revision 384740dc)
1 #ifndef _ALPHA_ATOMIC_H
2 #define _ALPHA_ATOMIC_H
3 
4 #include <asm/barrier.h>
5 #include <asm/system.h>
6 
7 /*
8  * Atomic operations that C can't guarantee us.  Useful for
9  * resource counting etc...
10  *
11  * But use these as seldom as possible since they are much slower
12  * than regular operations.
13  */
14 
15 
16 /*
17  * Counter is volatile to make sure gcc doesn't try to be clever
18  * and move things around on us. We need to use _exactly_ the address
19  * the user gave us, not some alias that contains the same information.
20  */
21 typedef struct { volatile int counter; } atomic_t;
22 typedef struct { volatile long counter; } atomic64_t;
23 
24 #define ATOMIC_INIT(i)		( (atomic_t) { (i) } )
25 #define ATOMIC64_INIT(i)	( (atomic64_t) { (i) } )
26 
27 #define atomic_read(v)		((v)->counter + 0)
28 #define atomic64_read(v)	((v)->counter + 0)
29 
30 #define atomic_set(v,i)		((v)->counter = (i))
31 #define atomic64_set(v,i)	((v)->counter = (i))
32 
33 /*
34  * To get proper branch prediction for the main line, we must branch
35  * forward to code at the end of this object's .text section, then
36  * branch back to restart the operation.
37  */
38 
39 static __inline__ void atomic_add(int i, atomic_t * v)
40 {
41 	unsigned long temp;
42 	__asm__ __volatile__(
43 	"1:	ldl_l %0,%1\n"
44 	"	addl %0,%2,%0\n"
45 	"	stl_c %0,%1\n"
46 	"	beq %0,2f\n"
47 	".subsection 2\n"
48 	"2:	br 1b\n"
49 	".previous"
50 	:"=&r" (temp), "=m" (v->counter)
51 	:"Ir" (i), "m" (v->counter));
52 }
53 
54 static __inline__ void atomic64_add(long i, atomic64_t * v)
55 {
56 	unsigned long temp;
57 	__asm__ __volatile__(
58 	"1:	ldq_l %0,%1\n"
59 	"	addq %0,%2,%0\n"
60 	"	stq_c %0,%1\n"
61 	"	beq %0,2f\n"
62 	".subsection 2\n"
63 	"2:	br 1b\n"
64 	".previous"
65 	:"=&r" (temp), "=m" (v->counter)
66 	:"Ir" (i), "m" (v->counter));
67 }
68 
69 static __inline__ void atomic_sub(int i, atomic_t * v)
70 {
71 	unsigned long temp;
72 	__asm__ __volatile__(
73 	"1:	ldl_l %0,%1\n"
74 	"	subl %0,%2,%0\n"
75 	"	stl_c %0,%1\n"
76 	"	beq %0,2f\n"
77 	".subsection 2\n"
78 	"2:	br 1b\n"
79 	".previous"
80 	:"=&r" (temp), "=m" (v->counter)
81 	:"Ir" (i), "m" (v->counter));
82 }
83 
84 static __inline__ void atomic64_sub(long i, atomic64_t * v)
85 {
86 	unsigned long temp;
87 	__asm__ __volatile__(
88 	"1:	ldq_l %0,%1\n"
89 	"	subq %0,%2,%0\n"
90 	"	stq_c %0,%1\n"
91 	"	beq %0,2f\n"
92 	".subsection 2\n"
93 	"2:	br 1b\n"
94 	".previous"
95 	:"=&r" (temp), "=m" (v->counter)
96 	:"Ir" (i), "m" (v->counter));
97 }
98 
99 
100 /*
101  * Same as above, but return the result value
102  */
103 static inline int atomic_add_return(int i, atomic_t *v)
104 {
105 	long temp, result;
106 	smp_mb();
107 	__asm__ __volatile__(
108 	"1:	ldl_l %0,%1\n"
109 	"	addl %0,%3,%2\n"
110 	"	addl %0,%3,%0\n"
111 	"	stl_c %0,%1\n"
112 	"	beq %0,2f\n"
113 	".subsection 2\n"
114 	"2:	br 1b\n"
115 	".previous"
116 	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
117 	:"Ir" (i), "m" (v->counter) : "memory");
118 	smp_mb();
119 	return result;
120 }
121 
122 static __inline__ long atomic64_add_return(long i, atomic64_t * v)
123 {
124 	long temp, result;
125 	smp_mb();
126 	__asm__ __volatile__(
127 	"1:	ldq_l %0,%1\n"
128 	"	addq %0,%3,%2\n"
129 	"	addq %0,%3,%0\n"
130 	"	stq_c %0,%1\n"
131 	"	beq %0,2f\n"
132 	".subsection 2\n"
133 	"2:	br 1b\n"
134 	".previous"
135 	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
136 	:"Ir" (i), "m" (v->counter) : "memory");
137 	smp_mb();
138 	return result;
139 }
140 
141 static __inline__ long atomic_sub_return(int i, atomic_t * v)
142 {
143 	long temp, result;
144 	smp_mb();
145 	__asm__ __volatile__(
146 	"1:	ldl_l %0,%1\n"
147 	"	subl %0,%3,%2\n"
148 	"	subl %0,%3,%0\n"
149 	"	stl_c %0,%1\n"
150 	"	beq %0,2f\n"
151 	".subsection 2\n"
152 	"2:	br 1b\n"
153 	".previous"
154 	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
155 	:"Ir" (i), "m" (v->counter) : "memory");
156 	smp_mb();
157 	return result;
158 }
159 
160 static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
161 {
162 	long temp, result;
163 	smp_mb();
164 	__asm__ __volatile__(
165 	"1:	ldq_l %0,%1\n"
166 	"	subq %0,%3,%2\n"
167 	"	subq %0,%3,%0\n"
168 	"	stq_c %0,%1\n"
169 	"	beq %0,2f\n"
170 	".subsection 2\n"
171 	"2:	br 1b\n"
172 	".previous"
173 	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
174 	:"Ir" (i), "m" (v->counter) : "memory");
175 	smp_mb();
176 	return result;
177 }
178 
179 #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
180 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
181 
182 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
183 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
184 
185 /**
186  * atomic_add_unless - add unless the number is a given value
187  * @v: pointer of type atomic_t
188  * @a: the amount to add to v...
189  * @u: ...unless v is equal to u.
190  *
191  * Atomically adds @a to @v, so long as it was not @u.
192  * Returns non-zero if @v was not @u, and zero otherwise.
193  */
194 static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
195 {
196 	int c, old;
197 	c = atomic_read(v);
198 	for (;;) {
199 		if (unlikely(c == (u)))
200 			break;
201 		old = atomic_cmpxchg((v), c, c + (a));
202 		if (likely(old == c))
203 			break;
204 		c = old;
205 	}
206 	return c != (u);
207 }
208 
209 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
210 
211 /**
212  * atomic64_add_unless - add unless the number is a given value
213  * @v: pointer of type atomic64_t
214  * @a: the amount to add to v...
215  * @u: ...unless v is equal to u.
216  *
217  * Atomically adds @a to @v, so long as it was not @u.
218  * Returns non-zero if @v was not @u, and zero otherwise.
219  */
220 static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
221 {
222 	long c, old;
223 	c = atomic64_read(v);
224 	for (;;) {
225 		if (unlikely(c == (u)))
226 			break;
227 		old = atomic64_cmpxchg((v), c, c + (a));
228 		if (likely(old == c))
229 			break;
230 		c = old;
231 	}
232 	return c != (u);
233 }
234 
235 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
236 
237 #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
238 #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
239 
240 #define atomic_dec_return(v) atomic_sub_return(1,(v))
241 #define atomic64_dec_return(v) atomic64_sub_return(1,(v))
242 
243 #define atomic_inc_return(v) atomic_add_return(1,(v))
244 #define atomic64_inc_return(v) atomic64_add_return(1,(v))
245 
246 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
247 #define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0)
248 
249 #define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
250 #define atomic64_inc_and_test(v) (atomic64_add_return(1, (v)) == 0)
251 
252 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
253 #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
254 
255 #define atomic_inc(v) atomic_add(1,(v))
256 #define atomic64_inc(v) atomic64_add(1,(v))
257 
258 #define atomic_dec(v) atomic_sub(1,(v))
259 #define atomic64_dec(v) atomic64_sub(1,(v))
260 
261 #define smp_mb__before_atomic_dec()	smp_mb()
262 #define smp_mb__after_atomic_dec()	smp_mb()
263 #define smp_mb__before_atomic_inc()	smp_mb()
264 #define smp_mb__after_atomic_inc()	smp_mb()
265 
266 #include <asm-generic/atomic.h>
267 #endif /* _ALPHA_ATOMIC_H */
268