Add SHA2 SIMD feature tests for libspl

These are added via HWCAP interface:
- zfs_neon_available() for arm and aarch64
- zfs_sha256_available() for arm and aarch64
- zfs_sha512_available() for aarch64

This one via cpuid() call:
- zfs_shani_available() for x86_64

Tested-by: Rich Ercolani <rincebrain@gmail.com>
Tested-by: Sebastian Gottschall <s.gottschall@dd-wrt.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tino Reichardt <milky-zfs@mcmilk.de>
Closes #13741
This commit is contained in:
Tino Reichardt 2022-09-28 10:54:35 +02:00 committed by Brian Behlendorf
parent cef1253135
commit ac678c8eee
2 changed files with 101 additions and 26 deletions

View File

@ -46,7 +46,6 @@ libspl_sys_HEADERS = \
%D%/sys/poll.h \ %D%/sys/poll.h \
%D%/sys/priv.h \ %D%/sys/priv.h \
%D%/sys/processor.h \ %D%/sys/processor.h \
%D%/sys/sha2.h \
%D%/sys/simd.h \ %D%/sys/simd.h \
%D%/sys/stack.h \ %D%/sys/stack.h \
%D%/sys/stdtypes.h \ %D%/sys/stdtypes.h \

View File

@ -30,6 +30,28 @@
#include <sys/isa_defs.h> #include <sys/isa_defs.h>
#include <sys/types.h> #include <sys/types.h>
/* including <sys/auxv.h> clashes with AT_UID and others */
#if defined(__arm__) || defined(__aarch64__) || defined(powerpc)
#if defined(__FreeBSD__)
#define AT_HWCAP 25
#define AT_HWCAP2 26
extern int elf_aux_info(int aux, void *buf, int buflen);
static inline unsigned long getauxval(unsigned long key)
{
unsigned long val = 0UL;
if (elf_aux_info((int)key, &val, sizeof (val)) != 0)
return (0UL);
return (val);
}
#elif defined(__linux__)
#define AT_HWCAP 16
#define AT_HWCAP2 26
extern unsigned long getauxval(unsigned long type);
#endif /* __linux__ */
#endif /* arm || aarch64 || powerpc */
#if defined(__x86) #if defined(__x86)
#include <cpuid.h> #include <cpuid.h>
@ -78,7 +100,8 @@ typedef enum cpuid_inst_sets {
AVX512VL, AVX512VL,
AES, AES,
PCLMULQDQ, PCLMULQDQ,
MOVBE MOVBE,
SHA_NI
} cpuid_inst_sets_t; } cpuid_inst_sets_t;
/* /*
@ -103,6 +126,7 @@ typedef struct cpuid_feature_desc {
#define _AES_BIT (1U << 25) #define _AES_BIT (1U << 25)
#define _PCLMULQDQ_BIT (1U << 1) #define _PCLMULQDQ_BIT (1U << 1)
#define _MOVBE_BIT (1U << 22) #define _MOVBE_BIT (1U << 22)
#define _SHA_NI_BIT (1U << 29)
/* /*
* Descriptions of supported instruction sets * Descriptions of supported instruction sets
@ -131,6 +155,7 @@ static const cpuid_feature_desc_t cpuid_features[] = {
[AES] = {1U, 0U, _AES_BIT, ECX }, [AES] = {1U, 0U, _AES_BIT, ECX },
[PCLMULQDQ] = {1U, 0U, _PCLMULQDQ_BIT, ECX }, [PCLMULQDQ] = {1U, 0U, _PCLMULQDQ_BIT, ECX },
[MOVBE] = {1U, 0U, _MOVBE_BIT, ECX }, [MOVBE] = {1U, 0U, _MOVBE_BIT, ECX },
[SHA_NI] = {7U, 0U, _SHA_NI_BIT, EBX },
}; };
/* /*
@ -204,6 +229,7 @@ CPUID_FEATURE_CHECK(avx512vl, AVX512VL);
CPUID_FEATURE_CHECK(aes, AES); CPUID_FEATURE_CHECK(aes, AES);
CPUID_FEATURE_CHECK(pclmulqdq, PCLMULQDQ); CPUID_FEATURE_CHECK(pclmulqdq, PCLMULQDQ);
CPUID_FEATURE_CHECK(movbe, MOVBE); CPUID_FEATURE_CHECK(movbe, MOVBE);
CPUID_FEATURE_CHECK(shani, SHA_NI);
/* /*
* Detect register set support * Detect register set support
@ -345,6 +371,15 @@ zfs_movbe_available(void)
return (__cpuid_has_movbe()); return (__cpuid_has_movbe());
} }
/*
* Check if SHA_NI instruction is available
*/
static inline boolean_t
zfs_shani_available(void)
{
return (__cpuid_has_shani());
}
/* /*
* AVX-512 family of instruction sets: * AVX-512 family of instruction sets:
* *
@ -443,6 +478,36 @@ zfs_avx512vbmi_available(void)
__zmm_enabled()); __zmm_enabled());
} }
#elif defined(__arm__)
#define kfpu_allowed() 1
#define kfpu_initialize(tsk) do {} while (0)
#define kfpu_begin() do {} while (0)
#define kfpu_end() do {} while (0)
#define HWCAP_NEON 0x00001000
#define HWCAP2_SHA2 0x00000008
/*
* Check if NEON is available
*/
static inline boolean_t
zfs_neon_available(void)
{
unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & HWCAP_NEON);
}
/*
* Check if SHA2 is available
*/
static inline boolean_t
zfs_sha256_available(void)
{
unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & HWCAP2_SHA2);
}
#elif defined(__aarch64__) #elif defined(__aarch64__)
#define kfpu_allowed() 1 #define kfpu_allowed() 1
@ -450,28 +515,41 @@ zfs_avx512vbmi_available(void)
#define kfpu_begin() do {} while (0) #define kfpu_begin() do {} while (0)
#define kfpu_end() do {} while (0) #define kfpu_end() do {} while (0)
#elif defined(__powerpc__) #define HWCAP_FP 0x00000001
#define HWCAP_SHA2 0x00000040
#define HWCAP_SHA512 0x00200000
/* including <sys/auxv.h> clashes with AT_UID and others */ /*
#if defined(__FreeBSD__) * Check if NEON is available
#define AT_HWCAP 25 /* CPU feature flags. */ */
#define AT_HWCAP2 26 /* CPU feature flags 2. */ static inline boolean_t
extern int elf_aux_info(int aux, void *buf, int buflen); zfs_neon_available(void)
static inline unsigned long
getauxval(unsigned long key)
{ {
unsigned long val = 0UL; unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & HWCAP_FP);
if (elf_aux_info((int)key, &val, sizeof (val)) != 0)
return (0UL);
return (val);
} }
#elif defined(__linux__)
#define AT_HWCAP 16 /* CPU feature flags. */ /*
#define AT_HWCAP2 26 /* CPU feature flags 2. */ * Check if SHA2 is available
extern unsigned long getauxval(unsigned long type); */
#endif static inline boolean_t
zfs_sha256_available(void)
{
unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & HWCAP_SHA2);
}
/*
* Check if SHA512 is available
*/
static inline boolean_t
zfs_sha512_available(void)
{
unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & HWCAP_SHA512);
}
#elif defined(__powerpc__)
#define kfpu_allowed() 1 #define kfpu_allowed() 1
#define kfpu_initialize(tsk) do {} while (0) #define kfpu_initialize(tsk) do {} while (0)
@ -479,30 +557,28 @@ extern unsigned long getauxval(unsigned long type);
#define kfpu_end() do {} while (0) #define kfpu_end() do {} while (0)
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000 #define PPC_FEATURE_HAS_ALTIVEC 0x10000000
#define PPC_FEATURE_HAS_VSX 0x00000080
#define PPC_FEATURE2_ARCH_2_07 0x80000000
static inline boolean_t static inline boolean_t
zfs_altivec_available(void) zfs_altivec_available(void)
{ {
unsigned long hwcap = getauxval(AT_HWCAP); unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & PPC_FEATURE_HAS_ALTIVEC); return (hwcap & PPC_FEATURE_HAS_ALTIVEC);
} }
#define PPC_FEATURE_HAS_VSX 0x00000080
static inline boolean_t static inline boolean_t
zfs_vsx_available(void) zfs_vsx_available(void)
{ {
unsigned long hwcap = getauxval(AT_HWCAP); unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & PPC_FEATURE_HAS_VSX); return (hwcap & PPC_FEATURE_HAS_VSX);
} }
#define PPC_FEATURE2_ARCH_2_07 0x80000000
static inline boolean_t static inline boolean_t
zfs_isa207_available(void) zfs_isa207_available(void)
{ {
unsigned long hwcap = getauxval(AT_HWCAP); unsigned long hwcap = getauxval(AT_HWCAP);
unsigned long hwcap2 = getauxval(AT_HWCAP2); unsigned long hwcap2 = getauxval(AT_HWCAP2);
return ((hwcap & PPC_FEATURE_HAS_VSX) && return ((hwcap & PPC_FEATURE_HAS_VSX) &&
(hwcap2 & PPC_FEATURE2_ARCH_2_07)); (hwcap2 & PPC_FEATURE2_ARCH_2_07));
} }