1 /*
2  * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
3  *
4  * This file is licensed under the terms of the GNU General Public License
5  * version 2.  This program is licensed "as is" without any warranty of any
6  * kind, whether express or implied.
7  */
8 
9 #ifndef __ASM_OPENRISC_CMPXCHG_H
10 #define __ASM_OPENRISC_CMPXCHG_H
11 
12 #include  <linux/types.h>
13 
14 /*
15  * This function doesn't exist, so you'll get a linker error
16  * if something tries to do an invalid cmpxchg().
17  */
18 extern void __cmpxchg_called_with_bad_pointer(void);
19 
20 #define __HAVE_ARCH_CMPXCHG 1
21 
22 static inline unsigned long
23 __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
24 {
25 	if (size != 4) {
26 		__cmpxchg_called_with_bad_pointer();
27 		return old;
28 	}
29 
30 	__asm__ __volatile__(
31 		"1:	l.lwa %0, 0(%1)		\n"
32 		"	l.sfeq %0, %2		\n"
33 		"	l.bnf 2f		\n"
34 		"	 l.nop			\n"
35 		"	l.swa 0(%1), %3		\n"
36 		"	l.bnf 1b		\n"
37 		"	 l.nop			\n"
38 		"2:				\n"
39 		: "=&r"(old)
40 		: "r"(ptr), "r"(old), "r"(new)
41 		: "cc", "memory");
42 
43 	return old;
44 }
45 
46 #define cmpxchg(ptr, o, n)						\
47 	({								\
48 		(__typeof__(*(ptr))) __cmpxchg((ptr),			\
49 					       (unsigned long)(o),	\
50 					       (unsigned long)(n),	\
51 					       sizeof(*(ptr)));		\
52 	})
53 
54 /*
55  * This function doesn't exist, so you'll get a linker error if
56  * something tries to do an invalidly-sized xchg().
57  */
58 extern void __xchg_called_with_bad_pointer(void);
59 
60 static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
61 				   int size)
62 {
63 	if (size != 4) {
64 		__xchg_called_with_bad_pointer();
65 		return val;
66 	}
67 
68 	__asm__ __volatile__(
69 		"1:	l.lwa %0, 0(%1)		\n"
70 		"	l.swa 0(%1), %2		\n"
71 		"	l.bnf 1b		\n"
72 		"	 l.nop			\n"
73 		: "=&r"(val)
74 		: "r"(ptr), "r"(val)
75 		: "cc", "memory");
76 
77 	return val;
78 }
79 
80 #define xchg(ptr, with) 						\
81 	({								\
82 		(__typeof__(*(ptr))) __xchg((unsigned long)(with),	\
83 					    (ptr),			\
84 					    sizeof(*(ptr)));		\
85 	})
86 
87 #endif /* __ASM_OPENRISC_CMPXCHG_H */
88