]>
Commit | Line | Data |
---|---|---|
220c0626 BS |
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" \ | |
03760270 MF |
35 | " .literal_position\n" \ |
36 | "5: movi %0, 3b\n" \ | |
220c0626 BS |
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 | ||
30d6e0a4 JS |
47 | static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, |
48 | u32 __user *uaddr) | |
220c0626 | 49 | { |
220c0626 | 50 | int oldval = 0, ret; |
220c0626 BS |
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 | ||
30d6e0a4 JS |
84 | if (!ret) |
85 | *oval = oldval; | |
220c0626 | 86 | |
30d6e0a4 | 87 | return ret; |
220c0626 BS |
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; | |
220c0626 | 95 | |
96d4f267 | 96 | if (!access_ok(uaddr, sizeof(u32))) |
220c0626 BS |
97 | return -EFAULT; |
98 | ||
99 | #if !XCHAL_HAVE_S32C1I | |
100 | return -ENOSYS; | |
101 | #endif | |
102 | ||
103 | __asm__ __volatile__ ( | |
104 | " # futex_atomic_cmpxchg_inatomic\n" | |
ca474809 MF |
105 | " wsr %5, scompare1\n" |
106 | "1: s32c1i %1, %4, 0\n" | |
107 | " s32i %1, %6, 0\n" | |
108 | "2:\n" | |
220c0626 BS |
109 | " .section .fixup,\"ax\"\n" |
110 | " .align 4\n" | |
03760270 MF |
111 | " .literal_position\n" |
112 | "4: movi %1, 2b\n" | |
ca474809 | 113 | " movi %0, %7\n" |
220c0626 BS |
114 | " jx %1\n" |
115 | " .previous\n" | |
116 | " .section __ex_table,\"a\"\n" | |
ca474809 | 117 | " .long 1b,4b\n" |
220c0626 | 118 | " .previous\n" |
ca474809 MF |
119 | : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval) |
120 | : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT) | |
220c0626 BS |
121 | : "memory"); |
122 | ||
220c0626 BS |
123 | return ret; |
124 | } | |
125 | ||
126 | #endif /* __KERNEL__ */ | |
127 | #endif /* _ASM_XTENSA_FUTEX_H */ |