Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
01b812bc VG |
2 | /* |
3 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | |
4 | * | |
01b812bc VG |
5 | * Vineetg: August 2010: From Android kernel work |
6 | */ | |
7 | ||
8 | #ifndef _ASM_FUTEX_H | |
9 | #define _ASM_FUTEX_H | |
10 | ||
11 | #include <linux/futex.h> | |
12 | #include <linux/preempt.h> | |
13 | #include <linux/uaccess.h> | |
14 | #include <asm/errno.h> | |
15 | ||
9138d413 VG |
16 | #ifdef CONFIG_ARC_HAS_LLSC |
17 | ||
18 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\ | |
19 | \ | |
31d30c82 | 20 | smp_mb(); \ |
9138d413 VG |
21 | __asm__ __volatile__( \ |
22 | "1: llock %1, [%2] \n" \ | |
23 | insn "\n" \ | |
24 | "2: scond %0, [%2] \n" \ | |
25 | " bnz 1b \n" \ | |
26 | " mov %0, 0 \n" \ | |
27 | "3: \n" \ | |
28 | " .section .fixup,\"ax\" \n" \ | |
29 | " .align 4 \n" \ | |
30 | "4: mov %0, %4 \n" \ | |
6de6066c | 31 | " j 3b \n" \ |
9138d413 VG |
32 | " .previous \n" \ |
33 | " .section __ex_table,\"a\" \n" \ | |
34 | " .align 4 \n" \ | |
35 | " .word 1b, 4b \n" \ | |
36 | " .word 2b, 4b \n" \ | |
37 | " .previous \n" \ | |
38 | \ | |
39 | : "=&r" (ret), "=&r" (oldval) \ | |
40 | : "r" (uaddr), "r" (oparg), "ir" (-EFAULT) \ | |
31d30c82 VG |
41 | : "cc", "memory"); \ |
42 | smp_mb() \ | |
9138d413 VG |
43 | |
44 | #else /* !CONFIG_ARC_HAS_LLSC */ | |
45 | ||
01b812bc VG |
46 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\ |
47 | \ | |
31d30c82 | 48 | smp_mb(); \ |
01b812bc | 49 | __asm__ __volatile__( \ |
9138d413 | 50 | "1: ld %1, [%2] \n" \ |
01b812bc | 51 | insn "\n" \ |
9138d413 | 52 | "2: st %0, [%2] \n" \ |
01b812bc VG |
53 | " mov %0, 0 \n" \ |
54 | "3: \n" \ | |
55 | " .section .fixup,\"ax\" \n" \ | |
56 | " .align 4 \n" \ | |
57 | "4: mov %0, %4 \n" \ | |
6de6066c | 58 | " j 3b \n" \ |
01b812bc VG |
59 | " .previous \n" \ |
60 | " .section __ex_table,\"a\" \n" \ | |
61 | " .align 4 \n" \ | |
62 | " .word 1b, 4b \n" \ | |
63 | " .word 2b, 4b \n" \ | |
64 | " .previous \n" \ | |
65 | \ | |
66 | : "=&r" (ret), "=&r" (oldval) \ | |
67 | : "r" (uaddr), "r" (oparg), "ir" (-EFAULT) \ | |
31d30c82 VG |
68 | : "cc", "memory"); \ |
69 | smp_mb() \ | |
01b812bc | 70 | |
9138d413 VG |
71 | #endif |
72 | ||
30d6e0a4 JS |
73 | static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, |
74 | u32 __user *uaddr) | |
01b812bc | 75 | { |
01b812bc VG |
76 | int oldval = 0, ret; |
77 | ||
a08971e9 AV |
78 | if (!access_ok(uaddr, sizeof(u32))) |
79 | return -EFAULT; | |
80 | ||
eb2cd8b7 VG |
81 | #ifndef CONFIG_ARC_HAS_LLSC |
82 | preempt_disable(); /* to guarantee atomic r-m-w of futex op */ | |
83 | #endif | |
01b812bc VG |
84 | |
85 | switch (op) { | |
86 | case FUTEX_OP_SET: | |
87 | __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg); | |
88 | break; | |
89 | case FUTEX_OP_ADD: | |
ed574e2b | 90 | /* oldval = *uaddr; *uaddr += oparg ; ret = *uaddr */ |
01b812bc VG |
91 | __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg); |
92 | break; | |
93 | case FUTEX_OP_OR: | |
94 | __futex_atomic_op("or %0, %1, %3", ret, oldval, uaddr, oparg); | |
95 | break; | |
96 | case FUTEX_OP_ANDN: | |
97 | __futex_atomic_op("bic %0, %1, %3", ret, oldval, uaddr, oparg); | |
98 | break; | |
99 | case FUTEX_OP_XOR: | |
100 | __futex_atomic_op("xor %0, %1, %3", ret, oldval, uaddr, oparg); | |
101 | break; | |
102 | default: | |
103 | ret = -ENOSYS; | |
104 | } | |
105 | ||
eb2cd8b7 VG |
106 | #ifndef CONFIG_ARC_HAS_LLSC |
107 | preempt_enable(); | |
108 | #endif | |
01b812bc | 109 | |
30d6e0a4 JS |
110 | if (!ret) |
111 | *oval = oldval; | |
112 | ||
01b812bc VG |
113 | return ret; |
114 | } | |
115 | ||
31d30c82 VG |
116 | /* |
117 | * cmpxchg of futex (pagefaults disabled by caller) | |
882a95ae | 118 | * Return 0 for success, -EFAULT otherwise |
01b812bc VG |
119 | */ |
120 | static inline int | |
ed574e2b VG |
121 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 expval, |
122 | u32 newval) | |
01b812bc | 123 | { |
882a95ae | 124 | int ret = 0; |
ed574e2b | 125 | u32 existval; |
01b812bc | 126 | |
96d4f267 | 127 | if (!access_ok(uaddr, sizeof(u32))) |
01b812bc VG |
128 | return -EFAULT; |
129 | ||
eb2cd8b7 VG |
130 | #ifndef CONFIG_ARC_HAS_LLSC |
131 | preempt_disable(); /* to guarantee atomic r-m-w of futex op */ | |
132 | #endif | |
31d30c82 | 133 | smp_mb(); |
01b812bc | 134 | |
01b812bc | 135 | __asm__ __volatile__( |
9138d413 | 136 | #ifdef CONFIG_ARC_HAS_LLSC |
882a95ae VG |
137 | "1: llock %1, [%4] \n" |
138 | " brne %1, %2, 3f \n" | |
139 | "2: scond %3, [%4] \n" | |
9138d413 VG |
140 | " bnz 1b \n" |
141 | #else | |
882a95ae VG |
142 | "1: ld %1, [%4] \n" |
143 | " brne %1, %2, 3f \n" | |
144 | "2: st %3, [%4] \n" | |
9138d413 | 145 | #endif |
01b812bc VG |
146 | "3: \n" |
147 | " .section .fixup,\"ax\" \n" | |
882a95ae | 148 | "4: mov %0, %5 \n" |
6de6066c | 149 | " j 3b \n" |
01b812bc VG |
150 | " .previous \n" |
151 | " .section __ex_table,\"a\" \n" | |
152 | " .align 4 \n" | |
153 | " .word 1b, 4b \n" | |
154 | " .word 2b, 4b \n" | |
155 | " .previous\n" | |
882a95ae | 156 | : "+&r"(ret), "=&r"(existval) |
ed574e2b | 157 | : "r"(expval), "r"(newval), "r"(uaddr), "ir"(-EFAULT) |
01b812bc VG |
158 | : "cc", "memory"); |
159 | ||
31d30c82 | 160 | smp_mb(); |
01b812bc | 161 | |
eb2cd8b7 VG |
162 | #ifndef CONFIG_ARC_HAS_LLSC |
163 | preempt_enable(); | |
164 | #endif | |
ed574e2b | 165 | *uval = existval; |
882a95ae | 166 | return ret; |
01b812bc VG |
167 | } |
168 | ||
169 | #endif |