Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
/*
|
|
|
|
* CDDL HEADER START
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the terms of the
|
|
|
|
* Common Development and Distribution License (the "License").
|
|
|
|
* You may not use this file except in compliance with the License.
|
|
|
|
*
|
|
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
|
|
* or http://www.opensolaris.org/os/licensing.
|
|
|
|
* See the License for the specific language governing permissions
|
|
|
|
* and limitations under the License.
|
|
|
|
*
|
|
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
|
|
*
|
|
|
|
* CDDL HEADER END
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 Gvozden Neskovic <neskovic@compeng.uni-frankfurt.de>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* USER API:
|
|
|
|
*
|
|
|
|
* Kernel fpu methods:
|
2019-07-17 00:22:31 +00:00
|
|
|
* kfpu_allowed()
|
|
|
|
* kfpu_begin()
|
|
|
|
* kfpu_end()
|
2019-07-12 16:31:20 +00:00
|
|
|
* kfpu_init()
|
|
|
|
* kfpu_fini()
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
*
|
|
|
|
* SIMD support:
|
|
|
|
*
|
|
|
|
* Following functions should be called to determine whether CPU feature
|
|
|
|
* is supported. All functions are usable in kernel and user space.
|
|
|
|
* If a SIMD algorithm is using more than one instruction set
|
|
|
|
* all relevant feature test functions should be called.
|
|
|
|
*
|
|
|
|
* Supported features:
|
2019-07-17 00:22:31 +00:00
|
|
|
* zfs_sse_available()
|
|
|
|
* zfs_sse2_available()
|
|
|
|
* zfs_sse3_available()
|
|
|
|
* zfs_ssse3_available()
|
|
|
|
* zfs_sse4_1_available()
|
|
|
|
* zfs_sse4_2_available()
|
2016-07-01 16:33:04 +00:00
|
|
|
*
|
2019-07-17 00:22:31 +00:00
|
|
|
* zfs_avx_available()
|
|
|
|
* zfs_avx2_available()
|
2016-07-01 16:33:04 +00:00
|
|
|
*
|
2019-07-17 00:22:31 +00:00
|
|
|
* zfs_bmi1_available()
|
|
|
|
* zfs_bmi2_available()
|
2016-07-01 16:33:04 +00:00
|
|
|
*
|
2019-07-17 00:22:31 +00:00
|
|
|
* zfs_avx512f_available()
|
|
|
|
* zfs_avx512cd_available()
|
|
|
|
* zfs_avx512er_available()
|
|
|
|
* zfs_avx512pf_available()
|
|
|
|
* zfs_avx512bw_available()
|
|
|
|
* zfs_avx512dq_available()
|
|
|
|
* zfs_avx512vl_available()
|
|
|
|
* zfs_avx512ifma_available()
|
|
|
|
* zfs_avx512vbmi_available()
|
2016-07-01 16:33:04 +00:00
|
|
|
*
|
|
|
|
* NOTE(AVX-512VL): If using AVX-512 instructions with 128Bit registers
|
2019-07-17 00:22:31 +00:00
|
|
|
* also add zfs_avx512vl_available() to feature check.
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _SIMD_X86_H
|
|
|
|
#define _SIMD_X86_H
|
|
|
|
|
|
|
|
#include <sys/isa_defs.h>
|
|
|
|
|
|
|
|
/* only for __x86 */
|
|
|
|
#if defined(__x86)
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
#include <asm/cpufeature.h>
|
|
|
|
#else
|
|
|
|
#include <cpuid.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(_KERNEL)
|
2019-03-07 00:03:03 +00:00
|
|
|
|
2019-07-12 16:31:20 +00:00
|
|
|
/*
|
|
|
|
* Disable the WARN_ON_FPU() macro to prevent additional dependencies
|
|
|
|
* when providing the kfpu_* functions. Relevant warnings are included
|
|
|
|
* as appropriate and are unconditionally enabled.
|
|
|
|
*/
|
|
|
|
#if defined(CONFIG_X86_DEBUG_FPU) && !defined(KERNEL_EXPORTS_X86_FPU)
|
|
|
|
#undef CONFIG_X86_DEBUG_FPU
|
|
|
|
#endif
|
|
|
|
|
2019-03-07 00:03:03 +00:00
|
|
|
#if defined(HAVE_KERNEL_FPU_API_HEADER)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
#include <asm/fpu/api.h>
|
|
|
|
#include <asm/fpu/internal.h>
|
2019-03-07 00:03:03 +00:00
|
|
|
#else
|
|
|
|
#include <asm/i387.h>
|
|
|
|
#include <asm/xcr.h>
|
|
|
|
#endif
|
|
|
|
|
2019-07-12 16:31:20 +00:00
|
|
|
/*
|
|
|
|
* The following cases are for kernels which export either the
|
|
|
|
* kernel_fpu_* or __kernel_fpu_* functions.
|
|
|
|
*/
|
|
|
|
#if defined(KERNEL_EXPORTS_X86_FPU)
|
|
|
|
|
|
|
|
#define kfpu_allowed() 1
|
|
|
|
#define kfpu_init() 0
|
|
|
|
#define kfpu_fini() ((void) 0)
|
|
|
|
|
2019-03-07 00:03:03 +00:00
|
|
|
#if defined(HAVE_UNDERSCORE_KERNEL_FPU)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
#define kfpu_begin() \
|
2019-07-12 16:31:20 +00:00
|
|
|
{ \
|
|
|
|
preempt_disable(); \
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
__kernel_fpu_begin(); \
|
|
|
|
}
|
2019-07-12 16:31:20 +00:00
|
|
|
#define kfpu_end() \
|
|
|
|
{ \
|
|
|
|
__kernel_fpu_end(); \
|
|
|
|
preempt_enable(); \
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
}
|
2019-07-12 16:31:20 +00:00
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif defined(HAVE_KERNEL_FPU)
|
2019-07-12 16:31:20 +00:00
|
|
|
#define kfpu_begin() kernel_fpu_begin()
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
#define kfpu_end() kernel_fpu_end()
|
2019-07-12 16:31:20 +00:00
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
2019-07-12 16:31:20 +00:00
|
|
|
/*
|
|
|
|
* This case is unreachable. When KERNEL_EXPORTS_X86_FPU is defined then
|
|
|
|
* either HAVE_UNDERSCORE_KERNEL_FPU or HAVE_KERNEL_FPU must be defined.
|
|
|
|
*/
|
|
|
|
#error "Unreachable kernel configuration"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else /* defined(KERNEL_EXPORTS_X86_FPU) */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When the kernel_fpu_* symbols are unavailable then provide our own
|
|
|
|
* versions which allow the FPU to be safely used.
|
|
|
|
*/
|
|
|
|
#if defined(HAVE_KERNEL_FPU_INTERNAL)
|
|
|
|
|
2019-12-10 20:53:25 +00:00
|
|
|
#include <linux/mm.h>
|
|
|
|
|
2019-07-12 16:31:20 +00:00
|
|
|
extern union fpregs_state **zfs_kfpu_fpregs;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize per-cpu variables to store FPU state.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
kfpu_fini(void)
|
|
|
|
{
|
|
|
|
int cpu;
|
|
|
|
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
|
|
if (zfs_kfpu_fpregs[cpu] != NULL) {
|
2019-12-10 20:53:25 +00:00
|
|
|
free_pages((unsigned long)zfs_kfpu_fpregs[cpu],
|
|
|
|
get_order(sizeof (union fpregs_state)));
|
2019-07-12 16:31:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(zfs_kfpu_fpregs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
kfpu_init(void)
|
|
|
|
{
|
|
|
|
zfs_kfpu_fpregs = kzalloc(num_possible_cpus() *
|
|
|
|
sizeof (union fpregs_state *), GFP_KERNEL);
|
|
|
|
if (zfs_kfpu_fpregs == NULL)
|
|
|
|
return (-ENOMEM);
|
|
|
|
|
2019-12-10 20:53:25 +00:00
|
|
|
/*
|
|
|
|
* The fxsave and xsave operations require 16-/64-byte alignment of
|
|
|
|
* the target memory. Since kmalloc() provides no alignment
|
|
|
|
* guarantee instead use alloc_pages_node().
|
|
|
|
*/
|
|
|
|
unsigned int order = get_order(sizeof (union fpregs_state));
|
|
|
|
int cpu;
|
|
|
|
|
2019-07-12 16:31:20 +00:00
|
|
|
for_each_possible_cpu(cpu) {
|
2019-12-10 20:53:25 +00:00
|
|
|
struct page *page = alloc_pages_node(cpu_to_node(cpu),
|
|
|
|
GFP_KERNEL | __GFP_ZERO, order);
|
|
|
|
if (page == NULL) {
|
2019-07-12 16:31:20 +00:00
|
|
|
kfpu_fini();
|
|
|
|
return (-ENOMEM);
|
|
|
|
}
|
2019-12-10 20:53:25 +00:00
|
|
|
|
|
|
|
zfs_kfpu_fpregs[cpu] = page_address(page);
|
2019-07-12 16:31:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define kfpu_allowed() 1
|
|
|
|
#define ex_handler_fprestore ex_handler_default
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FPU save and restore instructions.
|
|
|
|
*/
|
|
|
|
#define __asm __asm__ __volatile__
|
|
|
|
#define kfpu_fxsave(addr) __asm("fxsave %0" : "=m" (*(addr)))
|
|
|
|
#define kfpu_fxsaveq(addr) __asm("fxsaveq %0" : "=m" (*(addr)))
|
|
|
|
#define kfpu_fnsave(addr) __asm("fnsave %0; fwait" : "=m" (*(addr)))
|
|
|
|
#define kfpu_fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr)))
|
|
|
|
#define kfpu_fxrstorq(addr) __asm("fxrstorq %0" : : "m" (*(addr)))
|
|
|
|
#define kfpu_frstor(addr) __asm("frstor %0" : : "m" (*(addr)))
|
|
|
|
#define kfpu_fxsr_clean(rval) __asm("fnclex; emms; fildl %P[addr]" \
|
|
|
|
: : [addr] "m" (rval));
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_save_xsave(struct xregs_state *addr, uint64_t mask)
|
|
|
|
{
|
|
|
|
uint32_t low, hi;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
low = mask;
|
|
|
|
hi = mask >> 32;
|
|
|
|
XSTATE_XSAVE(addr, low, hi, err);
|
|
|
|
WARN_ON_ONCE(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_save_fxsr(struct fxregs_state *addr)
|
|
|
|
{
|
|
|
|
if (IS_ENABLED(CONFIG_X86_32))
|
|
|
|
kfpu_fxsave(addr);
|
|
|
|
else
|
|
|
|
kfpu_fxsaveq(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_save_fsave(struct fregs_state *addr)
|
|
|
|
{
|
|
|
|
kfpu_fnsave(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_begin(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Preemption and interrupts must be disabled for the critical
|
|
|
|
* region where the FPU state is being modified.
|
|
|
|
*/
|
|
|
|
preempt_disable();
|
|
|
|
local_irq_disable();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The current FPU registers need to be preserved by kfpu_begin()
|
|
|
|
* and restored by kfpu_end(). They are stored in a dedicated
|
|
|
|
* per-cpu variable, not in the task struct, this allows any user
|
|
|
|
* FPU state to be correctly preserved and restored.
|
|
|
|
*/
|
|
|
|
union fpregs_state *state = zfs_kfpu_fpregs[smp_processor_id()];
|
|
|
|
|
|
|
|
if (static_cpu_has(X86_FEATURE_XSAVE)) {
|
|
|
|
kfpu_save_xsave(&state->xsave, ~0);
|
|
|
|
} else if (static_cpu_has(X86_FEATURE_FXSR)) {
|
|
|
|
kfpu_save_fxsr(&state->fxsave);
|
|
|
|
} else {
|
|
|
|
kfpu_save_fsave(&state->fsave);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_restore_xsave(struct xregs_state *addr, uint64_t mask)
|
|
|
|
{
|
|
|
|
uint32_t low, hi;
|
|
|
|
|
|
|
|
low = mask;
|
|
|
|
hi = mask >> 32;
|
|
|
|
XSTATE_XRESTORE(addr, low, hi);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_restore_fxsr(struct fxregs_state *addr)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* On AuthenticAMD K7 and K8 processors the fxrstor instruction only
|
|
|
|
* restores the _x87 FOP, FIP, and FDP registers when an exception
|
|
|
|
* is pending. Clean the _x87 state to force the restore.
|
|
|
|
*/
|
|
|
|
if (unlikely(static_cpu_has_bug(X86_BUG_FXSAVE_LEAK)))
|
|
|
|
kfpu_fxsr_clean(addr);
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_X86_32)) {
|
|
|
|
kfpu_fxrstor(addr);
|
|
|
|
} else {
|
|
|
|
kfpu_fxrstorq(addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_restore_fsave(struct fregs_state *addr)
|
|
|
|
{
|
|
|
|
kfpu_frstor(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
kfpu_end(void)
|
|
|
|
{
|
|
|
|
union fpregs_state *state = zfs_kfpu_fpregs[smp_processor_id()];
|
|
|
|
|
|
|
|
if (static_cpu_has(X86_FEATURE_XSAVE)) {
|
|
|
|
kfpu_restore_xsave(&state->xsave, ~0);
|
|
|
|
} else if (static_cpu_has(X86_FEATURE_FXSR)) {
|
|
|
|
kfpu_restore_fxsr(&state->fxsave);
|
|
|
|
} else {
|
|
|
|
kfpu_restore_fsave(&state->fsave);
|
|
|
|
}
|
|
|
|
|
|
|
|
local_irq_enable();
|
|
|
|
preempt_enable();
|
|
|
|
}
|
2019-01-12 02:01:28 +00:00
|
|
|
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
#else
|
2019-07-12 16:31:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FPU support is unavailable.
|
|
|
|
*/
|
|
|
|
#define kfpu_allowed() 0
|
|
|
|
#define kfpu_begin() do {} while (0)
|
|
|
|
#define kfpu_end() do {} while (0)
|
|
|
|
#define kfpu_init() 0
|
|
|
|
#define kfpu_fini() ((void) 0)
|
|
|
|
|
|
|
|
#endif /* defined(HAVE_KERNEL_FPU_INTERNAL) */
|
|
|
|
#endif /* defined(KERNEL_EXPORTS_X86_FPU) */
|
|
|
|
|
|
|
|
#else /* defined(_KERNEL) */
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
/*
|
2019-07-12 16:31:20 +00:00
|
|
|
* FPU dummy methods for user space.
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
*/
|
2019-07-12 16:31:20 +00:00
|
|
|
#define kfpu_allowed() 1
|
|
|
|
#define kfpu_begin() do {} while (0)
|
|
|
|
#define kfpu_end() do {} while (0)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
#endif /* defined(_KERNEL) */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CPUID feature tests for user-space. Linux kernel provides an interface for
|
|
|
|
* CPU feature testing.
|
|
|
|
*/
|
|
|
|
#if !defined(_KERNEL)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* x86 registers used implicitly by CPUID
|
|
|
|
*/
|
|
|
|
typedef enum cpuid_regs {
|
|
|
|
EAX = 0,
|
|
|
|
EBX,
|
|
|
|
ECX,
|
|
|
|
EDX,
|
|
|
|
CPUID_REG_CNT = 4
|
|
|
|
} cpuid_regs_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* List of instruction sets identified by CPUID
|
|
|
|
*/
|
|
|
|
typedef enum cpuid_inst_sets {
|
|
|
|
SSE = 0,
|
|
|
|
SSE2,
|
|
|
|
SSE3,
|
|
|
|
SSSE3,
|
|
|
|
SSE4_1,
|
|
|
|
SSE4_2,
|
|
|
|
OSXSAVE,
|
|
|
|
AVX,
|
|
|
|
AVX2,
|
|
|
|
BMI1,
|
2016-07-01 16:33:04 +00:00
|
|
|
BMI2,
|
|
|
|
AVX512F,
|
|
|
|
AVX512CD,
|
|
|
|
AVX512DQ,
|
|
|
|
AVX512BW,
|
|
|
|
AVX512IFMA,
|
|
|
|
AVX512VBMI,
|
|
|
|
AVX512PF,
|
|
|
|
AVX512ER,
|
2018-08-02 18:59:24 +00:00
|
|
|
AVX512VL,
|
|
|
|
AES,
|
|
|
|
PCLMULQDQ
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
} cpuid_inst_sets_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Instruction set descriptor.
|
|
|
|
*/
|
|
|
|
typedef struct cpuid_feature_desc {
|
|
|
|
uint32_t leaf; /* CPUID leaf */
|
2016-07-01 16:33:04 +00:00
|
|
|
uint32_t subleaf; /* CPUID sub-leaf */
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
uint32_t flag; /* bit mask of the feature */
|
|
|
|
cpuid_regs_t reg; /* which CPUID return register to test */
|
|
|
|
} cpuid_feature_desc_t;
|
|
|
|
|
2016-07-01 16:33:04 +00:00
|
|
|
#define _AVX512F_BIT (1U << 16)
|
|
|
|
#define _AVX512CD_BIT (_AVX512F_BIT | (1U << 28))
|
|
|
|
#define _AVX512DQ_BIT (_AVX512F_BIT | (1U << 17))
|
|
|
|
#define _AVX512BW_BIT (_AVX512F_BIT | (1U << 30))
|
|
|
|
#define _AVX512IFMA_BIT (_AVX512F_BIT | (1U << 21))
|
|
|
|
#define _AVX512VBMI_BIT (1U << 1) /* AVX512F_BIT is on another leaf */
|
|
|
|
#define _AVX512PF_BIT (_AVX512F_BIT | (1U << 26))
|
|
|
|
#define _AVX512ER_BIT (_AVX512F_BIT | (1U << 27))
|
|
|
|
#define _AVX512VL_BIT (1U << 31) /* if used also check other levels */
|
2018-08-02 18:59:24 +00:00
|
|
|
#define _AES_BIT (1U << 25)
|
|
|
|
#define _PCLMULQDQ_BIT (1U << 1)
|
2016-07-01 16:33:04 +00:00
|
|
|
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
/*
|
|
|
|
* Descriptions of supported instruction sets
|
|
|
|
*/
|
|
|
|
static const cpuid_feature_desc_t cpuid_features[] = {
|
2019-07-17 00:22:31 +00:00
|
|
|
[SSE] = {1U, 0U, 1U << 25, EDX },
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
[SSE2] = {1U, 0U, 1U << 26, EDX },
|
|
|
|
[SSE3] = {1U, 0U, 1U << 0, ECX },
|
|
|
|
[SSSE3] = {1U, 0U, 1U << 9, ECX },
|
|
|
|
[SSE4_1] = {1U, 0U, 1U << 19, ECX },
|
|
|
|
[SSE4_2] = {1U, 0U, 1U << 20, ECX },
|
|
|
|
[OSXSAVE] = {1U, 0U, 1U << 27, ECX },
|
|
|
|
[AVX] = {1U, 0U, 1U << 28, ECX },
|
|
|
|
[AVX2] = {7U, 0U, 1U << 5, EBX },
|
|
|
|
[BMI1] = {7U, 0U, 1U << 3, EBX },
|
2016-07-01 16:33:04 +00:00
|
|
|
[BMI2] = {7U, 0U, 1U << 8, EBX },
|
|
|
|
[AVX512F] = {7U, 0U, _AVX512F_BIT, EBX },
|
|
|
|
[AVX512CD] = {7U, 0U, _AVX512CD_BIT, EBX },
|
|
|
|
[AVX512DQ] = {7U, 0U, _AVX512DQ_BIT, EBX },
|
|
|
|
[AVX512BW] = {7U, 0U, _AVX512BW_BIT, EBX },
|
|
|
|
[AVX512IFMA] = {7U, 0U, _AVX512IFMA_BIT, EBX },
|
|
|
|
[AVX512VBMI] = {7U, 0U, _AVX512VBMI_BIT, ECX },
|
|
|
|
[AVX512PF] = {7U, 0U, _AVX512PF_BIT, EBX },
|
|
|
|
[AVX512ER] = {7U, 0U, _AVX512ER_BIT, EBX },
|
2018-08-02 18:59:24 +00:00
|
|
|
[AVX512VL] = {7U, 0U, _AVX512ER_BIT, EBX },
|
|
|
|
[AES] = {1U, 0U, _AES_BIT, ECX },
|
|
|
|
[PCLMULQDQ] = {1U, 0U, _PCLMULQDQ_BIT, ECX },
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if OS supports AVX and AVX2 by checking XCR0
|
|
|
|
* Only call this function if CPUID indicates that AVX feature is
|
|
|
|
* supported by the CPU, otherwise it might be an illegal instruction.
|
|
|
|
*/
|
|
|
|
static inline uint64_t
|
|
|
|
xgetbv(uint32_t index)
|
|
|
|
{
|
|
|
|
uint32_t eax, edx;
|
|
|
|
/* xgetbv - instruction byte code */
|
|
|
|
__asm__ __volatile__(".byte 0x0f; .byte 0x01; .byte 0xd0"
|
2016-12-12 18:46:26 +00:00
|
|
|
: "=a" (eax), "=d" (edx)
|
|
|
|
: "c" (index));
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
|
|
|
|
return ((((uint64_t)edx)<<32) | (uint64_t)eax);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if CPU supports a feature
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
__cpuid_check_feature(const cpuid_feature_desc_t *desc)
|
|
|
|
{
|
|
|
|
uint32_t r[CPUID_REG_CNT];
|
|
|
|
|
|
|
|
if (__get_cpuid_max(0, NULL) >= desc->leaf) {
|
|
|
|
/*
|
|
|
|
* __cpuid_count is needed to properly check
|
|
|
|
* for AVX2. It is a macro, so return parameters
|
|
|
|
* are passed by value.
|
|
|
|
*/
|
|
|
|
__cpuid_count(desc->leaf, desc->subleaf,
|
2016-12-12 18:46:26 +00:00
|
|
|
r[EAX], r[EBX], r[ECX], r[EDX]);
|
2016-07-01 16:33:04 +00:00
|
|
|
return ((r[desc->reg] & desc->flag) == desc->flag);
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
}
|
|
|
|
return (B_FALSE);
|
|
|
|
}
|
|
|
|
|
2016-12-12 18:46:26 +00:00
|
|
|
#define CPUID_FEATURE_CHECK(name, id) \
|
2016-07-01 16:33:04 +00:00
|
|
|
static inline boolean_t \
|
|
|
|
__cpuid_has_ ## name(void) \
|
|
|
|
{ \
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_check_feature(&cpuid_features[id])); \
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Define functions for user-space CPUID features testing
|
|
|
|
*/
|
|
|
|
CPUID_FEATURE_CHECK(sse, SSE);
|
|
|
|
CPUID_FEATURE_CHECK(sse2, SSE2);
|
|
|
|
CPUID_FEATURE_CHECK(sse3, SSE3);
|
|
|
|
CPUID_FEATURE_CHECK(ssse3, SSSE3);
|
|
|
|
CPUID_FEATURE_CHECK(sse4_1, SSE4_1);
|
|
|
|
CPUID_FEATURE_CHECK(sse4_2, SSE4_2);
|
|
|
|
CPUID_FEATURE_CHECK(avx, AVX);
|
|
|
|
CPUID_FEATURE_CHECK(avx2, AVX2);
|
|
|
|
CPUID_FEATURE_CHECK(osxsave, OSXSAVE);
|
|
|
|
CPUID_FEATURE_CHECK(bmi1, BMI1);
|
|
|
|
CPUID_FEATURE_CHECK(bmi2, BMI2);
|
2016-07-01 16:33:04 +00:00
|
|
|
CPUID_FEATURE_CHECK(avx512f, AVX512F);
|
|
|
|
CPUID_FEATURE_CHECK(avx512cd, AVX512CD);
|
|
|
|
CPUID_FEATURE_CHECK(avx512dq, AVX512DQ);
|
|
|
|
CPUID_FEATURE_CHECK(avx512bw, AVX512BW);
|
|
|
|
CPUID_FEATURE_CHECK(avx512ifma, AVX512IFMA);
|
|
|
|
CPUID_FEATURE_CHECK(avx512vbmi, AVX512VBMI);
|
|
|
|
CPUID_FEATURE_CHECK(avx512pf, AVX512PF);
|
|
|
|
CPUID_FEATURE_CHECK(avx512er, AVX512ER);
|
|
|
|
CPUID_FEATURE_CHECK(avx512vl, AVX512VL);
|
2018-08-02 18:59:24 +00:00
|
|
|
CPUID_FEATURE_CHECK(aes, AES);
|
|
|
|
CPUID_FEATURE_CHECK(pclmulqdq, PCLMULQDQ);
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
|
|
|
|
#endif /* !defined(_KERNEL) */
|
|
|
|
|
|
|
|
/*
|
2016-07-01 16:33:04 +00:00
|
|
|
* Detect register set support
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
*/
|
|
|
|
static inline boolean_t
|
2016-07-01 16:33:04 +00:00
|
|
|
__simd_state_enabled(const uint64_t state)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
{
|
|
|
|
boolean_t has_osxsave;
|
|
|
|
uint64_t xcr0;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_OSXSAVE)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
has_osxsave = !!boot_cpu_has(X86_FEATURE_OSXSAVE);
|
|
|
|
#else
|
2019-01-12 02:01:28 +00:00
|
|
|
has_osxsave = B_FALSE;
|
|
|
|
#endif
|
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
has_osxsave = __cpuid_has_osxsave();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!has_osxsave)
|
|
|
|
return (B_FALSE);
|
|
|
|
|
|
|
|
xcr0 = xgetbv(0);
|
2016-07-01 16:33:04 +00:00
|
|
|
return ((xcr0 & state) == state);
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
}
|
|
|
|
|
2016-07-01 16:33:04 +00:00
|
|
|
#define _XSTATE_SSE_AVX (0x2 | 0x4)
|
|
|
|
#define _XSTATE_AVX512 (0xE0 | _XSTATE_SSE_AVX)
|
|
|
|
|
|
|
|
#define __ymm_enabled() __simd_state_enabled(_XSTATE_SSE_AVX)
|
|
|
|
#define __zmm_enabled() __simd_state_enabled(_XSTATE_AVX512)
|
|
|
|
|
|
|
|
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
/*
|
|
|
|
* Check if SSE instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_sse_available(void)
|
|
|
|
{
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
return (!!boot_cpu_has(X86_FEATURE_XMM));
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_sse());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if SSE2 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_sse2_available(void)
|
|
|
|
{
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
return (!!boot_cpu_has(X86_FEATURE_XMM2));
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_sse2());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if SSE3 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_sse3_available(void)
|
|
|
|
{
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
return (!!boot_cpu_has(X86_FEATURE_XMM3));
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_sse3());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if SSSE3 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_ssse3_available(void)
|
|
|
|
{
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
return (!!boot_cpu_has(X86_FEATURE_SSSE3));
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_ssse3());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if SSE4.1 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_sse4_1_available(void)
|
|
|
|
{
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
return (!!boot_cpu_has(X86_FEATURE_XMM4_1));
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_sse4_1());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if SSE4.2 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_sse4_2_available(void)
|
|
|
|
{
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
return (!!boot_cpu_has(X86_FEATURE_XMM4_2));
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_sse4_2());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if AVX instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx;
|
|
|
|
#if defined(_KERNEL)
|
|
|
|
has_avx = !!boot_cpu_has(X86_FEATURE_AVX);
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
has_avx = __cpuid_has_avx();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx && __ymm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if AVX2 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx2_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx2;
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
has_avx2 = !!boot_cpu_has(X86_FEATURE_AVX2);
|
2019-01-12 02:01:28 +00:00
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
has_avx2 = __cpuid_has_avx2();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx2 && __ymm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if BMI1 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_bmi1_available(void)
|
|
|
|
{
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_BMI1)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (!!boot_cpu_has(X86_FEATURE_BMI1));
|
|
|
|
#else
|
2019-01-12 02:01:28 +00:00
|
|
|
return (B_FALSE);
|
|
|
|
#endif
|
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_bmi1());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if BMI2 instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_bmi2_available(void)
|
|
|
|
{
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_BMI2)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (!!boot_cpu_has(X86_FEATURE_BMI2));
|
|
|
|
#else
|
2019-01-12 02:01:28 +00:00
|
|
|
return (B_FALSE);
|
|
|
|
#endif
|
|
|
|
#elif !defined(_KERNEL)
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
return (__cpuid_has_bmi2());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-08-02 18:59:24 +00:00
|
|
|
/*
|
|
|
|
* Check if AES instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_aes_available(void)
|
|
|
|
{
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AES)
|
2018-08-02 18:59:24 +00:00
|
|
|
return (!!boot_cpu_has(X86_FEATURE_AES));
|
|
|
|
#else
|
2019-01-12 02:01:28 +00:00
|
|
|
return (B_FALSE);
|
|
|
|
#endif
|
|
|
|
#elif !defined(_KERNEL)
|
2018-08-02 18:59:24 +00:00
|
|
|
return (__cpuid_has_aes());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if PCLMULQDQ instruction set is available
|
|
|
|
*/
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_pclmulqdq_available(void)
|
|
|
|
{
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_PCLMULQDQ)
|
2018-08-02 18:59:24 +00:00
|
|
|
return (!!boot_cpu_has(X86_FEATURE_PCLMULQDQ));
|
|
|
|
#else
|
2019-01-12 02:01:28 +00:00
|
|
|
return (B_FALSE);
|
|
|
|
#endif
|
|
|
|
#elif !defined(_KERNEL)
|
2018-08-02 18:59:24 +00:00
|
|
|
return (__cpuid_has_pclmulqdq());
|
|
|
|
#endif
|
|
|
|
}
|
2016-07-01 16:33:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* AVX-512 family of instruction sets:
|
|
|
|
*
|
|
|
|
* AVX512F Foundation
|
|
|
|
* AVX512CD Conflict Detection Instructions
|
|
|
|
* AVX512ER Exponential and Reciprocal Instructions
|
|
|
|
* AVX512PF Prefetch Instructions
|
|
|
|
*
|
|
|
|
* AVX512BW Byte and Word Instructions
|
|
|
|
* AVX512DQ Double-word and Quadword Instructions
|
|
|
|
* AVX512VL Vector Length Extensions
|
|
|
|
*
|
|
|
|
* AVX512IFMA Integer Fused Multiply Add (Not supported by kernel 4.4)
|
|
|
|
* AVX512VBMI Vector Byte Manipulation Instructions
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* Check if AVX512F instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512f_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512F)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = !!boot_cpu_has(X86_FEATURE_AVX512F);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512f();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512CD instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512cd_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512CD)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512CD);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512cd();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512ER instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512er_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512ER)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512ER);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512er();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512PF instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512pf_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512PF)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512PF);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512pf();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512BW instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512bw_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512BW)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512BW);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512bw();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512DQ instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512dq_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512DQ)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512DQ);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512dq();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512VL instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512vl_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512VL)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512VL);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512vl();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512IFMA instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512ifma_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512IFMA)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512IFMA);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512ifma();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if AVX512VBMI instruction set is available */
|
|
|
|
static inline boolean_t
|
|
|
|
zfs_avx512vbmi_available(void)
|
|
|
|
{
|
|
|
|
boolean_t has_avx512 = B_FALSE;
|
|
|
|
|
2019-01-12 02:01:28 +00:00
|
|
|
#if defined(_KERNEL)
|
2019-07-12 16:31:20 +00:00
|
|
|
#if defined(X86_FEATURE_AVX512VBMI)
|
2016-07-01 16:33:04 +00:00
|
|
|
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
|
|
|
|
boot_cpu_has(X86_FEATURE_AVX512VBMI);
|
2019-01-12 02:01:28 +00:00
|
|
|
#else
|
|
|
|
has_avx512 = B_FALSE;
|
|
|
|
#endif
|
2016-07-01 16:33:04 +00:00
|
|
|
#elif !defined(_KERNEL)
|
|
|
|
has_avx512 = __cpuid_has_avx512f() &&
|
|
|
|
__cpuid_has_avx512vbmi();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (has_avx512 && __zmm_enabled());
|
|
|
|
}
|
|
|
|
|
Support for vectorized algorithms on x86
This is initial support for x86 vectorized implementations of ZFS parity
and checksum algorithms.
For the compilation phase, configure step checks if toolchain supports relevant
instruction sets. Each implementation must ensure that the code is not passed
to compiler if relevant instruction set is not supported. For this purpose,
following new defines are provided if instruction set is supported:
- HAVE_SSE,
- HAVE_SSE2,
- HAVE_SSE3,
- HAVE_SSSE3,
- HAVE_SSE4_1,
- HAVE_SSE4_2,
- HAVE_AVX,
- HAVE_AVX2.
For detecting if an instruction set can be used in runtime, following functions
are provided in (include/linux/simd_x86.h):
- zfs_sse_available()
- zfs_sse2_available()
- zfs_sse3_available()
- zfs_ssse3_available()
- zfs_sse4_1_available()
- zfs_sse4_2_available()
- zfs_avx_available()
- zfs_avx2_available()
- zfs_bmi1_available()
- zfs_bmi2_available()
These function should be called once, on module load, or initialization.
They are safe to use from user and kernel space.
If an implementation is using more than single instruction set, both compiler
and runtime support for all relevant instruction sets should be checked.
Kernel fpu methods:
- kfpu_begin()
- kfpu_end()
Use __get_cpuid_max and __cpuid_count from <cpuid.h>
Both gcc and clang have support for these. They also handle ebx register
in case it is used for PIC code.
Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4381
2016-02-29 18:42:27 +00:00
|
|
|
#endif /* defined(__x86) */
|
|
|
|
|
|
|
|
#endif /* _SIMD_X86_H */
|