GNU Linux-libre 4.14.290-gnu1
[releases.git] / arch / metag / include / asm / atomic_lnkget.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef __ASM_METAG_ATOMIC_LNKGET_H
3 #define __ASM_METAG_ATOMIC_LNKGET_H
4
5 #define ATOMIC_INIT(i)  { (i) }
6
7 #define atomic_set(v, i)                WRITE_ONCE((v)->counter, (i))
8
9 #include <linux/compiler.h>
10
11 #include <asm/barrier.h>
12
13 /*
14  * None of these asm statements clobber memory as LNKSET writes around
15  * the cache so the memory it modifies cannot safely be read by any means
16  * other than these accessors.
17  */
18
19 static inline int atomic_read(const atomic_t *v)
20 {
21         int temp;
22
23         asm volatile (
24                 "LNKGETD %0, [%1]\n"
25                 : "=da" (temp)
26                 : "da" (&v->counter));
27
28         return temp;
29 }
30
31 #define ATOMIC_OP(op)                                                   \
32 static inline void atomic_##op(int i, atomic_t *v)                      \
33 {                                                                       \
34         int temp;                                                       \
35                                                                         \
36         asm volatile (                                                  \
37                 "1:     LNKGETD %0, [%1]\n"                             \
38                 "       " #op " %0, %0, %2\n"                           \
39                 "       LNKSETD [%1], %0\n"                             \
40                 "       DEFR    %0, TXSTAT\n"                           \
41                 "       ANDT    %0, %0, #HI(0x3f000000)\n"              \
42                 "       CMPT    %0, #HI(0x02000000)\n"                  \
43                 "       BNZ     1b\n"                                   \
44                 : "=&d" (temp)                                          \
45                 : "da" (&v->counter), "bd" (i)                          \
46                 : "cc");                                                \
47 }                                                                       \
48
49 #define ATOMIC_OP_RETURN(op)                                            \
50 static inline int atomic_##op##_return(int i, atomic_t *v)              \
51 {                                                                       \
52         int result, temp;                                               \
53                                                                         \
54         smp_mb();                                                       \
55                                                                         \
56         asm volatile (                                                  \
57                 "1:     LNKGETD %1, [%2]\n"                             \
58                 "       " #op " %1, %1, %3\n"                           \
59                 "       LNKSETD [%2], %1\n"                             \
60                 "       DEFR    %0, TXSTAT\n"                           \
61                 "       ANDT    %0, %0, #HI(0x3f000000)\n"              \
62                 "       CMPT    %0, #HI(0x02000000)\n"                  \
63                 "       BNZ 1b\n"                                       \
64                 : "=&d" (temp), "=&da" (result)                         \
65                 : "da" (&v->counter), "br" (i)                          \
66                 : "cc");                                                \
67                                                                         \
68         smp_mb();                                                       \
69                                                                         \
70         return result;                                                  \
71 }
72
73 #define ATOMIC_FETCH_OP(op)                                             \
74 static inline int atomic_fetch_##op(int i, atomic_t *v)                 \
75 {                                                                       \
76         int result, temp;                                               \
77                                                                         \
78         smp_mb();                                                       \
79                                                                         \
80         asm volatile (                                                  \
81                 "1:     LNKGETD %1, [%2]\n"                             \
82                 "       " #op " %0, %1, %3\n"                           \
83                 "       LNKSETD [%2], %0\n"                             \
84                 "       DEFR    %0, TXSTAT\n"                           \
85                 "       ANDT    %0, %0, #HI(0x3f000000)\n"              \
86                 "       CMPT    %0, #HI(0x02000000)\n"                  \
87                 "       BNZ 1b\n"                                       \
88                 : "=&d" (temp), "=&d" (result)                          \
89                 : "da" (&v->counter), "bd" (i)                          \
90                 : "cc");                                                \
91                                                                         \
92         smp_mb();                                                       \
93                                                                         \
94         return result;                                                  \
95 }
96
97 #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op)
98
99 ATOMIC_OPS(add)
100 ATOMIC_OPS(sub)
101
102 #undef ATOMIC_OPS
103 #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
104
105 ATOMIC_OPS(and)
106 ATOMIC_OPS(or)
107 ATOMIC_OPS(xor)
108
109 #undef ATOMIC_OPS
110 #undef ATOMIC_FETCH_OP
111 #undef ATOMIC_OP_RETURN
112 #undef ATOMIC_OP
113
114 static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
115 {
116         int result, temp;
117
118         smp_mb();
119
120         asm volatile (
121                 "1:     LNKGETD %1, [%2]\n"
122                 "       CMP     %1, %3\n"
123                 "       LNKSETDEQ [%2], %4\n"
124                 "       BNE     2f\n"
125                 "       DEFR    %0, TXSTAT\n"
126                 "       ANDT    %0, %0, #HI(0x3f000000)\n"
127                 "       CMPT    %0, #HI(0x02000000)\n"
128                 "       BNZ     1b\n"
129                 "2:\n"
130                 : "=&d" (temp), "=&d" (result)
131                 : "da" (&v->counter), "bd" (old), "da" (new)
132                 : "cc");
133
134         smp_mb();
135
136         return result;
137 }
138
139 static inline int atomic_xchg(atomic_t *v, int new)
140 {
141         int temp, old;
142
143         asm volatile (
144                 "1:     LNKGETD %1, [%2]\n"
145                 "       LNKSETD [%2], %3\n"
146                 "       DEFR    %0, TXSTAT\n"
147                 "       ANDT    %0, %0, #HI(0x3f000000)\n"
148                 "       CMPT    %0, #HI(0x02000000)\n"
149                 "       BNZ     1b\n"
150                 : "=&d" (temp), "=&d" (old)
151                 : "da" (&v->counter), "da" (new)
152                 : "cc");
153
154         return old;
155 }
156
157 static inline int __atomic_add_unless(atomic_t *v, int a, int u)
158 {
159         int result, temp;
160
161         smp_mb();
162
163         asm volatile (
164                 "1:     LNKGETD %1, [%2]\n"
165                 "       CMP     %1, %3\n"
166                 "       ADD     %0, %1, %4\n"
167                 "       LNKSETDNE [%2], %0\n"
168                 "       BEQ     2f\n"
169                 "       DEFR    %0, TXSTAT\n"
170                 "       ANDT    %0, %0, #HI(0x3f000000)\n"
171                 "       CMPT    %0, #HI(0x02000000)\n"
172                 "       BNZ     1b\n"
173                 "2:\n"
174                 : "=&d" (temp), "=&d" (result)
175                 : "da" (&v->counter), "bd" (u), "bd" (a)
176                 : "cc");
177
178         smp_mb();
179
180         return result;
181 }
182
183 static inline int atomic_sub_if_positive(int i, atomic_t *v)
184 {
185         int result, temp;
186
187         asm volatile (
188                 "1:     LNKGETD %1, [%2]\n"
189                 "       SUBS    %1, %1, %3\n"
190                 "       LNKSETDGE [%2], %1\n"
191                 "       BLT     2f\n"
192                 "       DEFR    %0, TXSTAT\n"
193                 "       ANDT    %0, %0, #HI(0x3f000000)\n"
194                 "       CMPT    %0, #HI(0x02000000)\n"
195                 "       BNZ     1b\n"
196                 "2:\n"
197                 : "=&d" (temp), "=&da" (result)
198                 : "da" (&v->counter), "bd" (i)
199                 : "cc");
200
201         return result;
202 }
203
204 #endif /* __ASM_METAG_ATOMIC_LNKGET_H */