68000, 68010, and CPU32 don't support bitfield instructions: - Implement ffz(), ffs(), __ffs(), and fls() on bitfield-less CPUs, - Always use the (very generic) __const_*() routines on bitfield-less CPUs, - Don't use bitfield instructions directly in the various *find_*() routines, call __ffs() and ffs() instead, - Implement minix_find_first_zero_bit() similarly to find_first_zero_bit() for consistency (and speed). --- bitops.h | 380 +++++++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 238 insertions(+), 142 deletions(-) --- linux-m68k-2.6.8.1+uc0/include/asm-m68k/bitops.h 2004-06-21 20:20:00.000000000 +0200 +++ uClinux-amiga-2.6.8.1/include/asm-m68k/bitops.h 2004-10-17 18:02:37.000000000 +0200 @@ -8,21 +8,13 @@ * for more details. */ +#include #include /* - * Require 68020 or better. - * - * They use the standard big-endian m680x0 bit ordering. + * All bit operations use the standard big-endian m680x0 bit ordering. */ -#define test_and_set_bit(nr,vaddr) \ - (__builtin_constant_p(nr) ? \ - __constant_test_and_set_bit(nr, vaddr) : \ - __generic_test_and_set_bit(nr, vaddr)) - -#define __test_and_set_bit(nr,vaddr) test_and_set_bit(nr,vaddr) - static inline int __constant_test_and_set_bit(int nr, unsigned long *vaddr) { char *p = (char *)vaddr + (nr ^ 31) / 8; @@ -35,23 +27,6 @@ static inline int __constant_test_and_se return retval; } -static inline int __generic_test_and_set_bit(int nr, unsigned long *vaddr) -{ - char retval; - - __asm__ __volatile__ ("bfset %2{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr^31), "o" (*vaddr) : "memory"); - - return retval; -} - -#define set_bit(nr,vaddr) \ - (__builtin_constant_p(nr) ? \ - __constant_set_bit(nr, vaddr) : \ - __generic_set_bit(nr, vaddr)) - -#define __set_bit(nr,vaddr) set_bit(nr,vaddr) - static inline void __constant_set_bit(int nr, volatile unsigned long *vaddr) { char *p = (char *)vaddr + (nr ^ 31) / 8; @@ -59,19 +34,6 @@ static inline void __constant_set_bit(in : "+m" (*p) : "di" (nr & 7)); } -static inline void __generic_set_bit(int nr, volatile unsigned long *vaddr) -{ - __asm__ __volatile__ ("bfset %1{%0:#1}" - : : "d" (nr^31), "o" (*vaddr) : "memory"); -} - -#define test_and_clear_bit(nr,vaddr) \ - (__builtin_constant_p(nr) ? \ - __constant_test_and_clear_bit(nr, vaddr) : \ - __generic_test_and_clear_bit(nr, vaddr)) - -#define __test_and_clear_bit(nr,vaddr) test_and_clear_bit(nr,vaddr) - static inline int __constant_test_and_clear_bit(int nr, unsigned long *vaddr) { char *p = (char *)vaddr + (nr ^ 31) / 8; @@ -84,61 +46,180 @@ static inline int __constant_test_and_cl return retval; } -static inline int __generic_test_and_clear_bit(int nr, unsigned long *vaddr) +static inline void __constant_clear_bit(int nr, volatile unsigned long *vaddr) +{ + char *p = (char *)vaddr + (nr ^ 31) / 8; + __asm__ __volatile__ ("bclr %1,%0" + : "+m" (*p) : "di" (nr & 7)); +} + +static inline int __constant_test_and_change_bit(int nr, unsigned long *vaddr) { + char *p = (char *)vaddr + (nr ^ 31) / 8; char retval; - __asm__ __volatile__ ("bfclr %2{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr^31), "o" (*vaddr) : "memory"); + __asm__ __volatile__ ("bchg %2,%1; sne %0" + : "=d" (retval), "+m" (*p) + : "di" (nr & 7)); return retval; } +static inline void __constant_change_bit(int nr, unsigned long *vaddr) +{ + char *p = (char *)vaddr + (nr ^ 31) / 8; + __asm__ __volatile__ ("bchg %1,%0" + : "+m" (*p) : "di" (nr & 7)); +} + + +#define __test_and_set_bit(nr,vaddr) test_and_set_bit(nr,vaddr) +#define __set_bit(nr,vaddr) set_bit(nr,vaddr) +#define __test_and_clear_bit(nr,vaddr) test_and_clear_bit(nr,vaddr) +#define __clear_bit(nr,vaddr) clear_bit(nr,vaddr) +#define __test_and_change_bit(nr,vaddr) test_and_change_bit(nr,vaddr) +#define __change_bit(nr,vaddr) change_bit(nr,vaddr) + + /* * clear_bit() doesn't provide any barrier for the compiler. */ #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() -#define clear_bit(nr,vaddr) \ - (__builtin_constant_p(nr) ? \ - __constant_clear_bit(nr, vaddr) : \ - __generic_clear_bit(nr, vaddr)) -#define __clear_bit(nr,vaddr) clear_bit(nr,vaddr) -static inline void __constant_clear_bit(int nr, volatile unsigned long *vaddr) +#if defined(CONFIG_M68000) || defined(CONFIG_M68010) || defined(CONFIG_MCPU32) + +/* + * Since 68000, 68010, and CPU32 don't have bitfield instructions, we just use + * the same code as for the constant case + */ + +#define test_and_set_bit(nr,vaddr) __constant_test_and_set_bit(nr, vaddr) +#define set_bit(nr,vaddr) __constant_set_bit(nr, vaddr) +#define test_and_clear_bit(nr,vaddr) __constant_test_and_clear_bit(nr, vaddr) +#define clear_bit(nr,vaddr) __constant_clear_bit(nr, vaddr) +#define test_and_change_bit(nr,vaddr) __constant_test_and_change_bit(nr, vaddr) +#define change_bit(nr,vaddr) __constant_change_bit(nr, vaddr) + +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +#define ffz(x) __ffs(~(x)) + +#ifdef __KERNEL__ + +/* + * 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). + */ + +static inline int ffs(int x) { - char *p = (char *)vaddr + (nr ^ 31) / 8; - __asm__ __volatile__ ("bclr %1,%0" - : "+m" (*p) : "di" (nr & 7)); + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; } -static inline void __generic_clear_bit(int nr, volatile unsigned long *vaddr) + +/* + * Generic __ffs(). + */ + +static inline int __ffs(int x) { - __asm__ __volatile__ ("bfclr %1{%0:#1}" - : : "d" (nr^31), "o" (*vaddr) : "memory"); + int r = 0; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; } -#define test_and_change_bit(nr,vaddr) \ - (__builtin_constant_p(nr) ? \ - __constant_test_and_change_bit(nr, vaddr) : \ - __generic_test_and_change_bit(nr, vaddr)) +/* + * fls: find last bit set. + */ +#define fls(x) generic_fls(x) -#define __test_and_change_bit(nr,vaddr) test_and_change_bit(nr,vaddr) -#define __change_bit(nr,vaddr) change_bit(nr,vaddr) +#endif /* __KERNEL__ */ -static inline int __constant_test_and_change_bit(int nr, unsigned long *vaddr) +#else /* 68020 or higher */ + +static inline int __generic_test_and_set_bit(int nr, unsigned long *vaddr) { - char *p = (char *)vaddr + (nr ^ 31) / 8; char retval; - __asm__ __volatile__ ("bchg %2,%1; sne %0" - : "=d" (retval), "+m" (*p) - : "di" (nr & 7)); + __asm__ __volatile__ ("bfset %2{%1:#1}; sne %0" + : "=d" (retval) : "d" (nr^31), "o" (*vaddr) : "memory"); return retval; } +static inline void __generic_set_bit(int nr, volatile unsigned long *vaddr) +{ + __asm__ __volatile__ ("bfset %1{%0:#1}" + : : "d" (nr^31), "o" (*vaddr) : "memory"); +} + +static inline int __generic_test_and_clear_bit(int nr, unsigned long *vaddr) +{ + char retval; + + __asm__ __volatile__ ("bfclr %2{%1:#1}; sne %0" + : "=d" (retval) : "d" (nr^31), "o" (*vaddr) : "memory"); + + return retval; +} + +static inline void __generic_clear_bit(int nr, volatile unsigned long *vaddr) +{ + __asm__ __volatile__ ("bfclr %1{%0:#1}" + : : "d" (nr^31), "o" (*vaddr) : "memory"); +} + static inline int __generic_test_and_change_bit(int nr, unsigned long *vaddr) { char retval; @@ -149,24 +230,91 @@ static inline int __generic_test_and_cha return retval; } +static inline void __generic_change_bit(int nr, unsigned long *vaddr) +{ + __asm__ __volatile__ ("bfchg %1{%0:#1}" + : : "d" (nr^31), "o" (*vaddr) : "memory"); +} + + +#define test_and_set_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_test_and_set_bit(nr, vaddr) : \ + __generic_test_and_set_bit(nr, vaddr)) + +#define set_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_set_bit(nr, vaddr) : \ + __generic_set_bit(nr, vaddr)) + +#define test_and_clear_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_test_and_clear_bit(nr, vaddr) : \ + __generic_test_and_clear_bit(nr, vaddr)) + +#define clear_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_clear_bit(nr, vaddr) : \ + __generic_clear_bit(nr, vaddr)) + +#define test_and_change_bit(nr,vaddr) \ + (__builtin_constant_p(nr) ? \ + __constant_test_and_change_bit(nr, vaddr) : \ + __generic_test_and_change_bit(nr, vaddr)) + #define change_bit(nr,vaddr) \ (__builtin_constant_p(nr) ? \ __constant_change_bit(nr, vaddr) : \ __generic_change_bit(nr, vaddr)) -static inline void __constant_change_bit(int nr, unsigned long *vaddr) +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +static inline unsigned long ffz(unsigned long word) { - char *p = (char *)vaddr + (nr ^ 31) / 8; - __asm__ __volatile__ ("bchg %1,%0" - : "+m" (*p) : "di" (nr & 7)); + int res; + + __asm__ __volatile__ ("bfffo %1{#0,#0},%0" + : "=d" (res) : "d" (~word & -~word)); + return res ^ 31; } -static inline void __generic_change_bit(int nr, unsigned long *vaddr) +#ifdef __KERNEL__ + +/* + * 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). + */ + +static inline int ffs(int x) { - __asm__ __volatile__ ("bfchg %1{%0:#1}" - : : "d" (nr^31), "o" (*vaddr) : "memory"); + int cnt; + + asm ("bfffo %1{#0:#0},%0" : "=d" (cnt) : "dm" (x & -x)); + + return 32 - cnt; +} +#define __ffs(x) (ffs(x) - 1) + +/* + * fls: find last bit set. + */ + +static inline int fls(int x) +{ + int cnt; + + asm ("bfffo %1{#0,#0},%0" : "=d" (cnt) : "dm" (x)); + + return 32 - cnt; } +#endif /* __KERNEL__ */ + +#endif /* 68020 or higher */ + static inline int test_bit(int nr, const unsigned long *vaddr) { return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0; @@ -188,9 +336,7 @@ static inline int find_first_zero_bit(co goto out; } - __asm__ __volatile__ ("bfffo %1{#0,#0},%0" - : "=d" (res) : "d" (num & -num)); - res ^= 31; + res = __ffs(num); out: return ((long)p - (long)vaddr - 4) * 8 + res; } @@ -208,11 +354,9 @@ static inline int find_next_zero_bit(con unsigned long num = ~*p++ & (~0UL << bit); offset -= bit; - /* Look for zero in first longword */ - __asm__ __volatile__ ("bfffo %1{#0,#0},%0" - : "=d" (res) : "d" (num & -num)); - if (res < 32) - return offset + (res ^ 31); + res = ffs(num); + if (res) + return offset + res - 1; offset += 32; } /* No zero yet, search remaining full bytes for a zero */ @@ -235,9 +379,7 @@ static inline int find_first_bit(const u goto out; } - __asm__ __volatile__ ("bfffo %1{#0,#0},%0" - : "=d" (res) : "d" (num & -num)); - res ^= 31; + res = __ffs(num); out: return ((long)p - (long)vaddr - 4) * 8 + res; } @@ -255,11 +397,9 @@ static inline int find_next_bit(const un unsigned long num = *p++ & (~0UL << bit); offset -= bit; - /* Look for one in first longword */ - __asm__ __volatile__ ("bfffo %1{#0,#0},%0" - : "=d" (res) : "d" (num & -num)); - if (res < 32) - return offset + (res ^ 31); + res = ffs(num); + if (res) + return offset + res - 1; offset += 32; } /* No one yet, search remaining full bytes for a one */ @@ -267,51 +407,9 @@ static inline int find_next_bit(const un return offset + res; } -/* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. - */ -static inline unsigned long ffz(unsigned long word) -{ - int res; - - __asm__ __volatile__ ("bfffo %1{#0,#0},%0" - : "=d" (res) : "d" (~word & -~word)); - return res ^ 31; -} - #ifdef __KERNEL__ /* - * 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). - */ - -static inline int ffs(int x) -{ - int cnt; - - asm ("bfffo %1{#0:#0},%0" : "=d" (cnt) : "dm" (x & -x)); - - return 32 - cnt; -} -#define __ffs(x) (ffs(x) - 1) - -/* - * fls: find last bit set. - */ - -static inline int fls(int x) -{ - int cnt; - - asm ("bfffo %1{#0,#0},%0" : "=d" (cnt) : "dm" (x)); - - return 32 - cnt; -} - -/* * Every architecture must define this function. It's the fastest * way of searching a 140-bit bitmap where the first 100 bits are * unlikely to be set. It's guaranteed that at least one of the 140 @@ -344,24 +442,22 @@ static inline int sched_find_first_bit(c static inline int minix_find_first_zero_bit(const void *vaddr, unsigned size) { - const unsigned short *p = vaddr, *addr = vaddr; - int res; + const unsigned short *p = vaddr; + int res = 16; unsigned short num; if (!size) return 0; - size = (size >> 4) + ((size & 15) > 0); - while (*p++ == 0xffff) - { - if (--size == 0) - return (p - addr) << 4; + size = (size + 15) >> 4; + while (!(num = ~*p++)) { + if (!--size) + goto out; } - num = ~*--p; - __asm__ __volatile__ ("bfffo %1{#16,#16},%0" - : "=d" (res) : "d" (num & -num)); - return ((p - addr) << 4) + (res ^ 31); + res = __ffs(num); +out: + return ((long)p - (long)vaddr - 2) * 8 + res; } #define minix_test_and_set_bit(nr, addr) test_and_set_bit((nr) ^ 16, (unsigned long *)(addr))