xref: /OK3568_Linux_fs/kernel/arch/arc/include/asm/cmpxchg.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #ifndef __ASM_ARC_CMPXCHG_H
7*4882a593Smuzhiyun #define __ASM_ARC_CMPXCHG_H
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/types.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <asm/barrier.h>
12*4882a593Smuzhiyun #include <asm/smp.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #ifdef CONFIG_ARC_HAS_LLSC
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun static inline unsigned long
__cmpxchg(volatile void * ptr,unsigned long expected,unsigned long new)17*4882a593Smuzhiyun __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun 	unsigned long prev;
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun 	/*
22*4882a593Smuzhiyun 	 * Explicit full memory barrier needed before/after as
23*4882a593Smuzhiyun 	 * LLOCK/SCOND themselves don't provide any such semantics
24*4882a593Smuzhiyun 	 */
25*4882a593Smuzhiyun 	smp_mb();
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 	__asm__ __volatile__(
28*4882a593Smuzhiyun 	"1:	llock   %0, [%1]	\n"
29*4882a593Smuzhiyun 	"	brne    %0, %2, 2f	\n"
30*4882a593Smuzhiyun 	"	scond   %3, [%1]	\n"
31*4882a593Smuzhiyun 	"	bnz     1b		\n"
32*4882a593Smuzhiyun 	"2:				\n"
33*4882a593Smuzhiyun 	: "=&r"(prev)	/* Early clobber, to prevent reg reuse */
34*4882a593Smuzhiyun 	: "r"(ptr),	/* Not "m": llock only supports reg direct addr mode */
35*4882a593Smuzhiyun 	  "ir"(expected),
36*4882a593Smuzhiyun 	  "r"(new)	/* can't be "ir". scond can't take LIMM for "b" */
37*4882a593Smuzhiyun 	: "cc", "memory"); /* so that gcc knows memory is being written here */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	smp_mb();
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	return prev;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #else /* !CONFIG_ARC_HAS_LLSC */
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static inline unsigned long
__cmpxchg(volatile void * ptr,unsigned long expected,unsigned long new)47*4882a593Smuzhiyun __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	unsigned long flags;
50*4882a593Smuzhiyun 	int prev;
51*4882a593Smuzhiyun 	volatile unsigned long *p = ptr;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	/*
54*4882a593Smuzhiyun 	 * spin lock/unlock provide the needed smp_mb() before/after
55*4882a593Smuzhiyun 	 */
56*4882a593Smuzhiyun 	atomic_ops_lock(flags);
57*4882a593Smuzhiyun 	prev = *p;
58*4882a593Smuzhiyun 	if (prev == expected)
59*4882a593Smuzhiyun 		*p = new;
60*4882a593Smuzhiyun 	atomic_ops_unlock(flags);
61*4882a593Smuzhiyun 	return prev;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #endif
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define cmpxchg(ptr, o, n) ({				\
67*4882a593Smuzhiyun 	(typeof(*(ptr)))__cmpxchg((ptr),		\
68*4882a593Smuzhiyun 				  (unsigned long)(o),	\
69*4882a593Smuzhiyun 				  (unsigned long)(n));	\
70*4882a593Smuzhiyun })
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /*
73*4882a593Smuzhiyun  * atomic_cmpxchg is same as cmpxchg
74*4882a593Smuzhiyun  *   LLSC: only different in data-type, semantics are exactly same
75*4882a593Smuzhiyun  *  !LLSC: cmpxchg() has to use an external lock atomic_ops_lock to guarantee
76*4882a593Smuzhiyun  *         semantics, and this lock also happens to be used by atomic_*()
77*4882a593Smuzhiyun  */
78*4882a593Smuzhiyun #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /*
82*4882a593Smuzhiyun  * xchg (reg with memory) based on "Native atomic" EX insn
83*4882a593Smuzhiyun  */
__xchg(unsigned long val,volatile void * ptr,int size)84*4882a593Smuzhiyun static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
85*4882a593Smuzhiyun 				   int size)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	extern unsigned long __xchg_bad_pointer(void);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	switch (size) {
90*4882a593Smuzhiyun 	case 4:
91*4882a593Smuzhiyun 		smp_mb();
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 		__asm__ __volatile__(
94*4882a593Smuzhiyun 		"	ex  %0, [%1]	\n"
95*4882a593Smuzhiyun 		: "+r"(val)
96*4882a593Smuzhiyun 		: "r"(ptr)
97*4882a593Smuzhiyun 		: "memory");
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 		smp_mb();
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 		return val;
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun 	return __xchg_bad_pointer();
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun #define _xchg(ptr, with) ((typeof(*(ptr)))__xchg((unsigned long)(with), (ptr), \
107*4882a593Smuzhiyun 						 sizeof(*(ptr))))
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /*
110*4882a593Smuzhiyun  * xchg() maps directly to ARC EX instruction which guarantees atomicity.
111*4882a593Smuzhiyun  * However in !LLSC config, it also needs to be use @atomic_ops_lock spinlock
112*4882a593Smuzhiyun  * due to a subtle reason:
113*4882a593Smuzhiyun  *  - For !LLSC, cmpxchg() needs to use that lock (see above) and there is lot
114*4882a593Smuzhiyun  *    of  kernel code which calls xchg()/cmpxchg() on same data (see llist.h)
115*4882a593Smuzhiyun  *    Hence xchg() needs to follow same locking rules.
116*4882a593Smuzhiyun  *
117*4882a593Smuzhiyun  * Technically the lock is also needed for UP (boils down to irq save/restore)
118*4882a593Smuzhiyun  * but we can cheat a bit since cmpxchg() atomic_ops_lock() would cause irqs to
119*4882a593Smuzhiyun  * be disabled thus can't possibly be interrpted/preempted/clobbered by xchg()
120*4882a593Smuzhiyun  * Other way around, xchg is one instruction anyways, so can't be interrupted
121*4882a593Smuzhiyun  * as such
122*4882a593Smuzhiyun  */
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun #if !defined(CONFIG_ARC_HAS_LLSC) && defined(CONFIG_SMP)
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun #define xchg(ptr, with)			\
127*4882a593Smuzhiyun ({					\
128*4882a593Smuzhiyun 	unsigned long flags;		\
129*4882a593Smuzhiyun 	typeof(*(ptr)) old_val;		\
130*4882a593Smuzhiyun 					\
131*4882a593Smuzhiyun 	atomic_ops_lock(flags);		\
132*4882a593Smuzhiyun 	old_val = _xchg(ptr, with);	\
133*4882a593Smuzhiyun 	atomic_ops_unlock(flags);	\
134*4882a593Smuzhiyun 	old_val;			\
135*4882a593Smuzhiyun })
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun #else
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun #define xchg(ptr, with)  _xchg(ptr, with)
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun #endif
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun /*
144*4882a593Smuzhiyun  * "atomic" variant of xchg()
145*4882a593Smuzhiyun  * REQ: It needs to follow the same serialization rules as other atomic_xxx()
146*4882a593Smuzhiyun  * Since xchg() doesn't always do that, it would seem that following defintion
147*4882a593Smuzhiyun  * is incorrect. But here's the rationale:
148*4882a593Smuzhiyun  *   SMP : Even xchg() takes the atomic_ops_lock, so OK.
149*4882a593Smuzhiyun  *   LLSC: atomic_ops_lock are not relevant at all (even if SMP, since LLSC
150*4882a593Smuzhiyun  *         is natively "SMP safe", no serialization required).
151*4882a593Smuzhiyun  *   UP  : other atomics disable IRQ, so no way a difft ctxt atomic_xchg()
152*4882a593Smuzhiyun  *         could clobber them. atomic_xchg() itself would be 1 insn, so it
153*4882a593Smuzhiyun  *         can't be clobbered by others. Thus no serialization required when
154*4882a593Smuzhiyun  *         atomic_xchg is involved.
155*4882a593Smuzhiyun  */
156*4882a593Smuzhiyun #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun #endif
159