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
This commit is contained in:
Andrew Turner 2021-07-22 10:24:33 +00:00
parent 4d15976919
commit a93941b439

View File

@ -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)