xref: /linux/arch/arm/lib/csumpartial.S (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */
21da177e4SLinus Torvalds/*
31da177e4SLinus Torvalds *  linux/arch/arm/lib/csumpartial.S
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *  Copyright (C) 1995-1998 Russell King
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds#include <linux/linkage.h>
81da177e4SLinus Torvalds#include <asm/assembler.h>
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds		.text
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds/*
131da177e4SLinus Torvalds * Function: __u32 csum_partial(const char *src, int len, __u32 sum)
141da177e4SLinus Torvalds * Params  : r0 = buffer, r1 = len, r2 = checksum
151da177e4SLinus Torvalds * Returns : r0 = new checksum
161da177e4SLinus Torvalds */
171da177e4SLinus Torvalds
181da177e4SLinus Torvaldsbuf	.req	r0
191da177e4SLinus Torvaldslen	.req	r1
201da177e4SLinus Torvaldssum	.req	r2
211da177e4SLinus Torvaldstd0	.req	r3
221da177e4SLinus Torvaldstd1	.req	r4	@ save before use
231da177e4SLinus Torvaldstd2	.req	r5	@ save before use
241da177e4SLinus Torvaldstd3	.req	lr
251da177e4SLinus Torvalds
268adbb371SNicolas Pitre.Lzero:		mov	r0, sum
271da177e4SLinus Torvalds		add	sp, sp, #4
281da177e4SLinus Torvalds		ldr	pc, [sp], #4
291da177e4SLinus Torvalds
301da177e4SLinus Torvalds		/*
311da177e4SLinus Torvalds		 * Handle 0 to 7 bytes, with any alignment of source and
321da177e4SLinus Torvalds		 * destination pointers.  Note that when we get here, C = 0
331da177e4SLinus Torvalds		 */
348adbb371SNicolas Pitre.Lless8:		teq	len, #0			@ check for zero count
358adbb371SNicolas Pitre		beq	.Lzero
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds		/* we must have at least one byte. */
381da177e4SLinus Torvalds		tst	buf, #1			@ odd address?
39af36bef0SRussell King		movne	sum, sum, ror #8
40e44fc388SStefan Agner		ldrbne	td0, [buf], #1
411da177e4SLinus Torvalds		subne	len, len, #1
42e44fc388SStefan Agner		adcsne	sum, sum, td0, put_byte_1
431da177e4SLinus Torvalds
448adbb371SNicolas Pitre.Lless4:		tst	len, #6
458adbb371SNicolas Pitre		beq	.Lless8_byte
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds		/* we are now half-word aligned */
481da177e4SLinus Torvalds
498adbb371SNicolas Pitre.Lless8_wordlp:
501da177e4SLinus Torvalds#if __LINUX_ARM_ARCH__ >= 4
511da177e4SLinus Torvalds		ldrh	td0, [buf], #2
521da177e4SLinus Torvalds		sub	len, len, #2
531da177e4SLinus Torvalds#else
541da177e4SLinus Torvalds		ldrb	td0, [buf], #1
551da177e4SLinus Torvalds		ldrb	td3, [buf], #1
561da177e4SLinus Torvalds		sub	len, len, #2
571da177e4SLinus Torvalds#ifndef __ARMEB__
581da177e4SLinus Torvalds		orr	td0, td0, td3, lsl #8
591da177e4SLinus Torvalds#else
601da177e4SLinus Torvalds		orr	td0, td3, td0, lsl #8
611da177e4SLinus Torvalds#endif
621da177e4SLinus Torvalds#endif
631da177e4SLinus Torvalds		adcs	sum, sum, td0
641da177e4SLinus Torvalds		tst	len, #6
658adbb371SNicolas Pitre		bne	.Lless8_wordlp
661da177e4SLinus Torvalds
678adbb371SNicolas Pitre.Lless8_byte:	tst	len, #1			@ odd number of bytes
68e44fc388SStefan Agner		ldrbne	td0, [buf], #1		@ include last byte
69e44fc388SStefan Agner		adcsne	sum, sum, td0, put_byte_0	@ update checksum
701da177e4SLinus Torvalds
718adbb371SNicolas Pitre.Ldone:		adc	r0, sum, #0		@ collect up the last carry
721da177e4SLinus Torvalds		ldr	td0, [sp], #4
731da177e4SLinus Torvalds		tst	td0, #1			@ check buffer alignment
741da177e4SLinus Torvalds		movne	r0, r0, ror #8		@ rotate checksum by 8 bits
751da177e4SLinus Torvalds		ldr	pc, [sp], #4		@ return
761da177e4SLinus Torvalds
778adbb371SNicolas Pitre.Lnot_aligned:	tst	buf, #1			@ odd address
78e44fc388SStefan Agner		ldrbne	td0, [buf], #1		@ make even
791da177e4SLinus Torvalds		subne	len, len, #1
80e44fc388SStefan Agner		adcsne	sum, sum, td0, put_byte_1	@ update checksum
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds		tst	buf, #2			@ 32-bit aligned?
831da177e4SLinus Torvalds#if __LINUX_ARM_ARCH__ >= 4
84e44fc388SStefan Agner		ldrhne	td0, [buf], #2		@ make 32-bit aligned
851da177e4SLinus Torvalds		subne	len, len, #2
861da177e4SLinus Torvalds#else
87e44fc388SStefan Agner		ldrbne	td0, [buf], #1
88e44fc388SStefan Agner		ldrbne	ip, [buf], #1
891da177e4SLinus Torvalds		subne	len, len, #2
901da177e4SLinus Torvalds#ifndef __ARMEB__
911da177e4SLinus Torvalds		orrne	td0, td0, ip, lsl #8
921da177e4SLinus Torvalds#else
931da177e4SLinus Torvalds		orrne	td0, ip, td0, lsl #8
941da177e4SLinus Torvalds#endif
951da177e4SLinus Torvalds#endif
96e44fc388SStefan Agner		adcsne	sum, sum, td0		@ update checksum
976ebbf2ceSRussell King		ret	lr
981da177e4SLinus Torvalds
991da177e4SLinus TorvaldsENTRY(csum_partial)
1001da177e4SLinus Torvalds		stmfd	sp!, {buf, lr}
1011da177e4SLinus Torvalds		cmp	len, #8			@ Ensure that we have at least
1028adbb371SNicolas Pitre		blo	.Lless8			@ 8 bytes to copy.
1031da177e4SLinus Torvalds
104af36bef0SRussell King		tst	buf, #1
105af36bef0SRussell King		movne	sum, sum, ror #8
106af36bef0SRussell King
1071da177e4SLinus Torvalds		adds	sum, sum, #0		@ C = 0
1081da177e4SLinus Torvalds		tst	buf, #3			@ Test destination alignment
1098adbb371SNicolas Pitre		blne	.Lnot_aligned		@ align destination, return here
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds1:		bics	ip, len, #31
1121da177e4SLinus Torvalds		beq	3f
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds		stmfd	sp!, {r4 - r5}
1151da177e4SLinus Torvalds2:		ldmia	buf!, {td0, td1, td2, td3}
1161da177e4SLinus Torvalds		adcs	sum, sum, td0
1171da177e4SLinus Torvalds		adcs	sum, sum, td1
1181da177e4SLinus Torvalds		adcs	sum, sum, td2
1191da177e4SLinus Torvalds		adcs	sum, sum, td3
1201da177e4SLinus Torvalds		ldmia	buf!, {td0, td1, td2, td3}
1211da177e4SLinus Torvalds		adcs	sum, sum, td0
1221da177e4SLinus Torvalds		adcs	sum, sum, td1
1231da177e4SLinus Torvalds		adcs	sum, sum, td2
1241da177e4SLinus Torvalds		adcs	sum, sum, td3
1251da177e4SLinus Torvalds		sub	ip, ip, #32
1261da177e4SLinus Torvalds		teq	ip, #0
1271da177e4SLinus Torvalds		bne	2b
1281da177e4SLinus Torvalds		ldmfd	sp!, {r4 - r5}
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds3:		tst	len, #0x1c		@ should not change C
1318adbb371SNicolas Pitre		beq	.Lless4
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds4:		ldr	td0, [buf], #4
1341da177e4SLinus Torvalds		sub	len, len, #4
1351da177e4SLinus Torvalds		adcs	sum, sum, td0
1361da177e4SLinus Torvalds		tst	len, #0x1c
1371da177e4SLinus Torvalds		bne	4b
1388adbb371SNicolas Pitre		b	.Lless4
13993ed3970SCatalin MarinasENDPROC(csum_partial)
140