]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
lib/crc64: add support for arch-optimized implementations
authorEric Biggers <ebiggers@google.com>
Thu, 30 Jan 2025 03:51:24 +0000 (19:51 -0800)
committerEric Biggers <ebiggers@google.com>
Sun, 9 Feb 2025 04:06:28 +0000 (20:06 -0800)
Add support for architecture-optimized implementations of the CRC64
library functions, following the approach taken for the CRC32 and
CRC-T10DIF library functions.

Also take the opportunity to tweak the function prototypes:
- Use 'const void *' for the lib entry points (since this is easier for
  users) but 'const u8 *' for the underlying arch and generic functions
  (since this is easier for the implementations of these functions).
- Don't bother with __pure.  It's an unusual optimization that doesn't
  help properly written code.  It's a weird quirk we can do without.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: "Martin K. Petersen" <martin.petersen@oracle.com>
Acked-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20250130035130.180676-6-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
include/linux/crc64.h
lib/Kconfig
lib/crc64.c

index 17cf5af3e78ed0c6395666b64a57032ce313b151..41de30b907dff891fec961a05b12474a234104b0 100644 (file)
@@ -7,8 +7,24 @@
 
 #include <linux/types.h>
 
-u64 __pure crc64_be(u64 crc, const void *p, size_t len);
-u64 __pure crc64_nvme_generic(u64 crc, const void *p, size_t len);
+u64 crc64_be_arch(u64 crc, const u8 *p, size_t len);
+u64 crc64_be_generic(u64 crc, const u8 *p, size_t len);
+u64 crc64_nvme_arch(u64 crc, const u8 *p, size_t len);
+u64 crc64_nvme_generic(u64 crc, const u8 *p, size_t len);
+
+/**
+ * crc64_be - Calculate bitwise big-endian ECMA-182 CRC64
+ * @crc: seed value for computation. 0 or (u64)~0 for a new CRC calculation,
+ *       or the previous crc64 value if computing incrementally.
+ * @p: pointer to buffer over which CRC64 is run
+ * @len: length of buffer @p
+ */
+static inline u64 crc64_be(u64 crc, const void *p, size_t len)
+{
+       if (IS_ENABLED(CONFIG_CRC64_ARCH))
+               return crc64_be_arch(crc, p, len);
+       return crc64_be_generic(crc, p, len);
+}
 
 /**
  * crc64_nvme - Calculate CRC64-NVME
@@ -20,9 +36,11 @@ u64 __pure crc64_nvme_generic(u64 crc, const void *p, size_t len);
  * This computes the CRC64 defined in the NVME NVM Command Set Specification,
  * *including the bitwise inversion at the beginning and end*.
  */
-static inline u64 crc64_nvme(u64 crc, const u8 *p, size_t len)
+static inline u64 crc64_nvme(u64 crc, const void *p, size_t len)
 {
-       return crc64_nvme_generic(crc, p, len);
+       if (IS_ENABLED(CONFIG_CRC64_ARCH))
+               return ~crc64_nvme_arch(~crc, p, len);
+       return ~crc64_nvme_generic(~crc, p, len);
 }
 
 #endif /* _LINUX_CRC64_H */
index da07fd39cf97e2680c73a3bf544893157456bc8e..67bbf4f64dd986054be42db6cf14498f2fd79e72 100644 (file)
@@ -201,6 +201,13 @@ config CRC64
          the kernel tree does. Such modules that use library CRC64
          functions require M here.
 
+config ARCH_HAS_CRC64
+       bool
+
+config CRC64_ARCH
+       tristate
+       default CRC64 if ARCH_HAS_CRC64 && CRC_OPTIMIZATIONS
+
 config CRC4
        tristate "CRC4 functions"
        help
index d6f3f245eedee703dc0f5086ccfe401f7b74d22b..5b1b17057f0aef3dd5d2cc5afd3ab576fe82c3c9 100644 (file)
 MODULE_DESCRIPTION("CRC64 calculations");
 MODULE_LICENSE("GPL v2");
 
-/**
- * crc64_be - Calculate bitwise big-endian ECMA-182 CRC64
- * @crc: seed value for computation. 0 or (u64)~0 for a new CRC calculation,
- *       or the previous crc64 value if computing incrementally.
- * @p: pointer to buffer over which CRC64 is run
- * @len: length of buffer @p
- */
-u64 __pure crc64_be(u64 crc, const void *p, size_t len)
+u64 crc64_be_generic(u64 crc, const u8 *p, size_t len)
 {
-       size_t i, t;
-
-       const unsigned char *_p = p;
-
-       for (i = 0; i < len; i++) {
-               t = ((crc >> 56) ^ (*_p++)) & 0xFF;
-               crc = crc64table[t] ^ (crc << 8);
-       }
-
+       while (len--)
+               crc = (crc << 8) ^ crc64table[(crc >> 56) ^ *p++];
        return crc;
 }
-EXPORT_SYMBOL_GPL(crc64_be);
+EXPORT_SYMBOL_GPL(crc64_be_generic);
 
-u64 __pure crc64_nvme_generic(u64 crc, const void *p, size_t len)
+u64 crc64_nvme_generic(u64 crc, const u8 *p, size_t len)
 {
-       const unsigned char *_p = p;
-       size_t i;
-
-       crc = ~crc;
-
-       for (i = 0; i < len; i++)
-               crc = (crc >> 8) ^ crc64nvmetable[(crc & 0xff) ^ *_p++];
-
-       return ~crc;
+       while (len--)
+               crc = (crc >> 8) ^ crc64nvmetable[(crc & 0xff) ^ *p++];
+       return crc;
 }
 EXPORT_SYMBOL_GPL(crc64_nvme_generic);