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