From e22bfd814960295029ca41c8e116e8d516d3e730 Mon Sep 17 00:00:00 2001 From: Tony Hutter Date: Fri, 11 Jan 2019 18:01:28 -0800 Subject: [PATCH] Linux 5.0 compat: Disable vector instructions on 5.0+ kernels The 5.0 kernel no longer exports the functions we need to do vector (SSE/SSE2/SSE3/AVX...) instructions. Disable vector-based checksum algorithms when building against those kernels. Reviewed-by: Brian Behlendorf Signed-off-by: Tony Hutter Closes #8259 --- config/kernel-fpu.m4 | 41 ++++++++++--- include/linux/simd_x86.h | 127 +++++++++++++++++++++++++++++++-------- 2 files changed, 134 insertions(+), 34 deletions(-) diff --git a/config/kernel-fpu.m4 b/config/kernel-fpu.m4 index 1c5690969d..671fe7ea54 100644 --- a/config/kernel-fpu.m4 +++ b/config/kernel-fpu.m4 @@ -1,18 +1,41 @@ +dnl # +dnl # Handle differences in kernel FPU code. dnl # -dnl # 4.2 API change -dnl # asm/i387.h is replaced by asm/fpu/api.h +dnl # Kernel +dnl # 5.0: All kernel fpu functions are GPL only, so we can't use them. +dnl # (nothing defined) +dnl # +dnl # 4.2: Use __kernel_fpu_{begin,end}() +dnl # HAVE_UNDERSCORE_KERNEL_FPU & KERNEL_EXPORTS_X86_FPU +dnl # +dnl # Pre-4.2: Use kernel_fpu_{begin,end}() +dnl # HAVE_KERNEL_FPU & KERNEL_EXPORTS_X86_FPU dnl # AC_DEFUN([ZFS_AC_KERNEL_FPU], [ - AC_MSG_CHECKING([whether asm/fpu/api.h exists]) + AC_MSG_CHECKING([which kernel_fpu function to use]) ZFS_LINUX_TRY_COMPILE([ - #include - #include + #include + #include ],[ - __kernel_fpu_begin(); + kernel_fpu_begin(); + kernel_fpu_end(); ],[ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_FPU_API_H, 1, [kernel has interface]) + AC_MSG_RESULT(kernel_fpu_*) + AC_DEFINE(HAVE_KERNEL_FPU, 1, [kernel has kernel_fpu_* functions]) + AC_DEFINE(KERNEL_EXPORTS_X86_FPU, 1, [kernel exports FPU functions]) ],[ - AC_MSG_RESULT(no) + ZFS_LINUX_TRY_COMPILE([ + #include + #include + ],[ + __kernel_fpu_begin(); + __kernel_fpu_end(); + ],[ + AC_MSG_RESULT(__kernel_fpu_*) + AC_DEFINE(HAVE_UNDERSCORE_KERNEL_FPU, 1, [kernel has __kernel_fpu_* functions]) + AC_DEFINE(KERNEL_EXPORTS_X86_FPU, 1, [kernel exports FPU functions]) + ],[ + AC_MSG_RESULT(not exported) + ]) ]) ]) diff --git a/include/linux/simd_x86.h b/include/linux/simd_x86.h index c9e3970c0c..c55cb17789 100644 --- a/include/linux/simd_x86.h +++ b/include/linux/simd_x86.h @@ -81,7 +81,7 @@ #endif #if defined(_KERNEL) -#if defined(HAVE_FPU_API_H) +#if defined(HAVE_UNDERSCORE_KERNEL_FPU) #include #include #define kfpu_begin() \ @@ -94,12 +94,18 @@ __kernel_fpu_end(); \ preempt_enable(); \ } -#else +#elif defined(HAVE_KERNEL_FPU) #include #include #define kfpu_begin() kernel_fpu_begin() #define kfpu_end() kernel_fpu_end() -#endif /* defined(HAVE_FPU_API_H) */ +#else +/* Kernel doesn't export any kernel_fpu_* functions */ +#include /* For kernel xgetbv() */ +#define kfpu_begin() panic("This code should never run") +#define kfpu_end() panic("This code should never run") +#endif /* defined(HAVE_KERNEL_FPU) */ + #else /* * fpu dummy methods for userspace @@ -278,11 +284,13 @@ __simd_state_enabled(const uint64_t state) boolean_t has_osxsave; uint64_t xcr0; -#if defined(_KERNEL) && defined(X86_FEATURE_OSXSAVE) +#if defined(_KERNEL) +#if defined(X86_FEATURE_OSXSAVE) && defined(KERNEL_EXPORTS_X86_FPU) has_osxsave = !!boot_cpu_has(X86_FEATURE_OSXSAVE); -#elif defined(_KERNEL) && !defined(X86_FEATURE_OSXSAVE) - has_osxsave = B_FALSE; #else + has_osxsave = B_FALSE; +#endif +#elif !defined(_KERNEL) has_osxsave = __cpuid_has_osxsave(); #endif @@ -307,8 +315,12 @@ static inline boolean_t zfs_sse_available(void) { #if defined(_KERNEL) +#if defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_XMM)); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_sse()); #endif } @@ -320,8 +332,12 @@ static inline boolean_t zfs_sse2_available(void) { #if defined(_KERNEL) +#if defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_XMM2)); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_sse2()); #endif } @@ -333,8 +349,12 @@ static inline boolean_t zfs_sse3_available(void) { #if defined(_KERNEL) +#if defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_XMM3)); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_sse3()); #endif } @@ -346,8 +366,12 @@ static inline boolean_t zfs_ssse3_available(void) { #if defined(_KERNEL) +#if defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_SSSE3)); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_ssse3()); #endif } @@ -359,8 +383,12 @@ static inline boolean_t zfs_sse4_1_available(void) { #if defined(_KERNEL) +#if defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_XMM4_1)); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_sse4_1()); #endif } @@ -372,8 +400,12 @@ static inline boolean_t zfs_sse4_2_available(void) { #if defined(_KERNEL) +#if defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_XMM4_2)); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_sse4_2()); #endif } @@ -386,8 +418,12 @@ zfs_avx_available(void) { boolean_t has_avx; #if defined(_KERNEL) +#if defined(KERNEL_EXPORTS_X86_FPU) has_avx = !!boot_cpu_has(X86_FEATURE_AVX); #else + has_avx = B_FALSE; +#endif +#elif !defined(_KERNEL) has_avx = __cpuid_has_avx(); #endif @@ -401,11 +437,13 @@ static inline boolean_t zfs_avx2_available(void) { boolean_t has_avx2; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX2) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX2) && defined(KERNEL_EXPORTS_X86_FPU) has_avx2 = !!boot_cpu_has(X86_FEATURE_AVX2); -#elif defined(_KERNEL) && !defined(X86_FEATURE_AVX2) - has_avx2 = B_FALSE; #else + has_avx2 = B_FALSE; +#endif +#elif !defined(_KERNEL) has_avx2 = __cpuid_has_avx2(); #endif @@ -418,11 +456,13 @@ zfs_avx2_available(void) static inline boolean_t zfs_bmi1_available(void) { -#if defined(_KERNEL) && defined(X86_FEATURE_BMI1) +#if defined(_KERNEL) +#if defined(X86_FEATURE_BMI1) && defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_BMI1)); -#elif defined(_KERNEL) && !defined(X86_FEATURE_BMI1) - return (B_FALSE); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_bmi1()); #endif } @@ -433,16 +473,17 @@ zfs_bmi1_available(void) static inline boolean_t zfs_bmi2_available(void) { -#if defined(_KERNEL) && defined(X86_FEATURE_BMI2) +#if defined(_KERNEL) +#if defined(X86_FEATURE_BMI2) && defined(KERNEL_EXPORTS_X86_FPU) return (!!boot_cpu_has(X86_FEATURE_BMI2)); -#elif defined(_KERNEL) && !defined(X86_FEATURE_BMI2) - return (B_FALSE); #else + return (B_FALSE); +#endif +#elif !defined(_KERNEL) return (__cpuid_has_bmi2()); #endif } - /* * AVX-512 family of instruction sets: * @@ -466,8 +507,12 @@ zfs_avx512f_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512F) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512F) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = !!boot_cpu_has(X86_FEATURE_AVX512F); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512f(); #endif @@ -481,9 +526,13 @@ zfs_avx512cd_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512CD) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512CD) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512CD); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512cd(); #endif @@ -497,9 +546,13 @@ zfs_avx512er_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512ER) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512ER) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512ER); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512er(); #endif @@ -513,9 +566,13 @@ zfs_avx512pf_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512PF) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512PF) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512PF); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512pf(); #endif @@ -529,9 +586,13 @@ zfs_avx512bw_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512BW) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512BW) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512BW); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512bw(); #endif @@ -545,9 +606,13 @@ zfs_avx512dq_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512DQ) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512DQ) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512DQ); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512dq(); #endif @@ -561,9 +626,13 @@ zfs_avx512vl_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512VL) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512VL) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512VL); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512vl(); #endif @@ -577,9 +646,13 @@ zfs_avx512ifma_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512IFMA) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512IFMA) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512IFMA); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512ifma(); #endif @@ -593,9 +666,13 @@ zfs_avx512vbmi_available(void) { boolean_t has_avx512 = B_FALSE; -#if defined(_KERNEL) && defined(X86_FEATURE_AVX512VBMI) +#if defined(_KERNEL) +#if defined(X86_FEATURE_AVX512VBMI) && defined(KERNEL_EXPORTS_X86_FPU) has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && boot_cpu_has(X86_FEATURE_AVX512VBMI); +#else + has_avx512 = B_FALSE; +#endif #elif !defined(_KERNEL) has_avx512 = __cpuid_has_avx512f() && __cpuid_has_avx512vbmi();