diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-03-24 06:15:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-24 10:33:20 -0500 |
commit | 74373c6acc52450ced28780d5fece60f1d7d20aa (patch) | |
tree | 6717fce7fdebbda48ad62b79b4ff721fae1c8dc3 /lib/bitmap.c | |
parent | 87e24802586333fa861861f6493c76039872755b (diff) |
[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: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Paul Jackson <pj@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'lib/bitmap.c')
-rw-r--r-- | lib/bitmap.c | 110 |
1 files changed, 76 insertions, 34 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c index 3fab1ce9ac65..f49eabe09271 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c | |||
@@ -692,26 +692,44 @@ EXPORT_SYMBOL(bitmap_bitremap); | |||
692 | */ | 692 | */ |
693 | int bitmap_find_free_region(unsigned long *bitmap, int bits, int order) | 693 | int bitmap_find_free_region(unsigned long *bitmap, int bits, int order) |
694 | { | 694 | { |
695 | unsigned long mask; | 695 | int nbits; /* number of bits in region */ |
696 | int nbits = 1 << order; | 696 | int nlongs; /* num longs spanned by region in bitmap */ |
697 | int i; | 697 | int nbitsinlong; /* num bits of region in each spanned long */ |
698 | 698 | unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */ | |
699 | if (nbits > BITS_PER_LONG) | 699 | int i; /* scans bitmap by longs */ |
700 | return -EINVAL; | 700 | |
701 | nbits = 1 << order; | ||
702 | nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG; | ||
703 | nbitsinlong = nbits; | ||
704 | if (nbitsinlong > BITS_PER_LONG) | ||
705 | nbitsinlong = BITS_PER_LONG; | ||
701 | 706 | ||
702 | /* make a mask of the order */ | 707 | /* make a mask of the order */ |
703 | mask = (1UL << (nbits - 1)); | 708 | mask = (1UL << (nbitsinlong - 1)); |
704 | mask += mask - 1; | 709 | mask += mask - 1; |
705 | 710 | ||
706 | /* run up the bitmap nbits at a time */ | 711 | /* run up the bitmap nbitsinlong at a time */ |
707 | for (i = 0; i < bits; i += nbits) { | 712 | for (i = 0; i < bits; i += nbitsinlong) { |
708 | int index = i / BITS_PER_LONG; | 713 | int index = i / BITS_PER_LONG; |
709 | int offset = i - (index * BITS_PER_LONG); | 714 | int offset = i - (index * BITS_PER_LONG); |
710 | if ((bitmap[index] & (mask << offset)) == 0) { | 715 | int j, space = 1; |
716 | |||
717 | /* find space in the bitmap */ | ||
718 | for (j = 0; j < nlongs; j++) | ||
719 | if ((bitmap[index + j] & (mask << offset))) { | ||
720 | space = 0; | ||
721 | break; | ||
722 | } | ||
723 | |||
724 | /* keep looking */ | ||
725 | if (unlikely(!space)) | ||
726 | continue; | ||
727 | |||
728 | for (j = 0; j < nlongs; j++) | ||
711 | /* set region in bitmap */ | 729 | /* set region in bitmap */ |
712 | bitmap[index] |= (mask << offset); | 730 | bitmap[index + j] |= (mask << offset); |
713 | return i; | 731 | |
714 | } | 732 | return i; |
715 | } | 733 | } |
716 | return -ENOMEM; | 734 | return -ENOMEM; |
717 | } | 735 | } |
@@ -728,13 +746,28 @@ EXPORT_SYMBOL(bitmap_find_free_region); | |||
728 | */ | 746 | */ |
729 | void bitmap_release_region(unsigned long *bitmap, int pos, int order) | 747 | void bitmap_release_region(unsigned long *bitmap, int pos, int order) |
730 | { | 748 | { |
731 | int nbits = 1 << order; | 749 | int nbits; /* number of bits in region */ |
732 | unsigned long mask = (1UL << (nbits - 1)); | 750 | int nlongs; /* num longs spanned by region in bitmap */ |
733 | int index = pos / BITS_PER_LONG; | 751 | int index; /* index first long of region in bitmap */ |
734 | int offset = pos - (index * BITS_PER_LONG); | 752 | int offset; /* bit offset region in bitmap[index] */ |
735 | 753 | int nbitsinlong; /* num bits of region in each spanned long */ | |
754 | unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */ | ||
755 | int i; /* scans bitmap by longs */ | ||
756 | |||
757 | nbits = 1 << order; | ||
758 | nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG; | ||
759 | index = pos / BITS_PER_LONG; | ||
760 | offset = pos - (index * BITS_PER_LONG); | ||
761 | |||
762 | nbitsinlong = nbits; | ||
763 | if (nbitsinlong > BITS_PER_LONG) | ||
764 | nbitsinlong = BITS_PER_LONG; | ||
765 | |||
766 | mask = (1UL << (nbitsinlong - 1)); | ||
736 | mask += mask - 1; | 767 | mask += mask - 1; |
737 | bitmap[index] &= ~(mask << offset); | 768 | |
769 | for (i = 0; i < nlongs; i++) | ||
770 | bitmap[index + i] &= ~(mask << offset); | ||
738 | } | 771 | } |
739 | EXPORT_SYMBOL(bitmap_release_region); | 772 | EXPORT_SYMBOL(bitmap_release_region); |
740 | 773 | ||
@@ -750,22 +783,31 @@ EXPORT_SYMBOL(bitmap_release_region); | |||
750 | */ | 783 | */ |
751 | int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) | 784 | int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) |
752 | { | 785 | { |
753 | int nbits = 1 << order; | 786 | int nbits; /* number of bits in region */ |
754 | unsigned long mask = (1UL << (nbits - 1)); | 787 | int nlongs; /* num longs spanned by region in bitmap */ |
755 | int index = pos / BITS_PER_LONG; | 788 | int index; /* index first long of region in bitmap */ |
756 | int offset = pos - (index * BITS_PER_LONG); | 789 | int offset; /* bit offset region in bitmap[index] */ |
757 | 790 | int nbitsinlong; /* num bits of region in each spanned long */ | |
758 | /* | 791 | unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */ |
759 | * We don't do regions of nbits > BITS_PER_LONG. The | 792 | int i; /* scans bitmap by longs */ |
760 | * algorithm would be a simple look for multiple zeros in the | 793 | |
761 | * array, but there's no driver today that needs this. If you | 794 | nbits = 1 << order; |
762 | * trip this BUG(), you get to code it... | 795 | nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG; |
763 | */ | 796 | index = pos / BITS_PER_LONG; |
764 | BUG_ON(nbits > BITS_PER_LONG); | 797 | offset = pos - (index * BITS_PER_LONG); |
798 | |||
799 | nbitsinlong = nbits; | ||
800 | if (nbitsinlong > BITS_PER_LONG) | ||
801 | nbitsinlong = BITS_PER_LONG; | ||
802 | |||
803 | mask = (1UL << (nbitsinlong - 1)); | ||
765 | mask += mask - 1; | 804 | mask += mask - 1; |
766 | if (bitmap[index] & (mask << offset)) | 805 | |
767 | return -EBUSY; | 806 | for (i = 0; i < nlongs; i++) |
768 | bitmap[index] |= (mask << offset); | 807 | if (bitmap[index + i] & (mask << offset)) |
808 | return -EBUSY; | ||
809 | for (i = 0; i < nlongs; i++) | ||
810 | bitmap[index + i] |= (mask << offset); | ||
769 | return 0; | 811 | return 0; |
770 | } | 812 | } |
771 | EXPORT_SYMBOL(bitmap_allocate_region); | 813 | EXPORT_SYMBOL(bitmap_allocate_region); |