Merge tag 'fsnotify_for_v5.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / arch / arm64 / include / asm / futex.h
CommitLineData
6170a974
CM
1/*
2 * Copyright (C) 2012 ARM Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#ifndef __ASM_FUTEX_H
17#define __ASM_FUTEX_H
18
19#ifdef __KERNEL__
20
21#include <linux/futex.h>
22#include <linux/uaccess.h>
338d4f49 23
6170a974
CM
24#include <asm/errno.h>
25
03110a5c
WD
26#define FUTEX_MAX_LOOPS 128 /* What's the largest number you can think of? */
27
6170a974 28#define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \
bd38967d 29do { \
03110a5c
WD
30 unsigned int loops = FUTEX_MAX_LOOPS; \
31 \
bd38967d 32 uaccess_enable(); \
6170a974 33 asm volatile( \
0ea366f5 34" prfm pstl1strm, %2\n" \
8e86f0b4 35"1: ldxr %w1, %2\n" \
6170a974 36 insn "\n" \
045afc24 37"2: stlxr %w0, %w3, %2\n" \
03110a5c
WD
38" cbz %w0, 3f\n" \
39" sub %w4, %w4, %w0\n" \
40" cbnz %w4, 1b\n" \
41" mov %w0, %w7\n" \
6170a974 42"3:\n" \
03110a5c 43" dmb ish\n" \
6170a974 44" .pushsection .fixup,\"ax\"\n" \
4da7a56c 45" .align 2\n" \
03110a5c 46"4: mov %w0, %w6\n" \
6170a974
CM
47" b 3b\n" \
48" .popsection\n" \
6c94f27a
AB
49 _ASM_EXTABLE(1b, 4b) \
50 _ASM_EXTABLE(2b, 4b) \
03110a5c
WD
51 : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp), \
52 "+r" (loops) \
53 : "r" (oparg), "Ir" (-EFAULT), "Ir" (-EAGAIN) \
bd38967d
CM
54 : "memory"); \
55 uaccess_disable(); \
56} while (0)
6170a974
CM
57
58static inline int
91b2d344 59arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
6170a974 60{
ff8acf92 61 int oldval = 0, ret, tmp;
91b2d344 62 u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
6170a974 63
2f09b227 64 pagefault_disable();
6170a974
CM
65
66 switch (op) {
67 case FUTEX_OP_SET:
03110a5c 68 __futex_atomic_op("mov %w3, %w5",
6170a974
CM
69 ret, oldval, uaddr, tmp, oparg);
70 break;
71 case FUTEX_OP_ADD:
03110a5c 72 __futex_atomic_op("add %w3, %w1, %w5",
6170a974
CM
73 ret, oldval, uaddr, tmp, oparg);
74 break;
75 case FUTEX_OP_OR:
03110a5c 76 __futex_atomic_op("orr %w3, %w1, %w5",
6170a974
CM
77 ret, oldval, uaddr, tmp, oparg);
78 break;
79 case FUTEX_OP_ANDN:
03110a5c 80 __futex_atomic_op("and %w3, %w1, %w5",
6170a974
CM
81 ret, oldval, uaddr, tmp, ~oparg);
82 break;
83 case FUTEX_OP_XOR:
03110a5c 84 __futex_atomic_op("eor %w3, %w1, %w5",
6170a974
CM
85 ret, oldval, uaddr, tmp, oparg);
86 break;
87 default:
88 ret = -ENOSYS;
89 }
90
2f09b227 91 pagefault_enable();
6170a974 92
30d6e0a4
JS
93 if (!ret)
94 *oval = oldval;
95
6170a974
CM
96 return ret;
97}
98
99static inline int
91b2d344 100futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
6170a974
CM
101 u32 oldval, u32 newval)
102{
103 int ret = 0;
03110a5c 104 unsigned int loops = FUTEX_MAX_LOOPS;
6170a974 105 u32 val, tmp;
91b2d344 106 u32 __user *uaddr;
6170a974 107
96d4f267 108 if (!access_ok(_uaddr, sizeof(u32)))
6170a974
CM
109 return -EFAULT;
110
91b2d344 111 uaddr = __uaccess_mask_ptr(_uaddr);
bd38967d 112 uaccess_enable();
6170a974 113 asm volatile("// futex_atomic_cmpxchg_inatomic\n"
0ea366f5 114" prfm pstl1strm, %2\n"
8e86f0b4 115"1: ldxr %w1, %2\n"
03110a5c
WD
116" sub %w3, %w1, %w5\n"
117" cbnz %w3, 4f\n"
118"2: stlxr %w3, %w6, %2\n"
119" cbz %w3, 3f\n"
120" sub %w4, %w4, %w3\n"
121" cbnz %w4, 1b\n"
122" mov %w0, %w8\n"
6170a974 123"3:\n"
03110a5c
WD
124" dmb ish\n"
125"4:\n"
6170a974 126" .pushsection .fixup,\"ax\"\n"
03110a5c
WD
127"5: mov %w0, %w7\n"
128" b 4b\n"
6170a974 129" .popsection\n"
03110a5c
WD
130 _ASM_EXTABLE(1b, 5b)
131 _ASM_EXTABLE(2b, 5b)
132 : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp), "+r" (loops)
133 : "r" (oldval), "r" (newval), "Ir" (-EFAULT), "Ir" (-EAGAIN)
95c41896 134 : "memory");
bd38967d 135 uaccess_disable();
6170a974 136
8e4e0ac0
WD
137 if (!ret)
138 *uval = val;
139
6170a974
CM
140 return ret;
141}
142
143#endif /* __KERNEL__ */
144#endif /* __ASM_FUTEX_H */