xref: /linux/lib/crc/arm64/crc32.h (revision a578dd095dfe8b56c167201d9aea43e47d27f807)
1*2b7531b2SEric Biggers // SPDX-License-Identifier: GPL-2.0-only
2*2b7531b2SEric Biggers 
3*2b7531b2SEric Biggers #include <asm/alternative.h>
4*2b7531b2SEric Biggers #include <asm/cpufeature.h>
5*2b7531b2SEric Biggers #include <asm/neon.h>
6*2b7531b2SEric Biggers #include <asm/simd.h>
7*2b7531b2SEric Biggers 
8*2b7531b2SEric Biggers #include <crypto/internal/simd.h>
9*2b7531b2SEric Biggers 
10*2b7531b2SEric Biggers // The minimum input length to consider the 4-way interleaved code path
11*2b7531b2SEric Biggers static const size_t min_len = 1024;
12*2b7531b2SEric Biggers 
13*2b7531b2SEric Biggers asmlinkage u32 crc32_le_arm64(u32 crc, unsigned char const *p, size_t len);
14*2b7531b2SEric Biggers asmlinkage u32 crc32c_le_arm64(u32 crc, unsigned char const *p, size_t len);
15*2b7531b2SEric Biggers asmlinkage u32 crc32_be_arm64(u32 crc, unsigned char const *p, size_t len);
16*2b7531b2SEric Biggers 
17*2b7531b2SEric Biggers asmlinkage u32 crc32_le_arm64_4way(u32 crc, unsigned char const *p, size_t len);
18*2b7531b2SEric Biggers asmlinkage u32 crc32c_le_arm64_4way(u32 crc, unsigned char const *p, size_t len);
19*2b7531b2SEric Biggers asmlinkage u32 crc32_be_arm64_4way(u32 crc, unsigned char const *p, size_t len);
20*2b7531b2SEric Biggers 
crc32_le_arch(u32 crc,const u8 * p,size_t len)21*2b7531b2SEric Biggers static inline u32 crc32_le_arch(u32 crc, const u8 *p, size_t len)
22*2b7531b2SEric Biggers {
23*2b7531b2SEric Biggers 	if (!alternative_has_cap_likely(ARM64_HAS_CRC32))
24*2b7531b2SEric Biggers 		return crc32_le_base(crc, p, len);
25*2b7531b2SEric Biggers 
26*2b7531b2SEric Biggers 	if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) {
27*2b7531b2SEric Biggers 		kernel_neon_begin();
28*2b7531b2SEric Biggers 		crc = crc32_le_arm64_4way(crc, p, len);
29*2b7531b2SEric Biggers 		kernel_neon_end();
30*2b7531b2SEric Biggers 
31*2b7531b2SEric Biggers 		p += round_down(len, 64);
32*2b7531b2SEric Biggers 		len %= 64;
33*2b7531b2SEric Biggers 
34*2b7531b2SEric Biggers 		if (!len)
35*2b7531b2SEric Biggers 			return crc;
36*2b7531b2SEric Biggers 	}
37*2b7531b2SEric Biggers 
38*2b7531b2SEric Biggers 	return crc32_le_arm64(crc, p, len);
39*2b7531b2SEric Biggers }
40*2b7531b2SEric Biggers 
crc32c_arch(u32 crc,const u8 * p,size_t len)41*2b7531b2SEric Biggers static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len)
42*2b7531b2SEric Biggers {
43*2b7531b2SEric Biggers 	if (!alternative_has_cap_likely(ARM64_HAS_CRC32))
44*2b7531b2SEric Biggers 		return crc32c_base(crc, p, len);
45*2b7531b2SEric Biggers 
46*2b7531b2SEric Biggers 	if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) {
47*2b7531b2SEric Biggers 		kernel_neon_begin();
48*2b7531b2SEric Biggers 		crc = crc32c_le_arm64_4way(crc, p, len);
49*2b7531b2SEric Biggers 		kernel_neon_end();
50*2b7531b2SEric Biggers 
51*2b7531b2SEric Biggers 		p += round_down(len, 64);
52*2b7531b2SEric Biggers 		len %= 64;
53*2b7531b2SEric Biggers 
54*2b7531b2SEric Biggers 		if (!len)
55*2b7531b2SEric Biggers 			return crc;
56*2b7531b2SEric Biggers 	}
57*2b7531b2SEric Biggers 
58*2b7531b2SEric Biggers 	return crc32c_le_arm64(crc, p, len);
59*2b7531b2SEric Biggers }
60*2b7531b2SEric Biggers 
crc32_be_arch(u32 crc,const u8 * p,size_t len)61*2b7531b2SEric Biggers static inline u32 crc32_be_arch(u32 crc, const u8 *p, size_t len)
62*2b7531b2SEric Biggers {
63*2b7531b2SEric Biggers 	if (!alternative_has_cap_likely(ARM64_HAS_CRC32))
64*2b7531b2SEric Biggers 		return crc32_be_base(crc, p, len);
65*2b7531b2SEric Biggers 
66*2b7531b2SEric Biggers 	if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) {
67*2b7531b2SEric Biggers 		kernel_neon_begin();
68*2b7531b2SEric Biggers 		crc = crc32_be_arm64_4way(crc, p, len);
69*2b7531b2SEric Biggers 		kernel_neon_end();
70*2b7531b2SEric Biggers 
71*2b7531b2SEric Biggers 		p += round_down(len, 64);
72*2b7531b2SEric Biggers 		len %= 64;
73*2b7531b2SEric Biggers 
74*2b7531b2SEric Biggers 		if (!len)
75*2b7531b2SEric Biggers 			return crc;
76*2b7531b2SEric Biggers 	}
77*2b7531b2SEric Biggers 
78*2b7531b2SEric Biggers 	return crc32_be_arm64(crc, p, len);
79*2b7531b2SEric Biggers }
80*2b7531b2SEric Biggers 
crc32_optimizations_arch(void)81*2b7531b2SEric Biggers static inline u32 crc32_optimizations_arch(void)
82*2b7531b2SEric Biggers {
83*2b7531b2SEric Biggers 	if (alternative_has_cap_likely(ARM64_HAS_CRC32))
84*2b7531b2SEric Biggers 		return CRC32_LE_OPTIMIZATION |
85*2b7531b2SEric Biggers 		       CRC32_BE_OPTIMIZATION |
86*2b7531b2SEric Biggers 		       CRC32C_OPTIMIZATION;
87*2b7531b2SEric Biggers 	return 0;
88*2b7531b2SEric Biggers }
89