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