blob: 11f96f40f4a79f293ffa4fb5766e222b9042d751 [file] [log] [blame]
Thomas Gleixnerb4d0d232019-05-20 19:08:01 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Arnd Bergmann3f7e2122009-05-13 22:56:35 +00002/*
Arun Sharmaacac43e2011-07-26 16:09:08 -07003 * Generic C implementation of atomic counter operations. Usable on
4 * UP systems only. Do not include in machine independent code.
5 *
Arnd Bergmann3f7e2122009-05-13 22:56:35 +00006 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
7 * Written by David Howells (dhowells@redhat.com)
Arnd Bergmann3f7e2122009-05-13 22:56:35 +00008 */
9#ifndef __ASM_GENERIC_ATOMIC_H
10#define __ASM_GENERIC_ATOMIC_H
11
David Howells34484272012-03-28 18:30:03 +010012#include <asm/cmpxchg.h>
Peter Zijlstrafebdbfe2014-02-06 18:16:07 +010013#include <asm/barrier.h>
David Howells34484272012-03-28 18:30:03 +010014
Peter Zijlstra560cb122014-04-23 16:12:30 +020015/*
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
Arnd Bergmann3f7e2122009-05-13 22:56:35 +000032#ifdef CONFIG_SMP
Peter Zijlstra560cb122014-04-23 16:12:30 +020033
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
Peter Zijlstra28aa2bd2016-04-18 00:54:38 +020058#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
Peter Zijlstra560cb122014-04-23 16:12:30 +020070#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
Peter Zijlstra28aa2bd2016-04-18 00:54:38 +020097#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
Peter Zijlstra560cb122014-04-23 16:12:30 +0200111#endif /* CONFIG_SMP */
112
113#ifndef atomic_add_return
114ATOMIC_OP_RETURN(add, +)
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000115#endif
116
Peter Zijlstra560cb122014-04-23 16:12:30 +0200117#ifndef atomic_sub_return
118ATOMIC_OP_RETURN(sub, -)
119#endif
120
Peter Zijlstra28aa2bd2016-04-18 00:54:38 +0200121#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
Peter Zijlstra28aa2bd2016-04-18 00:54:38 +0200134ATOMIC_FETCH_OP(or, |)
135#endif
136
137#ifndef atomic_fetch_xor
138ATOMIC_FETCH_OP(xor, ^)
139#endif
140
Peter Zijlstra56d1def2015-07-15 15:47:25 +0200141#ifndef atomic_and
Peter Zijlstra560cb122014-04-23 16:12:30 +0200142ATOMIC_OP(and, &)
Peter Zijlstra56d1def2015-07-15 15:47:25 +0200143#endif
144
Peter Zijlstra56d1def2015-07-15 15:47:25 +0200145#ifndef atomic_or
Peter Zijlstra560cb122014-04-23 16:12:30 +0200146ATOMIC_OP(or, |)
Peter Zijlstra56d1def2015-07-15 15:47:25 +0200147#endif
148
Peter Zijlstrae6942b72014-04-23 19:32:50 +0200149#ifndef atomic_xor
150ATOMIC_OP(xor, ^)
Peter Zijlstra560cb122014-04-23 16:12:30 +0200151#endif
152
Peter Zijlstra28aa2bd2016-04-18 00:54:38 +0200153#undef ATOMIC_FETCH_OP
Peter Zijlstra560cb122014-04-23 16:12:30 +0200154#undef ATOMIC_OP_RETURN
155#undef ATOMIC_OP
156
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000157/*
158 * Atomic operations that C can't guarantee us. Useful for
159 * resource counting etc..
160 */
161
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000162/**
163 * atomic_read - read atomic variable
164 * @v: pointer of type atomic_t
165 *
Peter Fritzsche37682172010-05-24 14:33:09 -0700166 * Atomically reads the value of @v.
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000167 */
Mike Frysinger7505cb62011-07-26 16:09:11 -0700168#ifndef atomic_read
Peter Zijlstra62e8a322015-09-18 11:13:10 +0200169#define atomic_read(v) READ_ONCE((v)->counter)
Mike Frysinger7505cb62011-07-26 16:09:11 -0700170#endif
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000171
172/**
173 * atomic_set - set atomic variable
174 * @v: pointer of type atomic_t
175 * @i: required value
176 *
Peter Fritzsche37682172010-05-24 14:33:09 -0700177 * Atomically sets the value of @v to @i.
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000178 */
Peter Zijlstra62e8a322015-09-18 11:13:10 +0200179#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000180
David Howellsdf9ee292010-10-07 14:08:55 +0100181#include <linux/irqflags.h>
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000182
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000183static 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
Mathieu Lacage8b9d4062010-06-27 12:26:06 +0200193#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v)))
194#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
195
Arnd Bergmann3f7e2122009-05-13 22:56:35 +0000196#endif /* __ASM_GENERIC_ATOMIC_H */