s390/crc32: expose CRC32 functions through lib
authorEric Biggers <ebiggers@google.com>
Mon, 2 Dec 2024 01:08:34 +0000 (17:08 -0800)
committerEric Biggers <ebiggers@google.com>
Mon, 2 Dec 2024 01:23:01 +0000 (17:23 -0800)
Move the s390 CRC32 assembly code into the lib directory and wire it up
to the library interface.  This allows it to be used without going
through the crypto API.  It remains usable via the crypto API too via
the shash algorithms that use the library interface.  Thus all the
arch-specific "shash" code becomes unnecessary and is removed.

Note: to see the diff from arch/s390/crypto/crc32-vx.c to
arch/s390/lib/crc32-glue.c, view this commit with 'git show -M10'.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20241202010844.144356-10-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
14 files changed:
arch/s390/Kconfig
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/crypto/Kconfig
arch/s390/crypto/Makefile
arch/s390/crypto/crc32-vx.c [deleted file]
arch/s390/crypto/crc32-vx.h [deleted file]
arch/s390/crypto/crc32be-vx.c [deleted file]
arch/s390/crypto/crc32le-vx.c [deleted file]
arch/s390/lib/Makefile
arch/s390/lib/crc32-glue.c [new file with mode: 0644]
arch/s390/lib/crc32-vx.h [new file with mode: 0644]
arch/s390/lib/crc32be-vx.c [new file with mode: 0644]
arch/s390/lib/crc32le-vx.c [new file with mode: 0644]

index 0077969170e8b4ca4c99e87ec75f6ea94f3e8e00..d272230cc885259504dde3eef774881da16af02b 100644 (file)
@@ -72,6 +72,7 @@ config S390
        select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM
        select ARCH_ENABLE_MEMORY_HOTREMOVE
        select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
+       select ARCH_HAS_CRC32
        select ARCH_HAS_CURRENT_STACK_POINTER
        select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEBUG_VM_PGTABLE
index d8d227ab82de0e78bb9f1766d3d547f702e47881..f2a149b4fafd0e45f9d06ce569cc0ffe474ac920 100644 (file)
@@ -795,7 +795,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_SHA512_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
index 6c2f2bb4fbf8f676e847818cd81bbfaa34af826a..d521aabc31d7d0d9c0b9c5388564a66099f375bf 100644 (file)
@@ -782,7 +782,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_SHA512_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
index d3eb3a23369321868f76cd422883dc18855577d0..b760232537f1c6942c6a8d6b70ce04aa013fd8be 100644 (file)
@@ -2,18 +2,6 @@
 
 menu "Accelerated Cryptographic Algorithms for CPU (s390)"
 
-config CRYPTO_CRC32_S390
-       tristate "CRC32c and CRC32"
-       depends on S390
-       select CRYPTO_HASH
-       select CRC32
-       help
-         CRC32c and CRC32 CRC algorithms
-
-         Architecture: s390
-
-         It is available with IBM z13 or later.
-
 config CRYPTO_SHA512_S390
        tristate "Hash functions: SHA-384 and SHA-512"
        depends on S390
index a0cb96937c3de249cd66a17d6e17a68968a72e3e..14dafadbcbed4718af6abf5e4a93677830564440 100644 (file)
@@ -14,9 +14,7 @@ obj-$(CONFIG_CRYPTO_PAES_S390) += paes_s390.o
 obj-$(CONFIG_CRYPTO_CHACHA_S390) += chacha_s390.o
 obj-$(CONFIG_S390_PRNG) += prng.o
 obj-$(CONFIG_CRYPTO_GHASH_S390) += ghash_s390.o
-obj-$(CONFIG_CRYPTO_CRC32_S390) += crc32-vx_s390.o
 obj-$(CONFIG_CRYPTO_HMAC_S390) += hmac_s390.o
 obj-y += arch_random.o
 
-crc32-vx_s390-y := crc32-vx.o crc32le-vx.o crc32be-vx.o
 chacha_s390-y := chacha-glue.o chacha-s390.o
