aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/include/asm/futex.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/include/asm/futex.h')
-rw-r--r--arch/tile/include/asm/futex.h141
1 files changed, 141 insertions, 0 deletions
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
new file mode 100644
index 000000000000..fe0d10dcae57
--- /dev/null
+++ b/arch/tile/include/asm/futex.h
@@ -0,0 +1,141 @@
1/*
2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 *
14 * These routines make two important assumptions:
15 *
16 * 1. atomic_t is really an int and can be freely cast back and forth
17 * (validated in __init_atomic_per_cpu).
18 *
19 * 2. userspace uses sys_cmpxchg() for all atomic operations, thus using
20 * the same locking convention that all the kernel atomic routines use.
21 */
22
23#ifndef _ASM_TILE_FUTEX_H
24#define _ASM_TILE_FUTEX_H
25
26#ifndef __ASSEMBLY__
27
28#include <linux/futex.h>
29#include <linux/uaccess.h>
30#include <linux/errno.h>
31
32extern struct __get_user futex_set(int __user *v, int i);
33extern struct __get_user futex_add(int __user *v, int n);
34extern struct __get_user futex_or(int __user *v, int n);
35extern struct __get_user futex_andn(int __user *v, int n);
36extern struct __get_user futex_cmpxchg(int __user *v, int o, int n);
37
38#ifndef __tilegx__
39extern struct __get_user futex_xor(int __user *v, int n);
40#else
41static inline struct __get_user futex_xor(int __user *uaddr, int n)
42{
43 struct __get_user asm_ret = __get_user_4(uaddr);
44 if (!asm_ret.err) {
45 int oldval, newval;
46 do {
47 oldval = asm_ret.val;
48 newval = oldval ^ n;
49 asm_ret = futex_cmpxchg(uaddr, oldval, newval);
50 } while (asm_ret.err == 0 && oldval != asm_ret.val);
51 }
52 return asm_ret;
53}
54#endif
55
56static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
57{
58 int op = (encoded_op >> 28) & 7;
59 int cmp = (encoded_op >> 24) & 15;
60 int oparg = (encoded_op << 8) >> 20;
61 int cmparg = (encoded_op << 20) >> 20;
62 int ret;
63 struct __get_user asm_ret;
64
65 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
66 oparg = 1 << oparg;
67
68 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
69 return -EFAULT;
70
71 pagefault_disable();
72 switch (op) {
73 case FUTEX_OP_SET:
74 asm_ret = futex_set(uaddr, oparg);
75 break;
76 case FUTEX_OP_ADD:
77 asm_ret = futex_add(uaddr, oparg);
78 break;
79 case FUTEX_OP_OR:
80 asm_ret = futex_or(uaddr, oparg);
81 break;
82 case FUTEX_OP_ANDN:
83 asm_ret = futex_andn(uaddr, oparg);
84 break;
85 case FUTEX_OP_XOR:
86 asm_ret = futex_xor(uaddr, oparg);
87 break;
88 default:
89 asm_ret.err = -ENOSYS;
90 }
91 pagefault_enable();
92
93 ret = asm_ret.err;
94
95 if (!ret) {
96 switch (cmp) {
97 case FUTEX_OP_CMP_EQ:
98 ret = (asm_ret.val == cmparg);
99 break;
100 case FUTEX_OP_CMP_NE:
101 ret = (asm_ret.val != cmparg);
102 break;
103 case FUTEX_OP_CMP_LT:
104 ret = (asm_ret.val < cmparg);
105 break;
106 case FUTEX_OP_CMP_GE:
107 ret = (asm_ret.val >= cmparg);
108 break;
109 case FUTEX_OP_CMP_LE:
110 ret = (asm_ret.val <= cmparg);
111 break;
112 case FUTEX_OP_CMP_GT:
113 ret = (asm_ret.val > cmparg);
114 break;
115 default:
116 ret = -ENOSYS;
117 }
118 }
119 return ret;
120}
121
122static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
123 int newval)
124{
125 struct __get_user asm_ret;
126
127 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
128 return -EFAULT;
129
130 asm_ret = futex_cmpxchg(uaddr, oldval, newval);
131 return asm_ret.err ? asm_ret.err : asm_ret.val;
132}
133
134#ifndef __tilegx__
135/* Return failure from the atomic wrappers. */
136struct __get_user __atomic_bad_address(int __user *addr);
137#endif
138
139#endif /* !__ASSEMBLY__ */
140
141#endif /* _ASM_TILE_FUTEX_H */