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	" SYMBOL_NAME_STR(fail)		\
32 	:					\
33 	: "r" (ptr)				\
34 	: "ip", "lr", "cc", "memory");		\
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	" SYMBOL_NAME_STR(fail) "\n"	\
54 "	mov	%0, ip"				\
55 	: "=&r" (result)			\
56 	: "r" (ptr)				\
57 	: "ip", "lr", "cc", "memory");		\
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	" SYMBOL_NAME_STR(wake)		\
76 	:					\
77 	: "r" (ptr)				\
78 	: "ip", "lr", "cc", "memory");		\
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	" SYMBOL_NAME_STR(fail)		\
108 	:					\
109 	: "r" (ptr), "I" (RW_LOCK_BIAS)		\
110 	: "ip", "lr", "cc", "memory");		\
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	" SYMBOL_NAME_STR(wake)		\
131 	:					\
132 	: "r" (ptr), "I" (RW_LOCK_BIAS)		\
133 	: "ip", "lr", "cc", "memory");		\
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	" SYMBOL_NAME_STR(wake)		\
156 	:					\
157 	: "r" (ptr), "I" (1)			\
158 	: "ip", "lr", "cc", "memory");		\
159 	})
160 
161 #endif
162