]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/openrisc/include/asm/futex.h
7780873419771e27cf92b684887790029f5de113
[mirror_ubuntu-artful-kernel.git] / arch / openrisc / include / asm / futex.h
1 #ifndef __ASM_OPENRISC_FUTEX_H
2 #define __ASM_OPENRISC_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: l.lwa %0, %2 \n" \
14 insn "\n" \
15 "2: l.swa %2, %1 \n" \
16 " l.bnf 1b \n" \
17 " l.ori %1, r0, 0 \n" \
18 "3: \n" \
19 ".section .fixup,\"ax\" \n" \
20 "4: l.j 3b \n" \
21 " l.addi %1, r0, %3 \n" \
22 ".previous \n" \
23 ".section __ex_table,\"a\" \n" \
24 ".word 1b,4b,2b,4b \n" \
25 ".previous \n" \
26 : "=&r" (oldval), "=&r" (ret), "+m" (*uaddr) \
27 : "i" (-EFAULT), "r" (oparg) \
28 : "cc", "memory" \
29 ); \
30 })
31
32 static inline int
33 futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
34 {
35 int op = (encoded_op >> 28) & 7;
36 int cmp = (encoded_op >> 24) & 15;
37 int oparg = (encoded_op << 8) >> 20;
38 int cmparg = (encoded_op << 20) >> 20;
39 int oldval = 0, ret;
40
41 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
42 oparg = 1 << oparg;
43
44 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
45 return -EFAULT;
46
47 pagefault_disable();
48
49 switch (op) {
50 case FUTEX_OP_SET:
51 __futex_atomic_op("l.or %1,%4,%4", ret, oldval, uaddr, oparg);
52 break;
53 case FUTEX_OP_ADD:
54 __futex_atomic_op("l.add %1,%0,%4", ret, oldval, uaddr, oparg);
55 break;
56 case FUTEX_OP_OR:
57 __futex_atomic_op("l.or %1,%0,%4", ret, oldval, uaddr, oparg);
58 break;
59 case FUTEX_OP_ANDN:
60 __futex_atomic_op("l.and %1,%0,%4", ret, oldval, uaddr, ~oparg);
61 break;
62 case FUTEX_OP_XOR:
63 __futex_atomic_op("l.xor %1,%0,%4", ret, oldval, uaddr, oparg);
64 break;
65 default:
66 ret = -ENOSYS;
67 }
68
69 pagefault_enable();
70
71 if (!ret) {
72 switch (cmp) {
73 case FUTEX_OP_CMP_EQ:
74 ret = (oldval == cmparg);
75 break;
76 case FUTEX_OP_CMP_NE:
77 ret = (oldval != cmparg);
78 break;
79 case FUTEX_OP_CMP_LT:
80 ret = (oldval < cmparg);
81 break;
82 case FUTEX_OP_CMP_GE:
83 ret = (oldval >= cmparg);
84 break;
85 case FUTEX_OP_CMP_LE:
86 ret = (oldval <= cmparg);
87 break;
88 case FUTEX_OP_CMP_GT:
89 ret = (oldval > cmparg);
90 break;
91 default:
92 ret = -ENOSYS;
93 }
94 }
95 return ret;
96 }
97
98 static inline int
99 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
100 u32 oldval, u32 newval)
101 {
102 int ret = 0;
103 u32 prev;
104
105 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
106 return -EFAULT;
107
108 __asm__ __volatile__ ( \
109 "1: l.lwa %1, %2 \n" \
110 " l.sfeq %1, %3 \n" \
111 " l.bnf 3f \n" \
112 " l.nop \n" \
113 "2: l.swa %2, %4 \n" \
114 " l.bnf 1b \n" \
115 " l.nop \n" \
116 "3: \n" \
117 ".section .fixup,\"ax\" \n" \
118 "4: l.j 3b \n" \
119 " l.addi %0, r0, %5 \n" \
120 ".previous \n" \
121 ".section __ex_table,\"a\" \n" \
122 ".word 1b,4b,2b,4b \n" \
123 ".previous \n" \
124 : "+r" (ret), "=&r" (prev), "+m" (*uaddr) \
125 : "r" (oldval), "r" (newval), "i" (-EFAULT) \
126 : "cc", "memory" \
127 );
128
129 *uval = prev;
130 return ret;
131 }
132
133 #endif /* __KERNEL__ */
134
135 #endif /* __ASM_OPENRISC_FUTEX_H */