1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * CRC vpmsum tester 4 * Copyright 2017 Daniel Axtens, IBM Corporation. 5 */ 6 7 #include <linux/crc-t10dif.h> 8 #include <linux/crc32.h> 9 #include <crypto/internal/hash.h> 10 #include <linux/init.h> 11 #include <linux/module.h> 12 #include <linux/string.h> 13 #include <linux/kernel.h> 14 #include <linux/cpufeature.h> 15 #include <asm/switch_to.h> 16 17 static unsigned long iterations = 10000; 18 19 #define MAX_CRC_LENGTH 65535 20 21 22 static int __init crc_test_init(void) 23 { 24 u16 crc16 = 0, verify16 = 0; 25 u32 crc32 = 0, verify32 = 0; 26 __le32 verify32le = 0; 27 unsigned char *data; 28 unsigned long i; 29 int ret; 30 31 struct crypto_shash *crct10dif_tfm; 32 struct crypto_shash *crc32c_tfm; 33 34 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 35 return -ENODEV; 36 37 data = kmalloc(MAX_CRC_LENGTH, GFP_KERNEL); 38 if (!data) 39 return -ENOMEM; 40 41 crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0); 42 43 if (IS_ERR(crct10dif_tfm)) { 44 pr_err("Error allocating crc-t10dif\n"); 45 goto free_buf; 46 } 47 48 crc32c_tfm = crypto_alloc_shash("crc32c", 0, 0); 49 50 if (IS_ERR(crc32c_tfm)) { 51 pr_err("Error allocating crc32c\n"); 52 goto free_16; 53 } 54 55 do { 56 SHASH_DESC_ON_STACK(crct10dif_shash, crct10dif_tfm); 57 SHASH_DESC_ON_STACK(crc32c_shash, crc32c_tfm); 58 59 crct10dif_shash->tfm = crct10dif_tfm; 60 ret = crypto_shash_init(crct10dif_shash); 61 62 if (ret) { 63 pr_err("Error initing crc-t10dif\n"); 64 goto free_32; 65 } 66 67 68 crc32c_shash->tfm = crc32c_tfm; 69 ret = crypto_shash_init(crc32c_shash); 70 71 if (ret) { 72 pr_err("Error initing crc32c\n"); 73 goto free_32; 74 } 75 76 pr_info("crc-vpmsum_test begins, %lu iterations\n", iterations); 77 for (i=0; i<iterations; i++) { 78 size_t offset = prandom_u32_max(16); 79 size_t len = prandom_u32_max(MAX_CRC_LENGTH); 80 81 if (len <= offset) 82 continue; 83 prandom_bytes(data, len); 84 len -= offset; 85 86 crypto_shash_update(crct10dif_shash, data+offset, len); 87 crypto_shash_final(crct10dif_shash, (u8 *)(&crc16)); 88 verify16 = crc_t10dif_generic(verify16, data+offset, len); 89 90 91 if (crc16 != verify16) { 92 pr_err("FAILURE in CRC16: got 0x%04x expected 0x%04x (len %lu)\n", 93 crc16, verify16, len); 94 break; 95 } 96 97 crypto_shash_update(crc32c_shash, data+offset, len); 98 crypto_shash_final(crc32c_shash, (u8 *)(&crc32)); 99 verify32 = le32_to_cpu(verify32le); 100 verify32le = ~cpu_to_le32(__crc32c_le(~verify32, data+offset, len)); 101 if (crc32 != (u32)verify32le) { 102 pr_err("FAILURE in CRC32: got 0x%08x expected 0x%08x (len %lu)\n", 103 crc32, verify32, len); 104 break; 105 } 106 } 107 pr_info("crc-vpmsum_test done, completed %lu iterations\n", i); 108 } while (0); 109 110 free_32: 111 crypto_free_shash(crc32c_tfm); 112 113 free_16: 114 crypto_free_shash(crct10dif_tfm); 115 116 free_buf: 117 kfree(data); 118 119 return 0; 120 } 121 122 static void __exit crc_test_exit(void) {} 123 124 module_init(crc_test_init); 125 module_exit(crc_test_exit); 126 module_param(iterations, long, 0400); 127 128 MODULE_AUTHOR("Daniel Axtens <dja@axtens.net>"); 129 MODULE_DESCRIPTION("Vector polynomial multiply-sum CRC tester"); 130 MODULE_LICENSE("GPL"); 131