2015-04-16 22:43:16 +03:00
/* bit search implementation
2005-04-17 02:20:36 +04:00
*
* Copyright ( C ) 2004 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
2015-04-16 22:43:16 +03:00
* Copyright ( C ) 2008 IBM Corporation
* ' find_last_bit ' is written by Rusty Russell < rusty @ rustcorp . com . au >
* ( Inspired by David Howell ' s find_next_bit implementation )
*
2015-04-16 22:43:13 +03:00
* Rewritten by Yury Norov < yury . norov @ gmail . com > to decrease
* size and improve performance , 2015.
*
2005-04-17 02:20:36 +04:00
* 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>
2015-04-16 22:43:16 +03:00
# include <linux/bitmap.h>
2011-11-17 06:29:17 +04:00
# include <linux/export.h>
2015-04-16 22:43:13 +03:00
# include <linux/kernel.h>
2005-04-17 02:20:36 +04:00
2015-04-16 22:43:13 +03:00
# if !defined(find_next_bit) || !defined(find_next_zero_bit)
2006-03-26 13:39:11 +04:00
2008-03-11 18:17:19 +03:00
/*
2015-04-16 22:43:13 +03:00
* This is a common helper function for find_next_bit and
* find_next_zero_bit . The difference is the " invert " argument , which
* is XORed with each fetched word before searching it for one bits .
2006-03-26 13:39:11 +04:00
*/
2015-04-16 22:43:13 +03:00
static unsigned long _find_next_bit ( const unsigned long * addr ,
unsigned long nbits , unsigned long start , unsigned long invert )
2005-04-17 02:20:36 +04:00
{
unsigned long tmp ;
2015-04-16 22:43:13 +03:00
if ( ! nbits | | start > = nbits )
return nbits ;
tmp = addr [ start / BITS_PER_LONG ] ^ invert ;
/* Handle 1st word. */
tmp & = BITMAP_FIRST_WORD_MASK ( start ) ;
start = round_down ( start , BITS_PER_LONG ) ;
while ( ! tmp ) {
start + = BITS_PER_LONG ;
if ( start > = nbits )
return nbits ;
tmp = addr [ start / BITS_PER_LONG ] ^ invert ;
2005-04-17 02:20:36 +04:00
}
2015-04-16 22:43:13 +03:00
return min ( start + __ffs ( tmp ) , nbits ) ;
2006-03-26 13:39:11 +04:00
}
2011-05-27 03:26:09 +04:00
# endif
2005-04-17 02:20:36 +04:00
2015-04-16 22:43:13 +03:00
# ifndef find_next_bit
2006-03-26 13:39:11 +04:00
/*
2015-04-16 22:43:13 +03:00
* Find the next set bit in a memory region .
2006-03-26 13:39:11 +04:00
*/
2015-04-16 22:43:13 +03:00
unsigned long find_next_bit ( const unsigned long * addr , unsigned long size ,
unsigned long offset )
{
return _find_next_bit ( addr , size , offset , 0UL ) ;
}
EXPORT_SYMBOL ( find_next_bit ) ;
# endif
# ifndef find_next_zero_bit
2008-04-29 14:01:02 +04:00
unsigned long find_next_zero_bit ( const unsigned long * addr , unsigned long size ,
unsigned long offset )
2006-03-26 13:39:11 +04:00
{
2015-04-16 22:43:13 +03:00
return _find_next_bit ( addr , size , offset , ~ 0UL ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-29 14:01:02 +04:00
EXPORT_SYMBOL ( find_next_zero_bit ) ;
2011-05-27 03:26:09 +04:00
# endif
2008-04-01 13:46:19 +04:00
2011-05-27 03:26:09 +04:00
# ifndef find_first_bit
2008-04-01 13:46:19 +04:00
/*
* Find the first set bit in a memory region .
*/
2008-04-29 14:01:02 +04:00
unsigned long find_first_bit ( const unsigned long * addr , unsigned long size )
2008-04-01 13:46:19 +04:00
{
2015-04-16 22:43:13 +03:00
unsigned long idx ;
2008-04-01 13:46:19 +04:00
2015-04-16 22:43:13 +03:00
for ( idx = 0 ; idx * BITS_PER_LONG < size ; idx + + ) {
if ( addr [ idx ] )
return min ( idx * BITS_PER_LONG + __ffs ( addr [ idx ] ) , size ) ;
2008-04-01 13:46:19 +04:00
}
2015-04-16 22:43:13 +03:00
return size ;
2008-04-01 13:46:19 +04:00
}
2008-04-29 14:01:02 +04:00
EXPORT_SYMBOL ( find_first_bit ) ;
2011-05-27 03:26:09 +04:00
# endif
2008-04-01 13:46:19 +04:00
2011-05-27 03:26:09 +04:00
# ifndef find_first_zero_bit
2008-04-01 13:46:19 +04:00
/*
* Find the first cleared bit in a memory region .
*/
2008-04-29 14:01:02 +04:00
unsigned long find_first_zero_bit ( const unsigned long * addr , unsigned long size )
2008-04-01 13:46:19 +04:00
{
2015-04-16 22:43:13 +03:00
unsigned long idx ;
2008-04-01 13:46:19 +04:00
2015-04-16 22:43:13 +03:00
for ( idx = 0 ; idx * BITS_PER_LONG < size ; idx + + ) {
if ( addr [ idx ] ! = ~ 0UL )
return min ( idx * BITS_PER_LONG + ffz ( addr [ idx ] ) , size ) ;
2008-04-01 13:46:19 +04:00
}
2015-04-16 22:43:13 +03:00
return size ;
2008-04-01 13:46:19 +04:00
}
2008-04-29 14:01:02 +04:00
EXPORT_SYMBOL ( find_first_zero_bit ) ;
2011-05-27 03:26:09 +04:00
# endif
2006-03-26 13:39:15 +04:00
2015-04-16 22:43:16 +03:00
# ifndef find_last_bit
unsigned long find_last_bit ( const unsigned long * addr , unsigned long size )
{
if ( size ) {
unsigned long val = BITMAP_LAST_WORD_MASK ( size ) ;
unsigned long idx = ( size - 1 ) / BITS_PER_LONG ;
do {
val & = addr [ idx ] ;
if ( val )
return idx * BITS_PER_LONG + __fls ( val ) ;
val = ~ 0ul ;
} while ( idx - - ) ;
}
return size ;
}
EXPORT_SYMBOL ( find_last_bit ) ;
# endif
2006-03-26 13:39:15 +04:00
# ifdef __BIG_ENDIAN
/* include/linux/byteorder does not 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
}
2015-04-16 22:43:13 +03:00
# if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le)
static unsigned long _find_next_bit_le ( const unsigned long * addr ,
unsigned long nbits , unsigned long start , unsigned long invert )
2006-03-26 13:39:15 +04:00
{
unsigned long tmp ;
2015-04-16 22:43:13 +03:00
if ( ! nbits | | start > = nbits )
return nbits ;
tmp = addr [ start / BITS_PER_LONG ] ^ invert ;
/* Handle 1st word. */
tmp & = ext2_swab ( BITMAP_FIRST_WORD_MASK ( start ) ) ;
start = round_down ( start , BITS_PER_LONG ) ;
2006-03-26 13:39:15 +04:00
2015-04-16 22:43:13 +03:00
while ( ! tmp ) {
start + = BITS_PER_LONG ;
if ( start > = nbits )
return nbits ;
tmp = addr [ start / BITS_PER_LONG ] ^ invert ;
2006-03-26 13:39:15 +04:00
}
2015-04-16 22:43:13 +03:00
return min ( start + __ffs ( ext2_swab ( tmp ) ) , nbits ) ;
}
# endif
# ifndef find_next_zero_bit_le
unsigned long find_next_zero_bit_le ( const void * addr , unsigned
long size , unsigned long offset )
{
return _find_next_bit_le ( addr , size , offset , ~ 0UL ) ;
2006-03-26 13:39:15 +04:00
}
2011-03-24 02:41:47 +03:00
EXPORT_SYMBOL ( find_next_zero_bit_le ) ;
2011-05-27 03:26:09 +04:00
# endif
2006-03-26 13:39:15 +04:00
2011-05-27 03:26:09 +04:00
# ifndef find_next_bit_le
2011-03-24 02:41:50 +03:00
unsigned long find_next_bit_le ( const void * addr , unsigned
2008-01-29 07:58:27 +03:00
long size , unsigned long offset )
{
2015-04-16 22:43:13 +03:00
return _find_next_bit_le ( addr , size , offset , 0UL ) ;
2008-01-29 07:58:27 +03:00
}
2011-03-24 02:41:47 +03:00
EXPORT_SYMBOL ( find_next_bit_le ) ;
2011-05-27 03:26:09 +04:00
# endif
2011-03-24 02:41:59 +03:00
2006-03-26 13:39:15 +04:00
# endif /* __BIG_ENDIAN */