1/* 2 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 3 * Written by David Howells (dhowells@redhat.com) 4 * Copyright (C) 2008 IBM Corporation 5 * Written by Rusty Russell <rusty@rustcorp.com.au> 6 * (Inspired by David Howell's find_next_bit implementation) 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 11 * 2 of the License, or (at your option) any later version. 12 */ 13 14#include "bitops.h" 15 16#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) 17 18/* 19 * Find the next set bit in a memory region. 20 */ 21unsigned long find_next_bit(const unsigned long *addr, unsigned long size, 22 unsigned long offset) 23{ 24 const unsigned long *p = addr + BITOP_WORD(offset); 25 unsigned long result = offset & ~(BITS_PER_LONG-1); 26 unsigned long tmp; 27 28 if (offset >= size) { 29 return size; 30 } 31 size -= result; 32 offset %= BITS_PER_LONG; 33 if (offset) { 34 tmp = *(p++); 35 tmp &= (~0UL << offset); 36 if (size < BITS_PER_LONG) { 37 goto found_first; 38 } 39 if (tmp) { 40 goto found_middle; 41 } 42 size -= BITS_PER_LONG; 43 result += BITS_PER_LONG; 44 } 45 while (size & ~(BITS_PER_LONG-1)) { 46 if ((tmp = *(p++))) { 47 goto found_middle; 48 } 49 result += BITS_PER_LONG; 50 size -= BITS_PER_LONG; 51 } 52 if (!size) { 53 return result; 54 } 55 tmp = *p; 56 57found_first: 58 tmp &= (~0UL >> (BITS_PER_LONG - size)); 59 if (tmp == 0UL) { /* Are any bits set? */ 60 return result + size; /* Nope. */ 61 } 62found_middle: 63 return result + bitops_ffsl(tmp); 64} 65 66/* 67 * This implementation of find_{first,next}_zero_bit was stolen from 68 * Linus' asm-alpha/bitops.h. 69 */ 70unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, 71 unsigned long offset) 72{ 73 const unsigned long *p = addr + BITOP_WORD(offset); 74 unsigned long result = offset & ~(BITS_PER_LONG-1); 75 unsigned long tmp; 76 77 if (offset >= size) { 78 return size; 79 } 80 size -= result; 81 offset %= BITS_PER_LONG; 82 if (offset) { 83 tmp = *(p++); 84 tmp |= ~0UL >> (BITS_PER_LONG - offset); 85 if (size < BITS_PER_LONG) { 86 goto found_first; 87 } 88 if (~tmp) { 89 goto found_middle; 90 } 91 size -= BITS_PER_LONG; 92 result += BITS_PER_LONG; 93 } 94 while (size & ~(BITS_PER_LONG-1)) { 95 if (~(tmp = *(p++))) { 96 goto found_middle; 97 } 98 result += BITS_PER_LONG; 99 size -= BITS_PER_LONG; 100 } 101 if (!size) { 102 return result; 103 } 104 tmp = *p; 105 106found_first: 107 tmp |= ~0UL << size; 108 if (tmp == ~0UL) { /* Are any bits zero? */ 109 return result + size; /* Nope. */ 110 } 111found_middle: 112 return result + ffz(tmp); 113} 114 115unsigned long find_last_bit(const unsigned long *addr, unsigned long size) 116{ 117 unsigned long words; 118 unsigned long tmp; 119 120 /* Start at final word. */ 121 words = size / BITS_PER_LONG; 122 123 /* Partial final word? */ 124 if (size & (BITS_PER_LONG-1)) { 125 tmp = (addr[words] & (~0UL >> (BITS_PER_LONG 126 - (size & (BITS_PER_LONG-1))))); 127 if (tmp) { 128 goto found; 129 } 130 } 131 132 while (words) { 133 tmp = addr[--words]; 134 if (tmp) { 135 found: 136 return words * BITS_PER_LONG + bitops_flsl(tmp); 137 } 138 } 139 140 /* Not found */ 141 return size; 142} 143