Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / include / asm-arm26 / locks.h
1 /*
2  *  linux/include/asm-arm/proc-armo/locks.h
3  *
4  *  Copyright (C) 2000 Russell King
5  *  Fixes for 26 bit machines, (C) 2000 Dave Gilbert
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  *  Interrupt safe locking assembler. 
12  */
13 #ifndef __ASM_PROC_LOCKS_H
14 #define __ASM_PROC_LOCKS_H
15
16 /* Decrements by 1, fails if value < 0 */
17 #define __down_op(ptr,fail)                     \
18         ({                                      \
19         __asm__ __volatile__ (                  \
20         "@ atomic down operation\n"             \
21 "       mov     ip, pc\n"                       \
22 "       orr     lr, ip, #0x08000000\n"          \
23 "       teqp    lr, #0\n"                       \
24 "       ldr     lr, [%0]\n"                     \
25 "       and     ip, ip, #0x0c000003\n"          \
26 "       subs    lr, lr, #1\n"                   \
27 "       str     lr, [%0]\n"                     \
28 "       orrmi   ip, ip, #0x80000000     @ set N\n" \
29 "       teqp    ip, #0\n"                       \
30 "       movmi   ip, %0\n"                       \
31 "       blmi    " #fail                         \
32         :                                       \
33         : "r" (ptr)                             \
34         : "ip", "lr", "cc");                    \
35         })
36
37 #define __down_op_ret(ptr,fail)                 \
38         ({                                      \
39                 unsigned int result;            \
40         __asm__ __volatile__ (                  \
41 "       @ down_op_ret\n"                        \
42 "       mov     ip, pc\n"                       \
43 "       orr     lr, ip, #0x08000000\n"          \
44 "       teqp    lr, #0\n"                       \
45 "       ldr     lr, [%1]\n"                     \
46 "       and     ip, ip, #0x0c000003\n"          \
47 "       subs    lr, lr, #1\n"                   \
48 "       str     lr, [%1]\n"                     \
49 "       orrmi   ip, ip, #0x80000000     @ set N\n" \
50 "       teqp    ip, #0\n"                       \
51 "       movmi   ip, %1\n"                       \
52 "       movpl   ip, #0\n"                       \
53 "       blmi    " #fail "\n"                    \
54 "       mov     %0, ip"                         \
55         : "=&r" (result)                        \
56         : "r" (ptr)                             \
57         : "ip", "lr", "cc");                    \
58         result;                                 \
59         })
60
61 #define __up_op(ptr,wake)                       \
62         ({                                      \
63         __asm__ __volatile__ (                  \
64         "@ up_op\n"                             \
65 "       mov     ip, pc\n"                       \
66 "       orr     lr, ip, #0x08000000\n"          \
67 "       teqp    lr, #0\n"                       \
68 "       ldr     lr, [%0]\n"                     \
69 "       and     ip, ip, #0x0c000003\n"          \
70 "       adds    lr, lr, #1\n"                   \
71 "       str     lr, [%0]\n"                     \
72 "       orrle   ip, ip, #0x80000000     @ set N - should this be mi ??? DAG ! \n" \
73 "       teqp    ip, #0\n"                       \
74 "       movmi   ip, %0\n"                       \
75 "       blmi    " #wake                         \
76         :                                       \
77         : "r" (ptr)                             \
78         : "ip", "lr", "cc");                    \
79         })
80
81 /*
82  * The value 0x01000000 supports up to 128 processors and
83  * lots of processes.  BIAS must be chosen such that sub'ing
84  * BIAS once per CPU will result in the long remaining
85  * negative.
86  */
87 #define RW_LOCK_BIAS      0x01000000
88 #define RW_LOCK_BIAS_STR "0x01000000"
89
90 /* Decrements by RW_LOCK_BIAS rather than 1, fails if value != 0 */
91 #define __down_op_write(ptr,fail)               \
92         ({                                      \
93         __asm__ __volatile__(                   \
94         "@ down_op_write\n"                     \
95 "       mov     ip, pc\n"                       \
96 "       orr     lr, ip, #0x08000000\n"          \
97 "       teqp    lr, #0\n"                       \
98 "       and     ip, ip, #0x0c000003\n"          \
99 \
100 "       ldr     lr, [%0]\n"                     \
101 "       subs    lr, lr, %1\n"                   \
102 "       str     lr, [%0]\n"                     \
103 \
104 " orreq ip, ip, #0x40000000 @ set Z \n"\
105 "       teqp    ip, #0\n"                       \
106 "       movne   ip, %0\n"                       \
107 "       blne    " #fail                         \
108         :                                       \
109         : "r" (ptr), "I" (RW_LOCK_BIAS)         \
110         : "ip", "lr", "cc");                    \
111         })
112
113 /* Increments by RW_LOCK_BIAS, wakes if value >= 0 */
114 #define __up_op_write(ptr,wake)                 \
115         ({                                      \
116         __asm__ __volatile__(                   \
117         "@ up_op_read\n"                        \
118 "       mov     ip, pc\n"                       \
119 "       orr     lr, ip, #0x08000000\n"          \
120 "       teqp    lr, #0\n"                       \
121 \
122 "       ldr     lr, [%0]\n"                     \
123 "       and     ip, ip, #0x0c000003\n"          \
124 "       adds    lr, lr, %1\n"                   \
125 "       str     lr, [%0]\n"                     \
126 \
127 " orrcs ip, ip, #0x20000000 @ set C\n" \
128 "       teqp    ip, #0\n"                       \
129 "       movcs   ip, %0\n"                       \
130 "       blcs    " #wake                         \
131         :                                       \
132         : "r" (ptr), "I" (RW_LOCK_BIAS)         \
133         : "ip", "lr", "cc");                    \
134         })
135
136 #define __down_op_read(ptr,fail)                \
137         __down_op(ptr, fail)
138
139 #define __up_op_read(ptr,wake)                  \
140         ({                                      \
141         __asm__ __volatile__(                   \
142         "@ up_op_read\n"                        \
143 "       mov     ip, pc\n"                       \
144 "       orr     lr, ip, #0x08000000\n"          \
145 "       teqp    lr, #0\n"                       \
146 \
147 "       ldr     lr, [%0]\n"                     \
148 "       and     ip, ip, #0x0c000003\n"          \
149 "       adds    lr, lr, %1\n"                   \
150 "       str     lr, [%0]\n"                     \
151 \
152 " orreq ip, ip, #0x40000000 @ Set Z \n" \
153 "       teqp    ip, #0\n"                       \
154 "       moveq   ip, %0\n"                       \
155 "       bleq    " #wake                         \
156         :                                       \
157         : "r" (ptr), "I" (1)                    \
158         : "ip", "lr", "cc");                    \
159         })
160
161 #endif