1#ifndef _ASM_M32R_CMPXCHG_H
2#define _ASM_M32R_CMPXCHG_H
3
4/*
5 *  M32R version:
6 *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
7 *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
8 */
9
10#include <linux/irqflags.h>
11#include <asm/assembler.h>
12#include <asm/dcache_clear.h>
13
14extern void  __xchg_called_with_bad_pointer(void);
15
16static __always_inline unsigned long
17__xchg(unsigned long x, volatile void *ptr, int size)
18{
19	unsigned long flags;
20	unsigned long tmp = 0;
21
22	local_irq_save(flags);
23
24	switch (size) {
25#ifndef CONFIG_SMP
26	case 1:
27		__asm__ __volatile__ (
28			"ldb	%0, @%2 \n\t"
29			"stb	%1, @%2 \n\t"
30			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
31		break;
32	case 2:
33		__asm__ __volatile__ (
34			"ldh	%0, @%2 \n\t"
35			"sth	%1, @%2 \n\t"
36			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
37		break;
38	case 4:
39		__asm__ __volatile__ (
40			"ld	%0, @%2 \n\t"
41			"st	%1, @%2 \n\t"
42			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
43		break;
44#else  /* CONFIG_SMP */
45	case 4:
46		__asm__ __volatile__ (
47			DCACHE_CLEAR("%0", "r4", "%2")
48			"lock	%0, @%2;	\n\t"
49			"unlock	%1, @%2;	\n\t"
50			: "=&r" (tmp) : "r" (x), "r" (ptr)
51			: "memory"
52#ifdef CONFIG_CHIP_M32700_TS1
53			, "r4"
54#endif	/* CONFIG_CHIP_M32700_TS1 */
55		);
56		break;
57#endif  /* CONFIG_SMP */
58	default:
59		__xchg_called_with_bad_pointer();
60	}
61
62	local_irq_restore(flags);
63
64	return (tmp);
65}
66
67#define xchg(ptr, x)							\
68	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
69
70static __always_inline unsigned long
71__xchg_local(unsigned long x, volatile void *ptr, int size)
72{
73	unsigned long flags;
74	unsigned long tmp = 0;
75
76	local_irq_save(flags);
77
78	switch (size) {
79	case 1:
80		__asm__ __volatile__ (
81			"ldb	%0, @%2 \n\t"
82			"stb	%1, @%2 \n\t"
83			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
84		break;
85	case 2:
86		__asm__ __volatile__ (
87			"ldh	%0, @%2 \n\t"
88			"sth	%1, @%2 \n\t"
89			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
90		break;
91	case 4:
92		__asm__ __volatile__ (
93			"ld	%0, @%2 \n\t"
94			"st	%1, @%2 \n\t"
95			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
96		break;
97	default:
98		__xchg_called_with_bad_pointer();
99	}
100
101	local_irq_restore(flags);
102
103	return (tmp);
104}
105
106#define xchg_local(ptr, x)						\
107	((__typeof__(*(ptr)))__xchg_local((unsigned long)(x), (ptr),	\
108			sizeof(*(ptr))))
109
110#define __HAVE_ARCH_CMPXCHG	1
111
112static inline unsigned long
113__cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
114{
115	unsigned long flags;
116	unsigned int retval;
117
118	local_irq_save(flags);
119	__asm__ __volatile__ (
120			DCACHE_CLEAR("%0", "r4", "%1")
121			M32R_LOCK" %0, @%1;	\n"
122		"	bne	%0, %2, 1f;	\n"
123			M32R_UNLOCK" %3, @%1;	\n"
124		"	bra	2f;		\n"
125                "       .fillinsn		\n"
126		"1:"
127			M32R_UNLOCK" %0, @%1;	\n"
128                "       .fillinsn		\n"
129		"2:"
130			: "=&r" (retval)
131			: "r" (p), "r" (old), "r" (new)
132			: "cbit", "memory"
133#ifdef CONFIG_CHIP_M32700_TS1
134			, "r4"
135#endif  /* CONFIG_CHIP_M32700_TS1 */
136		);
137	local_irq_restore(flags);
138
139	return retval;
140}
141
142static inline unsigned long
143__cmpxchg_local_u32(volatile unsigned int *p, unsigned int old,
144			unsigned int new)
145{
146	unsigned long flags;
147	unsigned int retval;
148
149	local_irq_save(flags);
150	__asm__ __volatile__ (
151			DCACHE_CLEAR("%0", "r4", "%1")
152			"ld %0, @%1;		\n"
153		"	bne	%0, %2, 1f;	\n"
154			"st %3, @%1;		\n"
155		"	bra	2f;		\n"
156		"       .fillinsn		\n"
157		"1:"
158			"st %0, @%1;		\n"
159		"       .fillinsn		\n"
160		"2:"
161			: "=&r" (retval)
162			: "r" (p), "r" (old), "r" (new)
163			: "cbit", "memory"
164#ifdef CONFIG_CHIP_M32700_TS1
165			, "r4"
166#endif  /* CONFIG_CHIP_M32700_TS1 */
167		);
168	local_irq_restore(flags);
169
170	return retval;
171}
172
173/* This function doesn't exist, so you'll get a linker error
174   if something tries to do an invalid cmpxchg().  */
175extern void __cmpxchg_called_with_bad_pointer(void);
176
177static inline unsigned long
178__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
179{
180	switch (size) {
181	case 4:
182		return __cmpxchg_u32(ptr, old, new);
183#if 0	/* we don't have __cmpxchg_u64 */
184	case 8:
185		return __cmpxchg_u64(ptr, old, new);
186#endif /* 0 */
187	}
188	__cmpxchg_called_with_bad_pointer();
189	return old;
190}
191
192#define cmpxchg(ptr, o, n)						 \
193	((__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)(o),	 \
194			(unsigned long)(n), sizeof(*(ptr))))
195
196#include <asm-generic/cmpxchg-local.h>
197
198static inline unsigned long __cmpxchg_local(volatile void *ptr,
199				      unsigned long old,
200				      unsigned long new, int size)
201{
202	switch (size) {
203	case 4:
204		return __cmpxchg_local_u32(ptr, old, new);
205	default:
206		return __cmpxchg_local_generic(ptr, old, new, size);
207	}
208
209	return old;
210}
211
212/*
213 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
214 * them available.
215 */
216#define cmpxchg_local(ptr, o, n)				  	    \
217	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	    \
218			(unsigned long)(n), sizeof(*(ptr))))
219#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
220
221#endif /* _ASM_M32R_CMPXCHG_H */
222