GNU Linux-libre 5.19-rc6-gnu
[releases.git] / arch / microblaze / include / asm / futex.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_MICROBLAZE_FUTEX_H
3 #define _ASM_MICROBLAZE_FUTEX_H
4
5 #ifdef __KERNEL__
6
7 #include <linux/futex.h>
8 #include <linux/uaccess.h>
9 #include <asm/errno.h>
10
11 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
12 ({                                                                      \
13         __asm__ __volatile__ (                                          \
14                         "1:     lwx     %0, %2, r0; "                   \
15                                 insn                                    \
16                         "2:     swx     %1, %2, r0;                     \
17                                 addic   %1, r0, 0;                      \
18                                 bnei    %1, 1b;                         \
19                         3:                                              \
20                         .section .fixup,\"ax\";                         \
21                         4:      brid    3b;                             \
22                                 addik   %1, r0, %3;                     \
23                         .previous;                                      \
24                         .section __ex_table,\"a\";                      \
25                         .word   1b,4b,2b,4b;                            \
26                         .previous;"                                     \
27         : "=&r" (oldval), "=&r" (ret)                                   \
28         : "r" (uaddr), "i" (-EFAULT), "r" (oparg)                       \
29         );                                                              \
30 })
31
32 static inline int
33 arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
34 {
35         int oldval = 0, ret;
36
37         if (!access_ok(uaddr, sizeof(u32)))
38                 return -EFAULT;
39
40         switch (op) {
41         case FUTEX_OP_SET:
42                 __futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg);
43                 break;
44         case FUTEX_OP_ADD:
45                 __futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg);
46                 break;
47         case FUTEX_OP_OR:
48                 __futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg);
49                 break;
50         case FUTEX_OP_ANDN:
51                 __futex_atomic_op("andn %1,%0,%4;", ret, oldval, uaddr, oparg);
52                 break;
53         case FUTEX_OP_XOR:
54                 __futex_atomic_op("xor %1,%0,%4;", ret, oldval, uaddr, oparg);
55                 break;
56         default:
57                 ret = -ENOSYS;
58         }
59
60         if (!ret)
61                 *oval = oldval;
62
63         return ret;
64 }
65
66 static inline int
67 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
68                               u32 oldval, u32 newval)
69 {
70         int ret = 0, cmp;
71         u32 prev;
72
73         if (!access_ok(uaddr, sizeof(u32)))
74                 return -EFAULT;
75
76         __asm__ __volatile__ ("1:       lwx     %1, %3, r0;             \
77                                         cmp     %2, %1, %4;             \
78                                         bnei    %2, 3f;                 \
79                                 2:      swx     %5, %3, r0;             \
80                                         addic   %2, r0, 0;              \
81                                         bnei    %2, 1b;                 \
82                                 3:                                      \
83                                 .section .fixup,\"ax\";                 \
84                                 4:      brid    3b;                     \
85                                         addik   %0, r0, %6;             \
86                                 .previous;                              \
87                                 .section __ex_table,\"a\";              \
88                                 .word   1b,4b,2b,4b;                    \
89                                 .previous;"                             \
90                 : "+r" (ret), "=&r" (prev), "=&r"(cmp)  \
91                 : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
92
93         *uval = prev;
94         return ret;
95 }
96
97 #endif /* __KERNEL__ */
98
99 #endif