18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This file contains assembly-language implementations
48c2ecf20Sopenharmony_ci * of IP-style 1's complement checksum routines.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/sys.h>
128c2ecf20Sopenharmony_ci#include <asm/processor.h>
138c2ecf20Sopenharmony_ci#include <asm/cache.h>
148c2ecf20Sopenharmony_ci#include <asm/errno.h>
158c2ecf20Sopenharmony_ci#include <asm/ppc_asm.h>
168c2ecf20Sopenharmony_ci#include <asm/export.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	.text
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * computes the checksum of a memory block at buff, length len,
228c2ecf20Sopenharmony_ci * and adds in "sum" (32-bit)
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * __csum_partial(buff, len, sum)
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci_GLOBAL(__csum_partial)
278c2ecf20Sopenharmony_ci	subi	r3,r3,4
288c2ecf20Sopenharmony_ci	srawi.	r6,r4,2		/* Divide len by 4 and also clear carry */
298c2ecf20Sopenharmony_ci	beq	3f		/* if we're doing < 4 bytes */
308c2ecf20Sopenharmony_ci	andi.	r0,r3,2		/* Align buffer to longword boundary */
318c2ecf20Sopenharmony_ci	beq+	1f
328c2ecf20Sopenharmony_ci	lhz	r0,4(r3)	/* do 2 bytes to get aligned */
338c2ecf20Sopenharmony_ci	subi	r4,r4,2
348c2ecf20Sopenharmony_ci	addi	r3,r3,2
358c2ecf20Sopenharmony_ci	srwi.	r6,r4,2		/* # words to do */
368c2ecf20Sopenharmony_ci	adde	r5,r5,r0
378c2ecf20Sopenharmony_ci	beq	3f
388c2ecf20Sopenharmony_ci1:	andi.	r6,r6,3		/* Prepare to handle words 4 by 4 */
398c2ecf20Sopenharmony_ci	beq	21f
408c2ecf20Sopenharmony_ci	mtctr	r6
418c2ecf20Sopenharmony_ci2:	lwzu	r0,4(r3)
428c2ecf20Sopenharmony_ci	adde	r5,r5,r0
438c2ecf20Sopenharmony_ci	bdnz	2b
448c2ecf20Sopenharmony_ci21:	srwi.	r6,r4,4		/* # blocks of 4 words to do */
458c2ecf20Sopenharmony_ci	beq	3f
468c2ecf20Sopenharmony_ci	lwz	r0,4(r3)
478c2ecf20Sopenharmony_ci	mtctr	r6
488c2ecf20Sopenharmony_ci	lwz	r6,8(r3)
498c2ecf20Sopenharmony_ci	adde	r5,r5,r0
508c2ecf20Sopenharmony_ci	lwz	r7,12(r3)
518c2ecf20Sopenharmony_ci	adde	r5,r5,r6
528c2ecf20Sopenharmony_ci	lwzu	r8,16(r3)
538c2ecf20Sopenharmony_ci	adde	r5,r5,r7
548c2ecf20Sopenharmony_ci	bdz	23f
558c2ecf20Sopenharmony_ci22:	lwz	r0,4(r3)
568c2ecf20Sopenharmony_ci	adde	r5,r5,r8
578c2ecf20Sopenharmony_ci	lwz	r6,8(r3)
588c2ecf20Sopenharmony_ci	adde	r5,r5,r0
598c2ecf20Sopenharmony_ci	lwz	r7,12(r3)
608c2ecf20Sopenharmony_ci	adde	r5,r5,r6
618c2ecf20Sopenharmony_ci	lwzu	r8,16(r3)
628c2ecf20Sopenharmony_ci	adde	r5,r5,r7
638c2ecf20Sopenharmony_ci	bdnz	22b
648c2ecf20Sopenharmony_ci23:	adde	r5,r5,r8
658c2ecf20Sopenharmony_ci3:	andi.	r0,r4,2
668c2ecf20Sopenharmony_ci	beq+	4f
678c2ecf20Sopenharmony_ci	lhz	r0,4(r3)
688c2ecf20Sopenharmony_ci	addi	r3,r3,2
698c2ecf20Sopenharmony_ci	adde	r5,r5,r0
708c2ecf20Sopenharmony_ci4:	andi.	r0,r4,1
718c2ecf20Sopenharmony_ci	beq+	5f
728c2ecf20Sopenharmony_ci	lbz	r0,4(r3)
738c2ecf20Sopenharmony_ci	slwi	r0,r0,8		/* Upper byte of word */
748c2ecf20Sopenharmony_ci	adde	r5,r5,r0
758c2ecf20Sopenharmony_ci5:	addze	r3,r5		/* add in final carry */
768c2ecf20Sopenharmony_ci	blr
778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__csum_partial)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * Computes the checksum of a memory block at src, length len,
818c2ecf20Sopenharmony_ci * and adds in 0xffffffff, while copying the block to dst.
828c2ecf20Sopenharmony_ci * If an access exception occurs it returns zero.
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci * csum_partial_copy_generic(src, dst, len)
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_ci#define CSUM_COPY_16_BYTES_WITHEX(n)	\
878c2ecf20Sopenharmony_ci8 ## n ## 0:			\
888c2ecf20Sopenharmony_ci	lwz	r7,4(r4);	\
898c2ecf20Sopenharmony_ci8 ## n ## 1:			\
908c2ecf20Sopenharmony_ci	lwz	r8,8(r4);	\
918c2ecf20Sopenharmony_ci8 ## n ## 2:			\
928c2ecf20Sopenharmony_ci	lwz	r9,12(r4);	\
938c2ecf20Sopenharmony_ci8 ## n ## 3:			\
948c2ecf20Sopenharmony_ci	lwzu	r10,16(r4);	\
958c2ecf20Sopenharmony_ci8 ## n ## 4:			\
968c2ecf20Sopenharmony_ci	stw	r7,4(r6);	\
978c2ecf20Sopenharmony_ci	adde	r12,r12,r7;	\
988c2ecf20Sopenharmony_ci8 ## n ## 5:			\
998c2ecf20Sopenharmony_ci	stw	r8,8(r6);	\
1008c2ecf20Sopenharmony_ci	adde	r12,r12,r8;	\
1018c2ecf20Sopenharmony_ci8 ## n ## 6:			\
1028c2ecf20Sopenharmony_ci	stw	r9,12(r6);	\
1038c2ecf20Sopenharmony_ci	adde	r12,r12,r9;	\
1048c2ecf20Sopenharmony_ci8 ## n ## 7:			\
1058c2ecf20Sopenharmony_ci	stwu	r10,16(r6);	\
1068c2ecf20Sopenharmony_ci	adde	r12,r12,r10
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci#define CSUM_COPY_16_BYTES_EXCODE(n)		\
1098c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 0b, fault);	\
1108c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 1b, fault);	\
1118c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 2b, fault);	\
1128c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 3b, fault);	\
1138c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 4b, fault);	\
1148c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 5b, fault);	\
1158c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 6b, fault);	\
1168c2ecf20Sopenharmony_ci	EX_TABLE(8 ## n ## 7b, fault);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	.text
1198c2ecf20Sopenharmony_ci	.stabs	"arch/powerpc/lib/",N_SO,0,0,0f
1208c2ecf20Sopenharmony_ci	.stabs	"checksum_32.S",N_SO,0,0,0f
1218c2ecf20Sopenharmony_ci0:
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ciCACHELINE_BYTES = L1_CACHE_BYTES
1248c2ecf20Sopenharmony_ciLG_CACHELINE_BYTES = L1_CACHE_SHIFT
1258c2ecf20Sopenharmony_ciCACHELINE_MASK = (L1_CACHE_BYTES-1)
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci_GLOBAL(csum_partial_copy_generic)
1288c2ecf20Sopenharmony_ci	li	r12,-1
1298c2ecf20Sopenharmony_ci	addic	r0,r0,0			/* clear carry */
1308c2ecf20Sopenharmony_ci	addi	r6,r4,-4
1318c2ecf20Sopenharmony_ci	neg	r0,r4
1328c2ecf20Sopenharmony_ci	addi	r4,r3,-4
1338c2ecf20Sopenharmony_ci	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
1348c2ecf20Sopenharmony_ci	crset	4*cr7+eq
1358c2ecf20Sopenharmony_ci	beq	58f
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	cmplw	0,r5,r0			/* is this more than total to do? */
1388c2ecf20Sopenharmony_ci	blt	63f			/* if not much to do */
1398c2ecf20Sopenharmony_ci	rlwinm	r7,r6,3,0x8
1408c2ecf20Sopenharmony_ci	rlwnm	r12,r12,r7,0,31	/* odd destination address: rotate one byte */
1418c2ecf20Sopenharmony_ci	cmplwi	cr7,r7,0	/* is destination address even ? */
1428c2ecf20Sopenharmony_ci	andi.	r8,r0,3			/* get it word-aligned first */
1438c2ecf20Sopenharmony_ci	mtctr	r8
1448c2ecf20Sopenharmony_ci	beq+	61f
1458c2ecf20Sopenharmony_ci	li	r3,0
1468c2ecf20Sopenharmony_ci70:	lbz	r9,4(r4)		/* do some bytes */
1478c2ecf20Sopenharmony_ci	addi	r4,r4,1
1488c2ecf20Sopenharmony_ci	slwi	r3,r3,8
1498c2ecf20Sopenharmony_ci	rlwimi	r3,r9,0,24,31
1508c2ecf20Sopenharmony_ci71:	stb	r9,4(r6)
1518c2ecf20Sopenharmony_ci	addi	r6,r6,1
1528c2ecf20Sopenharmony_ci	bdnz	70b
1538c2ecf20Sopenharmony_ci	adde	r12,r12,r3
1548c2ecf20Sopenharmony_ci61:	subf	r5,r0,r5
1558c2ecf20Sopenharmony_ci	srwi.	r0,r0,2
1568c2ecf20Sopenharmony_ci	mtctr	r0
1578c2ecf20Sopenharmony_ci	beq	58f
1588c2ecf20Sopenharmony_ci72:	lwzu	r9,4(r4)		/* do some words */
1598c2ecf20Sopenharmony_ci	adde	r12,r12,r9
1608c2ecf20Sopenharmony_ci73:	stwu	r9,4(r6)
1618c2ecf20Sopenharmony_ci	bdnz	72b
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
1648c2ecf20Sopenharmony_ci	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
1658c2ecf20Sopenharmony_ci	li	r11,4
1668c2ecf20Sopenharmony_ci	beq	63f
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* Here we decide how far ahead to prefetch the source */
1698c2ecf20Sopenharmony_ci	li	r3,4
1708c2ecf20Sopenharmony_ci	cmpwi	r0,1
1718c2ecf20Sopenharmony_ci	li	r7,0
1728c2ecf20Sopenharmony_ci	ble	114f
1738c2ecf20Sopenharmony_ci	li	r7,1
1748c2ecf20Sopenharmony_ci#if MAX_COPY_PREFETCH > 1
1758c2ecf20Sopenharmony_ci	/* Heuristically, for large transfers we prefetch
1768c2ecf20Sopenharmony_ci	   MAX_COPY_PREFETCH cachelines ahead.  For small transfers
1778c2ecf20Sopenharmony_ci	   we prefetch 1 cacheline ahead. */
1788c2ecf20Sopenharmony_ci	cmpwi	r0,MAX_COPY_PREFETCH
1798c2ecf20Sopenharmony_ci	ble	112f
1808c2ecf20Sopenharmony_ci	li	r7,MAX_COPY_PREFETCH
1818c2ecf20Sopenharmony_ci112:	mtctr	r7
1828c2ecf20Sopenharmony_ci111:	dcbt	r3,r4
1838c2ecf20Sopenharmony_ci	addi	r3,r3,CACHELINE_BYTES
1848c2ecf20Sopenharmony_ci	bdnz	111b
1858c2ecf20Sopenharmony_ci#else
1868c2ecf20Sopenharmony_ci	dcbt	r3,r4
1878c2ecf20Sopenharmony_ci	addi	r3,r3,CACHELINE_BYTES
1888c2ecf20Sopenharmony_ci#endif /* MAX_COPY_PREFETCH > 1 */
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci114:	subf	r8,r7,r0
1918c2ecf20Sopenharmony_ci	mr	r0,r7
1928c2ecf20Sopenharmony_ci	mtctr	r8
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci53:	dcbt	r3,r4
1958c2ecf20Sopenharmony_ci54:	dcbz	r11,r6
1968c2ecf20Sopenharmony_ci/* the main body of the cacheline loop */
1978c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(0)
1988c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 32
1998c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(1)
2008c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 64
2018c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(2)
2028c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(3)
2038c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 128
2048c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(4)
2058c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(5)
2068c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(6)
2078c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_WITHEX(7)
2088c2ecf20Sopenharmony_ci#endif
2098c2ecf20Sopenharmony_ci#endif
2108c2ecf20Sopenharmony_ci#endif
2118c2ecf20Sopenharmony_ci	bdnz	53b
2128c2ecf20Sopenharmony_ci	cmpwi	r0,0
2138c2ecf20Sopenharmony_ci	li	r3,4
2148c2ecf20Sopenharmony_ci	li	r7,0
2158c2ecf20Sopenharmony_ci	bne	114b
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci63:	srwi.	r0,r5,2
2188c2ecf20Sopenharmony_ci	mtctr	r0
2198c2ecf20Sopenharmony_ci	beq	64f
2208c2ecf20Sopenharmony_ci30:	lwzu	r0,4(r4)
2218c2ecf20Sopenharmony_ci	adde	r12,r12,r0
2228c2ecf20Sopenharmony_ci31:	stwu	r0,4(r6)
2238c2ecf20Sopenharmony_ci	bdnz	30b
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci64:	andi.	r0,r5,2
2268c2ecf20Sopenharmony_ci	beq+	65f
2278c2ecf20Sopenharmony_ci40:	lhz	r0,4(r4)
2288c2ecf20Sopenharmony_ci	addi	r4,r4,2
2298c2ecf20Sopenharmony_ci41:	sth	r0,4(r6)
2308c2ecf20Sopenharmony_ci	adde	r12,r12,r0
2318c2ecf20Sopenharmony_ci	addi	r6,r6,2
2328c2ecf20Sopenharmony_ci65:	andi.	r0,r5,1
2338c2ecf20Sopenharmony_ci	beq+	66f
2348c2ecf20Sopenharmony_ci50:	lbz	r0,4(r4)
2358c2ecf20Sopenharmony_ci51:	stb	r0,4(r6)
2368c2ecf20Sopenharmony_ci	slwi	r0,r0,8
2378c2ecf20Sopenharmony_ci	adde	r12,r12,r0
2388c2ecf20Sopenharmony_ci66:	addze	r3,r12
2398c2ecf20Sopenharmony_ci	beqlr+	cr7
2408c2ecf20Sopenharmony_ci	rlwinm	r3,r3,8,0,31	/* odd destination address: rotate one byte */
2418c2ecf20Sopenharmony_ci	blr
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cifault:
2448c2ecf20Sopenharmony_ci	li	r3,0
2458c2ecf20Sopenharmony_ci	blr
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	EX_TABLE(70b, fault);
2488c2ecf20Sopenharmony_ci	EX_TABLE(71b, fault);
2498c2ecf20Sopenharmony_ci	EX_TABLE(72b, fault);
2508c2ecf20Sopenharmony_ci	EX_TABLE(73b, fault);
2518c2ecf20Sopenharmony_ci	EX_TABLE(54b, fault);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci/*
2548c2ecf20Sopenharmony_ci * this stuff handles faults in the cacheline loop and branches to either
2558c2ecf20Sopenharmony_ci * fault (if in read part) or fault (if in write part)
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(0)
2588c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 32
2598c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(1)
2608c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 64
2618c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(2)
2628c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(3)
2638c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 128
2648c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(4)
2658c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(5)
2668c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(6)
2678c2ecf20Sopenharmony_ci	CSUM_COPY_16_BYTES_EXCODE(7)
2688c2ecf20Sopenharmony_ci#endif
2698c2ecf20Sopenharmony_ci#endif
2708c2ecf20Sopenharmony_ci#endif
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	EX_TABLE(30b, fault);
2738c2ecf20Sopenharmony_ci	EX_TABLE(31b, fault);
2748c2ecf20Sopenharmony_ci	EX_TABLE(40b, fault);
2758c2ecf20Sopenharmony_ci	EX_TABLE(41b, fault);
2768c2ecf20Sopenharmony_ci	EX_TABLE(50b, fault);
2778c2ecf20Sopenharmony_ci	EX_TABLE(51b, fault);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(csum_partial_copy_generic)
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/*
2828c2ecf20Sopenharmony_ci * __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
2838c2ecf20Sopenharmony_ci *			   const struct in6_addr *daddr,
2848c2ecf20Sopenharmony_ci *			   __u32 len, __u8 proto, __wsum sum)
2858c2ecf20Sopenharmony_ci */
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci_GLOBAL(csum_ipv6_magic)
2888c2ecf20Sopenharmony_ci	lwz	r8, 0(r3)
2898c2ecf20Sopenharmony_ci	lwz	r9, 4(r3)
2908c2ecf20Sopenharmony_ci	addc	r0, r7, r8
2918c2ecf20Sopenharmony_ci	lwz	r10, 8(r3)
2928c2ecf20Sopenharmony_ci	adde	r0, r0, r9
2938c2ecf20Sopenharmony_ci	lwz	r11, 12(r3)
2948c2ecf20Sopenharmony_ci	adde	r0, r0, r10
2958c2ecf20Sopenharmony_ci	lwz	r8, 0(r4)
2968c2ecf20Sopenharmony_ci	adde	r0, r0, r11
2978c2ecf20Sopenharmony_ci	lwz	r9, 4(r4)
2988c2ecf20Sopenharmony_ci	adde	r0, r0, r8
2998c2ecf20Sopenharmony_ci	lwz	r10, 8(r4)
3008c2ecf20Sopenharmony_ci	adde	r0, r0, r9
3018c2ecf20Sopenharmony_ci	lwz	r11, 12(r4)
3028c2ecf20Sopenharmony_ci	adde	r0, r0, r10
3038c2ecf20Sopenharmony_ci	add	r5, r5, r6	/* assumption: len + proto doesn't carry */
3048c2ecf20Sopenharmony_ci	adde	r0, r0, r11
3058c2ecf20Sopenharmony_ci	adde	r0, r0, r5
3068c2ecf20Sopenharmony_ci	addze	r0, r0
3078c2ecf20Sopenharmony_ci	rotlwi	r3, r0, 16
3088c2ecf20Sopenharmony_ci	add	r3, r0, r3
3098c2ecf20Sopenharmony_ci	not	r3, r3
3108c2ecf20Sopenharmony_ci	rlwinm	r3, r3, 16, 16, 31
3118c2ecf20Sopenharmony_ci	blr
3128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(csum_ipv6_magic)
313