16cc25e4bSEric Biggers // SPDX-License-Identifier: GPL-2.0-only 26cc25e4bSEric Biggers /* 36cc25e4bSEric Biggers * Accelerated CRC-T10DIF using ARM NEON and Crypto Extensions instructions 46cc25e4bSEric Biggers * 56cc25e4bSEric Biggers * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org> 66cc25e4bSEric Biggers */ 76cc25e4bSEric Biggers 86cc25e4bSEric Biggers #include <linux/crc-t10dif.h> 96cc25e4bSEric Biggers #include <linux/init.h> 106cc25e4bSEric Biggers #include <linux/kernel.h> 116cc25e4bSEric Biggers #include <linux/module.h> 126cc25e4bSEric Biggers #include <linux/string.h> 136cc25e4bSEric Biggers 146cc25e4bSEric Biggers #include <crypto/internal/simd.h> 156cc25e4bSEric Biggers 166cc25e4bSEric Biggers #include <asm/neon.h> 176cc25e4bSEric Biggers #include <asm/simd.h> 186cc25e4bSEric Biggers 196cc25e4bSEric Biggers static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); 206cc25e4bSEric Biggers static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_pmull); 216cc25e4bSEric Biggers 226cc25e4bSEric Biggers #define CRC_T10DIF_PMULL_CHUNK_SIZE 16U 236cc25e4bSEric Biggers 246cc25e4bSEric Biggers asmlinkage u16 crc_t10dif_pmull64(u16 init_crc, const u8 *buf, size_t len); 256cc25e4bSEric Biggers asmlinkage void crc_t10dif_pmull8(u16 init_crc, const u8 *buf, size_t len, 266cc25e4bSEric Biggers u8 out[16]); 276cc25e4bSEric Biggers 286cc25e4bSEric Biggers u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) 296cc25e4bSEric Biggers { 306cc25e4bSEric Biggers if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE) { 316cc25e4bSEric Biggers if (static_branch_likely(&have_pmull)) { 326cc25e4bSEric Biggers if (crypto_simd_usable()) { 336cc25e4bSEric Biggers kernel_neon_begin(); 346cc25e4bSEric Biggers crc = crc_t10dif_pmull64(crc, data, length); 356cc25e4bSEric Biggers kernel_neon_end(); 366cc25e4bSEric Biggers return crc; 376cc25e4bSEric Biggers } 386cc25e4bSEric Biggers } else if (length > CRC_T10DIF_PMULL_CHUNK_SIZE && 396cc25e4bSEric Biggers static_branch_likely(&have_neon) && 406cc25e4bSEric Biggers crypto_simd_usable()) { 416cc25e4bSEric Biggers u8 buf[16] __aligned(16); 426cc25e4bSEric Biggers 436cc25e4bSEric Biggers kernel_neon_begin(); 446cc25e4bSEric Biggers crc_t10dif_pmull8(crc, data, length, buf); 456cc25e4bSEric Biggers kernel_neon_end(); 466cc25e4bSEric Biggers 476cc25e4bSEric Biggers return crc_t10dif_generic(0, buf, sizeof(buf)); 486cc25e4bSEric Biggers } 496cc25e4bSEric Biggers } 506cc25e4bSEric Biggers return crc_t10dif_generic(crc, data, length); 516cc25e4bSEric Biggers } 526cc25e4bSEric Biggers EXPORT_SYMBOL(crc_t10dif_arch); 536cc25e4bSEric Biggers 546cc25e4bSEric Biggers static int __init crc_t10dif_arm_init(void) 556cc25e4bSEric Biggers { 566cc25e4bSEric Biggers if (elf_hwcap & HWCAP_NEON) { 576cc25e4bSEric Biggers static_branch_enable(&have_neon); 586cc25e4bSEric Biggers if (elf_hwcap2 & HWCAP2_PMULL) 596cc25e4bSEric Biggers static_branch_enable(&have_pmull); 606cc25e4bSEric Biggers } 616cc25e4bSEric Biggers return 0; 626cc25e4bSEric Biggers } 63*648c7fb1SEric Biggers subsys_initcall(crc_t10dif_arm_init); 646cc25e4bSEric Biggers 656cc25e4bSEric Biggers static void __exit crc_t10dif_arm_exit(void) 666cc25e4bSEric Biggers { 676cc25e4bSEric Biggers } 686cc25e4bSEric Biggers module_exit(crc_t10dif_arm_exit); 696cc25e4bSEric Biggers 706cc25e4bSEric Biggers MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 716cc25e4bSEric Biggers MODULE_DESCRIPTION("Accelerated CRC-T10DIF using ARM NEON and Crypto Extensions"); 726cc25e4bSEric Biggers MODULE_LICENSE("GPL v2"); 73