]> git.apps.os.sepia.ceph.com Git - ceph-client.git/commitdiff
lib/crc: s390: Migrate optimized CRC code into lib/crc/
authorEric Biggers <ebiggers@kernel.org>
Sat, 7 Jun 2025 20:04:51 +0000 (13:04 -0700)
committerEric Biggers <ebiggers@kernel.org>
Mon, 30 Jun 2025 16:31:57 +0000 (09:31 -0700)
Move the s390-optimized CRC code from arch/s390/lib/crc* into its new
location in lib/crc/s390/, and wire it up in the new way.  This new way
of organizing the CRC code eliminates the need to artificially split the
code for each CRC variant into separate arch and generic modules,
enabling better inlining and dead code elimination.  For more details,
see "lib/crc: Prepare for arch-optimized code in subdirs of lib/crc/".

Reviewed-by: "Martin K. Petersen" <martin.petersen@oracle.com>
Acked-by: Ingo Molnar <mingo@kernel.org>
Acked-by: "Jason A. Donenfeld" <Jason@zx2c4.com>
Link: https://lore.kernel.org/r/20250607200454.73587-10-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
12 files changed:
arch/s390/Kconfig
arch/s390/lib/Makefile
arch/s390/lib/crc32-vx.h [deleted file]
arch/s390/lib/crc32.c [deleted file]
arch/s390/lib/crc32be-vx.c [deleted file]
arch/s390/lib/crc32le-vx.c [deleted file]
lib/crc/Kconfig
lib/crc/Makefile
lib/crc/s390/crc32-vx.h [new file with mode: 0644]
lib/crc/s390/crc32.h [new file with mode: 0644]
lib/crc/s390/crc32be-vx.c [new file with mode: 0644]
lib/crc/s390/crc32le-vx.c [new file with mode: 0644]

index 0c16dc443e2f65fc6bd71352e1cc8d7aa60a7c6a..22b90f6aa1a09d4355e07b259c205c3590737f18 100644 (file)
@@ -75,7 +75,6 @@ config S390
        select ARCH_ENABLE_MEMORY_HOTREMOVE
        select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
        select ARCH_HAS_CPU_FINALIZE_INIT
-       select ARCH_HAS_CRC32
        select ARCH_HAS_CURRENT_STACK_POINTER
        select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEBUG_VM_PGTABLE
index cd35cdbfa87134ab67ea0e0a9d490d4c95fe9b0e..7c8583d46eca1d50cd2d3bf76d04210c0ae24649 100644 (file)
@@ -25,6 +25,3 @@ 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.o crc32le-vx.o crc32be-vx.o
diff --git a/arch/s390/lib/crc32-vx.h b/arch/s390/lib/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/lib/crc32.c b/arch/s390/lib/crc32.c
deleted file mode 100644 (file)
index 3c4b344..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-// 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)
-
-/*
- * 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 || !cpu_has_vx())  \
-                       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_arch, crc32c_le_vgfm_16, crc32c_base)
-
-u32 crc32_optimizations(void)
-{
-       if (cpu_has_vx()) {
-               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/crc32be-vx.c b/arch/s390/lib/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/lib/crc32le-vx.c b/arch/s390/lib/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 b8894c451aca9d31631f691b5ea403b08cd0f40e..c8d540a6b04a0563e87097706597e17dc89f8aff 100644 (file)
@@ -74,6 +74,7 @@ config CRC32_ARCH
        default y if MIPS && CPU_MIPSR6
        default y if PPC64 && ALTIVEC
        default y if RISCV && RISCV_ISA_ZBC
+       default y if S390
 
 config CRC64
        tristate
index 190f889adf556e98daf332c3993204c94e0f0e47..bec58266251f8555c5461368659cf09031c9894b 100644 (file)
@@ -27,6 +27,7 @@ crc32-$(CONFIG_ARM) += arm/crc32-core.o
 crc32-$(CONFIG_ARM64) += arm64/crc32-core.o
 crc32-$(CONFIG_PPC) += powerpc/crc32c-vpmsum_asm.o
 crc32-$(CONFIG_RISCV) += riscv/crc32_lsb.o riscv/crc32_msb.o
+crc32-$(CONFIG_S390) += s390/crc32le-vx.o s390/crc32be-vx.o
 endif
 
 obj-$(CONFIG_CRC64) += crc64.o
diff --git a/lib/crc/s390/crc32-vx.h b/lib/crc/s390/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/lib/crc/s390/crc32.h b/lib/crc/s390/crc32.h
new file mode 100644 (file)
index 0000000..59c8983
--- /dev/null
@@ -0,0 +1,67 @@
+// 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>
+ */
+
+#include <linux/cpufeature.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)
+
+/*
+ * 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 inline 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 || !cpu_has_vx())  \
+                       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_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_arch, crc32c_le_vgfm_16, crc32c_base)
+
+static inline u32 crc32_optimizations_arch(void)
+{
+       if (cpu_has_vx()) {
+               return CRC32_LE_OPTIMIZATION |
+                      CRC32_BE_OPTIMIZATION |
+                      CRC32C_OPTIMIZATION;
+       }
+       return 0;
+}
diff --git a/lib/crc/s390/crc32be-vx.c b/lib/crc/s390/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/lib/crc/s390/crc32le-vx.c b/lib/crc/s390/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]);
+}