aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/include/asm/word-at-a-time.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/include/asm/word-at-a-time.h')
-rw-r--r--arch/powerpc/include/asm/word-at-a-time.h112
1 files changed, 98 insertions, 14 deletions
diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h
index 9a5c928bb3c6..5b3a903adae6 100644
--- a/arch/powerpc/include/asm/word-at-a-time.h
+++ b/arch/powerpc/include/asm/word-at-a-time.h
@@ -42,32 +42,65 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
42 42
43#else 43#else
44 44
45#ifdef CONFIG_64BIT
46
47/* unused */
45struct word_at_a_time { 48struct word_at_a_time {
46 const unsigned long one_bits, high_bits;
47}; 49};
48 50
49#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } 51#define WORD_AT_A_TIME_CONSTANTS { }
50 52
51#ifdef CONFIG_64BIT 53/* This will give us 0xff for a NULL char and 0x00 elsewhere */
54static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
55{
56 unsigned long ret;
57 unsigned long zero = 0;
52 58
53/* Alan Modra's little-endian strlen tail for 64-bit */ 59 asm("cmpb %0,%1,%2" : "=r" (ret) : "r" (a), "r" (zero));
54#define create_zero_mask(mask) (mask) 60 *bits = ret;
55 61
56static inline unsigned long find_zero(unsigned long mask) 62 return ret;
63}
64
65static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
66{
67 return bits;
68}
69
70/* Alan Modra's little-endian strlen tail for 64-bit */
71static inline unsigned long create_zero_mask(unsigned long bits)
57{ 72{
58 unsigned long leading_zero_bits; 73 unsigned long leading_zero_bits;
59 long trailing_zero_bit_mask; 74 long trailing_zero_bit_mask;
60 75
61 asm ("addi %1,%2,-1\n\t" 76 asm("addi %1,%2,-1\n\t"
62 "andc %1,%1,%2\n\t" 77 "andc %1,%1,%2\n\t"
63 "popcntd %0,%1" 78 "popcntd %0,%1"
64 : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask) 79 : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask)
65 : "r" (mask)); 80 : "r" (bits));
66 return leading_zero_bits >> 3; 81
82 return leading_zero_bits;
83}
84
85static inline unsigned long find_zero(unsigned long mask)
86{
87 return mask >> 3;
88}
89
90/* This assumes that we never ask for an all 1s bitmask */
91static inline unsigned long zero_bytemask(unsigned long mask)
92{
93 return (1UL << mask) - 1;
67} 94}
68 95
69#else /* 32-bit case */ 96#else /* 32-bit case */
70 97
98struct word_at_a_time {
99 const unsigned long one_bits, high_bits;
100};
101
102#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
103
71/* 104/*
72 * This is largely generic for little-endian machines, but the 105 * This is largely generic for little-endian machines, but the
73 * optimal byte mask counting is probably going to be something 106 * optimal byte mask counting is probably going to be something
@@ -96,8 +129,6 @@ static inline unsigned long find_zero(unsigned long mask)
96 return count_masked_bytes(mask); 129 return count_masked_bytes(mask);
97} 130}
98 131
99#endif
100
101/* Return nonzero if it has a zero */ 132/* Return nonzero if it has a zero */
102static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c) 133static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
103{ 134{
@@ -114,6 +145,59 @@ static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits,
114/* The mask we created is directly usable as a bytemask */ 145/* The mask we created is directly usable as a bytemask */
115#define zero_bytemask(mask) (mask) 146#define zero_bytemask(mask) (mask)
116 147
148#endif /* CONFIG_64BIT */
149
150#endif /* __BIG_ENDIAN__ */
151
152/*
153 * We use load_unaligned_zero() in a selftest, which builds a userspace
154 * program. Some linker scripts seem to discard the .fixup section, so allow
155 * the test code to use a different section name.
156 */
157#ifndef FIXUP_SECTION
158#define FIXUP_SECTION ".fixup"
159#endif
160
161static inline unsigned long load_unaligned_zeropad(const void *addr)
162{
163 unsigned long ret, offset, tmp;
164
165 asm(
166 "1: " PPC_LL "%[ret], 0(%[addr])\n"
167 "2:\n"
168 ".section " FIXUP_SECTION ",\"ax\"\n"
169 "3: "
170#ifdef __powerpc64__
171 "clrrdi %[tmp], %[addr], 3\n\t"
172 "clrlsldi %[offset], %[addr], 61, 3\n\t"
173 "ld %[ret], 0(%[tmp])\n\t"
174#ifdef __BIG_ENDIAN__
175 "sld %[ret], %[ret], %[offset]\n\t"
176#else
177 "srd %[ret], %[ret], %[offset]\n\t"
117#endif 178#endif
179#else
180 "clrrwi %[tmp], %[addr], 2\n\t"
181 "clrlslwi %[offset], %[addr], 30, 3\n\t"
182 "lwz %[ret], 0(%[tmp])\n\t"
183#ifdef __BIG_ENDIAN__
184 "slw %[ret], %[ret], %[offset]\n\t"
185#else
186 "srw %[ret], %[ret], %[offset]\n\t"
187#endif
188#endif
189 "b 2b\n"
190 ".previous\n"
191 ".section __ex_table,\"a\"\n\t"
192 PPC_LONG_ALIGN "\n\t"
193 PPC_LONG "1b,3b\n"
194 ".previous"
195 : [tmp] "=&b" (tmp), [offset] "=&r" (offset), [ret] "=&r" (ret)
196 : [addr] "b" (addr), "m" (*(unsigned long *)addr));
197
198 return ret;
199}
200
201#undef FIXUP_SECTION
118 202
119#endif /* _ASM_WORD_AT_A_TIME_H */ 203#endif /* _ASM_WORD_AT_A_TIME_H */