]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - include/asm-mips/futex.h
[PATCH] lightweight robust futexes updates
[mirror_ubuntu-zesty-kernel.git] / include / asm-mips / futex.h
1 #ifndef _ASM_FUTEX_H
2 #define _ASM_FUTEX_H
3
4 #ifdef __KERNEL__
5
6 #include <linux/config.h>
7 #include <linux/futex.h>
8 #include <asm/errno.h>
9 #include <asm/uaccess.h>
10
11 #ifdef CONFIG_SMP
12 #define __FUTEX_SMP_SYNC " sync \n"
13 #else
14 #define __FUTEX_SMP_SYNC
15 #endif
16
17 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
18 { \
19 __asm__ __volatile__( \
20 " .set push \n" \
21 " .set noat \n" \
22 " .set mips3 \n" \
23 "1: ll %1, (%3) # __futex_atomic_op1 \n" \
24 " .set mips0 \n" \
25 " " insn " \n" \
26 " .set mips3 \n" \
27 "2: sc $1, (%3) \n" \
28 " beqzl $1, 1b \n" \
29 __FUTEX_SMP_SYNC \
30 "3: \n" \
31 " .set pop \n" \
32 " .set mips0 \n" \
33 " .section .fixup,\"ax\" \n" \
34 "4: li %0, %5 \n" \
35 " j 2b \n" \
36 " .previous \n" \
37 " .section __ex_table,\"a\" \n" \
38 " "__UA_ADDR "\t1b, 4b \n" \
39 " "__UA_ADDR "\t2b, 4b \n" \
40 " .previous \n" \
41 : "=r" (ret), "=r" (oldval) \
42 : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \
43 }
44
45 static inline int
46 futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
47 {
48 int op = (encoded_op >> 28) & 7;
49 int cmp = (encoded_op >> 24) & 15;
50 int oparg = (encoded_op << 8) >> 20;
51 int cmparg = (encoded_op << 20) >> 20;
52 int oldval = 0, ret;
53 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
54 oparg = 1 << oparg;
55
56 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
57 return -EFAULT;
58
59 inc_preempt_count();
60
61 switch (op) {
62 case FUTEX_OP_SET:
63 __futex_atomic_op("move $1, %z4", ret, oldval, uaddr, oparg);
64 break;
65
66 case FUTEX_OP_ADD:
67 __futex_atomic_op("addu $1, %1, %z4",
68 ret, oldval, uaddr, oparg);
69 break;
70 case FUTEX_OP_OR:
71 __futex_atomic_op("or $1, %1, %z4",
72 ret, oldval, uaddr, oparg);
73 break;
74 case FUTEX_OP_ANDN:
75 __futex_atomic_op("and $1, %1, %z4",
76 ret, oldval, uaddr, ~oparg);
77 break;
78 case FUTEX_OP_XOR:
79 __futex_atomic_op("xor $1, %1, %z4",
80 ret, oldval, uaddr, oparg);
81 break;
82 default:
83 ret = -ENOSYS;
84 }
85
86 dec_preempt_count();
87
88 if (!ret) {
89 switch (cmp) {
90 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
91 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
92 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
93 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
94 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
95 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
96 default: ret = -ENOSYS;
97 }
98 }
99 return ret;
100 }
101
102 static inline int
103 futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
104 {
105 return -ENOSYS;
106 }
107
108 #endif
109 #endif