Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / xtensa / include / asm / futex.h
1 /*
2  * Atomic futex routines
3  *
4  * Based on the PowerPC implementataion
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Copyright (C) 2013 TangoTec Ltd.
11  *
12  * Baruch Siach <baruch@tkos.co.il>
13  */
14
15 #ifndef _ASM_XTENSA_FUTEX_H
16 #define _ASM_XTENSA_FUTEX_H
17
18 #ifdef __KERNEL__
19
20 #include <linux/futex.h>
21 #include <linux/uaccess.h>
22 #include <linux/errno.h>
23
24 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
25         __asm__ __volatile(                             \
26         "1:     l32i    %0, %2, 0\n"                    \
27                 insn "\n"                               \
28         "       wsr     %0, scompare1\n"                \
29         "2:     s32c1i  %1, %2, 0\n"                    \
30         "       bne     %1, %0, 1b\n"                   \
31         "       movi    %1, 0\n"                        \
32         "3:\n"                                          \
33         "       .section .fixup,\"ax\"\n"               \
34         "       .align 4\n"                             \
35         "4:     .long   3b\n"                           \
36         "5:     l32r    %0, 4b\n"                       \
37         "       movi    %1, %3\n"                       \
38         "       jx      %0\n"                           \
39         "       .previous\n"                            \
40         "       .section __ex_table,\"a\"\n"            \
41         "       .long 1b,5b,2b,5b\n"                    \
42         "       .previous\n"                            \
43         : "=&r" (oldval), "=&r" (ret)                   \
44         : "r" (uaddr), "I" (-EFAULT), "r" (oparg)       \
45         : "memory")
46
47 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
48 {
49         int op = (encoded_op >> 28) & 7;
50         int cmp = (encoded_op >> 24) & 15;
51         int oparg = (encoded_op << 8) >> 20;
52         int cmparg = (encoded_op << 20) >> 20;
53         int oldval = 0, ret;
54         if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
55                 oparg = 1 << oparg;
56
57         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
58                 return -EFAULT;
59
60 #if !XCHAL_HAVE_S32C1I
61         return -ENOSYS;
62 #endif
63
64         pagefault_disable();
65
66         switch (op) {
67         case FUTEX_OP_SET:
68                 __futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg);
69                 break;
70         case FUTEX_OP_ADD:
71                 __futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr,
72                                 oparg);
73                 break;
74         case FUTEX_OP_OR:
75                 __futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr,
76                                 oparg);
77                 break;
78         case FUTEX_OP_ANDN:
79                 __futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr,
80                                 ~oparg);
81                 break;
82         case FUTEX_OP_XOR:
83                 __futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr,
84                                 oparg);
85                 break;
86         default:
87                 ret = -ENOSYS;
88         }
89
90         pagefault_enable();
91
92         if (ret)
93                 return ret;
94
95         switch (cmp) {
96         case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
97         case FUTEX_OP_CMP_NE: return (oldval != cmparg);
98         case FUTEX_OP_CMP_LT: return (oldval < cmparg);
99         case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
100         case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
101         case FUTEX_OP_CMP_GT: return (oldval > cmparg);
102         }
103
104         return -ENOSYS;
105 }
106
107 static inline int
108 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
109                               u32 oldval, u32 newval)
110 {
111         int ret = 0;
112         u32 prev;
113
114         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
115                 return -EFAULT;
116
117 #if !XCHAL_HAVE_S32C1I
118         return -ENOSYS;
119 #endif
120
121         __asm__ __volatile__ (
122         "       # futex_atomic_cmpxchg_inatomic\n"
123         "1:     l32i    %1, %3, 0\n"
124         "       mov     %0, %5\n"
125         "       wsr     %1, scompare1\n"
126         "2:     s32c1i  %0, %3, 0\n"
127         "3:\n"
128         "       .section .fixup,\"ax\"\n"
129         "       .align 4\n"
130         "4:     .long   3b\n"
131         "5:     l32r    %1, 4b\n"
132         "       movi    %0, %6\n"
133         "       jx      %1\n"
134         "       .previous\n"
135         "       .section __ex_table,\"a\"\n"
136         "       .long 1b,5b,2b,5b\n"
137         "       .previous\n"
138         : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
139         : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
140         : "memory");
141
142         *uval = prev;
143         return ret;
144 }
145
146 #endif /* __KERNEL__ */
147 #endif /* _ASM_XTENSA_FUTEX_H */