Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
futex.h
Go to the documentation of this file.
1 #ifndef _ASM_ALPHA_FUTEX_H
2 #define _ASM_ALPHA_FUTEX_H
3 
4 #ifdef __KERNEL__
5 
6 #include <linux/futex.h>
7 #include <linux/uaccess.h>
8 #include <asm/errno.h>
9 #include <asm/barrier.h>
10 
11 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
12  __asm__ __volatile__( \
13  __ASM_SMP_MB \
14  "1: ldl_l %0,0(%2)\n" \
15  insn \
16  "2: stl_c %1,0(%2)\n" \
17  " beq %1,4f\n" \
18  " mov $31,%1\n" \
19  "3: .subsection 2\n" \
20  "4: br 1b\n" \
21  " .previous\n" \
22  " .section __ex_table,\"a\"\n" \
23  " .long 1b-.\n" \
24  " lda $31,3b-1b(%1)\n" \
25  " .long 2b-.\n" \
26  " lda $31,3b-2b(%1)\n" \
27  " .previous\n" \
28  : "=&r" (oldval), "=&r"(ret) \
29  : "r" (uaddr), "r"(oparg) \
30  : "memory")
31 
32 static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
33 {
34  int op = (encoded_op >> 28) & 7;
35  int cmp = (encoded_op >> 24) & 15;
36  int oparg = (encoded_op << 8) >> 20;
37  int cmparg = (encoded_op << 20) >> 20;
38  int oldval = 0, ret;
39  if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
40  oparg = 1 << oparg;
41 
42  if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
43  return -EFAULT;
44 
45  pagefault_disable();
46 
47  switch (op) {
48  case FUTEX_OP_SET:
49  __futex_atomic_op("mov %3,%1\n", ret, oldval, uaddr, oparg);
50  break;
51  case FUTEX_OP_ADD:
52  __futex_atomic_op("addl %0,%3,%1\n", ret, oldval, uaddr, oparg);
53  break;
54  case FUTEX_OP_OR:
55  __futex_atomic_op("or %0,%3,%1\n", ret, oldval, uaddr, oparg);
56  break;
57  case FUTEX_OP_ANDN:
58  __futex_atomic_op("andnot %0,%3,%1\n", ret, oldval, uaddr, oparg);
59  break;
60  case FUTEX_OP_XOR:
61  __futex_atomic_op("xor %0,%3,%1\n", ret, oldval, uaddr, oparg);
62  break;
63  default:
64  ret = -ENOSYS;
65  }
66 
67  pagefault_enable();
68 
69  if (!ret) {
70  switch (cmp) {
71  case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
72  case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
73  case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
74  case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
75  case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
76  case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
77  default: ret = -ENOSYS;
78  }
79  }
80  return ret;
81 }
82 
83 static inline int
84 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
85  u32 oldval, u32 newval)
86 {
87  int ret = 0, cmp;
88  u32 prev;
89 
90  if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
91  return -EFAULT;
92 
93  __asm__ __volatile__ (
95  "1: ldl_l %1,0(%3)\n"
96  " cmpeq %1,%4,%2\n"
97  " beq %2,3f\n"
98  " mov %5,%2\n"
99  "2: stl_c %2,0(%3)\n"
100  " beq %2,4f\n"
101  "3: .subsection 2\n"
102  "4: br 1b\n"
103  " .previous\n"
104  " .section __ex_table,\"a\"\n"
105  " .long 1b-.\n"
106  " lda $31,3b-1b(%0)\n"
107  " .long 2b-.\n"
108  " lda $31,3b-2b(%0)\n"
109  " .previous\n"
110  : "+r"(ret), "=&r"(prev), "=&r"(cmp)
111  : "r"(uaddr), "r"((long)(int)oldval), "r"(newval)
112  : "memory");
113 
114  *uval = prev;
115  return ret;
116 }
117 
118 #endif /* __KERNEL__ */
119 #endif /* _ASM_ALPHA_FUTEX_H */