// SPDX-License-Identifier: GPL-2.0-only
      /*
       * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal.
       * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE)
       * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at:
       * http://www.intel.com/products/processor/manuals/
       * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
       * Volume 2A: Instruction Set Reference, A-M
       *
       * Copyright (C) 2008 Intel Corporation
       * Authors: Austin Zhang <austin_zhang@linux.intel.com>
       *          Kent Liu <kent.liu@intel.com>
       */
      #include <linux/init.h>
      #include <linux/module.h>
      #include <linux/string.h>
      #include <linux/kernel.h>
      #include <crypto/internal/hash.h>
      #include <crypto/internal/simd.h>
      
      #include <asm/cpufeatures.h>
      #include <asm/cpu_device_id.h>
      #include <asm/simd.h>
      
      #define CHKSUM_BLOCK_SIZE        1
      #define CHKSUM_DIGEST_SIZE        4
      
      #define SCALE_F        sizeof(unsigned long)
      
      #ifdef CONFIG_X86_64
      #define CRC32_INST "crc32q %1, %q0"
      #else
      #define CRC32_INST "crc32l %1, %0"
      #endif
      
      #ifdef CONFIG_X86_64
      /*
       * use carryless multiply version of crc32c when buffer
       * size is >= 512 to account
       * for fpu state save/restore overhead.
       */
      #define CRC32C_PCL_BREAKEVEN        512
      
      asmlinkage unsigned int crc_pcl(const u8 *buffer, int len,
                                      unsigned int crc_init);
      #endif /* CONFIG_X86_64 */
      
      static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length)
      {
              while (length--) {
                      asm("crc32b %1, %0"
   25                     : "+r" (crc) : "rm" (*data));
                      data++;
              }
      
              return crc;
      }
      
      static u32 __pure crc32c_intel_le_hw(u32 crc, unsigned char const *p, size_t len)
      {
              unsigned int iquotient = len / SCALE_F;
              unsigned int iremainder = len % SCALE_F;
              unsigned long *ptmp = (unsigned long *)p;
      
              while (iquotient--) {
                      asm(CRC32_INST
   47                     : "+r" (crc) : "rm" (*ptmp));
                      ptmp++;
              }
      
   47         if (iremainder)
   25                 crc = crc32c_intel_le_hw_byte(crc, (unsigned char *)ptmp,
                                       iremainder);
      
              return crc;
      }
      
      /*
       * Setting the seed allows arbitrary accumulators and flexible XOR policy
       * If your algorithm starts with ~0, then XOR with ~0 before you set
       * the seed.
       */
      static int crc32c_intel_setkey(struct crypto_shash *hash, const u8 *key,
                              unsigned int keylen)
      {
              u32 *mctx = crypto_shash_ctx(hash);
      
              if (keylen != sizeof(u32))
                      return -EINVAL;
              *mctx = le32_to_cpup((__le32 *)key);
              return 0;
      }
      
      static int crc32c_intel_init(struct shash_desc *desc)
      {
              u32 *mctx = crypto_shash_ctx(desc->tfm);
              u32 *crcp = shash_desc_ctx(desc);
      
              *crcp = *mctx;
      
              return 0;
      }
      
      static int crc32c_intel_update(struct shash_desc *desc, const u8 *data,
                                     unsigned int len)
      {