1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * INET An implementation of the TCP/IP protocol suite for the LINUX
4*4882a593Smuzhiyun * operating system. INET is implemented using the BSD Socket
5*4882a593Smuzhiyun * interface as the means of communication with the user level.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * IP/TCP/UDP checksumming routines
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Authors: Jorge Cwik, <jorge@laser.satlink.net>
10*4882a593Smuzhiyun * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
11*4882a593Smuzhiyun * Tom May, <ftom@netcom.com>
12*4882a593Smuzhiyun * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
13*4882a593Smuzhiyun * Lots of code moved from tcp.c and ip.c; see those files
14*4882a593Smuzhiyun * for more names.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek:
17*4882a593Smuzhiyun * Fixed some nasty bugs, causing some horrible crashes.
18*4882a593Smuzhiyun * A: At some points, the sum (%0) was used as
19*4882a593Smuzhiyun * length-counter instead of the length counter
20*4882a593Smuzhiyun * (%1). Thanks to Roman Hodek for pointing this out.
21*4882a593Smuzhiyun * B: GCC seems to mess up if one uses too many
22*4882a593Smuzhiyun * data-registers to hold input values and one tries to
23*4882a593Smuzhiyun * specify d0 and d1 as scratch registers. Letting gcc
24*4882a593Smuzhiyun * choose these registers itself solves the problem.
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * 1998/8/31 Andreas Schwab:
27*4882a593Smuzhiyun * Zero out rest of buffer on exception in
28*4882a593Smuzhiyun * csum_partial_copy_from_user.
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <linux/module.h>
32*4882a593Smuzhiyun #include <net/checksum.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun * computes a partial checksum, e.g. for TCP/UDP fragments
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun
csum_partial(const void * buff,int len,__wsum sum)38*4882a593Smuzhiyun __wsum csum_partial(const void *buff, int len, __wsum sum)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun unsigned long tmp1, tmp2;
41*4882a593Smuzhiyun /*
42*4882a593Smuzhiyun * Experiments with ethernet and slip connections show that buff
43*4882a593Smuzhiyun * is aligned on either a 2-byte or 4-byte boundary.
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun __asm__("movel %2,%3\n\t"
46*4882a593Smuzhiyun "btst #1,%3\n\t" /* Check alignment */
47*4882a593Smuzhiyun "jeq 2f\n\t"
48*4882a593Smuzhiyun "subql #2,%1\n\t" /* buff%4==2: treat first word */
49*4882a593Smuzhiyun "jgt 1f\n\t"
50*4882a593Smuzhiyun "addql #2,%1\n\t" /* len was == 2, treat only rest */
51*4882a593Smuzhiyun "jra 4f\n"
52*4882a593Smuzhiyun "1:\t"
53*4882a593Smuzhiyun "addw %2@+,%0\n\t" /* add first word to sum */
54*4882a593Smuzhiyun "clrl %3\n\t"
55*4882a593Smuzhiyun "addxl %3,%0\n" /* add X bit */
56*4882a593Smuzhiyun "2:\t"
57*4882a593Smuzhiyun /* unrolled loop for the main part: do 8 longs at once */
58*4882a593Smuzhiyun "movel %1,%3\n\t" /* save len in tmp1 */
59*4882a593Smuzhiyun "lsrl #5,%1\n\t" /* len/32 */
60*4882a593Smuzhiyun "jeq 2f\n\t" /* not enough... */
61*4882a593Smuzhiyun "subql #1,%1\n"
62*4882a593Smuzhiyun "1:\t"
63*4882a593Smuzhiyun "movel %2@+,%4\n\t"
64*4882a593Smuzhiyun "addxl %4,%0\n\t"
65*4882a593Smuzhiyun "movel %2@+,%4\n\t"
66*4882a593Smuzhiyun "addxl %4,%0\n\t"
67*4882a593Smuzhiyun "movel %2@+,%4\n\t"
68*4882a593Smuzhiyun "addxl %4,%0\n\t"
69*4882a593Smuzhiyun "movel %2@+,%4\n\t"
70*4882a593Smuzhiyun "addxl %4,%0\n\t"
71*4882a593Smuzhiyun "movel %2@+,%4\n\t"
72*4882a593Smuzhiyun "addxl %4,%0\n\t"
73*4882a593Smuzhiyun "movel %2@+,%4\n\t"
74*4882a593Smuzhiyun "addxl %4,%0\n\t"
75*4882a593Smuzhiyun "movel %2@+,%4\n\t"
76*4882a593Smuzhiyun "addxl %4,%0\n\t"
77*4882a593Smuzhiyun "movel %2@+,%4\n\t"
78*4882a593Smuzhiyun "addxl %4,%0\n\t"
79*4882a593Smuzhiyun "dbra %1,1b\n\t"
80*4882a593Smuzhiyun "clrl %4\n\t"
81*4882a593Smuzhiyun "addxl %4,%0\n\t" /* add X bit */
82*4882a593Smuzhiyun "clrw %1\n\t"
83*4882a593Smuzhiyun "subql #1,%1\n\t"
84*4882a593Smuzhiyun "jcc 1b\n"
85*4882a593Smuzhiyun "2:\t"
86*4882a593Smuzhiyun "movel %3,%1\n\t" /* restore len from tmp1 */
87*4882a593Smuzhiyun "andw #0x1c,%3\n\t" /* number of rest longs */
88*4882a593Smuzhiyun "jeq 4f\n\t"
89*4882a593Smuzhiyun "lsrw #2,%3\n\t"
90*4882a593Smuzhiyun "subqw #1,%3\n"
91*4882a593Smuzhiyun "3:\t"
92*4882a593Smuzhiyun /* loop for rest longs */
93*4882a593Smuzhiyun "movel %2@+,%4\n\t"
94*4882a593Smuzhiyun "addxl %4,%0\n\t"
95*4882a593Smuzhiyun "dbra %3,3b\n\t"
96*4882a593Smuzhiyun "clrl %4\n\t"
97*4882a593Smuzhiyun "addxl %4,%0\n" /* add X bit */
98*4882a593Smuzhiyun "4:\t"
99*4882a593Smuzhiyun /* now check for rest bytes that do not fit into longs */
100*4882a593Smuzhiyun "andw #3,%1\n\t"
101*4882a593Smuzhiyun "jeq 7f\n\t"
102*4882a593Smuzhiyun "clrl %4\n\t" /* clear tmp2 for rest bytes */
103*4882a593Smuzhiyun "subqw #2,%1\n\t"
104*4882a593Smuzhiyun "jlt 5f\n\t"
105*4882a593Smuzhiyun "movew %2@+,%4\n\t" /* have rest >= 2: get word */
106*4882a593Smuzhiyun "swap %4\n\t" /* into bits 16..31 */
107*4882a593Smuzhiyun "tstw %1\n\t" /* another byte? */
108*4882a593Smuzhiyun "jeq 6f\n"
109*4882a593Smuzhiyun "5:\t"
110*4882a593Smuzhiyun "moveb %2@,%4\n\t" /* have odd rest: get byte */
111*4882a593Smuzhiyun "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */
112*4882a593Smuzhiyun "6:\t"
113*4882a593Smuzhiyun "addl %4,%0\n\t" /* now add rest long to sum */
114*4882a593Smuzhiyun "clrl %4\n\t"
115*4882a593Smuzhiyun "addxl %4,%0\n" /* add X bit */
116*4882a593Smuzhiyun "7:\t"
117*4882a593Smuzhiyun : "=d" (sum), "=d" (len), "=a" (buff),
118*4882a593Smuzhiyun "=&d" (tmp1), "=&d" (tmp2)
119*4882a593Smuzhiyun : "0" (sum), "1" (len), "2" (buff)
120*4882a593Smuzhiyun );
121*4882a593Smuzhiyun return(sum);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun EXPORT_SYMBOL(csum_partial);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun * copy from user space while checksumming, with exception handling.
129*4882a593Smuzhiyun */
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun __wsum
csum_and_copy_from_user(const void __user * src,void * dst,int len)132*4882a593Smuzhiyun csum_and_copy_from_user(const void __user *src, void *dst, int len)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun /*
135*4882a593Smuzhiyun * GCC doesn't like more than 10 operands for the asm
136*4882a593Smuzhiyun * statements so we have to use tmp2 for the error
137*4882a593Smuzhiyun * code.
138*4882a593Smuzhiyun */
139*4882a593Smuzhiyun unsigned long tmp1, tmp2;
140*4882a593Smuzhiyun __wsum sum = ~0U;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun __asm__("movel %2,%4\n\t"
143*4882a593Smuzhiyun "btst #1,%4\n\t" /* Check alignment */
144*4882a593Smuzhiyun "jeq 2f\n\t"
145*4882a593Smuzhiyun "subql #2,%1\n\t" /* buff%4==2: treat first word */
146*4882a593Smuzhiyun "jgt 1f\n\t"
147*4882a593Smuzhiyun "addql #2,%1\n\t" /* len was == 2, treat only rest */
148*4882a593Smuzhiyun "jra 4f\n"
149*4882a593Smuzhiyun "1:\n"
150*4882a593Smuzhiyun "10:\t"
151*4882a593Smuzhiyun "movesw %2@+,%4\n\t" /* add first word to sum */
152*4882a593Smuzhiyun "addw %4,%0\n\t"
153*4882a593Smuzhiyun "movew %4,%3@+\n\t"
154*4882a593Smuzhiyun "clrl %4\n\t"
155*4882a593Smuzhiyun "addxl %4,%0\n" /* add X bit */
156*4882a593Smuzhiyun "2:\t"
157*4882a593Smuzhiyun /* unrolled loop for the main part: do 8 longs at once */
158*4882a593Smuzhiyun "movel %1,%4\n\t" /* save len in tmp1 */
159*4882a593Smuzhiyun "lsrl #5,%1\n\t" /* len/32 */
160*4882a593Smuzhiyun "jeq 2f\n\t" /* not enough... */
161*4882a593Smuzhiyun "subql #1,%1\n"
162*4882a593Smuzhiyun "1:\n"
163*4882a593Smuzhiyun "11:\t"
164*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
165*4882a593Smuzhiyun "addxl %5,%0\n\t"
166*4882a593Smuzhiyun "movel %5,%3@+\n\t"
167*4882a593Smuzhiyun "12:\t"
168*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
169*4882a593Smuzhiyun "addxl %5,%0\n\t"
170*4882a593Smuzhiyun "movel %5,%3@+\n\t"
171*4882a593Smuzhiyun "13:\t"
172*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
173*4882a593Smuzhiyun "addxl %5,%0\n\t"
174*4882a593Smuzhiyun "movel %5,%3@+\n\t"
175*4882a593Smuzhiyun "14:\t"
176*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
177*4882a593Smuzhiyun "addxl %5,%0\n\t"
178*4882a593Smuzhiyun "movel %5,%3@+\n\t"
179*4882a593Smuzhiyun "15:\t"
180*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
181*4882a593Smuzhiyun "addxl %5,%0\n\t"
182*4882a593Smuzhiyun "movel %5,%3@+\n\t"
183*4882a593Smuzhiyun "16:\t"
184*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
185*4882a593Smuzhiyun "addxl %5,%0\n\t"
186*4882a593Smuzhiyun "movel %5,%3@+\n\t"
187*4882a593Smuzhiyun "17:\t"
188*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
189*4882a593Smuzhiyun "addxl %5,%0\n\t"
190*4882a593Smuzhiyun "movel %5,%3@+\n\t"
191*4882a593Smuzhiyun "18:\t"
192*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
193*4882a593Smuzhiyun "addxl %5,%0\n\t"
194*4882a593Smuzhiyun "movel %5,%3@+\n\t"
195*4882a593Smuzhiyun "dbra %1,1b\n\t"
196*4882a593Smuzhiyun "clrl %5\n\t"
197*4882a593Smuzhiyun "addxl %5,%0\n\t" /* add X bit */
198*4882a593Smuzhiyun "clrw %1\n\t"
199*4882a593Smuzhiyun "subql #1,%1\n\t"
200*4882a593Smuzhiyun "jcc 1b\n"
201*4882a593Smuzhiyun "2:\t"
202*4882a593Smuzhiyun "movel %4,%1\n\t" /* restore len from tmp1 */
203*4882a593Smuzhiyun "andw #0x1c,%4\n\t" /* number of rest longs */
204*4882a593Smuzhiyun "jeq 4f\n\t"
205*4882a593Smuzhiyun "lsrw #2,%4\n\t"
206*4882a593Smuzhiyun "subqw #1,%4\n"
207*4882a593Smuzhiyun "3:\n"
208*4882a593Smuzhiyun /* loop for rest longs */
209*4882a593Smuzhiyun "19:\t"
210*4882a593Smuzhiyun "movesl %2@+,%5\n\t"
211*4882a593Smuzhiyun "addxl %5,%0\n\t"
212*4882a593Smuzhiyun "movel %5,%3@+\n\t"
213*4882a593Smuzhiyun "dbra %4,3b\n\t"
214*4882a593Smuzhiyun "clrl %5\n\t"
215*4882a593Smuzhiyun "addxl %5,%0\n" /* add X bit */
216*4882a593Smuzhiyun "4:\t"
217*4882a593Smuzhiyun /* now check for rest bytes that do not fit into longs */
218*4882a593Smuzhiyun "andw #3,%1\n\t"
219*4882a593Smuzhiyun "jeq 7f\n\t"
220*4882a593Smuzhiyun "clrl %5\n\t" /* clear tmp2 for rest bytes */
221*4882a593Smuzhiyun "subqw #2,%1\n\t"
222*4882a593Smuzhiyun "jlt 5f\n\t"
223*4882a593Smuzhiyun "20:\t"
224*4882a593Smuzhiyun "movesw %2@+,%5\n\t" /* have rest >= 2: get word */
225*4882a593Smuzhiyun "movew %5,%3@+\n\t"
226*4882a593Smuzhiyun "swap %5\n\t" /* into bits 16..31 */
227*4882a593Smuzhiyun "tstw %1\n\t" /* another byte? */
228*4882a593Smuzhiyun "jeq 6f\n"
229*4882a593Smuzhiyun "5:\n"
230*4882a593Smuzhiyun "21:\t"
231*4882a593Smuzhiyun "movesb %2@,%5\n\t" /* have odd rest: get byte */
232*4882a593Smuzhiyun "moveb %5,%3@+\n\t"
233*4882a593Smuzhiyun "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */
234*4882a593Smuzhiyun "6:\t"
235*4882a593Smuzhiyun "addl %5,%0\n\t" /* now add rest long to sum */
236*4882a593Smuzhiyun "clrl %5\n\t"
237*4882a593Smuzhiyun "addxl %5,%0\n\t" /* add X bit */
238*4882a593Smuzhiyun "7:\t"
239*4882a593Smuzhiyun ".section .fixup,\"ax\"\n"
240*4882a593Smuzhiyun ".even\n"
241*4882a593Smuzhiyun /* If any exception occurs, return 0 */
242*4882a593Smuzhiyun "90:\t"
243*4882a593Smuzhiyun "clrl %0\n"
244*4882a593Smuzhiyun "jra 7b\n"
245*4882a593Smuzhiyun ".previous\n"
246*4882a593Smuzhiyun ".section __ex_table,\"a\"\n"
247*4882a593Smuzhiyun ".long 10b,90b\n"
248*4882a593Smuzhiyun ".long 11b,90b\n"
249*4882a593Smuzhiyun ".long 12b,90b\n"
250*4882a593Smuzhiyun ".long 13b,90b\n"
251*4882a593Smuzhiyun ".long 14b,90b\n"
252*4882a593Smuzhiyun ".long 15b,90b\n"
253*4882a593Smuzhiyun ".long 16b,90b\n"
254*4882a593Smuzhiyun ".long 17b,90b\n"
255*4882a593Smuzhiyun ".long 18b,90b\n"
256*4882a593Smuzhiyun ".long 19b,90b\n"
257*4882a593Smuzhiyun ".long 20b,90b\n"
258*4882a593Smuzhiyun ".long 21b,90b\n"
259*4882a593Smuzhiyun ".previous"
260*4882a593Smuzhiyun : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
261*4882a593Smuzhiyun "=&d" (tmp1), "=d" (tmp2)
262*4882a593Smuzhiyun : "0" (sum), "1" (len), "2" (src), "3" (dst)
263*4882a593Smuzhiyun );
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun return sum;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun EXPORT_SYMBOL(csum_and_copy_from_user);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /*
272*4882a593Smuzhiyun * copy from kernel space while checksumming, otherwise like csum_partial
273*4882a593Smuzhiyun */
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun __wsum
csum_partial_copy_nocheck(const void * src,void * dst,int len)276*4882a593Smuzhiyun csum_partial_copy_nocheck(const void *src, void *dst, int len)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun unsigned long tmp1, tmp2;
279*4882a593Smuzhiyun __wsum sum = 0;
280*4882a593Smuzhiyun __asm__("movel %2,%4\n\t"
281*4882a593Smuzhiyun "btst #1,%4\n\t" /* Check alignment */
282*4882a593Smuzhiyun "jeq 2f\n\t"
283*4882a593Smuzhiyun "subql #2,%1\n\t" /* buff%4==2: treat first word */
284*4882a593Smuzhiyun "jgt 1f\n\t"
285*4882a593Smuzhiyun "addql #2,%1\n\t" /* len was == 2, treat only rest */
286*4882a593Smuzhiyun "jra 4f\n"
287*4882a593Smuzhiyun "1:\t"
288*4882a593Smuzhiyun "movew %2@+,%4\n\t" /* add first word to sum */
289*4882a593Smuzhiyun "addw %4,%0\n\t"
290*4882a593Smuzhiyun "movew %4,%3@+\n\t"
291*4882a593Smuzhiyun "clrl %4\n\t"
292*4882a593Smuzhiyun "addxl %4,%0\n" /* add X bit */
293*4882a593Smuzhiyun "2:\t"
294*4882a593Smuzhiyun /* unrolled loop for the main part: do 8 longs at once */
295*4882a593Smuzhiyun "movel %1,%4\n\t" /* save len in tmp1 */
296*4882a593Smuzhiyun "lsrl #5,%1\n\t" /* len/32 */
297*4882a593Smuzhiyun "jeq 2f\n\t" /* not enough... */
298*4882a593Smuzhiyun "subql #1,%1\n"
299*4882a593Smuzhiyun "1:\t"
300*4882a593Smuzhiyun "movel %2@+,%5\n\t"
301*4882a593Smuzhiyun "addxl %5,%0\n\t"
302*4882a593Smuzhiyun "movel %5,%3@+\n\t"
303*4882a593Smuzhiyun "movel %2@+,%5\n\t"
304*4882a593Smuzhiyun "addxl %5,%0\n\t"
305*4882a593Smuzhiyun "movel %5,%3@+\n\t"
306*4882a593Smuzhiyun "movel %2@+,%5\n\t"
307*4882a593Smuzhiyun "addxl %5,%0\n\t"
308*4882a593Smuzhiyun "movel %5,%3@+\n\t"
309*4882a593Smuzhiyun "movel %2@+,%5\n\t"
310*4882a593Smuzhiyun "addxl %5,%0\n\t"
311*4882a593Smuzhiyun "movel %5,%3@+\n\t"
312*4882a593Smuzhiyun "movel %2@+,%5\n\t"
313*4882a593Smuzhiyun "addxl %5,%0\n\t"
314*4882a593Smuzhiyun "movel %5,%3@+\n\t"
315*4882a593Smuzhiyun "movel %2@+,%5\n\t"
316*4882a593Smuzhiyun "addxl %5,%0\n\t"
317*4882a593Smuzhiyun "movel %5,%3@+\n\t"
318*4882a593Smuzhiyun "movel %2@+,%5\n\t"
319*4882a593Smuzhiyun "addxl %5,%0\n\t"
320*4882a593Smuzhiyun "movel %5,%3@+\n\t"
321*4882a593Smuzhiyun "movel %2@+,%5\n\t"
322*4882a593Smuzhiyun "addxl %5,%0\n\t"
323*4882a593Smuzhiyun "movel %5,%3@+\n\t"
324*4882a593Smuzhiyun "dbra %1,1b\n\t"
325*4882a593Smuzhiyun "clrl %5\n\t"
326*4882a593Smuzhiyun "addxl %5,%0\n\t" /* add X bit */
327*4882a593Smuzhiyun "clrw %1\n\t"
328*4882a593Smuzhiyun "subql #1,%1\n\t"
329*4882a593Smuzhiyun "jcc 1b\n"
330*4882a593Smuzhiyun "2:\t"
331*4882a593Smuzhiyun "movel %4,%1\n\t" /* restore len from tmp1 */
332*4882a593Smuzhiyun "andw #0x1c,%4\n\t" /* number of rest longs */
333*4882a593Smuzhiyun "jeq 4f\n\t"
334*4882a593Smuzhiyun "lsrw #2,%4\n\t"
335*4882a593Smuzhiyun "subqw #1,%4\n"
336*4882a593Smuzhiyun "3:\t"
337*4882a593Smuzhiyun /* loop for rest longs */
338*4882a593Smuzhiyun "movel %2@+,%5\n\t"
339*4882a593Smuzhiyun "addxl %5,%0\n\t"
340*4882a593Smuzhiyun "movel %5,%3@+\n\t"
341*4882a593Smuzhiyun "dbra %4,3b\n\t"
342*4882a593Smuzhiyun "clrl %5\n\t"
343*4882a593Smuzhiyun "addxl %5,%0\n" /* add X bit */
344*4882a593Smuzhiyun "4:\t"
345*4882a593Smuzhiyun /* now check for rest bytes that do not fit into longs */
346*4882a593Smuzhiyun "andw #3,%1\n\t"
347*4882a593Smuzhiyun "jeq 7f\n\t"
348*4882a593Smuzhiyun "clrl %5\n\t" /* clear tmp2 for rest bytes */
349*4882a593Smuzhiyun "subqw #2,%1\n\t"
350*4882a593Smuzhiyun "jlt 5f\n\t"
351*4882a593Smuzhiyun "movew %2@+,%5\n\t" /* have rest >= 2: get word */
352*4882a593Smuzhiyun "movew %5,%3@+\n\t"
353*4882a593Smuzhiyun "swap %5\n\t" /* into bits 16..31 */
354*4882a593Smuzhiyun "tstw %1\n\t" /* another byte? */
355*4882a593Smuzhiyun "jeq 6f\n"
356*4882a593Smuzhiyun "5:\t"
357*4882a593Smuzhiyun "moveb %2@,%5\n\t" /* have odd rest: get byte */
358*4882a593Smuzhiyun "moveb %5,%3@+\n\t"
359*4882a593Smuzhiyun "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */
360*4882a593Smuzhiyun "6:\t"
361*4882a593Smuzhiyun "addl %5,%0\n\t" /* now add rest long to sum */
362*4882a593Smuzhiyun "clrl %5\n\t"
363*4882a593Smuzhiyun "addxl %5,%0\n" /* add X bit */
364*4882a593Smuzhiyun "7:\t"
365*4882a593Smuzhiyun : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
366*4882a593Smuzhiyun "=&d" (tmp1), "=&d" (tmp2)
367*4882a593Smuzhiyun : "0" (sum), "1" (len), "2" (src), "3" (dst)
368*4882a593Smuzhiyun );
369*4882a593Smuzhiyun return(sum);
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun EXPORT_SYMBOL(csum_partial_copy_nocheck);
372