arm: tegra: fix error check in tegra2_clocks.c
[pandora-kernel.git] / arch / unicore32 / include / asm / futex.h
1 /*
2  * linux/arch/unicore32/include/asm/futex.h
3  *
4  * Code specific to PKUnity SoC and UniCore ISA
5  *
6  * Copyright (C) 2001-2010 GUAN Xue-tao
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #ifndef __UNICORE_FUTEX_H__
14 #define __UNICORE_FUTEX_H__
15
16 #ifdef __KERNEL__
17
18 #include <linux/futex.h>
19 #include <linux/preempt.h>
20 #include <linux/uaccess.h>
21 #include <linux/errno.h>
22
23 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)      \
24         __asm__ __volatile__(                                   \
25         "1:     ldw.u   %1, [%2]\n"                             \
26         "       " insn "\n"                                     \
27         "2:     stw.u   %0, [%2]\n"                             \
28         "       mov     %0, #0\n"                               \
29         "3:\n"                                                  \
30         "       .pushsection __ex_table,\"a\"\n"                \
31         "       .align  3\n"                                    \
32         "       .long   1b, 4f, 2b, 4f\n"                       \
33         "       .popsection\n"                                  \
34         "       .pushsection .fixup,\"ax\"\n"                   \
35         "4:     mov     %0, %4\n"                               \
36         "       b       3b\n"                                   \
37         "       .popsection"                                    \
38         : "=&r" (ret), "=&r" (oldval)                           \
39         : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)              \
40         : "cc", "memory")
41
42 static inline int
43 futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
44 {
45         int op = (encoded_op >> 28) & 7;
46         int cmp = (encoded_op >> 24) & 15;
47         int oparg = (encoded_op << 8) >> 20;
48         int cmparg = (encoded_op << 20) >> 20;
49         int oldval = 0, ret;
50
51         if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
52                 oparg = 1 << oparg;
53
54         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
55                 return -EFAULT;
56
57         pagefault_disable();    /* implies preempt_disable() */
58
59         switch (op) {
60         case FUTEX_OP_SET:
61                 __futex_atomic_op("mov  %0, %3", ret, oldval, uaddr, oparg);
62                 break;
63         case FUTEX_OP_ADD:
64                 __futex_atomic_op("add  %0, %1, %3", ret, oldval, uaddr, oparg);
65                 break;
66         case FUTEX_OP_OR:
67                 __futex_atomic_op("or   %0, %1, %3", ret, oldval, uaddr, oparg);
68                 break;
69         case FUTEX_OP_ANDN:
70                 __futex_atomic_op("and  %0, %1, %3",
71                                 ret, oldval, uaddr, ~oparg);
72                 break;
73         case FUTEX_OP_XOR:
74                 __futex_atomic_op("xor  %0, %1, %3", ret, oldval, uaddr, oparg);
75                 break;
76         default:
77                 ret = -ENOSYS;
78         }
79
80         pagefault_enable();     /* subsumes preempt_enable() */
81
82         if (!ret) {
83                 switch (cmp) {
84                 case FUTEX_OP_CMP_EQ:
85                         ret = (oldval == cmparg);
86                         break;
87                 case FUTEX_OP_CMP_NE:
88                         ret = (oldval != cmparg);
89                         break;
90                 case FUTEX_OP_CMP_LT:
91                         ret = (oldval <  cmparg);
92                         break;
93                 case FUTEX_OP_CMP_GE:
94                         ret = (oldval >= cmparg);
95                         break;
96                 case FUTEX_OP_CMP_LE:
97                         ret = (oldval <= cmparg);
98                         break;
99                 case FUTEX_OP_CMP_GT:
100                         ret = (oldval >  cmparg);
101                         break;
102                 default:
103                         ret = -ENOSYS;
104                 }
105         }
106         return ret;
107 }
108
109 static inline int
110 futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
111 {
112         int val;
113
114         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
115                 return -EFAULT;
116
117         pagefault_disable();    /* implies preempt_disable() */
118
119         __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
120         "1:     ldw.u   %0, [%3]\n"
121         "       cmpxor.a        %0, %1\n"
122         "       bne     3f\n"
123         "2:     stw.u   %2, [%3]\n"
124         "3:\n"
125         "       .pushsection __ex_table,\"a\"\n"
126         "       .align  3\n"
127         "       .long   1b, 4f, 2b, 4f\n"
128         "       .popsection\n"
129         "       .pushsection .fixup,\"ax\"\n"
130         "4:     mov     %0, %4\n"
131         "       b       3b\n"
132         "       .popsection"
133         : "=&r" (val)
134         : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
135         : "cc", "memory");
136
137         pagefault_enable();     /* subsumes preempt_enable() */
138
139         return val;
140 }
141
142 #endif /* __KERNEL__ */
143 #endif /* __UNICORE_FUTEX_H__ */