1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Generic C implementation of atomic counter operations. Usable on 4 * UP systems only. Do not include in machine independent code. 5 * 6 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 7 * Written by David Howells (dhowells@redhat.com) 8 */ 9 #ifndef __ASM_GENERIC_ATOMIC_H 10 #define __ASM_GENERIC_ATOMIC_H 11 12 #include <asm/cmpxchg.h> 13 #include <asm/barrier.h> 14 15 /* 16 * atomic_$op() - $op integer to atomic variable 17 * @i: integer value to $op 18 * @v: pointer to the atomic variable 19 * 20 * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use 21 * smp_mb__{before,after}_atomic(). 22 */ 23 24 /* 25 * atomic_$op_return() - $op interer to atomic variable and returns the result 26 * @i: integer value to $op 27 * @v: pointer to the atomic variable 28 * 29 * Atomically $ops @i to @v. Does imply a full memory barrier. 30 */ 31 32 #ifdef CONFIG_SMP 33 34 /* we can build all atomic primitives from cmpxchg */ 35 36 #define ATOMIC_OP(op, c_op) \ 37 static inline void atomic_##op(int i, atomic_t *v) \ 38 { \ 39 int c, old; \ 40 \ 41 c = v->counter; \ 42 while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ 43 c = old; \ 44 } 45 46 #define ATOMIC_OP_RETURN(op, c_op) \ 47 static inline int atomic_##op##_return(int i, atomic_t *v) \ 48 { \ 49 int c, old; \ 50 \ 51 c = v->counter; \ 52 while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ 53 c = old; \ 54 \ 55 return c c_op i; \ 56 } 57 58 #define ATOMIC_FETCH_OP(op, c_op) \ 59 static inline int atomic_fetch_##op(int i, atomic_t *v) \ 60 { \ 61 int c, old; \ 62 \ 63 c = v->counter; \ 64 while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ 65 c = old; \ 66 \ 67 return c; \ 68 } 69 70 #else 71 72 #include <linux/irqflags.h> 73 74 #define ATOMIC_OP(op, c_op) \ 75 static inline void atomic_##op(int i, atomic_t *v) \ 76 { \ 77 unsigned long flags; \ 78 \ 79 raw_local_irq_save(flags); \ 80 v->counter = v->counter c_op i; \ 81 raw_local_irq_restore(flags); \ 82 } 83 84 #define ATOMIC_OP_RETURN(op, c_op) \ 85 static inline int atomic_##op##_return(int i, atomic_t *v) \ 86 { \ 87 unsigned long flags; \ 88 int ret; \ 89 \ 90 raw_local_irq_save(flags); \ 91 ret = (v->counter = v->counter c_op i); \ 92 raw_local_irq_restore(flags); \ 93 \ 94 return ret; \ 95 } 96 97 #define ATOMIC_FETCH_OP(op, c_op) \ 98 static inline int atomic_fetch_##op(int i, atomic_t *v) \ 99 { \ 100 unsigned long flags; \ 101 int ret; \ 102 \ 103 raw_local_irq_save(flags); \ 104 ret = v->counter; \ 105 v->counter = v->counter c_op i; \ 106 raw_local_irq_restore(flags); \ 107 \ 108 return ret; \ 109 } 110 111 #endif /* CONFIG_SMP */ 112 113 #ifndef atomic_add_return 114 ATOMIC_OP_RETURN(add, +) 115 #endif 116 117 #ifndef atomic_sub_return 118 ATOMIC_OP_RETURN(sub, -) 119 #endif 120 121 #ifndef atomic_fetch_add 122 ATOMIC_FETCH_OP(add, +) 123 #endif 124 125 #ifndef atomic_fetch_sub 126 ATOMIC_FETCH_OP(sub, -) 127 #endif 128 129 #ifndef atomic_fetch_and 130 ATOMIC_FETCH_OP(and, &) 131 #endif 132 133 #ifndef atomic_fetch_or 134 ATOMIC_FETCH_OP(or, |) 135 #endif 136 137 #ifndef atomic_fetch_xor 138 ATOMIC_FETCH_OP(xor, ^) 139 #endif 140 141 #ifndef atomic_and 142 ATOMIC_OP(and, &) 143 #endif 144 145 #ifndef atomic_or 146 ATOMIC_OP(or, |) 147 #endif 148 149 #ifndef atomic_xor 150 ATOMIC_OP(xor, ^) 151 #endif 152 153 #undef ATOMIC_FETCH_OP 154 #undef ATOMIC_OP_RETURN 155 #undef ATOMIC_OP 156 157 /* 158 * Atomic operations that C can't guarantee us. Useful for 159 * resource counting etc.. 160 */ 161 162 /** 163 * atomic_read - read atomic variable 164 * @v: pointer of type atomic_t 165 * 166 * Atomically reads the value of @v. 167 */ 168 #ifndef atomic_read 169 #define atomic_read(v) READ_ONCE((v)->counter) 170 #endif 171 172 /** 173 * atomic_set - set atomic variable 174 * @v: pointer of type atomic_t 175 * @i: required value 176 * 177 * Atomically sets the value of @v to @i. 178 */ 179 #define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) 180 181 #include <linux/irqflags.h> 182 183 static inline void atomic_add(int i, atomic_t *v) 184 { 185 atomic_add_return(i, v); 186 } 187 188 static inline void atomic_sub(int i, atomic_t *v) 189 { 190 atomic_sub_return(i, v); 191 } 192 193 #define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) 194 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 195 196 #endif /* __ASM_GENERIC_ATOMIC_H */ 197