Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

riscv/atomic: Strengthen implementations with fences

Atomics present the same issue with locking: release and acquire
variants need to be strengthened to meet the constraints defined
by the Linux-kernel memory consistency model [1].

Atomics present a further issue: implementations of atomics such
as atomic_cmpxchg() and atomic_add_unless() rely on LR/SC pairs,
which do not give full-ordering with .aqrl; for example, current
implementations allow the "lr-sc-aqrl-pair-vs-full-barrier" test
below to end up with the state indicated in the "exists" clause.

In order to "synchronize" LKMM and RISC-V's implementation, this
commit strengthens the implementations of the atomics operations
by replacing .rl and .aq with the use of ("lightweigth") fences,
and by replacing .aqrl LR/SC pairs in sequences such as:

0: lr.w.aqrl %0, %addr
bne %0, %old, 1f
...
sc.w.aqrl %1, %new, %addr
bnez %1, 0b
1:

with sequences of the form:

0: lr.w %0, %addr
bne %0, %old, 1f
...
sc.w.rl %1, %new, %addr /* SC-release */
bnez %1, 0b
fence rw, rw /* "full" fence */
1:

following Daniel's suggestion.

These modifications were validated with simulation of the RISC-V
memory consistency model.

C lr-sc-aqrl-pair-vs-full-barrier

{}

P0(int *x, int *y, atomic_t *u)
{
int r0;
int r1;

WRITE_ONCE(*x, 1);
r0 = atomic_cmpxchg(u, 0, 1);
r1 = READ_ONCE(*y);
}

P1(int *x, int *y, atomic_t *v)
{
int r0;
int r1;

WRITE_ONCE(*y, 1);
r0 = atomic_cmpxchg(v, 0, 1);
r1 = READ_ONCE(*x);
}

exists (u=1 /\ v=1 /\ 0:r1=0 /\ 1:r1=0)

[1] https://marc.info/?l=linux-kernel&m=151930201102853&w=2
https://groups.google.com/a/groups.riscv.org/forum/#!topic/isa-dev/hKywNHBkAXM
https://marc.info/?l=linux-kernel&m=151633436614259&w=2

Suggested-by: Daniel Lustig <dlustig@nvidia.com>
Signed-off-by: Andrea Parri <parri.andrea@gmail.com>
Cc: Palmer Dabbelt <palmer@sifive.com>
Cc: Albert Ou <albert@sifive.com>
Cc: Daniel Lustig <dlustig@nvidia.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Jade Alglave <j.alglave@ucl.ac.uk>
Cc: Luc Maranget <luc.maranget@inria.fr>
Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Cc: Akira Yokosawa <akiyks@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-riscv@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>

authored by

Andrea Parri and committed by
Palmer Dabbelt
5ce6c1f3 0123f4d7

