at v5.13 4.2 kB view raw
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) \ 37static 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) \ 47static 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) \ 59static 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) \ 75static 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) \ 85static 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) \ 98static 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 114ATOMIC_OP_RETURN(add, +) 115#endif 116 117#ifndef atomic_sub_return 118ATOMIC_OP_RETURN(sub, -) 119#endif 120 121#ifndef atomic_fetch_add 122ATOMIC_FETCH_OP(add, +) 123#endif 124 125#ifndef atomic_fetch_sub 126ATOMIC_FETCH_OP(sub, -) 127#endif 128 129#ifndef atomic_fetch_and 130ATOMIC_FETCH_OP(and, &) 131#endif 132 133#ifndef atomic_fetch_or 134ATOMIC_FETCH_OP(or, |) 135#endif 136 137#ifndef atomic_fetch_xor 138ATOMIC_FETCH_OP(xor, ^) 139#endif 140 141#ifndef atomic_and 142ATOMIC_OP(and, &) 143#endif 144 145#ifndef atomic_or 146ATOMIC_OP(or, |) 147#endif 148 149#ifndef atomic_xor 150ATOMIC_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 183static inline void atomic_add(int i, atomic_t *v) 184{ 185 atomic_add_return(i, v); 186} 187 188static 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 */