GNU Linux-libre 4.14.266-gnu1
[releases.git] / arch / openrisc / include / asm / cmpxchg.h
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 */