diff options
Diffstat (limited to 'include/asm-mips/pmc-sierra/msp71xx/msp_regops.h')
-rw-r--r-- | include/asm-mips/pmc-sierra/msp71xx/msp_regops.h | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/include/asm-mips/pmc-sierra/msp71xx/msp_regops.h b/include/asm-mips/pmc-sierra/msp71xx/msp_regops.h new file mode 100644 index 000000000000..60a5a38dd5b2 --- /dev/null +++ b/include/asm-mips/pmc-sierra/msp71xx/msp_regops.h | |||
@@ -0,0 +1,236 @@ | |||
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/war.h> | ||
53 | |||
54 | #ifndef R10000_LLSC_WAR | ||
55 | #define R10000_LLSC_WAR 0 | ||
56 | #endif | ||
57 | |||
58 | #if R10000_LLSC_WAR == 1 | ||
59 | #define __beqz "beqzl " | ||
60 | #else | ||
61 | #define __beqz "beqz " | ||
62 | #endif | ||
63 | |||
64 | #ifndef _LINUX_TYPES_H | ||
65 | typedef unsigned int u32; | ||
66 | #endif | ||
67 | |||
68 | /* | ||
69 | * Sets all the masked bits to the corresponding value bits | ||
70 | */ | ||
71 | static inline void set_value_reg32(volatile u32 *const addr, | ||
72 | u32 const mask, | ||
73 | u32 const value) | ||
74 | { | ||
75 | u32 temp; | ||
76 | |||
77 | __asm__ __volatile__( | ||
78 | " .set push \n" | ||
79 | " .set mips3 \n" | ||
80 | "1: ll %0, %1 # set_value_reg32 \n" | ||
81 | " and %0, %2 \n" | ||
82 | " or %0, %3 \n" | ||
83 | " sc %0, %1 \n" | ||
84 | " "__beqz"%0, 1b \n" | ||
85 | " nop \n" | ||
86 | " .set pop \n" | ||
87 | : "=&r" (temp), "=m" (*addr) | ||
88 | : "ir" (~mask), "ir" (value), "m" (*addr)); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Sets all the masked bits to '1' | ||
93 | */ | ||
94 | static inline void set_reg32(volatile u32 *const addr, | ||
95 | u32 const mask) | ||
96 | { | ||
97 | u32 temp; | ||
98 | |||
99 | __asm__ __volatile__( | ||
100 | " .set push \n" | ||
101 | " .set mips3 \n" | ||
102 | "1: ll %0, %1 # set_reg32 \n" | ||
103 | " or %0, %2 \n" | ||
104 | " sc %0, %1 \n" | ||
105 | " "__beqz"%0, 1b \n" | ||
106 | " nop \n" | ||
107 | " .set pop \n" | ||
108 | : "=&r" (temp), "=m" (*addr) | ||
109 | : "ir" (mask), "m" (*addr)); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Sets all the masked bits to '0' | ||
114 | */ | ||
115 | static inline void clear_reg32(volatile u32 *const addr, | ||
116 | u32 const mask) | ||
117 | { | ||
118 | u32 temp; | ||
119 | |||
120 | __asm__ __volatile__( | ||
121 | " .set push \n" | ||
122 | " .set mips3 \n" | ||
123 | "1: ll %0, %1 # clear_reg32 \n" | ||
124 | " and %0, %2 \n" | ||
125 | " sc %0, %1 \n" | ||
126 | " "__beqz"%0, 1b \n" | ||
127 | " nop \n" | ||
128 | " .set pop \n" | ||
129 | : "=&r" (temp), "=m" (*addr) | ||
130 | : "ir" (~mask), "m" (*addr)); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Toggles all masked bits from '0' to '1' and '1' to '0' | ||
135 | */ | ||
136 | static inline void toggle_reg32(volatile u32 *const addr, | ||
137 | u32 const mask) | ||
138 | { | ||
139 | u32 temp; | ||
140 | |||
141 | __asm__ __volatile__( | ||
142 | " .set push \n" | ||
143 | " .set mips3 \n" | ||
144 | "1: ll %0, %1 # toggle_reg32 \n" | ||
145 | " xor %0, %2 \n" | ||
146 | " sc %0, %1 \n" | ||
147 | " "__beqz"%0, 1b \n" | ||
148 | " nop \n" | ||
149 | " .set pop \n" | ||
150 | : "=&r" (temp), "=m" (*addr) | ||
151 | : "ir" (mask), "m" (*addr)); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Read all masked bits others are returned as '0' | ||
156 | */ | ||
157 | static inline u32 read_reg32(volatile u32 *const addr, | ||
158 | u32 const mask) | ||
159 | { | ||
160 | u32 temp; | ||
161 | |||
162 | __asm__ __volatile__( | ||
163 | " .set push \n" | ||
164 | " .set noreorder \n" | ||
165 | " lw %0, %1 # read \n" | ||
166 | " and %0, %2 # mask \n" | ||
167 | " .set pop \n" | ||
168 | : "=&r" (temp) | ||
169 | : "m" (*addr), "ir" (mask)); | ||
170 | |||
171 | return temp; | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * blocking_read_reg32 - Read address with blocking load | ||
176 | * | ||
177 | * Uncached writes need to be read back to ensure they reach RAM. | ||
178 | * The returned value must be 'used' to prevent from becoming a | ||
179 | * non-blocking load. | ||
180 | */ | ||
181 | static inline u32 blocking_read_reg32(volatile u32 *const addr) | ||
182 | { | ||
183 | u32 temp; | ||
184 | |||
185 | __asm__ __volatile__( | ||
186 | " .set push \n" | ||
187 | " .set noreorder \n" | ||
188 | " lw %0, %1 # read \n" | ||
189 | " move %0, %0 # block \n" | ||
190 | " .set pop \n" | ||
191 | : "=&r" (temp) | ||
192 | : "m" (*addr)); | ||
193 | |||
194 | return temp; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * For special strange cases only: | ||
199 | * | ||
200 | * If you need custom processing within a ll/sc loop, use the following macros | ||
201 | * VERY CAREFULLY: | ||
202 | * | ||
203 | * u32 tmp; <-- Define a variable to hold the data | ||
204 | * | ||
205 | * custom_read_reg32(address, tmp); <-- Reads the address and put the value | ||
206 | * in the 'tmp' variable given | ||
207 | * | ||
208 | * From here on out, you are (basicly) atomic, so don't do anything too | ||
209 | * fancy! | ||
210 | * Also, this code may loop if the end of this block fails to write | ||
211 | * everything back safely due do the other CPU, so do NOT do anything | ||
212 | * with side-effects! | ||
213 | * | ||
214 | * custom_write_reg32(address, tmp); <-- Writes back 'tmp' safely. | ||
215 | */ | ||
216 | #define custom_read_reg32(address, tmp) \ | ||
217 | __asm__ __volatile__( \ | ||
218 | " .set push \n" \ | ||
219 | " .set mips3 \n" \ | ||
220 | "1: ll %0, %1 #custom_read_reg32 \n" \ | ||
221 | " .set pop \n" \ | ||
222 | : "=r" (tmp), "=m" (*address) \ | ||
223 | : "m" (*address)) | ||
224 | |||
225 | #define custom_write_reg32(address, tmp) \ | ||
226 | __asm__ __volatile__( \ | ||
227 | " .set push \n" \ | ||
228 | " .set mips3 \n" \ | ||
229 | " sc %0, %1 #custom_write_reg32 \n" \ | ||
230 | " "__beqz"%0, 1b \n" \ | ||
231 | " nop \n" \ | ||
232 | " .set pop \n" \ | ||
233 | : "=&r" (tmp), "=m" (*address) \ | ||
234 | : "0" (tmp), "m" (*address)) | ||
235 | |||
236 | #endif /* __ASM_REGOPS_H__ */ | ||