crypto: add rocksoft 64b crc guard tag framework

Hardware specific features may be able to calculate a crc64, so provide
a framework for drivers to register their implementation. If nothing is
registered, fallback to the generic table lookup implementation. The
implementation is modeled after the crct10dif equivalent.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20220303201312.3255347-7-kbusch@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Keith Busch 2022-03-03 12:13:10 -08:00 committed by Jens Axboe
parent cbc0a40e17
commit f3813f4b28
9 changed files with 258 additions and 0 deletions

View File

@ -735,6 +735,11 @@ config CRYPTO_CRCT10DIF_VPMSUM
multiply-sum (vpmsum) instructions, introduced in POWER8. Enable on multiply-sum (vpmsum) instructions, introduced in POWER8. Enable on
POWER8 and newer processors for improved performance. POWER8 and newer processors for improved performance.
config CRYPTO_CRC64_ROCKSOFT
tristate "Rocksoft Model CRC64 algorithm"
depends on CRC64
select CRYPTO_HASH
config CRYPTO_VPMSUM_TESTER config CRYPTO_VPMSUM_TESTER
tristate "Powerpc64 vpmsum hardware acceleration tester" tristate "Powerpc64 vpmsum hardware acceleration tester"
depends on CRYPTO_CRCT10DIF_VPMSUM && CRYPTO_CRC32C_VPMSUM depends on CRYPTO_CRCT10DIF_VPMSUM && CRYPTO_CRC32C_VPMSUM

View File

@ -152,6 +152,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o
obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o
obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT) += crc64_rocksoft_generic.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o
obj-$(CONFIG_CRYPTO_LZ4) += lz4.o obj-$(CONFIG_CRYPTO_LZ4) += lz4.o

View File

