[MIPS] Optimize csum_partial for 64bit kernel
[linux-2.6] / arch / mips / lib / csum_partial.S
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Quick'n'dirty IP checksum ...
7  *
8  * Copyright (C) 1998, 1999 Ralf Baechle
9  * Copyright (C) 1999 Silicon Graphics, Inc.
10  */
11 #include <asm/asm.h>
12 #include <asm/regdef.h>
13
14 #ifdef CONFIG_64BIT
15 /*
16  * As we are sharing code base with the mips32 tree (which use the o32 ABI
17  * register definitions). We need to redefine the register definitions from
18  * the n64 ABI register naming to the o32 ABI register naming.
19  */
20 #undef t0
21 #undef t1
22 #undef t2
23 #undef t3
24 #define t0      $8
25 #define t1      $9
26 #define t2      $10
27 #define t3      $11
28 #define t4      $12
29 #define t5      $13
30 #define t6      $14
31 #define t7      $15
32
33 #define USE_DOUBLE
34 #endif
35
36 #ifdef USE_DOUBLE
37
38 #define LOAD   ld
39 #define ADD    daddu
40 #define NBYTES 8
41
42 #else
43
44 #define LOAD   lw
45 #define ADD    addu
46 #define NBYTES 4
47
48 #endif /* USE_DOUBLE */
49
50 #define UNIT(unit)  ((unit)*NBYTES)
51
52 #define ADDC(sum,reg)                                           \
53         ADD     sum, reg;                                       \
54         sltu    v1, sum, reg;                                   \
55         ADD     sum, v1
56
57 #define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3)    \
58         LOAD    _t0, (offset + UNIT(0))(src);                   \
59         LOAD    _t1, (offset + UNIT(1))(src);                   \
60         LOAD    _t2, (offset + UNIT(2))(src);                   \
61         LOAD    _t3, (offset + UNIT(3))(src);                   \
62         ADDC(sum, _t0);                                         \
63         ADDC(sum, _t1);                                         \
64         ADDC(sum, _t2);                                         \
65         ADDC(sum, _t3)
66
67 #ifdef USE_DOUBLE
68 #define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3)     \
69         CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3)
70 #else
71 #define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3)     \
72         CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3);   \
73         CSUM_BIGCHUNK1(src, offset + 0x10, sum, _t0, _t1, _t2, _t3)
74 #endif
75
76 /*
77  * a0: source address
78  * a1: length of the area to checksum
79  * a2: partial checksum
80  */
81
82 #define src a0
83 #define sum v0
84
85         .text
86         .set    noreorder
87         .align  5
88 LEAF(csum_partial)
89         move    sum, zero
90         move    t7, zero
91
92         sltiu   t8, a1, 0x8
93         bnez    t8, small_csumcpy               /* < 8 bytes to copy */
94          move   t2, a1
95
96         andi    t7, src, 0x1                    /* odd buffer? */
97
98 hword_align:
99         beqz    t7, word_align
100          andi   t8, src, 0x2
101
102         lbu     t0, (src)
103         LONG_SUBU       a1, a1, 0x1
104 #ifdef __MIPSEL__
105         sll     t0, t0, 8
106 #endif
107         ADDC(sum, t0)
108         PTR_ADDU        src, src, 0x1
109         andi    t8, src, 0x2
110
111 word_align:
112         beqz    t8, dword_align
113          sltiu  t8, a1, 56
114
115         lhu     t0, (src)
116         LONG_SUBU       a1, a1, 0x2
117         ADDC(sum, t0)
118         sltiu   t8, a1, 56
119         PTR_ADDU        src, src, 0x2
120
121 dword_align:
122         bnez    t8, do_end_words
123          move   t8, a1
124
125         andi    t8, src, 0x4
126         beqz    t8, qword_align
127          andi   t8, src, 0x8
128
129         lw      t0, 0x00(src)
130         LONG_SUBU       a1, a1, 0x4
131         ADDC(sum, t0)
132         PTR_ADDU        src, src, 0x4
133         andi    t8, src, 0x8
134
135 qword_align:
136         beqz    t8, oword_align
137          andi   t8, src, 0x10
138
139 #ifdef USE_DOUBLE
140         ld      t0, 0x00(src)
141         LONG_SUBU       a1, a1, 0x8
142         ADDC(sum, t0)
143 #else
144         lw      t0, 0x00(src)
145         lw      t1, 0x04(src)
146         LONG_SUBU       a1, a1, 0x8
147         ADDC(sum, t0)
148         ADDC(sum, t1)
149 #endif
150         PTR_ADDU        src, src, 0x8
151         andi    t8, src, 0x10
152
153 oword_align:
154         beqz    t8, begin_movement
155          LONG_SRL       t8, a1, 0x7
156
157 #ifdef USE_DOUBLE
158         ld      t0, 0x00(src)
159         ld      t1, 0x08(src)
160         ADDC(sum, t0)
161         ADDC(sum, t1)
162 #else
163         CSUM_BIGCHUNK1(src, 0x00, sum, t0, t1, t3, t4)
164 #endif
165         LONG_SUBU       a1, a1, 0x10
166         PTR_ADDU        src, src, 0x10
167         LONG_SRL        t8, a1, 0x7
168
169 begin_movement:
170         beqz    t8, 1f
171          andi   t2, a1, 0x40
172
173 move_128bytes:
174         CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
175         CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4)
176         CSUM_BIGCHUNK(src, 0x40, sum, t0, t1, t3, t4)
177         CSUM_BIGCHUNK(src, 0x60, sum, t0, t1, t3, t4)
178         LONG_SUBU       t8, t8, 0x01
179         bnez    t8, move_128bytes
180          PTR_ADDU       src, src, 0x80
181
182 1:
183         beqz    t2, 1f
184          andi   t2, a1, 0x20
185
186 move_64bytes:
187         CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
188         CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4)
189         PTR_ADDU        src, src, 0x40
190
191 1:
192         beqz    t2, do_end_words
193          andi   t8, a1, 0x1c
194
195 move_32bytes:
196         CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
197         andi    t8, a1, 0x1c
198         PTR_ADDU        src, src, 0x20
199
200 do_end_words:
201         beqz    t8, small_csumcpy
202          andi   t2, a1, 0x3
203         LONG_SRL        t8, t8, 0x2
204
205 end_words:
206         lw      t0, (src)
207         LONG_SUBU       t8, t8, 0x1
208         ADDC(sum, t0)
209         bnez    t8, end_words
210          PTR_ADDU       src, src, 0x4
211
212 /* unknown src alignment and < 8 bytes to go  */
213 small_csumcpy:
214         move    a1, t2
215
216         andi    t0, a1, 4
217         beqz    t0, 1f
218          andi   t0, a1, 2
219
220         /* Still a full word to go  */
221         ulw     t1, (src)
222         PTR_ADDIU       src, 4
223         ADDC(sum, t1)
224
225 1:      move    t1, zero
226         beqz    t0, 1f
227          andi   t0, a1, 1
228
229         /* Still a halfword to go  */
230         ulhu    t1, (src)
231         PTR_ADDIU       src, 2
232
233 1:      beqz    t0, 1f
234          sll    t1, t1, 16
235
236         lbu     t2, (src)
237          nop
238
239 #ifdef __MIPSEB__
240         sll     t2, t2, 8
241 #endif
242         or      t1, t2
243
244 1:      ADDC(sum, t1)
245
246         /* fold checksum */
247 #ifdef USE_DOUBLE
248         dsll32  v1, sum, 0
249         daddu   sum, v1
250         sltu    v1, sum, v1
251         dsra32  sum, sum, 0
252         addu    sum, v1
253 #endif
254         sll     v1, sum, 16
255         addu    sum, v1
256         sltu    v1, sum, v1
257         srl     sum, sum, 16
258         addu    sum, v1
259
260         /* odd buffer alignment? */
261         beqz    t7, 1f
262          nop
263         sll     v1, sum, 8
264         srl     sum, sum, 8
265         or      sum, v1
266         andi    sum, 0xffff
267 1:
268         .set    reorder
269         /* Add the passed partial csum.  */
270         ADDC(sum, a2)
271         jr      ra
272         .set    noreorder
273         END(csum_partial)