From a93941b439fce7047dffad6bc380cc9454b967cd Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Thu, 22 Jul 2021 10:24:33 +0000 Subject: [PATCH] Switch to an ifunc in the kernel for crc32c There is no need to read the same variable to check if the CPU supports crc32c instructions. Reviewed by: arichardson, kib, markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D31274 --- sys/libkern/gsb_crc32.c | 56 ++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/sys/libkern/gsb_crc32.c b/sys/libkern/gsb_crc32.c index 170ceb3aa71..27b9a926888 100644 --- a/sys/libkern/gsb_crc32.c +++ b/sys/libkern/gsb_crc32.c @@ -55,11 +55,12 @@ __FBSDID("$FreeBSD$"); #if defined(__amd64__) || defined(__i386__) #include #include +#include #endif #if defined(__aarch64__) -#include -#include +#include +#include #endif #endif /* _KERNEL */ @@ -750,29 +751,48 @@ multitable_crc32c(uint32_t crc32c, return (crc32c_sb8_64_bit(crc32c, buffer, length, to_even_word)); } -uint32_t -calculate_crc32c(uint32_t crc32c, - const unsigned char *buffer, - unsigned int length) +static uint32_t +table_crc32c(uint32_t crc32c, const unsigned char *buffer, unsigned int length) { -#ifdef _KERNEL -#if defined(__amd64__) || defined(__i386__) - if ((cpu_feature2 & CPUID2_SSE42) != 0) { - return (sse42_crc32c(crc32c, buffer, length)); - } else -#endif -#if defined(__aarch64__) - if ((elf_hwcap & HWCAP_CRC32) != 0) { - return (armv8_crc32c(crc32c, buffer, length)); - } else -#endif -#endif /* _KERNEL */ if (length < 4) { return (singletable_crc32c(crc32c, buffer, length)); } else { return (multitable_crc32c(crc32c, buffer, length)); } } + +#if defined(_KERNEL) && defined(__aarch64__) +DEFINE_IFUNC(, uint32_t, calculate_crc32c, + (uint32_t crc32c, const unsigned char *buffer, unsigned int length)) +{ + uint64_t reg; + + if (get_kernel_reg(ID_AA64ISAR0_EL1, ®)) { + if (ID_AA64ISAR0_CRC32_VAL(reg) >= ID_AA64ISAR0_CRC32_BASE) + return (armv8_crc32c); + } + + return (table_crc32c); +} +#elif defined(_KERNEL) && (defined(__amd64__) || defined(__i386__)) +DEFINE_IFUNC(, uint32_t, calculate_crc32c, + (uint32_t crc32c, const unsigned char *buffer, unsigned int length)) +{ + if ((cpu_feature2 & CPUID2_SSE42) != 0) + return (sse42_crc32c); + + return (table_crc32c); +} +#else +uint32_t +calculate_crc32c(uint32_t crc32c, + const unsigned char *buffer, + unsigned int length) +{ + return (table_crc32c(crc32c, buffer, length)); +} +#endif /* _KERNEL && __aarch64__ */ + #else uint32_t calculate_crc32c(uint32_t crc32c, const unsigned char *buffer, unsigned int length)