1 /*
2  * SMP/VPE-safe functions to access "registers" (see note).
3  *
4  * NOTES:
5 * - These macros use ll/sc instructions, so it is your responsibility to
6  * ensure these are available on your platform before including this file.
7  * - The MIPS32 spec states that ll/sc results are undefined for uncached
8  * accesses. This means they can't be used on HW registers accessed
9  * through kseg1. Code which requires these macros for this purpose must
10  * front-end the registers with cached memory "registers" and have a single
11  * thread update the actual HW registers.
12  * - A maximum of 2k of code can be inserted between ll and sc. Every
13  * memory accesses between the instructions will increase the chance of
14  * sc failing and having to loop.
15  * - When using custom_read_reg32/custom_write_reg32 only perform the
16  * necessary logical operations on the register value in between these
17  * two calls. All other logic should be performed before the first call.
18   * - There is a bug on the R10000 chips which has a workaround. If you
19  * are affected by this bug, make sure to define the symbol 'R10000_LLSC_WAR'
20  * to be non-zero.  If you are using this header from within linux, you may
21  * include <asm/war.h> before including this file to have this defined
22  * appropriately for you.
23  *
24  * Copyright 2005-2007 PMC-Sierra, Inc.
25  *
26  *  This program is free software; you can redistribute  it and/or modify it
27  *  under  the terms of  the GNU General  Public License as published by the
28  *  Free Software Foundation;  either version 2 of the  License, or (at your
29  *  option) any later version.
30  *
31  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
32  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
33  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
34  *  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
35  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36  *  LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF USE,
37  *  DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38  *  THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
39  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41  *
42  *  You should have received a copy of the  GNU General Public License along
43  *  with this program; if not, write  to the Free Software Foundation, Inc., 675
44  *  Mass Ave, Cambridge, MA 02139, USA.
45  */
46 
47 #ifndef __ASM_REGOPS_H__
48 #define __ASM_REGOPS_H__
49 
50 #include <linux/types.h>
51 
52 #include <asm/compiler.h>
53 #include <asm/war.h>
54 
55 #ifndef R10000_LLSC_WAR
56 #define R10000_LLSC_WAR 0
57 #endif
58 
59 #if R10000_LLSC_WAR == 1
60 #define __beqz	"beqzl	"
61 #else
62 #define __beqz	"beqz	"
63 #endif
64 
65 #ifndef _LINUX_TYPES_H
66 typedef unsigned int u32;
67 #endif
68 
69 /*
70  * Sets all the masked bits to the corresponding value bits
71  */
set_value_reg32(volatile u32 * const addr,u32 const mask,u32 const value)72 static inline void set_value_reg32(volatile u32 *const addr,
73 					u32 const mask,
74 					u32 const value)
75 {
76 	u32 temp;
77 
78 	__asm__ __volatile__(
79 	"	.set	push				\n"
80 	"	.set	arch=r4000			\n"
81 	"1:	ll	%0, %1	# set_value_reg32	\n"
82 	"	and	%0, %2				\n"
83 	"	or	%0, %3				\n"
84 	"	sc	%0, %1				\n"
85 	"	"__beqz"%0, 1b				\n"
86 	"	nop					\n"
87 	"	.set	pop				\n"
88 	: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
89 	: "ir" (~mask), "ir" (value), GCC_OFF_SMALL_ASM() (*addr));
90 }
91 
92 /*
93  * Sets all the masked bits to '1'
94  */
set_reg32(volatile u32 * const addr,u32 const mask)95 static inline void set_reg32(volatile u32 *const addr,
96 				u32 const mask)
97 {
98 	u32 temp;
99 
100 	__asm__ __volatile__(
101 	"	.set	push				\n"
102 	"	.set	arch=r4000			\n"
103 	"1:	ll	%0, %1		# set_reg32	\n"
104 	"	or	%0, %2				\n"
105 	"	sc	%0, %1				\n"
106 	"	"__beqz"%0, 1b				\n"
107 	"	nop					\n"
108 	"	.set	pop				\n"
109 	: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
110 	: "ir" (mask), GCC_OFF_SMALL_ASM() (*addr));
111 }
112 
113 /*
114  * Sets all the masked bits to '0'
115  */
clear_reg32(volatile u32 * const addr,u32 const mask)116 static inline void clear_reg32(volatile u32 *const addr,
117 				u32 const mask)
118 {
119 	u32 temp;
120 
121 	__asm__ __volatile__(
122 	"	.set	push				\n"
123 	"	.set	arch=r4000			\n"
124 	"1:	ll	%0, %1		# clear_reg32	\n"
125 	"	and	%0, %2				\n"
126 	"	sc	%0, %1				\n"
127 	"	"__beqz"%0, 1b				\n"
128 	"	nop					\n"
129 	"	.set	pop				\n"
130 	: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
131 	: "ir" (~mask), GCC_OFF_SMALL_ASM() (*addr));
132 }
133 
134 /*
135  * Toggles all masked bits from '0' to '1' and '1' to '0'
136  */
toggle_reg32(volatile u32 * const addr,u32 const mask)137 static inline void toggle_reg32(volatile u32 *const addr,
138 				u32 const mask)
139 {
140 	u32 temp;
141 
142 	__asm__ __volatile__(
143 	"	.set	push				\n"
144 	"	.set	arch=r4000			\n"
145 	"1:	ll	%0, %1		# toggle_reg32	\n"
146 	"	xor	%0, %2				\n"
147 	"	sc	%0, %1				\n"
148 	"	"__beqz"%0, 1b				\n"
149 	"	nop					\n"
150 	"	.set	pop				\n"
151 	: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
152 	: "ir" (mask), GCC_OFF_SMALL_ASM() (*addr));
153 }
154 
155 /*
156  * Read all masked bits others are returned as '0'
157  */
read_reg32(volatile u32 * const addr,u32 const mask)158 static inline u32 read_reg32(volatile u32 *const addr,
159 				u32 const mask)
160 {
161 	u32 temp;
162 
163 	__asm__ __volatile__(
164 	"	.set	push				\n"
165 	"	.set	noreorder			\n"
166 	"	lw	%0, %1		# read		\n"
167 	"	and	%0, %2		# mask		\n"
168 	"	.set	pop				\n"
169 	: "=&r" (temp)
170 	: "m" (*addr), "ir" (mask));
171 
172 	return temp;
173 }
174 
175 /*
176  * blocking_read_reg32 - Read address with blocking load
177  *
178  * Uncached writes need to be read back to ensure they reach RAM.
179  * The returned value must be 'used' to prevent from becoming a
180  * non-blocking load.
181  */
blocking_read_reg32(volatile u32 * const addr)182 static inline u32 blocking_read_reg32(volatile u32 *const addr)
183 {
184 	u32 temp;
185 
186 	__asm__ __volatile__(
187 	"	.set	push				\n"
188 	"	.set	noreorder			\n"
189 	"	lw	%0, %1		# read		\n"
190 	"	move	%0, %0		# block		\n"
191 	"	.set	pop				\n"
192 	: "=&r" (temp)
193 	: "m" (*addr));
194 
195 	return temp;
196 }
197 
198 /*
199  * For special strange cases only:
200  *
201  * If you need custom processing within a ll/sc loop, use the following macros
202  * VERY CAREFULLY:
203  *
204  *   u32 tmp;				<-- Define a variable to hold the data
205  *
206  *   custom_read_reg32(address, tmp);	<-- Reads the address and put the value
207  *						in the 'tmp' variable given
208  *
209  *	From here on out, you are (basically) atomic, so don't do anything too
210  *	fancy!
211  *	Also, this code may loop if the end of this block fails to write
212  *	everything back safely due do the other CPU, so do NOT do anything
213  *	with side-effects!
214  *
215  *   custom_write_reg32(address, tmp);	<-- Writes back 'tmp' safely.
216  */
217 #define custom_read_reg32(address, tmp)				\
218 	__asm__ __volatile__(					\
219 	"	.set	push				\n"	\
220 	"	.set	arch=r4000			\n"	\
221 	"1:	ll	%0, %1	#custom_read_reg32	\n"	\
222 	"	.set	pop				\n"	\
223 	: "=r" (tmp), "=" GCC_OFF_SMALL_ASM() (*address)		\
224 	: GCC_OFF_SMALL_ASM() (*address))
225 
226 #define custom_write_reg32(address, tmp)			\
227 	__asm__ __volatile__(					\
228 	"	.set	push				\n"	\
229 	"	.set	arch=r4000			\n"	\
230 	"	sc	%0, %1	#custom_write_reg32	\n"	\
231 	"	"__beqz"%0, 1b				\n"	\
232 	"	nop					\n"	\
233 	"	.set	pop				\n"	\
234 	: "=&r" (tmp), "=" GCC_OFF_SMALL_ASM() (*address)		\
235 	: "0" (tmp), GCC_OFF_SMALL_ASM() (*address))
236 
237 #endif	/* __ASM_REGOPS_H__ */
238