1 #ifndef _ASM_S390_FUTEX_H
2 #define _ASM_S390_FUTEX_H
3
4 #include <linux/uaccess.h>
5 #include <linux/futex.h>
6 #include <asm/mmu_context.h>
7 #include <asm/errno.h>
8
9 #define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
10 asm volatile( \
11 " sacf 256\n" \
12 "0: l %1,0(%6)\n" \
13 "1:"insn \
14 "2: cs %1,%2,0(%6)\n" \
15 "3: jl 1b\n" \
16 " lhi %0,0\n" \
17 "4: sacf 768\n" \
18 EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \
19 : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
20 "=m" (*uaddr) \
21 : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
22 "m" (*uaddr) : "cc");
23
futex_atomic_op_inuser(int encoded_op,u32 __user * uaddr)24 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
25 {
26 int op = (encoded_op >> 28) & 7;
27 int cmp = (encoded_op >> 24) & 15;
28 int oparg = (encoded_op << 8) >> 20;
29 int cmparg = (encoded_op << 20) >> 20;
30 int oldval = 0, newval, ret;
31
32 load_kernel_asce();
33 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
34 oparg = 1 << oparg;
35
36 pagefault_disable();
37 switch (op) {
38 case FUTEX_OP_SET:
39 __futex_atomic_op("lr %2,%5\n",
40 ret, oldval, newval, uaddr, oparg);
41 break;
42 case FUTEX_OP_ADD:
43 __futex_atomic_op("lr %2,%1\nar %2,%5\n",
44 ret, oldval, newval, uaddr, oparg);
45 break;
46 case FUTEX_OP_OR:
47 __futex_atomic_op("lr %2,%1\nor %2,%5\n",
48 ret, oldval, newval, uaddr, oparg);
49 break;
50 case FUTEX_OP_ANDN:
51 __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
52 ret, oldval, newval, uaddr, oparg);
53 break;
54 case FUTEX_OP_XOR:
55 __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
56 ret, oldval, newval, uaddr, oparg);
57 break;
58 default:
59 ret = -ENOSYS;
60 }
61 pagefault_enable();
62
63 if (!ret) {
64 switch (cmp) {
65 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
66 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
67 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
68 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
69 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
70 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
71 default: ret = -ENOSYS;
72 }
73 }
74 return ret;
75 }
76
futex_atomic_cmpxchg_inatomic(u32 * uval,u32 __user * uaddr,u32 oldval,u32 newval)77 static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
78 u32 oldval, u32 newval)
79 {
80 int ret;
81
82 load_kernel_asce();
83 asm volatile(
84 " sacf 256\n"
85 "0: cs %1,%4,0(%5)\n"
86 "1: la %0,0\n"
87 "2: sacf 768\n"
88 EX_TABLE(0b,2b) EX_TABLE(1b,2b)
89 : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
90 : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
91 : "cc", "memory");
92 *uval = oldval;
93 return ret;
94 }
95
96 #endif /* _ASM_S390_FUTEX_H */
97