linux/lib/crc/crc64-neon.c
Ard Biesheuvel 061cef5fce lib/crc: Turn NEON intrinsics crc64 implementation into common code
Move and rename the CRC64 NEON intrinsics implementation source file and
rename the function name to reflect that it is NEON code that can be
shared. This will be wired up for 32-bit ARM in a subsequent patch.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20260422171655.3437334-14-ardb+git@google.com
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
2026-05-28 13:14:22 -07:00

48 lines
1.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Accelerated CRC64 (NVMe) using ARM NEON C intrinsics
*/
#include <linux/types.h>
#include <asm/neon-intrinsics.h>
#include "crc64-neon.h"
u64 crc64_nvme_neon(u64 crc, const u8 *p, size_t len);
/* x^191 mod G, x^127 mod G */
static const u64 fold_consts_val[2] = { 0xeadc41fd2ba3d420ULL,
0x21e9761e252621acULL };
/* floor(x^127 / G), (G - x^64) / x */
static const u64 bconsts_val[2] = { 0x27ecfa329aef9f77ULL,
0x34d926535897936aULL };
u64 crc64_nvme_neon(u64 crc, const u8 *p, size_t len)
{
uint64x2_t fold_consts = vld1q_u64(fold_consts_val);
uint64x2_t v0 = { crc, 0 };
uint64x2_t zero = { };
for (;;) {
v0 ^= vreinterpretq_u64_u8(vld1q_u8(p));
p += 16;
len -= 16;
if (len < 16)
break;
v0 = pmull64(fold_consts, v0) ^ pmull64_high(fold_consts, v0);
}
/* Multiply the 128-bit value by x^64 and reduce it back to 128 bits. */
v0 = vextq_u64(v0, zero, 1) ^ pmull64_hi_lo(fold_consts, v0);
/* Final Barrett reduction */
uint64x2_t bconsts = vld1q_u64(bconsts_val);
uint64x2_t final = pmull64(bconsts, v0);
v0 ^= vextq_u64(zero, final, 1) ^ pmull64_hi_lo(bconsts, final);
return vgetq_lane_u64(v0, 1);
}