xref: /openbmc/linux/arch/csky/include/asm/futex.h (revision d6c5cb9f)
1*d6c5cb9fSGuo Ren /* SPDX-License-Identifier: GPL-2.0 */
2*d6c5cb9fSGuo Ren 
3*d6c5cb9fSGuo Ren #ifndef __ASM_CSKY_FUTEX_H
4*d6c5cb9fSGuo Ren #define __ASM_CSKY_FUTEX_H
5*d6c5cb9fSGuo Ren 
6*d6c5cb9fSGuo Ren #ifndef CONFIG_SMP
7*d6c5cb9fSGuo Ren #include <asm-generic/futex.h>
8*d6c5cb9fSGuo Ren #else
9*d6c5cb9fSGuo Ren #include <linux/atomic.h>
10*d6c5cb9fSGuo Ren #include <linux/futex.h>
11*d6c5cb9fSGuo Ren #include <linux/uaccess.h>
12*d6c5cb9fSGuo Ren #include <linux/errno.h>
13*d6c5cb9fSGuo Ren 
14*d6c5cb9fSGuo Ren #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)		\
15*d6c5cb9fSGuo Ren {									\
16*d6c5cb9fSGuo Ren 	u32 tmp;							\
17*d6c5cb9fSGuo Ren 									\
18*d6c5cb9fSGuo Ren 	__atomic_pre_full_fence();					\
19*d6c5cb9fSGuo Ren 									\
20*d6c5cb9fSGuo Ren 	__asm__ __volatile__ (						\
21*d6c5cb9fSGuo Ren 	"1:	ldex.w	%[ov], %[u]			\n"		\
22*d6c5cb9fSGuo Ren 	"	"insn"					\n"		\
23*d6c5cb9fSGuo Ren 	"2:	stex.w	%[t], %[u]			\n"		\
24*d6c5cb9fSGuo Ren 	"	bez	%[t], 1b			\n"		\
25*d6c5cb9fSGuo Ren 	"	br	4f				\n"		\
26*d6c5cb9fSGuo Ren 	"3:	mov	%[r], %[e]			\n"		\
27*d6c5cb9fSGuo Ren 	"4:						\n"		\
28*d6c5cb9fSGuo Ren 	"	.section __ex_table,\"a\"		\n"		\
29*d6c5cb9fSGuo Ren 	"	.balign 4				\n"		\
30*d6c5cb9fSGuo Ren 	"	.long	1b, 3b				\n"		\
31*d6c5cb9fSGuo Ren 	"	.long	2b, 3b				\n"		\
32*d6c5cb9fSGuo Ren 	"	.previous				\n"		\
33*d6c5cb9fSGuo Ren 	: [r] "+r" (ret), [ov] "=&r" (oldval),				\
34*d6c5cb9fSGuo Ren 	  [u] "+m" (*uaddr), [t] "=&r" (tmp)				\
35*d6c5cb9fSGuo Ren 	: [op] "Jr" (oparg), [e] "jr" (-EFAULT)				\
36*d6c5cb9fSGuo Ren 	: "memory");							\
37*d6c5cb9fSGuo Ren 									\
38*d6c5cb9fSGuo Ren 	__atomic_post_full_fence();					\
39*d6c5cb9fSGuo Ren }
40*d6c5cb9fSGuo Ren 
41*d6c5cb9fSGuo Ren static inline int
arch_futex_atomic_op_inuser(int op,int oparg,int * oval,u32 __user * uaddr)42*d6c5cb9fSGuo Ren arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
43*d6c5cb9fSGuo Ren {
44*d6c5cb9fSGuo Ren 	int oldval = 0, ret = 0;
45*d6c5cb9fSGuo Ren 
46*d6c5cb9fSGuo Ren 	if (!access_ok(uaddr, sizeof(u32)))
47*d6c5cb9fSGuo Ren 		return -EFAULT;
48*d6c5cb9fSGuo Ren 
49*d6c5cb9fSGuo Ren 	switch (op) {
50*d6c5cb9fSGuo Ren 	case FUTEX_OP_SET:
51*d6c5cb9fSGuo Ren 		__futex_atomic_op("mov %[t], %[ov]",
52*d6c5cb9fSGuo Ren 				  ret, oldval, uaddr, oparg);
53*d6c5cb9fSGuo Ren 		break;
54*d6c5cb9fSGuo Ren 	case FUTEX_OP_ADD:
55*d6c5cb9fSGuo Ren 		__futex_atomic_op("add %[t], %[ov], %[op]",
56*d6c5cb9fSGuo Ren 				  ret, oldval, uaddr, oparg);
57*d6c5cb9fSGuo Ren 		break;
58*d6c5cb9fSGuo Ren 	case FUTEX_OP_OR:
59*d6c5cb9fSGuo Ren 		__futex_atomic_op("or %[t], %[ov], %[op]",
60*d6c5cb9fSGuo Ren 				  ret, oldval, uaddr, oparg);
61*d6c5cb9fSGuo Ren 		break;
62*d6c5cb9fSGuo Ren 	case FUTEX_OP_ANDN:
63*d6c5cb9fSGuo Ren 		__futex_atomic_op("and %[t], %[ov], %[op]",
64*d6c5cb9fSGuo Ren 				  ret, oldval, uaddr, ~oparg);
65*d6c5cb9fSGuo Ren 		break;
66*d6c5cb9fSGuo Ren 	case FUTEX_OP_XOR:
67*d6c5cb9fSGuo Ren 		__futex_atomic_op("xor %[t], %[ov], %[op]",
68*d6c5cb9fSGuo Ren 				  ret, oldval, uaddr, oparg);
69*d6c5cb9fSGuo Ren 		break;
70*d6c5cb9fSGuo Ren 	default:
71*d6c5cb9fSGuo Ren 		ret = -ENOSYS;
72*d6c5cb9fSGuo Ren 	}
73*d6c5cb9fSGuo Ren 
74*d6c5cb9fSGuo Ren 	if (!ret)
75*d6c5cb9fSGuo Ren 		*oval = oldval;
76*d6c5cb9fSGuo Ren 
77*d6c5cb9fSGuo Ren 	return ret;
78*d6c5cb9fSGuo Ren }
79*d6c5cb9fSGuo Ren 
80*d6c5cb9fSGuo Ren 
81*d6c5cb9fSGuo Ren 
82*d6c5cb9fSGuo Ren static inline int
futex_atomic_cmpxchg_inatomic(u32 * uval,u32 __user * uaddr,u32 oldval,u32 newval)83*d6c5cb9fSGuo Ren futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
84*d6c5cb9fSGuo Ren 			      u32 oldval, u32 newval)
85*d6c5cb9fSGuo Ren {
86*d6c5cb9fSGuo Ren 	int ret = 0;
87*d6c5cb9fSGuo Ren 	u32 val, tmp;
88*d6c5cb9fSGuo Ren 
89*d6c5cb9fSGuo Ren 	if (!access_ok(uaddr, sizeof(u32)))
90*d6c5cb9fSGuo Ren 		return -EFAULT;
91*d6c5cb9fSGuo Ren 
92*d6c5cb9fSGuo Ren 	__atomic_pre_full_fence();
93*d6c5cb9fSGuo Ren 
94*d6c5cb9fSGuo Ren 	__asm__ __volatile__ (
95*d6c5cb9fSGuo Ren 	"1:	ldex.w	%[v], %[u]			\n"
96*d6c5cb9fSGuo Ren 	"	cmpne	%[v], %[ov]			\n"
97*d6c5cb9fSGuo Ren 	"	bt	4f				\n"
98*d6c5cb9fSGuo Ren 	"	mov	%[t], %[nv]			\n"
99*d6c5cb9fSGuo Ren 	"2:	stex.w	%[t], %[u]			\n"
100*d6c5cb9fSGuo Ren 	"	bez	%[t], 1b			\n"
101*d6c5cb9fSGuo Ren 	"	br	4f				\n"
102*d6c5cb9fSGuo Ren 	"3:	mov	%[r], %[e]			\n"
103*d6c5cb9fSGuo Ren 	"4:						\n"
104*d6c5cb9fSGuo Ren 	"	.section __ex_table,\"a\"		\n"
105*d6c5cb9fSGuo Ren 	"	.balign 4				\n"
106*d6c5cb9fSGuo Ren 	"	.long	1b, 3b				\n"
107*d6c5cb9fSGuo Ren 	"	.long	2b, 3b				\n"
108*d6c5cb9fSGuo Ren 	"	.previous				\n"
109*d6c5cb9fSGuo Ren 	: [r] "+r" (ret), [v] "=&r" (val), [u] "+m" (*uaddr),
110*d6c5cb9fSGuo Ren 	  [t] "=&r" (tmp)
111*d6c5cb9fSGuo Ren 	: [ov] "Jr" (oldval), [nv] "Jr" (newval), [e] "Jr" (-EFAULT)
112*d6c5cb9fSGuo Ren 	: "memory");
113*d6c5cb9fSGuo Ren 
114*d6c5cb9fSGuo Ren 	__atomic_post_full_fence();
115*d6c5cb9fSGuo Ren 
116*d6c5cb9fSGuo Ren 	*uval = val;
117*d6c5cb9fSGuo Ren 	return ret;
118*d6c5cb9fSGuo Ren }
119*d6c5cb9fSGuo Ren 
120*d6c5cb9fSGuo Ren #endif /* CONFIG_SMP */
121*d6c5cb9fSGuo Ren #endif /* __ASM_CSKY_FUTEX_H */
122