diff --git a/arch/s390/crypto/crc32-vx.c b/arch/s390/crypto/crc32-vx.c
deleted file mode 100644 (file)
index 89a1033..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Crypto-API module for CRC-32 algorithms implemented with the
- * z/Architecture Vector Extension Facility.
- *
- * Copyright IBM Corp. 2015
- * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
- */
-#define KMSG_COMPONENT "crc32-vx"
-#define pr_fmt(fmt)    KMSG_COMPONENT ": " fmt
-
-#include <linux/module.h>
-#include <linux/cpufeature.h>
-#include <linux/crc32.h>
-#include <crypto/internal/hash.h>
-#include <asm/fpu.h>
-#include "crc32-vx.h"
-
-#define CRC32_BLOCK_SIZE       1
-#define CRC32_DIGEST_SIZE      4
-
-#define VX_MIN_LEN             64
-#define VX_ALIGNMENT           16L
-#define VX_ALIGN_MASK          (VX_ALIGNMENT - 1)
-
-struct crc_ctx {
-       u32 key;
-};
-
-struct crc_desc_ctx {
-       u32 crc;
-};
-
-/*
- * DEFINE_CRC32_VX() - Define a CRC-32 function using the vector extension
- *
- * Creates a function to perform a particular CRC-32 computation. Depending
- * on the message buffer, the hardware-accelerated or software implementation
- * is used.   Note that the message buffer is aligned to improve fetch
- * operations of VECTOR LOAD MULTIPLE instructions.
- *
- */
-#define DEFINE_CRC32_VX(___fname, ___crc32_vx, ___crc32_sw)                \
-       static u32 __pure ___fname(u32 crc,                                 \
-                               unsigned char const *data, size_t datalen)  \
-       {                                                                   \
-               unsigned long prealign, aligned, remaining;                 \
-               DECLARE_KERNEL_FPU_ONSTACK16(vxstate);                      \
-                                                                           \
-               if (datalen < VX_MIN_LEN + VX_ALIGN_MASK)                   \
-                       return ___crc32_sw(crc, data, datalen);             \
-                                                                           \
-               if ((unsigned long)data & VX_ALIGN_MASK) {                  \
-                       prealign = VX_ALIGNMENT -                           \
-                                 ((unsigned long)data & VX_ALIGN_MASK);    \
-                       datalen -= prealign;                                \
-                       crc = ___crc32_sw(crc, data, prealign);             \
-                       data = (void *)((unsigned long)data + prealign);    \
-               }                                                           \
-                                                                           \
-               aligned = datalen & ~VX_ALIGN_MASK;                         \
-               remaining = datalen & VX_ALIGN_MASK;                        \
-                                                                           \
-               kernel_fpu_begin(&vxstate, KERNEL_VXR_LOW);                 \
-               crc = ___crc32_vx(crc, data, aligned);                      \
-               kernel_fpu_end(&vxstate, KERNEL_VXR_LOW);                   \
-                                                                           \
-               if (remaining)                                              \
-                       crc = ___crc32_sw(crc, data + aligned, remaining);  \
-                                                                           \
-               return crc;                                                 \
-       }
-
-DEFINE_CRC32_VX(crc32_le_vx, crc32_le_vgfm_16, crc32_le)
-DEFINE_CRC32_VX(crc32_be_vx, crc32_be_vgfm_16, crc32_be)
-DEFINE_CRC32_VX(crc32c_le_vx, crc32c_le_vgfm_16, __crc32c_le)
-
-
-static int crc32_vx_cra_init_zero(struct crypto_tfm *tfm)
-{
-       struct crc_ctx *mctx = crypto_tfm_ctx(tfm);
-
-       mctx->key = 0;
-       return 0;
-}
-
-static int crc32_vx_cra_init_invert(struct crypto_tfm *tfm)
-{
-       struct crc_ctx *mctx = crypto_tfm_ctx(tfm);
-
-       mctx->key = ~0;
-       return 0;
-}
-
-static int crc32_vx_init(struct shash_desc *desc)
-{
-       struct crc_ctx *mctx = crypto_shash_ctx(desc->tfm);
-       struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       ctx->crc = mctx->key;
-       return 0;
-}
-
-static int crc32_vx_setkey(struct crypto_shash *tfm, const u8 *newkey,
-                          unsigned int newkeylen)
-{
-       struct crc_ctx *mctx = crypto_shash_ctx(tfm);
-
-       if (newkeylen != sizeof(mctx->key))
-               return -EINVAL;
-       mctx->key = le32_to_cpu(*(__le32 *)newkey);
-       return 0;
-}
-
-static int crc32be_vx_setkey(struct crypto_shash *tfm, const u8 *newkey,
-                            unsigned int newkeylen)
-{
-       struct crc_ctx *mctx = crypto_shash_ctx(tfm);
-
-       if (newkeylen != sizeof(mctx->key))
-               return -EINVAL;
-       mctx->key = be32_to_cpu(*(__be32 *)newkey);
-       return 0;
-}
-
-static int crc32le_vx_final(struct shash_desc *desc, u8 *out)
-{
-       struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       *(__le32 *)out = cpu_to_le32p(&ctx->crc);
-       return 0;
-}
-
-static int crc32be_vx_final(struct shash_desc *desc, u8 *out)
-{
-       struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       *(__be32 *)out = cpu_to_be32p(&ctx->crc);
-       return 0;
-}
-
-static int crc32c_vx_final(struct shash_desc *desc, u8 *out)
-{
-       struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       /*
-        * Perform a final XOR with 0xFFFFFFFF to be in sync
-        * with the generic crc32c shash implementation.
-        */
-       *(__le32 *)out = ~cpu_to_le32p(&ctx->crc);
-       return 0;
-}
-
-static int __crc32le_vx_finup(u32 *crc, const u8 *data, unsigned int len,
-                             u8 *out)
-{
-       *(__le32 *)out = cpu_to_le32(crc32_le_vx(*crc, data, len));
-       return 0;
-}
-
-static int __crc32be_vx_finup(u32 *crc, const u8 *data, unsigned int len,
-                             u8 *out)
-{
-       *(__be32 *)out = cpu_to_be32(crc32_be_vx(*crc, data, len));
-       return 0;
-}
-
-static int __crc32c_vx_finup(u32 *crc, const u8 *data, unsigned int len,
-                            u8 *out)
-{
-       /*
-        * Perform a final XOR with 0xFFFFFFFF to be in sync
-        * with the generic crc32c shash implementation.
-        */
-       *(__le32 *)out = ~cpu_to_le32(crc32c_le_vx(*crc, data, len));
-       return 0;
-}
-
-
-#define CRC32_VX_FINUP(alg, func)                                            \
-       static int alg ## _vx_finup(struct shash_desc *desc, const u8 *data,  \
-                                  unsigned int datalen, u8 *out)             \
-       {                                                                     \
-               return __ ## alg ## _vx_finup(shash_desc_ctx(desc),           \
-                                             data, datalen, out);            \
-       }
-
-CRC32_VX_FINUP(crc32le, crc32_le_vx)
-CRC32_VX_FINUP(crc32be, crc32_be_vx)
-CRC32_VX_FINUP(crc32c, crc32c_le_vx)
-
-#define CRC32_VX_DIGEST(alg, func)                                           \
-       static int alg ## _vx_digest(struct shash_desc *desc, const u8 *data, \
-                                    unsigned int len, u8 *out)               \
-       {                                                                     \
-               return __ ## alg ## _vx_finup(crypto_shash_ctx(desc->tfm),    \
-                                             data, len, out);                \
-       }
-
-CRC32_VX_DIGEST(crc32le, crc32_le_vx)
-CRC32_VX_DIGEST(crc32be, crc32_be_vx)
-CRC32_VX_DIGEST(crc32c, crc32c_le_vx)
-
-#define CRC32_VX_UPDATE(alg, func)                                           \
-       static int alg ## _vx_update(struct shash_desc *desc, const u8 *data, \
-                                    unsigned int datalen)                    \
-       {                                                                     \
-               struct crc_desc_ctx *ctx = shash_desc_ctx(desc);              \
-               ctx->crc = func(ctx->crc, data, datalen);                     \
-               return 0;                                                     \
-       }
-
-CRC32_VX_UPDATE(crc32le, crc32_le_vx)
-CRC32_VX_UPDATE(crc32be, crc32_be_vx)
-CRC32_VX_UPDATE(crc32c, crc32c_le_vx)
-
-
-static struct shash_alg crc32_vx_algs[] = {
-       /* CRC-32 LE */
-       {
-               .init           =       crc32_vx_init,
-               .setkey         =       crc32_vx_setkey,
-               .update         =       crc32le_vx_update,
-               .final          =       crc32le_vx_final,
-               .finup          =       crc32le_vx_finup,
-               .digest         =       crc32le_vx_digest,
-               .descsize       =       sizeof(struct crc_desc_ctx),
-               .digestsize     =       CRC32_DIGEST_SIZE,
-               .base           =       {
-                       .cra_name        = "crc32",
-                       .cra_driver_name = "crc32-vx",
-                       .cra_priority    = 200,
-                       .cra_flags       = CRYPTO_ALG_OPTIONAL_KEY,
-                       .cra_blocksize   = CRC32_BLOCK_SIZE,
-                       .cra_ctxsize     = sizeof(struct crc_ctx),
-                       .cra_module      = THIS_MODULE,
-                       .cra_init        = crc32_vx_cra_init_zero,
-               },
-       },
-       /* CRC-32 BE */
-       {
-               .init           =       crc32_vx_init,
-               .setkey         =       crc32be_vx_setkey,
-               .update         =       crc32be_vx_update,
-               .final          =       crc32be_vx_final,
-               .finup          =       crc32be_vx_finup,
-               .digest         =       crc32be_vx_digest,
-               .descsize       =       sizeof(struct crc_desc_ctx),
-               .digestsize     =       CRC32_DIGEST_SIZE,
-               .base           =       {
-                       .cra_name        = "crc32be",
-                       .cra_driver_name = "crc32be-vx",
-                       .cra_priority    = 200,
-                       .cra_flags       = CRYPTO_ALG_OPTIONAL_KEY,
-                       .cra_blocksize   = CRC32_BLOCK_SIZE,
-                       .cra_ctxsize     = sizeof(struct crc_ctx),
-                       .cra_module      = THIS_MODULE,
-                       .cra_init        = crc32_vx_cra_init_zero,
-               },
-       },
-       /* CRC-32C LE */
-       {
-               .init           =       crc32_vx_init,
-               .setkey         =       crc32_vx_setkey,
-               .update         =       crc32c_vx_update,
-               .final          =       crc32c_vx_final,
-               .finup          =       crc32c_vx_finup,
-               .digest         =       crc32c_vx_digest,
-               .descsize       =       sizeof(struct crc_desc_ctx),
-               .digestsize     =       CRC32_DIGEST_SIZE,
-               .base           =       {
-                       .cra_name        = "crc32c",
-                       .cra_driver_name = "crc32c-vx",
-                       .cra_priority    = 200,
-                       .cra_flags       = CRYPTO_ALG_OPTIONAL_KEY,
-                       .cra_blocksize   = CRC32_BLOCK_SIZE,
-                       .cra_ctxsize     = sizeof(struct crc_ctx),
-                       .cra_module      = THIS_MODULE,
-                       .cra_init        = crc32_vx_cra_init_invert,
-               },
-       },
-};
-
-
-static int __init crc_vx_mod_init(void)
-{
-       return crypto_register_shashes(crc32_vx_algs,
-                                      ARRAY_SIZE(crc32_vx_algs));
-}
-
-static void __exit crc_vx_mod_exit(void)
-{
-       crypto_unregister_shashes(crc32_vx_algs, ARRAY_SIZE(crc32_vx_algs));
-}
-
-module_cpu_feature_match(S390_CPU_FEATURE_VXRS, crc_vx_mod_init);
-module_exit(crc_vx_mod_exit);
-
-MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("CRC-32 algorithms using z/Architecture Vector Extension Facility");
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_CRYPTO("crc32");
-MODULE_ALIAS_CRYPTO("crc32-vx");
-MODULE_ALIAS_CRYPTO("crc32c");
-MODULE_ALIAS_CRYPTO("crc32c-vx");
diff --git a/arch/s390/crypto/crc32-vx.h b/arch/s390/crypto/crc32-vx.h
deleted file mode 100644 (file)
index 652c96e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef _CRC32_VX_S390_H
-#define _CRC32_VX_S390_H
-
-#include <linux/types.h>
-
-u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
-u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
-u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
-
-#endif /* _CRC32_VX_S390_H */
diff --git a/arch/s390/crypto/crc32be-vx.c b/arch/s390/crypto/crc32be-vx.c
deleted file mode 100644 (file)
index fed7c9c..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Hardware-accelerated CRC-32 variants for Linux on z Systems
- *
- * Use the z/Architecture Vector Extension Facility to accelerate the
- * computing of CRC-32 checksums.
- *
- * This CRC-32 implementation algorithm processes the most-significant
- * bit first (BE).
- *
- * Copyright IBM Corp. 2015
- * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
- */
-
-#include <linux/types.h>
-#include <asm/fpu.h>
-#include "crc32-vx.h"
-
-/* Vector register range containing CRC-32 constants */
-#define CONST_R1R2             9
-#define CONST_R3R4             10
-#define CONST_R5               11
-#define CONST_R6               12
-#define CONST_RU_POLY          13
-#define CONST_CRC_POLY         14
-
-/*
- * The CRC-32 constant block contains reduction constants to fold and
- * process particular chunks of the input data stream in parallel.
- *
- * For the CRC-32 variants, the constants are precomputed according to
- * these definitions:
- *
- *     R1 = x4*128+64 mod P(x)
- *     R2 = x4*128    mod P(x)
- *     R3 = x128+64   mod P(x)
- *     R4 = x128      mod P(x)
- *     R5 = x96       mod P(x)
- *     R6 = x64       mod P(x)
- *
- *     Barret reduction constant, u, is defined as floor(x**64 / P(x)).
- *
- *     where P(x) is the polynomial in the normal domain and the P'(x) is the
- *     polynomial in the reversed (bitreflected) domain.
- *
- * Note that the constant definitions below are extended in order to compute
- * intermediate results with a single VECTOR GALOIS FIELD MULTIPLY instruction.
- * The rightmost doubleword can be 0 to prevent contribution to the result or
- * can be multiplied by 1 to perform an XOR without the need for a separate
- * VECTOR EXCLUSIVE OR instruction.
- *
- * CRC-32 (IEEE 802.3 Ethernet, ...) polynomials:
- *
- *     P(x)  = 0x04C11DB7
- *     P'(x) = 0xEDB88320
- */
-
-static unsigned long constants_CRC_32_BE[] = {
-       0x08833794c, 0x0e6228b11,       /* R1, R2 */
-       0x0c5b9cd4c, 0x0e8a45605,       /* R3, R4 */
-       0x0f200aa66, 1UL << 32,         /* R5, x32 */
-       0x0490d678d, 1,                 /* R6, 1 */
-       0x104d101df, 0,                 /* u */
-       0x104C11DB7, 0,                 /* P(x) */
-};
-
-/**
- * crc32_be_vgfm_16 - Compute CRC-32 (BE variant) with vector registers
- * @crc: Initial CRC value, typically ~0.
- * @buf: Input buffer pointer, performance might be improved if the
- *       buffer is on a doubleword boundary.
- * @size: Size of the buffer, must be 64 bytes or greater.
- *
- * Register usage:
- *     V0:     Initial CRC value and intermediate constants and results.
- *     V1..V4: Data for CRC computation.
- *     V5..V8: Next data chunks that are fetched from the input buffer.
- *     V9..V14: CRC-32 constants.
- */
-u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
-{
-       /* Load CRC-32 constants */
-       fpu_vlm(CONST_R1R2, CONST_CRC_POLY, &constants_CRC_32_BE);
-       fpu_vzero(0);
-
-       /* Load the initial CRC value into the leftmost word of V0. */
-       fpu_vlvgf(0, crc, 0);
-
-       /* Load a 64-byte data chunk and XOR with CRC */
-       fpu_vlm(1, 4, buf);
-       fpu_vx(1, 0, 1);
-       buf += 64;
-       size -= 64;
-
-       while (size >= 64) {
-               /* Load the next 64-byte data chunk into V5 to V8 */
-               fpu_vlm(5, 8, buf);
-
-               /*
-                * Perform a GF(2) multiplication of the doublewords in V1 with
-                * the reduction constants in V0.  The intermediate result is
-                * then folded (accumulated) with the next data chunk in V5 and
-                * stored in V1.  Repeat this step for the register contents
-                * in V2, V3, and V4 respectively.
-                */
-               fpu_vgfmag(1, CONST_R1R2, 1, 5);
-               fpu_vgfmag(2, CONST_R1R2, 2, 6);
-               fpu_vgfmag(3, CONST_R1R2, 3, 7);
-               fpu_vgfmag(4, CONST_R1R2, 4, 8);
-               buf += 64;
-               size -= 64;
-       }
-
-       /* Fold V1 to V4 into a single 128-bit value in V1 */
-       fpu_vgfmag(1, CONST_R3R4, 1, 2);
-       fpu_vgfmag(1, CONST_R3R4, 1, 3);
-       fpu_vgfmag(1, CONST_R3R4, 1, 4);
-
-       while (size >= 16) {
-               fpu_vl(2, buf);
-               fpu_vgfmag(1, CONST_R3R4, 1, 2);
-               buf += 16;
-               size -= 16;
-       }
-
-       /*
-        * The R5 constant is used to fold a 128-bit value into an 96-bit value
-        * that is XORed with the next 96-bit input data chunk.  To use a single
-        * VGFMG instruction, multiply the rightmost 64-bit with x^32 (1<<32) to
-        * form an intermediate 96-bit value (with appended zeros) which is then
-        * XORed with the intermediate reduction result.
-        */
-       fpu_vgfmg(1, CONST_R5, 1);
-
-       /*
-        * Further reduce the remaining 96-bit value to a 64-bit value using a
-        * single VGFMG, the rightmost doubleword is multiplied with 0x1. The
-        * intermediate result is then XORed with the product of the leftmost
-        * doubleword with R6.  The result is a 64-bit value and is subject to
-        * the Barret reduction.
-        */
-       fpu_vgfmg(1, CONST_R6, 1);
-
-       /*
-        * The input values to the Barret reduction are the degree-63 polynomial
-        * in V1 (R(x)), degree-32 generator polynomial, and the reduction
-        * constant u.  The Barret reduction result is the CRC value of R(x) mod
-        * P(x).
-        *
-        * The Barret reduction algorithm is defined as:
-        *
-        *    1. T1(x) = floor( R(x) / x^32 ) GF2MUL u
-        *    2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x)
-        *    3. C(x)  = R(x) XOR T2(x) mod x^32
-        *
-        * Note: To compensate the division by x^32, use the vector unpack
-        * instruction to move the leftmost word into the leftmost doubleword
-        * of the vector register.  The rightmost doubleword is multiplied
-        * with zero to not contribute to the intermediate results.
-        */
-
-       /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
-       fpu_vupllf(2, 1);
-       fpu_vgfmg(2, CONST_RU_POLY, 2);
-
-       /*
-        * Compute the GF(2) product of the CRC polynomial in VO with T1(x) in
-        * V2 and XOR the intermediate result, T2(x),  with the value in V1.
-        * The final result is in the rightmost word of V2.
-        */
-       fpu_vupllf(2, 2);
-       fpu_vgfmag(2, CONST_CRC_POLY, 2, 1);
-       return fpu_vlgvf(2, 3);
-}
diff --git a/arch/s390/crypto/crc32le-vx.c b/arch/s390/crypto/crc32le-vx.c
deleted file mode 100644 (file)
index 2f629f3..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Hardware-accelerated CRC-32 variants for Linux on z Systems
- *
- * Use the z/Architecture Vector Extension Facility to accelerate the
- * computing of bitreflected CRC-32 checksums for IEEE 802.3 Ethernet
- * and Castagnoli.
- *
- * This CRC-32 implementation algorithm is bitreflected and processes
- * the least-significant bit first (Little-Endian).
- *
- * Copyright IBM Corp. 2015
- * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
- */
-
-#include <linux/types.h>
-#include <asm/fpu.h>
-#include "crc32-vx.h"
-
-/* Vector register range containing CRC-32 constants */
-#define CONST_PERM_LE2BE       9
-#define CONST_R2R1             10
-#define CONST_R4R3             11
-#define CONST_R5               12
-#define CONST_RU_POLY          13
-#define CONST_CRC_POLY         14
-
-/*
- * The CRC-32 constant block contains reduction constants to fold and
- * process particular chunks of the input data stream in parallel.
- *
- * For the CRC-32 variants, the constants are precomputed according to
- * these definitions:
- *
- *     R1 = [(x4*128+32 mod P'(x) << 32)]' << 1
- *     R2 = [(x4*128-32 mod P'(x) << 32)]' << 1
- *     R3 = [(x128+32 mod P'(x) << 32)]'   << 1
- *     R4 = [(x128-32 mod P'(x) << 32)]'   << 1
- *     R5 = [(x64 mod P'(x) << 32)]'       << 1
- *     R6 = [(x32 mod P'(x) << 32)]'       << 1
- *
- *     The bitreflected Barret reduction constant, u', is defined as
- *     the bit reversal of floor(x**64 / P(x)).
- *
- *     where P(x) is the polynomial in the normal domain and the P'(x) is the
- *     polynomial in the reversed (bitreflected) domain.
- *
- * CRC-32 (IEEE 802.3 Ethernet, ...) polynomials:
- *
- *     P(x)  = 0x04C11DB7
- *     P'(x) = 0xEDB88320
- *
- * CRC-32C (Castagnoli) polynomials:
- *
- *     P(x)  = 0x1EDC6F41
- *     P'(x) = 0x82F63B78
- */
-
-static unsigned long constants_CRC_32_LE[] = {
-       0x0f0e0d0c0b0a0908, 0x0706050403020100, /* BE->LE mask */
-       0x1c6e41596, 0x154442bd4,               /* R2, R1 */
-       0x0ccaa009e, 0x1751997d0,               /* R4, R3 */
-       0x0, 0x163cd6124,                       /* R5 */
-       0x0, 0x1f7011641,                       /* u' */
-       0x0, 0x1db710641                        /* P'(x) << 1 */
-};
-
-static unsigned long constants_CRC_32C_LE[] = {
-       0x0f0e0d0c0b0a0908, 0x0706050403020100, /* BE->LE mask */
-       0x09e4addf8, 0x740eef02,                /* R2, R1 */
-       0x14cd00bd6, 0xf20c0dfe,                /* R4, R3 */
-       0x0, 0x0dd45aab8,                       /* R5 */
-       0x0, 0x0dea713f1,                       /* u' */
-       0x0, 0x105ec76f0                        /* P'(x) << 1 */
-};
-
-/**
- * crc32_le_vgfm_generic - Compute CRC-32 (LE variant) with vector registers
- * @crc: Initial CRC value, typically ~0.
- * @buf: Input buffer pointer, performance might be improved if the
- *      buffer is on a doubleword boundary.
- * @size: Size of the buffer, must be 64 bytes or greater.
- * @constants: CRC-32 constant pool base pointer.
- *
- * Register usage:
- *     V0:       Initial CRC value and intermediate constants and results.
- *     V1..V4:   Data for CRC computation.
- *     V5..V8:   Next data chunks that are fetched from the input buffer.
- *     V9:       Constant for BE->LE conversion and shift operations
- *     V10..V14: CRC-32 constants.
- */
-static u32 crc32_le_vgfm_generic(u32 crc, unsigned char const *buf, size_t size, unsigned long *constants)
-{
-       /* Load CRC-32 constants */
-       fpu_vlm(CONST_PERM_LE2BE, CONST_CRC_POLY, constants);
-
-       /*
-        * Load the initial CRC value.
-        *
-        * The CRC value is loaded into the rightmost word of the
-        * vector register and is later XORed with the LSB portion
-        * of the loaded input data.
-        */
-       fpu_vzero(0);                   /* Clear V0 */
-       fpu_vlvgf(0, crc, 3);           /* Load CRC into rightmost word */
-
-       /* Load a 64-byte data chunk and XOR with CRC */
-       fpu_vlm(1, 4, buf);
-       fpu_vperm(1, 1, 1, CONST_PERM_LE2BE);
-       fpu_vperm(2, 2, 2, CONST_PERM_LE2BE);
-       fpu_vperm(3, 3, 3, CONST_PERM_LE2BE);
-       fpu_vperm(4, 4, 4, CONST_PERM_LE2BE);
-
-       fpu_vx(1, 0, 1);                /* V1 ^= CRC */
-       buf += 64;
-       size -= 64;
-
-       while (size >= 64) {
-               fpu_vlm(5, 8, buf);
-               fpu_vperm(5, 5, 5, CONST_PERM_LE2BE);
-               fpu_vperm(6, 6, 6, CONST_PERM_LE2BE);
-               fpu_vperm(7, 7, 7, CONST_PERM_LE2BE);
-               fpu_vperm(8, 8, 8, CONST_PERM_LE2BE);
-               /*
-                * Perform a GF(2) multiplication of the doublewords in V1 with
-                * the R1 and R2 reduction constants in V0.  The intermediate
-                * result is then folded (accumulated) with the next data chunk
-                * in V5 and stored in V1. Repeat this step for the register
-                * contents in V2, V3, and V4 respectively.
-                */
-               fpu_vgfmag(1, CONST_R2R1, 1, 5);
-               fpu_vgfmag(2, CONST_R2R1, 2, 6);
-               fpu_vgfmag(3, CONST_R2R1, 3, 7);
-               fpu_vgfmag(4, CONST_R2R1, 4, 8);
-               buf += 64;
-               size -= 64;
-       }
-
-       /*
-        * Fold V1 to V4 into a single 128-bit value in V1.  Multiply V1 with R3
-        * and R4 and accumulating the next 128-bit chunk until a single 128-bit
-        * value remains.
-        */
-       fpu_vgfmag(1, CONST_R4R3, 1, 2);
-       fpu_vgfmag(1, CONST_R4R3, 1, 3);
-       fpu_vgfmag(1, CONST_R4R3, 1, 4);
-
-       while (size >= 16) {
-               fpu_vl(2, buf);
-               fpu_vperm(2, 2, 2, CONST_PERM_LE2BE);
-               fpu_vgfmag(1, CONST_R4R3, 1, 2);
-               buf += 16;
-               size -= 16;
-       }
-
-       /*
-        * Set up a vector register for byte shifts.  The shift value must
-        * be loaded in bits 1-4 in byte element 7 of a vector register.
-        * Shift by 8 bytes: 0x40
-        * Shift by 4 bytes: 0x20
-        */
-       fpu_vleib(9, 0x40, 7);
-
-       /*
-        * Prepare V0 for the next GF(2) multiplication: shift V0 by 8 bytes
-        * to move R4 into the rightmost doubleword and set the leftmost
-        * doubleword to 0x1.
-        */
-       fpu_vsrlb(0, CONST_R4R3, 9);
-       fpu_vleig(0, 1, 0);
-
-       /*
-        * Compute GF(2) product of V1 and V0.  The rightmost doubleword
-        * of V1 is multiplied with R4.  The leftmost doubleword of V1 is
-        * multiplied by 0x1 and is then XORed with rightmost product.
-        * Implicitly, the intermediate leftmost product becomes padded
-        */
-       fpu_vgfmg(1, 0, 1);
-
-       /*
-        * Now do the final 32-bit fold by multiplying the rightmost word
-        * in V1 with R5 and XOR the result with the remaining bits in V1.
-        *
-        * To achieve this by a single VGFMAG, right shift V1 by a word
-        * and store the result in V2 which is then accumulated.  Use the
-        * vector unpack instruction to load the rightmost half of the
-        * doubleword into the rightmost doubleword element of V1; the other
-        * half is loaded in the leftmost doubleword.
-        * The vector register with CONST_R5 contains the R5 constant in the
-        * rightmost doubleword and the leftmost doubleword is zero to ignore
-        * the leftmost product of V1.
-        */
-       fpu_vleib(9, 0x20, 7);            /* Shift by words */
-       fpu_vsrlb(2, 1, 9);               /* Store remaining bits in V2 */
-       fpu_vupllf(1, 1);                 /* Split rightmost doubleword */
-       fpu_vgfmag(1, CONST_R5, 1, 2);    /* V1 = (V1 * R5) XOR V2 */
-
-       /*
-        * Apply a Barret reduction to compute the final 32-bit CRC value.
-        *
-        * The input values to the Barret reduction are the degree-63 polynomial
-        * in V1 (R(x)), degree-32 generator polynomial, and the reduction
-        * constant u.  The Barret reduction result is the CRC value of R(x) mod
-        * P(x).
-        *
-        * The Barret reduction algorithm is defined as:
-        *
-        *    1. T1(x) = floor( R(x) / x^32 ) GF2MUL u
-        *    2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x)
-        *    3. C(x)  = R(x) XOR T2(x) mod x^32
-        *
-        *  Note: The leftmost doubleword of vector register containing
-        *  CONST_RU_POLY is zero and, thus, the intermediate GF(2) product
-        *  is zero and does not contribute to the final result.
-        */
-
-       /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
-       fpu_vupllf(2, 1);
-       fpu_vgfmg(2, CONST_RU_POLY, 2);
-
-       /*
-        * Compute the GF(2) product of the CRC polynomial with T1(x) in
-        * V2 and XOR the intermediate result, T2(x), with the value in V1.
-        * The final result is stored in word element 2 of V2.
-        */
-       fpu_vupllf(2, 2);
-       fpu_vgfmag(2, CONST_CRC_POLY, 2, 1);
-
-       return fpu_vlgvf(2, 2);
-}
-
-u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
-{
-       return crc32_le_vgfm_generic(crc, buf, size, &constants_CRC_32_LE[0]);
-}
-
-u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
-{
-       return crc32_le_vgfm_generic(crc, buf, size, &constants_CRC_32C_LE[0]);
-}
index f43f897d3fc027ad2f5cbf52ba2abc343b6e31ea..14bbfe50033c7c0591bf699608cb410975c31621 100644 (file)
@@ -24,3 +24,6 @@ obj-$(CONFIG_S390_MODULES_SANITY_TEST_HELPERS) += test_modules_helpers.o
 lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
 
 obj-$(CONFIG_EXPOLINE_EXTERN) += expoline.o