+586 -218
+268 -149
arch/riscv/include/asm/atomic.h
··· 24 24 #include <asm/barrier.h> 25 25 26 26 #define ATOMIC_INIT(i) { (i) } 27 + 28 + #define __atomic_op_acquire(op, args...) \ 29 + ({ \ 30 + typeof(op##_relaxed(args)) __ret = op##_relaxed(args); \ 31 + __asm__ __volatile__(RISCV_ACQUIRE_BARRIER "" ::: "memory"); \ 32 + __ret; \ 33 + }) 34 + 35 + #define __atomic_op_release(op, args...) \ 36 + ({ \ 37 + __asm__ __volatile__(RISCV_RELEASE_BARRIER "" ::: "memory"); \ 38 + op##_relaxed(args); \ 39 + }) 40 + 27 41 static __always_inline int atomic_read(const atomic_t *v) 28 42 { 29 43 return READ_ONCE(v->counter); ··· 64 50 * have the AQ or RL bits set. These don't return anything, so there's only 65 51 * one version to worry about. 66 52 */ 67 - #define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \ 68 - static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ 69 - { \ 70 - __asm__ __volatile__ ( \ 71 - "amo" #asm_op "." #asm_type " zero, %1, %0" \ 72 - : "+A" (v->counter) \ 73 - : "r" (I) \ 74 - : "memory"); \ 75 - } 53 + #define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \ 54 + static __always_inline \ 55 + void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ 56 + { \ 57 + __asm__ __volatile__ ( \ 58 + " amo" #asm_op "." #asm_type " zero, %1, %0" \ 59 + : "+A" (v->counter) \ 60 + : "r" (I) \ 61 + : "memory"); \ 62 + } \ 76 63 77 64 #ifdef CONFIG_GENERIC_ATOMIC64 78 - #define ATOMIC_OPS(op, asm_op, I) \ 65 + #define ATOMIC_OPS(op, asm_op, I) \ 79 66 ATOMIC_OP (op, asm_op, I, w, int, ) 80 67 #else 81 - #define ATOMIC_OPS(op, asm_op, I) \ 82 - ATOMIC_OP (op, asm_op, I, w, int, ) \ 68 + #define ATOMIC_OPS(op, asm_op, I) \ 69 + ATOMIC_OP (op, asm_op, I, w, int, ) \ 83 70 ATOMIC_OP (op, asm_op, I, d, long, 64) 84 71 #endif 85 72 ··· 94 79 #undef ATOMIC_OPS 95 80 96 81 /* 97 - * Atomic ops that have ordered, relaxed, acquire, and relese variants. 82 + * Atomic ops that have ordered, relaxed, acquire, and release variants. 98 83 * There's two flavors of these: the arithmatic ops have both fetch and return 99 84 * versions, while the logical ops only have fetch versions. 100 85 */ 101 - #define ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, asm_type, c_type, prefix) \ 102 - static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \ 103 - { \ 104 - register c_type ret; \ 105 - __asm__ __volatile__ ( \ 106 - "amo" #asm_op "." #asm_type #asm_or " %1, %2, %0" \ 107 - : "+A" (v->counter), "=r" (ret) \ 108 - : "r" (I) \ 109 - : "memory"); \ 110 - return ret; \ 86 + #define ATOMIC_FETCH_OP(op, asm_op, I, asm_type, c_type, prefix) \ 87 + static __always_inline \ 88 + c_type atomic##prefix##_fetch_##op##_relaxed(c_type i, \ 89 + atomic##prefix##_t *v) \ 90 + { \ 91 + register c_type ret; \ 92 + __asm__ __volatile__ ( \ 93 + " amo" #asm_op "." #asm_type " %1, %2, %0" \ 94 + : "+A" (v->counter), "=r" (ret) \ 95 + : "r" (I) \ 96 + : "memory"); \ 97 + return ret; \ 98 + } \ 99 + static __always_inline \ 100 + c_type atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v) \ 101 + { \ 102 + register c_type ret; \ 103 + __asm__ __volatile__ ( \ 104 + " amo" #asm_op "." #asm_type ".aqrl %1, %2, %0" \ 105 + : "+A" (v->counter), "=r" (ret) \ 106 + : "r" (I) \ 107 + : "memory"); \ 108 + return ret; \ 111 109 } 112 110 113 - #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix) \ 114 - static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, atomic##prefix##_t *v) \ 115 - { \ 116 - return atomic##prefix##_fetch_##op##c_or(i, v) c_op I; \ 111 + #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_type, c_type, prefix) \ 112 + static __always_inline \ 113 + c_type atomic##prefix##_##op##_return_relaxed(c_type i, \ 114 + atomic##prefix##_t *v) \ 115 + { \ 116 + return atomic##prefix##_fetch_##op##_relaxed(i, v) c_op I; \ 117 + } \ 118 + static __always_inline \ 119 + c_type atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v) \ 120 + { \ 121 + return atomic##prefix##_fetch_##op(i, v) c_op I; \ 117 122 } 118 123 119 124 #ifdef CONFIG_GENERIC_ATOMIC64 120 - #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ 121 - ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \ 122 - ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) 125 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 126 + ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \ 127 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) 123 128 #else 124 - #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ 125 - ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \ 126 - ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ 127 - ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, d, long, 64) \ 128 - ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) 129 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 130 + ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \ 131 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) \ 132 + ATOMIC_FETCH_OP( op, asm_op, I, d, long, 64) \ 133 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, d, long, 64) 129 134 #endif 130 135 131 - ATOMIC_OPS(add, add, +, i, , _relaxed) 132 - ATOMIC_OPS(add, add, +, i, .aq , _acquire) 133 - ATOMIC_OPS(add, add, +, i, .rl , _release) 134 - ATOMIC_OPS(add, add, +, i, .aqrl, ) 136 + ATOMIC_OPS(add, add, +, i) 137 + ATOMIC_OPS(sub, add, +, -i) 135 138 136 - ATOMIC_OPS(sub, add, +, -i, , _relaxed) 137 - ATOMIC_OPS(sub, add, +, -i, .aq , _acquire) 138 - ATOMIC_OPS(sub, add, +, -i, .rl , _release) 139 - ATOMIC_OPS(sub, add, +, -i, .aqrl, ) 139 + #define atomic_add_return_relaxed atomic_add_return_relaxed 140 + #define atomic_sub_return_relaxed atomic_sub_return_relaxed 141 + #define atomic_add_return atomic_add_return 142 + #define atomic_sub_return atomic_sub_return 143 + 144 + #define atomic_fetch_add_relaxed atomic_fetch_add_relaxed 145 + #define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed 146 + #define atomic_fetch_add atomic_fetch_add 147 + #define atomic_fetch_sub atomic_fetch_sub 148 + 149 + #ifndef CONFIG_GENERIC_ATOMIC64 150 + #define atomic64_add_return_relaxed atomic64_add_return_relaxed 151 + #define atomic64_sub_return_relaxed atomic64_sub_return_relaxed 152 + #define atomic64_add_return atomic64_add_return 153 + #define atomic64_sub_return atomic64_sub_return 154 + 155 + #define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed 156 + #define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed 157 + #define atomic64_fetch_add atomic64_fetch_add 158 + #define atomic64_fetch_sub atomic64_fetch_sub 159 + #endif 140 160 141 161 #undef ATOMIC_OPS 142 162 143 163 #ifdef CONFIG_GENERIC_ATOMIC64 144 - #define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \ 145 - ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, ) 164 + #define ATOMIC_OPS(op, asm_op, I) \ 165 + ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) 146 166 #else 147 - #define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \ 148 - ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, ) \ 149 - ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, d, long, 64) 167 + #define ATOMIC_OPS(op, asm_op, I) \ 168 + ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) \ 169 + ATOMIC_FETCH_OP(op, asm_op, I, d, long, 64) 150 170 #endif 151 171 152 - ATOMIC_OPS(and, and, i, , _relaxed) 153 - ATOMIC_OPS(and, and, i, .aq , _acquire) 154 - ATOMIC_OPS(and, and, i, .rl , _release) 155 - ATOMIC_OPS(and, and, i, .aqrl, ) 172 + ATOMIC_OPS(and, and, i) 173 + ATOMIC_OPS( or, or, i) 174 + ATOMIC_OPS(xor, xor, i) 156 175 157 - ATOMIC_OPS( or, or, i, , _relaxed) 158 - ATOMIC_OPS( or, or, i, .aq , _acquire) 159 - ATOMIC_OPS( or, or, i, .rl , _release) 160 - ATOMIC_OPS( or, or, i, .aqrl, ) 176 + #define atomic_fetch_and_relaxed atomic_fetch_and_relaxed 177 + #define atomic_fetch_or_relaxed atomic_fetch_or_relaxed 178 + #define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed 179 + #define atomic_fetch_and atomic_fetch_and 180 + #define atomic_fetch_or atomic_fetch_or 181 + #define atomic_fetch_xor atomic_fetch_xor 161 182 162 - ATOMIC_OPS(xor, xor, i, , _relaxed) 163 - ATOMIC_OPS(xor, xor, i, .aq , _acquire) 164 - ATOMIC_OPS(xor, xor, i, .rl , _release) 165 - ATOMIC_OPS(xor, xor, i, .aqrl, ) 183 + #ifndef CONFIG_GENERIC_ATOMIC64 184 + #define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed 185 + #define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed 186 + #define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed 187 + #define atomic64_fetch_and atomic64_fetch_and 188 + #define atomic64_fetch_or atomic64_fetch_or 189 + #define atomic64_fetch_xor atomic64_fetch_xor 190 + #endif 166 191 167 192 #undef ATOMIC_OPS 168 193 ··· 212 157 /* 213 158 * The extra atomic operations that are constructed from one of the core 214 159 * AMO-based operations above (aside from sub, which is easier to fit above). 215 - * These are required to perform a barrier, but they're OK this way because 216 - * atomic_*_return is also required to perform a barrier. 160 + * These are required to perform a full barrier, but they're OK this way 161 + * because atomic_*_return is also required to perform a full barrier. 162 + * 217 163 */ 218 - #define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \ 219 - static __always_inline bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ 220 - { \ 221 - return atomic##prefix##_##func_op##_return(i, v) comp_op I; \ 164 + #define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \ 165 + static __always_inline \ 166 + bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ 167 + { \ 168 + return atomic##prefix##_##func_op##_return(i, v) comp_op I; \ 222 169 } 223 170 224 171 #ifdef CONFIG_GENERIC_ATOMIC64 225 - #define ATOMIC_OPS(op, func_op, comp_op, I) \ 226 - ATOMIC_OP (op, func_op, comp_op, I, int, ) 172 + #define ATOMIC_OPS(op, func_op, comp_op, I) \ 173 + ATOMIC_OP(op, func_op, comp_op, I, int, ) 227 174 #else 228 - #define ATOMIC_OPS(op, func_op, comp_op, I) \ 229 - ATOMIC_OP (op, func_op, comp_op, I, int, ) \ 230 - ATOMIC_OP (op, func_op, comp_op, I, long, 64) 175 + #define ATOMIC_OPS(op, func_op, comp_op, I) \ 176 + ATOMIC_OP(op, func_op, comp_op, I, int, ) \ 177 + ATOMIC_OP(op, func_op, comp_op, I, long, 64) 231 178 #endif 232 179 233 180 ATOMIC_OPS(add_and_test, add, ==, 0) ··· 239 182 #undef ATOMIC_OP 240 183 #undef ATOMIC_OPS 241 184 242 - #define ATOMIC_OP(op, func_op, I, c_type, prefix) \ 243 - static __always_inline void atomic##prefix##_##op(atomic##prefix##_t *v) \ 244 - { \ 245 - atomic##prefix##_##func_op(I, v); \ 185 + #define ATOMIC_OP(op, func_op, I, c_type, prefix) \ 186 + static __always_inline \ 187 + void atomic##prefix##_##op(atomic##prefix##_t *v) \ 188 + { \ 189 + atomic##prefix##_##func_op(I, v); \ 246 190 } 247 191 248 - #define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix) \ 249 - static __always_inline c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \ 250 - { \ 251 - return atomic##prefix##_fetch_##func_op(I, v); \ 192 + #define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix) \ 193 + static __always_inline \ 194 + c_type atomic##prefix##_fetch_##op##_relaxed(atomic##prefix##_t *v) \ 195 + { \ 196 + return atomic##prefix##_fetch_##func_op##_relaxed(I, v); \ 197 + } \ 198 + static __always_inline \ 199 + c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \ 200 + { \ 201 + return atomic##prefix##_fetch_##func_op(I, v); \ 252 202 } 253 203 254 - #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, c_type, prefix) \ 255 - static __always_inline c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \ 256 - { \ 257 - return atomic##prefix##_fetch_##op(v) c_op I; \ 204 + #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, c_type, prefix) \ 205 + static __always_inline \ 206 + c_type atomic##prefix##_##op##_return_relaxed(atomic##prefix##_t *v) \ 207 + { \ 208 + return atomic##prefix##_fetch_##op##_relaxed(v) c_op I; \ 209 + } \ 210 + static __always_inline \ 211 + c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \ 212 + { \ 213 + return atomic##prefix##_fetch_##op(v) c_op I; \ 258 214 } 259 215 260 216 #ifdef CONFIG_GENERIC_ATOMIC64 261 - #define ATOMIC_OPS(op, asm_op, c_op, I) \ 262 - ATOMIC_OP (op, asm_op, I, int, ) \ 263 - ATOMIC_FETCH_OP (op, asm_op, I, int, ) \ 217 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 218 + ATOMIC_OP( op, asm_op, I, int, ) \ 219 + ATOMIC_FETCH_OP( op, asm_op, I, int, ) \ 264 220 ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) 265 221 #else 266 - #define ATOMIC_OPS(op, asm_op, c_op, I) \ 267 - ATOMIC_OP (op, asm_op, I, int, ) \ 268 - ATOMIC_FETCH_OP (op, asm_op, I, int, ) \ 269 - ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \ 270 - ATOMIC_OP (op, asm_op, I, long, 64) \ 271 - ATOMIC_FETCH_OP (op, asm_op, I, long, 64) \ 222 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 223 + ATOMIC_OP( op, asm_op, I, int, ) \ 224 + ATOMIC_FETCH_OP( op, asm_op, I, int, ) \ 225 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \ 226 + ATOMIC_OP( op, asm_op, I, long, 64) \ 227 + ATOMIC_FETCH_OP( op, asm_op, I, long, 64) \ 272 228 ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64) 273 229 #endif 274 230 275 231 ATOMIC_OPS(inc, add, +, 1) 276 232 ATOMIC_OPS(dec, add, +, -1) 277 233 234 + #define atomic_inc_return_relaxed atomic_inc_return_relaxed 235 + #define atomic_dec_return_relaxed atomic_dec_return_relaxed 236 + #define atomic_inc_return atomic_inc_return 237 + #define atomic_dec_return atomic_dec_return 238 + 239 + #define atomic_fetch_inc_relaxed atomic_fetch_inc_relaxed 240 + #define atomic_fetch_dec_relaxed atomic_fetch_dec_relaxed 241 + #define atomic_fetch_inc atomic_fetch_inc 242 + #define atomic_fetch_dec atomic_fetch_dec 243 + 244 + #ifndef CONFIG_GENERIC_ATOMIC64 245 + #define atomic64_inc_return_relaxed atomic64_inc_return_relaxed 246 + #define atomic64_dec_return_relaxed atomic64_dec_return_relaxed 247 + #define atomic64_inc_return atomic64_inc_return 248 + #define atomic64_dec_return atomic64_dec_return 249 + 250 + #define atomic64_fetch_inc_relaxed atomic64_fetch_inc_relaxed 251 + #define atomic64_fetch_dec_relaxed atomic64_fetch_dec_relaxed 252 + #define atomic64_fetch_inc atomic64_fetch_inc 253 + #define atomic64_fetch_dec atomic64_fetch_dec 254 + #endif 255 + 278 256 #undef ATOMIC_OPS 279 257 #undef ATOMIC_OP 280 258 #undef ATOMIC_FETCH_OP 281 259 #undef ATOMIC_OP_RETURN 282 260 283 - #define ATOMIC_OP(op, func_op, comp_op, I, prefix) \ 284 - static __always_inline bool atomic##prefix##_##op(atomic##prefix##_t *v) \ 285 - { \ 286 - return atomic##prefix##_##func_op##_return(v) comp_op I; \ 261 + #define ATOMIC_OP(op, func_op, comp_op, I, prefix) \ 262 + static __always_inline \ 263 + bool atomic##prefix##_##op(atomic##prefix##_t *v) \ 264 + { \ 265 + return atomic##prefix##_##func_op##_return(v) comp_op I; \ 287 266 } 288 267 289 268 ATOMIC_OP(inc_and_test, inc, ==, 0, ) ··· 331 238 332 239 #undef ATOMIC_OP 333 240 334 - /* This is required to provide a barrier on success. */ 241 + /* This is required to provide a full barrier on success. */ 335 242 static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) 336 243 { 337 244 int prev, rc; 338 245 339 246 __asm__ __volatile__ ( 340 - "0:\n\t" 341 - "lr.w.aqrl %[p], %[c]\n\t" 342 - "beq %[p], %[u], 1f\n\t" 343 - "add %[rc], %[p], %[a]\n\t" 344 - "sc.w.aqrl %[rc], %[rc], %[c]\n\t" 345 - "bnez %[rc], 0b\n\t" 346 - "1:" 247 + "0: lr.w %[p], %[c]\n" 248 + " beq %[p], %[u], 1f\n" 249 + " add %[rc], %[p], %[a]\n" 250 + " sc.w.rl %[rc], %[rc], %[c]\n" 251 + " bnez %[rc], 0b\n" 252 + " fence rw, rw\n" 253 + "1:\n" 347 254 : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 348 255 : [a]"r" (a), [u]"r" (u) 349 256 : "memory"); ··· 356 263 long prev, rc; 357 264 358 265 __asm__ __volatile__ ( 359 - "0:\n\t" 360 - "lr.d.aqrl %[p], %[c]\n\t" 361 - "beq %[p], %[u], 1f\n\t" 362 - "add %[rc], %[p], %[a]\n\t" 363 - "sc.d.aqrl %[rc], %[rc], %[c]\n\t" 364 - "bnez %[rc], 0b\n\t" 365 - "1:" 266 + "0: lr.d %[p], %[c]\n" 267 + " beq %[p], %[u], 1f\n" 268 + " add %[rc], %[p], %[a]\n" 269 + " sc.d.rl %[rc], %[rc], %[c]\n" 270 + " bnez %[rc], 0b\n" 271 + " fence rw, rw\n" 272 + "1:\n" 366 273 : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 367 274 : [a]"r" (a), [u]"r" (u) 368 275 : "memory"); ··· 393 300 394 301 /* 395 302 * atomic_{cmp,}xchg is required to have exactly the same ordering semantics as 396 - * {cmp,}xchg and the operations that return, so they need a barrier. 303 + * {cmp,}xchg and the operations that return, so they need a full barrier. 397 304 */ 398 - /* 399 - * FIXME: atomic_cmpxchg_{acquire,release,relaxed} are all implemented by 400 - * assigning the same barrier to both the LR and SC operations, but that might 401 - * not make any sense. We're waiting on a memory model specification to 402 - * determine exactly what the right thing to do is here. 403 - */ 404 - #define ATOMIC_OP(c_t, prefix, c_or, size, asm_or) \ 405 - static __always_inline c_t atomic##prefix##_cmpxchg##c_or(atomic##prefix##_t *v, c_t o, c_t n) \ 406 - { \ 407 - return __cmpxchg(&(v->counter), o, n, size, asm_or, asm_or); \ 408 - } \ 409 - static __always_inline c_t atomic##prefix##_xchg##c_or(atomic##prefix##_t *v, c_t n) \ 410 - { \ 411 - return __xchg(n, &(v->counter), size, asm_or); \ 305 + #define ATOMIC_OP(c_t, prefix, size) \ 306 + static __always_inline \ 307 + c_t atomic##prefix##_xchg_relaxed(atomic##prefix##_t *v, c_t n) \ 308 + { \ 309 + return __xchg_relaxed(&(v->counter), n, size); \ 310 + } \ 311 + static __always_inline \ 312 + c_t atomic##prefix##_xchg_acquire(atomic##prefix##_t *v, c_t n) \ 313 + { \ 314 + return __xchg_acquire(&(v->counter), n, size); \ 315 + } \ 316 + static __always_inline \ 317 + c_t atomic##prefix##_xchg_release(atomic##prefix##_t *v, c_t n) \ 318 + { \ 319 + return __xchg_release(&(v->counter), n, size); \ 320 + } \ 321 + static __always_inline \ 322 + c_t atomic##prefix##_xchg(atomic##prefix##_t *v, c_t n) \ 323 + { \ 324 + return __xchg(&(v->counter), n, size); \ 325 + } \ 326 + static __always_inline \ 327 + c_t atomic##prefix##_cmpxchg_relaxed(atomic##prefix##_t *v, \ 328 + c_t o, c_t n) \ 329 + { \ 330 + return __cmpxchg_relaxed(&(v->counter), o, n, size); \ 331 + } \ 332 + static __always_inline \ 333 + c_t atomic##prefix##_cmpxchg_acquire(atomic##prefix##_t *v, \ 334 + c_t o, c_t n) \ 335 + { \ 336 + return __cmpxchg_acquire(&(v->counter), o, n, size); \ 337 + } \ 338 + static __always_inline \ 339 + c_t atomic##prefix##_cmpxchg_release(atomic##prefix##_t *v, \ 340 + c_t o, c_t n) \ 341 + { \ 342 + return __cmpxchg_release(&(v->counter), o, n, size); \ 343 + } \ 344 + static __always_inline \ 345 + c_t atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n) \ 346 + { \ 347 + return __cmpxchg(&(v->counter), o, n, size); \ 412 348 } 413 349 414 350 #ifdef CONFIG_GENERIC_ATOMIC64 415 - #define ATOMIC_OPS(c_or, asm_or) \ 416 - ATOMIC_OP( int, , c_or, 4, asm_or) 351 + #define ATOMIC_OPS() \ 352 + ATOMIC_OP( int, , 4) 417 353 #else 418 - #define ATOMIC_OPS(c_or, asm_or) \ 419 - ATOMIC_OP( int, , c_or, 4, asm_or) \ 420 - ATOMIC_OP(long, 64, c_or, 8, asm_or) 354 + #define ATOMIC_OPS() \ 355 + ATOMIC_OP( int, , 4) \ 356 + ATOMIC_OP(long, 64, 8) 421 357 #endif 422 358 423 - ATOMIC_OPS( , .aqrl) 424 - ATOMIC_OPS(_acquire, .aq) 425 - ATOMIC_OPS(_release, .rl) 426 - ATOMIC_OPS(_relaxed, ) 359 + ATOMIC_OPS() 427 360 428 361 #undef ATOMIC_OPS 429 362 #undef ATOMIC_OP ··· 459 340 int prev, rc; 460 341 461 342 __asm__ __volatile__ ( 462 - "0:\n\t" 463 - "lr.w.aqrl %[p], %[c]\n\t" 464 - "sub %[rc], %[p], %[o]\n\t" 465 - "bltz %[rc], 1f\n\t" 466 - "sc.w.aqrl %[rc], %[rc], %[c]\n\t" 467 - "bnez %[rc], 0b\n\t" 468 - "1:" 343 + "0: lr.w %[p], %[c]\n" 344 + " sub %[rc], %[p], %[o]\n" 345 + " bltz %[rc], 1f\n" 346 + " sc.w.rl %[rc], %[rc], %[c]\n" 347 + " bnez %[rc], 0b\n" 348 + " fence rw, rw\n" 349 + "1:\n" 469 350 : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 470 351 : [o]"r" (offset) 471 352 : "memory"); ··· 480 361 long prev, rc; 481 362 482 363 __asm__ __volatile__ ( 483 - "0:\n\t" 484 - "lr.d.aqrl %[p], %[c]\n\t" 485 - "sub %[rc], %[p], %[o]\n\t" 486 - "bltz %[rc], 1f\n\t" 487 - "sc.d.aqrl %[rc], %[rc], %[c]\n\t" 488 - "bnez %[rc], 0b\n\t" 489 - "1:" 364 + "0: lr.d %[p], %[c]\n" 365 + " sub %[rc], %[p], %[o]\n" 366 + " bltz %[rc], 1f\n" 367 + " sc.d.rl %[rc], %[rc], %[c]\n" 368 + " bnez %[rc], 0b\n" 369 + " fence rw, rw\n" 370 + "1:\n" 490 371 : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 491 372 : [o]"r" (offset) 492 373 : "memory");
+318 -69
arch/riscv/include/asm/cmpxchg.h
··· 17 17 #include <linux/bug.h> 18 18 19 19 #include <asm/barrier.h> 20 + #include <asm/fence.h> 20 21 21 - #define __xchg(new, ptr, size, asm_or) \ 22 - ({ \ 23 - __typeof__(ptr) __ptr = (ptr); \ 24 - __typeof__(new) __new = (new); \ 25 - __typeof__(*(ptr)) __ret; \ 26 - switch (size) { \ 27 - case 4: \ 28 - __asm__ __volatile__ ( \ 29 - "amoswap.w" #asm_or " %0, %2, %1" \ 30 - : "=r" (__ret), "+A" (*__ptr) \ 31 - : "r" (__new) \ 32 - : "memory"); \ 33 - break; \ 34 - case 8: \ 35 - __asm__ __volatile__ ( \ 36 - "amoswap.d" #asm_or " %0, %2, %1" \ 37 - : "=r" (__ret), "+A" (*__ptr) \ 38 - : "r" (__new) \ 39 - : "memory"); \ 40 - break; \ 41 - default: \ 42 - BUILD_BUG(); \ 43 - } \ 44 - __ret; \ 22 + #define __xchg_relaxed(ptr, new, size) \ 23 + ({ \ 24 + __typeof__(ptr) __ptr = (ptr); \ 25 + __typeof__(new) __new = (new); \ 26 + __typeof__(*(ptr)) __ret; \ 27 + switch (size) { \ 28 + case 4: \ 29 + __asm__ __volatile__ ( \ 30 + " amoswap.w %0, %2, %1\n" \ 31 + : "=r" (__ret), "+A" (*__ptr) \ 32 + : "r" (__new) \ 33 + : "memory"); \ 34 + break; \ 35 + case 8: \ 36 + __asm__ __volatile__ ( \ 37 + " amoswap.d %0, %2, %1\n" \ 38 + : "=r" (__ret), "+A" (*__ptr) \ 39 + : "r" (__new) \ 40 + : "memory"); \ 41 + break; \ 42 + default: \ 43 + BUILD_BUG(); \ 44 + } \ 45 + __ret; \ 45 46 }) 46 47 47 - #define xchg(ptr, x) (__xchg((x), (ptr), sizeof(*(ptr)), .aqrl)) 48 - 49 - #define xchg32(ptr, x) \ 50 - ({ \ 51 - BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 52 - xchg((ptr), (x)); \ 48 + #define xchg_relaxed(ptr, x) \ 49 + ({ \ 50 + __typeof__(*(ptr)) _x_ = (x); \ 51 + (__typeof__(*(ptr))) __xchg_relaxed((ptr), \ 52 + _x_, sizeof(*(ptr))); \ 53 53 }) 54 54 55 - #define xchg64(ptr, x) \ 56 - ({ \ 57 - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 58 - xchg((ptr), (x)); \ 55 + #define __xchg_acquire(ptr, new, size) \ 56 + ({ \ 57 + __typeof__(ptr) __ptr = (ptr); \ 58 + __typeof__(new) __new = (new); \ 59 + __typeof__(*(ptr)) __ret; \ 60 + switch (size) { \ 61 + case 4: \ 62 + __asm__ __volatile__ ( \ 63 + " amoswap.w %0, %2, %1\n" \ 64 + RISCV_ACQUIRE_BARRIER \ 65 + : "=r" (__ret), "+A" (*__ptr) \ 66 + : "r" (__new) \ 67 + : "memory"); \ 68 + break; \ 69 + case 8: \ 70 + __asm__ __volatile__ ( \ 71 + " amoswap.d %0, %2, %1\n" \ 72 + RISCV_ACQUIRE_BARRIER \ 73 + : "=r" (__ret), "+A" (*__ptr) \ 74 + : "r" (__new) \ 75 + : "memory"); \ 76 + break; \ 77 + default: \ 78 + BUILD_BUG(); \ 79 + } \ 80 + __ret; \ 81 + }) 82 + 83 + #define xchg_acquire(ptr, x) \ 84 + ({ \ 85 + __typeof__(*(ptr)) _x_ = (x); \ 86 + (__typeof__(*(ptr))) __xchg_acquire((ptr), \ 87 + _x_, sizeof(*(ptr))); \ 88 + }) 89 + 90 + #define __xchg_release(ptr, new, size) \ 91 + ({ \ 92 + __typeof__(ptr) __ptr = (ptr); \ 93 + __typeof__(new) __new = (new); \ 94 + __typeof__(*(ptr)) __ret; \ 95 + switch (size) { \ 96 + case 4: \ 97 + __asm__ __volatile__ ( \ 98 + RISCV_RELEASE_BARRIER \ 99 + " amoswap.w %0, %2, %1\n" \ 100 + : "=r" (__ret), "+A" (*__ptr) \ 101 + : "r" (__new) \ 102 + : "memory"); \ 103 + break; \ 104 + case 8: \ 105 + __asm__ __volatile__ ( \ 106 + RISCV_RELEASE_BARRIER \ 107 + " amoswap.d %0, %2, %1\n" \ 108 + : "=r" (__ret), "+A" (*__ptr) \ 109 + : "r" (__new) \ 110 + : "memory"); \ 111 + break; \ 112 + default: \ 113 + BUILD_BUG(); \ 114 + } \ 115 + __ret; \ 116 + }) 117 + 118 + #define xchg_release(ptr, x) \ 119 + ({ \ 120 + __typeof__(*(ptr)) _x_ = (x); \ 121 + (__typeof__(*(ptr))) __xchg_release((ptr), \ 122 + _x_, sizeof(*(ptr))); \ 123 + }) 124 + 125 + #define __xchg(ptr, new, size) \ 126 + ({ \ 127 + __typeof__(ptr) __ptr = (ptr); \ 128 + __typeof__(new) __new = (new); \ 129 + __typeof__(*(ptr)) __ret; \ 130 + switch (size) { \ 131 + case 4: \ 132 + __asm__ __volatile__ ( \ 133 + " amoswap.w.aqrl %0, %2, %1\n" \ 134 + : "=r" (__ret), "+A" (*__ptr) \ 135 + : "r" (__new) \ 136 + : "memory"); \ 137 + break; \ 138 + case 8: \ 139 + __asm__ __volatile__ ( \ 140 + " amoswap.d.aqrl %0, %2, %1\n" \ 141 + : "=r" (__ret), "+A" (*__ptr) \ 142 + : "r" (__new) \ 143 + : "memory"); \ 144 + break; \ 145 + default: \ 146 + BUILD_BUG(); \ 147 + } \ 148 + __ret; \ 149 + }) 150 + 151 + #define xchg(ptr, x) \ 152 + ({ \ 153 + __typeof__(*(ptr)) _x_ = (x); \ 154 + (__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \ 155 + }) 156 + 157 + #define xchg32(ptr, x) \ 158 + ({ \ 159 + BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 160 + xchg((ptr), (x)); \ 161 + }) 162 + 163 + #define xchg64(ptr, x) \ 164 + ({ \ 165 + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 166 + xchg((ptr), (x)); \ 59 167 }) 60 168 61 169 /* ··· 171 63 * store NEW in MEM. Return the initial value in MEM. Success is 172 64 * indicated by comparing RETURN with OLD. 173 65 */ 174 - #define __cmpxchg(ptr, old, new, size, lrb, scb) \ 66 + #define __cmpxchg_relaxed(ptr, old, new, size) \ 175 67 ({ \ 176 68 __typeof__(ptr) __ptr = (ptr); \ 177 69 __typeof__(*(ptr)) __old = (old); \ ··· 181 73 switch (size) { \ 182 74 case 4: \ 183 75 __asm__ __volatile__ ( \ 184 - "0:" \ 185 - "lr.w" #scb " %0, %2\n" \ 186 - "bne %0, %z3, 1f\n" \ 187 - "sc.w" #lrb " %1, %z4, %2\n" \ 188 - "bnez %1, 0b\n" \ 189 - "1:" \ 76 + "0: lr.w %0, %2\n" \ 77 + " bne %0, %z3, 1f\n" \ 78 + " sc.w %1, %z4, %2\n" \ 79 + " bnez %1, 0b\n" \ 80 + "1:\n" \ 190 81 : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 191 82 : "rJ" (__old), "rJ" (__new) \ 192 83 : "memory"); \ 193 84 break; \ 194 85 case 8: \ 195 86 __asm__ __volatile__ ( \ 196 - "0:" \ 197 - "lr.d" #scb " %0, %2\n" \ 198 - "bne %0, %z3, 1f\n" \ 199 - "sc.d" #lrb " %1, %z4, %2\n" \ 200 - "bnez %1, 0b\n" \ 201 - "1:" \ 87 + "0: lr.d %0, %2\n" \ 88 + " bne %0, %z3, 1f\n" \ 89 + " sc.d %1, %z4, %2\n" \ 90 + " bnez %1, 0b\n" \ 91 + "1:\n" \ 202 92 : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 203 93 : "rJ" (__old), "rJ" (__new) \ 204 94 : "memory"); \ ··· 207 101 __ret; \ 208 102 }) 209 103 210 - #define cmpxchg(ptr, o, n) \ 211 - (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), .aqrl, .aqrl)) 212 - 213 - #define cmpxchg_local(ptr, o, n) \ 214 - (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), , )) 215 - 216 - #define cmpxchg32(ptr, o, n) \ 217 - ({ \ 218 - BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 219 - cmpxchg((ptr), (o), (n)); \ 104 + #define cmpxchg_relaxed(ptr, o, n) \ 105 + ({ \ 106 + __typeof__(*(ptr)) _o_ = (o); \ 107 + __typeof__(*(ptr)) _n_ = (n); \ 108 + (__typeof__(*(ptr))) __cmpxchg_relaxed((ptr), \ 109 + _o_, _n_, sizeof(*(ptr))); \ 220 110 }) 221 111 222 - #define cmpxchg32_local(ptr, o, n) \ 223 - ({ \ 224 - BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 225 - cmpxchg_local((ptr), (o), (n)); \ 112 + #define __cmpxchg_acquire(ptr, old, new, size) \ 113 + ({ \ 114 + __typeof__(ptr) __ptr = (ptr); \ 115 + __typeof__(*(ptr)) __old = (old); \ 116 + __typeof__(*(ptr)) __new = (new); \ 117 + __typeof__(*(ptr)) __ret; \ 118 + register unsigned int __rc; \ 119 + switch (size) { \ 120 + case 4: \ 121 + __asm__ __volatile__ ( \ 122 + "0: lr.w %0, %2\n" \ 123 + " bne %0, %z3, 1f\n" \ 124 + " sc.w %1, %z4, %2\n" \ 125 + " bnez %1, 0b\n" \ 126 + RISCV_ACQUIRE_BARRIER \ 127 + "1:\n" \ 128 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 129 + : "rJ" (__old), "rJ" (__new) \ 130 + : "memory"); \ 131 + break; \ 132 + case 8: \ 133 + __asm__ __volatile__ ( \ 134 + "0: lr.d %0, %2\n" \ 135 + " bne %0, %z3, 1f\n" \ 136 + " sc.d %1, %z4, %2\n" \ 137 + " bnez %1, 0b\n" \ 138 + RISCV_ACQUIRE_BARRIER \ 139 + "1:\n" \ 140 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 141 + : "rJ" (__old), "rJ" (__new) \ 142 + : "memory"); \ 143 + break; \ 144 + default: \ 145 + BUILD_BUG(); \ 146 + } \ 147 + __ret; \ 226 148 }) 227 149 228 - #define cmpxchg64(ptr, o, n) \ 229 - ({ \ 230 - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 231 - cmpxchg((ptr), (o), (n)); \ 150 + #define cmpxchg_acquire(ptr, o, n) \ 151 + ({ \ 152 + __typeof__(*(ptr)) _o_ = (o); \ 153 + __typeof__(*(ptr)) _n_ = (n); \ 154 + (__typeof__(*(ptr))) __cmpxchg_acquire((ptr), \ 155 + _o_, _n_, sizeof(*(ptr))); \ 232 156 }) 233 157 234 - #define cmpxchg64_local(ptr, o, n) \ 235 - ({ \ 236 - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 237 - cmpxchg_local((ptr), (o), (n)); \ 158 + #define __cmpxchg_release(ptr, old, new, size) \ 159 + ({ \ 160 + __typeof__(ptr) __ptr = (ptr); \ 161 + __typeof__(*(ptr)) __old = (old); \ 162 + __typeof__(*(ptr)) __new = (new); \ 163 + __typeof__(*(ptr)) __ret; \ 164 + register unsigned int __rc; \ 165 + switch (size) { \ 166 + case 4: \ 167 + __asm__ __volatile__ ( \ 168 + RISCV_RELEASE_BARRIER \ 169 + "0: lr.w %0, %2\n" \ 170 + " bne %0, %z3, 1f\n" \ 171 + " sc.w %1, %z4, %2\n" \ 172 + " bnez %1, 0b\n" \ 173 + "1:\n" \ 174 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 175 + : "rJ" (__old), "rJ" (__new) \ 176 + : "memory"); \ 177 + break; \ 178 + case 8: \ 179 + __asm__ __volatile__ ( \ 180 + RISCV_RELEASE_BARRIER \ 181 + "0: lr.d %0, %2\n" \ 182 + " bne %0, %z3, 1f\n" \ 183 + " sc.d %1, %z4, %2\n" \ 184 + " bnez %1, 0b\n" \ 185 + "1:\n" \ 186 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 187 + : "rJ" (__old), "rJ" (__new) \ 188 + : "memory"); \ 189 + break; \ 190 + default: \ 191 + BUILD_BUG(); \ 192 + } \ 193 + __ret; \ 194 + }) 195 + 196 + #define cmpxchg_release(ptr, o, n) \ 197 + ({ \ 198 + __typeof__(*(ptr)) _o_ = (o); \ 199 + __typeof__(*(ptr)) _n_ = (n); \ 200 + (__typeof__(*(ptr))) __cmpxchg_release((ptr), \ 201 + _o_, _n_, sizeof(*(ptr))); \ 202 + }) 203 + 204 + #define __cmpxchg(ptr, old, new, size) \ 205 + ({ \ 206 + __typeof__(ptr) __ptr = (ptr); \ 207 + __typeof__(*(ptr)) __old = (old); \ 208 + __typeof__(*(ptr)) __new = (new); \ 209 + __typeof__(*(ptr)) __ret; \ 210 + register unsigned int __rc; \ 211 + switch (size) { \ 212 + case 4: \ 213 + __asm__ __volatile__ ( \ 214 + "0: lr.w %0, %2\n" \ 215 + " bne %0, %z3, 1f\n" \ 216 + " sc.w.rl %1, %z4, %2\n" \ 217 + " bnez %1, 0b\n" \ 218 + " fence rw, rw\n" \ 219 + "1:\n" \ 220 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 221 + : "rJ" (__old), "rJ" (__new) \ 222 + : "memory"); \ 223 + break; \ 224 + case 8: \ 225 + __asm__ __volatile__ ( \ 226 + "0: lr.d %0, %2\n" \ 227 + " bne %0, %z3, 1f\n" \ 228 + " sc.d.rl %1, %z4, %2\n" \ 229 + " bnez %1, 0b\n" \ 230 + " fence rw, rw\n" \ 231 + "1:\n" \ 232 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 233 + : "rJ" (__old), "rJ" (__new) \ 234 + : "memory"); \ 235 + break; \ 236 + default: \ 237 + BUILD_BUG(); \ 238 + } \ 239 + __ret; \ 240 + }) 241 + 242 + #define cmpxchg(ptr, o, n) \ 243 + ({ \ 244 + __typeof__(*(ptr)) _o_ = (o); \ 245 + __typeof__(*(ptr)) _n_ = (n); \ 246 + (__typeof__(*(ptr))) __cmpxchg((ptr), \ 247 + _o_, _n_, sizeof(*(ptr))); \ 248 + }) 249 + 250 + #define cmpxchg_local(ptr, o, n) \ 251 + (__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr)))) 252 + 253 + #define cmpxchg32(ptr, o, n) \ 254 + ({ \ 255 + BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 256 + cmpxchg((ptr), (o), (n)); \ 257 + }) 258 + 259 + #define cmpxchg32_local(ptr, o, n) \ 260 + ({ \ 261 + BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 262 + cmpxchg_relaxed((ptr), (o), (n)) \ 263 + }) 264 + 265 + #define cmpxchg64(ptr, o, n) \ 266 + ({ \ 267 + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 268 + cmpxchg((ptr), (o), (n)); \ 269 + }) 270 + 271 + #define cmpxchg64_local(ptr, o, n) \ 272 + ({ \ 273 + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 274 + cmpxchg_relaxed((ptr), (o), (n)); \ 238 275 }) 239 276 240 277 #endif /* _ASM_RISCV_CMPXCHG_H */