162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CRC vpmsum tester 462306a36Sopenharmony_ci * Copyright 2017 Daniel Axtens, IBM Corporation. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/crc-t10dif.h> 862306a36Sopenharmony_ci#include <linux/crc32.h> 962306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/random.h> 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/cpufeature.h> 1662306a36Sopenharmony_ci#include <asm/switch_to.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic unsigned long iterations = 10000; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define MAX_CRC_LENGTH 65535 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int __init crc_test_init(void) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci u16 crc16 = 0, verify16 = 0; 2662306a36Sopenharmony_ci __le32 verify32le = 0; 2762306a36Sopenharmony_ci unsigned char *data; 2862306a36Sopenharmony_ci u32 verify32 = 0; 2962306a36Sopenharmony_ci unsigned long i; 3062306a36Sopenharmony_ci __le32 crc32; 3162306a36Sopenharmony_ci int ret; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci struct crypto_shash *crct10dif_tfm; 3462306a36Sopenharmony_ci struct crypto_shash *crc32c_tfm; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3762306a36Sopenharmony_ci return -ENODEV; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci data = kmalloc(MAX_CRC_LENGTH, GFP_KERNEL); 4062306a36Sopenharmony_ci if (!data) 4162306a36Sopenharmony_ci return -ENOMEM; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (IS_ERR(crct10dif_tfm)) { 4662306a36Sopenharmony_ci pr_err("Error allocating crc-t10dif\n"); 4762306a36Sopenharmony_ci goto free_buf; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci crc32c_tfm = crypto_alloc_shash("crc32c", 0, 0); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (IS_ERR(crc32c_tfm)) { 5362306a36Sopenharmony_ci pr_err("Error allocating crc32c\n"); 5462306a36Sopenharmony_ci goto free_16; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci do { 5862306a36Sopenharmony_ci SHASH_DESC_ON_STACK(crct10dif_shash, crct10dif_tfm); 5962306a36Sopenharmony_ci SHASH_DESC_ON_STACK(crc32c_shash, crc32c_tfm); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci crct10dif_shash->tfm = crct10dif_tfm; 6262306a36Sopenharmony_ci ret = crypto_shash_init(crct10dif_shash); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (ret) { 6562306a36Sopenharmony_ci pr_err("Error initing crc-t10dif\n"); 6662306a36Sopenharmony_ci goto free_32; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci crc32c_shash->tfm = crc32c_tfm; 7162306a36Sopenharmony_ci ret = crypto_shash_init(crc32c_shash); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (ret) { 7462306a36Sopenharmony_ci pr_err("Error initing crc32c\n"); 7562306a36Sopenharmony_ci goto free_32; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci pr_info("crc-vpmsum_test begins, %lu iterations\n", iterations); 7962306a36Sopenharmony_ci for (i=0; i<iterations; i++) { 8062306a36Sopenharmony_ci size_t offset = get_random_u32_below(16); 8162306a36Sopenharmony_ci size_t len = get_random_u32_below(MAX_CRC_LENGTH); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (len <= offset) 8462306a36Sopenharmony_ci continue; 8562306a36Sopenharmony_ci get_random_bytes(data, len); 8662306a36Sopenharmony_ci len -= offset; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci crypto_shash_update(crct10dif_shash, data+offset, len); 8962306a36Sopenharmony_ci crypto_shash_final(crct10dif_shash, (u8 *)(&crc16)); 9062306a36Sopenharmony_ci verify16 = crc_t10dif_generic(verify16, data+offset, len); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (crc16 != verify16) { 9462306a36Sopenharmony_ci pr_err("FAILURE in CRC16: got 0x%04x expected 0x%04x (len %lu)\n", 9562306a36Sopenharmony_ci crc16, verify16, len); 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci crypto_shash_update(crc32c_shash, data+offset, len); 10062306a36Sopenharmony_ci crypto_shash_final(crc32c_shash, (u8 *)(&crc32)); 10162306a36Sopenharmony_ci verify32 = le32_to_cpu(verify32le); 10262306a36Sopenharmony_ci verify32le = ~cpu_to_le32(__crc32c_le(~verify32, data+offset, len)); 10362306a36Sopenharmony_ci if (crc32 != verify32le) { 10462306a36Sopenharmony_ci pr_err("FAILURE in CRC32: got 0x%08x expected 0x%08x (len %lu)\n", 10562306a36Sopenharmony_ci crc32, verify32, len); 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci cond_resched(); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci pr_info("crc-vpmsum_test done, completed %lu iterations\n", i); 11162306a36Sopenharmony_ci } while (0); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cifree_32: 11462306a36Sopenharmony_ci crypto_free_shash(crc32c_tfm); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cifree_16: 11762306a36Sopenharmony_ci crypto_free_shash(crct10dif_tfm); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cifree_buf: 12062306a36Sopenharmony_ci kfree(data); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void __exit crc_test_exit(void) {} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cimodule_init(crc_test_init); 12862306a36Sopenharmony_cimodule_exit(crc_test_exit); 12962306a36Sopenharmony_cimodule_param(iterations, long, 0400); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Axtens <dja@axtens.net>"); 13262306a36Sopenharmony_ciMODULE_DESCRIPTION("Vector polynomial multiply-sum CRC tester"); 13362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 134