Commit | Line | Data |
---|---|---|
fd3db0a6 MS |
1 | #ifndef _ASM_MICROBLAZE_FUTEX_H |
2 | #define _ASM_MICROBLAZE_FUTEX_H | |
3 | ||
4 | #ifdef __KERNEL__ | |
5 | ||
6 | #include <linux/futex.h> | |
7 | #include <linux/uaccess.h> | |
8 | #include <asm/errno.h> | |
9 | ||
10 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ | |
11 | ({ \ | |
12 | __asm__ __volatile__ ( \ | |
13 | "1: lwx %0, %2, r0; " \ | |
14 | insn \ | |
15 | "2: swx %1, %2, r0; \ | |
16 | addic %1, r0, 0; \ | |
17 | bnei %1, 1b; \ | |
18 | 3: \ | |
19 | .section .fixup,\"ax\"; \ | |
20 | 4: brid 3b; \ | |
21 | addik %1, r0, %3; \ | |
22 | .previous; \ | |
23 | .section __ex_table,\"a\"; \ | |
24 | .word 1b,4b,2b,4b; \ | |
25 | .previous;" \ | |
26 | : "=&r" (oldval), "=&r" (ret) \ | |
8cf662ed | 27 | : "r" (uaddr), "i" (-EFAULT), "r" (oparg) \ |
fd3db0a6 MS |
28 | ); \ |
29 | }) | |
30 | ||
31 | static inline int | |
8d7718aa | 32 | futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) |
fd3db0a6 MS |
33 | { |
34 | int op = (encoded_op >> 28) & 7; | |
35 | int cmp = (encoded_op >> 24) & 15; | |
36 | int oparg = (encoded_op << 8) >> 20; | |
37 | int cmparg = (encoded_op << 20) >> 20; | |
38 | int oldval = 0, ret; | |
39 | if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
40 | oparg = 1 << oparg; | |
41 | ||
8d7718aa | 42 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) |
fd3db0a6 MS |
43 | return -EFAULT; |
44 | ||
45 | pagefault_disable(); | |
46 | ||
47 | switch (op) { | |
48 | case FUTEX_OP_SET: | |
49 | __futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg); | |
50 | break; | |
51 | case FUTEX_OP_ADD: | |
52 | __futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg); | |
53 | break; | |
54 | case FUTEX_OP_OR: | |
55 | __futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg); | |
56 | break; | |
57 | case FUTEX_OP_ANDN: | |
4bb30baa | 58 | __futex_atomic_op("andn %1,%0,%4;", ret, oldval, uaddr, oparg); |
fd3db0a6 MS |
59 | break; |
60 | case FUTEX_OP_XOR: | |
61 | __futex_atomic_op("xor %1,%0,%4;", ret, oldval, uaddr, oparg); | |
62 | break; | |
63 | default: | |
64 | ret = -ENOSYS; | |
65 | } | |
66 | ||
67 | pagefault_enable(); | |
68 | ||
69 | if (!ret) { | |
70 | switch (cmp) { | |
71 | case FUTEX_OP_CMP_EQ: | |
72 | ret = (oldval == cmparg); | |
73 | break; | |
74 | case FUTEX_OP_CMP_NE: | |
75 | ret = (oldval != cmparg); | |
76 | break; | |
77 | case FUTEX_OP_CMP_LT: | |
78 | ret = (oldval < cmparg); | |
79 | break; | |
80 | case FUTEX_OP_CMP_GE: | |
81 | ret = (oldval >= cmparg); | |
82 | break; | |
83 | case FUTEX_OP_CMP_LE: | |
84 | ret = (oldval <= cmparg); | |
85 | break; | |
86 | case FUTEX_OP_CMP_GT: | |
87 | ret = (oldval > cmparg); | |
88 | break; | |
89 | default: | |
90 | ret = -ENOSYS; | |
91 | } | |
92 | } | |
93 | return ret; | |
94 | } | |
95 | ||
96 | static inline int | |
8d7718aa ML |
97 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, |
98 | u32 oldval, u32 newval) | |
fd3db0a6 | 99 | { |
8d7718aa ML |
100 | int ret = 0, cmp; |
101 | u32 prev; | |
fd3db0a6 | 102 | |
8d7718aa | 103 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) |
fd3db0a6 MS |
104 | return -EFAULT; |
105 | ||
37a9d912 ML |
106 | __asm__ __volatile__ ("1: lwx %1, %3, r0; \ |
107 | cmp %2, %1, %4; \ | |
f6a12a7d | 108 | bnei %2, 3f; \ |
37a9d912 ML |
109 | 2: swx %5, %3, r0; \ |
110 | addic %2, r0, 0; \ | |
111 | bnei %2, 1b; \ | |
fd3db0a6 MS |
112 | 3: \ |
113 | .section .fixup,\"ax\"; \ | |
114 | 4: brid 3b; \ | |
37a9d912 | 115 | addik %0, r0, %6; \ |
fd3db0a6 MS |
116 | .previous; \ |
117 | .section __ex_table,\"a\"; \ | |
118 | .word 1b,4b,2b,4b; \ | |
119 | .previous;" \ | |
37a9d912 | 120 | : "+r" (ret), "=&r" (prev), "=&r"(cmp) \ |
fd3db0a6 MS |
121 | : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)); |
122 | ||
37a9d912 ML |
123 | *uval = prev; |
124 | return ret; | |
fd3db0a6 MS |
125 | } |
126 | ||
127 | #endif /* __KERNEL__ */ | |
128 | ||
129 | #endif |