diff options
Diffstat (limited to 'lib/crc/arm/crc-t10dif.h')
| -rw-r--r-- | lib/crc/arm/crc-t10dif.h | 55 | 
1 files changed, 55 insertions, 0 deletions
| diff --git a/lib/crc/arm/crc-t10dif.h b/lib/crc/arm/crc-t10dif.h new file mode 100644 index 000000000000..2edf7e9681d0 --- /dev/null +++ b/lib/crc/arm/crc-t10dif.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Accelerated CRC-T10DIF using ARM NEON and Crypto Extensions instructions + * + * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org> + */ + +#include <crypto/internal/simd.h> + +#include <asm/neon.h> +#include <asm/simd.h> + +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_pmull); + +#define CRC_T10DIF_PMULL_CHUNK_SIZE	16U + +asmlinkage u16 crc_t10dif_pmull64(u16 init_crc, const u8 *buf, size_t len); +asmlinkage void crc_t10dif_pmull8(u16 init_crc, const u8 *buf, size_t len, +				  u8 out[16]); + +static inline u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) +{ +	if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE) { +		if (static_branch_likely(&have_pmull)) { +			if (crypto_simd_usable()) { +				kernel_neon_begin(); +				crc = crc_t10dif_pmull64(crc, data, length); +				kernel_neon_end(); +				return crc; +			} +		} else if (length > CRC_T10DIF_PMULL_CHUNK_SIZE && +			   static_branch_likely(&have_neon) && +			   crypto_simd_usable()) { +			u8 buf[16] __aligned(16); + +			kernel_neon_begin(); +			crc_t10dif_pmull8(crc, data, length, buf); +			kernel_neon_end(); + +			return crc_t10dif_generic(0, buf, sizeof(buf)); +		} +	} +	return crc_t10dif_generic(crc, data, length); +} + +#define crc_t10dif_mod_init_arch crc_t10dif_mod_init_arch +static inline void crc_t10dif_mod_init_arch(void) +{ +	if (elf_hwcap & HWCAP_NEON) { +		static_branch_enable(&have_neon); +		if (elf_hwcap2 & HWCAP2_PMULL) +			static_branch_enable(&have_pmull); +	} +} | 
