aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-ppc64/futex.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/asm-ppc64/futex.h')
-rw-r--r--include/asm-ppc64/futex.h83
1 files changed, 83 insertions, 0 deletions
diff --git a/include/asm-ppc64/futex.h b/include/asm-ppc64/futex.h
new file mode 100644
index 000000000000..cb2640b3a408
--- /dev/null
+++ b/include/asm-ppc64/futex.h
@@ -0,0 +1,83 @@
1#ifndef _ASM_FUTEX_H
2#define _ASM_FUTEX_H
3
4#ifdef __KERNEL__
5
6#include <linux/futex.h>
7#include <asm/errno.h>
8#include <asm/memory.h>
9#include <asm/uaccess.h>
10
11#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
12 __asm__ __volatile (SYNC_ON_SMP \
13"1: lwarx %0,0,%2\n" \
14 insn \
15"2: stwcx. %1,0,%2\n\
16 bne- 1b\n\
17 li %1,0\n\
183: .section .fixup,\"ax\"\n\
194: li %1,%3\n\
20 b 3b\n\
21 .previous\n\
22 .section __ex_table,\"a\"\n\
23 .align 3\n\
24 .llong 1b,4b,2b,4b\n\
25 .previous" \
26 : "=&r" (oldval), "=&r" (ret) \
27 : "b" (uaddr), "i" (-EFAULT), "1" (oparg) \
28 : "cr0", "memory")
29
30static inline int
31futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
32{
33 int op = (encoded_op >> 28) & 7;
34 int cmp = (encoded_op >> 24) & 15;
35 int oparg = (encoded_op << 8) >> 20;
36 int cmparg = (encoded_op << 20) >> 20;
37 int oldval = 0, ret;
38 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
39 oparg = 1 << oparg;
40
41 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
42 return -EFAULT;
43
44 inc_preempt_count();
45
46 switch (op) {
47 case FUTEX_OP_SET:
48 __futex_atomic_op("", ret, oldval, uaddr, oparg);
49 break;
50 case FUTEX_OP_ADD:
51 __futex_atomic_op("add %1,%0,%1\n", ret, oldval, uaddr, oparg);
52 break;
53 case FUTEX_OP_OR:
54 __futex_atomic_op("or %1,%0,%1\n", ret, oldval, uaddr, oparg);
55 break;
56 case FUTEX_OP_ANDN:
57 __futex_atomic_op("andc %1,%0,%1\n", ret, oldval, uaddr, oparg);
58 break;
59 case FUTEX_OP_XOR:
60 __futex_atomic_op("xor %1,%0,%1\n", ret, oldval, uaddr, oparg);
61 break;
62 default:
63 ret = -ENOSYS;
64 }
65
66 dec_preempt_count();
67
68 if (!ret) {
69 switch (cmp) {
70 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
71 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
72 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
73 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
74 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
75 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
76 default: ret = -ENOSYS;
77 }
78 }
79 return ret;
80}
81
82#endif
83#endif