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

RISC-V: Atomic and Locking Code

This contains all the code that directly interfaces with the RISC-V
memory model. While this code corforms to the current RISC-V ISA
specifications (user 2.2 and priv 1.10), the memory model is somewhat
underspecified in those documents. There is a working group that hopes
to produce a formal memory model by the end of the year, but my
understanding is that the basic definitions we're relying on here won't
change significantly.

Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>

+1423
+375
arch/riscv/include/asm/atomic.h
··· 1 + /* 2 + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 3 + * Copyright (C) 2012 Regents of the University of California 4 + * Copyright (C) 2017 SiFive 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public Licence 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the Licence, or (at your option) any later version. 10 + */ 11 + 12 + #ifndef _ASM_RISCV_ATOMIC_H 13 + #define _ASM_RISCV_ATOMIC_H 14 + 15 + #ifdef CONFIG_GENERIC_ATOMIC64 16 + # include <asm-generic/atomic64.h> 17 + #else 18 + # if (__riscv_xlen < 64) 19 + # error "64-bit atomics require XLEN to be at least 64" 20 + # endif 21 + #endif 22 + 23 + #include <asm/cmpxchg.h> 24 + #include <asm/barrier.h> 25 + 26 + #define ATOMIC_INIT(i) { (i) } 27 + static __always_inline int atomic_read(const atomic_t *v) 28 + { 29 + return READ_ONCE(v->counter); 30 + } 31 + static __always_inline void atomic_set(atomic_t *v, int i) 32 + { 33 + WRITE_ONCE(v->counter, i); 34 + } 35 + 36 + #ifndef CONFIG_GENERIC_ATOMIC64 37 + #define ATOMIC64_INIT(i) { (i) } 38 + static __always_inline long atomic64_read(const atomic64_t *v) 39 + { 40 + return READ_ONCE(v->counter); 41 + } 42 + static __always_inline void atomic64_set(atomic64_t *v, long i) 43 + { 44 + WRITE_ONCE(v->counter, i); 45 + } 46 + #endif 47 + 48 + /* 49 + * First, the atomic ops that have no ordering constraints and therefor don't 50 + * have the AQ or RL bits set. These don't return anything, so there's only 51 + * one version to worry about. 52 + */ 53 + #define ATOMIC_OP(op, asm_op, c_op, I, asm_type, c_type, prefix) \ 54 + static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ 55 + { \ 56 + __asm__ __volatile__ ( \ 57 + "amo" #asm_op "." #asm_type " zero, %1, %0" \ 58 + : "+A" (v->counter) \ 59 + : "r" (I) \ 60 + : "memory"); \ 61 + } 62 + 63 + #ifdef CONFIG_GENERIC_ATOMIC64 64 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 65 + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) 66 + #else 67 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 68 + ATOMIC_OP (op, asm_op, c_op, I, w, int, ) \ 69 + ATOMIC_OP (op, asm_op, c_op, I, d, long, 64) 70 + #endif 71 + 72 + ATOMIC_OPS(add, add, +, i) 73 + ATOMIC_OPS(sub, add, +, -i) 74 + ATOMIC_OPS(and, and, &, i) 75 + ATOMIC_OPS( or, or, |, i) 76 + ATOMIC_OPS(xor, xor, ^, i) 77 + 78 + #undef ATOMIC_OP 79 + #undef ATOMIC_OPS 80 + 81 + /* 82 + * Atomic ops that have ordered, relaxed, acquire, and relese variants. 83 + * There's two flavors of these: the arithmatic ops have both fetch and return 84 + * versions, while the logical ops only have fetch versions. 85 + */ 86 + #define ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix) \ 87 + static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \ 88 + { \ 89 + register c_type ret; \ 90 + __asm__ __volatile__ ( \ 91 + "amo" #asm_op "." #asm_type #asm_or " %1, %2, %0" \ 92 + : "+A" (v->counter), "=r" (ret) \ 93 + : "r" (I) \ 94 + : "memory"); \ 95 + return ret; \ 96 + } 97 + 98 + #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix) \ 99 + static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, atomic##prefix##_t *v) \ 100 + { \ 101 + return atomic##prefix##_fetch_##op##c_or(i, v) c_op I; \ 102 + } 103 + 104 + #ifdef CONFIG_GENERIC_ATOMIC64 105 + #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ 106 + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ 107 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) 108 + #else 109 + #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ 110 + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ 111 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ 112 + ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, d, long, 64) \ 113 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) 114 + #endif 115 + 116 + ATOMIC_OPS(add, add, +, i, , _relaxed) 117 + ATOMIC_OPS(add, add, +, i, .aq , _acquire) 118 + ATOMIC_OPS(add, add, +, i, .rl , _release) 119 + ATOMIC_OPS(add, add, +, i, .aqrl, ) 120 + 121 + ATOMIC_OPS(sub, add, +, -i, , _relaxed) 122 + ATOMIC_OPS(sub, add, +, -i, .aq , _acquire) 123 + ATOMIC_OPS(sub, add, +, -i, .rl , _release) 124 + ATOMIC_OPS(sub, add, +, -i, .aqrl, ) 125 + 126 + #undef ATOMIC_OPS 127 + 128 + #ifdef CONFIG_GENERIC_ATOMIC64 129 + #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ 130 + ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w, int, ) 131 + #else 132 + #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ 133 + ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ 134 + ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) 135 + #endif 136 + 137 + ATOMIC_OPS(and, and, &, i, , _relaxed) 138 + ATOMIC_OPS(and, and, &, i, .aq , _acquire) 139 + ATOMIC_OPS(and, and, &, i, .rl , _release) 140 + ATOMIC_OPS(and, and, &, i, .aqrl, ) 141 + 142 + ATOMIC_OPS( or, or, |, i, , _relaxed) 143 + ATOMIC_OPS( or, or, |, i, .aq , _acquire) 144 + ATOMIC_OPS( or, or, |, i, .rl , _release) 145 + ATOMIC_OPS( or, or, |, i, .aqrl, ) 146 + 147 + ATOMIC_OPS(xor, xor, ^, i, , _relaxed) 148 + ATOMIC_OPS(xor, xor, ^, i, .aq , _acquire) 149 + ATOMIC_OPS(xor, xor, ^, i, .rl , _release) 150 + ATOMIC_OPS(xor, xor, ^, i, .aqrl, ) 151 + 152 + #undef ATOMIC_OPS 153 + 154 + #undef ATOMIC_FETCH_OP 155 + #undef ATOMIC_OP_RETURN 156 + 157 + /* 158 + * The extra atomic operations that are constructed from one of the core 159 + * AMO-based operations above (aside from sub, which is easier to fit above). 160 + * These are required to perform a barrier, but they're OK this way because 161 + * atomic_*_return is also required to perform a barrier. 162 + */ 163 + #define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \ 164 + static __always_inline bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ 165 + { \ 166 + return atomic##prefix##_##func_op##_return(i, v) comp_op I; \ 167 + } 168 + 169 + #ifdef CONFIG_GENERIC_ATOMIC64 170 + #define ATOMIC_OPS(op, func_op, comp_op, I) \ 171 + ATOMIC_OP (op, func_op, comp_op, I, int, ) 172 + #else 173 + #define ATOMIC_OPS(op, func_op, comp_op, I) \ 174 + ATOMIC_OP (op, func_op, comp_op, I, int, ) \ 175 + ATOMIC_OP (op, func_op, comp_op, I, long, 64) 176 + #endif 177 + 178 + ATOMIC_OPS(add_and_test, add, ==, 0) 179 + ATOMIC_OPS(sub_and_test, sub, ==, 0) 180 + ATOMIC_OPS(add_negative, add, <, 0) 181 + 182 + #undef ATOMIC_OP 183 + #undef ATOMIC_OPS 184 + 185 + #define ATOMIC_OP(op, func_op, c_op, I, c_type, prefix) \ 186 + static __always_inline void atomic##prefix##_##op(atomic##prefix##_t *v) \ 187 + { \ 188 + atomic##prefix##_##func_op(I, v); \ 189 + } 190 + 191 + #define ATOMIC_FETCH_OP(op, func_op, c_op, I, c_type, prefix) \ 192 + static __always_inline c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \ 193 + { \ 194 + return atomic##prefix##_fetch_##func_op(I, v); \ 195 + } 196 + 197 + #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, c_type, prefix) \ 198 + static __always_inline c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \ 199 + { \ 200 + return atomic##prefix##_fetch_##op(v) c_op I; \ 201 + } 202 + 203 + #ifdef CONFIG_GENERIC_ATOMIC64 204 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 205 + ATOMIC_OP (op, asm_op, c_op, I, int, ) \ 206 + ATOMIC_FETCH_OP (op, asm_op, c_op, I, int, ) \ 207 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) 208 + #else 209 + #define ATOMIC_OPS(op, asm_op, c_op, I) \ 210 + ATOMIC_OP (op, asm_op, c_op, I, int, ) \ 211 + ATOMIC_FETCH_OP (op, asm_op, c_op, I, int, ) \ 212 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \ 213 + ATOMIC_OP (op, asm_op, c_op, I, long, 64) \ 214 + ATOMIC_FETCH_OP (op, asm_op, c_op, I, long, 64) \ 215 + ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64) 216 + #endif 217 + 218 + ATOMIC_OPS(inc, add, +, 1) 219 + ATOMIC_OPS(dec, add, +, -1) 220 + 221 + #undef ATOMIC_OPS 222 + #undef ATOMIC_OP 223 + #undef ATOMIC_FETCH_OP 224 + #undef ATOMIC_OP_RETURN 225 + 226 + #define ATOMIC_OP(op, func_op, comp_op, I, prefix) \ 227 + static __always_inline bool atomic##prefix##_##op(atomic##prefix##_t *v) \ 228 + { \ 229 + return atomic##prefix##_##func_op##_return(v) comp_op I; \ 230 + } 231 + 232 + ATOMIC_OP(inc_and_test, inc, ==, 0, ) 233 + ATOMIC_OP(dec_and_test, dec, ==, 0, ) 234 + #ifndef CONFIG_GENERIC_ATOMIC64 235 + ATOMIC_OP(inc_and_test, inc, ==, 0, 64) 236 + ATOMIC_OP(dec_and_test, dec, ==, 0, 64) 237 + #endif 238 + 239 + #undef ATOMIC_OP 240 + 241 + /* This is required to provide a barrier on success. */ 242 + static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) 243 + { 244 + int prev, rc; 245 + 246 + __asm__ __volatile__ ( 247 + "0:\n\t" 248 + "lr.w.aqrl %[p], %[c]\n\t" 249 + "beq %[p], %[u], 1f\n\t" 250 + "add %[rc], %[p], %[a]\n\t" 251 + "sc.w.aqrl %[rc], %[rc], %[c]\n\t" 252 + "bnez %[rc], 0b\n\t" 253 + "1:" 254 + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 255 + : [a]"r" (a), [u]"r" (u) 256 + : "memory"); 257 + return prev; 258 + } 259 + 260 + #ifndef CONFIG_GENERIC_ATOMIC64 261 + static __always_inline long __atomic64_add_unless(atomic64_t *v, long a, long u) 262 + { 263 + long prev, rc; 264 + 265 + __asm__ __volatile__ ( 266 + "0:\n\t" 267 + "lr.d.aqrl %[p], %[c]\n\t" 268 + "beq %[p], %[u], 1f\n\t" 269 + "add %[rc], %[p], %[a]\n\t" 270 + "sc.d.aqrl %[rc], %[rc], %[c]\n\t" 271 + "bnez %[rc], 0b\n\t" 272 + "1:" 273 + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 274 + : [a]"r" (a), [u]"r" (u) 275 + : "memory"); 276 + return prev; 277 + } 278 + 279 + static __always_inline int atomic64_add_unless(atomic64_t *v, long a, long u) 280 + { 281 + return __atomic64_add_unless(v, a, u) != u; 282 + } 283 + #endif 284 + 285 + /* 286 + * The extra atomic operations that are constructed from one of the core 287 + * LR/SC-based operations above. 288 + */ 289 + static __always_inline int atomic_inc_not_zero(atomic_t *v) 290 + { 291 + return __atomic_add_unless(v, 1, 0); 292 + } 293 + 294 + #ifndef CONFIG_GENERIC_ATOMIC64 295 + static __always_inline long atomic64_inc_not_zero(atomic64_t *v) 296 + { 297 + return atomic64_add_unless(v, 1, 0); 298 + } 299 + #endif 300 + 301 + /* 302 + * atomic_{cmp,}xchg is required to have exactly the same ordering semantics as 303 + * {cmp,}xchg and the operations that return, so they need a barrier. We just 304 + * use the other implementations directly. 305 + */ 306 + #define ATOMIC_OP(c_t, prefix, c_or, size, asm_or) \ 307 + static __always_inline c_t atomic##prefix##_cmpxchg##c_or(atomic##prefix##_t *v, c_t o, c_t n) \ 308 + { \ 309 + return __cmpxchg(&(v->counter), o, n, size, asm_or, asm_or); \ 310 + } \ 311 + static __always_inline c_t atomic##prefix##_xchg##c_or(atomic##prefix##_t *v, c_t n) \ 312 + { \ 313 + return __xchg(n, &(v->counter), size, asm_or); \ 314 + } 315 + 316 + #ifdef CONFIG_GENERIC_ATOMIC64 317 + #define ATOMIC_OPS(c_or, asm_or) \ 318 + ATOMIC_OP( int, , c_or, 4, asm_or) 319 + #else 320 + #define ATOMIC_OPS(c_or, asm_or) \ 321 + ATOMIC_OP( int, , c_or, 4, asm_or) \ 322 + ATOMIC_OP(long, 64, c_or, 8, asm_or) 323 + #endif 324 + 325 + ATOMIC_OPS( , .aqrl) 326 + ATOMIC_OPS(_acquire, .aq) 327 + ATOMIC_OPS(_release, .rl) 328 + ATOMIC_OPS(_relaxed, ) 329 + 330 + #undef ATOMIC_OPS 331 + #undef ATOMIC_OP 332 + 333 + static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset) 334 + { 335 + int prev, rc; 336 + 337 + __asm__ __volatile__ ( 338 + "0:\n\t" 339 + "lr.w.aqrl %[p], %[c]\n\t" 340 + "sub %[rc], %[p], %[o]\n\t" 341 + "bltz %[rc], 1f\n\t" 342 + "sc.w.aqrl %[rc], %[rc], %[c]\n\t" 343 + "bnez %[rc], 0b\n\t" 344 + "1:" 345 + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 346 + : [o]"r" (offset) 347 + : "memory"); 348 + return prev - offset; 349 + } 350 + 351 + #define atomic_dec_if_positive(v) atomic_sub_if_positive(v, 1) 352 + 353 + #ifndef CONFIG_GENERIC_ATOMIC64 354 + static __always_inline long atomic64_sub_if_positive(atomic64_t *v, int offset) 355 + { 356 + long prev, rc; 357 + 358 + __asm__ __volatile__ ( 359 + "0:\n\t" 360 + "lr.d.aqrl %[p], %[c]\n\t" 361 + "sub %[rc], %[p], %[o]\n\t" 362 + "bltz %[rc], 1f\n\t" 363 + "sc.d.aqrl %[rc], %[rc], %[c]\n\t" 364 + "bnez %[rc], 0b\n\t" 365 + "1:" 366 + : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) 367 + : [o]"r" (offset) 368 + : "memory"); 369 + return prev - offset; 370 + } 371 + 372 + #define atomic64_dec_if_positive(v) atomic64_sub_if_positive(v, 1) 373 + #endif 374 + 375 + #endif /* _ASM_RISCV_ATOMIC_H */
+68
arch/riscv/include/asm/barrier.h
··· 1 + /* 2 + * Based on arch/arm/include/asm/barrier.h 3 + * 4 + * Copyright (C) 2012 ARM Ltd. 5 + * Copyright (C) 2013 Regents of the University of California 6 + * Copyright (C) 2017 SiFive 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License 18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 + */ 20 + 21 + #ifndef _ASM_RISCV_BARRIER_H 22 + #define _ASM_RISCV_BARRIER_H 23 + 24 + #ifndef __ASSEMBLY__ 25 + 26 + #define nop() __asm__ __volatile__ ("nop") 27 + 28 + #define RISCV_FENCE(p, s) \ 29 + __asm__ __volatile__ ("fence " #p "," #s : : : "memory") 30 + 31 + /* These barriers need to enforce ordering on both devices or memory. */ 32 + #define mb() RISCV_FENCE(iorw,iorw) 33 + #define rmb() RISCV_FENCE(ir,ir) 34 + #define wmb() RISCV_FENCE(ow,ow) 35 + 36 + /* These barriers do not need to enforce ordering on devices, just memory. */ 37 + #define smp_mb() RISCV_FENCE(rw,rw) 38 + #define smp_rmb() RISCV_FENCE(r,r) 39 + #define smp_wmb() RISCV_FENCE(w,w) 40 + 41 + /* 42 + * These fences exist to enforce ordering around the relaxed AMOs. The 43 + * documentation defines that 44 + * " 45 + * atomic_fetch_add(); 46 + * is equivalent to: 47 + * smp_mb__before_atomic(); 48 + * atomic_fetch_add_relaxed(); 49 + * smp_mb__after_atomic(); 50 + * " 51 + * So we emit full fences on both sides. 52 + */ 53 + #define __smb_mb__before_atomic() smp_mb() 54 + #define __smb_mb__after_atomic() smp_mb() 55 + 56 + /* 57 + * These barriers prevent accesses performed outside a spinlock from being moved 58 + * inside a spinlock. Since RISC-V sets the aq/rl bits on our spinlock only 59 + * enforce release consistency, we need full fences here. 60 + */ 61 + #define smb_mb__before_spinlock() smp_mb() 62 + #define smb_mb__after_spinlock() smp_mb() 63 + 64 + #include <asm-generic/barrier.h> 65 + 66 + #endif /* __ASSEMBLY__ */ 67 + 68 + #endif /* _ASM_RISCV_BARRIER_H */
+218
arch/riscv/include/asm/bitops.h
··· 1 + /* 2 + * Copyright (C) 2012 Regents of the University of California 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation, version 2. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef _ASM_RISCV_BITOPS_H 15 + #define _ASM_RISCV_BITOPS_H 16 + 17 + #ifndef _LINUX_BITOPS_H 18 + #error "Only <linux/bitops.h> can be included directly" 19 + #endif /* _LINUX_BITOPS_H */ 20 + 21 + #include <linux/compiler.h> 22 + #include <linux/irqflags.h> 23 + #include <asm/barrier.h> 24 + #include <asm/bitsperlong.h> 25 + 26 + #ifndef smp_mb__before_clear_bit 27 + #define smp_mb__before_clear_bit() smp_mb() 28 + #define smp_mb__after_clear_bit() smp_mb() 29 + #endif /* smp_mb__before_clear_bit */ 30 + 31 + #include <asm-generic/bitops/__ffs.h> 32 + #include <asm-generic/bitops/ffz.h> 33 + #include <asm-generic/bitops/fls.h> 34 + #include <asm-generic/bitops/__fls.h> 35 + #include <asm-generic/bitops/fls64.h> 36 + #include <asm-generic/bitops/find.h> 37 + #include <asm-generic/bitops/sched.h> 38 + #include <asm-generic/bitops/ffs.h> 39 + 40 + #include <asm-generic/bitops/hweight.h> 41 + 42 + #if (BITS_PER_LONG == 64) 43 + #define __AMO(op) "amo" #op ".d" 44 + #elif (BITS_PER_LONG == 32) 45 + #define __AMO(op) "amo" #op ".w" 46 + #else 47 + #error "Unexpected BITS_PER_LONG" 48 + #endif 49 + 50 + #define __test_and_op_bit_ord(op, mod, nr, addr, ord) \ 51 + ({ \ 52 + unsigned long __res, __mask; \ 53 + __mask = BIT_MASK(nr); \ 54 + __asm__ __volatile__ ( \ 55 + __AMO(op) #ord " %0, %2, %1" \ 56 + : "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \ 57 + : "r" (mod(__mask)) \ 58 + : "memory"); \ 59 + ((__res & __mask) != 0); \ 60 + }) 61 + 62 + #define __op_bit_ord(op, mod, nr, addr, ord) \ 63 + __asm__ __volatile__ ( \ 64 + __AMO(op) #ord " zero, %1, %0" \ 65 + : "+A" (addr[BIT_WORD(nr)]) \ 66 + : "r" (mod(BIT_MASK(nr))) \ 67 + : "memory"); 68 + 69 + #define __test_and_op_bit(op, mod, nr, addr) \ 70 + __test_and_op_bit_ord(op, mod, nr, addr, ) 71 + #define __op_bit(op, mod, nr, addr) \ 72 + __op_bit_ord(op, mod, nr, addr, ) 73 + 74 + /* Bitmask modifiers */ 75 + #define __NOP(x) (x) 76 + #define __NOT(x) (~(x)) 77 + 78 + /** 79 + * test_and_set_bit - Set a bit and return its old value 80 + * @nr: Bit to set 81 + * @addr: Address to count from 82 + * 83 + * This operation may be reordered on other architectures than x86. 84 + */ 85 + static inline int test_and_set_bit(int nr, volatile unsigned long *addr) 86 + { 87 + return __test_and_op_bit(or, __NOP, nr, addr); 88 + } 89 + 90 + /** 91 + * test_and_clear_bit - Clear a bit and return its old value 92 + * @nr: Bit to clear 93 + * @addr: Address to count from 94 + * 95 + * This operation can be reordered on other architectures other than x86. 96 + */ 97 + static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) 98 + { 99 + return __test_and_op_bit(and, __NOT, nr, addr); 100 + } 101 + 102 + /** 103 + * test_and_change_bit - Change a bit and return its old value 104 + * @nr: Bit to change 105 + * @addr: Address to count from 106 + * 107 + * This operation is atomic and cannot be reordered. 108 + * It also implies a memory barrier. 109 + */ 110 + static inline int test_and_change_bit(int nr, volatile unsigned long *addr) 111 + { 112 + return __test_and_op_bit(xor, __NOP, nr, addr); 113 + } 114 + 115 + /** 116 + * set_bit - Atomically set a bit in memory 117 + * @nr: the bit to set 118 + * @addr: the address to start counting from 119 + * 120 + * Note: there are no guarantees that this function will not be reordered 121 + * on non x86 architectures, so if you are writing portable code, 122 + * make sure not to rely on its reordering guarantees. 123 + * 124 + * Note that @nr may be almost arbitrarily large; this function is not 125 + * restricted to acting on a single-word quantity. 126 + */ 127 + static inline void set_bit(int nr, volatile unsigned long *addr) 128 + { 129 + __op_bit(or, __NOP, nr, addr); 130 + } 131 + 132 + /** 133 + * clear_bit - Clears a bit in memory 134 + * @nr: Bit to clear 135 + * @addr: Address to start counting from 136 + * 137 + * Note: there are no guarantees that this function will not be reordered 138 + * on non x86 architectures, so if you are writing portable code, 139 + * make sure not to rely on its reordering guarantees. 140 + */ 141 + static inline void clear_bit(int nr, volatile unsigned long *addr) 142 + { 143 + __op_bit(and, __NOT, nr, addr); 144 + } 145 + 146 + /** 147 + * change_bit - Toggle a bit in memory 148 + * @nr: Bit to change 149 + * @addr: Address to start counting from 150 + * 151 + * change_bit() may be reordered on other architectures than x86. 152 + * Note that @nr may be almost arbitrarily large; this function is not 153 + * restricted to acting on a single-word quantity. 154 + */ 155 + static inline void change_bit(int nr, volatile unsigned long *addr) 156 + { 157 + __op_bit(xor, __NOP, nr, addr); 158 + } 159 + 160 + /** 161 + * test_and_set_bit_lock - Set a bit and return its old value, for lock 162 + * @nr: Bit to set 163 + * @addr: Address to count from 164 + * 165 + * This operation is atomic and provides acquire barrier semantics. 166 + * It can be used to implement bit locks. 167 + */ 168 + static inline int test_and_set_bit_lock( 169 + unsigned long nr, volatile unsigned long *addr) 170 + { 171 + return __test_and_op_bit_ord(or, __NOP, nr, addr, .aq); 172 + } 173 + 174 + /** 175 + * clear_bit_unlock - Clear a bit in memory, for unlock 176 + * @nr: the bit to set 177 + * @addr: the address to start counting from 178 + * 179 + * This operation is atomic and provides release barrier semantics. 180 + */ 181 + static inline void clear_bit_unlock( 182 + unsigned long nr, volatile unsigned long *addr) 183 + { 184 + __op_bit_ord(and, __NOT, nr, addr, .rl); 185 + } 186 + 187 + /** 188 + * __clear_bit_unlock - Clear a bit in memory, for unlock 189 + * @nr: the bit to set 190 + * @addr: the address to start counting from 191 + * 192 + * This operation is like clear_bit_unlock, however it is not atomic. 193 + * It does provide release barrier semantics so it can be used to unlock 194 + * a bit lock, however it would only be used if no other CPU can modify 195 + * any bits in the memory until the lock is released (a good example is 196 + * if the bit lock itself protects access to the other bits in the word). 197 + * 198 + * On RISC-V systems there seems to be no benefit to taking advantage of the 199 + * non-atomic property here: it's a lot more instructions and we still have to 200 + * provide release semantics anyway. 201 + */ 202 + static inline void __clear_bit_unlock( 203 + unsigned long nr, volatile unsigned long *addr) 204 + { 205 + clear_bit_unlock(nr, addr); 206 + } 207 + 208 + #undef __test_and_op_bit 209 + #undef __op_bit 210 + #undef __NOP 211 + #undef __NOT 212 + #undef __AMO 213 + 214 + #include <asm-generic/bitops/non-atomic.h> 215 + #include <asm-generic/bitops/le.h> 216 + #include <asm-generic/bitops/ext2-atomic.h> 217 + 218 + #endif /* _ASM_RISCV_BITOPS_H */
+39
arch/riscv/include/asm/cacheflush.h
··· 1 + /* 2 + * Copyright (C) 2015 Regents of the University of California 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation, version 2. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef _ASM_RISCV_CACHEFLUSH_H 15 + #define _ASM_RISCV_CACHEFLUSH_H 16 + 17 + #include <asm-generic/cacheflush.h> 18 + 19 + #undef flush_icache_range 20 + #undef flush_icache_user_range 21 + 22 + static inline void local_flush_icache_all(void) 23 + { 24 + asm volatile ("fence.i" ::: "memory"); 25 + } 26 + 27 + #ifndef CONFIG_SMP 28 + 29 + #define flush_icache_range(start, end) local_flush_icache_all() 30 + #define flush_icache_user_range(vma, pg, addr, len) local_flush_icache_all() 31 + 32 + #else /* CONFIG_SMP */ 33 + 34 + #define flush_icache_range(start, end) sbi_remote_fence_i(0) 35 + #define flush_icache_user_range(vma, pg, addr, len) sbi_remote_fence_i(0) 36 + 37 + #endif /* CONFIG_SMP */ 38 + 39 + #endif /* _ASM_RISCV_CACHEFLUSH_H */
+134
arch/riscv/include/asm/cmpxchg.h
··· 1 + /* 2 + * Copyright (C) 2014 Regents of the University of California 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation, version 2. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef _ASM_RISCV_CMPXCHG_H 15 + #define _ASM_RISCV_CMPXCHG_H 16 + 17 + #include <linux/bug.h> 18 + 19 + #include <asm/barrier.h> 20 + 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; \ 45 + }) 46 + 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)); \ 53 + }) 54 + 55 + #define xchg64(ptr, x) \ 56 + ({ \ 57 + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 58 + xchg((ptr), (x)); \ 59 + }) 60 + 61 + /* 62 + * Atomic compare and exchange. Compare OLD with MEM, if identical, 63 + * store NEW in MEM. Return the initial value in MEM. Success is 64 + * indicated by comparing RETURN with OLD. 65 + */ 66 + #define __cmpxchg(ptr, old, new, size, lrb, scb) \ 67 + ({ \ 68 + __typeof__(ptr) __ptr = (ptr); \ 69 + __typeof__(*(ptr)) __old = (old); \ 70 + __typeof__(*(ptr)) __new = (new); \ 71 + __typeof__(*(ptr)) __ret; \ 72 + register unsigned int __rc; \ 73 + switch (size) { \ 74 + case 4: \ 75 + __asm__ __volatile__ ( \ 76 + "0:" \ 77 + "lr.w" #scb " %0, %2\n" \ 78 + "bne %0, %z3, 1f\n" \ 79 + "sc.w" #lrb " %1, %z4, %2\n" \ 80 + "bnez %1, 0b\n" \ 81 + "1:" \ 82 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 83 + : "rJ" (__old), "rJ" (__new) \ 84 + : "memory"); \ 85 + break; \ 86 + case 8: \ 87 + __asm__ __volatile__ ( \ 88 + "0:" \ 89 + "lr.d" #scb " %0, %2\n" \ 90 + "bne %0, %z3, 1f\n" \ 91 + "sc.d" #lrb " %1, %z4, %2\n" \ 92 + "bnez %1, 0b\n" \ 93 + "1:" \ 94 + : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ 95 + : "rJ" (__old), "rJ" (__new) \ 96 + : "memory"); \ 97 + break; \ 98 + default: \ 99 + BUILD_BUG(); \ 100 + } \ 101 + __ret; \ 102 + }) 103 + 104 + #define cmpxchg(ptr, o, n) \ 105 + (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), .aqrl, .aqrl)) 106 + 107 + #define cmpxchg_local(ptr, o, n) \ 108 + (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), , )) 109 + 110 + #define cmpxchg32(ptr, o, n) \ 111 + ({ \ 112 + BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 113 + cmpxchg((ptr), (o), (n)); \ 114 + }) 115 + 116 + #define cmpxchg32_local(ptr, o, n) \ 117 + ({ \ 118 + BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ 119 + cmpxchg_local((ptr), (o), (n)); \ 120 + }) 121 + 122 + #define cmpxchg64(ptr, o, n) \ 123 + ({ \ 124 + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 125 + cmpxchg((ptr), (o), (n)); \ 126 + }) 127 + 128 + #define cmpxchg64_local(ptr, o, n) \ 129 + ({ \ 130 + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 131 + cmpxchg_local((ptr), (o), (n)); \ 132 + }) 133 + 134 + #endif /* _ASM_RISCV_CMPXCHG_H */
+303
arch/riscv/include/asm/io.h
··· 1 + /* 2 + * {read,write}{b,w,l,q} based on arch/arm64/include/asm/io.h 3 + * which was based on arch/arm/include/io.h 4 + * 5 + * Copyright (C) 1996-2000 Russell King 6 + * Copyright (C) 2012 ARM Ltd. 7 + * Copyright (C) 2014 Regents of the University of California 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License 11 + * as published by the Free Software Foundation, version 2. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + */ 18 + 19 + #ifndef _ASM_RISCV_IO_H 20 + #define _ASM_RISCV_IO_H 21 + 22 + #ifdef CONFIG_MMU 23 + 24 + extern void __iomem *ioremap(phys_addr_t offset, unsigned long size); 25 + 26 + /* 27 + * The RISC-V ISA doesn't yet specify how to query or modify PMAs, so we can't 28 + * change the properties of memory regions. This should be fixed by the 29 + * upcoming platform spec. 30 + */ 31 + #define ioremap_nocache(addr, size) ioremap((addr), (size)) 32 + #define ioremap_wc(addr, size) ioremap((addr), (size)) 33 + #define ioremap_wt(addr, size) ioremap((addr), (size)) 34 + 35 + extern void iounmap(void __iomem *addr); 36 + 37 + #endif /* CONFIG_MMU */ 38 + 39 + /* Generic IO read/write. These perform native-endian accesses. */ 40 + #define __raw_writeb __raw_writeb 41 + static inline void __raw_writeb(u8 val, volatile void __iomem *addr) 42 + { 43 + asm volatile("sb %0, 0(%1)" : : "r" (val), "r" (addr)); 44 + } 45 + 46 + #define __raw_writew __raw_writew 47 + static inline void __raw_writew(u16 val, volatile void __iomem *addr) 48 + { 49 + asm volatile("sh %0, 0(%1)" : : "r" (val), "r" (addr)); 50 + } 51 + 52 + #define __raw_writel __raw_writel 53 + static inline void __raw_writel(u32 val, volatile void __iomem *addr) 54 + { 55 + asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr)); 56 + } 57 + 58 + #ifdef CONFIG_64BIT 59 + #define __raw_writeq __raw_writeq 60 + static inline void __raw_writeq(u64 val, volatile void __iomem *addr) 61 + { 62 + asm volatile("sd %0, 0(%1)" : : "r" (val), "r" (addr)); 63 + } 64 + #endif 65 + 66 + #define __raw_readb __raw_readb 67 + static inline u8 __raw_readb(const volatile void __iomem *addr) 68 + { 69 + u8 val; 70 + 71 + asm volatile("lb %0, 0(%1)" : "=r" (val) : "r" (addr)); 72 + return val; 73 + } 74 + 75 + #define __raw_readw __raw_readw 76 + static inline u16 __raw_readw(const volatile void __iomem *addr) 77 + { 78 + u16 val; 79 + 80 + asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr)); 81 + return val; 82 + } 83 + 84 + #define __raw_readl __raw_readl 85 + static inline u32 __raw_readl(const volatile void __iomem *addr) 86 + { 87 + u32 val; 88 + 89 + asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr)); 90 + return val; 91 + } 92 + 93 + #ifdef CONFIG_64BIT 94 + #define __raw_readq __raw_readq 95 + static inline u64 __raw_readq(const volatile void __iomem *addr) 96 + { 97 + u64 val; 98 + 99 + asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr)); 100 + return val; 101 + } 102 + #endif 103 + 104 + /* 105 + * FIXME: I'm flip-flopping on whether or not we should keep this or enforce 106 + * the ordering with I/O on spinlocks like PowerPC does. The worry is that 107 + * drivers won't get this correct, but I also don't want to introduce a fence 108 + * into the lock code that otherwise only uses AMOs (and is essentially defined 109 + * by the ISA to be correct). For now I'm leaving this here: "o,w" is 110 + * sufficient to ensure that all writes to the device have completed before the 111 + * write to the spinlock is allowed to commit. I surmised this from reading 112 + * "ACQUIRES VS I/O ACCESSES" in memory-barriers.txt. 113 + */ 114 + #define mmiowb() __asm__ __volatile__ ("fence o,w" : : : "memory"); 115 + 116 + /* 117 + * Unordered I/O memory access primitives. These are even more relaxed than 118 + * the relaxed versions, as they don't even order accesses between successive 119 + * operations to the I/O regions. 120 + */ 121 + #define readb_cpu(c) ({ u8 __r = __raw_readb(c); __r; }) 122 + #define readw_cpu(c) ({ u16 __r = le16_to_cpu((__force __le16)__raw_readw(c)); __r; }) 123 + #define readl_cpu(c) ({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; }) 124 + 125 + #define writeb_cpu(v,c) ((void)__raw_writeb((v),(c))) 126 + #define writew_cpu(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c))) 127 + #define writel_cpu(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c))) 128 + 129 + #ifdef CONFIG_64BIT 130 + #define readq_cpu(c) ({ u64 __r = le64_to_cpu((__force __le64)__raw_readq(c)); __r; }) 131 + #define writeq_cpu(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c))) 132 + #endif 133 + 134 + /* 135 + * Relaxed I/O memory access primitives. These follow the Device memory 136 + * ordering rules but do not guarantee any ordering relative to Normal memory 137 + * accesses. These are defined to order the indicated access (either a read or 138 + * write) with all other I/O memory accesses. Since the platform specification 139 + * defines that all I/O regions are strongly ordered on channel 2, no explicit 140 + * fences are required to enforce this ordering. 141 + */ 142 + /* FIXME: These are now the same as asm-generic */ 143 + #define __io_rbr() do {} while (0) 144 + #define __io_rar() do {} while (0) 145 + #define __io_rbw() do {} while (0) 146 + #define __io_raw() do {} while (0) 147 + 148 + #define readb_relaxed(c) ({ u8 __v; __io_rbr(); __v = readb_cpu(c); __io_rar(); __v; }) 149 + #define readw_relaxed(c) ({ u16 __v; __io_rbr(); __v = readw_cpu(c); __io_rar(); __v; }) 150 + #define readl_relaxed(c) ({ u32 __v; __io_rbr(); __v = readl_cpu(c); __io_rar(); __v; }) 151 + 152 + #define writeb_relaxed(v,c) ({ __io_rbw(); writeb_cpu((v),(c)); __io_raw(); }) 153 + #define writew_relaxed(v,c) ({ __io_rbw(); writew_cpu((v),(c)); __io_raw(); }) 154 + #define writel_relaxed(v,c) ({ __io_rbw(); writel_cpu((v),(c)); __io_raw(); }) 155 + 156 + #ifdef CONFIG_64BIT 157 + #define readq_relaxed(c) ({ u64 __v; __io_rbr(); __v = readq_cpu(c); __io_rar(); __v; }) 158 + #define writeq_relaxed(v,c) ({ __io_rbw(); writeq_cpu((v),(c)); __io_raw(); }) 159 + #endif 160 + 161 + /* 162 + * I/O memory access primitives. Reads are ordered relative to any 163 + * following Normal memory access. Writes are ordered relative to any prior 164 + * Normal memory access. The memory barriers here are necessary as RISC-V 165 + * doesn't define any ordering between the memory space and the I/O space. 166 + */ 167 + #define __io_br() do {} while (0) 168 + #define __io_ar() __asm__ __volatile__ ("fence i,r" : : : "memory"); 169 + #define __io_bw() __asm__ __volatile__ ("fence w,o" : : : "memory"); 170 + #define __io_aw() do {} while (0) 171 + 172 + #define readb(c) ({ u8 __v; __io_br(); __v = readb_cpu(c); __io_ar(); __v; }) 173 + #define readw(c) ({ u16 __v; __io_br(); __v = readw_cpu(c); __io_ar(); __v; }) 174 + #define readl(c) ({ u32 __v; __io_br(); __v = readl_cpu(c); __io_ar(); __v; }) 175 + 176 + #define writeb(v,c) ({ __io_bw(); writeb_cpu((v),(c)); __io_aw(); }) 177 + #define writew(v,c) ({ __io_bw(); writew_cpu((v),(c)); __io_aw(); }) 178 + #define writel(v,c) ({ __io_bw(); writel_cpu((v),(c)); __io_aw(); }) 179 + 180 + #ifdef CONFIG_64BIT 181 + #define readq(c) ({ u64 __v; __io_br(); __v = readq_cpu(c); __io_ar(); __v; }) 182 + #define writeq(v,c) ({ __io_bw(); writeq_cpu((v),(c)); __io_aw(); }) 183 + #endif 184 + 185 + /* 186 + * Emulation routines for the port-mapped IO space used by some PCI drivers. 187 + * These are defined as being "fully synchronous", but also "not guaranteed to 188 + * be fully ordered with respect to other memory and I/O operations". We're 189 + * going to be on the safe side here and just make them: 190 + * - Fully ordered WRT each other, by bracketing them with two fences. The 191 + * outer set contains both I/O so inX is ordered with outX, while the inner just 192 + * needs the type of the access (I for inX and O for outX). 193 + * - Ordered in the same manner as readX/writeX WRT memory by subsuming their 194 + * fences. 195 + * - Ordered WRT timer reads, so udelay and friends don't get elided by the 196 + * implementation. 197 + * Note that there is no way to actually enforce that outX is a non-posted 198 + * operation on RISC-V, but hopefully the timer ordering constraint is 199 + * sufficient to ensure this works sanely on controllers that support I/O 200 + * writes. 201 + */ 202 + #define __io_pbr() __asm__ __volatile__ ("fence io,i" : : : "memory"); 203 + #define __io_par() __asm__ __volatile__ ("fence i,ior" : : : "memory"); 204 + #define __io_pbw() __asm__ __volatile__ ("fence iow,o" : : : "memory"); 205 + #define __io_paw() __asm__ __volatile__ ("fence o,io" : : : "memory"); 206 + 207 + #define inb(c) ({ u8 __v; __io_pbr(); __v = readb_cpu((void*)(PCI_IOBASE + (c))); __io_par(); __v; }) 208 + #define inw(c) ({ u16 __v; __io_pbr(); __v = readw_cpu((void*)(PCI_IOBASE + (c))); __io_par(); __v; }) 209 + #define inl(c) ({ u32 __v; __io_pbr(); __v = readl_cpu((void*)(PCI_IOBASE + (c))); __io_par(); __v; }) 210 + 211 + #define outb(v,c) ({ __io_pbw(); writeb_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) 212 + #define outw(v,c) ({ __io_pbw(); writew_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) 213 + #define outl(v,c) ({ __io_pbw(); writel_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) 214 + 215 + #ifdef CONFIG_64BIT 216 + #define inq(c) ({ u64 __v; __io_pbr(); __v = readq_cpu((void*)(c)); __io_par(); __v; }) 217 + #define outq(v,c) ({ __io_pbw(); writeq_cpu((v),(void*)(c)); __io_paw(); }) 218 + #endif 219 + 220 + /* 221 + * Accesses from a single hart to a single I/O address must be ordered. This 222 + * allows us to use the raw read macros, but we still need to fence before and 223 + * after the block to ensure ordering WRT other macros. These are defined to 224 + * perform host-endian accesses so we use __raw instead of __cpu. 225 + */ 226 + #define __io_reads_ins(port, ctype, len, bfence, afence) \ 227 + static inline void __ ## port ## len(const volatile void __iomem *addr, \ 228 + void *buffer, \ 229 + unsigned int count) \ 230 + { \ 231 + bfence; \ 232 + if (count) { \ 233 + ctype *buf = buffer; \ 234 + \ 235 + do { \ 236 + ctype x = __raw_read ## len(addr); \ 237 + *buf++ = x; \ 238 + } while (--count); \ 239 + } \ 240 + afence; \ 241 + } 242 + 243 + #define __io_writes_outs(port, ctype, len, bfence, afence) \ 244 + static inline void __ ## port ## len(volatile void __iomem *addr, \ 245 + const void *buffer, \ 246 + unsigned int count) \ 247 + { \ 248 + bfence; \ 249 + if (count) { \ 250 + const ctype *buf = buffer; \ 251 + \ 252 + do { \ 253 + __raw_writeq(*buf++, addr); \ 254 + } while (--count); \ 255 + } \ 256 + afence; \ 257 + } 258 + 259 + __io_reads_ins(reads, u8, b, __io_br(), __io_ar()) 260 + __io_reads_ins(reads, u16, w, __io_br(), __io_ar()) 261 + __io_reads_ins(reads, u32, l, __io_br(), __io_ar()) 262 + #define readsb(addr, buffer, count) __readsb(addr, buffer, count) 263 + #define readsw(addr, buffer, count) __readsw(addr, buffer, count) 264 + #define readsl(addr, buffer, count) __readsl(addr, buffer, count) 265 + 266 + __io_reads_ins(ins, u8, b, __io_pbr(), __io_par()) 267 + __io_reads_ins(ins, u16, w, __io_pbr(), __io_par()) 268 + __io_reads_ins(ins, u32, l, __io_pbr(), __io_par()) 269 + #define insb(addr, buffer, count) __insb((void __iomem *)addr, buffer, count) 270 + #define insw(addr, buffer, count) __insw((void __iomem *)addr, buffer, count) 271 + #define insl(addr, buffer, count) __insl((void __iomem *)addr, buffer, count) 272 + 273 + __io_writes_outs(writes, u8, b, __io_bw(), __io_aw()) 274 + __io_writes_outs(writes, u16, w, __io_bw(), __io_aw()) 275 + __io_writes_outs(writes, u32, l, __io_bw(), __io_aw()) 276 + #define writesb(addr, buffer, count) __writesb(addr, buffer, count) 277 + #define writesw(addr, buffer, count) __writesw(addr, buffer, count) 278 + #define writesl(addr, buffer, count) __writesl(addr, buffer, count) 279 + 280 + __io_writes_outs(outs, u8, b, __io_pbw(), __io_paw()) 281 + __io_writes_outs(outs, u16, w, __io_pbw(), __io_paw()) 282 + __io_writes_outs(outs, u32, l, __io_pbw(), __io_paw()) 283 + #define outsb(addr, buffer, count) __outsb((void __iomem *)addr, buffer, count) 284 + #define outsw(addr, buffer, count) __outsw((void __iomem *)addr, buffer, count) 285 + #define outsl(addr, buffer, count) __outsl((void __iomem *)addr, buffer, count) 286 + 287 + #ifdef CONFIG_64BIT 288 + __io_reads_ins(reads, u64, q, __io_br(), __io_ar()) 289 + #define readsq(addr, buffer, count) __readsq(addr, buffer, count) 290 + 291 + __io_reads_ins(ins, u64, q, __io_pbr(), __io_par()) 292 + #define insq(addr, buffer, count) __insq((void __iomem *)addr, buffer, count) 293 + 294 + __io_writes_outs(writes, u64, q, __io_bw(), __io_aw()) 295 + #define writesq(addr, buffer, count) __writesq(addr, buffer, count) 296 + 297 + __io_writes_outs(outs, u64, q, __io_pbr(), __io_paw()) 298 + #define outsq(addr, buffer, count) __outsq((void __iomem *)addr, buffer, count) 299 + #endif 300 + 301 + #include <asm-generic/io.h> 302 + 303 + #endif /* _ASM_RISCV_IO_H */
+165
arch/riscv/include/asm/spinlock.h
··· 1 + /* 2 + * Copyright (C) 2015 Regents of the University of California 3 + * Copyright (C) 2017 SiFive 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify it under the terms of the GNU General Public License 7 + * as published by the Free Software Foundation, version 2. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #ifndef _ASM_RISCV_SPINLOCK_H 16 + #define _ASM_RISCV_SPINLOCK_H 17 + 18 + #include <linux/kernel.h> 19 + #include <asm/current.h> 20 + 21 + /* 22 + * Simple spin lock operations. These provide no fairness guarantees. 23 + */ 24 + 25 + /* FIXME: Replace this with a ticket lock, like MIPS. */ 26 + 27 + #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) 28 + #define arch_spin_is_locked(x) ((x)->lock != 0) 29 + 30 + static inline void arch_spin_unlock(arch_spinlock_t *lock) 31 + { 32 + __asm__ __volatile__ ( 33 + "amoswap.w.rl x0, x0, %0" 34 + : "=A" (lock->lock) 35 + :: "memory"); 36 + } 37 + 38 + static inline int arch_spin_trylock(arch_spinlock_t *lock) 39 + { 40 + int tmp = 1, busy; 41 + 42 + __asm__ __volatile__ ( 43 + "amoswap.w.aq %0, %2, %1" 44 + : "=r" (busy), "+A" (lock->lock) 45 + : "r" (tmp) 46 + : "memory"); 47 + 48 + return !busy; 49 + } 50 + 51 + static inline void arch_spin_lock(arch_spinlock_t *lock) 52 + { 53 + while (1) { 54 + if (arch_spin_is_locked(lock)) 55 + continue; 56 + 57 + if (arch_spin_trylock(lock)) 58 + break; 59 + } 60 + } 61 + 62 + static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) 63 + { 64 + smp_rmb(); 65 + do { 66 + cpu_relax(); 67 + } while (arch_spin_is_locked(lock)); 68 + smp_acquire__after_ctrl_dep(); 69 + } 70 + 71 + /***********************************************************/ 72 + 73 + static inline int arch_read_can_lock(arch_rwlock_t *lock) 74 + { 75 + return lock->lock >= 0; 76 + } 77 + 78 + static inline int arch_write_can_lock(arch_rwlock_t *lock) 79 + { 80 + return lock->lock == 0; 81 + } 82 + 83 + static inline void arch_read_lock(arch_rwlock_t *lock) 84 + { 85 + int tmp; 86 + 87 + __asm__ __volatile__( 88 + "1: lr.w %1, %0\n" 89 + " bltz %1, 1b\n" 90 + " addi %1, %1, 1\n" 91 + " sc.w.aq %1, %1, %0\n" 92 + " bnez %1, 1b\n" 93 + : "+A" (lock->lock), "=&r" (tmp) 94 + :: "memory"); 95 + } 96 + 97 + static inline void arch_write_lock(arch_rwlock_t *lock) 98 + { 99 + int tmp; 100 + 101 + __asm__ __volatile__( 102 + "1: lr.w %1, %0\n" 103 + " bnez %1, 1b\n" 104 + " li %1, -1\n" 105 + " sc.w.aq %1, %1, %0\n" 106 + " bnez %1, 1b\n" 107 + : "+A" (lock->lock), "=&r" (tmp) 108 + :: "memory"); 109 + } 110 + 111 + static inline int arch_read_trylock(arch_rwlock_t *lock) 112 + { 113 + int busy; 114 + 115 + __asm__ __volatile__( 116 + "1: lr.w %1, %0\n" 117 + " bltz %1, 1f\n" 118 + " addi %1, %1, 1\n" 119 + " sc.w.aq %1, %1, %0\n" 120 + " bnez %1, 1b\n" 121 + "1:\n" 122 + : "+A" (lock->lock), "=&r" (busy) 123 + :: "memory"); 124 + 125 + return !busy; 126 + } 127 + 128 + static inline int arch_write_trylock(arch_rwlock_t *lock) 129 + { 130 + int busy; 131 + 132 + __asm__ __volatile__( 133 + "1: lr.w %1, %0\n" 134 + " bnez %1, 1f\n" 135 + " li %1, -1\n" 136 + " sc.w.aq %1, %1, %0\n" 137 + " bnez %1, 1b\n" 138 + "1:\n" 139 + : "+A" (lock->lock), "=&r" (busy) 140 + :: "memory"); 141 + 142 + return !busy; 143 + } 144 + 145 + static inline void arch_read_unlock(arch_rwlock_t *lock) 146 + { 147 + __asm__ __volatile__( 148 + "amoadd.w.rl x0, %1, %0" 149 + : "+A" (lock->lock) 150 + : "r" (-1) 151 + : "memory"); 152 + } 153 + 154 + static inline void arch_write_unlock(arch_rwlock_t *lock) 155 + { 156 + __asm__ __volatile__ ( 157 + "amoswap.w.rl x0, x0, %0" 158 + : "=A" (lock->lock) 159 + :: "memory"); 160 + } 161 + 162 + #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) 163 + #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) 164 + 165 + #endif /* _ASM_RISCV_SPINLOCK_H */
+33
arch/riscv/include/asm/spinlock_types.h
··· 1 + /* 2 + * Copyright (C) 2015 Regents of the University of California 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation, version 2. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef _ASM_RISCV_SPINLOCK_TYPES_H 15 + #define _ASM_RISCV_SPINLOCK_TYPES_H 16 + 17 + #ifndef __LINUX_SPINLOCK_TYPES_H 18 + # error "please don't include this file directly" 19 + #endif 20 + 21 + typedef struct { 22 + volatile unsigned int lock; 23 + } arch_spinlock_t; 24 + 25 + #define __ARCH_SPIN_LOCK_UNLOCKED { 0 } 26 + 27 + typedef struct { 28 + volatile unsigned int lock; 29 + } arch_rwlock_t; 30 + 31 + #define __ARCH_RW_LOCK_UNLOCKED { 0 } 32 + 33 + #endif
+24
arch/riscv/include/asm/tlb.h
··· 1 + /* 2 + * Copyright (C) 2012 Regents of the University of California 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation, version 2. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef _ASM_RISCV_TLB_H 15 + #define _ASM_RISCV_TLB_H 16 + 17 + #include <asm-generic/tlb.h> 18 + 19 + static inline void tlb_flush(struct mmu_gather *tlb) 20 + { 21 + flush_tlb_mm(tlb->mm); 22 + } 23 + 24 + #endif /* _ASM_RISCV_TLB_H */
+64
arch/riscv/include/asm/tlbflush.h
··· 1 + /* 2 + * Copyright (C) 2009 Chen Liqin <liqin.chen@sunplusct.com> 3 + * Copyright (C) 2012 Regents of the University of California 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify it under the terms of the GNU General Public License 7 + * as published by the Free Software Foundation, version 2. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #ifndef _ASM_RISCV_TLBFLUSH_H 16 + #define _ASM_RISCV_TLBFLUSH_H 17 + 18 + #ifdef CONFIG_MMU 19 + 20 + /* Flush entire local TLB */ 21 + static inline void local_flush_tlb_all(void) 22 + { 23 + __asm__ __volatile__ ("sfence.vma" : : : "memory"); 24 + } 25 + 26 + /* Flush one page from local TLB */ 27 + static inline void local_flush_tlb_page(unsigned long addr) 28 + { 29 + __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"); 30 + } 31 + 32 + #ifndef CONFIG_SMP 33 + 34 + #define flush_tlb_all() local_flush_tlb_all() 35 + #define flush_tlb_page(vma, addr) local_flush_tlb_page(addr) 36 + #define flush_tlb_range(vma, start, end) local_flush_tlb_all() 37 + 38 + #else /* CONFIG_SMP */ 39 + 40 + #include <asm/sbi.h> 41 + 42 + #define flush_tlb_all() sbi_remote_sfence_vma(0, 0, -1) 43 + #define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0) 44 + #define flush_tlb_range(vma, start, end) \ 45 + sbi_remote_sfence_vma(0, start, (end) - (start)) 46 + 47 + #endif /* CONFIG_SMP */ 48 + 49 + /* Flush the TLB entries of the specified mm context */ 50 + static inline void flush_tlb_mm(struct mm_struct *mm) 51 + { 52 + flush_tlb_all(); 53 + } 54 + 55 + /* Flush a range of kernel pages */ 56 + static inline void flush_tlb_kernel_range(unsigned long start, 57 + unsigned long end) 58 + { 59 + flush_tlb_all(); 60 + } 61 + 62 + #endif /* CONFIG_MMU */ 63 + 64 + #endif /* _ASM_RISCV_TLBFLUSH_H */