diff options
author | Richard Kuo <rkuo@codeaurora.org> | 2011-10-31 19:27:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-01 10:34:18 -0400 |
commit | a86a7ce30ac04cfd6775dc9a0114d9c3924e682a (patch) | |
tree | 284ec1a0445d54532de8e70a02184e78e436a323 /arch/hexagon | |
parent | 8feca0e182d13914a0c4505488b36459f1532cea (diff) |
Hexagon: Add bitops support
Signed-off-by: Richard Kuo <rkuo@codeaurora.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/hexagon')
-rw-r--r-- | arch/hexagon/include/asm/bitops.h | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/arch/hexagon/include/asm/bitops.h b/arch/hexagon/include/asm/bitops.h new file mode 100644 index 000000000000..d23461e080ff --- /dev/null +++ b/arch/hexagon/include/asm/bitops.h | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * Bit operations for the Hexagon architecture | ||
3 | * | ||
4 | * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. | ||
5 | * | ||
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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef _ASM_BITOPS_H | ||
23 | #define _ASM_BITOPS_H | ||
24 | |||
25 | #include <linux/compiler.h> | ||
26 | #include <asm/byteorder.h> | ||
27 | #include <asm/system.h> | ||
28 | #include <asm/atomic.h> | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | #define smp_mb__before_clear_bit() barrier() | ||
33 | #define smp_mb__after_clear_bit() barrier() | ||
34 | |||
35 | /* | ||
36 | * The offset calculations for these are based on BITS_PER_LONG == 32 | ||
37 | * (i.e. I get to shift by #5-2 (32 bits per long, 4 bytes per access), | ||
38 | * mask by 0x0000001F) | ||
39 | * | ||
40 | * Typically, R10 is clobbered for address, R11 bit nr, and R12 is temp | ||
41 | */ | ||
42 | |||
43 | /** | ||
44 | * test_and_clear_bit - clear a bit and return its old value | ||
45 | * @nr: bit number to clear | ||
46 | * @addr: pointer to memory | ||
47 | */ | ||
48 | static inline int test_and_clear_bit(int nr, volatile void *addr) | ||
49 | { | ||
50 | int oldval; | ||
51 | |||
52 | __asm__ __volatile__ ( | ||
53 | " {R10 = %1; R11 = asr(%2,#5); }\n" | ||
54 | " {R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n" | ||
55 | "1: R12 = memw_locked(R10);\n" | ||
56 | " { P0 = tstbit(R12,R11); R12 = clrbit(R12,R11); }\n" | ||
57 | " memw_locked(R10,P1) = R12;\n" | ||
58 | " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" | ||
59 | : "=&r" (oldval) | ||
60 | : "r" (addr), "r" (nr) | ||
61 | : "r10", "r11", "r12", "p0", "p1", "memory" | ||
62 | ); | ||
63 | |||
64 | return oldval; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * test_and_set_bit - set a bit and return its old value | ||
69 | * @nr: bit number to set | ||
70 | * @addr: pointer to memory | ||
71 | */ | ||
72 | static inline int test_and_set_bit(int nr, volatile void *addr) | ||
73 | { | ||
74 | int oldval; | ||
75 | |||
76 | __asm__ __volatile__ ( | ||
77 | " {R10 = %1; R11 = asr(%2,#5); }\n" | ||
78 | " {R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n" | ||
79 | "1: R12 = memw_locked(R10);\n" | ||
80 | " { P0 = tstbit(R12,R11); R12 = setbit(R12,R11); }\n" | ||
81 | " memw_locked(R10,P1) = R12;\n" | ||
82 | " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" | ||
83 | : "=&r" (oldval) | ||
84 | : "r" (addr), "r" (nr) | ||
85 | : "r10", "r11", "r12", "p0", "p1", "memory" | ||
86 | ); | ||
87 | |||
88 | |||
89 | return oldval; | ||
90 | |||
91 | } | ||
92 | |||
93 | /** | ||
94 | * test_and_change_bit - toggle a bit and return its old value | ||
95 | * @nr: bit number to set | ||
96 | * @addr: pointer to memory | ||
97 | */ | ||
98 | static inline int test_and_change_bit(int nr, volatile void *addr) | ||
99 | { | ||
100 | int oldval; | ||
101 | |||
102 | __asm__ __volatile__ ( | ||
103 | " {R10 = %1; R11 = asr(%2,#5); }\n" | ||
104 | " {R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n" | ||
105 | "1: R12 = memw_locked(R10);\n" | ||
106 | " { P0 = tstbit(R12,R11); R12 = togglebit(R12,R11); }\n" | ||
107 | " memw_locked(R10,P1) = R12;\n" | ||
108 | " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" | ||
109 | : "=&r" (oldval) | ||
110 | : "r" (addr), "r" (nr) | ||
111 | : "r10", "r11", "r12", "p0", "p1", "memory" | ||
112 | ); | ||
113 | |||
114 | return oldval; | ||
115 | |||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Atomic, but doesn't care about the return value. | ||
120 | * Rewrite later to save a cycle or two. | ||
121 | */ | ||
122 | |||
123 | static inline void clear_bit(int nr, volatile void *addr) | ||
124 | { | ||
125 | test_and_clear_bit(nr, addr); | ||
126 | } | ||
127 | |||
128 | static inline void set_bit(int nr, volatile void *addr) | ||
129 | { | ||
130 | test_and_set_bit(nr, addr); | ||
131 | } | ||
132 | |||
133 | static inline void change_bit(int nr, volatile void *addr) | ||
134 | { | ||
135 | test_and_change_bit(nr, addr); | ||
136 | } | ||
137 | |||
138 | |||
139 | /* | ||
140 | * These are allowed to be non-atomic. In fact the generic flavors are | ||
141 | * in non-atomic.h. Would it be better to use intrinsics for this? | ||
142 | * | ||
143 | * OK, writes in our architecture do not invalidate LL/SC, so this has to | ||
144 | * be atomic, particularly for things like slab_lock and slab_unlock. | ||
145 | * | ||
146 | */ | ||
147 | static inline void __clear_bit(int nr, volatile unsigned long *addr) | ||
148 | { | ||
149 | test_and_clear_bit(nr, addr); | ||
150 | } | ||
151 | |||
152 | static inline void __set_bit(int nr, volatile unsigned long *addr) | ||
153 | { | ||
154 | test_and_set_bit(nr, addr); | ||
155 | } | ||
156 | |||
157 | static inline void __change_bit(int nr, volatile unsigned long *addr) | ||
158 | { | ||
159 | test_and_change_bit(nr, addr); | ||
160 | } | ||
161 | |||
162 | /* Apparently, at least some of these are allowed to be non-atomic */ | ||
163 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | ||
164 | { | ||
165 | return test_and_clear_bit(nr, addr); | ||
166 | } | ||
167 | |||
168 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | ||
169 | { | ||
170 | return test_and_set_bit(nr, addr); | ||
171 | } | ||
172 | |||
173 | static inline int __test_and_change_bit(int nr, volatile unsigned long *addr) | ||
174 | { | ||
175 | return test_and_change_bit(nr, addr); | ||
176 | } | ||
177 | |||
178 | static inline int __test_bit(int nr, const volatile unsigned long *addr) | ||
179 | { | ||
180 | int retval; | ||
181 | |||
182 | asm volatile( | ||
183 | "{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n" | ||
184 | : "=&r" (retval) | ||
185 | : "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG) | ||
186 | : "p0" | ||
187 | ); | ||
188 | |||
189 | return retval; | ||
190 | } | ||
191 | |||
192 | #define test_bit(nr, addr) __test_bit(nr, addr) | ||
193 | |||
194 | /* | ||
195 | * ffz - find first zero in word. | ||
196 | * @word: The word to search | ||
197 | * | ||
198 | * Undefined if no zero exists, so code should check against ~0UL first. | ||
199 | */ | ||
200 | static inline long ffz(int x) | ||
201 | { | ||
202 | int r; | ||
203 | |||
204 | asm("%0 = ct1(%1);\n" | ||
205 | : "=&r" (r) | ||
206 | : "r" (x)); | ||
207 | return r; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * fls - find last (most-significant) bit set | ||
212 | * @x: the word to search | ||
213 | * | ||
214 | * This is defined the same way as ffs. | ||
215 | * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. | ||
216 | */ | ||
217 | static inline long fls(int x) | ||
218 | { | ||
219 | int r; | ||
220 | |||
221 | asm("{ %0 = cl0(%1);}\n" | ||
222 | "%0 = sub(#32,%0);\n" | ||
223 | : "=&r" (r) | ||
224 | : "r" (x) | ||
225 | : "p0"); | ||
226 | |||
227 | return r; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * ffs - find first bit set | ||
232 | * @x: the word to search | ||
233 | * | ||
234 | * This is defined the same way as | ||
235 | * the libc and compiler builtin ffs routines, therefore | ||
236 | * differs in spirit from the above ffz (man ffs). | ||
237 | */ | ||
238 | static inline long ffs(int x) | ||
239 | { | ||
240 | int r; | ||
241 | |||
242 | asm("{ P0 = cmp.eq(%1,#0); %0 = ct0(%1);}\n" | ||
243 | "{ if P0 %0 = #0; if !P0 %0 = add(%0,#1);}\n" | ||
244 | : "=&r" (r) | ||
245 | : "r" (x) | ||
246 | : "p0"); | ||
247 | |||
248 | return r; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * __ffs - find first bit in word. | ||
253 | * @word: The word to search | ||
254 | * | ||
255 | * Undefined if no bit exists, so code should check against 0 first. | ||
256 | * | ||
257 | * bits_per_long assumed to be 32 | ||
258 | * numbering starts at 0 I think (instead of 1 like ffs) | ||
259 | */ | ||
260 | static inline unsigned long __ffs(unsigned long word) | ||
261 | { | ||
262 | int num; | ||
263 | |||
264 | asm("%0 = ct0(%1);\n" | ||
265 | : "=&r" (num) | ||
266 | : "r" (word)); | ||
267 | |||
268 | return num; | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * __fls - find last (most-significant) set bit in a long word | ||
273 | * @word: the word to search | ||
274 | * | ||
275 | * Undefined if no set bit exists, so code should check against 0 first. | ||
276 | * bits_per_long assumed to be 32 | ||
277 | */ | ||
278 | static inline unsigned long __fls(unsigned long word) | ||
279 | { | ||
280 | int num; | ||
281 | |||
282 | asm("%0 = cl0(%1);\n" | ||
283 | "%0 = sub(#31,%0);\n" | ||
284 | : "=&r" (num) | ||
285 | : "r" (word)); | ||
286 | |||
287 | return num; | ||
288 | } | ||
289 | |||
290 | #include <asm-generic/bitops/lock.h> | ||
291 | #include <asm-generic/bitops/find.h> | ||
292 | |||
293 | #include <asm-generic/bitops/fls64.h> | ||
294 | #include <asm-generic/bitops/sched.h> | ||
295 | #include <asm-generic/bitops/hweight.h> | ||
296 | |||
297 | #include <asm-generic/bitops/le.h> | ||
298 | #include <asm-generic/bitops/ext2-atomic.h> | ||
299 | |||
300 | #endif /* __KERNEL__ */ | ||
301 | #endif | ||