blob: 06445de1324bd3c058a507d08d0c747d6ab571ae [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 *
Ralf Baechle0004a9d2006-10-31 03:45:07 +00006 * Copyright (c) 1994 - 1997, 1999, 2000, 06 Ralf Baechle (ralf@linux-mips.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * 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 Baechle0004a9d2006-10-31 03:45:07 +000015#include <asm/barrier.h>
Ralf Baechleec917c22005-10-07 16:58:15 +010016#include <asm/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <asm/byteorder.h> /* sigh ... */
18#include <asm/cpu-features.h>
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000019#include <asm/sgidefs.h>
20#include <asm/war.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22#if (_MIPS_SZLONG == 32)
23#define SZLONG_LOG 5
24#define SZLONG_MASK 31UL
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000025#define __LL "ll "
26#define __SC "sc "
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#elif (_MIPS_SZLONG == 64)
28#define SZLONG_LOG 6
29#define SZLONG_MASK 63UL
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000030#define __LL "lld "
31#define __SC "scd "
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#endif
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034/*
35 * clear_bit() doesn't provide any barrier for the compiler.
36 */
37#define smp_mb__before_clear_bit() smp_mb()
38#define smp_mb__after_clear_bit() smp_mb()
39
40/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 * set_bit - Atomically set a bit in memory
42 * @nr: the bit to set
43 * @addr: the address to start counting from
44 *
45 * This function is atomic and may not be reordered. See __set_bit()
46 * if you do not require the atomic guarantees.
47 * Note that @nr may be almost arbitrarily large; this function is not
48 * restricted to acting on a single-word quantity.
49 */
50static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
51{
52 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
53 unsigned long temp;
54
55 if (cpu_has_llsc && R10000_LLSC_WAR) {
56 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +000057 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 "1: " __LL "%0, %1 # set_bit \n"
59 " or %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000060 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000062 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 : "=&r" (temp), "=m" (*m)
64 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
65 } else if (cpu_has_llsc) {
66 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +000067 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 "1: " __LL "%0, %1 # set_bit \n"
69 " or %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000070 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000072 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 : "=&r" (temp), "=m" (*m)
74 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
75 } else {
76 volatile unsigned long *a = addr;
77 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000078 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80 a += nr >> SZLONG_LOG;
81 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000082 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 *a |= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000084 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 }
86}
87
88/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 * clear_bit - Clears a bit in memory
90 * @nr: Bit to clear
91 * @addr: Address to start counting from
92 *
93 * clear_bit() is atomic and may not be reordered. However, it does
94 * not contain a memory barrier, so if it is used for locking purposes,
95 * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
96 * in order to ensure changes are visible on other processors.
97 */
98static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
99{
100 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
101 unsigned long temp;
102
103 if (cpu_has_llsc && R10000_LLSC_WAR) {
104 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000105 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 "1: " __LL "%0, %1 # clear_bit \n"
107 " and %0, %2 \n"
108 " " __SC "%0, %1 \n"
109 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000110 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 : "=&r" (temp), "=m" (*m)
112 : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
113 } else if (cpu_has_llsc) {
114 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000115 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 "1: " __LL "%0, %1 # clear_bit \n"
117 " and %0, %2 \n"
118 " " __SC "%0, %1 \n"
119 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000120 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 : "=&r" (temp), "=m" (*m)
122 : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
123 } else {
124 volatile unsigned long *a = addr;
125 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000126 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128 a += nr >> SZLONG_LOG;
129 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000130 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 *a &= ~mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000132 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 }
134}
135
136/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 * change_bit - Toggle a bit in memory
138 * @nr: Bit to change
139 * @addr: Address to start counting from
140 *
141 * change_bit() is atomic and may not be reordered.
142 * Note that @nr may be almost arbitrarily large; this function is not
143 * restricted to acting on a single-word quantity.
144 */
145static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
146{
147 if (cpu_has_llsc && R10000_LLSC_WAR) {
148 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
149 unsigned long temp;
150
151 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000152 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 "1: " __LL "%0, %1 # change_bit \n"
154 " xor %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000155 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000157 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 : "=&r" (temp), "=m" (*m)
159 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
160 } else if (cpu_has_llsc) {
161 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
162 unsigned long temp;
163
164 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000165 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 "1: " __LL "%0, %1 # change_bit \n"
167 " xor %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000168 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000170 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 : "=&r" (temp), "=m" (*m)
172 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
173 } else {
174 volatile unsigned long *a = addr;
175 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000176 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178 a += nr >> SZLONG_LOG;
179 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000180 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 *a ^= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000182 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
184}
185
186/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 * test_and_set_bit - Set a bit and return its old value
188 * @nr: Bit to set
189 * @addr: Address to count from
190 *
191 * This operation is atomic and cannot be reordered.
192 * It also implies a memory barrier.
193 */
194static inline int test_and_set_bit(unsigned long nr,
195 volatile unsigned long *addr)
196{
197 if (cpu_has_llsc && R10000_LLSC_WAR) {
198 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
199 unsigned long temp, res;
200
201 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000202 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 "1: " __LL "%0, %1 # test_and_set_bit \n"
204 " or %2, %0, %3 \n"
205 " " __SC "%2, %1 \n"
206 " beqzl %2, 1b \n"
207 " and %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000208 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 : "=&r" (temp), "=m" (*m), "=&r" (res)
210 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
211 : "memory");
212
213 return res != 0;
214 } else if (cpu_has_llsc) {
215 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
216 unsigned long temp, res;
217
218 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000219 " .set push \n"
220 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000221 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000222 "1: " __LL "%0, %1 # test_and_set_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 " or %2, %0, %3 \n"
224 " " __SC "%2, %1 \n"
225 " beqz %2, 1b \n"
226 " and %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000227 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 : "=&r" (temp), "=m" (*m), "=&r" (res)
229 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
230 : "memory");
231
232 return res != 0;
233 } else {
234 volatile unsigned long *a = addr;
235 unsigned long mask;
236 int retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000237 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 a += nr >> SZLONG_LOG;
240 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000241 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 retval = (mask & *a) != 0;
243 *a |= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000244 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 return retval;
247 }
Ralf Baechle0004a9d2006-10-31 03:45:07 +0000248
249 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250}
251
252/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 * test_and_clear_bit - Clear a bit and return its old value
254 * @nr: Bit to clear
255 * @addr: Address to count from
256 *
257 * This operation is atomic and cannot be reordered.
258 * It also implies a memory barrier.
259 */
260static inline int test_and_clear_bit(unsigned long nr,
261 volatile unsigned long *addr)
262{
263 if (cpu_has_llsc && R10000_LLSC_WAR) {
264 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
265 unsigned long temp, res;
266
267 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000268 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 "1: " __LL "%0, %1 # test_and_clear_bit \n"
270 " or %2, %0, %3 \n"
271 " xor %2, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000272 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 " beqzl %2, 1b \n"
274 " and %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000275 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 : "=&r" (temp), "=m" (*m), "=&r" (res)
277 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
278 : "memory");
279
280 return res != 0;
281 } else if (cpu_has_llsc) {
282 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
283 unsigned long temp, res;
284
285 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000286 " .set push \n"
287 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000288 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000289 "1: " __LL "%0, %1 # test_and_clear_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 " or %2, %0, %3 \n"
291 " xor %2, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000292 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 " beqz %2, 1b \n"
294 " and %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000295 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 : "=&r" (temp), "=m" (*m), "=&r" (res)
297 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
298 : "memory");
299
300 return res != 0;
301 } else {
302 volatile unsigned long *a = addr;
303 unsigned long mask;
304 int retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000305 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 a += nr >> SZLONG_LOG;
308 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000309 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 retval = (mask & *a) != 0;
311 *a &= ~mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000312 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 return retval;
315 }
Ralf Baechle0004a9d2006-10-31 03:45:07 +0000316
317 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318}
319
320/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 * test_and_change_bit - Change a bit and return its old value
322 * @nr: Bit to change
323 * @addr: Address to count from
324 *
325 * This operation is atomic and cannot be reordered.
326 * It also implies a memory barrier.
327 */
328static inline int test_and_change_bit(unsigned long nr,
329 volatile unsigned long *addr)
330{
331 if (cpu_has_llsc && R10000_LLSC_WAR) {
332 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
333 unsigned long temp, res;
334
335 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000336 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000337 "1: " __LL "%0, %1 # test_and_change_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 " xor %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000339 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 " beqzl %2, 1b \n"
341 " and %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000342 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 : "=&r" (temp), "=m" (*m), "=&r" (res)
344 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
345 : "memory");
346
347 return res != 0;
348 } else if (cpu_has_llsc) {
349 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
350 unsigned long temp, res;
351
352 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000353 " .set push \n"
354 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000355 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000356 "1: " __LL "%0, %1 # test_and_change_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 " xor %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000358 " " __SC "\t%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 " beqz %2, 1b \n"
360 " and %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000361 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 : "=&r" (temp), "=m" (*m), "=&r" (res)
363 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
364 : "memory");
365
366 return res != 0;
367 } else {
368 volatile unsigned long *a = addr;
369 unsigned long mask, retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000370 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 a += nr >> SZLONG_LOG;
373 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000374 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 retval = (mask & *a) != 0;
376 *a ^= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000377 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 return retval;
380 }
Ralf Baechle0004a9d2006-10-31 03:45:07 +0000381
382 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800385#include <asm-generic/bitops/non-atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Ralf Baechle65903262005-07-12 12:50:30 +0000387/*
388 * Return the bit position (0..63) of the most significant 1 bit in a word
389 * Returns -1 if no 1 bit exists
390 */
Ralf Baechleec917c22005-10-07 16:58:15 +0100391static inline int __ilog2(unsigned long x)
Ralf Baechle65903262005-07-12 12:50:30 +0000392{
393 int lz;
394
Ralf Baechleec917c22005-10-07 16:58:15 +0100395 if (sizeof(x) == 4) {
396 __asm__ (
397 " .set push \n"
398 " .set mips32 \n"
399 " clz %0, %1 \n"
400 " .set pop \n"
401 : "=r" (lz)
402 : "r" (x));
403
404 return 31 - lz;
405 }
406
407 BUG_ON(sizeof(x) != 8);
408
Ralf Baechle65903262005-07-12 12:50:30 +0000409 __asm__ (
410 " .set push \n"
411 " .set mips64 \n"
412 " dclz %0, %1 \n"
413 " .set pop \n"
414 : "=r" (lz)
415 : "r" (x));
416
417 return 63 - lz;
418}
Ralf Baechle65903262005-07-12 12:50:30 +0000419
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800420#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
421
Ralf Baechle65903262005-07-12 12:50:30 +0000422/*
423 * __ffs - find first bit in word.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 * @word: The word to search
425 *
Ralf Baechle65903262005-07-12 12:50:30 +0000426 * Returns 0..SZLONG-1
427 * Undefined if no bit exists, so code should check against 0 first.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 */
Ralf Baechle65903262005-07-12 12:50:30 +0000429static inline unsigned long __ffs(unsigned long word)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{
Ralf Baechle65903262005-07-12 12:50:30 +0000431 return __ilog2(word & -word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432}
433
434/*
Atsushi Nemotobc818242006-04-17 21:19:12 +0900435 * fls - find last bit set.
436 * @word: The word to search
437 *
438 * This is defined the same way as ffs.
439 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
440 */
441static inline int fls(int word)
442{
443 __asm__ ("clz %0, %1" : "=r" (word) : "r" (word));
444
445 return 32 - word;
446}
447
448#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPS64)
449static inline int fls64(__u64 word)
450{
451 __asm__ ("dclz %0, %1" : "=r" (word) : "r" (word));
452
453 return 64 - word;
454}
455#else
456#include <asm-generic/bitops/fls64.h>
457#endif
458
459/*
Ralf Baechle65903262005-07-12 12:50:30 +0000460 * ffs - find first bit set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 * @word: The word to search
462 *
Atsushi Nemotobc818242006-04-17 21:19:12 +0900463 * This is defined the same way as
464 * the libc and compiler builtin ffs routines, therefore
465 * differs in spirit from the above ffz (man ffs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 */
Atsushi Nemotobc818242006-04-17 21:19:12 +0900467static inline int ffs(int word)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468{
Ralf Baechle65903262005-07-12 12:50:30 +0000469 if (!word)
470 return 0;
471
Atsushi Nemotobc818242006-04-17 21:19:12 +0900472 return fls(word & -word);
Ralf Baechle65903262005-07-12 12:50:30 +0000473}
Ralf Baechle2caf1902006-01-30 17:14:41 +0000474
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800475#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800477#include <asm-generic/bitops/__ffs.h>
478#include <asm-generic/bitops/ffs.h>
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800479#include <asm-generic/bitops/fls.h>
Atsushi Nemotobc818242006-04-17 21:19:12 +0900480#include <asm-generic/bitops/fls64.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800482#endif /*defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Atsushi Nemotobc818242006-04-17 21:19:12 +0900484#include <asm-generic/bitops/ffz.h>
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800485#include <asm-generic/bitops/find.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487#ifdef __KERNEL__
488
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800489#include <asm-generic/bitops/sched.h>
490#include <asm-generic/bitops/hweight.h>
491#include <asm-generic/bitops/ext2-non-atomic.h>
492#include <asm-generic/bitops/ext2-atomic.h>
493#include <asm-generic/bitops/minix.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495#endif /* __KERNEL__ */
496
497#endif /* _ASM_BITOPS_H */