blob: 8cd61c1970528c4225ec78881372235683c933f5 [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 Baechleec917c22005-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 "
Ralf Baechle42a3b4f2005-09-03 15:56:17 -070026#define cpu_to_lelongp(x) cpu_to_le32p((__u32 *) (x))
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 "
Ralf Baechle42a3b4f2005-09-03 15:56:17 -070032#define cpu_to_lelongp(x) cpu_to_le64p((__u64 *) (x))
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#endif
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/*
36 * clear_bit() doesn't provide any barrier for the compiler.
37 */
38#define smp_mb__before_clear_bit() smp_mb()
39#define smp_mb__after_clear_bit() smp_mb()
40
41/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 * set_bit - Atomically set a bit in memory
43 * @nr: the bit to set
44 * @addr: the address to start counting from
45 *
46 * This function is atomic and may not be reordered. See __set_bit()
47 * if you do not require the atomic guarantees.
48 * Note that @nr may be almost arbitrarily large; this function is not
49 * restricted to acting on a single-word quantity.
50 */
51static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
52{
53 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
54 unsigned long temp;
55
56 if (cpu_has_llsc && R10000_LLSC_WAR) {
57 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +000058 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 "1: " __LL "%0, %1 # set_bit \n"
60 " or %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000061 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000063 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 : "=&r" (temp), "=m" (*m)
65 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
66 } else if (cpu_has_llsc) {
67 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +000068 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 "1: " __LL "%0, %1 # set_bit \n"
70 " or %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000071 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +000073 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 : "=&r" (temp), "=m" (*m)
75 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
76 } else {
77 volatile unsigned long *a = addr;
78 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000079 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
81 a += nr >> SZLONG_LOG;
82 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000083 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 *a |= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +000085 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 }
87}
88
89/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 * clear_bit - Clears a bit in memory
91 * @nr: Bit to clear
92 * @addr: Address to start counting from
93 *
94 * clear_bit() is atomic and may not be reordered. However, it does
95 * not contain a memory barrier, so if it is used for locking purposes,
96 * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
97 * in order to ensure changes are visible on other processors.
98 */
99static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
100{
101 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
102 unsigned long temp;
103
104 if (cpu_has_llsc && R10000_LLSC_WAR) {
105 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000106 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 "1: " __LL "%0, %1 # clear_bit \n"
108 " and %0, %2 \n"
109 " " __SC "%0, %1 \n"
110 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000111 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 : "=&r" (temp), "=m" (*m)
113 : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
114 } else if (cpu_has_llsc) {
115 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000116 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 "1: " __LL "%0, %1 # clear_bit \n"
118 " and %0, %2 \n"
119 " " __SC "%0, %1 \n"
120 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000121 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 : "=&r" (temp), "=m" (*m)
123 : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
124 } else {
125 volatile unsigned long *a = addr;
126 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000127 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129 a += nr >> SZLONG_LOG;
130 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000131 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 *a &= ~mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000133 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 }
135}
136
137/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 * change_bit - Toggle a bit in memory
139 * @nr: Bit to change
140 * @addr: Address to start counting from
141 *
142 * change_bit() is atomic and may not be reordered.
143 * Note that @nr may be almost arbitrarily large; this function is not
144 * restricted to acting on a single-word quantity.
145 */
146static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
147{
148 if (cpu_has_llsc && R10000_LLSC_WAR) {
149 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
150 unsigned long temp;
151
152 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000153 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 "1: " __LL "%0, %1 # change_bit \n"
155 " xor %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000156 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 " beqzl %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000158 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 : "=&r" (temp), "=m" (*m)
160 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
161 } else if (cpu_has_llsc) {
162 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
163 unsigned long temp;
164
165 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000166 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 "1: " __LL "%0, %1 # change_bit \n"
168 " xor %0, %2 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000169 " " __SC "%0, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 " beqz %0, 1b \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000171 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 : "=&r" (temp), "=m" (*m)
173 : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
174 } else {
175 volatile unsigned long *a = addr;
176 unsigned long mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000177 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 a += nr >> SZLONG_LOG;
180 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000181 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 *a ^= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000183 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 }
185}
186
187/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 * test_and_set_bit - Set a bit and return its old value
189 * @nr: Bit to set
190 * @addr: Address to count from
191 *
192 * This operation is atomic and cannot be reordered.
193 * It also implies a memory barrier.
194 */
195static inline int test_and_set_bit(unsigned long nr,
196 volatile unsigned long *addr)
197{
198 if (cpu_has_llsc && R10000_LLSC_WAR) {
199 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
200 unsigned long temp, res;
201
202 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000203 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 "1: " __LL "%0, %1 # test_and_set_bit \n"
205 " or %2, %0, %3 \n"
206 " " __SC "%2, %1 \n"
207 " beqzl %2, 1b \n"
208 " and %2, %0, %3 \n"
209#ifdef CONFIG_SMP
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000210 " sync \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000212 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 : "=&r" (temp), "=m" (*m), "=&r" (res)
214 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
215 : "memory");
216
217 return res != 0;
218 } else if (cpu_has_llsc) {
219 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
220 unsigned long temp, res;
221
222 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000223 " .set push \n"
224 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000225 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000226 "1: " __LL "%0, %1 # test_and_set_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 " or %2, %0, %3 \n"
228 " " __SC "%2, %1 \n"
229 " beqz %2, 1b \n"
230 " and %2, %0, %3 \n"
231#ifdef CONFIG_SMP
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000232 " sync \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000234 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 : "=&r" (temp), "=m" (*m), "=&r" (res)
236 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
237 : "memory");
238
239 return res != 0;
240 } else {
241 volatile unsigned long *a = addr;
242 unsigned long mask;
243 int retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000244 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 a += nr >> SZLONG_LOG;
247 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000248 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 retval = (mask & *a) != 0;
250 *a |= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000251 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253 return retval;
254 }
255}
256
257/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 * test_and_clear_bit - Clear a bit and return its old value
259 * @nr: Bit to clear
260 * @addr: Address to count from
261 *
262 * This operation is atomic and cannot be reordered.
263 * It also implies a memory barrier.
264 */
265static inline int test_and_clear_bit(unsigned long nr,
266 volatile unsigned long *addr)
267{
268 if (cpu_has_llsc && R10000_LLSC_WAR) {
269 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
270 unsigned long temp, res;
271
272 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000273 " .set mips3 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 "1: " __LL "%0, %1 # test_and_clear_bit \n"
275 " or %2, %0, %3 \n"
276 " xor %2, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000277 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 " beqzl %2, 1b \n"
279 " and %2, %0, %3 \n"
280#ifdef CONFIG_SMP
281 " sync \n"
282#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000283 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 : "=&r" (temp), "=m" (*m), "=&r" (res)
285 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
286 : "memory");
287
288 return res != 0;
289 } else if (cpu_has_llsc) {
290 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
291 unsigned long temp, res;
292
293 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000294 " .set push \n"
295 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000296 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000297 "1: " __LL "%0, %1 # test_and_clear_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 " or %2, %0, %3 \n"
299 " xor %2, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000300 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 " beqz %2, 1b \n"
302 " and %2, %0, %3 \n"
303#ifdef CONFIG_SMP
304 " sync \n"
305#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000306 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 : "=&r" (temp), "=m" (*m), "=&r" (res)
308 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
309 : "memory");
310
311 return res != 0;
312 } else {
313 volatile unsigned long *a = addr;
314 unsigned long mask;
315 int retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000316 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 a += nr >> SZLONG_LOG;
319 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000320 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 retval = (mask & *a) != 0;
322 *a &= ~mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000323 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 return retval;
326 }
327}
328
329/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 * test_and_change_bit - Change a bit and return its old value
331 * @nr: Bit to change
332 * @addr: Address to count from
333 *
334 * This operation is atomic and cannot be reordered.
335 * It also implies a memory barrier.
336 */
337static inline int test_and_change_bit(unsigned long nr,
338 volatile unsigned long *addr)
339{
340 if (cpu_has_llsc && R10000_LLSC_WAR) {
341 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
342 unsigned long temp, res;
343
344 __asm__ __volatile__(
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000345 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000346 "1: " __LL "%0, %1 # test_and_change_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 " xor %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000348 " " __SC "%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 " beqzl %2, 1b \n"
350 " and %2, %0, %3 \n"
351#ifdef CONFIG_SMP
352 " sync \n"
353#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000354 " .set mips0 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 : "=&r" (temp), "=m" (*m), "=&r" (res)
356 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
357 : "memory");
358
359 return res != 0;
360 } else if (cpu_has_llsc) {
361 unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
362 unsigned long temp, res;
363
364 __asm__ __volatile__(
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000365 " .set push \n"
366 " .set noreorder \n"
Maciej W. Rozyckic4559f62005-06-23 15:57:15 +0000367 " .set mips3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000368 "1: " __LL "%0, %1 # test_and_change_bit \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 " xor %2, %0, %3 \n"
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000370 " " __SC "\t%2, %1 \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 " beqz %2, 1b \n"
372 " and %2, %0, %3 \n"
373#ifdef CONFIG_SMP
374 " sync \n"
375#endif
Maciej W. Rozyckiaac8aa72005-06-14 17:35:03 +0000376 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 : "=&r" (temp), "=m" (*m), "=&r" (res)
378 : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
379 : "memory");
380
381 return res != 0;
382 } else {
383 volatile unsigned long *a = addr;
384 unsigned long mask, retval;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000385 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 a += nr >> SZLONG_LOG;
388 mask = 1UL << (nr & SZLONG_MASK);
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000389 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 retval = (mask & *a) != 0;
391 *a ^= mask;
Ralf Baechle4ffd8b32006-11-30 01:14:50 +0000392 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 return retval;
395 }
396}
397
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800398#include <asm-generic/bitops/non-atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Ralf Baechle65903262005-07-12 12:50:30 +0000400/*
401 * Return the bit position (0..63) of the most significant 1 bit in a word
402 * Returns -1 if no 1 bit exists
403 */
Ralf Baechleec917c22005-10-07 16:58:15 +0100404static inline int __ilog2(unsigned long x)
Ralf Baechle65903262005-07-12 12:50:30 +0000405{
406 int lz;
407
Ralf Baechleec917c22005-10-07 16:58:15 +0100408 if (sizeof(x) == 4) {
409 __asm__ (
410 " .set push \n"
411 " .set mips32 \n"
412 " clz %0, %1 \n"
413 " .set pop \n"
414 : "=r" (lz)
415 : "r" (x));
416
417 return 31 - lz;
418 }
419
420 BUG_ON(sizeof(x) != 8);
421
Ralf Baechle65903262005-07-12 12:50:30 +0000422 __asm__ (
423 " .set push \n"
424 " .set mips64 \n"
425 " dclz %0, %1 \n"
426 " .set pop \n"
427 : "=r" (lz)
428 : "r" (x));
429
430 return 63 - lz;
431}
Ralf Baechle65903262005-07-12 12:50:30 +0000432
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800433#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
434
Ralf Baechle65903262005-07-12 12:50:30 +0000435/*
436 * __ffs - find first bit in word.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 * @word: The word to search
438 *
Ralf Baechle65903262005-07-12 12:50:30 +0000439 * Returns 0..SZLONG-1
440 * Undefined if no bit exists, so code should check against 0 first.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 */
Ralf Baechle65903262005-07-12 12:50:30 +0000442static inline unsigned long __ffs(unsigned long word)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Ralf Baechle65903262005-07-12 12:50:30 +0000444 return __ilog2(word & -word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
447/*
Atsushi Nemotobc818242006-04-17 21:19:12 +0900448 * fls - find last bit set.
449 * @word: The word to search
450 *
451 * This is defined the same way as ffs.
452 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
453 */
454static inline int fls(int word)
455{
456 __asm__ ("clz %0, %1" : "=r" (word) : "r" (word));
457
458 return 32 - word;
459}
460
461#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPS64)
462static inline int fls64(__u64 word)
463{
464 __asm__ ("dclz %0, %1" : "=r" (word) : "r" (word));
465
466 return 64 - word;
467}
468#else
469#include <asm-generic/bitops/fls64.h>
470#endif
471
472/*
Ralf Baechle65903262005-07-12 12:50:30 +0000473 * ffs - find first bit set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 * @word: The word to search
475 *
Atsushi Nemotobc818242006-04-17 21:19:12 +0900476 * This is defined the same way as
477 * the libc and compiler builtin ffs routines, therefore
478 * differs in spirit from the above ffz (man ffs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 */
Atsushi Nemotobc818242006-04-17 21:19:12 +0900480static inline int ffs(int word)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
Ralf Baechle65903262005-07-12 12:50:30 +0000482 if (!word)
483 return 0;
484
Atsushi Nemotobc818242006-04-17 21:19:12 +0900485 return fls(word & -word);
Ralf Baechle65903262005-07-12 12:50:30 +0000486}
Ralf Baechle2caf1902006-01-30 17:14:41 +0000487
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800488#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800490#include <asm-generic/bitops/__ffs.h>
491#include <asm-generic/bitops/ffs.h>
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800492#include <asm-generic/bitops/fls.h>
Atsushi Nemotobc818242006-04-17 21:19:12 +0900493#include <asm-generic/bitops/fls64.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800495#endif /*defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Atsushi Nemotobc818242006-04-17 21:19:12 +0900497#include <asm-generic/bitops/ffz.h>
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800498#include <asm-generic/bitops/find.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
500#ifdef __KERNEL__
501
Akinobu Mita3c9ee7e2006-03-26 01:39:30 -0800502#include <asm-generic/bitops/sched.h>
503#include <asm-generic/bitops/hweight.h>
504#include <asm-generic/bitops/ext2-non-atomic.h>
505#include <asm-generic/bitops/ext2-atomic.h>
506#include <asm-generic/bitops/minix.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508#endif /* __KERNEL__ */
509
510#endif /* _ASM_BITOPS_H */