Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arc/include/asm/futex.h
26481 views
1
/* SPDX-License-Identifier: GPL-2.0-only */
2
/*
3
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
4
*
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
16
#ifdef CONFIG_ARC_HAS_LLSC
17
18
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
19
\
20
smp_mb(); \
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" \
31
" j 3b \n" \
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) \
41
: "cc", "memory"); \
42
smp_mb() \
43
44
#else /* !CONFIG_ARC_HAS_LLSC */
45
46
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
47
\
48
smp_mb(); \
49
__asm__ __volatile__( \
50
"1: ld %1, [%2] \n" \
51
insn "\n" \
52
"2: st %0, [%2] \n" \
53
" mov %0, 0 \n" \
54
"3: \n" \
55
" .section .fixup,\"ax\" \n" \
56
" .align 4 \n" \
57
"4: mov %0, %4 \n" \
58
" j 3b \n" \
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) \
68
: "cc", "memory"); \
69
smp_mb() \
70
71
#endif
72
73
static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
74
u32 __user *uaddr)
75
{
76
int oldval = 0, ret;
77
78
if (!access_ok(uaddr, sizeof(u32)))
79
return -EFAULT;
80
81
#ifndef CONFIG_ARC_HAS_LLSC
82
preempt_disable(); /* to guarantee atomic r-m-w of futex op */
83
#endif
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:
90
/* oldval = *uaddr; *uaddr += oparg ; ret = *uaddr */
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
106
#ifndef CONFIG_ARC_HAS_LLSC
107
preempt_enable();
108
#endif
109
110
if (!ret)
111
*oval = oldval;
112
113
return ret;
114
}
115
116
/*
117
* cmpxchg of futex (pagefaults disabled by caller)
118
* Return 0 for success, -EFAULT otherwise
119
*/
120
static inline int
121
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 expval,
122
u32 newval)
123
{
124
int ret = 0;
125
u32 existval;
126
127
if (!access_ok(uaddr, sizeof(u32)))
128
return -EFAULT;
129
130
#ifndef CONFIG_ARC_HAS_LLSC
131
preempt_disable(); /* to guarantee atomic r-m-w of futex op */
132
#endif
133
smp_mb();
134
135
__asm__ __volatile__(
136
#ifdef CONFIG_ARC_HAS_LLSC
137
"1: llock %1, [%4] \n"
138
" brne %1, %2, 3f \n"
139
"2: scond %3, [%4] \n"
140
" bnz 1b \n"
141
#else
142
"1: ld %1, [%4] \n"
143
" brne %1, %2, 3f \n"
144
"2: st %3, [%4] \n"
145
#endif
146
"3: \n"
147
" .section .fixup,\"ax\" \n"
148
"4: mov %0, %5 \n"
149
" j 3b \n"
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"
156
: "+&r"(ret), "=&r"(existval)
157
: "r"(expval), "r"(newval), "r"(uaddr), "ir"(-EFAULT)
158
: "cc", "memory");
159
160
smp_mb();
161
162
#ifndef CONFIG_ARC_HAS_LLSC
163
preempt_enable();
164
#endif
165
*uval = existval;
166
return ret;
167
}
168
169
#endif
170
171