2 * Copyright (c) 2020 iXsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/types.h>
30 #include <sys/cdefs.h>
32 #include <sys/systm.h>
34 #include <machine/pcb.h>
35 #include <x86/x86_var.h>
36 #include <x86/specialreg.h>
38 #define kfpu_init() (0)
39 #define kfpu_fini() do {} while (0)
40 #define kfpu_allowed() 1
41 #define kfpu_initialize(tsk) do {} while (0)
43 #define kfpu_begin() { \
44 if (__predict_false(!is_fpu_kern_thread(0))) \
45 fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);\
49 #define PCB_FPUNOSAVE PCB_NPXNOSAVE
52 #define kfpu_end() { \
53 if (__predict_false(curpcb->pcb_flags & PCB_FPUNOSAVE)) \
54 fpu_kern_leave(curthread, NULL); \
58 * Check if OS supports AVX and AVX2 by checking XCR0
59 * Only call this function if CPUID indicates that AVX feature is
60 * supported by the CPU, otherwise it might be an illegal instruction.
62 static inline uint64_t
63 xgetbv(uint32_t index
)
66 /* xgetbv - instruction byte code */
67 __asm__
__volatile__(".byte 0x0f; .byte 0x01; .byte 0xd0"
68 : "=a" (eax
), "=d" (edx
)
71 return ((((uint64_t)edx
)<<32) | (uint64_t)eax
);
76 * Detect register set support
78 static inline boolean_t
79 __simd_state_enabled(const uint64_t state
)
81 boolean_t has_osxsave
;
84 has_osxsave
= (cpu_feature2
& CPUID2_OSXSAVE
) != 0;
90 return ((xcr0
& state
) == state
);
93 #define _XSTATE_SSE_AVX (0x2 | 0x4)
94 #define _XSTATE_AVX512 (0xE0 | _XSTATE_SSE_AVX)
96 #define __ymm_enabled() __simd_state_enabled(_XSTATE_SSE_AVX)
97 #define __zmm_enabled() __simd_state_enabled(_XSTATE_AVX512)
101 * Check if SSE instruction set is available
103 static inline boolean_t
104 zfs_sse_available(void)
106 return ((cpu_feature
& CPUID_SSE
) != 0);
110 * Check if SSE2 instruction set is available
112 static inline boolean_t
113 zfs_sse2_available(void)
115 return ((cpu_feature
& CPUID_SSE2
) != 0);
119 * Check if SSE3 instruction set is available
121 static inline boolean_t
122 zfs_sse3_available(void)
124 return ((cpu_feature2
& CPUID2_SSE3
) != 0);
128 * Check if SSSE3 instruction set is available
130 static inline boolean_t
131 zfs_ssse3_available(void)
133 return ((cpu_feature2
& CPUID2_SSSE3
) != 0);
137 * Check if SSE4.1 instruction set is available
139 static inline boolean_t
140 zfs_sse4_1_available(void)
142 return ((cpu_feature2
& CPUID2_SSE41
) != 0);
146 * Check if SSE4.2 instruction set is available
148 static inline boolean_t
149 zfs_sse4_2_available(void)
151 return ((cpu_feature2
& CPUID2_SSE42
) != 0);
155 * Check if AVX instruction set is available
157 static inline boolean_t
158 zfs_avx_available(void)
162 has_avx
= (cpu_feature2
& CPUID2_AVX
) != 0;
164 return (has_avx
&& __ymm_enabled());
168 * Check if AVX2 instruction set is available
170 static inline boolean_t
171 zfs_avx2_available(void)
175 has_avx2
= (cpu_stdext_feature
& CPUID_STDEXT_AVX2
) != 0;
177 return (has_avx2
&& __ymm_enabled());
181 * Check if SHA_NI instruction set is available
183 static inline boolean_t
184 zfs_shani_available(void)
188 has_shani
= (cpu_stdext_feature
& CPUID_STDEXT_SHA
) != 0;
190 return (has_shani
&& __ymm_enabled());
194 * AVX-512 family of instruction sets:
197 * AVX512CD Conflict Detection Instructions
198 * AVX512ER Exponential and Reciprocal Instructions
199 * AVX512PF Prefetch Instructions
201 * AVX512BW Byte and Word Instructions
202 * AVX512DQ Double-word and Quadword Instructions
203 * AVX512VL Vector Length Extensions
205 * AVX512IFMA Integer Fused Multiply Add (Not supported by kernel 4.4)
206 * AVX512VBMI Vector Byte Manipulation Instructions
210 /* Check if AVX512F instruction set is available */
211 static inline boolean_t
212 zfs_avx512f_available(void)
214 boolean_t has_avx512
;
216 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0;
218 return (has_avx512
&& __zmm_enabled());
221 /* Check if AVX512CD instruction set is available */
222 static inline boolean_t
223 zfs_avx512cd_available(void)
225 boolean_t has_avx512
;
227 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0 &&
228 (cpu_stdext_feature
& CPUID_STDEXT_AVX512CD
) != 0;
230 return (has_avx512
&& __zmm_enabled());
233 /* Check if AVX512ER instruction set is available */
234 static inline boolean_t
235 zfs_avx512er_available(void)
237 boolean_t has_avx512
;
239 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0 &&
240 (cpu_stdext_feature
& CPUID_STDEXT_AVX512CD
) != 0;
242 return (has_avx512
&& __zmm_enabled());
245 /* Check if AVX512PF instruction set is available */
246 static inline boolean_t
247 zfs_avx512pf_available(void)
249 boolean_t has_avx512
;
251 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0 &&
252 (cpu_stdext_feature
& CPUID_STDEXT_AVX512PF
) != 0;
254 return (has_avx512
&& __zmm_enabled());
257 /* Check if AVX512BW instruction set is available */
258 static inline boolean_t
259 zfs_avx512bw_available(void)
261 boolean_t has_avx512
= B_FALSE
;
263 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512BW
) != 0;
265 return (has_avx512
&& __zmm_enabled());
268 /* Check if AVX512DQ instruction set is available */
269 static inline boolean_t
270 zfs_avx512dq_available(void)
272 boolean_t has_avx512
;
274 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0 &&
275 (cpu_stdext_feature
& CPUID_STDEXT_AVX512DQ
) != 0;
277 return (has_avx512
&& __zmm_enabled());
280 /* Check if AVX512VL instruction set is available */
281 static inline boolean_t
282 zfs_avx512vl_available(void)
284 boolean_t has_avx512
;
286 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0 &&
287 (cpu_stdext_feature
& CPUID_STDEXT_AVX512VL
) != 0;
289 return (has_avx512
&& __zmm_enabled());
292 /* Check if AVX512IFMA instruction set is available */
293 static inline boolean_t
294 zfs_avx512ifma_available(void)
296 boolean_t has_avx512
;
298 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0 &&
299 (cpu_stdext_feature
& CPUID_STDEXT_AVX512IFMA
) != 0;
301 return (has_avx512
&& __zmm_enabled());
304 /* Check if AVX512VBMI instruction set is available */
305 static inline boolean_t
306 zfs_avx512vbmi_available(void)
308 boolean_t has_avx512
;
310 has_avx512
= (cpu_stdext_feature
& CPUID_STDEXT_AVX512F
) != 0 &&
311 (cpu_stdext_feature
& CPUID_STDEXT_BMI1
) != 0;
313 return (has_avx512
&& __zmm_enabled());