diff options
author | Chris Metcalf <cmetcalf@tilera.com> | 2012-03-29 13:30:31 -0400 |
---|---|---|
committer | Chris Metcalf <cmetcalf@tilera.com> | 2012-05-25 12:48:22 -0400 |
commit | 1efea40d4172a2a475ccb29b59d6221e9d0c174b (patch) | |
tree | 8152b61bb3fa83eb3403bca5cb05731c1063e999 /arch/tile/lib | |
parent | 73636b1aacb1a07e6fbe0d25e560e69b024a8e25 (diff) |
arch/tile: support building big-endian kernel
The toolchain supports big-endian mode now, so add support for building
the kernel to run big-endian as well.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch/tile/lib')
-rw-r--r-- | arch/tile/lib/memchr_64.c | 8 | ||||
-rw-r--r-- | arch/tile/lib/memcpy_64.c | 23 | ||||
-rw-r--r-- | arch/tile/lib/strchr_64.c | 15 | ||||
-rw-r--r-- | arch/tile/lib/string-endian.h | 33 | ||||
-rw-r--r-- | arch/tile/lib/strlen_64.c | 11 |
5 files changed, 66 insertions, 24 deletions
diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c index 84fdc8d8e735..6f867dbf7c56 100644 --- a/arch/tile/lib/memchr_64.c +++ b/arch/tile/lib/memchr_64.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include "string-endian.h" | ||
18 | 19 | ||
19 | void *memchr(const void *s, int c, size_t n) | 20 | void *memchr(const void *s, int c, size_t n) |
20 | { | 21 | { |
@@ -39,11 +40,8 @@ void *memchr(const void *s, int c, size_t n) | |||
39 | 40 | ||
40 | /* Read the first word, but munge it so that bytes before the array | 41 | /* Read the first word, but munge it so that bytes before the array |
41 | * will not match goal. | 42 | * will not match goal. |
42 | * | ||
43 | * Note that this shift count expression works because we know | ||
44 | * shift counts are taken mod 64. | ||
45 | */ | 43 | */ |
46 | before_mask = (1ULL << (s_int << 3)) - 1; | 44 | before_mask = MASK(s_int); |
47 | v = (*p | before_mask) ^ (goal & before_mask); | 45 | v = (*p | before_mask) ^ (goal & before_mask); |
48 | 46 | ||
49 | /* Compute the address of the last byte. */ | 47 | /* Compute the address of the last byte. */ |
@@ -65,7 +63,7 @@ void *memchr(const void *s, int c, size_t n) | |||
65 | /* We found a match, but it might be in a byte past the end | 63 | /* We found a match, but it might be in a byte past the end |
66 | * of the array. | 64 | * of the array. |
67 | */ | 65 | */ |
68 | ret = ((char *)p) + (__insn_ctz(bits) >> 3); | 66 | ret = ((char *)p) + (CFZ(bits) >> 3); |
69 | return (ret <= last_byte_ptr) ? ret : NULL; | 67 | return (ret <= last_byte_ptr) ? ret : NULL; |
70 | } | 68 | } |
71 | EXPORT_SYMBOL(memchr); | 69 | EXPORT_SYMBOL(memchr); |
diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c index 3fab9a6a2bbe..c79b8e7c6828 100644 --- a/arch/tile/lib/memcpy_64.c +++ b/arch/tile/lib/memcpy_64.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #define __memcpy memcpy | ||
19 | /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ | 18 | /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ |
20 | 19 | ||
21 | /* Must be 8 bytes in size. */ | 20 | /* Must be 8 bytes in size. */ |
@@ -188,6 +187,7 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) | |||
188 | 187 | ||
189 | /* n != 0 if we get here. Write out any trailing bytes. */ | 188 | /* n != 0 if we get here. Write out any trailing bytes. */ |
190 | dst1 = (char *)dst8; | 189 | dst1 = (char *)dst8; |
190 | #ifndef __BIG_ENDIAN__ | ||
191 | if (n & 4) { | 191 | if (n & 4) { |
192 | ST4((uint32_t *)dst1, final); | 192 | ST4((uint32_t *)dst1, final); |
193 | dst1 += 4; | 193 | dst1 += 4; |
@@ -202,11 +202,30 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) | |||
202 | } | 202 | } |
203 | if (n) | 203 | if (n) |
204 | ST1((uint8_t *)dst1, final); | 204 | ST1((uint8_t *)dst1, final); |
205 | #else | ||
206 | if (n & 4) { | ||
207 | ST4((uint32_t *)dst1, final >> 32); | ||
208 | dst1 += 4; | ||
209 | } | ||
210 | else | ||
211 | { | ||
212 | final >>= 32; | ||
213 | } | ||
214 | if (n & 2) { | ||
215 | ST2((uint16_t *)dst1, final >> 16); | ||
216 | dst1 += 2; | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | final >>= 16; | ||
221 | } | ||
222 | if (n & 1) | ||
223 | ST1((uint8_t *)dst1, final >> 8); | ||
224 | #endif | ||
205 | 225 | ||
206 | return RETVAL; | 226 | return RETVAL; |
207 | } | 227 | } |
208 | 228 | ||
209 | |||
210 | #ifdef USERCOPY_FUNC | 229 | #ifdef USERCOPY_FUNC |
211 | #undef ST1 | 230 | #undef ST1 |
212 | #undef ST2 | 231 | #undef ST2 |
diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c index 617a9273aaa8..f39f9dc422b0 100644 --- a/arch/tile/lib/strchr_64.c +++ b/arch/tile/lib/strchr_64.c | |||
@@ -15,8 +15,7 @@ | |||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | 18 | #include "string-endian.h" | |
19 | #undef strchr | ||
20 | 19 | ||
21 | char *strchr(const char *s, int c) | 20 | char *strchr(const char *s, int c) |
22 | { | 21 | { |
@@ -33,13 +32,9 @@ char *strchr(const char *s, int c) | |||
33 | * match neither zero nor goal (we make sure the high bit of each | 32 | * match neither zero nor goal (we make sure the high bit of each |
34 | * byte is 1, and the low 7 bits are all the opposite of the goal | 33 | * byte is 1, and the low 7 bits are all the opposite of the goal |
35 | * byte). | 34 | * byte). |
36 | * | ||
37 | * Note that this shift count expression works because we know shift | ||
38 | * counts are taken mod 64. | ||
39 | */ | 35 | */ |
40 | const uint64_t before_mask = (1ULL << (s_int << 3)) - 1; | 36 | const uint64_t before_mask = MASK(s_int); |
41 | uint64_t v = (*p | before_mask) ^ | 37 | uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui(before_mask, 1)); |
42 | (goal & __insn_v1shrsi(before_mask, 1)); | ||
43 | 38 | ||
44 | uint64_t zero_matches, goal_matches; | 39 | uint64_t zero_matches, goal_matches; |
45 | while (1) { | 40 | while (1) { |
@@ -55,8 +50,8 @@ char *strchr(const char *s, int c) | |||
55 | v = *++p; | 50 | v = *++p; |
56 | } | 51 | } |
57 | 52 | ||
58 | z = __insn_ctz(zero_matches); | 53 | z = CFZ(zero_matches); |
59 | g = __insn_ctz(goal_matches); | 54 | g = CFZ(goal_matches); |
60 | 55 | ||
61 | /* If we found c before '\0' we got a match. Note that if c == '\0' | 56 | /* If we found c before '\0' we got a match. Note that if c == '\0' |
62 | * then g == z, and we correctly return the address of the '\0' | 57 | * then g == z, and we correctly return the address of the '\0' |
diff --git a/arch/tile/lib/string-endian.h b/arch/tile/lib/string-endian.h new file mode 100644 index 000000000000..c0eed7ce69c3 --- /dev/null +++ b/arch/tile/lib/string-endian.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * Provide a mask based on the pointer alignment that | ||
15 | * sets up non-zero bytes before the beginning of the string. | ||
16 | * The MASK expression works because shift counts are taken mod 64. | ||
17 | * Also, specify how to count "first" and "last" bits | ||
18 | * when the bits have been read as a word. | ||
19 | */ | ||
20 | |||
21 | #include <asm/byteorder.h> | ||
22 | |||
23 | #ifdef __LITTLE_ENDIAN | ||
24 | #define MASK(x) (__insn_shl(1ULL, (x << 3)) - 1) | ||
25 | #define NULMASK(x) ((2ULL << x) - 1) | ||
26 | #define CFZ(x) __insn_ctz(x) | ||
27 | #define REVCZ(x) __insn_clz(x) | ||
28 | #else | ||
29 | #define MASK(x) (__insn_shl(-2LL, ((-x << 3) - 1))) | ||
30 | #define NULMASK(x) (-2LL << (63 - x)) | ||
31 | #define CFZ(x) __insn_clz(x) | ||
32 | #define REVCZ(x) __insn_ctz(x) | ||
33 | #endif | ||
diff --git a/arch/tile/lib/strlen_64.c b/arch/tile/lib/strlen_64.c index 1c92d46202a8..9583fc3361fa 100644 --- a/arch/tile/lib/strlen_64.c +++ b/arch/tile/lib/strlen_64.c | |||
@@ -15,8 +15,7 @@ | |||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | 18 | #include "string-endian.h" | |
19 | #undef strlen | ||
20 | 19 | ||
21 | size_t strlen(const char *s) | 20 | size_t strlen(const char *s) |
22 | { | 21 | { |
@@ -24,15 +23,13 @@ size_t strlen(const char *s) | |||
24 | const uintptr_t s_int = (uintptr_t) s; | 23 | const uintptr_t s_int = (uintptr_t) s; |
25 | const uint64_t *p = (const uint64_t *)(s_int & -8); | 24 | const uint64_t *p = (const uint64_t *)(s_int & -8); |
26 | 25 | ||
27 | /* Read the first word, but force bytes before the string to be nonzero. | 26 | /* Read and MASK the first word. */ |
28 | * This expression works because we know shift counts are taken mod 64. | 27 | uint64_t v = *p | MASK(s_int); |
29 | */ | ||
30 | uint64_t v = *p | ((1ULL << (s_int << 3)) - 1); | ||
31 | 28 | ||
32 | uint64_t bits; | 29 | uint64_t bits; |
33 | while ((bits = __insn_v1cmpeqi(v, 0)) == 0) | 30 | while ((bits = __insn_v1cmpeqi(v, 0)) == 0) |
34 | v = *++p; | 31 | v = *++p; |
35 | 32 | ||
36 | return ((const char *)p) + (__insn_ctz(bits) >> 3) - s; | 33 | return ((const char *)p) + (CFZ(bits) >> 3) - s; |
37 | } | 34 | } |
38 | EXPORT_SYMBOL(strlen); | 35 | EXPORT_SYMBOL(strlen); |