xref: /kernel/linux/linux-6.6/arch/m68k/lib/checksum.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * INET		An implementation of the TCP/IP protocol suite for the LINUX
462306a36Sopenharmony_ci *		operating system.  INET is implemented using the  BSD Socket
562306a36Sopenharmony_ci *		interface as the means of communication with the user level.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *		IP/TCP/UDP checksumming routines
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
1062306a36Sopenharmony_ci *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
1162306a36Sopenharmony_ci *		Tom May, <ftom@netcom.com>
1262306a36Sopenharmony_ci *		Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
1362306a36Sopenharmony_ci *		Lots of code moved from tcp.c and ip.c; see those files
1462306a36Sopenharmony_ci *		for more names.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * 03/02/96	Jes Sorensen, Andreas Schwab, Roman Hodek:
1762306a36Sopenharmony_ci *		Fixed some nasty bugs, causing some horrible crashes.
1862306a36Sopenharmony_ci *		A: At some points, the sum (%0) was used as
1962306a36Sopenharmony_ci *		length-counter instead of the length counter
2062306a36Sopenharmony_ci *		(%1). Thanks to Roman Hodek for pointing this out.
2162306a36Sopenharmony_ci *		B: GCC seems to mess up if one uses too many
2262306a36Sopenharmony_ci *		data-registers to hold input values and one tries to
2362306a36Sopenharmony_ci *		specify d0 and d1 as scratch registers. Letting gcc
2462306a36Sopenharmony_ci *		choose these registers itself solves the problem.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * 1998/8/31	Andreas Schwab:
2762306a36Sopenharmony_ci *		Zero out rest of buffer on exception in
2862306a36Sopenharmony_ci *		csum_partial_copy_from_user.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <linux/module.h>
3262306a36Sopenharmony_ci#include <net/checksum.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * computes a partial checksum, e.g. for TCP/UDP fragments
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci__wsum csum_partial(const void *buff, int len, __wsum sum)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	unsigned long tmp1, tmp2;
4162306a36Sopenharmony_ci	  /*
4262306a36Sopenharmony_ci	   * Experiments with ethernet and slip connections show that buff
4362306a36Sopenharmony_ci	   * is aligned on either a 2-byte or 4-byte boundary.
4462306a36Sopenharmony_ci	   */
4562306a36Sopenharmony_ci	__asm__("movel %2,%3\n\t"
4662306a36Sopenharmony_ci		"btst #1,%3\n\t"	/* Check alignment */
4762306a36Sopenharmony_ci		"jeq 2f\n\t"
4862306a36Sopenharmony_ci		"subql #2,%1\n\t"	/* buff%4==2: treat first word */
4962306a36Sopenharmony_ci		"jgt 1f\n\t"
5062306a36Sopenharmony_ci		"addql #2,%1\n\t"	/* len was == 2, treat only rest */
5162306a36Sopenharmony_ci		"jra 4f\n"
5262306a36Sopenharmony_ci	     "1:\t"
5362306a36Sopenharmony_ci		"addw %2@+,%0\n\t"	/* add first word to sum */
5462306a36Sopenharmony_ci		"clrl %3\n\t"
5562306a36Sopenharmony_ci		"addxl %3,%0\n"		/* add X bit */
5662306a36Sopenharmony_ci	     "2:\t"
5762306a36Sopenharmony_ci		/* unrolled loop for the main part: do 8 longs at once */
5862306a36Sopenharmony_ci		"movel %1,%3\n\t"	/* save len in tmp1 */
5962306a36Sopenharmony_ci		"lsrl #5,%1\n\t"	/* len/32 */
6062306a36Sopenharmony_ci		"jeq 2f\n\t"		/* not enough... */
6162306a36Sopenharmony_ci		"subql #1,%1\n"
6262306a36Sopenharmony_ci	     "1:\t"
6362306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
6462306a36Sopenharmony_ci		"addxl %4,%0\n\t"
6562306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
6662306a36Sopenharmony_ci		"addxl %4,%0\n\t"
6762306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
6862306a36Sopenharmony_ci		"addxl %4,%0\n\t"
6962306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
7062306a36Sopenharmony_ci		"addxl %4,%0\n\t"
7162306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
7262306a36Sopenharmony_ci		"addxl %4,%0\n\t"
7362306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
7462306a36Sopenharmony_ci		"addxl %4,%0\n\t"
7562306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
7662306a36Sopenharmony_ci		"addxl %4,%0\n\t"
7762306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
7862306a36Sopenharmony_ci		"addxl %4,%0\n\t"
7962306a36Sopenharmony_ci		"dbra %1,1b\n\t"
8062306a36Sopenharmony_ci		"clrl %4\n\t"
8162306a36Sopenharmony_ci		"addxl %4,%0\n\t"	/* add X bit */
8262306a36Sopenharmony_ci		"clrw %1\n\t"
8362306a36Sopenharmony_ci		"subql #1,%1\n\t"
8462306a36Sopenharmony_ci		"jcc 1b\n"
8562306a36Sopenharmony_ci	     "2:\t"
8662306a36Sopenharmony_ci		"movel %3,%1\n\t"	/* restore len from tmp1 */
8762306a36Sopenharmony_ci		"andw #0x1c,%3\n\t"	/* number of rest longs */
8862306a36Sopenharmony_ci		"jeq 4f\n\t"
8962306a36Sopenharmony_ci		"lsrw #2,%3\n\t"
9062306a36Sopenharmony_ci		"subqw #1,%3\n"
9162306a36Sopenharmony_ci	     "3:\t"
9262306a36Sopenharmony_ci		/* loop for rest longs */
9362306a36Sopenharmony_ci		"movel %2@+,%4\n\t"
9462306a36Sopenharmony_ci		"addxl %4,%0\n\t"
9562306a36Sopenharmony_ci		"dbra %3,3b\n\t"
9662306a36Sopenharmony_ci		"clrl %4\n\t"
9762306a36Sopenharmony_ci		"addxl %4,%0\n"		/* add X bit */
9862306a36Sopenharmony_ci	     "4:\t"
9962306a36Sopenharmony_ci		/* now check for rest bytes that do not fit into longs */
10062306a36Sopenharmony_ci		"andw #3,%1\n\t"
10162306a36Sopenharmony_ci		"jeq 7f\n\t"
10262306a36Sopenharmony_ci		"clrl %4\n\t"		/* clear tmp2 for rest bytes */
10362306a36Sopenharmony_ci		"subqw #2,%1\n\t"
10462306a36Sopenharmony_ci		"jlt 5f\n\t"
10562306a36Sopenharmony_ci		"movew %2@+,%4\n\t"	/* have rest >= 2: get word */
10662306a36Sopenharmony_ci		"swap %4\n\t"		/* into bits 16..31 */
10762306a36Sopenharmony_ci		"tstw %1\n\t"		/* another byte? */
10862306a36Sopenharmony_ci		"jeq 6f\n"
10962306a36Sopenharmony_ci	     "5:\t"
11062306a36Sopenharmony_ci		"moveb %2@,%4\n\t"	/* have odd rest: get byte */
11162306a36Sopenharmony_ci		"lslw #8,%4\n\t"	/* into bits 8..15; 16..31 untouched */
11262306a36Sopenharmony_ci	     "6:\t"
11362306a36Sopenharmony_ci		"addl %4,%0\n\t"	/* now add rest long to sum */
11462306a36Sopenharmony_ci		"clrl %4\n\t"
11562306a36Sopenharmony_ci		"addxl %4,%0\n"		/* add X bit */
11662306a36Sopenharmony_ci	     "7:\t"
11762306a36Sopenharmony_ci		: "=d" (sum), "=d" (len), "=a" (buff),
11862306a36Sopenharmony_ci		  "=&d" (tmp1), "=&d" (tmp2)
11962306a36Sopenharmony_ci		: "0" (sum), "1" (len), "2" (buff)
12062306a36Sopenharmony_ci	    );
12162306a36Sopenharmony_ci	return(sum);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciEXPORT_SYMBOL(csum_partial);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/*
12862306a36Sopenharmony_ci * copy from user space while checksumming, with exception handling.
12962306a36Sopenharmony_ci */
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci__wsum
13262306a36Sopenharmony_cicsum_and_copy_from_user(const void __user *src, void *dst, int len)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	/*
13562306a36Sopenharmony_ci	 * GCC doesn't like more than 10 operands for the asm
13662306a36Sopenharmony_ci	 * statements so we have to use tmp2 for the error
13762306a36Sopenharmony_ci	 * code.
13862306a36Sopenharmony_ci	 */
13962306a36Sopenharmony_ci	unsigned long tmp1, tmp2;
14062306a36Sopenharmony_ci	__wsum sum = ~0U;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	__asm__("movel %2,%4\n\t"
14362306a36Sopenharmony_ci		"btst #1,%4\n\t"	/* Check alignment */
14462306a36Sopenharmony_ci		"jeq 2f\n\t"
14562306a36Sopenharmony_ci		"subql #2,%1\n\t"	/* buff%4==2: treat first word */
14662306a36Sopenharmony_ci		"jgt 1f\n\t"
14762306a36Sopenharmony_ci		"addql #2,%1\n\t"	/* len was == 2, treat only rest */
14862306a36Sopenharmony_ci		"jra 4f\n"
14962306a36Sopenharmony_ci	     "1:\n"
15062306a36Sopenharmony_ci	     "10:\t"
15162306a36Sopenharmony_ci		"movesw %2@+,%4\n\t"	/* add first word to sum */
15262306a36Sopenharmony_ci		"addw %4,%0\n\t"
15362306a36Sopenharmony_ci		"movew %4,%3@+\n\t"
15462306a36Sopenharmony_ci		"clrl %4\n\t"
15562306a36Sopenharmony_ci		"addxl %4,%0\n"		/* add X bit */
15662306a36Sopenharmony_ci	     "2:\t"
15762306a36Sopenharmony_ci		/* unrolled loop for the main part: do 8 longs at once */
15862306a36Sopenharmony_ci		"movel %1,%4\n\t"	/* save len in tmp1 */
15962306a36Sopenharmony_ci		"lsrl #5,%1\n\t"	/* len/32 */
16062306a36Sopenharmony_ci		"jeq 2f\n\t"		/* not enough... */
16162306a36Sopenharmony_ci		"subql #1,%1\n"
16262306a36Sopenharmony_ci	     "1:\n"
16362306a36Sopenharmony_ci	     "11:\t"
16462306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
16562306a36Sopenharmony_ci		"addxl %5,%0\n\t"
16662306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
16762306a36Sopenharmony_ci	     "12:\t"
16862306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
16962306a36Sopenharmony_ci		"addxl %5,%0\n\t"
17062306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
17162306a36Sopenharmony_ci	     "13:\t"
17262306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
17362306a36Sopenharmony_ci		"addxl %5,%0\n\t"
17462306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
17562306a36Sopenharmony_ci	     "14:\t"
17662306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
17762306a36Sopenharmony_ci		"addxl %5,%0\n\t"
17862306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
17962306a36Sopenharmony_ci	     "15:\t"
18062306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
18162306a36Sopenharmony_ci		"addxl %5,%0\n\t"
18262306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
18362306a36Sopenharmony_ci	     "16:\t"
18462306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
18562306a36Sopenharmony_ci		"addxl %5,%0\n\t"
18662306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
18762306a36Sopenharmony_ci	     "17:\t"
18862306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
18962306a36Sopenharmony_ci		"addxl %5,%0\n\t"
19062306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
19162306a36Sopenharmony_ci	     "18:\t"
19262306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
19362306a36Sopenharmony_ci		"addxl %5,%0\n\t"
19462306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
19562306a36Sopenharmony_ci		"dbra %1,1b\n\t"
19662306a36Sopenharmony_ci		"clrl %5\n\t"
19762306a36Sopenharmony_ci		"addxl %5,%0\n\t"	/* add X bit */
19862306a36Sopenharmony_ci		"clrw %1\n\t"
19962306a36Sopenharmony_ci		"subql #1,%1\n\t"
20062306a36Sopenharmony_ci		"jcc 1b\n"
20162306a36Sopenharmony_ci	     "2:\t"
20262306a36Sopenharmony_ci		"movel %4,%1\n\t"	/* restore len from tmp1 */
20362306a36Sopenharmony_ci		"andw #0x1c,%4\n\t"	/* number of rest longs */
20462306a36Sopenharmony_ci		"jeq 4f\n\t"
20562306a36Sopenharmony_ci		"lsrw #2,%4\n\t"
20662306a36Sopenharmony_ci		"subqw #1,%4\n"
20762306a36Sopenharmony_ci	     "3:\n"
20862306a36Sopenharmony_ci		/* loop for rest longs */
20962306a36Sopenharmony_ci	     "19:\t"
21062306a36Sopenharmony_ci		"movesl %2@+,%5\n\t"
21162306a36Sopenharmony_ci		"addxl %5,%0\n\t"
21262306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
21362306a36Sopenharmony_ci		"dbra %4,3b\n\t"
21462306a36Sopenharmony_ci		"clrl %5\n\t"
21562306a36Sopenharmony_ci		"addxl %5,%0\n"		/* add X bit */
21662306a36Sopenharmony_ci	     "4:\t"
21762306a36Sopenharmony_ci		/* now check for rest bytes that do not fit into longs */
21862306a36Sopenharmony_ci		"andw #3,%1\n\t"
21962306a36Sopenharmony_ci		"jeq 7f\n\t"
22062306a36Sopenharmony_ci		"clrl %5\n\t"		/* clear tmp2 for rest bytes */
22162306a36Sopenharmony_ci		"subqw #2,%1\n\t"
22262306a36Sopenharmony_ci		"jlt 5f\n\t"
22362306a36Sopenharmony_ci	     "20:\t"
22462306a36Sopenharmony_ci		"movesw %2@+,%5\n\t"	/* have rest >= 2: get word */
22562306a36Sopenharmony_ci		"movew %5,%3@+\n\t"
22662306a36Sopenharmony_ci		"swap %5\n\t"		/* into bits 16..31 */
22762306a36Sopenharmony_ci		"tstw %1\n\t"		/* another byte? */
22862306a36Sopenharmony_ci		"jeq 6f\n"
22962306a36Sopenharmony_ci	     "5:\n"
23062306a36Sopenharmony_ci	     "21:\t"
23162306a36Sopenharmony_ci		"movesb %2@,%5\n\t"	/* have odd rest: get byte */
23262306a36Sopenharmony_ci		"moveb %5,%3@+\n\t"
23362306a36Sopenharmony_ci		"lslw #8,%5\n\t"	/* into bits 8..15; 16..31 untouched */
23462306a36Sopenharmony_ci	     "6:\t"
23562306a36Sopenharmony_ci		"addl %5,%0\n\t"	/* now add rest long to sum */
23662306a36Sopenharmony_ci		"clrl %5\n\t"
23762306a36Sopenharmony_ci		"addxl %5,%0\n\t"	/* add X bit */
23862306a36Sopenharmony_ci	     "7:\t"
23962306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"
24062306a36Sopenharmony_ci		".even\n"
24162306a36Sopenharmony_ci		/* If any exception occurs, return 0 */
24262306a36Sopenharmony_ci	     "90:\t"
24362306a36Sopenharmony_ci		"clrl %0\n"
24462306a36Sopenharmony_ci		"jra 7b\n"
24562306a36Sopenharmony_ci		".previous\n"
24662306a36Sopenharmony_ci		".section __ex_table,\"a\"\n"
24762306a36Sopenharmony_ci		".long 10b,90b\n"
24862306a36Sopenharmony_ci		".long 11b,90b\n"
24962306a36Sopenharmony_ci		".long 12b,90b\n"
25062306a36Sopenharmony_ci		".long 13b,90b\n"
25162306a36Sopenharmony_ci		".long 14b,90b\n"
25262306a36Sopenharmony_ci		".long 15b,90b\n"
25362306a36Sopenharmony_ci		".long 16b,90b\n"
25462306a36Sopenharmony_ci		".long 17b,90b\n"
25562306a36Sopenharmony_ci		".long 18b,90b\n"
25662306a36Sopenharmony_ci		".long 19b,90b\n"
25762306a36Sopenharmony_ci		".long 20b,90b\n"
25862306a36Sopenharmony_ci		".long 21b,90b\n"
25962306a36Sopenharmony_ci		".previous"
26062306a36Sopenharmony_ci		: "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
26162306a36Sopenharmony_ci		  "=&d" (tmp1), "=d" (tmp2)
26262306a36Sopenharmony_ci		: "0" (sum), "1" (len), "2" (src), "3" (dst)
26362306a36Sopenharmony_ci	    );
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return sum;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/*
27062306a36Sopenharmony_ci * copy from kernel space while checksumming, otherwise like csum_partial
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci__wsum
27462306a36Sopenharmony_cicsum_partial_copy_nocheck(const void *src, void *dst, int len)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	unsigned long tmp1, tmp2;
27762306a36Sopenharmony_ci	__wsum sum = 0;
27862306a36Sopenharmony_ci	__asm__("movel %2,%4\n\t"
27962306a36Sopenharmony_ci		"btst #1,%4\n\t"	/* Check alignment */
28062306a36Sopenharmony_ci		"jeq 2f\n\t"
28162306a36Sopenharmony_ci		"subql #2,%1\n\t"	/* buff%4==2: treat first word */
28262306a36Sopenharmony_ci		"jgt 1f\n\t"
28362306a36Sopenharmony_ci		"addql #2,%1\n\t"	/* len was == 2, treat only rest */
28462306a36Sopenharmony_ci		"jra 4f\n"
28562306a36Sopenharmony_ci	     "1:\t"
28662306a36Sopenharmony_ci		"movew %2@+,%4\n\t"	/* add first word to sum */
28762306a36Sopenharmony_ci		"addw %4,%0\n\t"
28862306a36Sopenharmony_ci		"movew %4,%3@+\n\t"
28962306a36Sopenharmony_ci		"clrl %4\n\t"
29062306a36Sopenharmony_ci		"addxl %4,%0\n"		/* add X bit */
29162306a36Sopenharmony_ci	     "2:\t"
29262306a36Sopenharmony_ci		/* unrolled loop for the main part: do 8 longs at once */
29362306a36Sopenharmony_ci		"movel %1,%4\n\t"	/* save len in tmp1 */
29462306a36Sopenharmony_ci		"lsrl #5,%1\n\t"	/* len/32 */
29562306a36Sopenharmony_ci		"jeq 2f\n\t"		/* not enough... */
29662306a36Sopenharmony_ci		"subql #1,%1\n"
29762306a36Sopenharmony_ci	     "1:\t"
29862306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
29962306a36Sopenharmony_ci		"addxl %5,%0\n\t"
30062306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
30162306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
30262306a36Sopenharmony_ci		"addxl %5,%0\n\t"
30362306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
30462306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
30562306a36Sopenharmony_ci		"addxl %5,%0\n\t"
30662306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
30762306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
30862306a36Sopenharmony_ci		"addxl %5,%0\n\t"
30962306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
31062306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
31162306a36Sopenharmony_ci		"addxl %5,%0\n\t"
31262306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
31362306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
31462306a36Sopenharmony_ci		"addxl %5,%0\n\t"
31562306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
31662306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
31762306a36Sopenharmony_ci		"addxl %5,%0\n\t"
31862306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
31962306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
32062306a36Sopenharmony_ci		"addxl %5,%0\n\t"
32162306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
32262306a36Sopenharmony_ci		"dbra %1,1b\n\t"
32362306a36Sopenharmony_ci		"clrl %5\n\t"
32462306a36Sopenharmony_ci		"addxl %5,%0\n\t"	/* add X bit */
32562306a36Sopenharmony_ci		"clrw %1\n\t"
32662306a36Sopenharmony_ci		"subql #1,%1\n\t"
32762306a36Sopenharmony_ci		"jcc 1b\n"
32862306a36Sopenharmony_ci	     "2:\t"
32962306a36Sopenharmony_ci		"movel %4,%1\n\t"	/* restore len from tmp1 */
33062306a36Sopenharmony_ci		"andw #0x1c,%4\n\t"	/* number of rest longs */
33162306a36Sopenharmony_ci		"jeq 4f\n\t"
33262306a36Sopenharmony_ci		"lsrw #2,%4\n\t"
33362306a36Sopenharmony_ci		"subqw #1,%4\n"
33462306a36Sopenharmony_ci	     "3:\t"
33562306a36Sopenharmony_ci		/* loop for rest longs */
33662306a36Sopenharmony_ci		"movel %2@+,%5\n\t"
33762306a36Sopenharmony_ci		"addxl %5,%0\n\t"
33862306a36Sopenharmony_ci		"movel %5,%3@+\n\t"
33962306a36Sopenharmony_ci		"dbra %4,3b\n\t"
34062306a36Sopenharmony_ci		"clrl %5\n\t"
34162306a36Sopenharmony_ci		"addxl %5,%0\n"		/* add X bit */
34262306a36Sopenharmony_ci	     "4:\t"
34362306a36Sopenharmony_ci		/* now check for rest bytes that do not fit into longs */
34462306a36Sopenharmony_ci		"andw #3,%1\n\t"
34562306a36Sopenharmony_ci		"jeq 7f\n\t"
34662306a36Sopenharmony_ci		"clrl %5\n\t"		/* clear tmp2 for rest bytes */
34762306a36Sopenharmony_ci		"subqw #2,%1\n\t"
34862306a36Sopenharmony_ci		"jlt 5f\n\t"
34962306a36Sopenharmony_ci		"movew %2@+,%5\n\t"	/* have rest >= 2: get word */
35062306a36Sopenharmony_ci		"movew %5,%3@+\n\t"
35162306a36Sopenharmony_ci		"swap %5\n\t"		/* into bits 16..31 */
35262306a36Sopenharmony_ci		"tstw %1\n\t"		/* another byte? */
35362306a36Sopenharmony_ci		"jeq 6f\n"
35462306a36Sopenharmony_ci	     "5:\t"
35562306a36Sopenharmony_ci		"moveb %2@,%5\n\t"	/* have odd rest: get byte */
35662306a36Sopenharmony_ci		"moveb %5,%3@+\n\t"
35762306a36Sopenharmony_ci		"lslw #8,%5\n"		/* into bits 8..15; 16..31 untouched */
35862306a36Sopenharmony_ci	     "6:\t"
35962306a36Sopenharmony_ci		"addl %5,%0\n\t"	/* now add rest long to sum */
36062306a36Sopenharmony_ci		"clrl %5\n\t"
36162306a36Sopenharmony_ci		"addxl %5,%0\n"		/* add X bit */
36262306a36Sopenharmony_ci	     "7:\t"
36362306a36Sopenharmony_ci		: "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
36462306a36Sopenharmony_ci		  "=&d" (tmp1), "=&d" (tmp2)
36562306a36Sopenharmony_ci		: "0" (sum), "1" (len), "2" (src), "3" (dst)
36662306a36Sopenharmony_ci	    );
36762306a36Sopenharmony_ci    return(sum);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ciEXPORT_SYMBOL(csum_partial_copy_nocheck);
370