2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2017-03-15 23:37:37 +11:00
/*
* CRC vpmsum tester
* Copyright 2017 Daniel Axtens , IBM Corporation .
*/
# include <linux/crc-t10dif.h>
# include <linux/crc32.h>
# include <crypto/internal/hash.h>
# include <linux/init.h>
# include <linux/module.h>
2020-08-19 21:58:20 +10:00
# include <linux/random.h>
2017-03-15 23:37:37 +11:00
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/cpufeature.h>
# include <asm/switch_to.h>
static unsigned long iterations = 10000 ;
# define MAX_CRC_LENGTH 65535
static int __init crc_test_init ( void )
{
u16 crc16 = 0 , verify16 = 0 ;
__le32 verify32le = 0 ;
unsigned char * data ;
2020-08-25 11:52:02 +10:00
u32 verify32 = 0 ;
2017-03-15 23:37:37 +11:00
unsigned long i ;
2020-08-25 11:52:02 +10:00
__le32 crc32 ;
2017-03-15 23:37:37 +11:00
int ret ;
struct crypto_shash * crct10dif_tfm ;
struct crypto_shash * crc32c_tfm ;
if ( ! cpu_has_feature ( CPU_FTR_ARCH_207S ) )
return - ENODEV ;
data = kmalloc ( MAX_CRC_LENGTH , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
crct10dif_tfm = crypto_alloc_shash ( " crct10dif " , 0 , 0 ) ;
if ( IS_ERR ( crct10dif_tfm ) ) {
pr_err ( " Error allocating crc-t10dif \n " ) ;
goto free_buf ;
}
crc32c_tfm = crypto_alloc_shash ( " crc32c " , 0 , 0 ) ;
if ( IS_ERR ( crc32c_tfm ) ) {
pr_err ( " Error allocating crc32c \n " ) ;
goto free_16 ;
}
do {
SHASH_DESC_ON_STACK ( crct10dif_shash , crct10dif_tfm ) ;
SHASH_DESC_ON_STACK ( crc32c_shash , crc32c_tfm ) ;
crct10dif_shash - > tfm = crct10dif_tfm ;
ret = crypto_shash_init ( crct10dif_shash ) ;
if ( ret ) {
pr_err ( " Error initing crc-t10dif \n " ) ;
goto free_32 ;
}
crc32c_shash - > tfm = crc32c_tfm ;
ret = crypto_shash_init ( crc32c_shash ) ;
if ( ret ) {
pr_err ( " Error initing crc32c \n " ) ;
goto free_32 ;
}
pr_info ( " crc-vpmsum_test begins, %lu iterations \n " , iterations ) ;
for ( i = 0 ; i < iterations ; i + + ) {
2019-03-21 10:42:22 +00:00
size_t offset = prandom_u32_max ( 16 ) ;
size_t len = prandom_u32_max ( MAX_CRC_LENGTH ) ;
2017-03-15 23:37:37 +11:00
if ( len < = offset )
continue ;
2019-03-21 10:42:22 +00:00
prandom_bytes ( data , len ) ;
2017-03-15 23:37:37 +11:00
len - = offset ;
crypto_shash_update ( crct10dif_shash , data + offset , len ) ;
crypto_shash_final ( crct10dif_shash , ( u8 * ) ( & crc16 ) ) ;
verify16 = crc_t10dif_generic ( verify16 , data + offset , len ) ;
if ( crc16 ! = verify16 ) {
pr_err ( " FAILURE in CRC16: got 0x%04x expected 0x%04x (len %lu) \n " ,
crc16 , verify16 , len ) ;
break ;
}
crypto_shash_update ( crc32c_shash , data + offset , len ) ;
crypto_shash_final ( crc32c_shash , ( u8 * ) ( & crc32 ) ) ;
verify32 = le32_to_cpu ( verify32le ) ;
verify32le = ~ cpu_to_le32 ( __crc32c_le ( ~ verify32 , data + offset , len ) ) ;
2020-08-25 11:52:02 +10:00
if ( crc32 ! = verify32le ) {
2017-03-15 23:37:37 +11:00
pr_err ( " FAILURE in CRC32: got 0x%08x expected 0x%08x (len %lu) \n " ,
crc32 , verify32 , len ) ;
break ;
}
2019-11-03 23:33:56 +00:00
cond_resched ( ) ;
2017-03-15 23:37:37 +11:00
}
pr_info ( " crc-vpmsum_test done, completed %lu iterations \n " , i ) ;
} while ( 0 ) ;
free_32 :
crypto_free_shash ( crc32c_tfm ) ;
free_16 :
crypto_free_shash ( crct10dif_tfm ) ;
free_buf :
kfree ( data ) ;
return 0 ;
}
static void __exit crc_test_exit ( void ) { }
module_init ( crc_test_init ) ;
module_exit ( crc_test_exit ) ;
module_param ( iterations , long , 0400 ) ;
MODULE_AUTHOR ( " Daniel Axtens <dja@axtens.net> " ) ;
MODULE_DESCRIPTION ( " Vector polynomial multiply-sum CRC tester " ) ;
MODULE_LICENSE ( " GPL " ) ;