Merge tag 'xtensa-20181115' of git://github.com/jcmvbkbc/linux-xtensa
[sfrench/cifs-2.6.git] / arch / xtensa / include / asm / futex.h
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 */