at v5.5 265 lines 7.3 kB view raw
1/* 2 * include/asm-xtensa/atomic.h 3 * 4 * Atomic operations that C can't guarantee us. Useful for resource counting.. 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 * 10 * Copyright (C) 2001 - 2008 Tensilica Inc. 11 */ 12 13#ifndef _XTENSA_ATOMIC_H 14#define _XTENSA_ATOMIC_H 15 16#include <linux/stringify.h> 17#include <linux/types.h> 18#include <asm/processor.h> 19#include <asm/cmpxchg.h> 20#include <asm/barrier.h> 21 22#define ATOMIC_INIT(i) { (i) } 23 24/* 25 * This Xtensa implementation assumes that the right mechanism 26 * for exclusion is for locking interrupts to level EXCM_LEVEL. 27 * 28 * Locking interrupts looks like this: 29 * 30 * rsil a15, TOPLEVEL 31 * <code> 32 * wsr a15, PS 33 * rsync 34 * 35 * Note that a15 is used here because the register allocation 36 * done by the compiler is not guaranteed and a window overflow 37 * may not occur between the rsil and wsr instructions. By using 38 * a15 in the rsil, the machine is guaranteed to be in a state 39 * where no register reference will cause an overflow. 40 */ 41 42/** 43 * atomic_read - read atomic variable 44 * @v: pointer of type atomic_t 45 * 46 * Atomically reads the value of @v. 47 */ 48#define atomic_read(v) READ_ONCE((v)->counter) 49 50/** 51 * atomic_set - set atomic variable 52 * @v: pointer of type atomic_t 53 * @i: required value 54 * 55 * Atomically sets the value of @v to @i. 56 */ 57#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i)) 58 59#if XCHAL_HAVE_EXCLUSIVE 60#define ATOMIC_OP(op) \ 61static inline void atomic_##op(int i, atomic_t *v) \ 62{ \ 63 unsigned long tmp; \ 64 int result; \ 65 \ 66 __asm__ __volatile__( \ 67 "1: l32ex %[tmp], %[addr]\n" \ 68 " " #op " %[result], %[tmp], %[i]\n" \ 69 " s32ex %[result], %[addr]\n" \ 70 " getex %[result]\n" \ 71 " beqz %[result], 1b\n" \ 72 : [result] "=&a" (result), [tmp] "=&a" (tmp) \ 73 : [i] "a" (i), [addr] "a" (v) \ 74 : "memory" \ 75 ); \ 76} \ 77 78#define ATOMIC_OP_RETURN(op) \ 79static inline int atomic_##op##_return(int i, atomic_t *v) \ 80{ \ 81 unsigned long tmp; \ 82 int result; \ 83 \ 84 __asm__ __volatile__( \ 85 "1: l32ex %[tmp], %[addr]\n" \ 86 " " #op " %[result], %[tmp], %[i]\n" \ 87 " s32ex %[result], %[addr]\n" \ 88 " getex %[result]\n" \ 89 " beqz %[result], 1b\n" \ 90 " " #op " %[result], %[tmp], %[i]\n" \ 91 : [result] "=&a" (result), [tmp] "=&a" (tmp) \ 92 : [i] "a" (i), [addr] "a" (v) \ 93 : "memory" \ 94 ); \ 95 \ 96 return result; \ 97} 98 99#define ATOMIC_FETCH_OP(op) \ 100static inline int atomic_fetch_##op(int i, atomic_t *v) \ 101{ \ 102 unsigned long tmp; \ 103 int result; \ 104 \ 105 __asm__ __volatile__( \ 106 "1: l32ex %[tmp], %[addr]\n" \ 107 " " #op " %[result], %[tmp], %[i]\n" \ 108 " s32ex %[result], %[addr]\n" \ 109 " getex %[result]\n" \ 110 " beqz %[result], 1b\n" \ 111 : [result] "=&a" (result), [tmp] "=&a" (tmp) \ 112 : [i] "a" (i), [addr] "a" (v) \ 113 : "memory" \ 114 ); \ 115 \ 116 return tmp; \ 117} 118 119#elif XCHAL_HAVE_S32C1I 120#define ATOMIC_OP(op) \ 121static inline void atomic_##op(int i, atomic_t * v) \ 122{ \ 123 unsigned long tmp; \ 124 int result; \ 125 \ 126 __asm__ __volatile__( \ 127 "1: l32i %[tmp], %[mem]\n" \ 128 " wsr %[tmp], scompare1\n" \ 129 " " #op " %[result], %[tmp], %[i]\n" \ 130 " s32c1i %[result], %[mem]\n" \ 131 " bne %[result], %[tmp], 1b\n" \ 132 : [result] "=&a" (result), [tmp] "=&a" (tmp), \ 133 [mem] "+m" (*v) \ 134 : [i] "a" (i) \ 135 : "memory" \ 136 ); \ 137} \ 138 139#define ATOMIC_OP_RETURN(op) \ 140static inline int atomic_##op##_return(int i, atomic_t * v) \ 141{ \ 142 unsigned long tmp; \ 143 int result; \ 144 \ 145 __asm__ __volatile__( \ 146 "1: l32i %[tmp], %[mem]\n" \ 147 " wsr %[tmp], scompare1\n" \ 148 " " #op " %[result], %[tmp], %[i]\n" \ 149 " s32c1i %[result], %[mem]\n" \ 150 " bne %[result], %[tmp], 1b\n" \ 151 " " #op " %[result], %[result], %[i]\n" \ 152 : [result] "=&a" (result), [tmp] "=&a" (tmp), \ 153 [mem] "+m" (*v) \ 154 : [i] "a" (i) \ 155 : "memory" \ 156 ); \ 157 \ 158 return result; \ 159} 160 161#define ATOMIC_FETCH_OP(op) \ 162static inline int atomic_fetch_##op(int i, atomic_t * v) \ 163{ \ 164 unsigned long tmp; \ 165 int result; \ 166 \ 167 __asm__ __volatile__( \ 168 "1: l32i %[tmp], %[mem]\n" \ 169 " wsr %[tmp], scompare1\n" \ 170 " " #op " %[result], %[tmp], %[i]\n" \ 171 " s32c1i %[result], %[mem]\n" \ 172 " bne %[result], %[tmp], 1b\n" \ 173 : [result] "=&a" (result), [tmp] "=&a" (tmp), \ 174 [mem] "+m" (*v) \ 175 : [i] "a" (i) \ 176 : "memory" \ 177 ); \ 178 \ 179 return result; \ 180} 181 182#else /* XCHAL_HAVE_S32C1I */ 183 184#define ATOMIC_OP(op) \ 185static inline void atomic_##op(int i, atomic_t * v) \ 186{ \ 187 unsigned int vval; \ 188 \ 189 __asm__ __volatile__( \ 190 " rsil a15, "__stringify(TOPLEVEL)"\n" \ 191 " l32i %[result], %[mem]\n" \ 192 " " #op " %[result], %[result], %[i]\n" \ 193 " s32i %[result], %[mem]\n" \ 194 " wsr a15, ps\n" \ 195 " rsync\n" \ 196 : [result] "=&a" (vval), [mem] "+m" (*v) \ 197 : [i] "a" (i) \ 198 : "a15", "memory" \ 199 ); \ 200} \ 201 202#define ATOMIC_OP_RETURN(op) \ 203static inline int atomic_##op##_return(int i, atomic_t * v) \ 204{ \ 205 unsigned int vval; \ 206 \ 207 __asm__ __volatile__( \ 208 " rsil a15,"__stringify(TOPLEVEL)"\n" \ 209 " l32i %[result], %[mem]\n" \ 210 " " #op " %[result], %[result], %[i]\n" \ 211 " s32i %[result], %[mem]\n" \ 212 " wsr a15, ps\n" \ 213 " rsync\n" \ 214 : [result] "=&a" (vval), [mem] "+m" (*v) \ 215 : [i] "a" (i) \ 216 : "a15", "memory" \ 217 ); \ 218 \ 219 return vval; \ 220} 221 222#define ATOMIC_FETCH_OP(op) \ 223static inline int atomic_fetch_##op(int i, atomic_t * v) \ 224{ \ 225 unsigned int tmp, vval; \ 226 \ 227 __asm__ __volatile__( \ 228 " rsil a15,"__stringify(TOPLEVEL)"\n" \ 229 " l32i %[result], %[mem]\n" \ 230 " " #op " %[tmp], %[result], %[i]\n" \ 231 " s32i %[tmp], %[mem]\n" \ 232 " wsr a15, ps\n" \ 233 " rsync\n" \ 234 : [result] "=&a" (vval), [tmp] "=&a" (tmp), \ 235 [mem] "+m" (*v) \ 236 : [i] "a" (i) \ 237 : "a15", "memory" \ 238 ); \ 239 \ 240 return vval; \ 241} 242 243#endif /* XCHAL_HAVE_S32C1I */ 244 245#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op) 246 247ATOMIC_OPS(add) 248ATOMIC_OPS(sub) 249 250#undef ATOMIC_OPS 251#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) 252 253ATOMIC_OPS(and) 254ATOMIC_OPS(or) 255ATOMIC_OPS(xor) 256 257#undef ATOMIC_OPS 258#undef ATOMIC_FETCH_OP 259#undef ATOMIC_OP_RETURN 260#undef ATOMIC_OP 261 262#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 263#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 264 265#endif /* _XTENSA_ATOMIC_H */