aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-s390/bitops.h
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2005-07-27 14:44:58 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-27 19:26:04 -0400
commitafff7e2b3b13dbd26a2b9991d3d571df111d92e8 (patch)
tree51142ff8f5160bcd317120ffba604653c9e34455 /include/asm-s390/bitops.h
parent951f22d5b1f0eaae35dafc669e3774a0c2084d10 (diff)
[PATCH] s390: find_next_{zero}_bit fixes
The find_next_{zero}_bit primitives on s390* should never return a bit number bigger then the bit field size. In the case of a bitfield that doesn't end on a word boundary, an offset that makes the search start at the last word of the bit field and the last word doesn't contain any zero/one bits the search is continued with a call to find_first_bit with a negative size. The search normally ends pretty quickly because the words following the bit field contain a mix of zeros and ones. But the bit number that is returned in this case is too big. To fix this and additional if to check for this case is needed. To make the code easier to read I removed the assembler parts from the find_next_{zero}_bit functions, the C-ified code is as good. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/asm-s390/bitops.h')
-rw-r--r--include/asm-s390/bitops.h440
1 files changed, 140 insertions, 300 deletions
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
index 16bb08499c7f..8651524217fd 100644
--- a/include/asm-s390/bitops.h
+++ b/include/asm-s390/bitops.h
@@ -527,13 +527,64 @@ __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) {
527 __constant_test_bit((nr),(addr)) : \ 527 __constant_test_bit((nr),(addr)) : \
528 __test_bit((nr),(addr)) ) 528 __test_bit((nr),(addr)) )
529 529
530#ifndef __s390x__ 530/*
531 * ffz = Find First Zero in word. Undefined if no zero exists,
532 * so code should check against ~0UL first..
533 */
534static inline unsigned long ffz(unsigned long word)
535{
536 unsigned long bit = 0;
537
538#ifdef __s390x__
539 if (likely((word & 0xffffffff) == 0xffffffff)) {
540 word >>= 32;
541 bit += 32;
542 }
543#endif
544 if (likely((word & 0xffff) == 0xffff)) {
545 word >>= 16;
546 bit += 16;
547 }
548 if (likely((word & 0xff) == 0xff)) {
549 word >>= 8;
550 bit += 8;
551 }
552 return bit + _zb_findmap[word & 0xff];
553}
554
555/*
556 * __ffs = find first bit in word. Undefined if no bit exists,
557 * so code should check against 0UL first..
558 */
559static inline unsigned long __ffs (unsigned long word)
560{
561 unsigned long bit = 0;
562
563#ifdef __s390x__
564 if (likely((word & 0xffffffff) == 0)) {
565 word >>= 32;
566 bit += 32;
567 }
568#endif
569 if (likely((word & 0xffff) == 0)) {
570 word >>= 16;
571 bit += 16;
572 }
573 if (likely((word & 0xff) == 0)) {
574 word >>= 8;
575 bit += 8;
576 }
577 return bit + _sb_findmap[word & 0xff];
578}
531 579
532/* 580/*
533 * Find-bit routines.. 581 * Find-bit routines..
534 */ 582 */
583
584#ifndef __s390x__
585
535static inline int 586static inline int
536find_first_zero_bit(const unsigned long * addr, unsigned int size) 587find_first_zero_bit(const unsigned long * addr, unsigned long size)
537{ 588{
538 typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; 589 typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
539 unsigned long cmp, count; 590 unsigned long cmp, count;
@@ -548,7 +599,7 @@ find_first_zero_bit(const unsigned long * addr, unsigned int size)
548 " srl %2,5\n" 599 " srl %2,5\n"
549 "0: c %1,0(%0,%4)\n" 600 "0: c %1,0(%0,%4)\n"
550 " jne 1f\n" 601 " jne 1f\n"
551 " ahi %0,4\n" 602 " la %0,4(%0)\n"
552 " brct %2,0b\n" 603 " brct %2,0b\n"
553 " lr %0,%3\n" 604 " lr %0,%3\n"
554 " j 4f\n" 605 " j 4f\n"
@@ -574,7 +625,7 @@ find_first_zero_bit(const unsigned long * addr, unsigned int size)
574} 625}
575 626
576static inline int 627static inline int
577find_first_bit(const unsigned long * addr, unsigned int size) 628find_first_bit(const unsigned long * addr, unsigned long size)
578{ 629{
579 typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; 630 typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
580 unsigned long cmp, count; 631 unsigned long cmp, count;
@@ -589,7 +640,7 @@ find_first_bit(const unsigned long * addr, unsigned int size)
589 " srl %2,5\n" 640 " srl %2,5\n"
590 "0: c %1,0(%0,%4)\n" 641 "0: c %1,0(%0,%4)\n"
591 " jne 1f\n" 642 " jne 1f\n"
592 " ahi %0,4\n" 643 " la %0,4(%0)\n"
593 " brct %2,0b\n" 644 " brct %2,0b\n"
594 " lr %0,%3\n" 645 " lr %0,%3\n"
595 " j 4f\n" 646 " j 4f\n"
@@ -614,89 +665,8 @@ find_first_bit(const unsigned long * addr, unsigned int size)
614 return (res < size) ? res : size; 665 return (res < size) ? res : size;
615} 666}
616 667
617static inline int
618find_next_zero_bit (const unsigned long * addr, int size, int offset)
619{
620 unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
621 unsigned long bitvec, reg;
622 int set, bit = offset & 31, res;
623
624 if (bit) {
625 /*
626 * Look for zero in first word
627 */
628 bitvec = (*p) >> bit;
629 __asm__(" slr %0,%0\n"
630 " lhi %2,0xff\n"
631 " tml %1,0xffff\n"
632 " jno 0f\n"
633 " ahi %0,16\n"
634 " srl %1,16\n"
635 "0: tml %1,0x00ff\n"
636 " jno 1f\n"
637 " ahi %0,8\n"
638 " srl %1,8\n"
639 "1: nr %1,%2\n"
640 " ic %1,0(%1,%3)\n"
641 " alr %0,%1"
642 : "=&d" (set), "+a" (bitvec), "=&d" (reg)
643 : "a" (&_zb_findmap) : "cc" );
644 if (set < (32 - bit))
645 return set + offset;
646 offset += 32 - bit;
647 p++;
648 }
649 /*
650 * No zero yet, search remaining full words for a zero
651 */
652 res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
653 return (offset + res);
654}
655
656static inline int
657find_next_bit (const unsigned long * addr, int size, int offset)
658{
659 unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
660 unsigned long bitvec, reg;
661 int set, bit = offset & 31, res;
662
663 if (bit) {
664 /*
665 * Look for set bit in first word
666 */
667 bitvec = (*p) >> bit;
668 __asm__(" slr %0,%0\n"
669 " lhi %2,0xff\n"
670 " tml %1,0xffff\n"
671 " jnz 0f\n"
672 " ahi %0,16\n"
673 " srl %1,16\n"
674 "0: tml %1,0x00ff\n"
675 " jnz 1f\n"
676 " ahi %0,8\n"
677 " srl %1,8\n"
678 "1: nr %1,%2\n"
679 " ic %1,0(%1,%3)\n"
680 " alr %0,%1"
681 : "=&d" (set), "+a" (bitvec), "=&d" (reg)
682 : "a" (&_sb_findmap) : "cc" );
683 if (set < (32 - bit))
684 return set + offset;
685 offset += 32 - bit;
686 p++;
687 }
688 /*
689 * No set bit yet, search remaining full words for a bit
690 */
691 res = find_first_bit (p, size - 32 * (p - (unsigned long *) addr));
692 return (offset + res);
693}
694
695#else /* __s390x__ */ 668#else /* __s390x__ */
696 669
697/*
698 * Find-bit routines..
699 */
700static inline unsigned long 670static inline unsigned long
701find_first_zero_bit(const unsigned long * addr, unsigned long size) 671find_first_zero_bit(const unsigned long * addr, unsigned long size)
702{ 672{
@@ -712,7 +682,7 @@ find_first_zero_bit(const unsigned long * addr, unsigned long size)
712 " srlg %2,%2,6\n" 682 " srlg %2,%2,6\n"
713 "0: cg %1,0(%0,%4)\n" 683 "0: cg %1,0(%0,%4)\n"
714 " jne 1f\n" 684 " jne 1f\n"
715 " aghi %0,8\n" 685 " la %0,8(%0)\n"
716 " brct %2,0b\n" 686 " brct %2,0b\n"
717 " lgr %0,%3\n" 687 " lgr %0,%3\n"
718 " j 5f\n" 688 " j 5f\n"
@@ -785,143 +755,66 @@ find_first_bit(const unsigned long * addr, unsigned long size)
785 return (res < size) ? res : size; 755 return (res < size) ? res : size;
786} 756}
787 757
788static inline unsigned long
789find_next_zero_bit (const unsigned long * addr, unsigned long size, unsigned long offset)
790{
791 unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
792 unsigned long bitvec, reg;
793 unsigned long set, bit = offset & 63, res;
794
795 if (bit) {
796 /*
797 * Look for zero in first word
798 */
799 bitvec = (*p) >> bit;
800 __asm__(" lhi %2,-1\n"
801 " slgr %0,%0\n"
802 " clr %1,%2\n"
803 " jne 0f\n"
804 " aghi %0,32\n"
805 " srlg %1,%1,32\n"
806 "0: lghi %2,0xff\n"
807 " tmll %1,0xffff\n"
808 " jno 1f\n"
809 " aghi %0,16\n"
810 " srlg %1,%1,16\n"
811 "1: tmll %1,0x00ff\n"
812 " jno 2f\n"
813 " aghi %0,8\n"
814 " srlg %1,%1,8\n"
815 "2: ngr %1,%2\n"
816 " ic %1,0(%1,%3)\n"
817 " algr %0,%1"
818 : "=&d" (set), "+a" (bitvec), "=&d" (reg)
819 : "a" (&_zb_findmap) : "cc" );
820 if (set < (64 - bit))
821 return set + offset;
822 offset += 64 - bit;
823 p++;
824 }
825 /*
826 * No zero yet, search remaining full words for a zero
827 */
828 res = find_first_zero_bit (p, size - 64 * (p - (unsigned long *) addr));
829 return (offset + res);
830}
831
832static inline unsigned long
833find_next_bit (const unsigned long * addr, unsigned long size, unsigned long offset)
834{
835 unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
836 unsigned long bitvec, reg;
837 unsigned long set, bit = offset & 63, res;
838
839 if (bit) {
840 /*
841 * Look for zero in first word
842 */
843 bitvec = (*p) >> bit;
844 __asm__(" slgr %0,%0\n"
845 " ltr %1,%1\n"
846 " jnz 0f\n"
847 " aghi %0,32\n"
848 " srlg %1,%1,32\n"
849 "0: lghi %2,0xff\n"
850 " tmll %1,0xffff\n"
851 " jnz 1f\n"
852 " aghi %0,16\n"
853 " srlg %1,%1,16\n"
854 "1: tmll %1,0x00ff\n"
855 " jnz 2f\n"
856 " aghi %0,8\n"
857 " srlg %1,%1,8\n"
858 "2: ngr %1,%2\n"
859 " ic %1,0(%1,%3)\n"
860 " algr %0,%1"
861 : "=&d" (set), "+a" (bitvec), "=&d" (reg)
862 : "a" (&_sb_findmap) : "cc" );
863 if (set < (64 - bit))
864 return set + offset;
865 offset += 64 - bit;
866 p++;
867 }
868 /*
869 * No set bit yet, search remaining full words for a bit
870 */
871 res = find_first_bit (p, size - 64 * (p - (unsigned long *) addr));
872 return (offset + res);
873}
874
875#endif /* __s390x__ */ 758#endif /* __s390x__ */
876 759
877/* 760static inline int
878 * ffz = Find First Zero in word. Undefined if no zero exists, 761find_next_zero_bit (const unsigned long * addr, unsigned long size,
879 * so code should check against ~0UL first.. 762 unsigned long offset)
880 */
881static inline unsigned long ffz(unsigned long word)
882{ 763{
883 unsigned long bit = 0; 764 const unsigned long *p;
884 765 unsigned long bit, set;
885#ifdef __s390x__ 766
886 if (likely((word & 0xffffffff) == 0xffffffff)) { 767 if (offset >= size)
887 word >>= 32; 768 return size;
888 bit += 32; 769 bit = offset & (__BITOPS_WORDSIZE - 1);
889 } 770 offset -= bit;
890#endif 771 size -= offset;
891 if (likely((word & 0xffff) == 0xffff)) { 772 p = addr + offset / __BITOPS_WORDSIZE;
892 word >>= 16; 773 if (bit) {
893 bit += 16; 774 /*
775 * s390 version of ffz returns __BITOPS_WORDSIZE
776 * if no zero bit is present in the word.
777 */
778 set = ffz(*p >> bit) + bit;
779 if (set >= size)
780 return size + offset;
781 if (set < __BITOPS_WORDSIZE)
782 return set + offset;
783 offset += __BITOPS_WORDSIZE;
784 size -= __BITOPS_WORDSIZE;
785 p++;
894 } 786 }
895 if (likely((word & 0xff) == 0xff)) { 787 return offset + find_first_zero_bit(p, size);
896 word >>= 8;
897 bit += 8;
898 }
899 return bit + _zb_findmap[word & 0xff];
900} 788}
901 789
902/* 790static inline int
903 * __ffs = find first bit in word. Undefined if no bit exists, 791find_next_bit (const unsigned long * addr, unsigned long size,
904 * so code should check against 0UL first.. 792 unsigned long offset)
905 */
906static inline unsigned long __ffs (unsigned long word)
907{ 793{
908 unsigned long bit = 0; 794 const unsigned long *p;
909 795 unsigned long bit, set;
910#ifdef __s390x__ 796
911 if (likely((word & 0xffffffff) == 0)) { 797 if (offset >= size)
912 word >>= 32; 798 return size;
913 bit += 32; 799 bit = offset & (__BITOPS_WORDSIZE - 1);
800 offset -= bit;
801 size -= offset;
802 p = addr + offset / __BITOPS_WORDSIZE;
803 if (bit) {
804 /*
805 * s390 version of __ffs returns __BITOPS_WORDSIZE
806 * if no one bit is present in the word.
807 */
808 set = __ffs(*p & (~0UL << bit));
809 if (set >= size)
810 return size + offset;
811 if (set < __BITOPS_WORDSIZE)
812 return set + offset;
813 offset += __BITOPS_WORDSIZE;
814 size -= __BITOPS_WORDSIZE;
815 p++;
914 } 816 }
915#endif 817 return offset + find_first_bit(p, size);
916 if (likely((word & 0xffff) == 0)) {
917 word >>= 16;
918 bit += 16;
919 }
920 if (likely((word & 0xff) == 0)) {
921 word >>= 8;
922 bit += 8;
923 }
924 return bit + _sb_findmap[word & 0xff];
925} 818}
926 819
927/* 820/*
@@ -1031,49 +924,6 @@ ext2_find_first_zero_bit(void *vaddr, unsigned int size)
1031 return (res < size) ? res : size; 924 return (res < size) ? res : size;
1032} 925}
1033 926
1034static inline int
1035ext2_find_next_zero_bit(void *vaddr, unsigned int size, unsigned offset)
1036{
1037 unsigned long *addr = vaddr;
1038 unsigned long *p = addr + (offset >> 5);
1039 unsigned long word, reg;
1040 unsigned int bit = offset & 31UL, res;
1041
1042 if (offset >= size)
1043 return size;
1044
1045 if (bit) {
1046 __asm__(" ic %0,0(%1)\n"
1047 " icm %0,2,1(%1)\n"
1048 " icm %0,4,2(%1)\n"
1049 " icm %0,8,3(%1)"
1050 : "=&a" (word) : "a" (p) : "cc" );
1051 word >>= bit;
1052 res = bit;
1053 /* Look for zero in first longword */
1054 __asm__(" lhi %2,0xff\n"
1055 " tml %1,0xffff\n"
1056 " jno 0f\n"
1057 " ahi %0,16\n"
1058 " srl %1,16\n"
1059 "0: tml %1,0x00ff\n"
1060 " jno 1f\n"
1061 " ahi %0,8\n"
1062 " srl %1,8\n"
1063 "1: nr %1,%2\n"
1064 " ic %1,0(%1,%3)\n"
1065 " alr %0,%1"
1066 : "+&d" (res), "+&a" (word), "=&d" (reg)
1067 : "a" (&_zb_findmap) : "cc" );
1068 if (res < 32)
1069 return (p - addr)*32 + res;
1070 p++;
1071 }
1072 /* No zero yet, search remaining full bytes for a zero */
1073 res = ext2_find_first_zero_bit (p, size - 32 * (p - addr));
1074 return (p - addr) * 32 + res;
1075}
1076
1077#else /* __s390x__ */ 927#else /* __s390x__ */
1078 928
1079static inline unsigned long 929static inline unsigned long
@@ -1120,56 +970,46 @@ ext2_find_first_zero_bit(void *vaddr, unsigned long size)
1120 return (res < size) ? res : size; 970 return (res < size) ? res : size;
1121} 971}
1122 972
1123static inline unsigned long 973#endif /* __s390x__ */
974
975static inline int
1124ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) 976ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
1125{ 977{
1126 unsigned long *addr = vaddr; 978 unsigned long *addr = vaddr, *p;
1127 unsigned long *p = addr + (offset >> 6); 979 unsigned long word, bit, set;
1128 unsigned long word, reg;
1129 unsigned long bit = offset & 63UL, res;
1130 980
1131 if (offset >= size) 981 if (offset >= size)
1132 return size; 982 return size;
1133 983 bit = offset & (__BITOPS_WORDSIZE - 1);
984 offset -= bit;
985 size -= offset;
986 p = addr + offset / __BITOPS_WORDSIZE;
1134 if (bit) { 987 if (bit) {
1135 __asm__(" lrvg %0,%1" /* load reversed, neat instruction */ 988#ifndef __s390x__
1136 : "=a" (word) : "m" (*p) ); 989 asm(" ic %0,0(%1)\n"
1137 word >>= bit; 990 " icm %0,2,1(%1)\n"
1138 res = bit; 991 " icm %0,4,2(%1)\n"
1139 /* Look for zero in first 8 byte word */ 992 " icm %0,8,3(%1)"
1140 __asm__(" lghi %2,0xff\n" 993 : "=&a" (word) : "a" (p), "m" (*p) : "cc" );
1141 " tmll %1,0xffff\n" 994#else
1142 " jno 2f\n" 995 asm(" lrvg %0,%1" : "=a" (word) : "m" (*p) );
1143 " ahi %0,16\n" 996#endif
1144 " srlg %1,%1,16\n" 997 /*
1145 "0: tmll %1,0xffff\n" 998 * s390 version of ffz returns __BITOPS_WORDSIZE
1146 " jno 2f\n" 999 * if no zero bit is present in the word.
1147 " ahi %0,16\n" 1000 */
1148 " srlg %1,%1,16\n" 1001 set = ffz(word >> bit) + bit;
1149 "1: tmll %1,0xffff\n" 1002 if (set >= size)
1150 " jno 2f\n" 1003 return size + offset;
1151 " ahi %0,16\n" 1004 if (set < __BITOPS_WORDSIZE)
1152 " srl %1,16\n" 1005 return set + offset;
1153 "2: tmll %1,0x00ff\n" 1006 offset += __BITOPS_WORDSIZE;
1154 " jno 3f\n" 1007 size -= __BITOPS_WORDSIZE;
1155 " ahi %0,8\n" 1008 p++;
1156 " srl %1,8\n"
1157 "3: ngr %1,%2\n"
1158 " ic %1,0(%1,%3)\n"
1159 " alr %0,%1"
1160 : "+&d" (res), "+a" (word), "=&d" (reg)
1161 : "a" (&_zb_findmap) : "cc" );
1162 if (res < 64)
1163 return (p - addr)*64 + res;
1164 p++;
1165 } 1009 }
1166 /* No zero yet, search remaining full bytes for a zero */ 1010 return offset + ext2_find_first_zero_bit(p, size);
1167 res = ext2_find_first_zero_bit (p, size - 64 * (p - addr));
1168 return (p - addr) * 64 + res;
1169} 1011}
1170 1012
1171#endif /* __s390x__ */
1172
1173/* Bitmap functions for the minix filesystem. */ 1013/* Bitmap functions for the minix filesystem. */
1174/* FIXME !!! */ 1014/* FIXME !!! */
1175#define minix_test_and_set_bit(nr,addr) \ 1015#define minix_test_and_set_bit(nr,addr) \