X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=include%2Fasm-s390%2Fbitops.h;h=882db054110cbe9f8c7487e6dfe89cdc0647776e;hb=f9166e736e516a4b1de16577b5428afd0cffe325;hp=b07c578b22ea677d55f9bf147d8791a18c75a20e;hpb=c7c6e9494cc9a4a5b1a2ca870ed4531ad2b98a83;p=linux-2.6-omap-h63xx.git diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index b07c578b22e..882db054110 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h @@ -12,7 +12,13 @@ * Copyright (C) 1992, Linus Torvalds * */ -#include + +#ifdef __KERNEL__ + +#ifndef _LINUX_BITOPS_H +#error only can be included directly +#endif + #include /* @@ -51,19 +57,6 @@ * with operation of the form "set_bit(bitnr, flags)". */ -/* set ALIGN_CS to 1 if the SMP safe bit operations should - * align the address to 4 byte boundary. It seems to work - * without the alignment. - */ -#ifdef __KERNEL__ -#define ALIGN_CS 0 -#else -#define ALIGN_CS 1 -#ifndef CONFIG_SMP -#error "bitops won't work without CONFIG_SMP" -#endif -#endif - /* bitmap tables from arch/S390/kernel/bitmap.S */ extern const char _oi_bitmap[]; extern const char _ni_bitmap[]; @@ -78,16 +71,35 @@ extern const char _sb_findmap[]; #define __BITOPS_AND "nr" #define __BITOPS_XOR "xr" -#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ - __asm__ __volatile__(" l %0,0(%4)\n" \ - "0: lr %1,%0\n" \ - __op_string " %1,%3\n" \ - " cs %0,%1,0(%4)\n" \ - " jl 0b" \ - : "=&d" (__old), "=&d" (__new), \ - "=m" (*(unsigned long *) __addr) \ - : "d" (__val), "a" (__addr), \ - "m" (*(unsigned long *) __addr) : "cc" ); +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) + +#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ + asm volatile( \ + " l %0,%2\n" \ + "0: lr %1,%0\n" \ + __op_string " %1,%3\n" \ + " cs %0,%1,%2\n" \ + " jl 0b" \ + : "=&d" (__old), "=&d" (__new), \ + "=Q" (*(unsigned long *) __addr) \ + : "d" (__val), "Q" (*(unsigned long *) __addr) \ + : "cc"); + +#else /* __GNUC__ */ + +#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ + asm volatile( \ + " l %0,0(%4)\n" \ + "0: lr %1,%0\n" \ + __op_string " %1,%3\n" \ + " cs %0,%1,0(%4)\n" \ + " jl 0b" \ + : "=&d" (__old), "=&d" (__new), \ + "=m" (*(unsigned long *) __addr) \ + : "d" (__val), "a" (__addr), \ + "m" (*(unsigned long *) __addr) : "cc"); + +#endif /* __GNUC__ */ #else /* __s390x__ */ @@ -97,21 +109,41 @@ extern const char _sb_findmap[]; #define __BITOPS_AND "ngr" #define __BITOPS_XOR "xgr" -#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ - __asm__ __volatile__(" lg %0,0(%4)\n" \ - "0: lgr %1,%0\n" \ - __op_string " %1,%3\n" \ - " csg %0,%1,0(%4)\n" \ - " jl 0b" \ - : "=&d" (__old), "=&d" (__new), \ - "=m" (*(unsigned long *) __addr) \ - : "d" (__val), "a" (__addr), \ - "m" (*(unsigned long *) __addr) : "cc" ); +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) + +#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ + asm volatile( \ + " lg %0,%2\n" \ + "0: lgr %1,%0\n" \ + __op_string " %1,%3\n" \ + " csg %0,%1,%2\n" \ + " jl 0b" \ + : "=&d" (__old), "=&d" (__new), \ + "=Q" (*(unsigned long *) __addr) \ + : "d" (__val), "Q" (*(unsigned long *) __addr) \ + : "cc"); + +#else /* __GNUC__ */ + +#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ + asm volatile( \ + " lg %0,0(%4)\n" \ + "0: lgr %1,%0\n" \ + __op_string " %1,%3\n" \ + " csg %0,%1,0(%4)\n" \ + " jl 0b" \ + : "=&d" (__old), "=&d" (__new), \ + "=m" (*(unsigned long *) __addr) \ + : "d" (__val), "a" (__addr), \ + "m" (*(unsigned long *) __addr) : "cc"); + + +#endif /* __GNUC__ */ #endif /* __s390x__ */ #define __BITOPS_WORDS(bits) (((bits)+__BITOPS_WORDSIZE-1)/__BITOPS_WORDSIZE) -#define __BITOPS_BARRIER() __asm__ __volatile__ ( "" : : : "memory" ) +#define __BITOPS_BARRIER() asm volatile("" : : : "memory") #ifdef CONFIG_SMP /* @@ -122,10 +154,6 @@ static inline void set_bit_cs(unsigned long nr, volatile unsigned long *ptr) unsigned long addr, old, new, mask; addr = (unsigned long) ptr; -#if ALIGN_CS == 1 - nr += (addr & __BITOPS_ALIGN) << 3; /* add alignment to bit number */ - addr ^= addr & __BITOPS_ALIGN; /* align address to 8 */ -#endif /* calculate address for CS */ addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3; /* make OR mask */ @@ -142,10 +170,6 @@ static inline void clear_bit_cs(unsigned long nr, volatile unsigned long *ptr) unsigned long addr, old, new, mask; addr = (unsigned long) ptr; -#if ALIGN_CS == 1 - nr += (addr & __BITOPS_ALIGN) << 3; /* add alignment to bit number */ - addr ^= addr & __BITOPS_ALIGN; /* align address to 8 */ -#endif /* calculate address for CS */ addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3; /* make AND mask */ @@ -162,10 +186,6 @@ static inline void change_bit_cs(unsigned long nr, volatile unsigned long *ptr) unsigned long addr, old, new, mask; addr = (unsigned long) ptr; -#if ALIGN_CS == 1 - nr += (addr & __BITOPS_ALIGN) << 3; /* add alignment to bit number */ - addr ^= addr & __BITOPS_ALIGN; /* align address to 8 */ -#endif /* calculate address for CS */ addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3; /* make XOR mask */ @@ -183,10 +203,6 @@ test_and_set_bit_cs(unsigned long nr, volatile unsigned long *ptr) unsigned long addr, old, new, mask; addr = (unsigned long) ptr; -#if ALIGN_CS == 1 - nr += (addr & __BITOPS_ALIGN) << 3; /* add alignment to bit number */ - addr ^= addr & __BITOPS_ALIGN; /* align address to 8 */ -#endif /* calculate address for CS */ addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3; /* make OR/test mask */ @@ -206,10 +222,6 @@ test_and_clear_bit_cs(unsigned long nr, volatile unsigned long *ptr) unsigned long addr, old, new, mask; addr = (unsigned long) ptr; -#if ALIGN_CS == 1 - nr += (addr & __BITOPS_ALIGN) << 3; /* add alignment to bit number */ - addr ^= addr & __BITOPS_ALIGN; /* align address to 8 */ -#endif /* calculate address for CS */ addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3; /* make AND/test mask */ @@ -229,10 +241,6 @@ test_and_change_bit_cs(unsigned long nr, volatile unsigned long *ptr) unsigned long addr, old, new, mask; addr = (unsigned long) ptr; -#if ALIGN_CS == 1 - nr += (addr & __BITOPS_ALIGN) << 3; /* add alignment to bit number */ - addr ^= addr & __BITOPS_ALIGN; /* align address to 8 */ -#endif /* calculate address for CS */ addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3; /* make XOR/test mask */ @@ -252,10 +260,10 @@ static inline void __set_bit(unsigned long nr, volatile unsigned long *ptr) unsigned long addr; addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); - asm volatile("oc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_oi_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc" ); + asm volatile( + " oc 0(1,%1),0(%2)" + : "=m" (*(char *) addr) : "a" (addr), + "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" ); } static inline void @@ -264,40 +272,7 @@ __constant_set_bit(const unsigned long nr, volatile unsigned long *ptr) unsigned long addr; addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); - switch (nr&7) { - case 0: - asm volatile ("oi 0(%1),0x01" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 1: - asm volatile ("oi 0(%1),0x02" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 2: - asm volatile ("oi 0(%1),0x04" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 3: - asm volatile ("oi 0(%1),0x08" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 4: - asm volatile ("oi 0(%1),0x10" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 5: - asm volatile ("oi 0(%1),0x20" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 6: - asm volatile ("oi 0(%1),0x40" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 7: - asm volatile ("oi 0(%1),0x80" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - } + *(unsigned char *) addr |= 1 << (nr & 7); } #define set_bit_simple(nr,addr) \ @@ -314,10 +289,10 @@ __clear_bit(unsigned long nr, volatile unsigned long *ptr) unsigned long addr; addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); - asm volatile("nc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_ni_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc" ); + asm volatile( + " nc 0(1,%1),0(%2)" + : "=m" (*(char *) addr) : "a" (addr), + "a" (_ni_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc"); } static inline void @@ -326,40 +301,7 @@ __constant_clear_bit(const unsigned long nr, volatile unsigned long *ptr) unsigned long addr; addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); - switch (nr&7) { - case 0: - asm volatile ("ni 0(%1),0xFE" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 1: - asm volatile ("ni 0(%1),0xFD": "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 2: - asm volatile ("ni 0(%1),0xFB" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 3: - asm volatile ("ni 0(%1),0xF7" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 4: - asm volatile ("ni 0(%1),0xEF" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 5: - asm volatile ("ni 0(%1),0xDF" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 6: - asm volatile ("ni 0(%1),0xBF" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 7: - asm volatile ("ni 0(%1),0x7F" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - } + *(unsigned char *) addr &= ~(1 << (nr & 7)); } #define clear_bit_simple(nr,addr) \ @@ -375,10 +317,10 @@ static inline void __change_bit(unsigned long nr, volatile unsigned long *ptr) unsigned long addr; addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); - asm volatile("xc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_oi_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc" ); + asm volatile( + " xc 0(1,%1),0(%2)" + : "=m" (*(char *) addr) : "a" (addr), + "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" ); } static inline void @@ -387,40 +329,7 @@ __constant_change_bit(const unsigned long nr, volatile unsigned long *ptr) unsigned long addr; addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); - switch (nr&7) { - case 0: - asm volatile ("xi 0(%1),0x01" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 1: - asm volatile ("xi 0(%1),0x02" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 2: - asm volatile ("xi 0(%1),0x04" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 3: - asm volatile ("xi 0(%1),0x08" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 4: - asm volatile ("xi 0(%1),0x10" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 5: - asm volatile ("xi 0(%1),0x20" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 6: - asm volatile ("xi 0(%1),0x40" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - case 7: - asm volatile ("xi 0(%1),0x80" : "=m" (*(char *) addr) - : "a" (addr), "m" (*(char *) addr) : "cc" ); - break; - } + *(unsigned char *) addr ^= 1 << (nr & 7); } #define change_bit_simple(nr,addr) \ @@ -439,10 +348,11 @@ test_and_set_bit_simple(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); ch = *(unsigned char *) addr; - asm volatile("oc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_oi_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc", "memory" ); + asm volatile( + " oc 0(1,%1),0(%2)" + : "=m" (*(char *) addr) + : "a" (addr), "a" (_oi_bitmap + (nr & 7)), + "m" (*(char *) addr) : "cc", "memory"); return (ch >> (nr & 7)) & 1; } #define __test_and_set_bit(X,Y) test_and_set_bit_simple(X,Y) @@ -458,10 +368,11 @@ test_and_clear_bit_simple(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); ch = *(unsigned char *) addr; - asm volatile("nc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_ni_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc", "memory" ); + asm volatile( + " nc 0(1,%1),0(%2)" + : "=m" (*(char *) addr) + : "a" (addr), "a" (_ni_bitmap + (nr & 7)), + "m" (*(char *) addr) : "cc", "memory"); return (ch >> (nr & 7)) & 1; } #define __test_and_clear_bit(X,Y) test_and_clear_bit_simple(X,Y) @@ -477,10 +388,11 @@ test_and_change_bit_simple(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); ch = *(unsigned char *) addr; - asm volatile("xc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_oi_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc", "memory" ); + asm volatile( + " xc 0(1,%1),0(%2)" + : "=m" (*(char *) addr) + : "a" (addr), "a" (_oi_bitmap + (nr & 7)), + "m" (*(char *) addr) : "cc", "memory"); return (ch >> (nr & 7)) & 1; } #define __test_and_change_bit(X,Y) test_and_change_bit_simple(X,Y) @@ -518,8 +430,8 @@ static inline int __test_bit(unsigned long nr, const volatile unsigned long *ptr static inline int __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) { - return ((((volatile char *) addr) - [(nr^(__BITOPS_WORDSIZE-8))>>3] & (1<<(nr&7)))) != 0; + return (((volatile char *) addr) + [(nr^(__BITOPS_WORDSIZE-8))>>3] & (1<<(nr&7))) != 0; } #define test_bit(nr,addr) \ @@ -528,238 +440,256 @@ __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) { __test_bit((nr),(addr)) ) /* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. + * Optimized find bit helper functions. */ -static inline unsigned long ffz(unsigned long word) + +/** + * __ffz_word_loop - find byte offset of first long != -1UL + * @addr: pointer to array of unsigned long + * @size: size of the array in bits + */ +static inline unsigned long __ffz_word_loop(const unsigned long *addr, + unsigned long size) { - unsigned long bit = 0; + typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; + unsigned long bytes = 0; + + asm volatile( +#ifndef __s390x__ + " ahi %1,31\n" + " srl %1,5\n" + "0: c %2,0(%0,%3)\n" + " jne 1f\n" + " la %0,4(%0)\n" + " brct %1,0b\n" + "1:\n" +#else + " aghi %1,63\n" + " srlg %1,%1,6\n" + "0: cg %2,0(%0,%3)\n" + " jne 1f\n" + " la %0,8(%0)\n" + " brct %1,0b\n" + "1:\n" +#endif + : "+a" (bytes), "+d" (size) + : "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr) + : "cc" ); + return bytes; +} +/** + * __ffs_word_loop - find byte offset of first long != 0UL + * @addr: pointer to array of unsigned long + * @size: size of the array in bits + */ +static inline unsigned long __ffs_word_loop(const unsigned long *addr, + unsigned long size) +{ + typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; + unsigned long bytes = 0; + + asm volatile( +#ifndef __s390x__ + " ahi %1,31\n" + " srl %1,5\n" + "0: c %2,0(%0,%3)\n" + " jne 1f\n" + " la %0,4(%0)\n" + " brct %1,0b\n" + "1:\n" +#else + " aghi %1,63\n" + " srlg %1,%1,6\n" + "0: cg %2,0(%0,%3)\n" + " jne 1f\n" + " la %0,8(%0)\n" + " brct %1,0b\n" + "1:\n" +#endif + : "+a" (bytes), "+a" (size) + : "d" (0UL), "a" (addr), "m" (*(addrtype *) addr) + : "cc" ); + return bytes; +} + +/** + * __ffz_word - add number of the first unset bit + * @nr: base value the bit number is added to + * @word: the word that is searched for unset bits + */ +static inline unsigned long __ffz_word(unsigned long nr, unsigned long word) +{ #ifdef __s390x__ if (likely((word & 0xffffffff) == 0xffffffff)) { word >>= 32; - bit += 32; + nr += 32; } #endif if (likely((word & 0xffff) == 0xffff)) { word >>= 16; - bit += 16; + nr += 16; } if (likely((word & 0xff) == 0xff)) { word >>= 8; - bit += 8; + nr += 8; } - return bit + _zb_findmap[word & 0xff]; + return nr + _zb_findmap[(unsigned char) word]; } -/* - * __ffs = find first bit in word. Undefined if no bit exists, - * so code should check against 0UL first.. +/** + * __ffs_word - add number of the first set bit + * @nr: base value the bit number is added to + * @word: the word that is searched for set bits */ -static inline unsigned long __ffs (unsigned long word) +static inline unsigned long __ffs_word(unsigned long nr, unsigned long word) { - unsigned long bit = 0; - #ifdef __s390x__ if (likely((word & 0xffffffff) == 0)) { word >>= 32; - bit += 32; + nr += 32; } #endif if (likely((word & 0xffff) == 0)) { word >>= 16; - bit += 16; + nr += 16; } if (likely((word & 0xff) == 0)) { word >>= 8; - bit += 8; + nr += 8; } - return bit + _sb_findmap[word & 0xff]; + return nr + _sb_findmap[(unsigned char) word]; } -/* - * Find-bit routines.. - */ -#ifndef __s390x__ +/** + * __load_ulong_be - load big endian unsigned long + * @p: pointer to array of unsigned long + * @offset: byte offset of source value in the array + */ +static inline unsigned long __load_ulong_be(const unsigned long *p, + unsigned long offset) +{ + p = (unsigned long *)((unsigned long) p + offset); + return *p; +} -static inline int -find_first_zero_bit(const unsigned long * addr, unsigned long size) +/** + * __load_ulong_le - load little endian unsigned long + * @p: pointer to array of unsigned long + * @offset: byte offset of source value in the array + */ +static inline unsigned long __load_ulong_le(const unsigned long *p, + unsigned long offset) { - typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; - unsigned long cmp, count; - unsigned int res; + unsigned long word; - if (!size) - return 0; - __asm__(" lhi %1,-1\n" - " lr %2,%3\n" - " slr %0,%0\n" - " ahi %2,31\n" - " srl %2,5\n" - "0: c %1,0(%0,%4)\n" - " jne 1f\n" - " la %0,4(%0)\n" - " brct %2,0b\n" - " lr %0,%3\n" - " j 4f\n" - "1: l %2,0(%0,%4)\n" - " sll %0,3\n" - " lhi %1,0xff\n" - " tml %2,0xffff\n" - " jno 2f\n" - " ahi %0,16\n" - " srl %2,16\n" - "2: tml %2,0x00ff\n" - " jno 3f\n" - " ahi %0,8\n" - " srl %2,8\n" - "3: nr %2,%1\n" - " ic %2,0(%2,%5)\n" - " alr %0,%2\n" - "4:" - : "=&a" (res), "=&d" (cmp), "=&a" (count) - : "a" (size), "a" (addr), "a" (&_zb_findmap), - "m" (*(addrtype *) addr) : "cc" ); - return (res < size) ? res : size; + p = (unsigned long *)((unsigned long) p + offset); +#ifndef __s390x__ + asm volatile( + " ic %0,0(%1)\n" + " icm %0,2,1(%1)\n" + " icm %0,4,2(%1)\n" + " icm %0,8,3(%1)" + : "=&d" (word) : "a" (p), "m" (*p) : "cc"); +#else + asm volatile( + " lrvg %0,%1" + : "=d" (word) : "m" (*p) ); +#endif + return word; } -static inline int -find_first_bit(const unsigned long * addr, unsigned long size) +/* + * The various find bit functions. + */ + +/* + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. + */ +static inline unsigned long ffz(unsigned long word) { - typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; - unsigned long cmp, count; - unsigned int res; + return __ffz_word(0, word); +} - if (!size) - return 0; - __asm__(" slr %1,%1\n" - " lr %2,%3\n" - " slr %0,%0\n" - " ahi %2,31\n" - " srl %2,5\n" - "0: c %1,0(%0,%4)\n" - " jne 1f\n" - " la %0,4(%0)\n" - " brct %2,0b\n" - " lr %0,%3\n" - " j 4f\n" - "1: l %2,0(%0,%4)\n" - " sll %0,3\n" - " lhi %1,0xff\n" - " tml %2,0xffff\n" - " jnz 2f\n" - " ahi %0,16\n" - " srl %2,16\n" - "2: tml %2,0x00ff\n" - " jnz 3f\n" - " ahi %0,8\n" - " srl %2,8\n" - "3: nr %2,%1\n" - " ic %2,0(%2,%5)\n" - " alr %0,%2\n" - "4:" - : "=&a" (res), "=&d" (cmp), "=&a" (count) - : "a" (size), "a" (addr), "a" (&_sb_findmap), - "m" (*(addrtype *) addr) : "cc" ); - return (res < size) ? res : size; +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static inline unsigned long __ffs (unsigned long word) +{ + return __ffs_word(0, word); } -#else /* __s390x__ */ +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ +static inline int ffs(int x) +{ + if (!x) + return 0; + return __ffs_word(1, x); +} -static inline unsigned long -find_first_zero_bit(const unsigned long * addr, unsigned long size) +/** + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ +static inline unsigned long find_first_zero_bit(const unsigned long *addr, + unsigned long size) { - typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; - unsigned long res, cmp, count; + unsigned long bytes, bits; if (!size) return 0; - __asm__(" lghi %1,-1\n" - " lgr %2,%3\n" - " slgr %0,%0\n" - " aghi %2,63\n" - " srlg %2,%2,6\n" - "0: cg %1,0(%0,%4)\n" - " jne 1f\n" - " la %0,8(%0)\n" - " brct %2,0b\n" - " lgr %0,%3\n" - " j 5f\n" - "1: lg %2,0(%0,%4)\n" - " sllg %0,%0,3\n" - " clr %2,%1\n" - " jne 2f\n" - " aghi %0,32\n" - " srlg %2,%2,32\n" - "2: lghi %1,0xff\n" - " tmll %2,0xffff\n" - " jno 3f\n" - " aghi %0,16\n" - " srl %2,16\n" - "3: tmll %2,0x00ff\n" - " jno 4f\n" - " aghi %0,8\n" - " srl %2,8\n" - "4: ngr %2,%1\n" - " ic %2,0(%2,%5)\n" - " algr %0,%2\n" - "5:" - : "=&a" (res), "=&d" (cmp), "=&a" (count) - : "a" (size), "a" (addr), "a" (&_zb_findmap), - "m" (*(addrtype *) addr) : "cc" ); - return (res < size) ? res : size; + bytes = __ffz_word_loop(addr, size); + bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes)); + return (bits < size) ? bits : size; } -static inline unsigned long -find_first_bit(const unsigned long * addr, unsigned long size) +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first set bit, not the number of the byte + * containing a bit. + */ +static inline unsigned long find_first_bit(const unsigned long * addr, + unsigned long size) { - typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; - unsigned long res, cmp, count; + unsigned long bytes, bits; if (!size) return 0; - __asm__(" slgr %1,%1\n" - " lgr %2,%3\n" - " slgr %0,%0\n" - " aghi %2,63\n" - " srlg %2,%2,6\n" - "0: cg %1,0(%0,%4)\n" - " jne 1f\n" - " aghi %0,8\n" - " brct %2,0b\n" - " lgr %0,%3\n" - " j 5f\n" - "1: lg %2,0(%0,%4)\n" - " sllg %0,%0,3\n" - " clr %2,%1\n" - " jne 2f\n" - " aghi %0,32\n" - " srlg %2,%2,32\n" - "2: lghi %1,0xff\n" - " tmll %2,0xffff\n" - " jnz 3f\n" - " aghi %0,16\n" - " srl %2,16\n" - "3: tmll %2,0x00ff\n" - " jnz 4f\n" - " aghi %0,8\n" - " srl %2,8\n" - "4: ngr %2,%1\n" - " ic %2,0(%2,%5)\n" - " algr %0,%2\n" - "5:" - : "=&a" (res), "=&d" (cmp), "=&a" (count) - : "a" (size), "a" (addr), "a" (&_sb_findmap), - "m" (*(addrtype *) addr) : "cc" ); - return (res < size) ? res : size; + bytes = __ffs_word_loop(addr, size); + bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes)); + return (bits < size) ? bits : size; } -#endif /* __s390x__ */ - -static inline int -find_next_zero_bit (const unsigned long * addr, unsigned long size, - unsigned long offset) +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static inline int find_next_zero_bit (const unsigned long * addr, + unsigned long size, + unsigned long offset) { const unsigned long *p; unsigned long bit, set; @@ -772,10 +702,10 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size, p = addr + offset / __BITOPS_WORDSIZE; if (bit) { /* - * s390 version of ffz returns __BITOPS_WORDSIZE + * __ffz_word returns __BITOPS_WORDSIZE * if no zero bit is present in the word. */ - set = ffz(*p >> bit) + bit; + set = __ffz_word(0, *p >> bit) + bit; if (set >= size) return size + offset; if (set < __BITOPS_WORDSIZE) @@ -787,9 +717,15 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size, return offset + find_first_zero_bit(p, size); } -static inline int -find_next_bit (const unsigned long * addr, unsigned long size, - unsigned long offset) +/** + * find_next_bit - find the first set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static inline int find_next_bit (const unsigned long * addr, + unsigned long size, + unsigned long offset) { const unsigned long *p; unsigned long bit, set; @@ -802,10 +738,10 @@ find_next_bit (const unsigned long * addr, unsigned long size, p = addr + offset / __BITOPS_WORDSIZE; if (bit) { /* - * s390 version of __ffs returns __BITOPS_WORDSIZE + * __ffs_word returns __BITOPS_WORDSIZE * if no one bit is present in the word. */ - set = __ffs(*p & (~0UL << bit)); + set = __ffs_word(0, *p & (~0UL << bit)); if (set >= size) return size + offset; if (set < __BITOPS_WORDSIZE) @@ -828,36 +764,11 @@ static inline int sched_find_first_bit(unsigned long *b) return find_first_bit(b, 140); } -/* - * ffs: find first bit set. This is defined the same way as - * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). - */ -#define ffs(x) generic_ffs(x) - -/* - * fls: find last bit set. - */ -#define fls(x) generic_fls(x) - -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word - */ -#define hweight64(x) \ -({ \ - unsigned long __x = (x); \ - unsigned int __w; \ - __w = generic_hweight32((unsigned int) __x); \ - __w += generic_hweight32((unsigned int) (__x>>32)); \ - __w; \ -}) -#define hweight32(x) generic_hweight32(x) -#define hweight16(x) generic_hweight16(x) -#define hweight8(x) generic_hweight8(x) +#include +#include - -#ifdef __KERNEL__ +#include +#include /* * ATTENTION: intel byte ordering convention for ext2 and minix !! @@ -870,113 +781,32 @@ static inline int sched_find_first_bit(unsigned long *b) */ #define ext2_set_bit(nr, addr) \ - test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) + __test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) #define ext2_set_bit_atomic(lock, nr, addr) \ test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) #define ext2_clear_bit(nr, addr) \ - test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) + __test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) #define ext2_clear_bit_atomic(lock, nr, addr) \ test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) #define ext2_test_bit(nr, addr) \ test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) -#ifndef __s390x__ - -static inline int -ext2_find_first_zero_bit(void *vaddr, unsigned int size) +static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size) { - typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; - unsigned long cmp, count; - unsigned int res; + unsigned long bytes, bits; if (!size) return 0; - __asm__(" lhi %1,-1\n" - " lr %2,%3\n" - " ahi %2,31\n" - " srl %2,5\n" - " slr %0,%0\n" - "0: cl %1,0(%0,%4)\n" - " jne 1f\n" - " ahi %0,4\n" - " brct %2,0b\n" - " lr %0,%3\n" - " j 4f\n" - "1: l %2,0(%0,%4)\n" - " sll %0,3\n" - " ahi %0,24\n" - " lhi %1,0xff\n" - " tmh %2,0xffff\n" - " jo 2f\n" - " ahi %0,-16\n" - " srl %2,16\n" - "2: tml %2,0xff00\n" - " jo 3f\n" - " ahi %0,-8\n" - " srl %2,8\n" - "3: nr %2,%1\n" - " ic %2,0(%2,%5)\n" - " alr %0,%2\n" - "4:" - : "=&a" (res), "=&d" (cmp), "=&a" (count) - : "a" (size), "a" (vaddr), "a" (&_zb_findmap), - "m" (*(addrtype *) vaddr) : "cc" ); - return (res < size) ? res : size; + bytes = __ffz_word_loop(vaddr, size); + bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes)); + return (bits < size) ? bits : size; } -#else /* __s390x__ */ - -static inline unsigned long -ext2_find_first_zero_bit(void *vaddr, unsigned long size) -{ - typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; - unsigned long res, cmp, count; - - if (!size) - return 0; - __asm__(" lghi %1,-1\n" - " lgr %2,%3\n" - " aghi %2,63\n" - " srlg %2,%2,6\n" - " slgr %0,%0\n" - "0: clg %1,0(%0,%4)\n" - " jne 1f\n" - " aghi %0,8\n" - " brct %2,0b\n" - " lgr %0,%3\n" - " j 5f\n" - "1: cl %1,0(%0,%4)\n" - " jne 2f\n" - " aghi %0,4\n" - "2: l %2,0(%0,%4)\n" - " sllg %0,%0,3\n" - " aghi %0,24\n" - " lghi %1,0xff\n" - " tmlh %2,0xffff\n" - " jo 3f\n" - " aghi %0,-16\n" - " srl %2,16\n" - "3: tmll %2,0xff00\n" - " jo 4f\n" - " aghi %0,-8\n" - " srl %2,8\n" - "4: ngr %2,%1\n" - " ic %2,0(%2,%5)\n" - " algr %0,%2\n" - "5:" - : "=&a" (res), "=&d" (cmp), "=&a" (count) - : "a" (size), "a" (vaddr), "a" (&_zb_findmap), - "m" (*(addrtype *) vaddr) : "cc" ); - return (res < size) ? res : size; -} - -#endif /* __s390x__ */ - -static inline int -ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) +static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size, + unsigned long offset) { unsigned long *addr = vaddr, *p; - unsigned long word, bit, set; + unsigned long bit, set; if (offset >= size) return size; @@ -985,20 +815,11 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) size -= offset; p = addr + offset / __BITOPS_WORDSIZE; if (bit) { -#ifndef __s390x__ - asm(" ic %0,0(%1)\n" - " icm %0,2,1(%1)\n" - " icm %0,4,2(%1)\n" - " icm %0,8,3(%1)" - : "=&a" (word) : "a" (p), "m" (*p) : "cc" ); -#else - asm(" lrvg %0,%1" : "=a" (word) : "m" (*p) ); -#endif /* * s390 version of ffz returns __BITOPS_WORDSIZE * if no zero bit is present in the word. */ - set = ffz(word >> bit) + bit; + set = ffz(__load_ulong_le(p, 0) >> bit) + bit; if (set >= size) return size + offset; if (set < __BITOPS_WORDSIZE) @@ -1010,18 +831,48 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) return offset + ext2_find_first_zero_bit(p, size); } -/* Bitmap functions for the minix filesystem. */ -/* FIXME !!! */ -#define minix_test_and_set_bit(nr,addr) \ - test_and_set_bit(nr,(unsigned long *)addr) -#define minix_set_bit(nr,addr) \ - set_bit(nr,(unsigned long *)addr) -#define minix_test_and_clear_bit(nr,addr) \ - test_and_clear_bit(nr,(unsigned long *)addr) -#define minix_test_bit(nr,addr) \ - test_bit(nr,(unsigned long *)addr) -#define minix_find_first_zero_bit(addr,size) \ - find_first_zero_bit(addr,size) +static inline unsigned long ext2_find_first_bit(void *vaddr, + unsigned long size) +{ + unsigned long bytes, bits; + + if (!size) + return 0; + bytes = __ffs_word_loop(vaddr, size); + bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes)); + return (bits < size) ? bits : size; +} + +static inline int ext2_find_next_bit(void *vaddr, unsigned long size, + unsigned long offset) +{ + unsigned long *addr = vaddr, *p; + unsigned long bit, set; + + if (offset >= size) + return size; + bit = offset & (__BITOPS_WORDSIZE - 1); + offset -= bit; + size -= offset; + p = addr + offset / __BITOPS_WORDSIZE; + if (bit) { + /* + * s390 version of ffz returns __BITOPS_WORDSIZE + * if no zero bit is present in the word. + */ + set = ffs(__load_ulong_le(p, 0) >> bit) + bit; + if (set >= size) + return size + offset; + if (set < __BITOPS_WORDSIZE) + return set + offset; + offset += __BITOPS_WORDSIZE; + size -= __BITOPS_WORDSIZE; + p++; + } + return offset + ext2_find_first_bit(p, size); +} + +#include #endif /* __KERNEL__ */