at v6.19 221 lines 5.3 kB view raw
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 arch_atomic_read(v) READ_ONCE((v)->counter) 20#define arch_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) \ 33static inline void arch_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) \ 41static inline int arch_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 : "di" (i), "2" (arch_atomic_read(v))); \ 52 return t; \ 53} 54 55#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ 56static inline int arch_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 : "di" (i), "2" (arch_atomic_read(v))); \ 67 return tmp; \ 68} 69 70#else 71 72#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ 73static inline int arch_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) \ 86static inline int arch_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 106ATOMIC_OPS(add, +=, add) 107ATOMIC_OPS(sub, -=, sub) 108 109#define arch_atomic_add_return arch_atomic_add_return 110#define arch_atomic_sub_return arch_atomic_sub_return 111#define arch_atomic_fetch_add arch_atomic_fetch_add 112#define arch_atomic_fetch_sub arch_atomic_fetch_sub 113 114#undef ATOMIC_OPS 115#define ATOMIC_OPS(op, c_op, asm_op) \ 116 ATOMIC_OP(op, c_op, asm_op) \ 117 ATOMIC_FETCH_OP(op, c_op, asm_op) 118 119ATOMIC_OPS(and, &=, and) 120ATOMIC_OPS(or, |=, or) 121ATOMIC_OPS(xor, ^=, eor) 122 123#define arch_atomic_fetch_and arch_atomic_fetch_and 124#define arch_atomic_fetch_or arch_atomic_fetch_or 125#define arch_atomic_fetch_xor arch_atomic_fetch_xor 126 127#undef ATOMIC_OPS 128#undef ATOMIC_FETCH_OP 129#undef ATOMIC_OP_RETURN 130#undef ATOMIC_OP 131 132static inline void arch_atomic_inc(atomic_t *v) 133{ 134 __asm__ __volatile__("addql #1,%0" : "+m" (*v)); 135} 136#define arch_atomic_inc arch_atomic_inc 137 138static inline void arch_atomic_dec(atomic_t *v) 139{ 140 __asm__ __volatile__("subql #1,%0" : "+m" (*v)); 141} 142#define arch_atomic_dec arch_atomic_dec 143 144static inline int arch_atomic_dec_and_test(atomic_t *v) 145{ 146 char c; 147 __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v)); 148 return c != 0; 149} 150#define arch_atomic_dec_and_test arch_atomic_dec_and_test 151 152static inline int arch_atomic_dec_and_test_lt(atomic_t *v) 153{ 154 char c; 155 __asm__ __volatile__( 156 "subql #1,%1; slt %0" 157 : "=d" (c), "=m" (*v) 158 : "m" (*v)); 159 return c != 0; 160} 161 162static inline int arch_atomic_inc_and_test(atomic_t *v) 163{ 164 char c; 165 __asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v)); 166 return c != 0; 167} 168#define arch_atomic_inc_and_test arch_atomic_inc_and_test 169 170#ifndef CONFIG_RMW_INSNS 171 172static inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new) 173{ 174 unsigned long flags; 175 int prev; 176 177 local_irq_save(flags); 178 prev = arch_atomic_read(v); 179 if (prev == old) 180 arch_atomic_set(v, new); 181 local_irq_restore(flags); 182 return prev; 183} 184#define arch_atomic_cmpxchg arch_atomic_cmpxchg 185 186static inline int arch_atomic_xchg(atomic_t *v, int new) 187{ 188 unsigned long flags; 189 int prev; 190 191 local_irq_save(flags); 192 prev = arch_atomic_read(v); 193 arch_atomic_set(v, new); 194 local_irq_restore(flags); 195 return prev; 196} 197#define arch_atomic_xchg arch_atomic_xchg 198 199#endif /* !CONFIG_RMW_INSNS */ 200 201static inline int arch_atomic_sub_and_test(int i, atomic_t *v) 202{ 203 char c; 204 __asm__ __volatile__("subl %2,%1; seq %0" 205 : "=d" (c), "+m" (*v) 206 : ASM_DI (i)); 207 return c != 0; 208} 209#define arch_atomic_sub_and_test arch_atomic_sub_and_test 210 211static inline int arch_atomic_add_negative(int i, atomic_t *v) 212{ 213 char c; 214 __asm__ __volatile__("addl %2,%1; smi %0" 215 : "=d" (c), "+m" (*v) 216 : ASM_DI (i)); 217 return c != 0; 218} 219#define arch_atomic_add_negative arch_atomic_add_negative 220 221#endif /* __ARCH_M68K_ATOMIC __ */