Merge tag 'drm-amdkfd-next-2017-09-02' of git://people.freedesktop.org/~gabbayo/linux...
[sfrench/cifs-2.6.git] / 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  * arch_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 arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
29 {
30         int oldval, ret;
31         u32 tmp;
32
33         preempt_disable();
34         pagefault_disable();
35
36         ret = -EFAULT;
37         if (unlikely(get_user(oldval, uaddr) != 0))
38                 goto out_pagefault_enable;
39
40         ret = 0;
41         tmp = oldval;
42
43         switch (op) {
44         case FUTEX_OP_SET:
45                 tmp = oparg;
46                 break;
47         case FUTEX_OP_ADD:
48                 tmp += oparg;
49                 break;
50         case FUTEX_OP_OR:
51                 tmp |= oparg;
52                 break;
53         case FUTEX_OP_ANDN:
54                 tmp &= ~oparg;
55                 break;
56         case FUTEX_OP_XOR:
57                 tmp ^= oparg;
58                 break;
59         default:
60                 ret = -ENOSYS;
61         }
62
63         if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
64                 ret = -EFAULT;
65
66 out_pagefault_enable:
67         pagefault_enable();
68         preempt_enable();
69
70         if (ret == 0)
71                 *oval = oldval;
72
73         return ret;
74 }
75
76 /**
77  * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the
78  *                              uaddr with newval if the current value is
79  *                              oldval.
80  * @uval:       pointer to store content of @uaddr
81  * @uaddr:      pointer to user space address
82  * @oldval:     old value
83  * @newval:     new value to store to @uaddr
84  *
85  * Return:
86  * 0 - On success
87  * <0 - On error
88  */
89 static inline int
90 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
91                               u32 oldval, u32 newval)
92 {
93         u32 val;
94
95         preempt_disable();
96         if (unlikely(get_user(val, uaddr) != 0)) {
97                 preempt_enable();
98                 return -EFAULT;
99         }
100
101         if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
102                 preempt_enable();
103                 return -EFAULT;
104         }
105
106         *uval = val;
107         preempt_enable();
108
109         return 0;
110 }
111
112 #else
113 static inline int
114 arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
115 {
116         int oldval = 0, ret;
117
118         pagefault_disable();
119
120         switch (op) {
121         case FUTEX_OP_SET:
122         case FUTEX_OP_ADD:
123         case FUTEX_OP_OR:
124         case FUTEX_OP_ANDN:
125         case FUTEX_OP_XOR:
126         default:
127                 ret = -ENOSYS;
128         }
129
130         pagefault_enable();
131
132         if (!ret)
133                 *oval = oldval;
134
135         return ret;
136 }
137
138 static inline int
139 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
140                               u32 oldval, u32 newval)
141 {
142         return -ENOSYS;
143 }
144
145 #endif /* CONFIG_SMP */
146 #endif