1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_POWERPC_FUTEX_H
3#define _ASM_POWERPC_FUTEX_H
4
5#ifdef __KERNEL__
6
7#include <linux/futex.h>
8#include <linux/uaccess.h>
9#include <asm/errno.h>
10#include <asm/synch.h>
11
12#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
13  __asm__ __volatile ( \
14	PPC_ATOMIC_ENTRY_BARRIER \
15"1:	lwarx	%0,0,%2\n" \
16	insn \
17"2:	stwcx.	%1,0,%2\n" \
18	"bne-	1b\n" \
19	PPC_ATOMIC_EXIT_BARRIER \
20	"li	%1,0\n" \
21"3:	.section .fixup,\"ax\"\n" \
22"4:	li	%1,%3\n" \
23	"b	3b\n" \
24	".previous\n" \
25	EX_TABLE(1b, 4b) \
26	EX_TABLE(2b, 4b) \
27	: "=&r" (oldval), "=&r" (ret) \
28	: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
29	: "cr0", "memory")
30
31static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
32		u32 __user *uaddr)
33{
34	int oldval = 0, ret;
35
36	if (!user_access_begin(uaddr, sizeof(u32)))
37		return -EFAULT;
38
39	switch (op) {
40	case FUTEX_OP_SET:
41		__futex_atomic_op("mr %1,%4\n", ret, oldval, uaddr, oparg);
42		break;
43	case FUTEX_OP_ADD:
44		__futex_atomic_op("add %1,%0,%4\n", ret, oldval, uaddr, oparg);
45		break;
46	case FUTEX_OP_OR:
47		__futex_atomic_op("or %1,%0,%4\n", ret, oldval, uaddr, oparg);
48		break;
49	case FUTEX_OP_ANDN:
50		__futex_atomic_op("andc %1,%0,%4\n", ret, oldval, uaddr, oparg);
51		break;
52	case FUTEX_OP_XOR:
53		__futex_atomic_op("xor %1,%0,%4\n", ret, oldval, uaddr, oparg);
54		break;
55	default:
56		ret = -ENOSYS;
57	}
58	user_access_end();
59
60	*oval = oldval;
61
62	return ret;
63}
64
65static inline int
66futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
67			      u32 oldval, u32 newval)
68{
69	int ret = 0;
70	u32 prev;
71
72	if (!user_access_begin(uaddr, sizeof(u32)))
73		return -EFAULT;
74
75        __asm__ __volatile__ (
76        PPC_ATOMIC_ENTRY_BARRIER
77"1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
78        cmpw    0,%1,%4\n\
79        bne-    3f\n"
80"2:     stwcx.  %5,0,%3\n\
81        bne-    1b\n"
82        PPC_ATOMIC_EXIT_BARRIER
83"3:	.section .fixup,\"ax\"\n\
844:	li	%0,%6\n\
85	b	3b\n\
86	.previous\n"
87	EX_TABLE(1b, 4b)
88	EX_TABLE(2b, 4b)
89        : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
90        : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
91        : "cc", "memory");
92
93	user_access_end();
94
95	*uval = prev;
96
97        return ret;
98}
99
100#endif /* __KERNEL__ */
101#endif /* _ASM_POWERPC_FUTEX_H */
102