1367b8112SChris Zankel /* 2367b8112SChris Zankel * include/asm-xtensa/atomic.h 3367b8112SChris Zankel * 4367b8112SChris Zankel * Atomic operations that C can't guarantee us. Useful for resource counting.. 5367b8112SChris Zankel * 6367b8112SChris Zankel * This file is subject to the terms and conditions of the GNU General Public 7367b8112SChris Zankel * License. See the file "COPYING" in the main directory of this archive 8367b8112SChris Zankel * for more details. 9367b8112SChris Zankel * 102d1c645cSMarc Gauthier * Copyright (C) 2001 - 2008 Tensilica Inc. 11367b8112SChris Zankel */ 12367b8112SChris Zankel 13367b8112SChris Zankel #ifndef _XTENSA_ATOMIC_H 14367b8112SChris Zankel #define _XTENSA_ATOMIC_H 15367b8112SChris Zankel 16367b8112SChris Zankel #include <linux/stringify.h> 1752fefcecSLinus Torvalds #include <linux/types.h> 18367b8112SChris Zankel 19367b8112SChris Zankel #ifdef __KERNEL__ 20367b8112SChris Zankel #include <asm/processor.h> 21f9aa7e18SDavid Howells #include <asm/cmpxchg.h> 2209a01c0cSPeter Zijlstra #include <asm/barrier.h> 23367b8112SChris Zankel 24367b8112SChris Zankel #define ATOMIC_INIT(i) { (i) } 25367b8112SChris Zankel 26367b8112SChris Zankel /* 27367b8112SChris Zankel * This Xtensa implementation assumes that the right mechanism 282d1c645cSMarc Gauthier * for exclusion is for locking interrupts to level EXCM_LEVEL. 29367b8112SChris Zankel * 30367b8112SChris Zankel * Locking interrupts looks like this: 31367b8112SChris Zankel * 322d1c645cSMarc Gauthier * rsil a15, LOCKLEVEL 33367b8112SChris Zankel * <code> 34367b8112SChris Zankel * wsr a15, PS 35367b8112SChris Zankel * rsync 36367b8112SChris Zankel * 37367b8112SChris Zankel * Note that a15 is used here because the register allocation 38367b8112SChris Zankel * done by the compiler is not guaranteed and a window overflow 39367b8112SChris Zankel * may not occur between the rsil and wsr instructions. By using 40367b8112SChris Zankel * a15 in the rsil, the machine is guaranteed to be in a state 41367b8112SChris Zankel * where no register reference will cause an overflow. 42367b8112SChris Zankel */ 43367b8112SChris Zankel 44367b8112SChris Zankel /** 45367b8112SChris Zankel * atomic_read - read atomic variable 46367b8112SChris Zankel * @v: pointer of type atomic_t 47367b8112SChris Zankel * 48367b8112SChris Zankel * Atomically reads the value of @v. 49367b8112SChris Zankel */ 50f3d46f9dSAnton Blanchard #define atomic_read(v) (*(volatile int *)&(v)->counter) 51367b8112SChris Zankel 52367b8112SChris Zankel /** 53367b8112SChris Zankel * atomic_set - set atomic variable 54367b8112SChris Zankel * @v: pointer of type atomic_t 55367b8112SChris Zankel * @i: required value 56367b8112SChris Zankel * 57367b8112SChris Zankel * Atomically sets the value of @v to @i. 58367b8112SChris Zankel */ 59367b8112SChris Zankel #define atomic_set(v,i) ((v)->counter = (i)) 60367b8112SChris Zankel 61219b1e4cSMax Filippov #if XCHAL_HAVE_S32C1I 62d4608dd5SPeter Zijlstra #define ATOMIC_OP(op) \ 63d4608dd5SPeter Zijlstra static inline void atomic_##op(int i, atomic_t * v) \ 64d4608dd5SPeter Zijlstra { \ 65d4608dd5SPeter Zijlstra unsigned long tmp; \ 66d4608dd5SPeter Zijlstra int result; \ 67d4608dd5SPeter Zijlstra \ 68d4608dd5SPeter Zijlstra __asm__ __volatile__( \ 69d4608dd5SPeter Zijlstra "1: l32i %1, %3, 0\n" \ 70d4608dd5SPeter Zijlstra " wsr %1, scompare1\n" \ 71d4608dd5SPeter Zijlstra " " #op " %0, %1, %2\n" \ 72d4608dd5SPeter Zijlstra " s32c1i %0, %3, 0\n" \ 73d4608dd5SPeter Zijlstra " bne %0, %1, 1b\n" \ 74d4608dd5SPeter Zijlstra : "=&a" (result), "=&a" (tmp) \ 75d4608dd5SPeter Zijlstra : "a" (i), "a" (v) \ 76d4608dd5SPeter Zijlstra : "memory" \ 77d4608dd5SPeter Zijlstra ); \ 78d4608dd5SPeter Zijlstra } \ 79219b1e4cSMax Filippov 80d4608dd5SPeter Zijlstra #define ATOMIC_OP_RETURN(op) \ 81d4608dd5SPeter Zijlstra static inline int atomic_##op##_return(int i, atomic_t * v) \ 82d4608dd5SPeter Zijlstra { \ 83d4608dd5SPeter Zijlstra unsigned long tmp; \ 84d4608dd5SPeter Zijlstra int result; \ 85d4608dd5SPeter Zijlstra \ 86d4608dd5SPeter Zijlstra __asm__ __volatile__( \ 87d4608dd5SPeter Zijlstra "1: l32i %1, %3, 0\n" \ 88d4608dd5SPeter Zijlstra " wsr %1, scompare1\n" \ 89d4608dd5SPeter Zijlstra " " #op " %0, %1, %2\n" \ 90d4608dd5SPeter Zijlstra " s32c1i %0, %3, 0\n" \ 91d4608dd5SPeter Zijlstra " bne %0, %1, 1b\n" \ 92d4608dd5SPeter Zijlstra " " #op " %0, %0, %2\n" \ 93d4608dd5SPeter Zijlstra : "=&a" (result), "=&a" (tmp) \ 94d4608dd5SPeter Zijlstra : "a" (i), "a" (v) \ 95d4608dd5SPeter Zijlstra : "memory" \ 96d4608dd5SPeter Zijlstra ); \ 97d4608dd5SPeter Zijlstra \ 98d4608dd5SPeter Zijlstra return result; \ 99367b8112SChris Zankel } 100367b8112SChris Zankel 101d4608dd5SPeter Zijlstra #else /* XCHAL_HAVE_S32C1I */ 102219b1e4cSMax Filippov 103d4608dd5SPeter Zijlstra #define ATOMIC_OP(op) \ 104d4608dd5SPeter Zijlstra static inline void atomic_##op(int i, atomic_t * v) \ 105d4608dd5SPeter Zijlstra { \ 106d4608dd5SPeter Zijlstra unsigned int vval; \ 107d4608dd5SPeter Zijlstra \ 108d4608dd5SPeter Zijlstra __asm__ __volatile__( \ 109d4608dd5SPeter Zijlstra " rsil a15, "__stringify(LOCKLEVEL)"\n"\ 110d4608dd5SPeter Zijlstra " l32i %0, %2, 0\n" \ 111d4608dd5SPeter Zijlstra " " #op " %0, %0, %1\n" \ 112d4608dd5SPeter Zijlstra " s32i %0, %2, 0\n" \ 113d4608dd5SPeter Zijlstra " wsr a15, ps\n" \ 114d4608dd5SPeter Zijlstra " rsync\n" \ 115d4608dd5SPeter Zijlstra : "=&a" (vval) \ 116d4608dd5SPeter Zijlstra : "a" (i), "a" (v) \ 117d4608dd5SPeter Zijlstra : "a15", "memory" \ 118d4608dd5SPeter Zijlstra ); \ 119d4608dd5SPeter Zijlstra } \ 120367b8112SChris Zankel 121d4608dd5SPeter Zijlstra #define ATOMIC_OP_RETURN(op) \ 122d4608dd5SPeter Zijlstra static inline int atomic_##op##_return(int i, atomic_t * v) \ 123d4608dd5SPeter Zijlstra { \ 124d4608dd5SPeter Zijlstra unsigned int vval; \ 125d4608dd5SPeter Zijlstra \ 126d4608dd5SPeter Zijlstra __asm__ __volatile__( \ 127d4608dd5SPeter Zijlstra " rsil a15,"__stringify(LOCKLEVEL)"\n" \ 128d4608dd5SPeter Zijlstra " l32i %0, %2, 0\n" \ 129d4608dd5SPeter Zijlstra " " #op " %0, %0, %1\n" \ 130d4608dd5SPeter Zijlstra " s32i %0, %2, 0\n" \ 131d4608dd5SPeter Zijlstra " wsr a15, ps\n" \ 132d4608dd5SPeter Zijlstra " rsync\n" \ 133d4608dd5SPeter Zijlstra : "=&a" (vval) \ 134d4608dd5SPeter Zijlstra : "a" (i), "a" (v) \ 135d4608dd5SPeter Zijlstra : "a15", "memory" \ 136d4608dd5SPeter Zijlstra ); \ 137d4608dd5SPeter Zijlstra \ 138d4608dd5SPeter Zijlstra return vval; \ 139367b8112SChris Zankel } 140367b8112SChris Zankel 141d4608dd5SPeter Zijlstra #endif /* XCHAL_HAVE_S32C1I */ 142367b8112SChris Zankel 143d4608dd5SPeter Zijlstra #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) 144219b1e4cSMax Filippov 145d4608dd5SPeter Zijlstra ATOMIC_OPS(add) 146d4608dd5SPeter Zijlstra ATOMIC_OPS(sub) 147219b1e4cSMax Filippov 148d4608dd5SPeter Zijlstra #undef ATOMIC_OPS 149d4608dd5SPeter Zijlstra #undef ATOMIC_OP_RETURN 150d4608dd5SPeter Zijlstra #undef ATOMIC_OP 151367b8112SChris Zankel 152367b8112SChris Zankel /** 153367b8112SChris Zankel * atomic_sub_and_test - subtract value from variable and test result 154367b8112SChris Zankel * @i: integer value to subtract 155367b8112SChris Zankel * @v: pointer of type atomic_t 156367b8112SChris Zankel * 157367b8112SChris Zankel * Atomically subtracts @i from @v and returns 158367b8112SChris Zankel * true if the result is zero, or false for all 159367b8112SChris Zankel * other cases. 160367b8112SChris Zankel */ 161367b8112SChris Zankel #define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) 162367b8112SChris Zankel 163367b8112SChris Zankel /** 164367b8112SChris Zankel * atomic_inc - increment atomic variable 165367b8112SChris Zankel * @v: pointer of type atomic_t 166367b8112SChris Zankel * 167367b8112SChris Zankel * Atomically increments @v by 1. 168367b8112SChris Zankel */ 169367b8112SChris Zankel #define atomic_inc(v) atomic_add(1,(v)) 170367b8112SChris Zankel 171367b8112SChris Zankel /** 172367b8112SChris Zankel * atomic_inc - increment atomic variable 173367b8112SChris Zankel * @v: pointer of type atomic_t 174367b8112SChris Zankel * 175367b8112SChris Zankel * Atomically increments @v by 1. 176367b8112SChris Zankel */ 177367b8112SChris Zankel #define atomic_inc_return(v) atomic_add_return(1,(v)) 178367b8112SChris Zankel 179367b8112SChris Zankel /** 180367b8112SChris Zankel * atomic_dec - decrement atomic variable 181367b8112SChris Zankel * @v: pointer of type atomic_t 182367b8112SChris Zankel * 183367b8112SChris Zankel * Atomically decrements @v by 1. 184367b8112SChris Zankel */ 185367b8112SChris Zankel #define atomic_dec(v) atomic_sub(1,(v)) 186367b8112SChris Zankel 187367b8112SChris Zankel /** 188367b8112SChris Zankel * atomic_dec_return - decrement atomic variable 189367b8112SChris Zankel * @v: pointer of type atomic_t 190367b8112SChris Zankel * 191367b8112SChris Zankel * Atomically decrements @v by 1. 192367b8112SChris Zankel */ 193367b8112SChris Zankel #define atomic_dec_return(v) atomic_sub_return(1,(v)) 194367b8112SChris Zankel 195367b8112SChris Zankel /** 196367b8112SChris Zankel * atomic_dec_and_test - decrement and test 197367b8112SChris Zankel * @v: pointer of type atomic_t 198367b8112SChris Zankel * 199367b8112SChris Zankel * Atomically decrements @v by 1 and 200367b8112SChris Zankel * returns true if the result is 0, or false for all other 201367b8112SChris Zankel * cases. 202367b8112SChris Zankel */ 203367b8112SChris Zankel #define atomic_dec_and_test(v) (atomic_sub_return(1,(v)) == 0) 204367b8112SChris Zankel 205367b8112SChris Zankel /** 206367b8112SChris Zankel * atomic_inc_and_test - increment and test 207367b8112SChris Zankel * @v: pointer of type atomic_t 208367b8112SChris Zankel * 209367b8112SChris Zankel * Atomically increments @v by 1 210367b8112SChris Zankel * and returns true if the result is zero, or false for all 211367b8112SChris Zankel * other cases. 212367b8112SChris Zankel */ 213367b8112SChris Zankel #define atomic_inc_and_test(v) (atomic_add_return(1,(v)) == 0) 214367b8112SChris Zankel 215367b8112SChris Zankel /** 216367b8112SChris Zankel * atomic_add_negative - add and test if negative 217367b8112SChris Zankel * @v: pointer of type atomic_t 218367b8112SChris Zankel * @i: integer value to add 219367b8112SChris Zankel * 220367b8112SChris Zankel * Atomically adds @i to @v and returns true 221367b8112SChris Zankel * if the result is negative, or false when 222367b8112SChris Zankel * result is greater than or equal to zero. 223367b8112SChris Zankel */ 224367b8112SChris Zankel #define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0) 225367b8112SChris Zankel 226367b8112SChris Zankel #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 227367b8112SChris Zankel #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 228367b8112SChris Zankel 229367b8112SChris Zankel /** 230f24219b4SArun Sharma * __atomic_add_unless - add unless the number is a given value 231367b8112SChris Zankel * @v: pointer of type atomic_t 232367b8112SChris Zankel * @a: the amount to add to v... 233367b8112SChris Zankel * @u: ...unless v is equal to u. 234367b8112SChris Zankel * 235367b8112SChris Zankel * Atomically adds @a to @v, so long as it was not @u. 236f24219b4SArun Sharma * Returns the old value of @v. 237367b8112SChris Zankel */ 238f24219b4SArun Sharma static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) 239367b8112SChris Zankel { 240367b8112SChris Zankel int c, old; 241367b8112SChris Zankel c = atomic_read(v); 242367b8112SChris Zankel for (;;) { 243367b8112SChris Zankel if (unlikely(c == (u))) 244367b8112SChris Zankel break; 245367b8112SChris Zankel old = atomic_cmpxchg((v), c, c + (a)); 246367b8112SChris Zankel if (likely(old == c)) 247367b8112SChris Zankel break; 248367b8112SChris Zankel c = old; 249367b8112SChris Zankel } 250f24219b4SArun Sharma return c; 251367b8112SChris Zankel } 252367b8112SChris Zankel 253367b8112SChris Zankel 254367b8112SChris Zankel static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) 255367b8112SChris Zankel { 256219b1e4cSMax Filippov #if XCHAL_HAVE_S32C1I 257219b1e4cSMax Filippov unsigned long tmp; 258219b1e4cSMax Filippov int result; 259219b1e4cSMax Filippov 260219b1e4cSMax Filippov __asm__ __volatile__( 261219b1e4cSMax Filippov "1: l32i %1, %3, 0\n" 262219b1e4cSMax Filippov " wsr %1, scompare1\n" 263219b1e4cSMax Filippov " and %0, %1, %2\n" 264219b1e4cSMax Filippov " s32c1i %0, %3, 0\n" 265219b1e4cSMax Filippov " bne %0, %1, 1b\n" 266219b1e4cSMax Filippov : "=&a" (result), "=&a" (tmp) 267219b1e4cSMax Filippov : "a" (~mask), "a" (v) 268219b1e4cSMax Filippov : "memory" 269219b1e4cSMax Filippov ); 270219b1e4cSMax Filippov #else 271367b8112SChris Zankel unsigned int all_f = -1; 272367b8112SChris Zankel unsigned int vval; 273367b8112SChris Zankel 274367b8112SChris Zankel __asm__ __volatile__( 275219b1e4cSMax Filippov " rsil a15,"__stringify(LOCKLEVEL)"\n" 276219b1e4cSMax Filippov " l32i %0, %2, 0\n" 277219b1e4cSMax Filippov " xor %1, %4, %3\n" 278219b1e4cSMax Filippov " and %0, %0, %4\n" 279219b1e4cSMax Filippov " s32i %0, %2, 0\n" 280219b1e4cSMax Filippov " wsr a15, ps\n" 281367b8112SChris Zankel " rsync\n" 282367b8112SChris Zankel : "=&a" (vval), "=a" (mask) 283367b8112SChris Zankel : "a" (v), "a" (all_f), "1" (mask) 284367b8112SChris Zankel : "a15", "memory" 285367b8112SChris Zankel ); 286219b1e4cSMax Filippov #endif 287367b8112SChris Zankel } 288367b8112SChris Zankel 289367b8112SChris Zankel static inline void atomic_set_mask(unsigned int mask, atomic_t *v) 290367b8112SChris Zankel { 291219b1e4cSMax Filippov #if XCHAL_HAVE_S32C1I 292219b1e4cSMax Filippov unsigned long tmp; 293219b1e4cSMax Filippov int result; 294219b1e4cSMax Filippov 295219b1e4cSMax Filippov __asm__ __volatile__( 296219b1e4cSMax Filippov "1: l32i %1, %3, 0\n" 297219b1e4cSMax Filippov " wsr %1, scompare1\n" 298219b1e4cSMax Filippov " or %0, %1, %2\n" 299219b1e4cSMax Filippov " s32c1i %0, %3, 0\n" 300219b1e4cSMax Filippov " bne %0, %1, 1b\n" 301219b1e4cSMax Filippov : "=&a" (result), "=&a" (tmp) 302219b1e4cSMax Filippov : "a" (mask), "a" (v) 303219b1e4cSMax Filippov : "memory" 304219b1e4cSMax Filippov ); 305219b1e4cSMax Filippov #else 306367b8112SChris Zankel unsigned int vval; 307367b8112SChris Zankel 308367b8112SChris Zankel __asm__ __volatile__( 309219b1e4cSMax Filippov " rsil a15,"__stringify(LOCKLEVEL)"\n" 310219b1e4cSMax Filippov " l32i %0, %2, 0\n" 311219b1e4cSMax Filippov " or %0, %0, %1\n" 312219b1e4cSMax Filippov " s32i %0, %2, 0\n" 313219b1e4cSMax Filippov " wsr a15, ps\n" 314367b8112SChris Zankel " rsync\n" 315367b8112SChris Zankel : "=&a" (vval) 316367b8112SChris Zankel : "a" (mask), "a" (v) 317367b8112SChris Zankel : "a15", "memory" 318367b8112SChris Zankel ); 319219b1e4cSMax Filippov #endif 320367b8112SChris Zankel } 321367b8112SChris Zankel 322367b8112SChris Zankel #endif /* __KERNEL__ */ 323367b8112SChris Zankel 324367b8112SChris Zankel #endif /* _XTENSA_ATOMIC_H */ 325