ARC: futex cosmetics
[firefly-linux-kernel-4.4.55.git] / arch / arc / include / asm / futex.h
1 /*
2  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Vineetg: August 2010: From Android kernel work
9  */
10
11 #ifndef _ASM_FUTEX_H
12 #define _ASM_FUTEX_H
13
14 #include <linux/futex.h>
15 #include <linux/preempt.h>
16 #include <linux/uaccess.h>
17 #include <asm/errno.h>
18
19 #ifdef CONFIG_ARC_HAS_LLSC
20
21 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
22                                                         \
23         smp_mb();                                       \
24         __asm__ __volatile__(                           \
25         "1:     llock   %1, [%2]                \n"     \
26                 insn                            "\n"    \
27         "2:     scond   %0, [%2]                \n"     \
28         "       bnz     1b                      \n"     \
29         "       mov %0, 0                       \n"     \
30         "3:                                     \n"     \
31         "       .section .fixup,\"ax\"          \n"     \
32         "       .align  4                       \n"     \
33         "4:     mov %0, %4                      \n"     \
34         "       b   3b                          \n"     \
35         "       .previous                       \n"     \
36         "       .section __ex_table,\"a\"       \n"     \
37         "       .align  4                       \n"     \
38         "       .word   1b, 4b                  \n"     \
39         "       .word   2b, 4b                  \n"     \
40         "       .previous                       \n"     \
41                                                         \
42         : "=&r" (ret), "=&r" (oldval)                   \
43         : "r" (uaddr), "r" (oparg), "ir" (-EFAULT)      \
44         : "cc", "memory");                              \
45         smp_mb()                                        \
46
47 #else   /* !CONFIG_ARC_HAS_LLSC */
48
49 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
50                                                         \
51         smp_mb();                                       \
52         __asm__ __volatile__(                           \
53         "1:     ld      %1, [%2]                \n"     \
54                 insn                            "\n"    \
55         "2:     st      %0, [%2]                \n"     \
56         "       mov %0, 0                       \n"     \
57         "3:                                     \n"     \
58         "       .section .fixup,\"ax\"          \n"     \
59         "       .align  4                       \n"     \
60         "4:     mov %0, %4                      \n"     \
61         "       b   3b                          \n"     \
62         "       .previous                       \n"     \
63         "       .section __ex_table,\"a\"       \n"     \
64         "       .align  4                       \n"     \
65         "       .word   1b, 4b                  \n"     \
66         "       .word   2b, 4b                  \n"     \
67         "       .previous                       \n"     \
68                                                         \
69         : "=&r" (ret), "=&r" (oldval)                   \
70         : "r" (uaddr), "r" (oparg), "ir" (-EFAULT)      \
71         : "cc", "memory");                              \
72         smp_mb()                                        \
73
74 #endif
75
76 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
77 {
78         int op = (encoded_op >> 28) & 7;
79         int cmp = (encoded_op >> 24) & 15;
80         int oparg = (encoded_op << 8) >> 20;
81         int cmparg = (encoded_op << 20) >> 20;
82         int oldval = 0, ret;
83
84         if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
85                 oparg = 1 << oparg;
86
87         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
88                 return -EFAULT;
89
90         pagefault_disable();
91
92         switch (op) {
93         case FUTEX_OP_SET:
94                 __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
95                 break;
96         case FUTEX_OP_ADD:
97                 /* oldval = *uaddr; *uaddr += oparg ; ret = *uaddr */
98                 __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
99                 break;
100         case FUTEX_OP_OR:
101                 __futex_atomic_op("or  %0, %1, %3", ret, oldval, uaddr, oparg);
102                 break;
103         case FUTEX_OP_ANDN:
104                 __futex_atomic_op("bic %0, %1, %3", ret, oldval, uaddr, oparg);
105                 break;
106         case FUTEX_OP_XOR:
107                 __futex_atomic_op("xor %0, %1, %3", ret, oldval, uaddr, oparg);
108                 break;
109         default:
110                 ret = -ENOSYS;
111         }
112
113         pagefault_enable();
114
115         if (!ret) {
116                 switch (cmp) {
117                 case FUTEX_OP_CMP_EQ:
118                         ret = (oldval == cmparg);
119                         break;
120                 case FUTEX_OP_CMP_NE:
121                         ret = (oldval != cmparg);
122                         break;
123                 case FUTEX_OP_CMP_LT:
124                         ret = (oldval < cmparg);
125                         break;
126                 case FUTEX_OP_CMP_GE:
127                         ret = (oldval >= cmparg);
128                         break;
129                 case FUTEX_OP_CMP_LE:
130                         ret = (oldval <= cmparg);
131                         break;
132                 case FUTEX_OP_CMP_GT:
133                         ret = (oldval > cmparg);
134                         break;
135                 default:
136                         ret = -ENOSYS;
137                 }
138         }
139         return ret;
140 }
141
142 /*
143  * cmpxchg of futex (pagefaults disabled by caller)
144  */
145 static inline int
146 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 expval,
147                               u32 newval)
148 {
149         u32 existval;
150
151         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
152                 return -EFAULT;
153
154         smp_mb();
155
156         __asm__ __volatile__(
157 #ifdef CONFIG_ARC_HAS_LLSC
158         "1:     llock   %0, [%3]                \n"
159         "       brne    %0, %1, 3f              \n"
160         "2:     scond   %2, [%3]                \n"
161         "       bnz     1b                      \n"
162 #else
163         "1:     ld      %0, [%3]                \n"
164         "       brne    %0, %1, 3f              \n"
165         "2:     st      %2, [%3]                \n"
166 #endif
167         "3:     \n"
168         "       .section .fixup,\"ax\"  \n"
169         "4:     mov %0, %4      \n"
170         "       b   3b  \n"
171         "       .previous       \n"
172         "       .section __ex_table,\"a\"       \n"
173         "       .align  4       \n"
174         "       .word   1b, 4b  \n"
175         "       .word   2b, 4b  \n"
176         "       .previous\n"
177         : "=&r"(existval)
178         : "r"(expval), "r"(newval), "r"(uaddr), "ir"(-EFAULT)
179         : "cc", "memory");
180
181         smp_mb();
182
183         *uval = existval;
184         return existval;
185 }
186
187 #endif