2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-12-05 18:42:25 +00:00
/*
* Accelerated CRC - T10DIF using arm64 NEON and Crypto Extensions instructions
*
2017-07-24 11:28:06 +01:00
* Copyright ( C ) 2016 - 2017 Linaro Ltd < ard . biesheuvel @ linaro . org >
2016-12-05 18:42:25 +00:00
*/
# include <linux/cpufeature.h>
# 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>
2019-03-12 22:12:50 -07:00
# include <crypto/internal/simd.h>
2016-12-05 18:42:25 +00:00
# include <asm/neon.h>
2017-07-24 11:28:06 +01:00
# include <asm/simd.h>
2016-12-05 18:42:25 +00:00
# define CRC_T10DIF_PMULL_CHUNK_SIZE 16U
2019-01-30 20:42:42 -08:00
asmlinkage u16 crc_t10dif_pmull_p8 ( u16 init_crc , const u8 * buf , size_t len ) ;
asmlinkage u16 crc_t10dif_pmull_p64 ( u16 init_crc , const u8 * buf , size_t len ) ;
2018-08-27 17:38:11 +02:00
2016-12-05 18:42:25 +00:00
static int crct10dif_init ( struct shash_desc * desc )
{
u16 * crc = shash_desc_ctx ( desc ) ;
* crc = 0 ;
return 0 ;
}
2019-01-25 10:36:26 +01:00
static int crct10dif_update_pmull_p8 ( struct shash_desc * desc , const u8 * data ,
unsigned int length )
{
u16 * crc = shash_desc_ctx ( desc ) ;
2019-03-12 22:12:50 -07:00
if ( length > = CRC_T10DIF_PMULL_CHUNK_SIZE & & crypto_simd_usable ( ) ) {
2021-02-03 12:36:25 +01:00
do {
unsigned int chunk = length ;
if ( chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE )
chunk = SZ_4K ;
kernel_neon_begin ( ) ;
* crc = crc_t10dif_pmull_p8 ( * crc , data , chunk ) ;
kernel_neon_end ( ) ;
data + = chunk ;
length - = chunk ;
} while ( length ) ;
2019-01-25 10:36:26 +01:00
} else {
* crc = crc_t10dif_generic ( * crc , data , length ) ;
}
return 0 ;
}
static int crct10dif_update_pmull_p64 ( struct shash_desc * desc , const u8 * data ,
2016-12-05 18:42:25 +00:00
unsigned int length )
{
u16 * crc = shash_desc_ctx ( desc ) ;
2019-03-12 22:12:50 -07:00
if ( length > = CRC_T10DIF_PMULL_CHUNK_SIZE & & crypto_simd_usable ( ) ) {
2021-02-03 12:36:25 +01:00
do {
unsigned int chunk = length ;
if ( chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE )
chunk = SZ_4K ;
kernel_neon_begin ( ) ;
* crc = crc_t10dif_pmull_p64 ( * crc , data , chunk ) ;
kernel_neon_end ( ) ;
data + = chunk ;
length - = chunk ;
} while ( length ) ;
2019-01-27 10:16:53 +01:00
} else {
* crc = crc_t10dif_generic ( * crc , data , length ) ;
2016-12-05 18:42:25 +00:00
}
return 0 ;
}
static int crct10dif_final ( struct shash_desc * desc , u8 * out )
{
u16 * crc = shash_desc_ctx ( desc ) ;
* ( u16 * ) out = * crc ;
return 0 ;
}
2019-01-25 10:36:26 +01:00
static struct shash_alg crc_t10dif_alg [ ] = { {
2016-12-05 18:42:25 +00:00
. digestsize = CRC_T10DIF_DIGEST_SIZE ,
. init = crct10dif_init ,
2019-01-25 10:36:26 +01:00
. update = crct10dif_update_pmull_p8 ,
. final = crct10dif_final ,
. descsize = CRC_T10DIF_DIGEST_SIZE ,
. base . cra_name = " crct10dif " ,
. base . cra_driver_name = " crct10dif-arm64-neon " ,
. base . cra_priority = 100 ,
. base . cra_blocksize = CRC_T10DIF_BLOCK_SIZE ,
. base . cra_module = THIS_MODULE ,
} , {
. digestsize = CRC_T10DIF_DIGEST_SIZE ,
. init = crct10dif_init ,
. update = crct10dif_update_pmull_p64 ,
2016-12-05 18:42:25 +00:00
. final = crct10dif_final ,
. descsize = CRC_T10DIF_DIGEST_SIZE ,
. base . cra_name = " crct10dif " ,
. base . cra_driver_name = " crct10dif-arm64-ce " ,
. base . cra_priority = 200 ,
. base . cra_blocksize = CRC_T10DIF_BLOCK_SIZE ,
. base . cra_module = THIS_MODULE ,
2019-01-25 10:36:26 +01:00
} } ;
2016-12-05 18:42:25 +00:00
static int __init crc_t10dif_mod_init ( void )
{
2019-04-09 10:52:40 +01:00
if ( cpu_have_named_feature ( PMULL ) )
2019-01-25 10:36:26 +01:00
return crypto_register_shashes ( crc_t10dif_alg ,
ARRAY_SIZE ( crc_t10dif_alg ) ) ;
2018-08-27 17:38:12 +02:00
else
2019-01-25 10:36:26 +01:00
/* only register the first array element */
return crypto_register_shash ( crc_t10dif_alg ) ;
2016-12-05 18:42:25 +00:00
}
static void __exit crc_t10dif_mod_exit ( void )
{
2019-04-09 10:52:40 +01:00
if ( cpu_have_named_feature ( PMULL ) )
2019-01-25 10:36:26 +01:00
crypto_unregister_shashes ( crc_t10dif_alg ,
ARRAY_SIZE ( crc_t10dif_alg ) ) ;
else
crypto_unregister_shash ( crc_t10dif_alg ) ;
2016-12-05 18:42:25 +00:00
}
2018-08-27 17:38:12 +02:00
module_cpu_feature_match ( ASIMD , crc_t10dif_mod_init ) ;
2016-12-05 18:42:25 +00:00
module_exit ( crc_t10dif_mod_exit ) ;
MODULE_AUTHOR ( " Ard Biesheuvel <ard.biesheuvel@linaro.org> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2018-08-27 17:38:12 +02:00
MODULE_ALIAS_CRYPTO ( " crct10dif " ) ;
MODULE_ALIAS_CRYPTO ( " crct10dif-arm64-ce " ) ;