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