In order to retain the ability to check accelerated implementations of
CRC-T10DIF against the generic C implementation, expose both via the
generic crypto API shash driver. This relies on the arch specific version
to be registered beforehand - this will generally be the case, given that
the modules in question are autoloaded via CPU feature matching, but
let's use a module soft-dependency as well to trigger a load of such
modules if they exist on the system.

Signed-off-by: Ard Biesheuvel <a...@kernel.org>
---
 crypto/crct10dif_generic.c | 100 ++++++++++++++------
 1 file changed, 72 insertions(+), 28 deletions(-)

diff --git a/crypto/crct10dif_generic.c b/crypto/crct10dif_generic.c
index e843982073bb..7878eda7513e 100644
--- a/crypto/crct10dif_generic.c
+++ b/crypto/crct10dif_generic.c
@@ -48,8 +48,8 @@ static int chksum_init(struct shash_desc *desc)
        return 0;
 }
 
-static int chksum_update(struct shash_desc *desc, const u8 *data,
-                        unsigned int length)
+static int chksum_generic_update(struct shash_desc *desc, const u8 *data,
+                                unsigned int length)
 {
        struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
@@ -65,54 +65,97 @@ static int chksum_final(struct shash_desc *desc, u8 *out)
        return 0;
 }
 
-static int __chksum_finup(__u16 crc, const u8 *data, unsigned int len, u8 *out)
+static int __chksum_generic_finup(__u16 crc, const u8 *data, unsigned int len,
+                                 u8 *out)
 {
        *(__u16 *)out = crc_t10dif_generic(crc, data, len);
        return 0;
 }
 
-static int chksum_finup(struct shash_desc *desc, const u8 *data,
-                       unsigned int len, u8 *out)
+static int chksum_generic_finup(struct shash_desc *desc, const u8 *data,
+                               unsigned int len, u8 *out)
 {
        struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-       return __chksum_finup(ctx->crc, data, len, out);
+       return __chksum_generic_finup(ctx->crc, data, len, out);
 }
 
-static int chksum_digest(struct shash_desc *desc, const u8 *data,
-                        unsigned int length, u8 *out)
+static int chksum_generic_digest(struct shash_desc *desc, const u8 *data,
+                                unsigned int length, u8 *out)
 {
-       return __chksum_finup(0, data, length, out);
+       return __chksum_generic_finup(0, data, length, out);
 }
 
-static struct shash_alg alg = {
-       .digestsize             =       CRC_T10DIF_DIGEST_SIZE,
-       .init           =       chksum_init,
-       .update         =       chksum_update,
-       .final          =       chksum_final,
-       .finup          =       chksum_finup,
-       .digest         =       chksum_digest,
-       .descsize               =       sizeof(struct chksum_desc_ctx),
-       .base                   =       {
-               .cra_name               =       "crct10dif",
-               .cra_driver_name        =       "crct10dif-generic",
-               .cra_priority           =       100,
-               .cra_blocksize          =       CRC_T10DIF_BLOCK_SIZE,
-               .cra_module             =       THIS_MODULE,
-       }
-};
+static int chksum_arch_update(struct shash_desc *desc, const u8 *data,
+                             unsigned int length)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+       ctx->crc = crc_t10dif_update(ctx->crc, data, length);
+       return 0;
+}
+
+static int __chksum_arch_finup(__u16 crc, const u8 *data, unsigned int len,
+                              u8 *out)
+{
+       *(__u16 *)out = crc_t10dif_update(crc, data, len);
+       return 0;
+}
+
+static int chksum_arch_finup(struct shash_desc *desc, const u8 *data,
+                            unsigned int len, u8 *out)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+       return __chksum_arch_finup(ctx->crc, data, len, out);
+}
+
+static int chksum_arch_digest(struct shash_desc *desc, const u8 *data,
+                             unsigned int length, u8 *out)
+{
+       return __chksum_arch_finup(0, data, length, out);
+}
+
+static struct shash_alg algs[] = {{
+       .digestsize             = CRC_T10DIF_DIGEST_SIZE,
+       .init                   = chksum_init,
+       .update                 = chksum_generic_update,
+       .final                  = chksum_final,
+       .finup                  = chksum_generic_finup,
+       .digest                 = chksum_generic_digest,
+       .descsize               = sizeof(struct chksum_desc_ctx),
+
+       .base.cra_name          = "crct10dif",
+       .base.cra_driver_name   = "crct10dif-generic",
+       .base.cra_blocksize     = CRC_T10DIF_BLOCK_SIZE,
+       .base.cra_module        = THIS_MODULE,
+}, {
+       .digestsize             = CRC_T10DIF_DIGEST_SIZE,
+       .init                   = chksum_init,
+       .update                 = chksum_arch_update,
+       .final                  = chksum_final,
+       .finup                  = chksum_arch_finup,
+       .digest                 = chksum_arch_digest,
+       .descsize               = sizeof(struct chksum_desc_ctx),
+
+       .base.cra_name          = "crct10dif",
+       .base.cra_driver_name   = "crct10dif-arch",
+       .base.cra_priority      = 100,
+       .base.cra_blocksize     = CRC_T10DIF_BLOCK_SIZE,
+       .base.cra_module        = THIS_MODULE,
+}};
 
 static int __init crct10dif_mod_init(void)
 {
-       return crypto_register_shash(&alg);
+       return crypto_register_shashes(algs, ARRAY_SIZE(algs));
 }
 
 static void __exit crct10dif_mod_fini(void)
 {
-       crypto_unregister_shash(&alg);
+       crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
 }
 
-subsys_initcall(crct10dif_mod_init);
+module_init(crct10dif_mod_init);
 module_exit(crct10dif_mod_fini);
 
 MODULE_AUTHOR("Tim Chen <tim.c.c...@linux.intel.com>");
@@ -120,3 +163,4 @@ MODULE_DESCRIPTION("T10 DIF CRC calculation.");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("crct10dif");
 MODULE_ALIAS_CRYPTO("crct10dif-generic");
+MODULE_SOFTDEP("pre: crct10dif-arch");
-- 
2.17.1

Reply via email to