1 /* 2 * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> 3 * 4 * This file is licensed under the terms of the GNU General Public License 5 * version 2. This program is licensed "as is" without any warranty of any 6 * kind, whether express or implied. 7 */ 8 9 #ifndef __ASM_OPENRISC_ATOMIC_H 10 #define __ASM_OPENRISC_ATOMIC_H 11 12 #include <linux/types.h> 13 14 /* Atomically perform op with v->counter and i */ 15 #define ATOMIC_OP(op) \ 16 static inline void arch_atomic_##op(int i, atomic_t *v) \ 17 { \ 18 int tmp; \ 19 \ 20 __asm__ __volatile__( \ 21 "1: l.lwa %0,0(%1) \n" \ 22 " l." #op " %0,%0,%2 \n" \ 23 " l.swa 0(%1),%0 \n" \ 24 " l.bnf 1b \n" \ 25 " l.nop \n" \ 26 : "=&r"(tmp) \ 27 : "r"(&v->counter), "r"(i) \ 28 : "cc", "memory"); \ 29 } 30 31 /* Atomically perform op with v->counter and i, return the result */ 32 #define ATOMIC_OP_RETURN(op) \ 33 static inline int arch_atomic_##op##_return(int i, atomic_t *v) \ 34 { \ 35 int tmp; \ 36 \ 37 __asm__ __volatile__( \ 38 "1: l.lwa %0,0(%1) \n" \ 39 " l." #op " %0,%0,%2 \n" \ 40 " l.swa 0(%1),%0 \n" \ 41 " l.bnf 1b \n" \ 42 " l.nop \n" \ 43 : "=&r"(tmp) \ 44 : "r"(&v->counter), "r"(i) \ 45 : "cc", "memory"); \ 46 \ 47 return tmp; \ 48 } 49 50 /* Atomically perform op with v->counter and i, return orig v->counter */ 51 #define ATOMIC_FETCH_OP(op) \ 52 static inline int arch_atomic_fetch_##op(int i, atomic_t *v) \ 53 { \ 54 int tmp, old; \ 55 \ 56 __asm__ __volatile__( \ 57 "1: l.lwa %0,0(%2) \n" \ 58 " l." #op " %1,%0,%3 \n" \ 59 " l.swa 0(%2),%1 \n" \ 60 " l.bnf 1b \n" \ 61 " l.nop \n" \ 62 : "=&r"(old), "=&r"(tmp) \ 63 : "r"(&v->counter), "r"(i) \ 64 : "cc", "memory"); \ 65 \ 66 return old; \ 67 } 68 69 ATOMIC_OP_RETURN(add) 70 ATOMIC_OP_RETURN(sub) 71 72 ATOMIC_FETCH_OP(add) 73 ATOMIC_FETCH_OP(sub) 74 ATOMIC_FETCH_OP(and) 75 ATOMIC_FETCH_OP(or) 76 ATOMIC_FETCH_OP(xor) 77 78 ATOMIC_OP(add) 79 ATOMIC_OP(sub) 80 ATOMIC_OP(and) 81 ATOMIC_OP(or) 82 ATOMIC_OP(xor) 83 84 #undef ATOMIC_FETCH_OP 85 #undef ATOMIC_OP_RETURN 86 #undef ATOMIC_OP 87 88 #define arch_atomic_add_return arch_atomic_add_return 89 #define arch_atomic_sub_return arch_atomic_sub_return 90 #define arch_atomic_fetch_add arch_atomic_fetch_add 91 #define arch_atomic_fetch_sub arch_atomic_fetch_sub 92 #define arch_atomic_fetch_and arch_atomic_fetch_and 93 #define arch_atomic_fetch_or arch_atomic_fetch_or 94 #define arch_atomic_fetch_xor arch_atomic_fetch_xor 95 #define arch_atomic_add arch_atomic_add 96 #define arch_atomic_sub arch_atomic_sub 97 #define arch_atomic_and arch_atomic_and 98 #define arch_atomic_or arch_atomic_or 99 #define arch_atomic_xor arch_atomic_xor 100 101 /* 102 * Atomically add a to v->counter as long as v is not already u. 103 * Returns the original value at v->counter. 104 * 105 * This is often used through atomic_inc_not_zero() 106 */ 107 static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u) 108 { 109 int old, tmp; 110 111 __asm__ __volatile__( 112 "1: l.lwa %0, 0(%2) \n" 113 " l.sfeq %0, %4 \n" 114 " l.bf 2f \n" 115 " l.add %1, %0, %3 \n" 116 " l.swa 0(%2), %1 \n" 117 " l.bnf 1b \n" 118 " l.nop \n" 119 "2: \n" 120 : "=&r"(old), "=&r" (tmp) 121 : "r"(&v->counter), "r"(a), "r"(u) 122 : "cc", "memory"); 123 124 return old; 125 } 126 #define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless 127 128 #define arch_atomic_read(v) READ_ONCE((v)->counter) 129 #define arch_atomic_set(v,i) WRITE_ONCE((v)->counter, (i)) 130 131 #include <asm/cmpxchg.h> 132 133 #define arch_atomic_xchg(ptr, v) (arch_xchg(&(ptr)->counter, (v))) 134 #define arch_atomic_cmpxchg(v, old, new) (arch_cmpxchg(&((v)->counter), (old), (new))) 135 136 #endif /* __ASM_OPENRISC_ATOMIC_H */ 137