// SPDX-License-Identifier: GPL-2.0-or-later /* * Calculate a CRC T10-DIF with vpmsum acceleration * * Copyright 2017, Daniel Axtens, IBM Corporation. * [based on crc32c-vpmsum_glue.c] */ #include <linux/crc-t10dif.h> #include <crypto/internal/hash.h> #include <crypto/internal/simd.h> #include <linux/init.h> #include <linux/module.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/cpufeature.h> #include <asm/simd.h> #include <asm/switch_to.h> #define VMX_ALIGN 16 #define VMX_ALIGN_MASK (VMX_ALIGN-1) #define VECTOR_BREAKPOINT 64 u32 __crct10dif_vpmsum(u32 crc, unsigned char const *p, size_t len); static u16 crct10dif_vpmsum(u16 crci, unsigned char const *p, size_t len) { unsigned int prealign; unsigned int tail; u32 crc = crci; if (len < (VECTOR_BREAKPOINT + VMX_ALIGN) || !crypto_simd_usable()) return crc_t10dif_generic(crc, p, len); if ((unsigned long)p & VMX_ALIGN_MASK) { prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK); crc = crc_t10dif_generic(crc, p, prealign); len -= prealign; p += prealign; } if (len & ~VMX_ALIGN_MASK) { crc <<= 16; preempt_disable(); pagefault_disable(); enable_kernel_altivec(); crc = __crct10dif_vpmsum(crc, p, len & ~VMX_ALIGN_MASK); disable_kernel_altivec(); pagefault_enable(); preempt_enable(); crc >>= 16; } tail = len & VMX_ALIGN_MASK; if (tail) { p += len & ~VMX_ALIGN_MASK; crc = crc_t10dif_generic(crc, p, tail); } return crc & 0xffff; } static int crct10dif_vpmsum_init(struct shash_desc *desc) { u16 *crc = shash_desc_ctx(desc); *crc = 0; return 0; } static int crct10dif_vpmsum_update(struct shash_desc *desc, const u8 *data, unsigned int length) { u16 *crc = shash_desc_ctx(desc); *crc = crct10dif_vpmsum(*crc, data, length); return 0; } static int crct10dif_vpmsum_final(struct shash_desc *desc, u8 *out) { u16 *crcp = shash_desc_ctx(desc); *(u16 *)out = *crcp; return 0; } static struct shash_alg alg = { .init = crct10dif_vpmsum_init, .update = crct10dif_vpmsum_update, .final = crct10dif_vpmsum_final, .descsize = CRC_T10DIF_DIGEST_SIZE, .digestsize = CRC_T10DIF_DIGEST_SIZE, .base = { .cra_name = "crct10dif", .cra_driver_name = "crct10dif-vpmsum", .cra_priority = 200, .cra_blocksize = CRC_T10DIF_BLOCK_SIZE, .cra_module = THIS_MODULE, } }; static int __init crct10dif_vpmsum_mod_init(void) { if (!cpu_has_feature(CPU_FTR_ARCH_207S)) return -ENODEV; return crypto_register_shash(&alg); } static void __exit crct10dif_vpmsum_mod_fini(void) { crypto_unregister_shash(&alg); } module_cpu_feature_match(PPC_MODULE_FEATURE_VEC_CRYPTO, crct10dif_vpmsum_mod_init); module_exit(crct10dif_vpmsum_mod_fini); MODULE_AUTHOR("Daniel Axtens <dja@axtens.net>"); MODULE_DESCRIPTION("CRCT10DIF using vector polynomial multiply-sum instructions"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CRYPTO("crct10dif"); MODULE_ALIAS_CRYPTO("crct10dif-vpmsum");