Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / include / asm-generic / futex.h
1 #ifndef _ASM_GENERIC_FUTEX_H
2 #define _ASM_GENERIC_FUTEX_H
3
4 #include <linux/futex.h>
5 #include <linux/uaccess.h>
6 #include <asm/errno.h>
7
8 #ifndef CONFIG_SMP
9 /*
10  * The following implementation only for uniprocessor machines.
11  * It relies on preempt_disable() ensuring mutual exclusion.
12  *
13  */
14
15 /**
16  * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
17  *                        argument and comparison of the previous
18  *                        futex value with another constant.
19  *
20  * @encoded_op: encoded operation to execute
21  * @uaddr:      pointer to user space address
22  *
23  * Return:
24  * 0 - On success
25  * <0 - On error
26  */
27 static inline int
28 futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
29 {
30         int op = (encoded_op >> 28) & 7;
31         int cmp = (encoded_op >> 24) & 15;
32         int oparg = (encoded_op << 8) >> 20;
33         int cmparg = (encoded_op << 20) >> 20;
34         int oldval, ret;
35         u32 tmp;
36
37         if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
38                 oparg = 1 << oparg;
39
40         preempt_disable();
41         pagefault_disable();
42
43         ret = -EFAULT;
44         if (unlikely(get_user(oldval, uaddr) != 0))
45                 goto out_pagefault_enable;
46
47         ret = 0;
48         tmp = oldval;
49
50         switch (op) {
51         case FUTEX_OP_SET:
52                 tmp = oparg;
53                 break;
54         case FUTEX_OP_ADD:
55                 tmp += oparg;
56                 break;
57         case FUTEX_OP_OR:
58                 tmp |= oparg;
59                 break;
60         case FUTEX_OP_ANDN:
61                 tmp &= ~oparg;
62                 break;
63         case FUTEX_OP_XOR:
64                 tmp ^= oparg;
65                 break;
66         default:
67                 ret = -ENOSYS;
68         }
69
70         if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
71                 ret = -EFAULT;
72
73 out_pagefault_enable:
74         pagefault_enable();
75         preempt_enable();
76
77         if (ret == 0) {
78                 switch (cmp) {
79                 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
80                 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
81                 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
82                 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
83                 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
84                 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
85                 default: ret = -ENOSYS;
86                 }
87         }
88         return ret;
89 }
90
91 /**
92  * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the
93  *                              uaddr with newval if the current value is
94  *                              oldval.
95  * @uval:       pointer to store content of @uaddr
96  * @uaddr:      pointer to user space address
97  * @oldval:     old value
98  * @newval:     new value to store to @uaddr
99  *
100  * Return:
101  * 0 - On success
102  * <0 - On error
103  */
104 static inline int
105 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
106                               u32 oldval, u32 newval)
107 {
108         u32 val;
109
110         preempt_disable();
111         if (unlikely(get_user(val, uaddr) != 0))
112                 return -EFAULT;
113
114         if (val == oldval && unlikely(put_user(newval, uaddr) != 0))
115                 return -EFAULT;
116
117         *uval = val;
118         preempt_enable();
119
120         return 0;
121 }
122
123 #else
124 static inline int
125 futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
126 {
127         int op = (encoded_op >> 28) & 7;
128         int cmp = (encoded_op >> 24) & 15;
129         int oparg = (encoded_op << 8) >> 20;
130         int cmparg = (encoded_op << 20) >> 20;
131         int oldval = 0, ret;
132         if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
133                 oparg = 1 << oparg;
134
135         if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
136                 return -EFAULT;
137
138         pagefault_disable();
139
140         switch (op) {
141         case FUTEX_OP_SET:
142         case FUTEX_OP_ADD:
143         case FUTEX_OP_OR:
144         case FUTEX_OP_ANDN:
145         case FUTEX_OP_XOR:
146         default:
147                 ret = -ENOSYS;
148         }
149
150         pagefault_enable();
151
152         if (!ret) {
153                 switch (cmp) {
154                 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
155                 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
156                 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
157                 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
158                 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
159                 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
160                 default: ret = -ENOSYS;
161                 }
162         }
163         return ret;
164 }
165
166 static inline int
167 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
168                               u32 oldval, u32 newval)
169 {
170         return -ENOSYS;
171 }
172
173 #endif /* CONFIG_SMP */
174 #endif