xref: /linux/arch/arc/include/asm/atomic-spinlock.h (revision 6e7fd890f1d6ac83805409e9c346240de2705584)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #ifndef _ASM_ARC_ATOMIC_SPLOCK_H
4 #define _ASM_ARC_ATOMIC_SPLOCK_H
5 
6 /*
7  * Non hardware assisted Atomic-R-M-W
8  * Locking would change to irq-disabling only (UP) and spinlocks (SMP)
9  */
10 
11 static inline void arch_atomic_set(atomic_t *v, int i)
12 {
13 	/*
14 	 * Independent of hardware support, all of the atomic_xxx() APIs need
15 	 * to follow the same locking rules to make sure that a "hardware"
16 	 * atomic insn (e.g. LD) doesn't clobber an "emulated" atomic insn
17 	 * sequence
18 	 *
19 	 * Thus atomic_set() despite being 1 insn (and seemingly atomic)
20 	 * requires the locking.
21 	 */
22 	unsigned long flags;
23 
24 	atomic_ops_lock(flags);
25 	WRITE_ONCE(v->counter, i);
26 	atomic_ops_unlock(flags);
27 }
28 
29 #define arch_atomic_set_release(v, i)	arch_atomic_set((v), (i))
30 
31 #define ATOMIC_OP(op, c_op, asm_op)					\
32 static inline void arch_atomic_##op(int i, atomic_t *v)			\
33 {									\
34 	unsigned long flags;						\
35 									\
36 	atomic_ops_lock(flags);						\
37 	v->counter c_op i;						\
38 	atomic_ops_unlock(flags);					\
39 }
40 
41 #define ATOMIC_OP_RETURN(op, c_op, asm_op)				\
42 static inline int arch_atomic_##op##_return(int i, atomic_t *v)		\
43 {									\
44 	unsigned long flags;						\
45 	unsigned int temp;						\
46 									\
47 	/*								\
48 	 * spin lock/unlock provides the needed smp_mb() before/after	\
49 	 */								\
50 	atomic_ops_lock(flags);						\
51 	temp = v->counter;						\
52 	temp c_op i;							\
53 	v->counter = temp;						\
54 	atomic_ops_unlock(flags);					\
55 									\
56 	return temp;							\
57 }
58 
59 #define ATOMIC_FETCH_OP(op, c_op, asm_op)				\
60 static inline int arch_atomic_fetch_##op(int i, atomic_t *v)		\
61 {									\
62 	unsigned long flags;						\
63 	unsigned int orig;						\
64 									\
65 	/*								\
66 	 * spin lock/unlock provides the needed smp_mb() before/after	\
67 	 */								\
68 	atomic_ops_lock(flags);						\
69 	orig = v->counter;						\
70 	v->counter c_op i;						\
71 	atomic_ops_unlock(flags);					\
72 									\
73 	return orig;							\
74 }
75 
76 #define ATOMIC_OPS(op, c_op, asm_op)					\
77 	ATOMIC_OP(op, c_op, asm_op)					\
78 	ATOMIC_OP_RETURN(op, c_op, asm_op)				\
79 	ATOMIC_FETCH_OP(op, c_op, asm_op)
80 
81 ATOMIC_OPS(add, +=, add)
82 ATOMIC_OPS(sub, -=, sub)
83 
84 #define arch_atomic_fetch_add		arch_atomic_fetch_add
85 #define arch_atomic_fetch_sub		arch_atomic_fetch_sub
86 #define arch_atomic_add_return		arch_atomic_add_return
87 #define arch_atomic_sub_return		arch_atomic_sub_return
88 
89 #undef ATOMIC_OPS
90 #define ATOMIC_OPS(op, c_op, asm_op)					\
91 	ATOMIC_OP(op, c_op, asm_op)					\
92 	ATOMIC_FETCH_OP(op, c_op, asm_op)
93 
94 ATOMIC_OPS(and, &=, and)
95 ATOMIC_OPS(andnot, &= ~, bic)
96 ATOMIC_OPS(or, |=, or)
97 ATOMIC_OPS(xor, ^=, xor)
98 
99 #define arch_atomic_andnot		arch_atomic_andnot
100 
101 #define arch_atomic_fetch_and		arch_atomic_fetch_and
102 #define arch_atomic_fetch_andnot	arch_atomic_fetch_andnot
103 #define arch_atomic_fetch_or		arch_atomic_fetch_or
104 #define arch_atomic_fetch_xor		arch_atomic_fetch_xor
105 
106 #undef ATOMIC_OPS
107 #undef ATOMIC_FETCH_OP
108 #undef ATOMIC_OP_RETURN
109 #undef ATOMIC_OP
110 
111 #endif
112