@ -0,0 +1,89 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/crc64.h>
#include <linux/module.h>
#include <crypto/internal/hash.h>
#include <asm/unaligned.h>
static int chksum_init(struct shash_desc *desc)
{
u64 *crc = shash_desc_ctx(desc);
*crc = 0;
return 0;
}
static int chksum_update(struct shash_desc *desc, const u8 *data,
unsigned int length)
{
u64 *crc = shash_desc_ctx(desc);
*crc = crc64_rocksoft_generic(*crc, data, length);
return 0;
}
static int chksum_final(struct shash_desc *desc, u8 *out)
{
u64 *crc = shash_desc_ctx(desc);
put_unaligned_le64(*crc, out);
return 0;
}
static int __chksum_finup(u64 crc, const u8 *data, unsigned int len, u8 *out)
{
crc = crc64_rocksoft_generic(crc, data, len);
put_unaligned_le64(crc, out);
return 0;
}
static int chksum_finup(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *out)
{
u64 *crc = shash_desc_ctx(desc);
return __chksum_finup(*crc, data, len, out);
}
static int chksum_digest(struct shash_desc *desc, const u8 *data,
unsigned int length, u8 *out)
{
return __chksum_finup(0, data, length, out);
}
static struct shash_alg alg = {
.digestsize = sizeof(u64),
.init = chksum_init,
.update = chksum_update,
.final = chksum_final,
.finup = chksum_finup,
.digest = chksum_digest,
.descsize = sizeof(u64),
.base = {
.cra_name = CRC64_ROCKSOFT_STRING,
.cra_driver_name = "crc64-rocksoft-generic",
.cra_priority = 200,
.cra_blocksize = 1,
.cra_module = THIS_MODULE,
}
};
static int __init crc64_rocksoft_init(void)
{
return crypto_register_shash(&alg);
}
static void __exit crc64_rocksoft_exit(void)
{
crypto_unregister_shash(&alg);
}
module_init(crc64_rocksoft_init);
module_exit(crc64_rocksoft_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Rocksoft model CRC64 calculation.");
MODULE_ALIAS_CRYPTO("crc64-rocksoft");
MODULE_ALIAS_CRYPTO("crc64-rocksoft-generic");

View File

@ -4526,6 +4526,13 @@ static const struct alg_test_desc alg_test_descs[] = {
.suite = { .suite = {
.hash = __VECS(crc32c_tv_template) .hash = __VECS(crc32c_tv_template)
} }
}, {
.alg = "crc64-rocksoft",
.test = alg_test_hash,
.fips_allowed = 1,
.suite = {
.hash = __VECS(crc64_rocksoft_tv_template)
}
}, { }, {
.alg = "crct10dif", .alg = "crct10dif",
.test = alg_test_hash, .test = alg_test_hash,

View File

@ -3679,6 +3679,21 @@ static const struct hash_testvec rmd160_tv_template[] = {
} }
}; };
static const u8 zeroes[4096] = { [0 ... 4095] = 0 };
static const u8 ones[4096] = { [0 ... 4095] = 0xff };
static const struct hash_testvec crc64_rocksoft_tv_template[] = {
{
.plaintext = zeroes,
.psize = 4096,
.digest = (u8 *)(u64[]){ 0x6482d367eb22b64eull },
}, {
.plaintext = ones,
.psize = 4096,
.digest = (u8 *)(u64[]){ 0xc0ddba7302eca3acull },
}
};
static const struct hash_testvec crct10dif_tv_template[] = { static const struct hash_testvec crct10dif_tv_template[] = {
{ {
.plaintext = "abc", .plaintext = "abc",

View File

@ -7,7 +7,12 @@
#include <linux/types.h> #include <linux/types.h>
#define CRC64_ROCKSOFT_STRING "crc64-rocksoft"
u64 __pure crc64_be(u64 crc, const void *p, size_t len); u64 __pure crc64_be(u64 crc, const void *p, size_t len);
u64 __pure crc64_rocksoft_generic(u64 crc, const void *p, size_t len); u64 __pure crc64_rocksoft_generic(u64 crc, const void *p, size_t len);
u64 crc64_rocksoft(const unsigned char *buffer, size_t len);
u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len);
#endif /* _LINUX_CRC64_H */ #endif /* _LINUX_CRC64_H */

View File

@ -145,6 +145,15 @@ config CRC_T10DIF
kernel tree needs to calculate CRC checks for use with the kernel tree needs to calculate CRC checks for use with the
SCSI data integrity subsystem. SCSI data integrity subsystem.
config CRC64_ROCKSOFT
tristate "CRC calculation for the Rocksoft model CRC64"
select CRC64
select CRYPTO
select CRYPTO_CRC64_ROCKSOFT
help
This option provides a CRC64 API to a registered crypto driver.
This is used with the block layer's data integrity subsystem.
config CRC_ITU_T config CRC_ITU_T
tristate "CRC ITU-T V.41 functions" tristate "CRC ITU-T V.41 functions"
help help

View File

@ -175,6 +175,7 @@ obj-$(CONFIG_CRC4) += crc4.o
obj-$(CONFIG_CRC7) += crc7.o obj-$(CONFIG_CRC7) += crc7.o
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
obj-$(CONFIG_CRC8) += crc8.o obj-$(CONFIG_CRC8) += crc8.o
obj-$(CONFIG_CRC64_ROCKSOFT) += crc64-rocksoft.o
obj-$(CONFIG_XXHASH) += xxhash.o obj-$(CONFIG_XXHASH) += xxhash.o
obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o

126
lib/crc64-rocksoft.c Normal file
View File

@ -0,0 +1,126 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/module.h>
#include <linux/crc64.h>
#include <linux/err.h>
#include <linux/init.h>
#include <crypto/hash.h>
#include <crypto/algapi.h>
#include <linux/static_key.h>
#include <linux/notifier.h>
static struct crypto_shash __rcu *crc64_rocksoft_tfm;
static DEFINE_STATIC_KEY_TRUE(crc64_rocksoft_fallback);
static DEFINE_MUTEX(crc64_rocksoft_mutex);
static struct work_struct crc64_rocksoft_rehash_work;
static int crc64_rocksoft_notify(struct notifier_block *self, unsigned long val, void *data)
{
struct crypto_alg *alg = data;
if (val != CRYPTO_MSG_ALG_LOADED ||
strcmp(alg->cra_name, CRC64_ROCKSOFT_STRING))
return NOTIFY_DONE;
schedule_work(&crc64_rocksoft_rehash_work);
return NOTIFY_OK;
}
static void crc64_rocksoft_rehash(struct work_struct *work)
{
struct crypto_shash *new, *old;
mutex_lock(&crc64_rocksoft_mutex);
old = rcu_dereference_protected(crc64_rocksoft_tfm,
lockdep_is_held(&crc64_rocksoft_mutex));
new = crypto_alloc_shash(CRC64_ROCKSOFT_STRING, 0, 0);
if (IS_ERR(new)) {
mutex_unlock(&crc64_rocksoft_mutex);
return;
}
rcu_assign_pointer(crc64_rocksoft_tfm, new);
mutex_unlock(&crc64_rocksoft_mutex);
if (old) {
synchronize_rcu();
crypto_free_shash(old);
} else {
static_branch_disable(&crc64_rocksoft_fallback);
}
}
static struct notifier_block crc64_rocksoft_nb = {
.notifier_call = crc64_rocksoft_notify,
};
u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len)
{
struct {
struct shash_desc shash;
u64 crc;
} desc;
int err;
if (static_branch_unlikely(&crc64_rocksoft_fallback))
return crc64_rocksoft_generic(crc, buffer, len);
rcu_read_lock();
desc.shash.tfm = rcu_dereference(crc64_rocksoft_tfm);
desc.crc = crc;
err = crypto_shash_update(&desc.shash, buffer, len);
rcu_read_unlock();
BUG_ON(err);
return desc.crc;
}
EXPORT_SYMBOL_GPL(crc64_rocksoft_update);
u64 crc64_rocksoft(const unsigned char *buffer, size_t len)
{
return crc64_rocksoft_update(0, buffer, len);
}
EXPORT_SYMBOL_GPL(crc64_rocksoft);
static int __init crc64_rocksoft_mod_init(void)
{
INIT_WORK(&crc64_rocksoft_rehash_work, crc64_rocksoft_rehash);
crypto_register_notifier(&crc64_rocksoft_nb);
crc64_rocksoft_rehash(&crc64_rocksoft_rehash_work);
return 0;
}
static void __exit crc64_rocksoft_mod_fini(void)
{
crypto_unregister_notifier(&crc64_rocksoft_nb);
cancel_work_sync(&crc64_rocksoft_rehash_work);
crypto_free_shash(rcu_dereference_protected(crc64_rocksoft_tfm, 1));
}
module_init(crc64_rocksoft_mod_init);
module_exit(crc64_rocksoft_mod_fini);
static int crc64_rocksoft_transform_show(char *buffer, const struct kernel_param *kp)
{
struct crypto_shash *tfm;
int len;
if (static_branch_unlikely(&crc64_rocksoft_fallback))
return sprintf(buffer, "fallback\n");
rcu_read_lock();
tfm = rcu_dereference(crc64_rocksoft_tfm);
len = snprintf(buffer, PAGE_SIZE, "%s\n",
crypto_shash_driver_name(tfm));
rcu_read_unlock();
return len;
}
module_param_call(transform, NULL, crc64_rocksoft_transform_show, NULL, 0444);
MODULE_AUTHOR("Keith Busch <kbusch@kernel.org>");
MODULE_DESCRIPTION("Rocksoft model CRC64 calculation (library API)");
MODULE_LICENSE("GPL");
MODULE_SOFTDEP("pre: crc64");