28
28
#include <linux/futex.h>
29
29
#include <linux/uaccess.h>
30
30
#include <linux/errno.h>
32
extern struct __get_user futex_set(u32 __user *v, int i);
33
extern struct __get_user futex_add(u32 __user *v, int n);
34
extern struct __get_user futex_or(u32 __user *v, int n);
35
extern struct __get_user futex_andn(u32 __user *v, int n);
36
extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);
39
extern struct __get_user futex_xor(u32 __user *v, int n);
31
#include <asm/atomic.h>
34
* Support macros for futex operations. Do not use these macros directly.
35
* They assume "ret", "val", "oparg", and "uaddr" in the lexical context.
36
* __futex_cmpxchg() additionally assumes "oldval".
41
#define __futex_asm(OP) \
42
asm("1: {" #OP " %1, %3, %4; movei %0, 0 }\n" \
43
".pushsection .fixup,\"ax\"\n" \
44
"0: { movei %0, %5; j 9f }\n" \
45
".section __ex_table,\"a\"\n" \
49
: "=r" (ret), "=r" (val), "+m" (*(uaddr)) \
50
: "r" (uaddr), "r" (oparg), "i" (-EFAULT))
52
#define __futex_set() __futex_asm(exch4)
53
#define __futex_add() __futex_asm(fetchadd4)
54
#define __futex_or() __futex_asm(fetchor4)
55
#define __futex_andn() ({ oparg = ~oparg; __futex_asm(fetchand4); })
56
#define __futex_cmpxchg() \
57
({ __insn_mtspr(SPR_CMPEXCH_VALUE, oldval); __futex_asm(cmpexch4); })
59
#define __futex_xor() \
61
u32 oldval, n = oparg; \
62
if ((ret = __get_user(oldval, uaddr)) == 0) { \
66
} while (ret == 0 && oldval != val); \
70
/* No need to prefetch, since the atomic ops go to the home cache anyway. */
71
#define __futex_prolog()
41
static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
43
struct __get_user asm_ret = __get_user_4(uaddr);
49
asm_ret = futex_cmpxchg(uaddr, oldval, newval);
50
} while (asm_ret.err == 0 && oldval != asm_ret.val);
75
#define __futex_call(FN) \
77
struct __get_user gu = FN((u32 __force *)uaddr, lock, oparg); \
82
#define __futex_set() __futex_call(__atomic_xchg)
83
#define __futex_add() __futex_call(__atomic_xchg_add)
84
#define __futex_or() __futex_call(__atomic_or)
85
#define __futex_andn() __futex_call(__atomic_andn)
86
#define __futex_xor() __futex_call(__atomic_xor)
88
#define __futex_cmpxchg() \
90
struct __get_user gu = __atomic_cmpxchg((u32 __force *)uaddr, \
91
lock, oldval, oparg); \
97
* Find the lock pointer for the atomic calls to use, and issue a
98
* prefetch to the user address to bring it into cache. Similar to
99
* __atomic_setup(), but we can't do a read into the L1 since it might
100
* fault; instead we do a prefetch into the L2.
102
#define __futex_prolog() \
104
__insn_prefetch(uaddr); \
105
lock = __atomic_hashed_lock((int __force *)uaddr)
56
108
static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
71
127
pagefault_disable();
73
129
case FUTEX_OP_SET:
74
asm_ret = futex_set(uaddr, oparg);
76
132
case FUTEX_OP_ADD:
77
asm_ret = futex_add(uaddr, oparg);
80
asm_ret = futex_or(uaddr, oparg);
82
138
case FUTEX_OP_ANDN:
83
asm_ret = futex_andn(uaddr, oparg);
85
141
case FUTEX_OP_XOR:
86
asm_ret = futex_xor(uaddr, oparg);
89
asm_ret.err = -ENOSYS;
91
148
pagefault_enable();
97
152
case FUTEX_OP_CMP_EQ:
98
ret = (asm_ret.val == cmparg);
153
ret = (val == cmparg);
100
155
case FUTEX_OP_CMP_NE:
101
ret = (asm_ret.val != cmparg);
156
ret = (val != cmparg);
103
158
case FUTEX_OP_CMP_LT:
104
ret = (asm_ret.val < cmparg);
159
ret = (val < cmparg);
106
161
case FUTEX_OP_CMP_GE:
107
ret = (asm_ret.val >= cmparg);
162
ret = (val >= cmparg);
109
164
case FUTEX_OP_CMP_LE:
110
ret = (asm_ret.val <= cmparg);
165
ret = (val <= cmparg);
112
167
case FUTEX_OP_CMP_GT:
113
ret = (asm_ret.val > cmparg);
168
ret = (val > cmparg);
122
177
static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
123
u32 oldval, u32 newval)
178
u32 oldval, u32 oparg)
125
struct __get_user asm_ret;
127
184
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
130
asm_ret = futex_cmpxchg(uaddr, oldval, newval);
136
/* Return failure from the atomic wrappers. */
137
struct __get_user __atomic_bad_address(int __user *addr);
140
193
#endif /* !__ASSEMBLY__ */
142
195
#endif /* _ASM_TILE_FUTEX_H */