1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 3 * Copyright (C) 2006 Kyle McMartin <kyle@parisc-linux.org> 4 */ 5 6 #ifndef _ASM_PARISC_ATOMIC_H_ 7 #define _ASM_PARISC_ATOMIC_H_ 8 9 #include <linux/types.h> 10 #include <asm/cmpxchg.h> 11 #include <asm/barrier.h> 12 13 /* 14 * Atomic operations that C can't guarantee us. Useful for 15 * resource counting etc.. 16 * 17 * And probably incredibly slow on parisc. OTOH, we don't 18 * have to write any serious assembly. prumpf 19 */ 20 21 #ifdef CONFIG_SMP 22 #include <asm/spinlock.h> 23 #include <asm/cache.h> /* we use L1_CACHE_BYTES */ 24 25 /* Use an array of spinlocks for our atomic_ts. 26 * Hash function to index into a different SPINLOCK. 27 * Since "a" is usually an address, use one spinlock per cacheline. 28 */ 29 # define ATOMIC_HASH_SIZE 4 30 # define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) (a))/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ])) 31 32 extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; 33 34 /* Can't use raw_spin_lock_irq because of #include problems, so 35 * this is the substitute */ 36 #define _atomic_spin_lock_irqsave(l,f) do { \ 37 arch_spinlock_t *s = ATOMIC_HASH(l); \ 38 local_irq_save(f); \ 39 arch_spin_lock(s); \ 40 } while(0) 41 42 #define _atomic_spin_unlock_irqrestore(l,f) do { \ 43 arch_spinlock_t *s = ATOMIC_HASH(l); \ 44 arch_spin_unlock(s); \ 45 local_irq_restore(f); \ 46 } while(0) 47 48 49 #else 50 # define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0) 51 # define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0) 52 #endif 53 54 /* 55 * Note that we need not lock read accesses - aligned word writes/reads 56 * are atomic, so a reader never sees inconsistent values. 57 */ 58 59 static __inline__ void arch_atomic_set(atomic_t *v, int i) 60 { 61 unsigned long flags; 62 _atomic_spin_lock_irqsave(v, flags); 63 64 v->counter = i; 65 66 _atomic_spin_unlock_irqrestore(v, flags); 67 } 68 69 #define arch_atomic_set_release(v, i) arch_atomic_set((v), (i)) 70 71 static __inline__ int arch_atomic_read(const atomic_t *v) 72 { 73 return READ_ONCE((v)->counter); 74 } 75 76 #define ATOMIC_OP(op, c_op) \ 77 static __inline__ void arch_atomic_##op(int i, atomic_t *v) \ 78 { \ 79 unsigned long flags; \ 80 \ 81 _atomic_spin_lock_irqsave(v, flags); \ 82 v->counter c_op i; \ 83 _atomic_spin_unlock_irqrestore(v, flags); \ 84 } 85 86 #define ATOMIC_OP_RETURN(op, c_op) \ 87 static __inline__ int arch_atomic_##op##_return(int i, atomic_t *v) \ 88 { \ 89 unsigned long flags; \ 90 int ret; \ 91 \ 92 _atomic_spin_lock_irqsave(v, flags); \ 93 ret = (v->counter c_op i); \ 94 _atomic_spin_unlock_irqrestore(v, flags); \ 95 \ 96 return ret; \ 97 } 98 99 #define ATOMIC_FETCH_OP(op, c_op) \ 100 static __inline__ int arch_atomic_fetch_##op(int i, atomic_t *v) \ 101 { \ 102 unsigned long flags; \ 103 int ret; \ 104 \ 105 _atomic_spin_lock_irqsave(v, flags); \ 106 ret = v->counter; \ 107 v->counter c_op i; \ 108 _atomic_spin_unlock_irqrestore(v, flags); \ 109 \ 110 return ret; \ 111 } 112 113 #define ATOMIC_OPS(op, c_op) \ 114 ATOMIC_OP(op, c_op) \ 115 ATOMIC_OP_RETURN(op, c_op) \ 116 ATOMIC_FETCH_OP(op, c_op) 117 118 ATOMIC_OPS(add, +=) 119 ATOMIC_OPS(sub, -=) 120 121 #define arch_atomic_add_return arch_atomic_add_return 122 #define arch_atomic_sub_return arch_atomic_sub_return 123 #define arch_atomic_fetch_add arch_atomic_fetch_add 124 #define arch_atomic_fetch_sub arch_atomic_fetch_sub 125 126 #undef ATOMIC_OPS 127 #define ATOMIC_OPS(op, c_op) \ 128 ATOMIC_OP(op, c_op) \ 129 ATOMIC_FETCH_OP(op, c_op) 130 131 ATOMIC_OPS(and, &=) 132 ATOMIC_OPS(or, |=) 133 ATOMIC_OPS(xor, ^=) 134 135 #define arch_atomic_fetch_and arch_atomic_fetch_and 136 #define arch_atomic_fetch_or arch_atomic_fetch_or 137 #define arch_atomic_fetch_xor arch_atomic_fetch_xor 138 139 #undef ATOMIC_OPS 140 #undef ATOMIC_FETCH_OP 141 #undef ATOMIC_OP_RETURN 142 #undef ATOMIC_OP 143 144 #ifdef CONFIG_64BIT 145 146 #define ATOMIC64_INIT(i) { (i) } 147 148 #define ATOMIC64_OP(op, c_op) \ 149 static __inline__ void arch_atomic64_##op(s64 i, atomic64_t *v) \ 150 { \ 151 unsigned long flags; \ 152 \ 153 _atomic_spin_lock_irqsave(v, flags); \ 154 v->counter c_op i; \ 155 _atomic_spin_unlock_irqrestore(v, flags); \ 156 } 157 158 #define ATOMIC64_OP_RETURN(op, c_op) \ 159 static __inline__ s64 arch_atomic64_##op##_return(s64 i, atomic64_t *v) \ 160 { \ 161 unsigned long flags; \ 162 s64 ret; \ 163 \ 164 _atomic_spin_lock_irqsave(v, flags); \ 165 ret = (v->counter c_op i); \ 166 _atomic_spin_unlock_irqrestore(v, flags); \ 167 \ 168 return ret; \ 169 } 170 171 #define ATOMIC64_FETCH_OP(op, c_op) \ 172 static __inline__ s64 arch_atomic64_fetch_##op(s64 i, atomic64_t *v) \ 173 { \ 174 unsigned long flags; \ 175 s64 ret; \ 176 \ 177 _atomic_spin_lock_irqsave(v, flags); \ 178 ret = v->counter; \ 179 v->counter c_op i; \ 180 _atomic_spin_unlock_irqrestore(v, flags); \ 181 \ 182 return ret; \ 183 } 184 185 #define ATOMIC64_OPS(op, c_op) \ 186 ATOMIC64_OP(op, c_op) \ 187 ATOMIC64_OP_RETURN(op, c_op) \ 188 ATOMIC64_FETCH_OP(op, c_op) 189 190 ATOMIC64_OPS(add, +=) 191 ATOMIC64_OPS(sub, -=) 192 193 #define arch_atomic64_add_return arch_atomic64_add_return 194 #define arch_atomic64_sub_return arch_atomic64_sub_return 195 #define arch_atomic64_fetch_add arch_atomic64_fetch_add 196 #define arch_atomic64_fetch_sub arch_atomic64_fetch_sub 197 198 #undef ATOMIC64_OPS 199 #define ATOMIC64_OPS(op, c_op) \ 200 ATOMIC64_OP(op, c_op) \ 201 ATOMIC64_FETCH_OP(op, c_op) 202 203 ATOMIC64_OPS(and, &=) 204 ATOMIC64_OPS(or, |=) 205 ATOMIC64_OPS(xor, ^=) 206 207 #define arch_atomic64_fetch_and arch_atomic64_fetch_and 208 #define arch_atomic64_fetch_or arch_atomic64_fetch_or 209 #define arch_atomic64_fetch_xor arch_atomic64_fetch_xor 210 211 #undef ATOMIC64_OPS 212 #undef ATOMIC64_FETCH_OP 213 #undef ATOMIC64_OP_RETURN 214 #undef ATOMIC64_OP 215 216 static __inline__ void 217 arch_atomic64_set(atomic64_t *v, s64 i) 218 { 219 unsigned long flags; 220 _atomic_spin_lock_irqsave(v, flags); 221 222 v->counter = i; 223 224 _atomic_spin_unlock_irqrestore(v, flags); 225 } 226 227 #define arch_atomic64_set_release(v, i) arch_atomic64_set((v), (i)) 228 229 static __inline__ s64 230 arch_atomic64_read(const atomic64_t *v) 231 { 232 return READ_ONCE((v)->counter); 233 } 234 235 #endif /* !CONFIG_64BIT */ 236 237 238 #endif /* _ASM_PARISC_ATOMIC_H_ */ 239