1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __ARCH_M68K_ATOMIC__ 3 #define __ARCH_M68K_ATOMIC__ 4 5 #include <linux/types.h> 6 #include <linux/irqflags.h> 7 #include <asm/cmpxchg.h> 8 #include <asm/barrier.h> 9 10 /* 11 * Atomic operations that C can't guarantee us. Useful for 12 * resource counting etc.. 13 */ 14 15 /* 16 * We do not have SMP m68k systems, so we don't have to deal with that. 17 */ 18 19 #define atomic_read(v) READ_ONCE((v)->counter) 20 #define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) 21 22 /* 23 * The ColdFire parts cannot do some immediate to memory operations, 24 * so for them we do not specify the "i" asm constraint. 25 */ 26 #ifdef CONFIG_COLDFIRE 27 #define ASM_DI "d" 28 #else 29 #define ASM_DI "di" 30 #endif 31 32 #define ATOMIC_OP(op, c_op, asm_op) \ 33 static inline void atomic_##op(int i, atomic_t *v) \ 34 { \ 35 __asm__ __volatile__(#asm_op "l %1,%0" : "+m" (*v) : ASM_DI (i));\ 36 } \ 37 38 #ifdef CONFIG_RMW_INSNS 39 40 #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ 41 static inline int atomic_##op##_return(int i, atomic_t *v) \ 42 { \ 43 int t, tmp; \ 44 \ 45 __asm__ __volatile__( \ 46 "1: movel %2,%1\n" \ 47 " " #asm_op "l %3,%1\n" \ 48 " casl %2,%1,%0\n" \ 49 " jne 1b" \ 50 : "+m" (*v), "=&d" (t), "=&d" (tmp) \ 51 : "g" (i), "2" (atomic_read(v))); \ 52 return t; \ 53 } 54 55 #define ATOMIC_FETCH_OP(op, c_op, asm_op) \ 56 static inline int atomic_fetch_##op(int i, atomic_t *v) \ 57 { \ 58 int t, tmp; \ 59 \ 60 __asm__ __volatile__( \ 61 "1: movel %2,%1\n" \ 62 " " #asm_op "l %3,%1\n" \ 63 " casl %2,%1,%0\n" \ 64 " jne 1b" \ 65 : "+m" (*v), "=&d" (t), "=&d" (tmp) \ 66 : "g" (i), "2" (atomic_read(v))); \ 67 return tmp; \ 68 } 69 70 #else 71 72 #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ 73 static inline int atomic_##op##_return(int i, atomic_t * v) \ 74 { \ 75 unsigned long flags; \ 76 int t; \ 77 \ 78 local_irq_save(flags); \ 79 t = (v->counter c_op i); \ 80 local_irq_restore(flags); \ 81 \ 82 return t; \ 83 } 84 85 #define ATOMIC_FETCH_OP(op, c_op, asm_op) \ 86 static inline int atomic_fetch_##op(int i, atomic_t * v) \ 87 { \ 88 unsigned long flags; \ 89 int t; \ 90 \ 91 local_irq_save(flags); \ 92 t = v->counter; \ 93 v->counter c_op i; \ 94 local_irq_restore(flags); \ 95 \ 96 return t; \ 97 } 98 99 #endif /* CONFIG_RMW_INSNS */ 100 101 #define ATOMIC_OPS(op, c_op, asm_op) \ 102 ATOMIC_OP(op, c_op, asm_op) \ 103 ATOMIC_OP_RETURN(op, c_op, asm_op) \ 104 ATOMIC_FETCH_OP(op, c_op, asm_op) 105 106 ATOMIC_OPS(add, +=, add) 107 ATOMIC_OPS(sub, -=, sub) 108 109 #undef ATOMIC_OPS 110 #define ATOMIC_OPS(op, c_op, asm_op) \ 111 ATOMIC_OP(op, c_op, asm_op) \ 112 ATOMIC_FETCH_OP(op, c_op, asm_op) 113 114 ATOMIC_OPS(and, &=, and) 115 ATOMIC_OPS(or, |=, or) 116 ATOMIC_OPS(xor, ^=, eor) 117 118 #undef ATOMIC_OPS 119 #undef ATOMIC_FETCH_OP 120 #undef ATOMIC_OP_RETURN 121 #undef ATOMIC_OP 122 123 static inline void atomic_inc(atomic_t *v) 124 { 125 __asm__ __volatile__("addql #1,%0" : "+m" (*v)); 126 } 127 #define atomic_inc atomic_inc 128 129 static inline void atomic_dec(atomic_t *v) 130 { 131 __asm__ __volatile__("subql #1,%0" : "+m" (*v)); 132 } 133 #define atomic_dec atomic_dec 134 135 static inline int atomic_dec_and_test(atomic_t *v) 136 { 137 char c; 138 __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v)); 139 return c != 0; 140 } 141 #define atomic_dec_and_test atomic_dec_and_test 142 143 static inline int atomic_dec_and_test_lt(atomic_t *v) 144 { 145 char c; 146 __asm__ __volatile__( 147 "subql #1,%1; slt %0" 148 : "=d" (c), "=m" (*v) 149 : "m" (*v)); 150 return c != 0; 151 } 152 153 static inline int atomic_inc_and_test(atomic_t *v) 154 { 155 char c; 156 __asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v)); 157 return c != 0; 158 } 159 #define atomic_inc_and_test atomic_inc_and_test 160 161 #ifdef CONFIG_RMW_INSNS 162 163 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 164 #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 165 166 #else /* !CONFIG_RMW_INSNS */ 167 168 static inline int atomic_cmpxchg(atomic_t *v, int old, int new) 169 { 170 unsigned long flags; 171 int prev; 172 173 local_irq_save(flags); 174 prev = atomic_read(v); 175 if (prev == old) 176 atomic_set(v, new); 177 local_irq_restore(flags); 178 return prev; 179 } 180 181 static inline int atomic_xchg(atomic_t *v, int new) 182 { 183 unsigned long flags; 184 int prev; 185 186 local_irq_save(flags); 187 prev = atomic_read(v); 188 atomic_set(v, new); 189 local_irq_restore(flags); 190 return prev; 191 } 192 193 #endif /* !CONFIG_RMW_INSNS */ 194 195 static inline int atomic_sub_and_test(int i, atomic_t *v) 196 { 197 char c; 198 __asm__ __volatile__("subl %2,%1; seq %0" 199 : "=d" (c), "+m" (*v) 200 : ASM_DI (i)); 201 return c != 0; 202 } 203 #define atomic_sub_and_test atomic_sub_and_test 204 205 static inline int atomic_add_negative(int i, atomic_t *v) 206 { 207 char c; 208 __asm__ __volatile__("addl %2,%1; smi %0" 209 : "=d" (c), "+m" (*v) 210 : ASM_DI (i)); 211 return c != 0; 212 } 213 #define atomic_add_negative atomic_add_negative 214 215 #endif /* __ARCH_M68K_ATOMIC __ */ 216