162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file contains assembly-language implementations
462306a36Sopenharmony_ci * of IP-style 1's complement checksum routines.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci#include <linux/sys.h>
1362306a36Sopenharmony_ci#include <asm/processor.h>
1462306a36Sopenharmony_ci#include <asm/errno.h>
1562306a36Sopenharmony_ci#include <asm/ppc_asm.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Computes the checksum of a memory block at buff, length len,
1962306a36Sopenharmony_ci * and adds in "sum" (32-bit).
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * __csum_partial(r3=buff, r4=len, r5=sum)
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci_GLOBAL(__csum_partial)
2462306a36Sopenharmony_ci	addic	r0,r5,0			/* clear carry */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	srdi.	r6,r4,3			/* less than 8 bytes? */
2762306a36Sopenharmony_ci	beq	.Lcsum_tail_word
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	/*
3062306a36Sopenharmony_ci	 * If only halfword aligned, align to a double word. Since odd
3162306a36Sopenharmony_ci	 * aligned addresses should be rare and they would require more
3262306a36Sopenharmony_ci	 * work to calculate the correct checksum, we ignore that case
3362306a36Sopenharmony_ci	 * and take the potential slowdown of unaligned loads.
3462306a36Sopenharmony_ci	 */
3562306a36Sopenharmony_ci	rldicl. r6,r3,64-1,64-2		/* r6 = (r3 >> 1) & 0x3 */
3662306a36Sopenharmony_ci	beq	.Lcsum_aligned
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	li	r7,4
3962306a36Sopenharmony_ci	sub	r6,r7,r6
4062306a36Sopenharmony_ci	mtctr	r6
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci1:
4362306a36Sopenharmony_ci	lhz	r6,0(r3)		/* align to doubleword */
4462306a36Sopenharmony_ci	subi	r4,r4,2
4562306a36Sopenharmony_ci	addi	r3,r3,2
4662306a36Sopenharmony_ci	adde	r0,r0,r6
4762306a36Sopenharmony_ci	bdnz	1b
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci.Lcsum_aligned:
5062306a36Sopenharmony_ci	/*
5162306a36Sopenharmony_ci	 * We unroll the loop such that each iteration is 64 bytes with an
5262306a36Sopenharmony_ci	 * entry and exit limb of 64 bytes, meaning a minimum size of
5362306a36Sopenharmony_ci	 * 128 bytes.
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	srdi.	r6,r4,7
5662306a36Sopenharmony_ci	beq	.Lcsum_tail_doublewords		/* len < 128 */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	srdi	r6,r4,6
5962306a36Sopenharmony_ci	subi	r6,r6,1
6062306a36Sopenharmony_ci	mtctr	r6
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	stdu	r1,-STACKFRAMESIZE(r1)
6362306a36Sopenharmony_ci	std	r14,STK_REG(R14)(r1)
6462306a36Sopenharmony_ci	std	r15,STK_REG(R15)(r1)
6562306a36Sopenharmony_ci	std	r16,STK_REG(R16)(r1)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	ld	r6,0(r3)
6862306a36Sopenharmony_ci	ld	r9,8(r3)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ld	r10,16(r3)
7162306a36Sopenharmony_ci	ld	r11,24(r3)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/*
7462306a36Sopenharmony_ci	 * On POWER6 and POWER7 back to back adde instructions take 2 cycles
7562306a36Sopenharmony_ci	 * because of the XER dependency. This means the fastest this loop can
7662306a36Sopenharmony_ci	 * go is 16 cycles per iteration. The scheduling of the loop below has
7762306a36Sopenharmony_ci	 * been shown to hit this on both POWER6 and POWER7.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci	.align 5
8062306a36Sopenharmony_ci2:
8162306a36Sopenharmony_ci	adde	r0,r0,r6
8262306a36Sopenharmony_ci	ld	r12,32(r3)
8362306a36Sopenharmony_ci	ld	r14,40(r3)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	adde	r0,r0,r9
8662306a36Sopenharmony_ci	ld	r15,48(r3)
8762306a36Sopenharmony_ci	ld	r16,56(r3)
8862306a36Sopenharmony_ci	addi	r3,r3,64
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	adde	r0,r0,r10
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	adde	r0,r0,r11
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	adde	r0,r0,r12
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	adde	r0,r0,r14
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	adde	r0,r0,r15
9962306a36Sopenharmony_ci	ld	r6,0(r3)
10062306a36Sopenharmony_ci	ld	r9,8(r3)
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	adde	r0,r0,r16
10362306a36Sopenharmony_ci	ld	r10,16(r3)
10462306a36Sopenharmony_ci	ld	r11,24(r3)
10562306a36Sopenharmony_ci	bdnz	2b
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	adde	r0,r0,r6
10962306a36Sopenharmony_ci	ld	r12,32(r3)
11062306a36Sopenharmony_ci	ld	r14,40(r3)
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	adde	r0,r0,r9
11362306a36Sopenharmony_ci	ld	r15,48(r3)
11462306a36Sopenharmony_ci	ld	r16,56(r3)
11562306a36Sopenharmony_ci	addi	r3,r3,64
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	adde	r0,r0,r10
11862306a36Sopenharmony_ci	adde	r0,r0,r11
11962306a36Sopenharmony_ci	adde	r0,r0,r12
12062306a36Sopenharmony_ci	adde	r0,r0,r14
12162306a36Sopenharmony_ci	adde	r0,r0,r15
12262306a36Sopenharmony_ci	adde	r0,r0,r16
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	ld	r14,STK_REG(R14)(r1)
12562306a36Sopenharmony_ci	ld	r15,STK_REG(R15)(r1)
12662306a36Sopenharmony_ci	ld	r16,STK_REG(R16)(r1)
12762306a36Sopenharmony_ci	addi	r1,r1,STACKFRAMESIZE
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	andi.	r4,r4,63
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci.Lcsum_tail_doublewords:		/* Up to 127 bytes to go */
13262306a36Sopenharmony_ci	srdi.	r6,r4,3
13362306a36Sopenharmony_ci	beq	.Lcsum_tail_word
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	mtctr	r6
13662306a36Sopenharmony_ci3:
13762306a36Sopenharmony_ci	ld	r6,0(r3)
13862306a36Sopenharmony_ci	addi	r3,r3,8
13962306a36Sopenharmony_ci	adde	r0,r0,r6
14062306a36Sopenharmony_ci	bdnz	3b
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	andi.	r4,r4,7
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci.Lcsum_tail_word:			/* Up to 7 bytes to go */
14562306a36Sopenharmony_ci	srdi.	r6,r4,2
14662306a36Sopenharmony_ci	beq	.Lcsum_tail_halfword
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	lwz	r6,0(r3)
14962306a36Sopenharmony_ci	addi	r3,r3,4
15062306a36Sopenharmony_ci	adde	r0,r0,r6
15162306a36Sopenharmony_ci	subi	r4,r4,4
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci.Lcsum_tail_halfword:			/* Up to 3 bytes to go */
15462306a36Sopenharmony_ci	srdi.	r6,r4,1
15562306a36Sopenharmony_ci	beq	.Lcsum_tail_byte
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	lhz	r6,0(r3)
15862306a36Sopenharmony_ci	addi	r3,r3,2
15962306a36Sopenharmony_ci	adde	r0,r0,r6
16062306a36Sopenharmony_ci	subi	r4,r4,2
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci.Lcsum_tail_byte:			/* Up to 1 byte to go */
16362306a36Sopenharmony_ci	andi.	r6,r4,1
16462306a36Sopenharmony_ci	beq	.Lcsum_finish
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	lbz	r6,0(r3)
16762306a36Sopenharmony_ci#ifdef __BIG_ENDIAN__
16862306a36Sopenharmony_ci	sldi	r9,r6,8			/* Pad the byte out to 16 bits */
16962306a36Sopenharmony_ci	adde	r0,r0,r9
17062306a36Sopenharmony_ci#else
17162306a36Sopenharmony_ci	adde	r0,r0,r6
17262306a36Sopenharmony_ci#endif
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci.Lcsum_finish:
17562306a36Sopenharmony_ci	addze	r0,r0			/* add in final carry */
17662306a36Sopenharmony_ci	rldicl	r4,r0,32,0		/* fold two 32 bit halves together */
17762306a36Sopenharmony_ci	add	r3,r4,r0
17862306a36Sopenharmony_ci	srdi	r3,r3,32
17962306a36Sopenharmony_ci	blr
18062306a36Sopenharmony_ciEXPORT_SYMBOL(__csum_partial)
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	.macro srcnr
18462306a36Sopenharmony_ci100:
18562306a36Sopenharmony_ci	EX_TABLE(100b,.Lerror_nr)
18662306a36Sopenharmony_ci	.endm
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	.macro source
18962306a36Sopenharmony_ci150:
19062306a36Sopenharmony_ci	EX_TABLE(150b,.Lerror)
19162306a36Sopenharmony_ci	.endm
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	.macro dstnr
19462306a36Sopenharmony_ci200:
19562306a36Sopenharmony_ci	EX_TABLE(200b,.Lerror_nr)
19662306a36Sopenharmony_ci	.endm
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	.macro dest
19962306a36Sopenharmony_ci250:
20062306a36Sopenharmony_ci	EX_TABLE(250b,.Lerror)
20162306a36Sopenharmony_ci	.endm
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/*
20462306a36Sopenharmony_ci * Computes the checksum of a memory block at src, length len,
20562306a36Sopenharmony_ci * and adds in 0xffffffff (32-bit), while copying the block to dst.
20662306a36Sopenharmony_ci * If an access exception occurs, it returns 0.
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci * csum_partial_copy_generic(r3=src, r4=dst, r5=len)
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ci_GLOBAL(csum_partial_copy_generic)
21162306a36Sopenharmony_ci	li	r6,-1
21262306a36Sopenharmony_ci	addic	r0,r6,0			/* clear carry */
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	srdi.	r6,r5,3			/* less than 8 bytes? */
21562306a36Sopenharmony_ci	beq	.Lcopy_tail_word
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/*
21862306a36Sopenharmony_ci	 * If only halfword aligned, align to a double word. Since odd
21962306a36Sopenharmony_ci	 * aligned addresses should be rare and they would require more
22062306a36Sopenharmony_ci	 * work to calculate the correct checksum, we ignore that case
22162306a36Sopenharmony_ci	 * and take the potential slowdown of unaligned loads.
22262306a36Sopenharmony_ci	 *
22362306a36Sopenharmony_ci	 * If the source and destination are relatively unaligned we only
22462306a36Sopenharmony_ci	 * align the source. This keeps things simple.
22562306a36Sopenharmony_ci	 */
22662306a36Sopenharmony_ci	rldicl. r6,r3,64-1,64-2		/* r6 = (r3 >> 1) & 0x3 */
22762306a36Sopenharmony_ci	beq	.Lcopy_aligned
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	li	r9,4
23062306a36Sopenharmony_ci	sub	r6,r9,r6
23162306a36Sopenharmony_ci	mtctr	r6
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci1:
23462306a36Sopenharmony_cisrcnr;	lhz	r6,0(r3)		/* align to doubleword */
23562306a36Sopenharmony_ci	subi	r5,r5,2
23662306a36Sopenharmony_ci	addi	r3,r3,2
23762306a36Sopenharmony_ci	adde	r0,r0,r6
23862306a36Sopenharmony_cidstnr;	sth	r6,0(r4)
23962306a36Sopenharmony_ci	addi	r4,r4,2
24062306a36Sopenharmony_ci	bdnz	1b
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci.Lcopy_aligned:
24362306a36Sopenharmony_ci	/*
24462306a36Sopenharmony_ci	 * We unroll the loop such that each iteration is 64 bytes with an
24562306a36Sopenharmony_ci	 * entry and exit limb of 64 bytes, meaning a minimum size of
24662306a36Sopenharmony_ci	 * 128 bytes.
24762306a36Sopenharmony_ci	 */
24862306a36Sopenharmony_ci	srdi.	r6,r5,7
24962306a36Sopenharmony_ci	beq	.Lcopy_tail_doublewords		/* len < 128 */
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	srdi	r6,r5,6
25262306a36Sopenharmony_ci	subi	r6,r6,1
25362306a36Sopenharmony_ci	mtctr	r6
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	stdu	r1,-STACKFRAMESIZE(r1)
25662306a36Sopenharmony_ci	std	r14,STK_REG(R14)(r1)
25762306a36Sopenharmony_ci	std	r15,STK_REG(R15)(r1)
25862306a36Sopenharmony_ci	std	r16,STK_REG(R16)(r1)
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cisource;	ld	r6,0(r3)
26162306a36Sopenharmony_cisource;	ld	r9,8(r3)
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cisource;	ld	r10,16(r3)
26462306a36Sopenharmony_cisource;	ld	r11,24(r3)
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/*
26762306a36Sopenharmony_ci	 * On POWER6 and POWER7 back to back adde instructions take 2 cycles
26862306a36Sopenharmony_ci	 * because of the XER dependency. This means the fastest this loop can
26962306a36Sopenharmony_ci	 * go is 16 cycles per iteration. The scheduling of the loop below has
27062306a36Sopenharmony_ci	 * been shown to hit this on both POWER6 and POWER7.
27162306a36Sopenharmony_ci	 */
27262306a36Sopenharmony_ci	.align 5
27362306a36Sopenharmony_ci2:
27462306a36Sopenharmony_ci	adde	r0,r0,r6
27562306a36Sopenharmony_cisource;	ld	r12,32(r3)
27662306a36Sopenharmony_cisource;	ld	r14,40(r3)
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	adde	r0,r0,r9
27962306a36Sopenharmony_cisource;	ld	r15,48(r3)
28062306a36Sopenharmony_cisource;	ld	r16,56(r3)
28162306a36Sopenharmony_ci	addi	r3,r3,64
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	adde	r0,r0,r10
28462306a36Sopenharmony_cidest;	std	r6,0(r4)
28562306a36Sopenharmony_cidest;	std	r9,8(r4)
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	adde	r0,r0,r11
28862306a36Sopenharmony_cidest;	std	r10,16(r4)
28962306a36Sopenharmony_cidest;	std	r11,24(r4)
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	adde	r0,r0,r12
29262306a36Sopenharmony_cidest;	std	r12,32(r4)
29362306a36Sopenharmony_cidest;	std	r14,40(r4)
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	adde	r0,r0,r14
29662306a36Sopenharmony_cidest;	std	r15,48(r4)
29762306a36Sopenharmony_cidest;	std	r16,56(r4)
29862306a36Sopenharmony_ci	addi	r4,r4,64
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	adde	r0,r0,r15
30162306a36Sopenharmony_cisource;	ld	r6,0(r3)
30262306a36Sopenharmony_cisource;	ld	r9,8(r3)
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	adde	r0,r0,r16
30562306a36Sopenharmony_cisource;	ld	r10,16(r3)
30662306a36Sopenharmony_cisource;	ld	r11,24(r3)
30762306a36Sopenharmony_ci	bdnz	2b
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	adde	r0,r0,r6
31162306a36Sopenharmony_cisource;	ld	r12,32(r3)
31262306a36Sopenharmony_cisource;	ld	r14,40(r3)
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	adde	r0,r0,r9
31562306a36Sopenharmony_cisource;	ld	r15,48(r3)
31662306a36Sopenharmony_cisource;	ld	r16,56(r3)
31762306a36Sopenharmony_ci	addi	r3,r3,64
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	adde	r0,r0,r10
32062306a36Sopenharmony_cidest;	std	r6,0(r4)
32162306a36Sopenharmony_cidest;	std	r9,8(r4)
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	adde	r0,r0,r11
32462306a36Sopenharmony_cidest;	std	r10,16(r4)
32562306a36Sopenharmony_cidest;	std	r11,24(r4)
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	adde	r0,r0,r12
32862306a36Sopenharmony_cidest;	std	r12,32(r4)
32962306a36Sopenharmony_cidest;	std	r14,40(r4)
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	adde	r0,r0,r14
33262306a36Sopenharmony_cidest;	std	r15,48(r4)
33362306a36Sopenharmony_cidest;	std	r16,56(r4)
33462306a36Sopenharmony_ci	addi	r4,r4,64
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	adde	r0,r0,r15
33762306a36Sopenharmony_ci	adde	r0,r0,r16
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	ld	r14,STK_REG(R14)(r1)
34062306a36Sopenharmony_ci	ld	r15,STK_REG(R15)(r1)
34162306a36Sopenharmony_ci	ld	r16,STK_REG(R16)(r1)
34262306a36Sopenharmony_ci	addi	r1,r1,STACKFRAMESIZE
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	andi.	r5,r5,63
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci.Lcopy_tail_doublewords:		/* Up to 127 bytes to go */
34762306a36Sopenharmony_ci	srdi.	r6,r5,3
34862306a36Sopenharmony_ci	beq	.Lcopy_tail_word
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	mtctr	r6
35162306a36Sopenharmony_ci3:
35262306a36Sopenharmony_cisrcnr;	ld	r6,0(r3)
35362306a36Sopenharmony_ci	addi	r3,r3,8
35462306a36Sopenharmony_ci	adde	r0,r0,r6
35562306a36Sopenharmony_cidstnr;	std	r6,0(r4)
35662306a36Sopenharmony_ci	addi	r4,r4,8
35762306a36Sopenharmony_ci	bdnz	3b
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	andi.	r5,r5,7
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci.Lcopy_tail_word:			/* Up to 7 bytes to go */
36262306a36Sopenharmony_ci	srdi.	r6,r5,2
36362306a36Sopenharmony_ci	beq	.Lcopy_tail_halfword
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cisrcnr;	lwz	r6,0(r3)
36662306a36Sopenharmony_ci	addi	r3,r3,4
36762306a36Sopenharmony_ci	adde	r0,r0,r6
36862306a36Sopenharmony_cidstnr;	stw	r6,0(r4)
36962306a36Sopenharmony_ci	addi	r4,r4,4
37062306a36Sopenharmony_ci	subi	r5,r5,4
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci.Lcopy_tail_halfword:			/* Up to 3 bytes to go */
37362306a36Sopenharmony_ci	srdi.	r6,r5,1
37462306a36Sopenharmony_ci	beq	.Lcopy_tail_byte
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cisrcnr;	lhz	r6,0(r3)
37762306a36Sopenharmony_ci	addi	r3,r3,2
37862306a36Sopenharmony_ci	adde	r0,r0,r6
37962306a36Sopenharmony_cidstnr;	sth	r6,0(r4)
38062306a36Sopenharmony_ci	addi	r4,r4,2
38162306a36Sopenharmony_ci	subi	r5,r5,2
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci.Lcopy_tail_byte:			/* Up to 1 byte to go */
38462306a36Sopenharmony_ci	andi.	r6,r5,1
38562306a36Sopenharmony_ci	beq	.Lcopy_finish
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cisrcnr;	lbz	r6,0(r3)
38862306a36Sopenharmony_ci#ifdef __BIG_ENDIAN__
38962306a36Sopenharmony_ci	sldi	r9,r6,8			/* Pad the byte out to 16 bits */
39062306a36Sopenharmony_ci	adde	r0,r0,r9
39162306a36Sopenharmony_ci#else
39262306a36Sopenharmony_ci	adde	r0,r0,r6
39362306a36Sopenharmony_ci#endif
39462306a36Sopenharmony_cidstnr;	stb	r6,0(r4)
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci.Lcopy_finish:
39762306a36Sopenharmony_ci	addze	r0,r0			/* add in final carry */
39862306a36Sopenharmony_ci	rldicl	r4,r0,32,0		/* fold two 32 bit halves together */
39962306a36Sopenharmony_ci	add	r3,r4,r0
40062306a36Sopenharmony_ci	srdi	r3,r3,32
40162306a36Sopenharmony_ci	blr
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci.Lerror:
40462306a36Sopenharmony_ci	ld	r14,STK_REG(R14)(r1)
40562306a36Sopenharmony_ci	ld	r15,STK_REG(R15)(r1)
40662306a36Sopenharmony_ci	ld	r16,STK_REG(R16)(r1)
40762306a36Sopenharmony_ci	addi	r1,r1,STACKFRAMESIZE
40862306a36Sopenharmony_ci.Lerror_nr:
40962306a36Sopenharmony_ci	li	r3,0
41062306a36Sopenharmony_ci	blr
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ciEXPORT_SYMBOL(csum_partial_copy_generic)
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/*
41562306a36Sopenharmony_ci * __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
41662306a36Sopenharmony_ci *			   const struct in6_addr *daddr,
41762306a36Sopenharmony_ci *			   __u32 len, __u8 proto, __wsum sum)
41862306a36Sopenharmony_ci */
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci_GLOBAL(csum_ipv6_magic)
42162306a36Sopenharmony_ci	ld	r8, 0(r3)
42262306a36Sopenharmony_ci	ld	r9, 8(r3)
42362306a36Sopenharmony_ci	add	r5, r5, r6
42462306a36Sopenharmony_ci	addc	r0, r8, r9
42562306a36Sopenharmony_ci	ld	r10, 0(r4)
42662306a36Sopenharmony_ci	ld	r11, 8(r4)
42762306a36Sopenharmony_ci#ifdef CONFIG_CPU_LITTLE_ENDIAN
42862306a36Sopenharmony_ci	rotldi	r5, r5, 8
42962306a36Sopenharmony_ci#endif
43062306a36Sopenharmony_ci	adde	r0, r0, r10
43162306a36Sopenharmony_ci	add	r5, r5, r7
43262306a36Sopenharmony_ci	adde	r0, r0, r11
43362306a36Sopenharmony_ci	adde	r0, r0, r5
43462306a36Sopenharmony_ci	addze	r0, r0
43562306a36Sopenharmony_ci	rotldi  r3, r0, 32		/* fold two 32 bit halves together */
43662306a36Sopenharmony_ci	add	r3, r0, r3
43762306a36Sopenharmony_ci	srdi	r0, r3, 32
43862306a36Sopenharmony_ci	rotlwi	r3, r0, 16		/* fold two 16 bit halves together */
43962306a36Sopenharmony_ci	add	r3, r0, r3
44062306a36Sopenharmony_ci	not	r3, r3
44162306a36Sopenharmony_ci	rlwinm	r3, r3, 16, 16, 31
44262306a36Sopenharmony_ci	blr
44362306a36Sopenharmony_ciEXPORT_SYMBOL(csum_ipv6_magic)
444