| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /* find_next_bit.c: fallback find next bit implementation
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * Written by David Howells (dhowells@redhat.com) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version | 
					
						
							|  |  |  |  * 2 of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/bitops.h>
 | 
					
						
							| 
									
										
										
										
											2011-11-16 21:29:17 -05:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | #include <asm/types.h>
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:15 -08:00
										 |  |  | #include <asm/byteorder.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | #define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #ifndef find_next_bit
 | 
					
						
							| 
									
										
										
										
											2008-03-11 16:17:19 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Find the next set bit in a memory region. | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, | 
					
						
							|  |  |  | 			    unsigned long offset) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | 	const unsigned long *p = addr + BITOP_WORD(offset); | 
					
						
							|  |  |  | 	unsigned long result = offset & ~(BITS_PER_LONG-1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	unsigned long tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | 	if (offset >= size) | 
					
						
							|  |  |  | 		return size; | 
					
						
							|  |  |  | 	size -= result; | 
					
						
							|  |  |  | 	offset %= BITS_PER_LONG; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (offset) { | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | 		tmp = *(p++); | 
					
						
							|  |  |  | 		tmp &= (~0UL << offset); | 
					
						
							|  |  |  | 		if (size < BITS_PER_LONG) | 
					
						
							|  |  |  | 			goto found_first; | 
					
						
							|  |  |  | 		if (tmp) | 
					
						
							|  |  |  | 			goto found_middle; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	while (size & ~(BITS_PER_LONG-1)) { | 
					
						
							|  |  |  | 		if ((tmp = *(p++))) | 
					
						
							|  |  |  | 			goto found_middle; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | 	if (!size) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	tmp = *p; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | found_first: | 
					
						
							|  |  |  | 	tmp &= (~0UL >> (BITS_PER_LONG - size)); | 
					
						
							|  |  |  | 	if (tmp == 0UL)		/* Are any bits set? */ | 
					
						
							|  |  |  | 		return result + size;	/* Nope. */ | 
					
						
							|  |  |  | found_middle: | 
					
						
							|  |  |  | 	return result + __ffs(tmp); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | EXPORT_SYMBOL(find_next_bit); | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #ifndef find_next_zero_bit
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This implementation of find_{first,next}_zero_bit was stolen from | 
					
						
							|  |  |  |  * Linus' asm-alpha/bitops.h. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, | 
					
						
							|  |  |  | 				 unsigned long offset) | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	const unsigned long *p = addr + BITOP_WORD(offset); | 
					
						
							|  |  |  | 	unsigned long result = offset & ~(BITS_PER_LONG-1); | 
					
						
							|  |  |  | 	unsigned long tmp; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | 	if (offset >= size) | 
					
						
							|  |  |  | 		return size; | 
					
						
							|  |  |  | 	size -= result; | 
					
						
							|  |  |  | 	offset %= BITS_PER_LONG; | 
					
						
							|  |  |  | 	if (offset) { | 
					
						
							|  |  |  | 		tmp = *(p++); | 
					
						
							|  |  |  | 		tmp |= ~0UL >> (BITS_PER_LONG - offset); | 
					
						
							|  |  |  | 		if (size < BITS_PER_LONG) | 
					
						
							|  |  |  | 			goto found_first; | 
					
						
							|  |  |  | 		if (~tmp) | 
					
						
							|  |  |  | 			goto found_middle; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	while (size & ~(BITS_PER_LONG-1)) { | 
					
						
							|  |  |  | 		if (~(tmp = *(p++))) | 
					
						
							|  |  |  | 			goto found_middle; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | 	if (!size) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	tmp = *p; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:11 -08:00
										 |  |  | found_first: | 
					
						
							|  |  |  | 	tmp |= ~0UL << size; | 
					
						
							|  |  |  | 	if (tmp == ~0UL)	/* Are any bits zero? */ | 
					
						
							|  |  |  | 		return result + size;	/* Nope. */ | 
					
						
							|  |  |  | found_middle: | 
					
						
							|  |  |  | 	return result + ffz(tmp); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | EXPORT_SYMBOL(find_next_zero_bit); | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-04-01 11:46:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #ifndef find_first_bit
 | 
					
						
							| 
									
										
										
										
											2008-04-01 11:46:19 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Find the first set bit in a memory region. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | unsigned long find_first_bit(const unsigned long *addr, unsigned long size) | 
					
						
							| 
									
										
										
										
											2008-04-01 11:46:19 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	const unsigned long *p = addr; | 
					
						
							|  |  |  | 	unsigned long result = 0; | 
					
						
							|  |  |  | 	unsigned long tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (size & ~(BITS_PER_LONG-1)) { | 
					
						
							|  |  |  | 		if ((tmp = *(p++))) | 
					
						
							|  |  |  | 			goto found; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!size) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); | 
					
						
							|  |  |  | 	if (tmp == 0UL)		/* Are any bits set? */ | 
					
						
							|  |  |  | 		return result + size;	/* Nope. */ | 
					
						
							|  |  |  | found: | 
					
						
							|  |  |  | 	return result + __ffs(tmp); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | EXPORT_SYMBOL(find_first_bit); | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-04-01 11:46:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #ifndef find_first_zero_bit
 | 
					
						
							| 
									
										
										
										
											2008-04-01 11:46:19 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Find the first cleared bit in a memory region. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) | 
					
						
							| 
									
										
										
										
											2008-04-01 11:46:19 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	const unsigned long *p = addr; | 
					
						
							|  |  |  | 	unsigned long result = 0; | 
					
						
							|  |  |  | 	unsigned long tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (size & ~(BITS_PER_LONG-1)) { | 
					
						
							|  |  |  | 		if (~(tmp = *(p++))) | 
					
						
							|  |  |  | 			goto found; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!size) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp = (*p) | (~0UL << size); | 
					
						
							|  |  |  | 	if (tmp == ~0UL)	/* Are any bits zero? */ | 
					
						
							|  |  |  | 		return result + size;	/* Nope. */ | 
					
						
							|  |  |  | found: | 
					
						
							|  |  |  | 	return result + ffz(tmp); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-04-29 12:01:02 +02:00
										 |  |  | EXPORT_SYMBOL(find_first_zero_bit); | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:15 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef __BIG_ENDIAN
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* include/linux/byteorder does not support "unsigned long" type */ | 
					
						
							|  |  |  | static inline unsigned long ext2_swabp(const unsigned long * x) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if BITS_PER_LONG == 64
 | 
					
						
							|  |  |  | 	return (unsigned long) __swab64p((u64 *) x); | 
					
						
							|  |  |  | #elif BITS_PER_LONG == 32
 | 
					
						
							|  |  |  | 	return (unsigned long) __swab32p((u32 *) x); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #error BITS_PER_LONG not defined
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* include/linux/byteorder doesn't support "unsigned long" type */ | 
					
						
							|  |  |  | static inline unsigned long ext2_swab(const unsigned long y) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if BITS_PER_LONG == 64
 | 
					
						
							|  |  |  | 	return (unsigned long) __swab64((u64) y); | 
					
						
							|  |  |  | #elif BITS_PER_LONG == 32
 | 
					
						
							|  |  |  | 	return (unsigned long) __swab32((u32) y); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #error BITS_PER_LONG not defined
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #ifndef find_next_zero_bit_le
 | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:50 -07:00
										 |  |  | unsigned long find_next_zero_bit_le(const void *addr, unsigned | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:15 -08:00
										 |  |  | 		long size, unsigned long offset) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:50 -07:00
										 |  |  | 	const unsigned long *p = addr; | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:15 -08:00
										 |  |  | 	unsigned long result = offset & ~(BITS_PER_LONG - 1); | 
					
						
							|  |  |  | 	unsigned long tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (offset >= size) | 
					
						
							|  |  |  | 		return size; | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:50 -07:00
										 |  |  | 	p += BITOP_WORD(offset); | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:15 -08:00
										 |  |  | 	size -= result; | 
					
						
							|  |  |  | 	offset &= (BITS_PER_LONG - 1UL); | 
					
						
							|  |  |  | 	if (offset) { | 
					
						
							|  |  |  | 		tmp = ext2_swabp(p++); | 
					
						
							|  |  |  | 		tmp |= (~0UL >> (BITS_PER_LONG - offset)); | 
					
						
							|  |  |  | 		if (size < BITS_PER_LONG) | 
					
						
							|  |  |  | 			goto found_first; | 
					
						
							|  |  |  | 		if (~tmp) | 
					
						
							|  |  |  | 			goto found_middle; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (size & ~(BITS_PER_LONG - 1)) { | 
					
						
							|  |  |  | 		if (~(tmp = *(p++))) | 
					
						
							|  |  |  | 			goto found_middle_swap; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!size) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	tmp = ext2_swabp(p); | 
					
						
							|  |  |  | found_first: | 
					
						
							|  |  |  | 	tmp |= ~0UL << size; | 
					
						
							|  |  |  | 	if (tmp == ~0UL)	/* Are any bits zero? */ | 
					
						
							|  |  |  | 		return result + size; /* Nope. Skip ffz */ | 
					
						
							|  |  |  | found_middle: | 
					
						
							|  |  |  | 	return result + ffz(tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | found_middle_swap: | 
					
						
							|  |  |  | 	return result + ffz(ext2_swab(tmp)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:47 -07:00
										 |  |  | EXPORT_SYMBOL(find_next_zero_bit_le); | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:15 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #ifndef find_next_bit_le
 | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:50 -07:00
										 |  |  | unsigned long find_next_bit_le(const void *addr, unsigned | 
					
						
							| 
									
										
										
										
											2008-01-28 23:58:27 -05:00
										 |  |  | 		long size, unsigned long offset) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:50 -07:00
										 |  |  | 	const unsigned long *p = addr; | 
					
						
							| 
									
										
										
										
											2008-01-28 23:58:27 -05:00
										 |  |  | 	unsigned long result = offset & ~(BITS_PER_LONG - 1); | 
					
						
							|  |  |  | 	unsigned long tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (offset >= size) | 
					
						
							|  |  |  | 		return size; | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:50 -07:00
										 |  |  | 	p += BITOP_WORD(offset); | 
					
						
							| 
									
										
										
										
											2008-01-28 23:58:27 -05:00
										 |  |  | 	size -= result; | 
					
						
							|  |  |  | 	offset &= (BITS_PER_LONG - 1UL); | 
					
						
							|  |  |  | 	if (offset) { | 
					
						
							|  |  |  | 		tmp = ext2_swabp(p++); | 
					
						
							|  |  |  | 		tmp &= (~0UL << offset); | 
					
						
							|  |  |  | 		if (size < BITS_PER_LONG) | 
					
						
							|  |  |  | 			goto found_first; | 
					
						
							|  |  |  | 		if (tmp) | 
					
						
							|  |  |  | 			goto found_middle; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (size & ~(BITS_PER_LONG - 1)) { | 
					
						
							|  |  |  | 		tmp = *(p++); | 
					
						
							|  |  |  | 		if (tmp) | 
					
						
							|  |  |  | 			goto found_middle_swap; | 
					
						
							|  |  |  | 		result += BITS_PER_LONG; | 
					
						
							|  |  |  | 		size -= BITS_PER_LONG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!size) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	tmp = ext2_swabp(p); | 
					
						
							|  |  |  | found_first: | 
					
						
							|  |  |  | 	tmp &= (~0UL >> (BITS_PER_LONG - size)); | 
					
						
							|  |  |  | 	if (tmp == 0UL)		/* Are any bits set? */ | 
					
						
							|  |  |  | 		return result + size; /* Nope. */ | 
					
						
							|  |  |  | found_middle: | 
					
						
							|  |  |  | 	return result + __ffs(tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | found_middle_swap: | 
					
						
							|  |  |  | 	return result + __ffs(ext2_swab(tmp)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:47 -07:00
										 |  |  | EXPORT_SYMBOL(find_next_bit_le); | 
					
						
							| 
									
										
										
										
											2011-05-26 16:26:09 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-03-23 16:41:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-26 01:39:15 -08:00
										 |  |  | #endif /* __BIG_ENDIAN */
 |