lib/crc64: add support for arch-optimized implementations

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>
This commit is contained in:
Eric Biggers 2025-01-29 19:51:24 -08:00
parent 23709bd3c4
commit 067bc8717a
3 changed files with 37 additions and 32 deletions

View 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 */

View 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

View File

@ -41,38 +41,18 @@
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);