+
+obj-$(CONFIG_CRC32_ARCH) += crc32-s390.o
+crc32-s390-y := crc32-glue.o crc32le-vx.o crc32be-vx.o
diff --git a/arch/s390/lib/crc32-glue.c b/arch/s390/lib/crc32-glue.c
new file mode 100644 (file)
index 0000000..137080e
--- /dev/null
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CRC-32 implemented with the z/Architecture Vector Extension Facility.
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+#define KMSG_COMPONENT "crc32-vx"
+#define pr_fmt(fmt)    KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/cpufeature.h>
+#include <linux/crc32.h>
+#include <asm/fpu.h>
+#include "crc32-vx.h"
+
+#define VX_MIN_LEN             64
+#define VX_ALIGNMENT           16L
+#define VX_ALIGN_MASK          (VX_ALIGNMENT - 1)
+
+static DEFINE_STATIC_KEY_FALSE(have_vxrs);
+
+/*
+ * DEFINE_CRC32_VX() - Define a CRC-32 function using the vector extension
+ *
+ * Creates a function to perform a particular CRC-32 computation. Depending
+ * on the message buffer, the hardware-accelerated or software implementation
+ * is used.   Note that the message buffer is aligned to improve fetch
+ * operations of VECTOR LOAD MULTIPLE instructions.
+ */
+#define DEFINE_CRC32_VX(___fname, ___crc32_vx, ___crc32_sw)                \
+       u32 ___fname(u32 crc, const u8 *data, size_t datalen)               \
+       {                                                                   \
+               unsigned long prealign, aligned, remaining;                 \
+               DECLARE_KERNEL_FPU_ONSTACK16(vxstate);                      \
+                                                                           \
+               if (datalen < VX_MIN_LEN + VX_ALIGN_MASK ||                 \
+                   !static_branch_likely(&have_vxrs))                      \
+                       return ___crc32_sw(crc, data, datalen);             \
+                                                                           \
+               if ((unsigned long)data & VX_ALIGN_MASK) {                  \
+                       prealign = VX_ALIGNMENT -                           \
+                                 ((unsigned long)data & VX_ALIGN_MASK);    \
+                       datalen -= prealign;                                \
+                       crc = ___crc32_sw(crc, data, prealign);             \
+                       data = (void *)((unsigned long)data + prealign);    \
+               }                                                           \
+                                                                           \
+               aligned = datalen & ~VX_ALIGN_MASK;                         \
+               remaining = datalen & VX_ALIGN_MASK;                        \
+                                                                           \
+               kernel_fpu_begin(&vxstate, KERNEL_VXR_LOW);                 \
+               crc = ___crc32_vx(crc, data, aligned);                      \
+               kernel_fpu_end(&vxstate, KERNEL_VXR_LOW);                   \
+                                                                           \
+               if (remaining)                                              \
+                       crc = ___crc32_sw(crc, data + aligned, remaining);  \
+                                                                           \
+               return crc;                                                 \
+       }                                                                   \
+       EXPORT_SYMBOL(___fname);
+
+DEFINE_CRC32_VX(crc32_le_arch, crc32_le_vgfm_16, crc32_le_base)
+DEFINE_CRC32_VX(crc32_be_arch, crc32_be_vgfm_16, crc32_be_base)
+DEFINE_CRC32_VX(crc32c_le_arch, crc32c_le_vgfm_16, crc32c_le_base)
+
+static int __init crc32_s390_init(void)
+{
+       if (cpu_have_feature(S390_CPU_FEATURE_VXRS))
+               static_branch_enable(&have_vxrs);
+       return 0;
+}
+arch_initcall(crc32_s390_init);
+
+static void __exit crc32_s390_exit(void)
+{
+}
+module_exit(crc32_s390_exit);
+
+u32 crc32_optimizations(void)
+{
+       if (static_key_enabled(&have_vxrs))
+               return CRC32_LE_OPTIMIZATION |
+                      CRC32_BE_OPTIMIZATION |
+                      CRC32C_OPTIMIZATION;
+       return 0;
+}
+EXPORT_SYMBOL(crc32_optimizations);
+
+MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("CRC-32 algorithms using z/Architecture Vector Extension Facility");
+MODULE_LICENSE("GPL");
diff --git a/arch/s390/lib/crc32-vx.h b/arch/s390/lib/crc32-vx.h
new file mode 100644 (file)
index 0000000..652c96e
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _CRC32_VX_S390_H
+#define _CRC32_VX_S390_H
+
+#include <linux/types.h>
+
+u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
+u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
+u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
+
+#endif /* _CRC32_VX_S390_H */
diff --git a/arch/s390/lib/crc32be-vx.c b/arch/s390/lib/crc32be-vx.c
new file mode 100644 (file)
index 0000000..fed7c9c
--- /dev/null
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hardware-accelerated CRC-32 variants for Linux on z Systems
+ *
+ * Use the z/Architecture Vector Extension Facility to accelerate the
+ * computing of CRC-32 checksums.
+ *
+ * This CRC-32 implementation algorithm processes the most-significant
+ * bit first (BE).
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <asm/fpu.h>
+#include "crc32-vx.h"
+
+/* Vector register range containing CRC-32 constants */
+#define CONST_R1R2             9
+#define CONST_R3R4             10
+#define CONST_R5               11
+#define CONST_R6               12
+#define CONST_RU_POLY          13
+#define CONST_CRC_POLY         14
+
+/*
+ * The CRC-32 constant block contains reduction constants to fold and
+ * process particular chunks of the input data stream in parallel.
+ *
+ * For the CRC-32 variants, the constants are precomputed according to
+ * these definitions:
+ *
+ *     R1 = x4*128+64 mod P(x)
+ *     R2 = x4*128    mod P(x)
+ *     R3 = x128+64   mod P(x)
+ *     R4 = x128      mod P(x)
+ *     R5 = x96       mod P(x)
+ *     R6 = x64       mod P(x)
+ *
+ *     Barret reduction constant, u, is defined as floor(x**64 / P(x)).
+ *
+ *     where P(x) is the polynomial in the normal domain and the P'(x) is the
+ *     polynomial in the reversed (bitreflected) domain.
+ *
+ * Note that the constant definitions below are extended in order to compute
+ * intermediate results with a single VECTOR GALOIS FIELD MULTIPLY instruction.
+ * The rightmost doubleword can be 0 to prevent contribution to the result or
+ * can be multiplied by 1 to perform an XOR without the need for a separate
+ * VECTOR EXCLUSIVE OR instruction.
+ *
+ * CRC-32 (IEEE 802.3 Ethernet, ...) polynomials:
+ *
+ *     P(x)  = 0x04C11DB7
+ *     P'(x) = 0xEDB88320
+ */
+
+static unsigned long constants_CRC_32_BE[] = {
+       0x08833794c, 0x0e6228b11,       /* R1, R2 */
+       0x0c5b9cd4c, 0x0e8a45605,       /* R3, R4 */
+       0x0f200aa66, 1UL << 32,         /* R5, x32 */
+       0x0490d678d, 1,                 /* R6, 1 */
+       0x104d101df, 0,                 /* u */
+       0x104C11DB7, 0,                 /* P(x) */
+};
+
+/**
+ * crc32_be_vgfm_16 - Compute CRC-32 (BE variant) with vector registers
+ * @crc: Initial CRC value, typically ~0.
+ * @buf: Input buffer pointer, performance might be improved if the
+ *       buffer is on a doubleword boundary.
+ * @size: Size of the buffer, must be 64 bytes or greater.
+ *
+ * Register usage:
+ *     V0:     Initial CRC value and intermediate constants and results.
+ *     V1..V4: Data for CRC computation.
+ *     V5..V8: Next data chunks that are fetched from the input buffer.
+ *     V9..V14: CRC-32 constants.
+ */
+u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
+{
+       /* Load CRC-32 constants */
+       fpu_vlm(CONST_R1R2, CONST_CRC_POLY, &constants_CRC_32_BE);
+       fpu_vzero(0);
+
+       /* Load the initial CRC value into the leftmost word of V0. */
+       fpu_vlvgf(0, crc, 0);
+
+       /* Load a 64-byte data chunk and XOR with CRC */
+       fpu_vlm(1, 4, buf);
+       fpu_vx(1, 0, 1);
+       buf += 64;
+       size -= 64;
+
+       while (size >= 64) {
+               /* Load the next 64-byte data chunk into V5 to V8 */
+               fpu_vlm(5, 8, buf);
+
+               /*
+                * Perform a GF(2) multiplication of the doublewords in V1 with
+                * the reduction constants in V0.  The intermediate result is
+                * then folded (accumulated) with the next data chunk in V5 and
+                * stored in V1.  Repeat this step for the register contents
+                * in V2, V3, and V4 respectively.
+                */
+               fpu_vgfmag(1, CONST_R1R2, 1, 5);
+               fpu_vgfmag(2, CONST_R1R2, 2, 6);
+               fpu_vgfmag(3, CONST_R1R2, 3, 7);
+               fpu_vgfmag(4, CONST_R1R2, 4, 8);
+               buf += 64;
+               size -= 64;
+       }
+
+       /* Fold V1 to V4 into a single 128-bit value in V1 */
+       fpu_vgfmag(1, CONST_R3R4, 1, 2);
+       fpu_vgfmag(1, CONST_R3R4, 1, 3);
+       fpu_vgfmag(1, CONST_R3R4, 1, 4);
+
+       while (size >= 16) {
+               fpu_vl(2, buf);
+               fpu_vgfmag(1, CONST_R3R4, 1, 2);
+               buf += 16;
+               size -= 16;
+       }
+
+       /*
+        * The R5 constant is used to fold a 128-bit value into an 96-bit value
+        * that is XORed with the next 96-bit input data chunk.  To use a single
+        * VGFMG instruction, multiply the rightmost 64-bit with x^32 (1<<32) to
+        * form an intermediate 96-bit value (with appended zeros) which is then
+        * XORed with the intermediate reduction result.
+        */
+       fpu_vgfmg(1, CONST_R5, 1);
+
+       /*
+        * Further reduce the remaining 96-bit value to a 64-bit value using a
+        * single VGFMG, the rightmost doubleword is multiplied with 0x1. The
+        * intermediate result is then XORed with the product of the leftmost
+        * doubleword with R6.  The result is a 64-bit value and is subject to
+        * the Barret reduction.
+        */
+       fpu_vgfmg(1, CONST_R6, 1);
+
+       /*
+        * The input values to the Barret reduction are the degree-63 polynomial
+        * in V1 (R(x)), degree-32 generator polynomial, and the reduction
+        * constant u.  The Barret reduction result is the CRC value of R(x) mod
+        * P(x).
+        *
+        * The Barret reduction algorithm is defined as:
+        *
+        *    1. T1(x) = floor( R(x) / x^32 ) GF2MUL u
+        *    2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x)
+        *    3. C(x)  = R(x) XOR T2(x) mod x^32
+        *
+        * Note: To compensate the division by x^32, use the vector unpack
+        * instruction to move the leftmost word into the leftmost doubleword
+        * of the vector register.  The rightmost doubleword is multiplied
+        * with zero to not contribute to the intermediate results.
+        */
+
+       /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
+       fpu_vupllf(2, 1);
+       fpu_vgfmg(2, CONST_RU_POLY, 2);
+
+       /*
+        * Compute the GF(2) product of the CRC polynomial in VO with T1(x) in
+        * V2 and XOR the intermediate result, T2(x),  with the value in V1.
+        * The final result is in the rightmost word of V2.
+        */
+       fpu_vupllf(2, 2);
+       fpu_vgfmag(2, CONST_CRC_POLY, 2, 1);
+       return fpu_vlgvf(2, 3);
+}
diff --git a/arch/s390/lib/crc32le-vx.c b/arch/s390/lib/crc32le-vx.c
new file mode 100644 (file)
index 0000000..2f629f3
--- /dev/null
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hardware-accelerated CRC-32 variants for Linux on z Systems
+ *
+ * Use the z/Architecture Vector Extension Facility to accelerate the
+ * computing of bitreflected CRC-32 checksums for IEEE 802.3 Ethernet
+ * and Castagnoli.
+ *
+ * This CRC-32 implementation algorithm is bitreflected and processes
+ * the least-significant bit first (Little-Endian).
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <asm/fpu.h>
+#include "crc32-vx.h"
+
+/* Vector register range containing CRC-32 constants */
+#define CONST_PERM_LE2BE       9
+#define CONST_R2R1             10
+#define CONST_R4R3             11
+#define CONST_R5               12
+#define CONST_RU_POLY          13
+#define CONST_CRC_POLY         14
+
+/*
+ * The CRC-32 constant block contains reduction constants to fold and
+ * process particular chunks of the input data stream in parallel.
+ *
+ * For the CRC-32 variants, the constants are precomputed according to
+ * these definitions:
+ *
+ *     R1 = [(x4*128+32 mod P'(x) << 32)]' << 1
+ *     R2 = [(x4*128-32 mod P'(x) << 32)]' << 1
+ *     R3 = [(x128+32 mod P'(x) << 32)]'   << 1
+ *     R4 = [(x128-32 mod P'(x) << 32)]'   << 1
+ *     R5 = [(x64 mod P'(x) << 32)]'       << 1
+ *     R6 = [(x32 mod P'(x) << 32)]'       << 1
+ *
+ *     The bitreflected Barret reduction constant, u', is defined as
+ *     the bit reversal of floor(x**64 / P(x)).
+ *
+ *     where P(x) is the polynomial in the normal domain and the P'(x) is the
+ *     polynomial in the reversed (bitreflected) domain.
+ *
+ * CRC-32 (IEEE 802.3 Ethernet, ...) polynomials:
+ *
+ *     P(x)  = 0x04C11DB7
+ *     P'(x) = 0xEDB88320
+ *
+ * CRC-32C (Castagnoli) polynomials:
+ *
+ *     P(x)  = 0x1EDC6F41
+ *     P'(x) = 0x82F63B78
+ */
+
+static unsigned long constants_CRC_32_LE[] = {
+       0x0f0e0d0c0b0a0908, 0x0706050403020100, /* BE->LE mask */
+       0x1c6e41596, 0x154442bd4,               /* R2, R1 */
+       0x0ccaa009e, 0x1751997d0,               /* R4, R3 */
+       0x0, 0x163cd6124,                       /* R5 */
+       0x0, 0x1f7011641,                       /* u' */
+       0x0, 0x1db710641                        /* P'(x) << 1 */
+};
+
+static unsigned long constants_CRC_32C_LE[] = {
+       0x0f0e0d0c0b0a0908, 0x0706050403020100, /* BE->LE mask */
+       0x09e4addf8, 0x740eef02,                /* R2, R1 */
+       0x14cd00bd6, 0xf20c0dfe,                /* R4, R3 */
+       0x0, 0x0dd45aab8,                       /* R5 */
+       0x0, 0x0dea713f1,                       /* u' */
+       0x0, 0x105ec76f0                        /* P'(x) << 1 */
+};
+
+/**
+ * crc32_le_vgfm_generic - Compute CRC-32 (LE variant) with vector registers
+ * @crc: Initial CRC value, typically ~0.
+ * @buf: Input buffer pointer, performance might be improved if the
+ *      buffer is on a doubleword boundary.
+ * @size: Size of the buffer, must be 64 bytes or greater.
+ * @constants: CRC-32 constant pool base pointer.
+ *
+ * Register usage:
+ *     V0:       Initial CRC value and intermediate constants and results.
+ *     V1..V4:   Data for CRC computation.
+ *     V5..V8:   Next data chunks that are fetched from the input buffer.
+ *     V9:       Constant for BE->LE conversion and shift operations
+ *     V10..V14: CRC-32 constants.
+ */
+static u32 crc32_le_vgfm_generic(u32 crc, unsigned char const *buf, size_t size, unsigned long *constants)
+{
+       /* Load CRC-32 constants */
+       fpu_vlm(CONST_PERM_LE2BE, CONST_CRC_POLY, constants);
+
+       /*
+        * Load the initial CRC value.
+        *
+        * The CRC value is loaded into the rightmost word of the
+        * vector register and is later XORed with the LSB portion
+        * of the loaded input data.
+        */
+       fpu_vzero(0);                   /* Clear V0 */
+       fpu_vlvgf(0, crc, 3);           /* Load CRC into rightmost word */
+
+       /* Load a 64-byte data chunk and XOR with CRC */
+       fpu_vlm(1, 4, buf);
+       fpu_vperm(1, 1, 1, CONST_PERM_LE2BE);
+       fpu_vperm(2, 2, 2, CONST_PERM_LE2BE);
+       fpu_vperm(3, 3, 3, CONST_PERM_LE2BE);
+       fpu_vperm(4, 4, 4, CONST_PERM_LE2BE);
+
+       fpu_vx(1, 0, 1);                /* V1 ^= CRC */
+       buf += 64;
+       size -= 64;
+
+       while (size >= 64) {
+               fpu_vlm(5, 8, buf);
+               fpu_vperm(5, 5, 5, CONST_PERM_LE2BE);
+               fpu_vperm(6, 6, 6, CONST_PERM_LE2BE);
+               fpu_vperm(7, 7, 7, CONST_PERM_LE2BE);
+               fpu_vperm(8, 8, 8, CONST_PERM_LE2BE);
+               /*
+                * Perform a GF(2) multiplication of the doublewords in V1 with
+                * the R1 and R2 reduction constants in V0.  The intermediate
+                * result is then folded (accumulated) with the next data chunk
+                * in V5 and stored in V1. Repeat this step for the register
+                * contents in V2, V3, and V4 respectively.
+                */
+               fpu_vgfmag(1, CONST_R2R1, 1, 5);
+               fpu_vgfmag(2, CONST_R2R1, 2, 6);
+               fpu_vgfmag(3, CONST_R2R1, 3, 7);
+               fpu_vgfmag(4, CONST_R2R1, 4, 8);
+               buf += 64;
+               size -= 64;
+       }
+
+       /*
+        * Fold V1 to V4 into a single 128-bit value in V1.  Multiply V1 with R3
+        * and R4 and accumulating the next 128-bit chunk until a single 128-bit
+        * value remains.
+        */
+       fpu_vgfmag(1, CONST_R4R3, 1, 2);
+       fpu_vgfmag(1, CONST_R4R3, 1, 3);
+       fpu_vgfmag(1, CONST_R4R3, 1, 4);
+
+       while (size >= 16) {
+               fpu_vl(2, buf);
+               fpu_vperm(2, 2, 2, CONST_PERM_LE2BE);
+               fpu_vgfmag(1, CONST_R4R3, 1, 2);
+               buf += 16;
+               size -= 16;
+       }
+
+       /*
+        * Set up a vector register for byte shifts.  The shift value must
+        * be loaded in bits 1-4 in byte element 7 of a vector register.
+        * Shift by 8 bytes: 0x40
+        * Shift by 4 bytes: 0x20
+        */
+       fpu_vleib(9, 0x40, 7);
+
+       /*
+        * Prepare V0 for the next GF(2) multiplication: shift V0 by 8 bytes
+        * to move R4 into the rightmost doubleword and set the leftmost
+        * doubleword to 0x1.
+        */
+       fpu_vsrlb(0, CONST_R4R3, 9);
+       fpu_vleig(0, 1, 0);
+
+       /*
+        * Compute GF(2) product of V1 and V0.  The rightmost doubleword
+        * of V1 is multiplied with R4.  The leftmost doubleword of V1 is
+        * multiplied by 0x1 and is then XORed with rightmost product.
+        * Implicitly, the intermediate leftmost product becomes padded
+        */
+       fpu_vgfmg(1, 0, 1);
+
+       /*
+        * Now do the final 32-bit fold by multiplying the rightmost word
+        * in V1 with R5 and XOR the result with the remaining bits in V1.
+        *
+        * To achieve this by a single VGFMAG, right shift V1 by a word
+        * and store the result in V2 which is then accumulated.  Use the
+        * vector unpack instruction to load the rightmost half of the
+        * doubleword into the rightmost doubleword element of V1; the other
+        * half is loaded in the leftmost doubleword.
+        * The vector register with CONST_R5 contains the R5 constant in the
+        * rightmost doubleword and the leftmost doubleword is zero to ignore
+        * the leftmost product of V1.
+        */
+       fpu_vleib(9, 0x20, 7);            /* Shift by words */
+       fpu_vsrlb(2, 1, 9);               /* Store remaining bits in V2 */
+       fpu_vupllf(1, 1);                 /* Split rightmost doubleword */
+       fpu_vgfmag(1, CONST_R5, 1, 2);    /* V1 = (V1 * R5) XOR V2 */
+
+       /*
+        * Apply a Barret reduction to compute the final 32-bit CRC value.
+        *
+        * The input values to the Barret reduction are the degree-63 polynomial
+        * in V1 (R(x)), degree-32 generator polynomial, and the reduction
+        * constant u.  The Barret reduction result is the CRC value of R(x) mod
+        * P(x).
+        *
+        * The Barret reduction algorithm is defined as:
+        *
+        *    1. T1(x) = floor( R(x) / x^32 ) GF2MUL u
+        *    2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x)
+        *    3. C(x)  = R(x) XOR T2(x) mod x^32
+        *
+        *  Note: The leftmost doubleword of vector register containing
+        *  CONST_RU_POLY is zero and, thus, the intermediate GF(2) product
+        *  is zero and does not contribute to the final result.
+        */
+
+       /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
+       fpu_vupllf(2, 1);
+       fpu_vgfmg(2, CONST_RU_POLY, 2);
+
+       /*
+        * Compute the GF(2) product of the CRC polynomial with T1(x) in
+        * V2 and XOR the intermediate result, T2(x), with the value in V1.
+        * The final result is stored in word element 2 of V2.
+        */
+       fpu_vupllf(2, 2);
+       fpu_vgfmag(2, CONST_CRC_POLY, 2, 1);
+
+       return fpu_vlgvf(2, 2);
+}
+
+u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
+{
+       return crc32_le_vgfm_generic(crc, buf, size, &constants_CRC_32_LE[0]);
+}
+
+u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
+{
+       return crc32_le_vgfm_generic(crc, buf, size, &constants_CRC_32C_LE[0]);
+}