xref: /openbmc/linux/arch/powerpc/include/asm/local.h (revision a8da474e)
1 #ifndef _ARCH_POWERPC_LOCAL_H
2 #define _ARCH_POWERPC_LOCAL_H
3 
4 #include <linux/percpu.h>
5 #include <linux/atomic.h>
6 
7 typedef struct
8 {
9 	atomic_long_t a;
10 } local_t;
11 
12 #define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
13 
14 #define local_read(l)	atomic_long_read(&(l)->a)
15 #define local_set(l,i)	atomic_long_set(&(l)->a, (i))
16 
17 #define local_add(i,l)	atomic_long_add((i),(&(l)->a))
18 #define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
19 #define local_inc(l)	atomic_long_inc(&(l)->a)
20 #define local_dec(l)	atomic_long_dec(&(l)->a)
21 
22 static __inline__ long local_add_return(long a, local_t *l)
23 {
24 	long t;
25 
26 	__asm__ __volatile__(
27 "1:"	PPC_LLARX(%0,0,%2,0) "			# local_add_return\n\
28 	add	%0,%1,%0\n"
29 	PPC405_ERR77(0,%2)
30 	PPC_STLCX	"%0,0,%2 \n\
31 	bne-	1b"
32 	: "=&r" (t)
33 	: "r" (a), "r" (&(l->a.counter))
34 	: "cc", "memory");
35 
36 	return t;
37 }
38 
39 #define local_add_negative(a, l)	(local_add_return((a), (l)) < 0)
40 
41 static __inline__ long local_sub_return(long a, local_t *l)
42 {
43 	long t;
44 
45 	__asm__ __volatile__(
46 "1:"	PPC_LLARX(%0,0,%2,0) "			# local_sub_return\n\
47 	subf	%0,%1,%0\n"
48 	PPC405_ERR77(0,%2)
49 	PPC_STLCX	"%0,0,%2 \n\
50 	bne-	1b"
51 	: "=&r" (t)
52 	: "r" (a), "r" (&(l->a.counter))
53 	: "cc", "memory");
54 
55 	return t;
56 }
57 
58 static __inline__ long local_inc_return(local_t *l)
59 {
60 	long t;
61 
62 	__asm__ __volatile__(
63 "1:"	PPC_LLARX(%0,0,%1,0) "			# local_inc_return\n\
64 	addic	%0,%0,1\n"
65 	PPC405_ERR77(0,%1)
66 	PPC_STLCX	"%0,0,%1 \n\
67 	bne-	1b"
68 	: "=&r" (t)
69 	: "r" (&(l->a.counter))
70 	: "cc", "xer", "memory");
71 
72 	return t;
73 }
74 
75 /*
76  * local_inc_and_test - increment and test
77  * @l: pointer of type local_t
78  *
79  * Atomically increments @l by 1
80  * and returns true if the result is zero, or false for all
81  * other cases.
82  */
83 #define local_inc_and_test(l) (local_inc_return(l) == 0)
84 
85 static __inline__ long local_dec_return(local_t *l)
86 {
87 	long t;
88 
89 	__asm__ __volatile__(
90 "1:"	PPC_LLARX(%0,0,%1,0) "			# local_dec_return\n\
91 	addic	%0,%0,-1\n"
92 	PPC405_ERR77(0,%1)
93 	PPC_STLCX	"%0,0,%1\n\
94 	bne-	1b"
95 	: "=&r" (t)
96 	: "r" (&(l->a.counter))
97 	: "cc", "xer", "memory");
98 
99 	return t;
100 }
101 
102 #define local_cmpxchg(l, o, n) \
103 	(cmpxchg_local(&((l)->a.counter), (o), (n)))
104 #define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
105 
106 /**
107  * local_add_unless - add unless the number is a given value
108  * @l: pointer of type local_t
109  * @a: the amount to add to v...
110  * @u: ...unless v is equal to u.
111  *
112  * Atomically adds @a to @l, so long as it was not @u.
113  * Returns non-zero if @l was not @u, and zero otherwise.
114  */
115 static __inline__ int local_add_unless(local_t *l, long a, long u)
116 {
117 	long t;
118 
119 	__asm__ __volatile__ (
120 "1:"	PPC_LLARX(%0,0,%1,0) "			# local_add_unless\n\
121 	cmpw	0,%0,%3 \n\
122 	beq-	2f \n\
123 	add	%0,%2,%0 \n"
124 	PPC405_ERR77(0,%2)
125 	PPC_STLCX	"%0,0,%1 \n\
126 	bne-	1b \n"
127 "	subf	%0,%2,%0 \n\
128 2:"
129 	: "=&r" (t)
130 	: "r" (&(l->a.counter)), "r" (a), "r" (u)
131 	: "cc", "memory");
132 
133 	return t != u;
134 }
135 
136 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
137 
138 #define local_sub_and_test(a, l)	(local_sub_return((a), (l)) == 0)
139 #define local_dec_and_test(l)		(local_dec_return((l)) == 0)
140 
141 /*
142  * Atomically test *l and decrement if it is greater than 0.
143  * The function returns the old value of *l minus 1.
144  */
145 static __inline__ long local_dec_if_positive(local_t *l)
146 {
147 	long t;
148 
149 	__asm__ __volatile__(
150 "1:"	PPC_LLARX(%0,0,%1,0) "			# local_dec_if_positive\n\
151 	cmpwi	%0,1\n\
152 	addi	%0,%0,-1\n\
153 	blt-	2f\n"
154 	PPC405_ERR77(0,%1)
155 	PPC_STLCX	"%0,0,%1\n\
156 	bne-	1b"
157 	"\n\
158 2:"	: "=&b" (t)
159 	: "r" (&(l->a.counter))
160 	: "cc", "memory");
161 
162 	return t;
163 }
164 
165 /* Use these for per-cpu local_t variables: on some archs they are
166  * much more efficient than these naive implementations.  Note they take
167  * a variable, not an address.
168  */
169 
170 #define __local_inc(l)		((l)->a.counter++)
171 #define __local_dec(l)		((l)->a.counter++)
172 #define __local_add(i,l)	((l)->a.counter+=(i))
173 #define __local_sub(i,l)	((l)->a.counter-=(i))
174 
175 #endif /* _ARCH_POWERPC_LOCAL_H */
176