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 */ 135