blob: b9007411b60f977e8393e450d70bcfe3388a7f50 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (c) 1994 - 1997, 1999, 2000 Ralf Baechle (ralf@gnu.org)
7 * Copyright (c) 1999, 2000 Silicon Graphics, Inc.
8 */
9#ifndef _ASM_BITOPS_H
10#define _ASM_BITOPS_H
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/compiler.h>
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000013#include <linux/irqflags.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/types.h>
Ralf Baechleec917c2c2005-10-07 16:58:15 +010015#include <asm/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <asm/byteorder.h> /* sigh ... */
17#include <asm/cpu-features.h>
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000018#include <asm/sgidefs.h>
19#include <asm/war.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
21#if (_MIPS_SZLONG == 32)
22#define SZLONG_LOG 5
23#define SZLONG_MASK 31UL
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000024#define __LL "ll "
25#define __SC "sc "
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#elif (_MIPS_SZLONG == 64)
27#define SZLONG_LOG 6
28#define SZLONG_MASK 63UL
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000029#define __LL "lld "
30#define __SC "scd "
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#endif
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033/*
34 * clear_bit() doesn't provide any barrier for the compiler.
35 */
36#define smp_mb__before_clear_bit() smp_mb()
37#define smp_mb__after_clear_bit() smp_mb()
38
39/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 * set_bit - Atomically set a bit in memory
41 * @nr: the bit to set
42 * @addr: the address to start counting from
43 *
44 * This function is atomic and may not be reordered. See __set_bit()
45 * if you do not require the atomic guarantees.
46 * Note that @nr may be almost arbitrarily large; this function is not
47 * restricted to acting on a single-word quantity.
48 */
49static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
50{
51 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
52 unsigned long temp;
53
54 if (cpu_has_llsc && R10000_LLSC_WAR) {
55 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +000056 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 "1: " __LL "%0, %1 # set_bit \n"
58 " or %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000059 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000061 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 : "=&r" (temp), "=m" (*m)
63 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
64 } else if (cpu_has_llsc) {
65 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +000066 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 "1: " __LL "%0, %1 # set_bit \n"
68 " or %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000069 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000071 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 : "=&r" (temp), "=m" (*m)
73 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
74 } else {
75 volatile unsigned long *a = addr;
76 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000077 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79 a += nr >> SZLONG_LOG;
80 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000081 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 *a |= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000083 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 }
85}
86
87/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 * clear_bit - Clears a bit in memory
89 * @nr: Bit to clear
90 * @addr: Address to start counting from
91 *
92 * clear_bit() is atomic and may not be reordered. However, it does
93 * not contain a memory barrier, so if it is used for locking purposes,
94 * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
95 * in order to ensure changes are visible on other processors.
96 */
97static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
98{
99 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
100 unsigned long temp;
101
102 if (cpu_has_llsc && R10000_LLSC_WAR) {
103 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000104 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 "1: " __LL "%0, %1 # clear_bit \n"
106 " and %0, %2 \n"
107 " " __SC "%0, %1 \n"
108 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000109 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 : "=&r" (temp), "=m" (*m)
111 : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
112 } else if (cpu_has_llsc) {
113 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000114 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 "1: " __LL "%0, %1 # clear_bit \n"
116 " and %0, %2 \n"
117 " " __SC "%0, %1 \n"
118 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000119 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 : "=&r" (temp), "=m" (*m)
121 : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
122 } else {
123 volatile unsigned long *a = addr;
124 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000125 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 a += nr >> SZLONG_LOG;
128 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000129 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 *a &= ~mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000131 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133}
134
135/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 * change_bit - Toggle a bit in memory
137 * @nr: Bit to change
138 * @addr: Address to start counting from
139 *
140 * change_bit() is atomic and may not be reordered.
141 * Note that @nr may be almost arbitrarily large; this function is not
142 * restricted to acting on a single-word quantity.
143 */
144static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
145{
146 if (cpu_has_llsc && R10000_LLSC_WAR) {
147 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
148 unsigned long temp;
149
150 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000151 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 "1: " __LL "%0, %1 # change_bit \n"
153 " xor %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000154 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000156 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 : "=&r" (temp), "=m" (*m)
158 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
159 } else if (cpu_has_llsc) {
160 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
161 unsigned long temp;
162
163 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000164 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 "1: " __LL "%0, %1 # change_bit \n"
166 " xor %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000167 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000169 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 : "=&r" (temp), "=m" (*m)
171 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
172 } else {
173 volatile unsigned long *a = addr;
174 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000175 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177 a += nr >> SZLONG_LOG;
178 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000179 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 *a ^= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000181 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 }
183}
184
185/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 * test_and_set_bit - Set a bit and return its old value
187 * @nr: Bit to set
188 * @addr: Address to count from
189 *
190 * This operation is atomic and cannot be reordered.
191 * It also implies a memory barrier.
192 */
193static inline int test_and_set_bit(unsigned long nr,
194 volatile unsigned long *addr)
195{
196 if (cpu_has_llsc && R10000_LLSC_WAR) {
197 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
198 unsigned long temp, res;
199
200 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000201 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 "1: " __LL "%0, %1 # test_and_set_bit \n"
203 " or %2, %0, %3 \n"
204 " " __SC "%2, %1 \n"
205 " beqzl %2, 1b \n"
206 " and %2, %0, %3 \n"
207#ifdef CONFIG_SMP
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000208 " sync \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000210 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 : "=&r" (temp), "=m" (*m), "=&r" (res)
212 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
213 : "memory");
214
215 return res != 0;
216 } else if (cpu_has_llsc) {
217 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
218 unsigned long temp, res;
219
220 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000221 " .set push \n"
222 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000223 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000224 "1: " __LL "%0, %1 # test_and_set_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 " or %2, %0, %3 \n"
226 " " __SC "%2, %1 \n"
227 " beqz %2, 1b \n"
228 " and %2, %0, %3 \n"
229#ifdef CONFIG_SMP
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000230 " sync \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000232 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 : "=&r" (temp), "=m" (*m), "=&r" (res)
234 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
235 : "memory");
236
237 return res != 0;
238 } else {
239 volatile unsigned long *a = addr;
240 unsigned long mask;
241 int retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000242 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 a += nr >> SZLONG_LOG;
245 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000246 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 retval = (mask & *a) != 0;
248 *a |= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000249 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 return retval;
252 }
253}
254
255/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 * test_and_clear_bit - Clear a bit and return its old value
257 * @nr: Bit to clear
258 * @addr: Address to count from
259 *
260 * This operation is atomic and cannot be reordered.
261 * It also implies a memory barrier.
262 */
263static inline int test_and_clear_bit(unsigned long nr,
264 volatile unsigned long *addr)
265{
266 if (cpu_has_llsc && R10000_LLSC_WAR) {
267 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
268 unsigned long temp, res;
269
270 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000271 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 "1: " __LL "%0, %1 # test_and_clear_bit \n"
273 " or %2, %0, %3 \n"
274 " xor %2, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000275 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 " beqzl %2, 1b \n"
277 " and %2, %0, %3 \n"
278#ifdef CONFIG_SMP
279 " sync \n"
280#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000281 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 : "=&r" (temp), "=m" (*m), "=&r" (res)
283 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
284 : "memory");
285
286 return res != 0;
287 } else if (cpu_has_llsc) {
288 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
289 unsigned long temp, res;
290
291 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000292 " .set push \n"
293 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000294 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000295 "1: " __LL "%0, %1 # test_and_clear_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 " or %2, %0, %3 \n"
297 " xor %2, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000298 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 " beqz %2, 1b \n"
300 " and %2, %0, %3 \n"
301#ifdef CONFIG_SMP
302 " sync \n"
303#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000304 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 : "=&r" (temp), "=m" (*m), "=&r" (res)
306 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
307 : "memory");
308
309 return res != 0;
310 } else {
311 volatile unsigned long *a = addr;
312 unsigned long mask;
313 int retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000314 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 a += nr >> SZLONG_LOG;
317 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000318 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 retval = (mask & *a) != 0;
320 *a &= ~mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000321 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 return retval;
324 }
325}
326
327/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 * test_and_change_bit - Change a bit and return its old value
329 * @nr: Bit to change
330 * @addr: Address to count from
331 *
332 * This operation is atomic and cannot be reordered.
333 * It also implies a memory barrier.
334 */
335static inline int test_and_change_bit(unsigned long nr,
336 volatile unsigned long *addr)
337{
338 if (cpu_has_llsc && R10000_LLSC_WAR) {
339 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
340 unsigned long temp, res;
341
342 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000343 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000344 "1: " __LL "%0, %1 # test_and_change_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 " xor %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000346 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 " beqzl %2, 1b \n"
348 " and %2, %0, %3 \n"
349#ifdef CONFIG_SMP
350 " sync \n"
351#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000352 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 : "=&r" (temp), "=m" (*m), "=&r" (res)
354 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
355 : "memory");
356
357 return res != 0;
358 } else if (cpu_has_llsc) {
359 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
360 unsigned long temp, res;
361
362 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000363 " .set push \n"
364 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000365 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000366 "1: " __LL "%0, %1 # test_and_change_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 " xor %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000368 " " __SC "\t%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 " beqz %2, 1b \n"
370 " and %2, %0, %3 \n"
371#ifdef CONFIG_SMP
372 " sync \n"
373#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000374 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 : "=&r" (temp), "=m" (*m), "=&r" (res)
376 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
377 : "memory");
378
379 return res != 0;
380 } else {
381 volatile unsigned long *a = addr;
382 unsigned long mask, retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000383 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 a += nr >> SZLONG_LOG;
386 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000387 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 retval = (mask & *a) != 0;
389 *a ^= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000390 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392 return retval;
393 }
394}
395
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800396#include <asm-generic/bitops/non-atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Ralf Baechle65903262005-07-12 12:50:30 +0000398/*
399 * Return the bit position (0..63) of the most significant 1 bit in a word
400 * Returns -1 if no 1 bit exists
401 */
Ralf Baechleec917c2c2005-10-07 16:58:15 +0100402static inline int __ilog2(unsigned long x)
Ralf Baechle65903262005-07-12 12:50:30 +0000403{
404 int lz;
405
Ralf Baechleec917c2c2005-10-07 16:58:15 +0100406 if (sizeof(x) == 4) {
407 __asm__ (
408 " .set push \n"
409 " .set mips32 \n"
410 " clz %0, %1 \n"
411 " .set pop \n"
412 : "=r" (lz)
413 : "r" (x));
414
415 return 31 - lz;
416 }
417
418 BUG_ON(sizeof(x) != 8);
419
Ralf Baechle65903262005-07-12 12:50:30 +0000420 __asm__ (
421 " .set push \n"
422 " .set mips64 \n"
423 " dclz %0, %1 \n"
424 " .set pop \n"
425 : "=r" (lz)
426 : "r" (x));
427
428 return 63 - lz;
429}
Ralf Baechle65903262005-07-12 12:50:30 +0000430
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800431#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
432
Ralf Baechle65903262005-07-12 12:50:30 +0000433/*
434 * __ffs - find first bit in word.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 * @word: The word to search
436 *
Ralf Baechle65903262005-07-12 12:50:30 +0000437 * Returns 0..SZLONG-1
438 * Undefined if no bit exists, so code should check against 0 first.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 */
Ralf Baechle65903262005-07-12 12:50:30 +0000440static inline unsigned long __ffs(unsigned long word)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
Ralf Baechle65903262005-07-12 12:50:30 +0000442 return __ilog2(word & -word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
445/*
Atsushi Nemotobc818242006-04-17 21:19:12 +0900446 * fls - find last bit set.
447 * @word: The word to search
448 *
449 * This is defined the same way as ffs.
450 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
451 */
452static inline int fls(int word)
453{
454 __asm__ ("clz %0, %1" : "=r" (word) : "r" (word));
455
456 return 32 - word;
457}
458
459#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPS64)
460static inline int fls64(__u64 word)
461{
462 __asm__ ("dclz %0, %1" : "=r" (word) : "r" (word));
463
464 return 64 - word;
465}
466#else
467#include <asm-generic/bitops/fls64.h>
468#endif
469
470/*
Ralf Baechle65903262005-07-12 12:50:30 +0000471 * ffs - find first bit set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 * @word: The word to search
473 *
Atsushi Nemotobc818242006-04-17 21:19:12 +0900474 * This is defined the same way as
475 * the libc and compiler builtin ffs routines, therefore
476 * differs in spirit from the above ffz (man ffs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 */
Atsushi Nemotobc818242006-04-17 21:19:12 +0900478static inline int ffs(int word)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
Ralf Baechle65903262005-07-12 12:50:30 +0000480 if (!word)
481 return 0;
482
Atsushi Nemotobc818242006-04-17 21:19:12 +0900483 return fls(word & -word);
Ralf Baechle65903262005-07-12 12:50:30 +0000484}
Ralf Baechle2caf1902006-01-30 17:14:41 +0000485
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800486#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800488#include <asm-generic/bitops/__ffs.h>
489#include <asm-generic/bitops/ffs.h>
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800490#include <asm-generic/bitops/fls.h>
Atsushi Nemotobc818242006-04-17 21:19:12 +0900491#include <asm-generic/bitops/fls64.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800493#endif /*defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Atsushi Nemotobc818242006-04-17 21:19:12 +0900495#include <asm-generic/bitops/ffz.h>
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800496#include <asm-generic/bitops/find.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498#ifdef __KERNEL__
499
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800500#include <asm-generic/bitops/sched.h>
501#include <asm-generic/bitops/hweight.h>
502#include <asm-generic/bitops/ext2-non-atomic.h>
503#include <asm-generic/bitops/ext2-atomic.h>
504#include <asm-generic/bitops/minix.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506#endif /* __KERNEL__ */
507
508#endif /* _ASM_BITOPS_H */