blob: a4811aa0304d03264c4e63626d61619c62d16f0c [file] [log] [blame]
Martin Schwidefsky3363fbd2006-04-27 18:40:12 -07001#ifndef _ASM_S390_FUTEX_H
2#define _ASM_S390_FUTEX_H
Jakub Jelinek4732efb2005-09-06 15:16:25 -07003
Heiko Carstensd8ad0752007-01-09 10:18:50 +01004#include <linux/uaccess.h>
Heiko Carstens457f2182014-03-21 10:42:25 +01005#include <linux/futex.h>
6#include <asm/mmu_context.h>
Martin Schwidefsky3363fbd2006-04-27 18:40:12 -07007#include <asm/errno.h>
Martin Schwidefsky3363fbd2006-04-27 18:40:12 -07008
Heiko Carstens457f2182014-03-21 10:42:25 +01009#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");
Heiko Carstens4f41c2b2014-01-23 11:18:36 +010023
24static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
Martin Schwidefsky3363fbd2006-04-27 18:40:12 -070025{
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;
Heiko Carstens457f2182014-03-21 10:42:25 +010030 int oldval = 0, newval, ret;
Gerald Schaeferd02765d2006-09-20 15:59:42 +020031
Martin Schwidefskybeef5602014-04-14 15:11:26 +020032 load_kernel_asce();
Martin Schwidefsky3363fbd2006-04-27 18:40:12 -070033 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
34 oparg = 1 << oparg;
35
Heiko Carstensd8ad0752007-01-09 10:18:50 +010036 pagefault_disable();
Heiko Carstens457f2182014-03-21 10:42:25 +010037 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 }
Heiko Carstensd8ad0752007-01-09 10:18:50 +010061 pagefault_enable();
Martin Schwidefsky3363fbd2006-04-27 18:40:12 -070062
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
Heiko Carstens457f2182014-03-21 10:42:25 +010077static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
78 u32 oldval, u32 newval)
79{
80 int ret;
81
Martin Schwidefskybeef5602014-04-14 15:11:26 +020082 load_kernel_asce();
Heiko Carstens457f2182014-03-21 10:42:25 +010083 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
Martin Schwidefsky3363fbd2006-04-27 18:40:12 -070096#endif /* _ASM_S390_FUTEX_H */