xref: /openbmc/linux/arch/powerpc/include/asm/atomic.h (revision 62e7ca52)
1 #ifndef _ASM_POWERPC_ATOMIC_H_
2 #define _ASM_POWERPC_ATOMIC_H_
3 
4 /*
5  * PowerPC atomic operations
6  */
7 
8 #ifdef __KERNEL__
9 #include <linux/types.h>
10 #include <asm/cmpxchg.h>
11 #include <asm/barrier.h>
12 
13 #define ATOMIC_INIT(i)		{ (i) }
14 
15 static __inline__ int atomic_read(const atomic_t *v)
16 {
17 	int t;
18 
19 	__asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
20 
21 	return t;
22 }
23 
24 static __inline__ void atomic_set(atomic_t *v, int i)
25 {
26 	__asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
27 }
28 
29 static __inline__ void atomic_add(int a, atomic_t *v)
30 {
31 	int t;
32 
33 	__asm__ __volatile__(
34 "1:	lwarx	%0,0,%3		# atomic_add\n\
35 	add	%0,%2,%0\n"
36 	PPC405_ERR77(0,%3)
37 "	stwcx.	%0,0,%3 \n\
38 	bne-	1b"
39 	: "=&r" (t), "+m" (v->counter)
40 	: "r" (a), "r" (&v->counter)
41 	: "cc");
42 }
43 
44 static __inline__ int atomic_add_return(int a, atomic_t *v)
45 {
46 	int t;
47 
48 	__asm__ __volatile__(
49 	PPC_ATOMIC_ENTRY_BARRIER
50 "1:	lwarx	%0,0,%2		# atomic_add_return\n\
51 	add	%0,%1,%0\n"
52 	PPC405_ERR77(0,%2)
53 "	stwcx.	%0,0,%2 \n\
54 	bne-	1b"
55 	PPC_ATOMIC_EXIT_BARRIER
56 	: "=&r" (t)
57 	: "r" (a), "r" (&v->counter)
58 	: "cc", "memory");
59 
60 	return t;
61 }
62 
63 #define atomic_add_negative(a, v)	(atomic_add_return((a), (v)) < 0)
64 
65 static __inline__ void atomic_sub(int a, atomic_t *v)
66 {
67 	int t;
68 
69 	__asm__ __volatile__(
70 "1:	lwarx	%0,0,%3		# atomic_sub\n\
71 	subf	%0,%2,%0\n"
72 	PPC405_ERR77(0,%3)
73 "	stwcx.	%0,0,%3 \n\
74 	bne-	1b"
75 	: "=&r" (t), "+m" (v->counter)
76 	: "r" (a), "r" (&v->counter)
77 	: "cc");
78 }
79 
80 static __inline__ int atomic_sub_return(int a, atomic_t *v)
81 {
82 	int t;
83 
84 	__asm__ __volatile__(
85 	PPC_ATOMIC_ENTRY_BARRIER
86 "1:	lwarx	%0,0,%2		# atomic_sub_return\n\
87 	subf	%0,%1,%0\n"
88 	PPC405_ERR77(0,%2)
89 "	stwcx.	%0,0,%2 \n\
90 	bne-	1b"
91 	PPC_ATOMIC_EXIT_BARRIER
92 	: "=&r" (t)
93 	: "r" (a), "r" (&v->counter)
94 	: "cc", "memory");
95 
96 	return t;
97 }
98 
99 static __inline__ void atomic_inc(atomic_t *v)
100 {
101 	int t;
102 
103 	__asm__ __volatile__(
104 "1:	lwarx	%0,0,%2		# atomic_inc\n\
105 	addic	%0,%0,1\n"
106 	PPC405_ERR77(0,%2)
107 "	stwcx.	%0,0,%2 \n\
108 	bne-	1b"
109 	: "=&r" (t), "+m" (v->counter)
110 	: "r" (&v->counter)
111 	: "cc", "xer");
112 }
113 
114 static __inline__ int atomic_inc_return(atomic_t *v)
115 {
116 	int t;
117 
118 	__asm__ __volatile__(
119 	PPC_ATOMIC_ENTRY_BARRIER
120 "1:	lwarx	%0,0,%1		# atomic_inc_return\n\
121 	addic	%0,%0,1\n"
122 	PPC405_ERR77(0,%1)
123 "	stwcx.	%0,0,%1 \n\
124 	bne-	1b"
125 	PPC_ATOMIC_EXIT_BARRIER
126 	: "=&r" (t)
127 	: "r" (&v->counter)
128 	: "cc", "xer", "memory");
129 
130 	return t;
131 }
132 
133 /*
134  * atomic_inc_and_test - increment and test
135  * @v: pointer of type atomic_t
136  *
137  * Atomically increments @v by 1
138  * and returns true if the result is zero, or false for all
139  * other cases.
140  */
141 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
142 
143 static __inline__ void atomic_dec(atomic_t *v)
144 {
145 	int t;
146 
147 	__asm__ __volatile__(
148 "1:	lwarx	%0,0,%2		# atomic_dec\n\
149 	addic	%0,%0,-1\n"
150 	PPC405_ERR77(0,%2)\
151 "	stwcx.	%0,0,%2\n\
152 	bne-	1b"
153 	: "=&r" (t), "+m" (v->counter)
154 	: "r" (&v->counter)
155 	: "cc", "xer");
156 }
157 
158 static __inline__ int atomic_dec_return(atomic_t *v)
159 {
160 	int t;
161 
162 	__asm__ __volatile__(
163 	PPC_ATOMIC_ENTRY_BARRIER
164 "1:	lwarx	%0,0,%1		# atomic_dec_return\n\
165 	addic	%0,%0,-1\n"
166 	PPC405_ERR77(0,%1)
167 "	stwcx.	%0,0,%1\n\
168 	bne-	1b"
169 	PPC_ATOMIC_EXIT_BARRIER
170 	: "=&r" (t)
171 	: "r" (&v->counter)
172 	: "cc", "xer", "memory");
173 
174 	return t;
175 }
176 
177 #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
178 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
179 
180 /**
181  * __atomic_add_unless - add unless the number is a given value
182  * @v: pointer of type atomic_t
183  * @a: the amount to add to v...
184  * @u: ...unless v is equal to u.
185  *
186  * Atomically adds @a to @v, so long as it was not @u.
187  * Returns the old value of @v.
188  */
189 static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
190 {
191 	int t;
192 
193 	__asm__ __volatile__ (
194 	PPC_ATOMIC_ENTRY_BARRIER
195 "1:	lwarx	%0,0,%1		# __atomic_add_unless\n\
196 	cmpw	0,%0,%3 \n\
197 	beq-	2f \n\
198 	add	%0,%2,%0 \n"
199 	PPC405_ERR77(0,%2)
200 "	stwcx.	%0,0,%1 \n\
201 	bne-	1b \n"
202 	PPC_ATOMIC_EXIT_BARRIER
203 "	subf	%0,%2,%0 \n\
204 2:"
205 	: "=&r" (t)
206 	: "r" (&v->counter), "r" (a), "r" (u)
207 	: "cc", "memory");
208 
209 	return t;
210 }
211 
212 /**
213  * atomic_inc_not_zero - increment unless the number is zero
214  * @v: pointer of type atomic_t
215  *
216  * Atomically increments @v by 1, so long as @v is non-zero.
217  * Returns non-zero if @v was non-zero, and zero otherwise.
218  */
219 static __inline__ int atomic_inc_not_zero(atomic_t *v)
220 {
221 	int t1, t2;
222 
223 	__asm__ __volatile__ (
224 	PPC_ATOMIC_ENTRY_BARRIER
225 "1:	lwarx	%0,0,%2		# atomic_inc_not_zero\n\
226 	cmpwi	0,%0,0\n\
227 	beq-	2f\n\
228 	addic	%1,%0,1\n"
229 	PPC405_ERR77(0,%2)
230 "	stwcx.	%1,0,%2\n\
231 	bne-	1b\n"
232 	PPC_ATOMIC_EXIT_BARRIER
233 	"\n\
234 2:"
235 	: "=&r" (t1), "=&r" (t2)
236 	: "r" (&v->counter)
237 	: "cc", "xer", "memory");
238 
239 	return t1;
240 }
241 #define atomic_inc_not_zero(v) atomic_inc_not_zero((v))
242 
243 #define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
244 #define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)
245 
246 /*
247  * Atomically test *v and decrement if it is greater than 0.
248  * The function returns the old value of *v minus 1, even if
249  * the atomic variable, v, was not decremented.
250  */
251 static __inline__ int atomic_dec_if_positive(atomic_t *v)
252 {
253 	int t;
254 
255 	__asm__ __volatile__(
256 	PPC_ATOMIC_ENTRY_BARRIER
257 "1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
258 	cmpwi	%0,1\n\
259 	addi	%0,%0,-1\n\
260 	blt-	2f\n"
261 	PPC405_ERR77(0,%1)
262 "	stwcx.	%0,0,%1\n\
263 	bne-	1b"
264 	PPC_ATOMIC_EXIT_BARRIER
265 	"\n\
266 2:"	: "=&b" (t)
267 	: "r" (&v->counter)
268 	: "cc", "memory");
269 
270 	return t;
271 }
272 #define atomic_dec_if_positive atomic_dec_if_positive
273 
274 #ifdef __powerpc64__
275 
276 #define ATOMIC64_INIT(i)	{ (i) }
277 
278 static __inline__ long atomic64_read(const atomic64_t *v)
279 {
280 	long t;
281 
282 	__asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
283 
284 	return t;
285 }
286 
287 static __inline__ void atomic64_set(atomic64_t *v, long i)
288 {
289 	__asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
290 }
291 
292 static __inline__ void atomic64_add(long a, atomic64_t *v)
293 {
294 	long t;
295 
296 	__asm__ __volatile__(
297 "1:	ldarx	%0,0,%3		# atomic64_add\n\
298 	add	%0,%2,%0\n\
299 	stdcx.	%0,0,%3 \n\
300 	bne-	1b"
301 	: "=&r" (t), "+m" (v->counter)
302 	: "r" (a), "r" (&v->counter)
303 	: "cc");
304 }
305 
306 static __inline__ long atomic64_add_return(long a, atomic64_t *v)
307 {
308 	long t;
309 
310 	__asm__ __volatile__(
311 	PPC_ATOMIC_ENTRY_BARRIER
312 "1:	ldarx	%0,0,%2		# atomic64_add_return\n\
313 	add	%0,%1,%0\n\
314 	stdcx.	%0,0,%2 \n\
315 	bne-	1b"
316 	PPC_ATOMIC_EXIT_BARRIER
317 	: "=&r" (t)
318 	: "r" (a), "r" (&v->counter)
319 	: "cc", "memory");
320 
321 	return t;
322 }
323 
324 #define atomic64_add_negative(a, v)	(atomic64_add_return((a), (v)) < 0)
325 
326 static __inline__ void atomic64_sub(long a, atomic64_t *v)
327 {
328 	long t;
329 
330 	__asm__ __volatile__(
331 "1:	ldarx	%0,0,%3		# atomic64_sub\n\
332 	subf	%0,%2,%0\n\
333 	stdcx.	%0,0,%3 \n\
334 	bne-	1b"
335 	: "=&r" (t), "+m" (v->counter)
336 	: "r" (a), "r" (&v->counter)
337 	: "cc");
338 }
339 
340 static __inline__ long atomic64_sub_return(long a, atomic64_t *v)
341 {
342 	long t;
343 
344 	__asm__ __volatile__(
345 	PPC_ATOMIC_ENTRY_BARRIER
346 "1:	ldarx	%0,0,%2		# atomic64_sub_return\n\
347 	subf	%0,%1,%0\n\
348 	stdcx.	%0,0,%2 \n\
349 	bne-	1b"
350 	PPC_ATOMIC_EXIT_BARRIER
351 	: "=&r" (t)
352 	: "r" (a), "r" (&v->counter)
353 	: "cc", "memory");
354 
355 	return t;
356 }
357 
358 static __inline__ void atomic64_inc(atomic64_t *v)
359 {
360 	long t;
361 
362 	__asm__ __volatile__(
363 "1:	ldarx	%0,0,%2		# atomic64_inc\n\
364 	addic	%0,%0,1\n\
365 	stdcx.	%0,0,%2 \n\
366 	bne-	1b"
367 	: "=&r" (t), "+m" (v->counter)
368 	: "r" (&v->counter)
369 	: "cc", "xer");
370 }
371 
372 static __inline__ long atomic64_inc_return(atomic64_t *v)
373 {
374 	long t;
375 
376 	__asm__ __volatile__(
377 	PPC_ATOMIC_ENTRY_BARRIER
378 "1:	ldarx	%0,0,%1		# atomic64_inc_return\n\
379 	addic	%0,%0,1\n\
380 	stdcx.	%0,0,%1 \n\
381 	bne-	1b"
382 	PPC_ATOMIC_EXIT_BARRIER
383 	: "=&r" (t)
384 	: "r" (&v->counter)
385 	: "cc", "xer", "memory");
386 
387 	return t;
388 }
389 
390 /*
391  * atomic64_inc_and_test - increment and test
392  * @v: pointer of type atomic64_t
393  *
394  * Atomically increments @v by 1
395  * and returns true if the result is zero, or false for all
396  * other cases.
397  */
398 #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
399 
400 static __inline__ void atomic64_dec(atomic64_t *v)
401 {
402 	long t;
403 
404 	__asm__ __volatile__(
405 "1:	ldarx	%0,0,%2		# atomic64_dec\n\
406 	addic	%0,%0,-1\n\
407 	stdcx.	%0,0,%2\n\
408 	bne-	1b"
409 	: "=&r" (t), "+m" (v->counter)
410 	: "r" (&v->counter)
411 	: "cc", "xer");
412 }
413 
414 static __inline__ long atomic64_dec_return(atomic64_t *v)
415 {
416 	long t;
417 
418 	__asm__ __volatile__(
419 	PPC_ATOMIC_ENTRY_BARRIER
420 "1:	ldarx	%0,0,%1		# atomic64_dec_return\n\
421 	addic	%0,%0,-1\n\
422 	stdcx.	%0,0,%1\n\
423 	bne-	1b"
424 	PPC_ATOMIC_EXIT_BARRIER
425 	: "=&r" (t)
426 	: "r" (&v->counter)
427 	: "cc", "xer", "memory");
428 
429 	return t;
430 }
431 
432 #define atomic64_sub_and_test(a, v)	(atomic64_sub_return((a), (v)) == 0)
433 #define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
434 
435 /*
436  * Atomically test *v and decrement if it is greater than 0.
437  * The function returns the old value of *v minus 1.
438  */
439 static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
440 {
441 	long t;
442 
443 	__asm__ __volatile__(
444 	PPC_ATOMIC_ENTRY_BARRIER
445 "1:	ldarx	%0,0,%1		# atomic64_dec_if_positive\n\
446 	addic.	%0,%0,-1\n\
447 	blt-	2f\n\
448 	stdcx.	%0,0,%1\n\
449 	bne-	1b"
450 	PPC_ATOMIC_EXIT_BARRIER
451 	"\n\
452 2:"	: "=&r" (t)
453 	: "r" (&v->counter)
454 	: "cc", "xer", "memory");
455 
456 	return t;
457 }
458 
459 #define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
460 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
461 
462 /**
463  * atomic64_add_unless - add unless the number is a given value
464  * @v: pointer of type atomic64_t
465  * @a: the amount to add to v...
466  * @u: ...unless v is equal to u.
467  *
468  * Atomically adds @a to @v, so long as it was not @u.
469  * Returns the old value of @v.
470  */
471 static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
472 {
473 	long t;
474 
475 	__asm__ __volatile__ (
476 	PPC_ATOMIC_ENTRY_BARRIER
477 "1:	ldarx	%0,0,%1		# __atomic_add_unless\n\
478 	cmpd	0,%0,%3 \n\
479 	beq-	2f \n\
480 	add	%0,%2,%0 \n"
481 "	stdcx.	%0,0,%1 \n\
482 	bne-	1b \n"
483 	PPC_ATOMIC_EXIT_BARRIER
484 "	subf	%0,%2,%0 \n\
485 2:"
486 	: "=&r" (t)
487 	: "r" (&v->counter), "r" (a), "r" (u)
488 	: "cc", "memory");
489 
490 	return t != u;
491 }
492 
493 /**
494  * atomic_inc64_not_zero - increment unless the number is zero
495  * @v: pointer of type atomic64_t
496  *
497  * Atomically increments @v by 1, so long as @v is non-zero.
498  * Returns non-zero if @v was non-zero, and zero otherwise.
499  */
500 static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
501 {
502 	long t1, t2;
503 
504 	__asm__ __volatile__ (
505 	PPC_ATOMIC_ENTRY_BARRIER
506 "1:	ldarx	%0,0,%2		# atomic64_inc_not_zero\n\
507 	cmpdi	0,%0,0\n\
508 	beq-	2f\n\
509 	addic	%1,%0,1\n\
510 	stdcx.	%1,0,%2\n\
511 	bne-	1b\n"
512 	PPC_ATOMIC_EXIT_BARRIER
513 	"\n\
514 2:"
515 	: "=&r" (t1), "=&r" (t2)
516 	: "r" (&v->counter)
517 	: "cc", "xer", "memory");
518 
519 	return t1;
520 }
521 
522 #endif /* __powerpc64__ */
523 
524 #endif /* __KERNEL__ */
525 #endif /* _ASM_POWERPC_ATOMIC_H_ */
526