xref: /openbmc/linux/include/asm-generic/atomic.h (revision 2609a195fbd58f77d281c013f10b8dbaffca1637)
1b4d0d230SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
23f7e212dSArnd Bergmann /*
3*2609a195SMark Rutland  * Generic C implementation of atomic counter operations. Do not include in
4*2609a195SMark Rutland  * machine independent code.
5acac43e2SArun Sharma  *
63f7e212dSArnd Bergmann  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
73f7e212dSArnd Bergmann  * Written by David Howells (dhowells@redhat.com)
83f7e212dSArnd Bergmann  */
93f7e212dSArnd Bergmann #ifndef __ASM_GENERIC_ATOMIC_H
103f7e212dSArnd Bergmann #define __ASM_GENERIC_ATOMIC_H
113f7e212dSArnd Bergmann 
1234484277SDavid Howells #include <asm/cmpxchg.h>
13febdbfe8SPeter Zijlstra #include <asm/barrier.h>
1434484277SDavid Howells 
153f7e212dSArnd Bergmann #ifdef CONFIG_SMP
16560cb12aSPeter Zijlstra 
17560cb12aSPeter Zijlstra /* we can build all atomic primitives from cmpxchg */
18560cb12aSPeter Zijlstra 
19560cb12aSPeter Zijlstra #define ATOMIC_OP(op, c_op)						\
20560cb12aSPeter Zijlstra static inline void atomic_##op(int i, atomic_t *v)			\
21560cb12aSPeter Zijlstra {									\
22560cb12aSPeter Zijlstra 	int c, old;							\
23560cb12aSPeter Zijlstra 									\
24560cb12aSPeter Zijlstra 	c = v->counter;							\
25560cb12aSPeter Zijlstra 	while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)		\
26560cb12aSPeter Zijlstra 		c = old;						\
27560cb12aSPeter Zijlstra }
28560cb12aSPeter Zijlstra 
29560cb12aSPeter Zijlstra #define ATOMIC_OP_RETURN(op, c_op)					\
30560cb12aSPeter Zijlstra static inline int atomic_##op##_return(int i, atomic_t *v)		\
31560cb12aSPeter Zijlstra {									\
32560cb12aSPeter Zijlstra 	int c, old;							\
33560cb12aSPeter Zijlstra 									\
34560cb12aSPeter Zijlstra 	c = v->counter;							\
35560cb12aSPeter Zijlstra 	while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)		\
36560cb12aSPeter Zijlstra 		c = old;						\
37560cb12aSPeter Zijlstra 									\
38560cb12aSPeter Zijlstra 	return c c_op i;						\
39560cb12aSPeter Zijlstra }
40560cb12aSPeter Zijlstra 
4128aa2bdaSPeter Zijlstra #define ATOMIC_FETCH_OP(op, c_op)					\
4228aa2bdaSPeter Zijlstra static inline int atomic_fetch_##op(int i, atomic_t *v)			\
4328aa2bdaSPeter Zijlstra {									\
4428aa2bdaSPeter Zijlstra 	int c, old;							\
4528aa2bdaSPeter Zijlstra 									\
4628aa2bdaSPeter Zijlstra 	c = v->counter;							\
4728aa2bdaSPeter Zijlstra 	while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)		\
4828aa2bdaSPeter Zijlstra 		c = old;						\
4928aa2bdaSPeter Zijlstra 									\
5028aa2bdaSPeter Zijlstra 	return c;							\
5128aa2bdaSPeter Zijlstra }
5228aa2bdaSPeter Zijlstra 
53560cb12aSPeter Zijlstra #else
54560cb12aSPeter Zijlstra 
55560cb12aSPeter Zijlstra #include <linux/irqflags.h>
56560cb12aSPeter Zijlstra 
57560cb12aSPeter Zijlstra #define ATOMIC_OP(op, c_op)						\
58560cb12aSPeter Zijlstra static inline void atomic_##op(int i, atomic_t *v)			\
59560cb12aSPeter Zijlstra {									\
60560cb12aSPeter Zijlstra 	unsigned long flags;						\
61560cb12aSPeter Zijlstra 									\
62560cb12aSPeter Zijlstra 	raw_local_irq_save(flags);					\
63560cb12aSPeter Zijlstra 	v->counter = v->counter c_op i;					\
64560cb12aSPeter Zijlstra 	raw_local_irq_restore(flags);					\
65560cb12aSPeter Zijlstra }
66560cb12aSPeter Zijlstra 
67560cb12aSPeter Zijlstra #define ATOMIC_OP_RETURN(op, c_op)					\
68560cb12aSPeter Zijlstra static inline int atomic_##op##_return(int i, atomic_t *v)		\
69560cb12aSPeter Zijlstra {									\
70560cb12aSPeter Zijlstra 	unsigned long flags;						\
71560cb12aSPeter Zijlstra 	int ret;							\
72560cb12aSPeter Zijlstra 									\
73560cb12aSPeter Zijlstra 	raw_local_irq_save(flags);					\
74560cb12aSPeter Zijlstra 	ret = (v->counter = v->counter c_op i);				\
75560cb12aSPeter Zijlstra 	raw_local_irq_restore(flags);					\
76560cb12aSPeter Zijlstra 									\
77560cb12aSPeter Zijlstra 	return ret;							\
78560cb12aSPeter Zijlstra }
79560cb12aSPeter Zijlstra 
8028aa2bdaSPeter Zijlstra #define ATOMIC_FETCH_OP(op, c_op)					\
8128aa2bdaSPeter Zijlstra static inline int atomic_fetch_##op(int i, atomic_t *v)			\
8228aa2bdaSPeter Zijlstra {									\
8328aa2bdaSPeter Zijlstra 	unsigned long flags;						\
8428aa2bdaSPeter Zijlstra 	int ret;							\
8528aa2bdaSPeter Zijlstra 									\
8628aa2bdaSPeter Zijlstra 	raw_local_irq_save(flags);					\
8728aa2bdaSPeter Zijlstra 	ret = v->counter;						\
8828aa2bdaSPeter Zijlstra 	v->counter = v->counter c_op i;					\
8928aa2bdaSPeter Zijlstra 	raw_local_irq_restore(flags);					\
9028aa2bdaSPeter Zijlstra 									\
9128aa2bdaSPeter Zijlstra 	return ret;							\
9228aa2bdaSPeter Zijlstra }
9328aa2bdaSPeter Zijlstra 
94560cb12aSPeter Zijlstra #endif /* CONFIG_SMP */
95560cb12aSPeter Zijlstra 
96560cb12aSPeter Zijlstra #ifndef atomic_add_return
97560cb12aSPeter Zijlstra ATOMIC_OP_RETURN(add, +)
987505cb60SMike Frysinger #endif
99560cb12aSPeter Zijlstra 
100560cb12aSPeter Zijlstra #ifndef atomic_sub_return
101560cb12aSPeter Zijlstra ATOMIC_OP_RETURN(sub, -)
1023f7e212dSArnd Bergmann #endif
1033f7e212dSArnd Bergmann 
10428aa2bdaSPeter Zijlstra #ifndef atomic_fetch_add
10528aa2bdaSPeter Zijlstra ATOMIC_FETCH_OP(add, +)
10628aa2bdaSPeter Zijlstra #endif
10728aa2bdaSPeter Zijlstra 
10828aa2bdaSPeter Zijlstra #ifndef atomic_fetch_sub
10928aa2bdaSPeter Zijlstra ATOMIC_FETCH_OP(sub, -)
11028aa2bdaSPeter Zijlstra #endif
11128aa2bdaSPeter Zijlstra 
11228aa2bdaSPeter Zijlstra #ifndef atomic_fetch_and
11328aa2bdaSPeter Zijlstra ATOMIC_FETCH_OP(and, &)
11428aa2bdaSPeter Zijlstra #endif
11528aa2bdaSPeter Zijlstra 
11628aa2bdaSPeter Zijlstra #ifndef atomic_fetch_or
11728aa2bdaSPeter Zijlstra ATOMIC_FETCH_OP(or, |)
11828aa2bdaSPeter Zijlstra #endif
11928aa2bdaSPeter Zijlstra 
12028aa2bdaSPeter Zijlstra #ifndef atomic_fetch_xor
12128aa2bdaSPeter Zijlstra ATOMIC_FETCH_OP(xor, ^)
12228aa2bdaSPeter Zijlstra #endif
12328aa2bdaSPeter Zijlstra 
12456d1defeSPeter Zijlstra #ifndef atomic_and
125560cb12aSPeter Zijlstra ATOMIC_OP(and, &)
12656d1defeSPeter Zijlstra #endif
12756d1defeSPeter Zijlstra 
12856d1defeSPeter Zijlstra #ifndef atomic_or
129560cb12aSPeter Zijlstra ATOMIC_OP(or, |)
13056d1defeSPeter Zijlstra #endif
13156d1defeSPeter Zijlstra 
132e6942b7dSPeter Zijlstra #ifndef atomic_xor
133e6942b7dSPeter Zijlstra ATOMIC_OP(xor, ^)
134560cb12aSPeter Zijlstra #endif
135560cb12aSPeter Zijlstra 
13628aa2bdaSPeter Zijlstra #undef ATOMIC_FETCH_OP
137560cb12aSPeter Zijlstra #undef ATOMIC_OP_RETURN
138560cb12aSPeter Zijlstra #undef ATOMIC_OP
139560cb12aSPeter Zijlstra 
1407505cb60SMike Frysinger #ifndef atomic_read
14162e8a325SPeter Zijlstra #define atomic_read(v)	READ_ONCE((v)->counter)
1427505cb60SMike Frysinger #endif
1433f7e212dSArnd Bergmann 
14462e8a325SPeter Zijlstra #define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
1453f7e212dSArnd Bergmann 
146df9ee292SDavid Howells #include <linux/irqflags.h>
1473f7e212dSArnd Bergmann 
1483f7e212dSArnd Bergmann static inline void atomic_add(int i, atomic_t *v)
1493f7e212dSArnd Bergmann {
1503f7e212dSArnd Bergmann 	atomic_add_return(i, v);
1513f7e212dSArnd Bergmann }
1523f7e212dSArnd Bergmann 
1533f7e212dSArnd Bergmann static inline void atomic_sub(int i, atomic_t *v)
1543f7e212dSArnd Bergmann {
1553f7e212dSArnd Bergmann 	atomic_sub_return(i, v);
1563f7e212dSArnd Bergmann }
1573f7e212dSArnd Bergmann 
1588b9d4069SMathieu Lacage #define atomic_xchg(ptr, v)		(xchg(&(ptr)->counter, (v)))
1598b9d4069SMathieu Lacage #define atomic_cmpxchg(v, old, new)	(cmpxchg(&((v)->counter), (old), (new)))
1608b9d4069SMathieu Lacage 
1613f7e212dSArnd Bergmann #endif /* __ASM_GENERIC_ATOMIC_H */
162