18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Accelerated CRC-T10DIF using arm64 NEON and Crypto Extensions instructions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 - 2017 Linaro Ltd <ard.biesheuvel@linaro.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/cpufeature.h> 98c2ecf20Sopenharmony_ci#include <linux/crc-t10dif.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 168c2ecf20Sopenharmony_ci#include <crypto/internal/simd.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/neon.h> 198c2ecf20Sopenharmony_ci#include <asm/simd.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define CRC_T10DIF_PMULL_CHUNK_SIZE 16U 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciasmlinkage u16 crc_t10dif_pmull_p8(u16 init_crc, const u8 *buf, size_t len); 248c2ecf20Sopenharmony_ciasmlinkage u16 crc_t10dif_pmull_p64(u16 init_crc, const u8 *buf, size_t len); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int crct10dif_init(struct shash_desc *desc) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci u16 *crc = shash_desc_ctx(desc); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci *crc = 0; 318c2ecf20Sopenharmony_ci return 0; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int crct10dif_update_pmull_p8(struct shash_desc *desc, const u8 *data, 358c2ecf20Sopenharmony_ci unsigned int length) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci u16 *crc = shash_desc_ctx(desc); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) { 408c2ecf20Sopenharmony_ci do { 418c2ecf20Sopenharmony_ci unsigned int chunk = length; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE) 448c2ecf20Sopenharmony_ci chunk = SZ_4K; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci kernel_neon_begin(); 478c2ecf20Sopenharmony_ci *crc = crc_t10dif_pmull_p8(*crc, data, chunk); 488c2ecf20Sopenharmony_ci kernel_neon_end(); 498c2ecf20Sopenharmony_ci data += chunk; 508c2ecf20Sopenharmony_ci length -= chunk; 518c2ecf20Sopenharmony_ci } while (length); 528c2ecf20Sopenharmony_ci } else { 538c2ecf20Sopenharmony_ci *crc = crc_t10dif_generic(*crc, data, length); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int crct10dif_update_pmull_p64(struct shash_desc *desc, const u8 *data, 608c2ecf20Sopenharmony_ci unsigned int length) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci u16 *crc = shash_desc_ctx(desc); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) { 658c2ecf20Sopenharmony_ci do { 668c2ecf20Sopenharmony_ci unsigned int chunk = length; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE) 698c2ecf20Sopenharmony_ci chunk = SZ_4K; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci kernel_neon_begin(); 728c2ecf20Sopenharmony_ci *crc = crc_t10dif_pmull_p64(*crc, data, chunk); 738c2ecf20Sopenharmony_ci kernel_neon_end(); 748c2ecf20Sopenharmony_ci data += chunk; 758c2ecf20Sopenharmony_ci length -= chunk; 768c2ecf20Sopenharmony_ci } while (length); 778c2ecf20Sopenharmony_ci } else { 788c2ecf20Sopenharmony_ci *crc = crc_t10dif_generic(*crc, data, length); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int crct10dif_final(struct shash_desc *desc, u8 *out) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci u16 *crc = shash_desc_ctx(desc); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci *(u16 *)out = *crc; 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct shash_alg crc_t10dif_alg[] = {{ 938c2ecf20Sopenharmony_ci .digestsize = CRC_T10DIF_DIGEST_SIZE, 948c2ecf20Sopenharmony_ci .init = crct10dif_init, 958c2ecf20Sopenharmony_ci .update = crct10dif_update_pmull_p8, 968c2ecf20Sopenharmony_ci .final = crct10dif_final, 978c2ecf20Sopenharmony_ci .descsize = CRC_T10DIF_DIGEST_SIZE, 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci .base.cra_name = "crct10dif", 1008c2ecf20Sopenharmony_ci .base.cra_driver_name = "crct10dif-arm64-neon", 1018c2ecf20Sopenharmony_ci .base.cra_priority = 100, 1028c2ecf20Sopenharmony_ci .base.cra_blocksize = CRC_T10DIF_BLOCK_SIZE, 1038c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1048c2ecf20Sopenharmony_ci}, { 1058c2ecf20Sopenharmony_ci .digestsize = CRC_T10DIF_DIGEST_SIZE, 1068c2ecf20Sopenharmony_ci .init = crct10dif_init, 1078c2ecf20Sopenharmony_ci .update = crct10dif_update_pmull_p64, 1088c2ecf20Sopenharmony_ci .final = crct10dif_final, 1098c2ecf20Sopenharmony_ci .descsize = CRC_T10DIF_DIGEST_SIZE, 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci .base.cra_name = "crct10dif", 1128c2ecf20Sopenharmony_ci .base.cra_driver_name = "crct10dif-arm64-ce", 1138c2ecf20Sopenharmony_ci .base.cra_priority = 200, 1148c2ecf20Sopenharmony_ci .base.cra_blocksize = CRC_T10DIF_BLOCK_SIZE, 1158c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1168c2ecf20Sopenharmony_ci}}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int __init crc_t10dif_mod_init(void) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci if (cpu_have_named_feature(PMULL)) 1218c2ecf20Sopenharmony_ci return crypto_register_shashes(crc_t10dif_alg, 1228c2ecf20Sopenharmony_ci ARRAY_SIZE(crc_t10dif_alg)); 1238c2ecf20Sopenharmony_ci else 1248c2ecf20Sopenharmony_ci /* only register the first array element */ 1258c2ecf20Sopenharmony_ci return crypto_register_shash(crc_t10dif_alg); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void __exit crc_t10dif_mod_exit(void) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci if (cpu_have_named_feature(PMULL)) 1318c2ecf20Sopenharmony_ci crypto_unregister_shashes(crc_t10dif_alg, 1328c2ecf20Sopenharmony_ci ARRAY_SIZE(crc_t10dif_alg)); 1338c2ecf20Sopenharmony_ci else 1348c2ecf20Sopenharmony_ci crypto_unregister_shash(crc_t10dif_alg); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cimodule_cpu_feature_match(ASIMD, crc_t10dif_mod_init); 1388c2ecf20Sopenharmony_cimodule_exit(crc_t10dif_mod_exit); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 1418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1428c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("crct10dif"); 1438c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("crct10dif-arm64-ce"); 144