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 len, offset; 82 83 get_random_bytes(data, MAX_CRC_LENGTH); 84 get_random_bytes(&len, sizeof(len)); 85 get_random_bytes(&offset, sizeof(offset)); 86 87 len %= MAX_CRC_LENGTH; 88 offset &= 15; 89 if (len <= offset) 90 continue; 91 len -= offset; 92 93 crypto_shash_update(crct10dif_shash, data+offset, len); 94 crypto_shash_final(crct10dif_shash, (u8 *)(&crc16)); 95 verify16 = crc_t10dif_generic(verify16, data+offset, len); 96 97 98 if (crc16 != verify16) { 99 pr_err("FAILURE in CRC16: got 0x%04x expected 0x%04x (len %lu)\n", 100 crc16, verify16, len); 101 break; 102 } 103 104 crypto_shash_update(crc32c_shash, data+offset, len); 105 crypto_shash_final(crc32c_shash, (u8 *)(&crc32)); 106 verify32 = le32_to_cpu(verify32le); 107 verify32le = ~cpu_to_le32(__crc32c_le(~verify32, data+offset, len)); 108 if (crc32 != (u32)verify32le) { 109 pr_err("FAILURE in CRC32: got 0x%08x expected 0x%08x (len %lu)\n", 110 crc32, verify32, len); 111 break; 112 } 113 } 114 pr_info("crc-vpmsum_test done, completed %lu iterations\n", i); 115 } while (0); 116 117 free_32: 118 crypto_free_shash(crc32c_tfm); 119 120 free_16: 121 crypto_free_shash(crct10dif_tfm); 122 123 free_buf: 124 kfree(data); 125 126 return 0; 127 } 128 129 static void __exit crc_test_exit(void) {} 130 131 module_init(crc_test_init); 132 module_exit(crc_test_exit); 133 module_param(iterations, long, 0400); 134 135 MODULE_AUTHOR("Daniel Axtens <dja@axtens.net>"); 136 MODULE_DESCRIPTION("Vector polynomial multiply-sum CRC tester"); 137 MODULE_LICENSE("GPL"); 138