Merge remote-tracking branches 'asoc/fix/fsl-ssi', 'asoc/fix/intel', 'asoc/fix/intel...
[sfrench/cifs-2.6.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         __asm__ __volatile__(                           \
24         "1:     llock   %1, [%2]                \n"     \
25                 insn                            "\n"    \
26         "2:     scond   %0, [%2]                \n"     \
27         "       bnz     1b                      \n"     \
28         "       mov %0, 0                       \n"     \
29         "3:                                     \n"     \
30         "       .section .fixup,\"ax\"          \n"     \
31         "       .align  4                       \n"     \
32         "4:     mov %0, %4                      \n"     \
33         "       b   3b                          \n"     \
34         "       .previous                       \n"     \
35         "       .section __ex_table,\"a\"       \n"     \
36         "       .align  4                       \n"     \
37         "       .word   1b, 4b                  \n"     \
38         "       .word   2b, 4b                  \n"     \
39         "       .previous                       \n"     \
40                                                         \
41         : "=&r" (ret), "=&r" (oldval)                   \
42         : "r" (uaddr), "r" (oparg), "ir" (-EFAULT)      \
43         : "cc", "memory")
44
45 #else   /* !CONFIG_ARC_HAS_LLSC */
46
47 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
48                                                         \
49         __asm__ __volatile__(                           \
50         "1:     ld      %1, [%2]                \n"     \
51                 insn                            "\n"    \
52         "2:     st      %0, [%2]                \n"     \
53         "       mov %0, 0                       \n"     \
54         "3:                                     \n"     \
55         "       .section .fixup,\"ax\"          \n"     \
56         "       .align  4                       \n"     \
57         "4:     mov %0, %4                      \n"     \
58         "       b   3b                          \n"     \
59         "       .previous                       \n"     \
60         "       .section __ex_table,\"a\"       \n"     \
61         "       .align  4                       \n"     \
62         "       .word   1b, 4b                  \n"     \
63         "       .word   2b, 4b                  \n"     \
64         "       .previous                       \n"     \
65                                                         \
66         : "=&r" (ret), "=&r" (oldval)                   \
67         : "r" (uaddr), "r" (oparg), "ir" (-EFAULT)      \
68         : "cc", "memory")
69
70 #endif
71
72 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
73 {
74         int op = (encoded_op >> 28) & 7;
75         int cmp = (encoded_op >> 24) & 15;
76         int oparg = (encoded_op << 8) >> 20;
77         int cmparg = (encoded_op << 20) >> 20;
78         int oldval = 0, ret;
79
80         if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
81                 oparg = 1 << oparg;
82
83         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
84                 return -EFAULT;
85
86         pagefault_disable();
87
88         switch (op) {
89         case FUTEX_OP_SET:
90                 __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
91                 break;
92         case FUTEX_OP_ADD:
93                 __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
94                 break;
95         case FUTEX_OP_OR:
96                 __futex_atomic_op("or  %0, %1, %3", ret, oldval, uaddr, oparg);
97                 break;
98         case FUTEX_OP_ANDN:
99                 __futex_atomic_op("bic %0, %1, %3", ret, oldval, uaddr, oparg);
100                 break;
101         case FUTEX_OP_XOR:
102                 __futex_atomic_op("xor %0, %1, %3", ret, oldval, uaddr, oparg);
103                 break;
104         default:
105                 ret = -ENOSYS;
106         }
107
108         pagefault_enable();
109
110         if (!ret) {
111                 switch (cmp) {
112                 case FUTEX_OP_CMP_EQ:
113                         ret = (oldval == cmparg);
114                         break;
115                 case FUTEX_OP_CMP_NE:
116                         ret = (oldval != cmparg);
117                         break;
118                 case FUTEX_OP_CMP_LT:
119                         ret = (oldval < cmparg);
120                         break;
121                 case FUTEX_OP_CMP_GE:
122                         ret = (oldval >= cmparg);
123                         break;
124                 case FUTEX_OP_CMP_LE:
125                         ret = (oldval <= cmparg);
126                         break;
127                 case FUTEX_OP_CMP_GT:
128                         ret = (oldval > cmparg);
129                         break;
130                 default:
131                         ret = -ENOSYS;
132                 }
133         }
134         return ret;
135 }
136
137 /* Compare-xchg with pagefaults disabled.
138  *  Notes:
139  *      -Best-Effort: Exchg happens only if compare succeeds.
140  *          If compare fails, returns; leaving retry/looping to upper layers
141  *      -successful cmp-xchg: return orig value in @addr (same as cmp val)
142  *      -Compare fails: return orig value in @addr
143  *      -user access r/w fails: return -EFAULT
144  */
145 static inline int
146 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval,
147                                         u32 newval)
148 {
149         u32 val;
150
151         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
152                 return -EFAULT;
153
154         pagefault_disable();
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"(val)
178         : "r"(oldval), "r"(newval), "r"(uaddr), "ir"(-EFAULT)
179         : "cc", "memory");
180
181         pagefault_enable();
182
183         *uval = val;
184         return val;
185 }
186
187 #endif