Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ASM_WORD_AT_A_TIME_H
0003 #define _ASM_WORD_AT_A_TIME_H
0004 
0005 #include <linux/kernel.h>
0006 
0007 /*
0008  * This is largely generic for little-endian machines, but the
0009  * optimal byte mask counting is probably going to be something
0010  * that is architecture-specific. If you have a reliably fast
0011  * bit count instruction, that might be better than the multiply
0012  * and shift, for example.
0013  */
0014 struct word_at_a_time {
0015     const unsigned long one_bits, high_bits;
0016 };
0017 
0018 #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
0019 
0020 #ifdef CONFIG_64BIT
0021 
0022 /*
0023  * Jan Achrenius on G+: microoptimized version of
0024  * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
0025  * that works for the bytemasks without having to
0026  * mask them first.
0027  */
0028 static inline long count_masked_bytes(unsigned long mask)
0029 {
0030     return mask*0x0001020304050608ul >> 56;
0031 }
0032 
0033 #else   /* 32-bit case */
0034 
0035 /* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
0036 static inline long count_masked_bytes(long mask)
0037 {
0038     /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
0039     long a = (0x0ff0001+mask) >> 23;
0040     /* Fix the 1 for 00 case */
0041     return a & mask;
0042 }
0043 
0044 #endif
0045 
0046 /* Return nonzero if it has a zero */
0047 static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
0048 {
0049     unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
0050     *bits = mask;
0051     return mask;
0052 }
0053 
0054 static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
0055 {
0056     return bits;
0057 }
0058 
0059 static inline unsigned long create_zero_mask(unsigned long bits)
0060 {
0061     bits = (bits - 1) & ~bits;
0062     return bits >> 7;
0063 }
0064 
0065 /* The mask we created is directly usable as a bytemask */
0066 #define zero_bytemask(mask) (mask)
0067 
0068 static inline unsigned long find_zero(unsigned long mask)
0069 {
0070     return count_masked_bytes(mask);
0071 }
0072 
0073 /*
0074  * Load an unaligned word from kernel space.
0075  *
0076  * In the (very unlikely) case of the word being a page-crosser
0077  * and the next page not being mapped, take the exception and
0078  * return zeroes in the non-existing part.
0079  */
0080 static inline unsigned long load_unaligned_zeropad(const void *addr)
0081 {
0082     unsigned long ret;
0083 
0084     asm volatile(
0085         "1: mov %[mem], %[ret]\n"
0086         "2:\n"
0087         _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_ZEROPAD)
0088         : [ret] "=r" (ret)
0089         : [mem] "m" (*(unsigned long *)addr));
0090 
0091     return ret;
0092 }
0093 
0094 #endif /* _ASM_WORD_AT_A_TIME_H */