]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - include/os/freebsd/spl/sys/simd_x86.h
Update OpenZFS to 2.0.0-rc3-gfc5966
[FreeBSD/FreeBSD.git] / include / os / freebsd / spl / sys / simd_x86.h
1 /*
2  * Copyright (c) 2020 iXsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/proc.h>
33 #ifdef __i386__
34 #include <x86/fpu.h>
35 #else
36 #include <machine/fpu.h>
37 #endif
38 #include <x86/x86_var.h>
39 #include <x86/specialreg.h>
40
41 #define kfpu_init()             (0)
42 #define kfpu_fini()             do {} while (0)
43 #define kfpu_allowed()          1
44 #define kfpu_initialize(tsk)    do {} while (0)
45
46 #define kfpu_begin() {                                  \
47         if (__predict_false(!is_fpu_kern_thread(0)))            \
48                 fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);\
49 }
50
51 #define kfpu_end()      {                       \
52         if (__predict_false(curpcb->pcb_flags & PCB_FPUNOSAVE)) \
53                 fpu_kern_leave(curthread, NULL);        \
54 }
55
56 /*
57  * Check if OS supports AVX and AVX2 by checking XCR0
58  * Only call this function if CPUID indicates that AVX feature is
59  * supported by the CPU, otherwise it might be an illegal instruction.
60  */
61 static inline uint64_t
62 xgetbv(uint32_t index)
63 {
64         uint32_t eax, edx;
65         /* xgetbv - instruction byte code */
66         __asm__ __volatile__(".byte 0x0f; .byte 0x01; .byte 0xd0"
67             : "=a" (eax), "=d" (edx)
68             : "c" (index));
69
70         return ((((uint64_t)edx)<<32) | (uint64_t)eax);
71 }
72
73
74 /*
75  * Detect register set support
76  */
77 static inline boolean_t
78 __simd_state_enabled(const uint64_t state)
79 {
80         boolean_t has_osxsave;
81         uint64_t xcr0;
82
83         has_osxsave = !!(cpu_feature2 & CPUID2_OSXSAVE);
84
85         if (!has_osxsave)
86                 return (B_FALSE);
87
88         xcr0 = xgetbv(0);
89         return ((xcr0 & state) == state);
90 }
91
92 #define _XSTATE_SSE_AVX         (0x2 | 0x4)
93 #define _XSTATE_AVX512          (0xE0 | _XSTATE_SSE_AVX)
94
95 #define __ymm_enabled() __simd_state_enabled(_XSTATE_SSE_AVX)
96 #define __zmm_enabled() __simd_state_enabled(_XSTATE_AVX512)
97
98
99 /*
100  * Check if SSE instruction set is available
101  */
102 static inline boolean_t
103 zfs_sse_available(void)
104 {
105         return (!!(cpu_feature & CPUID_SSE));
106 }
107
108 /*
109  * Check if SSE2 instruction set is available
110  */
111 static inline boolean_t
112 zfs_sse2_available(void)
113 {
114         return (!!(cpu_feature & CPUID_SSE2));
115 }
116
117 /*
118  * Check if SSE3 instruction set is available
119  */
120 static inline boolean_t
121 zfs_sse3_available(void)
122 {
123         return (!!(cpu_feature2 & CPUID2_SSE3));
124 }
125
126 /*
127  * Check if SSSE3 instruction set is available
128  */
129 static inline boolean_t
130 zfs_ssse3_available(void)
131 {
132         return (!!(cpu_feature2 & CPUID2_SSSE3));
133 }
134
135 /*
136  * Check if SSE4.1 instruction set is available
137  */
138 static inline boolean_t
139 zfs_sse4_1_available(void)
140 {
141         return (!!(cpu_feature2 & CPUID2_SSE41));
142 }
143
144 /*
145  * Check if SSE4.2 instruction set is available
146  */
147 static inline boolean_t
148 zfs_sse4_2_available(void)
149 {
150         return (!!(cpu_feature2 & CPUID2_SSE42));
151 }
152
153 /*
154  * Check if AVX instruction set is available
155  */
156 static inline boolean_t
157 zfs_avx_available(void)
158 {
159         boolean_t has_avx;
160
161         has_avx = !!(cpu_feature2 & CPUID2_AVX);
162
163         return (has_avx && __ymm_enabled());
164 }
165
166 /*
167  * Check if AVX2 instruction set is available
168  */
169 static inline boolean_t
170 zfs_avx2_available(void)
171 {
172         boolean_t has_avx2;
173
174         has_avx2 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX2);
175
176         return (has_avx2 && __ymm_enabled());
177 }
178
179 /*
180  * AVX-512 family of instruction sets:
181  *
182  * AVX512F      Foundation
183  * AVX512CD     Conflict Detection Instructions
184  * AVX512ER     Exponential and Reciprocal Instructions
185  * AVX512PF     Prefetch Instructions
186  *
187  * AVX512BW     Byte and Word Instructions
188  * AVX512DQ     Double-word and Quadword Instructions
189  * AVX512VL     Vector Length Extensions
190  *
191  * AVX512IFMA   Integer Fused Multiply Add (Not supported by kernel 4.4)
192  * AVX512VBMI   Vector Byte Manipulation Instructions
193  */
194
195
196 /* Check if AVX512F instruction set is available */
197 static inline boolean_t
198 zfs_avx512f_available(void)
199 {
200         boolean_t has_avx512;
201
202         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F);
203
204         return (has_avx512 && __zmm_enabled());
205 }
206
207 /* Check if AVX512CD instruction set is available */
208 static inline boolean_t
209 zfs_avx512cd_available(void)
210 {
211         boolean_t has_avx512;
212
213         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F) &&
214             !!(cpu_stdext_feature & CPUID_STDEXT_AVX512CD);
215
216         return (has_avx512 && __zmm_enabled());
217 }
218
219 /* Check if AVX512ER instruction set is available */
220 static inline boolean_t
221 zfs_avx512er_available(void)
222 {
223         boolean_t has_avx512;
224
225         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F) &&
226             !!(cpu_stdext_feature & CPUID_STDEXT_AVX512CD);
227
228         return (has_avx512 && __zmm_enabled());
229 }
230
231 /* Check if AVX512PF instruction set is available */
232 static inline boolean_t
233 zfs_avx512pf_available(void)
234 {
235         boolean_t has_avx512;
236
237         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F) &&
238             !!(cpu_stdext_feature & CPUID_STDEXT_AVX512PF);
239
240         return (has_avx512 && __zmm_enabled());
241 }
242
243 /* Check if AVX512BW instruction set is available */
244 static inline boolean_t
245 zfs_avx512bw_available(void)
246 {
247         boolean_t has_avx512 = B_FALSE;
248
249         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512BW);
250
251         return (has_avx512 && __zmm_enabled());
252 }
253
254 /* Check if AVX512DQ instruction set is available */
255 static inline boolean_t
256 zfs_avx512dq_available(void)
257 {
258         boolean_t has_avx512;
259
260         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F) &&
261             !!(cpu_stdext_feature & CPUID_STDEXT_AVX512DQ);
262
263         return (has_avx512 && __zmm_enabled());
264 }
265
266 /* Check if AVX512VL instruction set is available */
267 static inline boolean_t
268 zfs_avx512vl_available(void)
269 {
270         boolean_t has_avx512;
271
272         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F) &&
273             !!(cpu_stdext_feature & CPUID_STDEXT_AVX512VL);
274
275         return (has_avx512 && __zmm_enabled());
276 }
277
278 /* Check if AVX512IFMA instruction set is available */
279 static inline boolean_t
280 zfs_avx512ifma_available(void)
281 {
282         boolean_t has_avx512;
283
284         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F) &&
285             !!(cpu_stdext_feature & CPUID_STDEXT_AVX512IFMA);
286
287         return (has_avx512 && __zmm_enabled());
288 }
289
290 /* Check if AVX512VBMI instruction set is available */
291 static inline boolean_t
292 zfs_avx512vbmi_available(void)
293 {
294         boolean_t has_avx512;
295
296         has_avx512 = !!(cpu_stdext_feature & CPUID_STDEXT_AVX512F) &&
297             !!(cpu_stdext_feature & CPUID_STDEXT_BMI1);
298
299         return (has_avx512 && __zmm_enabled());
300 }