forked from Minki/linux
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:
parent
cbc0a40e17
commit
f3813f4b28
@ -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
|
||||||
|
@ -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
|
||||||
|
89
crypto/crc64_rocksoft_generic.c
Normal file
89
crypto/crc64_rocksoft_generic.c
Normal 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");
|
@ -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,
|
||||||
|
@ -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",
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
|
@ -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
126
lib/crc64-rocksoft.c
Normal 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");
|
Loading…
Reference in New Issue
Block a user