diff options
author | Andrew Turner <andrew@FreeBSD.org> | 2021-07-22 10:24:33 +0000 |
---|---|---|
committer | Andrew Turner <andrew@FreeBSD.org> | 2021-07-22 20:54:21 +0000 |
commit | a93941b439fce7047dffad6bc380cc9454b967cd (patch) | |
tree | bf717a5a5b757c8fca811159b9dfea836b799e7d /sys/libkern | |
parent | 4d1597691916240b9023ee9f15e249503abf67fd (diff) | |
download | src-a93941b439fce7047dffad6bc380cc9454b967cd.tar.gz src-a93941b439fce7047dffad6bc380cc9454b967cd.zip |
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
Diffstat (limited to 'sys/libkern')
-rw-r--r-- | sys/libkern/gsb_crc32.c | 56 |
1 files changed, 38 insertions, 18 deletions
diff --git a/sys/libkern/gsb_crc32.c b/sys/libkern/gsb_crc32.c index 170ceb3aa710..27b9a926888b 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 <machine/md_var.h> #include <machine/specialreg.h> +#include <x86/ifunc.h> #endif #if defined(__aarch64__) -#include <machine/elf.h> -#include <machine/md_var.h> +#include <machine/armreg.h> +#include <machine/ifunc.h> #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) |