diff options
Diffstat (limited to 'arch/loongarch/lib')
-rw-r--r-- | arch/loongarch/lib/Makefile | 4 | ||||
-rw-r--r-- | arch/loongarch/lib/crc32-loongarch.c | 135 | ||||
-rw-r--r-- | arch/loongarch/lib/csum.c | 2 | ||||
-rw-r--r-- | arch/loongarch/lib/tishift.S | 56 |
4 files changed, 196 insertions, 1 deletions
diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile index a77bf160bfc4..fae77809048b 100644 --- a/arch/loongarch/lib/Makefile +++ b/arch/loongarch/lib/Makefile @@ -6,6 +6,10 @@ lib-y += delay.o memset.o memcpy.o memmove.o \ clear_user.o copy_user.o csum.o dump_tlb.o unaligned.o +obj-$(CONFIG_ARCH_SUPPORTS_INT128) += tishift.o + obj-$(CONFIG_CPU_HAS_LSX) += xor_simd.o xor_simd_glue.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o + +obj-$(CONFIG_CRC32_ARCH) += crc32-loongarch.o diff --git a/arch/loongarch/lib/crc32-loongarch.c b/arch/loongarch/lib/crc32-loongarch.c new file mode 100644 index 000000000000..c44ee4f32557 --- /dev/null +++ b/arch/loongarch/lib/crc32-loongarch.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CRC32 and CRC32C using LoongArch crc* instructions + * + * Module based on mips/crypto/crc32-mips.c + * + * Copyright (C) 2014 Linaro Ltd <yazen.ghannam@linaro.org> + * Copyright (C) 2018 MIPS Tech, LLC + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited + */ + +#include <asm/cpu-features.h> +#include <linux/crc32.h> +#include <linux/module.h> +#include <linux/unaligned.h> + +#define _CRC32(crc, value, size, type) \ +do { \ + __asm__ __volatile__( \ + #type ".w." #size ".w" " %0, %1, %0\n\t"\ + : "+r" (crc) \ + : "r" (value) \ + : "memory"); \ +} while (0) + +#define CRC32(crc, value, size) _CRC32(crc, value, size, crc) +#define CRC32C(crc, value, size) _CRC32(crc, value, size, crcc) + +static DEFINE_STATIC_KEY_FALSE(have_crc32); + +u32 crc32_le_arch(u32 crc, const u8 *p, size_t len) +{ + if (!static_branch_likely(&have_crc32)) + return crc32_le_base(crc, p, len); + + while (len >= sizeof(u64)) { + u64 value = get_unaligned_le64(p); + + CRC32(crc, value, d); + p += sizeof(u64); + len -= sizeof(u64); + } + + if (len & sizeof(u32)) { + u32 value = get_unaligned_le32(p); + + CRC32(crc, value, w); + p += sizeof(u32); + } + + if (len & sizeof(u16)) { + u16 value = get_unaligned_le16(p); + + CRC32(crc, value, h); + p += sizeof(u16); + } + + if (len & sizeof(u8)) { + u8 value = *p++; + + CRC32(crc, value, b); + } + + return crc; +} +EXPORT_SYMBOL(crc32_le_arch); + +u32 crc32c_arch(u32 crc, const u8 *p, size_t len) +{ + if (!static_branch_likely(&have_crc32)) + return crc32c_base(crc, p, len); + + while (len >= sizeof(u64)) { + u64 value = get_unaligned_le64(p); + + CRC32C(crc, value, d); + p += sizeof(u64); + len -= sizeof(u64); + } + + if (len & sizeof(u32)) { + u32 value = get_unaligned_le32(p); + + CRC32C(crc, value, w); + p += sizeof(u32); + } + + if (len & sizeof(u16)) { + u16 value = get_unaligned_le16(p); + + CRC32C(crc, value, h); + p += sizeof(u16); + } + + if (len & sizeof(u8)) { + u8 value = *p++; + + CRC32C(crc, value, b); + } + + return crc; +} +EXPORT_SYMBOL(crc32c_arch); + +u32 crc32_be_arch(u32 crc, const u8 *p, size_t len) +{ + return crc32_be_base(crc, p, len); +} +EXPORT_SYMBOL(crc32_be_arch); + +static int __init crc32_loongarch_init(void) +{ + if (cpu_has_crc32) + static_branch_enable(&have_crc32); + return 0; +} +arch_initcall(crc32_loongarch_init); + +static void __exit crc32_loongarch_exit(void) +{ +} +module_exit(crc32_loongarch_exit); + +u32 crc32_optimizations(void) +{ + if (static_key_enabled(&have_crc32)) + return CRC32_LE_OPTIMIZATION | CRC32C_OPTIMIZATION; + return 0; +} +EXPORT_SYMBOL(crc32_optimizations); + +MODULE_AUTHOR("Min Zhou <zhoumin@loongson.cn>"); +MODULE_AUTHOR("Huacai Chen <chenhuacai@loongson.cn>"); +MODULE_DESCRIPTION("CRC32 and CRC32C using LoongArch crc* instructions"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/loongarch/lib/csum.c b/arch/loongarch/lib/csum.c index a5e84b403c3b..df309ae4045d 100644 --- a/arch/loongarch/lib/csum.c +++ b/arch/loongarch/lib/csum.c @@ -25,7 +25,7 @@ unsigned int __no_sanitize_address do_csum(const unsigned char *buff, int len) const u64 *ptr; u64 data, sum64 = 0; - if (unlikely(len == 0)) + if (unlikely(len <= 0)) return 0; offset = (unsigned long)buff & 7; diff --git a/arch/loongarch/lib/tishift.S b/arch/loongarch/lib/tishift.S new file mode 100644 index 000000000000..fa1d310012bc --- /dev/null +++ b/arch/loongarch/lib/tishift.S @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <asm/asmmacro.h> +#include <linux/export.h> +#include <linux/linkage.h> + +SYM_FUNC_START(__ashlti3) + srli.d t2, a0, 1 + nor t3, zero, a2 + sll.d t1, a1, a2 + srl.d t2, t2, t3 + andi t0, a2, 64 + sll.d a0, a0, a2 + or t1, t2, t1 + maskeqz a1, a0, t0 + masknez a0, a0, t0 + masknez t0, t1, t0 + or a1, t0, a1 + jr ra +SYM_FUNC_END(__ashlti3) +EXPORT_SYMBOL(__ashlti3) + +SYM_FUNC_START(__ashrti3) + nor t3, zero, a2 + slli.d t2, a1, 1 + srl.d t1, a0, a2 + sll.d t2, t2, t3 + andi t0, a2, 64 + or t1, t2, t1 + sra.d a2, a1, a2 + srai.d a1, a1, 63 + maskeqz a0, a2, t0 + maskeqz a1, a1, t0 + masknez a2, a2, t0 + masknez t0, t1, t0 + or a1, a1, a2 + or a0, t0, a0 + jr ra +SYM_FUNC_END(__ashrti3) +EXPORT_SYMBOL(__ashrti3) + +SYM_FUNC_START(__lshrti3) + slli.d t2, a1, 1 + nor t3, zero, a2 + srl.d t1, a0, a2 + sll.d t2, t2, t3 + andi t0, a2, 64 + srl.d a1, a1, a2 + or t1, t2, t1 + maskeqz a0, a1, t0 + masknez a1, a1, t0 + masknez t0, t1, t0 + or a0, t0, a0 + jr ra +SYM_FUNC_END(__lshrti3) +EXPORT_SYMBOL(__lshrti3) |