| /* | 
 |  * Accelerated CRC-T10DIF using ARM NEON and Crypto Extensions instructions | 
 |  * | 
 |  * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org> | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify | 
 |  * it under the terms of the GNU General Public License version 2 as | 
 |  * published by the Free Software Foundation. | 
 |  */ | 
 |  | 
 | #include <linux/crc-t10dif.h> | 
 | #include <linux/init.h> | 
 | #include <linux/kernel.h> | 
 | #include <linux/module.h> | 
 | #include <linux/string.h> | 
 |  | 
 | #include <crypto/internal/hash.h> | 
 |  | 
 | #include <asm/neon.h> | 
 | #include <asm/simd.h> | 
 |  | 
 | #define CRC_T10DIF_PMULL_CHUNK_SIZE	16U | 
 |  | 
 | asmlinkage u16 crc_t10dif_pmull(u16 init_crc, const u8 buf[], u32 len); | 
 |  | 
 | static int crct10dif_init(struct shash_desc *desc) | 
 | { | 
 | 	u16 *crc = shash_desc_ctx(desc); | 
 |  | 
 | 	*crc = 0; | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int crct10dif_update(struct shash_desc *desc, const u8 *data, | 
 | 			    unsigned int length) | 
 | { | 
 | 	u16 *crc = shash_desc_ctx(desc); | 
 |  | 
 | 	if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && may_use_simd()) { | 
 | 		kernel_neon_begin(); | 
 | 		*crc = crc_t10dif_pmull(*crc, data, length); | 
 | 		kernel_neon_end(); | 
 | 	} else { | 
 | 		*crc = crc_t10dif_generic(*crc, data, length); | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int crct10dif_final(struct shash_desc *desc, u8 *out) | 
 | { | 
 | 	u16 *crc = shash_desc_ctx(desc); | 
 |  | 
 | 	*(u16 *)out = *crc; | 
 | 	return 0; | 
 | } | 
 |  | 
 | static struct shash_alg crc_t10dif_alg = { | 
 | 	.digestsize		= CRC_T10DIF_DIGEST_SIZE, | 
 | 	.init			= crct10dif_init, | 
 | 	.update			= crct10dif_update, | 
 | 	.final			= crct10dif_final, | 
 | 	.descsize		= CRC_T10DIF_DIGEST_SIZE, | 
 |  | 
 | 	.base.cra_name		= "crct10dif", | 
 | 	.base.cra_driver_name	= "crct10dif-arm-ce", | 
 | 	.base.cra_priority	= 200, | 
 | 	.base.cra_blocksize	= CRC_T10DIF_BLOCK_SIZE, | 
 | 	.base.cra_module	= THIS_MODULE, | 
 | }; | 
 |  | 
 | static int __init crc_t10dif_mod_init(void) | 
 | { | 
 | 	if (!(elf_hwcap2 & HWCAP2_PMULL)) | 
 | 		return -ENODEV; | 
 |  | 
 | 	return crypto_register_shash(&crc_t10dif_alg); | 
 | } | 
 |  | 
 | static void __exit crc_t10dif_mod_exit(void) | 
 | { | 
 | 	crypto_unregister_shash(&crc_t10dif_alg); | 
 | } | 
 |  | 
 | module_init(crc_t10dif_mod_init); | 
 | module_exit(crc_t10dif_mod_exit); | 
 |  | 
 | MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); | 
 | MODULE_LICENSE("GPL v2"); | 
 | MODULE_ALIAS_CRYPTO("crct10dif"); |