diff options
Diffstat (limited to 'arch/arm/lib/csumpartial.S')
-rw-r--r-- | arch/arm/lib/csumpartial.S | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S new file mode 100644 index 000000000000..cb5e3708f118 --- /dev/null +++ b/arch/arm/lib/csumpartial.S | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/csumpartial.S | ||
3 | * | ||
4 | * Copyright (C) 1995-1998 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/linkage.h> | ||
11 | #include <asm/assembler.h> | ||
12 | |||
13 | .text | ||
14 | |||
15 | /* | ||
16 | * Function: __u32 csum_partial(const char *src, int len, __u32 sum) | ||
17 | * Params : r0 = buffer, r1 = len, r2 = checksum | ||
18 | * Returns : r0 = new checksum | ||
19 | */ | ||
20 | |||
21 | buf .req r0 | ||
22 | len .req r1 | ||
23 | sum .req r2 | ||
24 | td0 .req r3 | ||
25 | td1 .req r4 @ save before use | ||
26 | td2 .req r5 @ save before use | ||
27 | td3 .req lr | ||
28 | |||
29 | .zero: mov r0, sum | ||
30 | add sp, sp, #4 | ||
31 | ldr pc, [sp], #4 | ||
32 | |||
33 | /* | ||
34 | * Handle 0 to 7 bytes, with any alignment of source and | ||
35 | * destination pointers. Note that when we get here, C = 0 | ||
36 | */ | ||
37 | .less8: teq len, #0 @ check for zero count | ||
38 | beq .zero | ||
39 | |||
40 | /* we must have at least one byte. */ | ||
41 | tst buf, #1 @ odd address? | ||
42 | ldrneb td0, [buf], #1 | ||
43 | subne len, len, #1 | ||
44 | adcnes sum, sum, td0, put_byte_1 | ||
45 | |||
46 | .less4: tst len, #6 | ||
47 | beq .less8_byte | ||
48 | |||
49 | /* we are now half-word aligned */ | ||
50 | |||
51 | .less8_wordlp: | ||
52 | #if __LINUX_ARM_ARCH__ >= 4 | ||
53 | ldrh td0, [buf], #2 | ||
54 | sub len, len, #2 | ||
55 | #else | ||
56 | ldrb td0, [buf], #1 | ||
57 | ldrb td3, [buf], #1 | ||
58 | sub len, len, #2 | ||
59 | #ifndef __ARMEB__ | ||
60 | orr td0, td0, td3, lsl #8 | ||
61 | #else | ||
62 | orr td0, td3, td0, lsl #8 | ||
63 | #endif | ||
64 | #endif | ||
65 | adcs sum, sum, td0 | ||
66 | tst len, #6 | ||
67 | bne .less8_wordlp | ||
68 | |||
69 | .less8_byte: tst len, #1 @ odd number of bytes | ||
70 | ldrneb td0, [buf], #1 @ include last byte | ||
71 | adcnes sum, sum, td0, put_byte_0 @ update checksum | ||
72 | |||
73 | .done: adc r0, sum, #0 @ collect up the last carry | ||
74 | ldr td0, [sp], #4 | ||
75 | tst td0, #1 @ check buffer alignment | ||
76 | movne r0, r0, ror #8 @ rotate checksum by 8 bits | ||
77 | ldr pc, [sp], #4 @ return | ||
78 | |||
79 | .not_aligned: tst buf, #1 @ odd address | ||
80 | ldrneb td0, [buf], #1 @ make even | ||
81 | subne len, len, #1 | ||
82 | adcnes sum, sum, td0, put_byte_1 @ update checksum | ||
83 | |||
84 | tst buf, #2 @ 32-bit aligned? | ||
85 | #if __LINUX_ARM_ARCH__ >= 4 | ||
86 | ldrneh td0, [buf], #2 @ make 32-bit aligned | ||
87 | subne len, len, #2 | ||
88 | #else | ||
89 | ldrneb td0, [buf], #1 | ||
90 | ldrneb ip, [buf], #1 | ||
91 | subne len, len, #2 | ||
92 | #ifndef __ARMEB__ | ||
93 | orrne td0, td0, ip, lsl #8 | ||
94 | #else | ||
95 | orrne td0, ip, td0, lsl #8 | ||
96 | #endif | ||
97 | #endif | ||
98 | adcnes sum, sum, td0 @ update checksum | ||
99 | mov pc, lr | ||
100 | |||
101 | ENTRY(csum_partial) | ||
102 | stmfd sp!, {buf, lr} | ||
103 | cmp len, #8 @ Ensure that we have at least | ||
104 | blo .less8 @ 8 bytes to copy. | ||
105 | |||
106 | adds sum, sum, #0 @ C = 0 | ||
107 | tst buf, #3 @ Test destination alignment | ||
108 | blne .not_aligned @ aligh destination, return here | ||
109 | |||
110 | 1: bics ip, len, #31 | ||
111 | beq 3f | ||
112 | |||
113 | stmfd sp!, {r4 - r5} | ||
114 | 2: ldmia buf!, {td0, td1, td2, td3} | ||
115 | adcs sum, sum, td0 | ||
116 | adcs sum, sum, td1 | ||
117 | adcs sum, sum, td2 | ||
118 | adcs sum, sum, td3 | ||
119 | ldmia buf!, {td0, td1, td2, td3} | ||
120 | adcs sum, sum, td0 | ||
121 | adcs sum, sum, td1 | ||
122 | adcs sum, sum, td2 | ||
123 | adcs sum, sum, td3 | ||
124 | sub ip, ip, #32 | ||
125 | teq ip, #0 | ||
126 | bne 2b | ||
127 | ldmfd sp!, {r4 - r5} | ||
128 | |||
129 | 3: tst len, #0x1c @ should not change C | ||
130 | beq .less4 | ||
131 | |||
132 | 4: ldr td0, [buf], #4 | ||
133 | sub len, len, #4 | ||
134 | adcs sum, sum, td0 | ||
135 | tst len, #0x1c | ||
136 | bne 4b | ||
137 | b .less4 | ||