diff options
Diffstat (limited to 'lib/crc')
| -rw-r--r-- | lib/crc/Kconfig | 1 | ||||
| -rw-r--r-- | lib/crc/Makefile | 1 | ||||
| -rw-r--r-- | lib/crc/sparc/crc32.h | 67 | ||||
| -rw-r--r-- | lib/crc/sparc/crc32c_asm.S | 20 |
4 files changed, 89 insertions, 0 deletions
diff --git a/lib/crc/Kconfig b/lib/crc/Kconfig index c8d540a6b04a..0eacefdccc28 100644 --- a/lib/crc/Kconfig +++ b/lib/crc/Kconfig @@ -75,6 +75,7 @@ config CRC32_ARCH default y if PPC64 && ALTIVEC default y if RISCV && RISCV_ISA_ZBC default y if S390 + default y if SPARC64 config CRC64 tristate diff --git a/lib/crc/Makefile b/lib/crc/Makefile index bec58266251f..81e176db0947 100644 --- a/lib/crc/Makefile +++ b/lib/crc/Makefile @@ -28,6 +28,7 @@ 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 +crc32-$(CONFIG_SPARC) += sparc/crc32c_asm.o endif obj-$(CONFIG_CRC64) += crc64.o diff --git a/lib/crc/sparc/crc32.h b/lib/crc/sparc/crc32.h new file mode 100644 index 000000000000..60f2765ac015 --- /dev/null +++ b/lib/crc/sparc/crc32.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* CRC32c (Castagnoli), sparc64 crc32c opcode accelerated + * + * This is based largely upon arch/x86/crypto/crc32c-intel.c + * + * Copyright (C) 2008 Intel Corporation + * Authors: Austin Zhang <austin_zhang@linux.intel.com> + * Kent Liu <kent.liu@intel.com> + */ + +#include <asm/pstate.h> +#include <asm/elf.h> + +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_crc32c_opcode); + +#define crc32_le_arch crc32_le_base /* not implemented on this arch */ +#define crc32_be_arch crc32_be_base /* not implemented on this arch */ + +void crc32c_sparc64(u32 *crcp, const u64 *data, size_t len); + +static inline u32 crc32c_arch(u32 crc, const u8 *data, size_t len) +{ + size_t n = -(uintptr_t)data & 7; + + if (!static_branch_likely(&have_crc32c_opcode)) + return crc32c_base(crc, data, len); + + if (n) { + /* Data isn't 8-byte aligned. Align it. */ + n = min(n, len); + crc = crc32c_base(crc, data, n); + data += n; + len -= n; + } + n = len & ~7U; + if (n) { + crc32c_sparc64(&crc, (const u64 *)data, n); + data += n; + len -= n; + } + if (len) + crc = crc32c_base(crc, data, len); + return crc; +} + +#define crc32_mod_init_arch crc32_mod_init_arch +static inline void crc32_mod_init_arch(void) +{ + unsigned long cfr; + + if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) + return; + + __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); + if (!(cfr & CFR_CRC32C)) + return; + + static_branch_enable(&have_crc32c_opcode); + pr_info("Using sparc64 crc32c opcode optimized CRC32C implementation\n"); +} + +static inline u32 crc32_optimizations_arch(void) +{ + if (static_key_enabled(&have_crc32c_opcode)) + return CRC32C_OPTIMIZATION; + return 0; +} diff --git a/lib/crc/sparc/crc32c_asm.S b/lib/crc/sparc/crc32c_asm.S new file mode 100644 index 000000000000..4db873850f44 --- /dev/null +++ b/lib/crc/sparc/crc32c_asm.S @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <linux/linkage.h> +#include <asm/opcodes.h> +#include <asm/visasm.h> +#include <asm/asi.h> + +ENTRY(crc32c_sparc64) + /* %o0=crc32p, %o1=data_ptr, %o2=len */ + VISEntryHalf + lda [%o0] ASI_PL, %f1 +1: ldd [%o1], %f2 + CRC32C(0,2,0) + subcc %o2, 8, %o2 + bne,pt %icc, 1b + add %o1, 0x8, %o1 + sta %f1, [%o0] ASI_PL + VISExitHalf +2: retl + nop +ENDPROC(crc32c_sparc64) |
