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