161 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0-only */
 | |
| /*
 | |
|  * Accelerated CRC32(C) using AArch64 CRC instructions
 | |
|  *
 | |
|  * Copyright (C) 2016 - 2018 Linaro Ltd <ard.biesheuvel@linaro.org>
 | |
|  */
 | |
| 
 | |
| #include <linux/linkage.h>
 | |
| #include <asm/alternative.h>
 | |
| #include <asm/assembler.h>
 | |
| 
 | |
| 	.arch		armv8-a+crc
 | |
| 
 | |
| 	.macro		byteorder, reg, be
 | |
| 	.if		\be
 | |
| CPU_LE( rev		\reg, \reg	)
 | |
| 	.else
 | |
| CPU_BE( rev		\reg, \reg	)
 | |
| 	.endif
 | |
| 	.endm
 | |
| 
 | |
| 	.macro		byteorder16, reg, be
 | |
| 	.if		\be
 | |
| CPU_LE( rev16		\reg, \reg	)
 | |
| 	.else
 | |
| CPU_BE( rev16		\reg, \reg	)
 | |
| 	.endif
 | |
| 	.endm
 | |
| 
 | |
| 	.macro		bitorder, reg, be
 | |
| 	.if		\be
 | |
| 	rbit		\reg, \reg
 | |
| 	.endif
 | |
| 	.endm
 | |
| 
 | |
| 	.macro		bitorder16, reg, be
 | |
| 	.if		\be
 | |
| 	rbit		\reg, \reg
 | |
| 	lsr		\reg, \reg, #16
 | |
| 	.endif
 | |
| 	.endm
 | |
| 
 | |
| 	.macro		bitorder8, reg, be
 | |
| 	.if		\be
 | |
| 	rbit		\reg, \reg
 | |
| 	lsr		\reg, \reg, #24
 | |
| 	.endif
 | |
| 	.endm
 | |
| 
 | |
| 	.macro		__crc32, c, be=0
 | |
| 	bitorder	w0, \be
 | |
| 	cmp		x2, #16
 | |
| 	b.lt		8f			// less than 16 bytes
 | |
| 
 | |
| 	and		x7, x2, #0x1f
 | |
| 	and		x2, x2, #~0x1f
 | |
| 	cbz		x7, 32f			// multiple of 32 bytes
 | |
| 
 | |
| 	and		x8, x7, #0xf
 | |
| 	ldp		x3, x4, [x1]
 | |
| 	add		x8, x8, x1
 | |
| 	add		x1, x1, x7
 | |
| 	ldp		x5, x6, [x8]
 | |
| 	byteorder	x3, \be
 | |
| 	byteorder	x4, \be
 | |
| 	byteorder	x5, \be
 | |
| 	byteorder	x6, \be
 | |
| 	bitorder	x3, \be
 | |
| 	bitorder	x4, \be
 | |
| 	bitorder	x5, \be
 | |
| 	bitorder	x6, \be
 | |
| 
 | |
| 	tst		x7, #8
 | |
| 	crc32\c\()x	w8, w0, x3
 | |
| 	csel		x3, x3, x4, eq
 | |
| 	csel		w0, w0, w8, eq
 | |
| 	tst		x7, #4
 | |
| 	lsr		x4, x3, #32
 | |
| 	crc32\c\()w	w8, w0, w3
 | |
| 	csel		x3, x3, x4, eq
 | |
| 	csel		w0, w0, w8, eq
 | |
| 	tst		x7, #2
 | |
| 	lsr		w4, w3, #16
 | |
| 	crc32\c\()h	w8, w0, w3
 | |
| 	csel		w3, w3, w4, eq
 | |
| 	csel		w0, w0, w8, eq
 | |
| 	tst		x7, #1
 | |
| 	crc32\c\()b	w8, w0, w3
 | |
| 	csel		w0, w0, w8, eq
 | |
| 	tst		x7, #16
 | |
| 	crc32\c\()x	w8, w0, x5
 | |
| 	crc32\c\()x	w8, w8, x6
 | |
| 	csel		w0, w0, w8, eq
 | |
| 	cbz		x2, 0f
 | |
| 
 | |
| 32:	ldp		x3, x4, [x1], #32
 | |
| 	sub		x2, x2, #32
 | |
| 	ldp		x5, x6, [x1, #-16]
 | |
| 	byteorder	x3, \be
 | |
| 	byteorder	x4, \be
 | |
| 	byteorder	x5, \be
 | |
| 	byteorder	x6, \be
 | |
| 	bitorder	x3, \be
 | |
| 	bitorder	x4, \be
 | |
| 	bitorder	x5, \be
 | |
| 	bitorder	x6, \be
 | |
| 	crc32\c\()x	w0, w0, x3
 | |
| 	crc32\c\()x	w0, w0, x4
 | |
| 	crc32\c\()x	w0, w0, x5
 | |
| 	crc32\c\()x	w0, w0, x6
 | |
| 	cbnz		x2, 32b
 | |
| 0:	bitorder	w0, \be
 | |
| 	ret
 | |
| 
 | |
| 8:	tbz		x2, #3, 4f
 | |
| 	ldr		x3, [x1], #8
 | |
| 	byteorder	x3, \be
 | |
| 	bitorder	x3, \be
 | |
| 	crc32\c\()x	w0, w0, x3
 | |
| 4:	tbz		x2, #2, 2f
 | |
| 	ldr		w3, [x1], #4
 | |
| 	byteorder	w3, \be
 | |
| 	bitorder	w3, \be
 | |
| 	crc32\c\()w	w0, w0, w3
 | |
| 2:	tbz		x2, #1, 1f
 | |
| 	ldrh		w3, [x1], #2
 | |
| 	byteorder16	w3, \be
 | |
| 	bitorder16	w3, \be
 | |
| 	crc32\c\()h	w0, w0, w3
 | |
| 1:	tbz		x2, #0, 0f
 | |
| 	ldrb		w3, [x1]
 | |
| 	bitorder8	w3, \be
 | |
| 	crc32\c\()b	w0, w0, w3
 | |
| 0:	bitorder	w0, \be
 | |
| 	ret
 | |
| 	.endm
 | |
| 
 | |
| 	.align		5
 | |
| SYM_FUNC_START(crc32_le)
 | |
| alternative_if_not ARM64_HAS_CRC32
 | |
| 	b		crc32_le_base
 | |
| alternative_else_nop_endif
 | |
| 	__crc32
 | |
| SYM_FUNC_END(crc32_le)
 | |
| 
 | |
| 	.align		5
 | |
| SYM_FUNC_START(__crc32c_le)
 | |
| alternative_if_not ARM64_HAS_CRC32
 | |
| 	b		__crc32c_le_base
 | |
| alternative_else_nop_endif
 | |
| 	__crc32		c
 | |
| SYM_FUNC_END(__crc32c_le)
 | |
| 
 | |
| 	.align		5
 | |
| SYM_FUNC_START(crc32_be)
 | |
| alternative_if_not ARM64_HAS_CRC32
 | |
| 	b		crc32_be_base
 | |
| alternative_else_nop_endif
 | |
| 	__crc32		be=1
 | |
| SYM_FUNC_END(crc32_be)
 |