Merge branch 'sh/smp'
[pandora-kernel.git] / arch / microblaze / include / asm / futex.h
1 #ifndef _ASM_MICROBLAZE_FUTEX_H
2 #define _ASM_MICROBLAZE_FUTEX_H
3
4 #ifdef __KERNEL__
5
6 #include <linux/futex.h>
7 #include <linux/uaccess.h>
8 #include <asm/errno.h>
9
10 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
11 ({                                                                      \
12         __asm__ __volatile__ (                                          \
13                         "1:     lwx     %0, %2, r0; "                   \
14                                 insn                                    \
15                         "2:     swx     %1, %2, r0;                     \
16                                 addic   %1, r0, 0;                      \
17                                 bnei    %1, 1b;                         \
18                         3:                                              \
19                         .section .fixup,\"ax\";                         \
20                         4:      brid    3b;                             \
21                                 addik   %1, r0, %3;                     \
22                         .previous;                                      \
23                         .section __ex_table,\"a\";                      \
24                         .word   1b,4b,2b,4b;                            \
25                         .previous;"                                     \
26         : "=&r" (oldval), "=&r" (ret)                                   \
27         : "b" (uaddr), "i" (-EFAULT), "r" (oparg)                       \
28         );                                                              \
29 })
30
31 static inline int
32 futex_atomic_op_inuser(int encoded_op, int __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(int)))
43                 return -EFAULT;
44
45         pagefault_disable();
46
47         switch (op) {
48         case FUTEX_OP_SET:
49                 __futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg);
50                 break;
51         case FUTEX_OP_ADD:
52                 __futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg);
53                 break;
54         case FUTEX_OP_OR:
55                 __futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg);
56                 break;
57         case FUTEX_OP_ANDN:
58                 __futex_atomic_op("andn %1,%0,%4;", ret, oldval, uaddr, oparg);
59                 break;
60         case FUTEX_OP_XOR:
61                 __futex_atomic_op("xor %1,%0,%4;", 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:
72                         ret = (oldval == cmparg);
73                         break;
74                 case FUTEX_OP_CMP_NE:
75                         ret = (oldval != cmparg);
76                         break;
77                 case FUTEX_OP_CMP_LT:
78                         ret = (oldval < cmparg);
79                         break;
80                 case FUTEX_OP_CMP_GE:
81                         ret = (oldval >= cmparg);
82                         break;
83                 case FUTEX_OP_CMP_LE:
84                         ret = (oldval <= cmparg);
85                         break;
86                 case FUTEX_OP_CMP_GT:
87                         ret = (oldval > cmparg);
88                         break;
89                 default:
90                         ret = -ENOSYS;
91                 }
92         }
93         return ret;
94 }
95
96 static inline int
97 futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
98 {
99         int prev, cmp;
100
101         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
102                 return -EFAULT;
103
104         __asm__ __volatile__ ("1:       lwx     %0, %2, r0;             \
105                                         cmp     %1, %0, %3;             \
106                                         beqi    %1, 3f;                 \
107                                 2:      swx     %4, %2, r0;             \
108                                         addic   %1, r0, 0;              \
109                                         bnei    %1, 1b;                 \
110                                 3:                                      \
111                                 .section .fixup,\"ax\";                 \
112                                 4:      brid    3b;                     \
113                                         addik   %0, r0, %5;             \
114                                 .previous;                              \
115                                 .section __ex_table,\"a\";              \
116                                 .word   1b,4b,2b,4b;                    \
117                                 .previous;"                             \
118                 : "=&r" (prev), "=&r"(cmp)                              \
119                 : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
120
121         return prev;
122 }
123
124 #endif /* __KERNEL__ */
125
126 #endif