aboutsummaryrefslogtreecommitdiff
path: root/sys/libkern
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2021-07-22 10:24:33 +0000
committerAndrew Turner <andrew@FreeBSD.org>2021-07-22 20:54:21 +0000
commita93941b439fce7047dffad6bc380cc9454b967cd (patch)
treebf717a5a5b757c8fca811159b9dfea836b799e7d /sys/libkern
parent4d1597691916240b9023ee9f15e249503abf67fd (diff)
downloadsrc-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.c56
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, &reg)) {
+ 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)