xref: /openbmc/linux/arch/xtensa/include/asm/futex.h (revision ba61bb17)
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 #ifdef __KERNEL__
19 
20 #include <linux/futex.h>
21 #include <linux/uaccess.h>
22 #include <linux/errno.h>
23 
24 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
25 	__asm__ __volatile(				\
26 	"1:	l32i	%0, %2, 0\n"			\
27 		insn "\n"				\
28 	"	wsr	%0, scompare1\n"		\
29 	"2:	s32c1i	%1, %2, 0\n"			\
30 	"	bne	%1, %0, 1b\n"			\
31 	"	movi	%1, 0\n"			\
32 	"3:\n"						\
33 	"	.section .fixup,\"ax\"\n"		\
34 	"	.align 4\n"				\
35 	"4:	.long	3b\n"				\
36 	"5:	l32r	%0, 4b\n"			\
37 	"	movi	%1, %3\n"			\
38 	"	jx	%0\n"				\
39 	"	.previous\n"				\
40 	"	.section __ex_table,\"a\"\n"		\
41 	"	.long 1b,5b,2b,5b\n"			\
42 	"	.previous\n"				\
43 	: "=&r" (oldval), "=&r" (ret)			\
44 	: "r" (uaddr), "I" (-EFAULT), "r" (oparg)	\
45 	: "memory")
46 
47 static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
48 		u32 __user *uaddr)
49 {
50 	int oldval = 0, ret;
51 
52 #if !XCHAL_HAVE_S32C1I
53 	return -ENOSYS;
54 #endif
55 
56 	pagefault_disable();
57 
58 	switch (op) {
59 	case FUTEX_OP_SET:
60 		__futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg);
61 		break;
62 	case FUTEX_OP_ADD:
63 		__futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr,
64 				oparg);
65 		break;
66 	case FUTEX_OP_OR:
67 		__futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr,
68 				oparg);
69 		break;
70 	case FUTEX_OP_ANDN:
71 		__futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr,
72 				~oparg);
73 		break;
74 	case FUTEX_OP_XOR:
75 		__futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr,
76 				oparg);
77 		break;
78 	default:
79 		ret = -ENOSYS;
80 	}
81 
82 	pagefault_enable();
83 
84 	if (!ret)
85 		*oval = oldval;
86 
87 	return ret;
88 }
89 
90 static inline int
91 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
92 			      u32 oldval, u32 newval)
93 {
94 	int ret = 0;
95 
96 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
97 		return -EFAULT;
98 
99 #if !XCHAL_HAVE_S32C1I
100 	return -ENOSYS;
101 #endif
102 
103 	__asm__ __volatile__ (
104 	"	# futex_atomic_cmpxchg_inatomic\n"
105 	"	wsr	%5, scompare1\n"
106 	"1:	s32c1i	%1, %4, 0\n"
107 	"	s32i	%1, %6, 0\n"
108 	"2:\n"
109 	"	.section .fixup,\"ax\"\n"
110 	"	.align 4\n"
111 	"3:	.long	2b\n"
112 	"4:	l32r	%1, 3b\n"
113 	"	movi	%0, %7\n"
114 	"	jx	%1\n"
115 	"	.previous\n"
116 	"	.section __ex_table,\"a\"\n"
117 	"	.long 1b,4b\n"
118 	"	.previous\n"
119 	: "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
120 	: "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
121 	: "memory");
122 
123 	return ret;
124 }
125 
126 #endif /* __KERNEL__ */
127 #endif /* _ASM_XTENSA_FUTEX_H */
128