1#ifndef __ASM_CMPXCHG_H
2#define __ASM_CMPXCHG_H
3
4#include <asm/alternative.h> /* Provides LOCK_PREFIX */
5
6#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
7
8#define __xg(x) ((volatile long *)(x))
9
10static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
11{
12	*ptr = val;
13}
14
15#define _set_64bit set_64bit
16
17/*
18 * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
19 * Note 2: xchg has side effect, so that attribute volatile is necessary,
20 *	  but generally the primitive is invalid, *ptr is output argument. --ANK
21 */
22static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
23{
24	switch (size) {
25		case 1:
26			__asm__ __volatile__("xchgb %b0,%1"
27				:"=q" (x)
28				:"m" (*__xg(ptr)), "0" (x)
29				:"memory");
30			break;
31		case 2:
32			__asm__ __volatile__("xchgw %w0,%1"
33				:"=r" (x)
34				:"m" (*__xg(ptr)), "0" (x)
35				:"memory");
36			break;
37		case 4:
38			__asm__ __volatile__("xchgl %k0,%1"
39				:"=r" (x)
40				:"m" (*__xg(ptr)), "0" (x)
41				:"memory");
42			break;
43		case 8:
44			__asm__ __volatile__("xchgq %0,%1"
45				:"=r" (x)
46				:"m" (*__xg(ptr)), "0" (x)
47				:"memory");
48			break;
49	}
50	return x;
51}
52
53/*
54 * Atomic compare and exchange.  Compare OLD with MEM, if identical,
55 * store NEW in MEM.  Return the initial value in MEM.  Success is
56 * indicated by comparing RETURN with OLD.
57 */
58
59#define __HAVE_ARCH_CMPXCHG 1
60
61static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
62				      unsigned long new, int size)
63{
64	unsigned long prev;
65	switch (size) {
66	case 1:
67		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
68				     : "=a"(prev)
69				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
70				     : "memory");
71		return prev;
72	case 2:
73		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
74				     : "=a"(prev)
75				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
76				     : "memory");
77		return prev;
78	case 4:
79		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
80				     : "=a"(prev)
81				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
82				     : "memory");
83		return prev;
84	case 8:
85		__asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
86				     : "=a"(prev)
87				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
88				     : "memory");
89		return prev;
90	}
91	return old;
92}
93
94static inline unsigned long __cmpxchg_local(volatile void *ptr,
95			unsigned long old, unsigned long new, int size)
96{
97	unsigned long prev;
98	switch (size) {
99	case 1:
100		__asm__ __volatile__("cmpxchgb %b1,%2"
101				     : "=a"(prev)
102				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
103				     : "memory");
104		return prev;
105	case 2:
106		__asm__ __volatile__("cmpxchgw %w1,%2"
107				     : "=a"(prev)
108				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
109				     : "memory");
110		return prev;
111	case 4:
112		__asm__ __volatile__("cmpxchgl %k1,%2"
113				     : "=a"(prev)
114				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
115				     : "memory");
116		return prev;
117	case 8:
118		__asm__ __volatile__("cmpxchgq %1,%2"
119				     : "=a"(prev)
120				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
121				     : "memory");
122		return prev;
123	}
124	return old;
125}
126
127#define cmpxchg(ptr,o,n)\
128	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
129					(unsigned long)(n),sizeof(*(ptr))))
130#define cmpxchg_local(ptr,o,n)\
131	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
132					(unsigned long)(n),sizeof(*(ptr))))
133
134#endif
135