Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef __ASM_ARM_WORD_AT_A_TIME_H
0003 #define __ASM_ARM_WORD_AT_A_TIME_H
0004 
0005 #ifndef __ARMEB__
0006 
0007 /*
0008  * Little-endian word-at-a-time zero byte handling.
0009  * Heavily based on the x86 algorithm.
0010  */
0011 #include <linux/kernel.h>
0012 
0013 struct word_at_a_time {
0014     const unsigned long one_bits, high_bits;
0015 };
0016 
0017 #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
0018 
0019 static inline unsigned long has_zero(unsigned long a, unsigned long *bits,
0020                      const struct word_at_a_time *c)
0021 {
0022     unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
0023     *bits = mask;
0024     return mask;
0025 }
0026 
0027 #define prep_zero_mask(a, bits, c) (bits)
0028 
0029 static inline unsigned long create_zero_mask(unsigned long bits)
0030 {
0031     bits = (bits - 1) & ~bits;
0032     return bits >> 7;
0033 }
0034 
0035 static inline unsigned long find_zero(unsigned long mask)
0036 {
0037     unsigned long ret;
0038 
0039 #if __LINUX_ARM_ARCH__ >= 5
0040     /* We have clz available. */
0041     ret = fls(mask) >> 3;
0042 #else
0043     /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
0044     ret = (0x0ff0001 + mask) >> 23;
0045     /* Fix the 1 for 00 case */
0046     ret &= mask;
0047 #endif
0048 
0049     return ret;
0050 }
0051 
0052 #define zero_bytemask(mask) (mask)
0053 
0054 #else   /* __ARMEB__ */
0055 #include <asm-generic/word-at-a-time.h>
0056 #endif
0057 
0058 #ifdef CONFIG_DCACHE_WORD_ACCESS
0059 
0060 /*
0061  * Load an unaligned word from kernel space.
0062  *
0063  * In the (very unlikely) case of the word being a page-crosser
0064  * and the next page not being mapped, take the exception and
0065  * return zeroes in the non-existing part.
0066  */
0067 static inline unsigned long load_unaligned_zeropad(const void *addr)
0068 {
0069     unsigned long ret, offset;
0070 
0071     /* Load word from unaligned pointer addr */
0072     asm(
0073     "1: ldr %0, [%2]\n"
0074     "2:\n"
0075     "   .pushsection .text.fixup,\"ax\"\n"
0076     "   .align 2\n"
0077     "3: and %1, %2, #0x3\n"
0078     "   bic %2, %2, #0x3\n"
0079     "   ldr %0, [%2]\n"
0080     "   lsl %1, %1, #0x3\n"
0081 #ifndef __ARMEB__
0082     "   lsr %0, %0, %1\n"
0083 #else
0084     "   lsl %0, %0, %1\n"
0085 #endif
0086     "   b   2b\n"
0087     "   .popsection\n"
0088     "   .pushsection __ex_table,\"a\"\n"
0089     "   .align  3\n"
0090     "   .long   1b, 3b\n"
0091     "   .popsection"
0092     : "=&r" (ret), "=&r" (offset)
0093     : "r" (addr), "Qo" (*(unsigned long *)addr));
0094 
0095     return ret;
0096 }
0097 
0098 #endif  /* DCACHE_WORD_ACCESS */
0099 #endif /* __ASM_ARM_WORD_AT_A_TIME_H */