xref: /OK3568_Linux_fs/kernel/arch/m68k/lib/checksum.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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