xref: /openbmc/linux/arch/xtensa/include/asm/futex.h (revision 8f8d5745bb520c76b81abef4a2cb3023d0313bfd)
1 /*
2  * Atomic futex routines
3  *
4  * Based on the PowerPC implementataion
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Copyright (C) 2013 TangoTec Ltd.
11  *
12  * Baruch Siach <baruch@tkos.co.il>
13  */
14 
15 #ifndef _ASM_XTENSA_FUTEX_H
16 #define _ASM_XTENSA_FUTEX_H
17 
18 #include <linux/futex.h>
19 #include <linux/uaccess.h>
20 #include <linux/errno.h>
21 
22 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
23 	__asm__ __volatile(				\
24 	"1:	l32i	%0, %2, 0\n"			\
25 		insn "\n"				\
26 	"	wsr	%0, scompare1\n"		\
27 	"2:	s32c1i	%1, %2, 0\n"			\
28 	"	bne	%1, %0, 1b\n"			\
29 	"	movi	%1, 0\n"			\
30 	"3:\n"						\
31 	"	.section .fixup,\"ax\"\n"		\
32 	"	.align 4\n"				\
33 	"	.literal_position\n"			\
34 	"5:	movi	%0, 3b\n"			\
35 	"	movi	%1, %3\n"			\
36 	"	jx	%0\n"				\
37 	"	.previous\n"				\
38 	"	.section __ex_table,\"a\"\n"		\
39 	"	.long 1b,5b,2b,5b\n"			\
40 	"	.previous\n"				\
41 	: "=&r" (oldval), "=&r" (ret)			\
42 	: "r" (uaddr), "I" (-EFAULT), "r" (oparg)	\
43 	: "memory")
44 
45 static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
46 		u32 __user *uaddr)
47 {
48 	int oldval = 0, ret;
49 
50 #if !XCHAL_HAVE_S32C1I
51 	return -ENOSYS;
52 #endif
53 
54 	pagefault_disable();
55 
56 	switch (op) {
57 	case FUTEX_OP_SET:
58 		__futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg);
59 		break;
60 	case FUTEX_OP_ADD:
61 		__futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr,
62 				oparg);
63 		break;
64 	case FUTEX_OP_OR:
65 		__futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr,
66 				oparg);
67 		break;
68 	case FUTEX_OP_ANDN:
69 		__futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr,
70 				~oparg);
71 		break;
72 	case FUTEX_OP_XOR:
73 		__futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr,
74 				oparg);
75 		break;
76 	default:
77 		ret = -ENOSYS;
78 	}
79 
80 	pagefault_enable();
81 
82 	if (!ret)
83 		*oval = oldval;
84 
85 	return ret;
86 }
87 
88 static inline int
89 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
90 			      u32 oldval, u32 newval)
91 {
92 	int ret = 0;
93 
94 	if (!access_ok(uaddr, sizeof(u32)))
95 		return -EFAULT;
96 
97 #if !XCHAL_HAVE_S32C1I
98 	return -ENOSYS;
99 #endif
100 
101 	__asm__ __volatile__ (
102 	"	# futex_atomic_cmpxchg_inatomic\n"
103 	"	wsr	%5, scompare1\n"
104 	"1:	s32c1i	%1, %4, 0\n"
105 	"	s32i	%1, %6, 0\n"
106 	"2:\n"
107 	"	.section .fixup,\"ax\"\n"
108 	"	.align 4\n"
109 	"	.literal_position\n"
110 	"4:	movi	%1, 2b\n"
111 	"	movi	%0, %7\n"
112 	"	jx	%1\n"
113 	"	.previous\n"
114 	"	.section __ex_table,\"a\"\n"
115 	"	.long 1b,4b\n"
116 	"	.previous\n"
117 	: "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
118 	: "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
119 	: "memory");
120 
121 	return ret;
122 }
123 
124 #endif /* _ASM_XTENSA_FUTEX_H */
125