Commit 74373c6a authored by Paul Mundt's avatar Paul Mundt Committed by Linus Torvalds

[PATCH] bitmap: region multiword spanning support

Add support to the lib/bitmap.c bitmap_*_region() routines

For bitmap regions larger than one word (nbits > BITS_PER_LONG).  This removes
a BUG_ON() in lib bitmap.

I have an updated store queue API for SH that is currently using this with
relative success, and at first glance, it seems like this could be useful for
x86 (arch/i386/kernel/pci-dma.c) as well.  Particularly for anything using
dma_declare_coherent_memory() on large areas and that attempts to allocate
large buffers from that space.

Paul Jackson also did some cleanup to this patch.
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
Signed-off-by: default avatarPaul Jackson <pj@sgi.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 87e24802
...@@ -692,26 +692,44 @@ EXPORT_SYMBOL(bitmap_bitremap); ...@@ -692,26 +692,44 @@ EXPORT_SYMBOL(bitmap_bitremap);
*/ */
int bitmap_find_free_region(unsigned long *bitmap, int bits, int order) int bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
{ {
unsigned long mask; int nbits; /* number of bits in region */
int nbits = 1 << order; int nlongs; /* num longs spanned by region in bitmap */
int i; int nbitsinlong; /* num bits of region in each spanned long */
unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
if (nbits > BITS_PER_LONG) int i; /* scans bitmap by longs */
return -EINVAL;
nbits = 1 << order;
nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
nbitsinlong = nbits;
if (nbitsinlong > BITS_PER_LONG)
nbitsinlong = BITS_PER_LONG;
/* make a mask of the order */ /* make a mask of the order */
mask = (1UL << (nbits - 1)); mask = (1UL << (nbitsinlong - 1));
mask += mask - 1; mask += mask - 1;
/* run up the bitmap nbits at a time */ /* run up the bitmap nbitsinlong at a time */
for (i = 0; i < bits; i += nbits) { for (i = 0; i < bits; i += nbitsinlong) {
int index = i / BITS_PER_LONG; int index = i / BITS_PER_LONG;
int offset = i - (index * BITS_PER_LONG); int offset = i - (index * BITS_PER_LONG);
if ((bitmap[index] & (mask << offset)) == 0) { int j, space = 1;
/* find space in the bitmap */
for (j = 0; j < nlongs; j++)
if ((bitmap[index + j] & (mask << offset))) {
space = 0;
break;
}
/* keep looking */
if (unlikely(!space))
continue;
for (j = 0; j < nlongs; j++)
/* set region in bitmap */ /* set region in bitmap */
bitmap[index] |= (mask << offset); bitmap[index + j] |= (mask << offset);
return i;
} return i;
} }
return -ENOMEM; return -ENOMEM;
} }
...@@ -728,13 +746,28 @@ EXPORT_SYMBOL(bitmap_find_free_region); ...@@ -728,13 +746,28 @@ EXPORT_SYMBOL(bitmap_find_free_region);
*/ */
void bitmap_release_region(unsigned long *bitmap, int pos, int order) void bitmap_release_region(unsigned long *bitmap, int pos, int order)
{ {
int nbits = 1 << order; int nbits; /* number of bits in region */
unsigned long mask = (1UL << (nbits - 1)); int nlongs; /* num longs spanned by region in bitmap */
int index = pos / BITS_PER_LONG; int index; /* index first long of region in bitmap */
int offset = pos - (index * BITS_PER_LONG); int offset; /* bit offset region in bitmap[index] */
int nbitsinlong; /* num bits of region in each spanned long */
unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
int i; /* scans bitmap by longs */
nbits = 1 << order;
nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
index = pos / BITS_PER_LONG;
offset = pos - (index * BITS_PER_LONG);
nbitsinlong = nbits;
if (nbitsinlong > BITS_PER_LONG)
nbitsinlong = BITS_PER_LONG;
mask = (1UL << (nbitsinlong - 1));
mask += mask - 1; mask += mask - 1;
bitmap[index] &= ~(mask << offset);
for (i = 0; i < nlongs; i++)
bitmap[index + i] &= ~(mask << offset);
} }
EXPORT_SYMBOL(bitmap_release_region); EXPORT_SYMBOL(bitmap_release_region);
...@@ -750,22 +783,31 @@ EXPORT_SYMBOL(bitmap_release_region); ...@@ -750,22 +783,31 @@ EXPORT_SYMBOL(bitmap_release_region);
*/ */
int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
{ {
int nbits = 1 << order; int nbits; /* number of bits in region */
unsigned long mask = (1UL << (nbits - 1)); int nlongs; /* num longs spanned by region in bitmap */
int index = pos / BITS_PER_LONG; int index; /* index first long of region in bitmap */
int offset = pos - (index * BITS_PER_LONG); int offset; /* bit offset region in bitmap[index] */
int nbitsinlong; /* num bits of region in each spanned long */
/* unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
* We don't do regions of nbits > BITS_PER_LONG. The int i; /* scans bitmap by longs */
* algorithm would be a simple look for multiple zeros in the
* array, but there's no driver today that needs this. If you nbits = 1 << order;
* trip this BUG(), you get to code it... nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
*/ index = pos / BITS_PER_LONG;
BUG_ON(nbits > BITS_PER_LONG); offset = pos - (index * BITS_PER_LONG);
nbitsinlong = nbits;
if (nbitsinlong > BITS_PER_LONG)
nbitsinlong = BITS_PER_LONG;
mask = (1UL << (nbitsinlong - 1));
mask += mask - 1; mask += mask - 1;
if (bitmap[index] & (mask << offset))
return -EBUSY; for (i = 0; i < nlongs; i++)
bitmap[index] |= (mask << offset); if (bitmap[index + i] & (mask << offset))
return -EBUSY;
for (i = 0; i < nlongs; i++)
bitmap[index + i] |= (mask << offset);
return 0; return 0;
} }
EXPORT_SYMBOL(bitmap_allocate_region); EXPORT_SYMBOL(bitmap_allocate_region);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment