4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2024 Google, Inc. All rights reserved.
24 #include <sys/zfs_context.h>
25 #include <sys/kstat.h>
31 #include <linux/simd.h>
32 #endif /* __linux__ */
33 kstat_t
*simd_stat_kstat
;
37 /* Sometimes, we don't define these at all. */
38 #ifndef HAVE_KERNEL_FPU
39 #define HAVE_KERNEL_FPU (0)
41 #ifndef HAVE_KERNEL_NEON
42 #define HAVE_KERNEL_NEON (0)
44 #ifndef HAVE_KERNEL_FPU_INTERNAL
45 #define HAVE_KERNEL_FPU_INTERNAL (0)
47 #ifndef HAVE_UNDERSCORE_KERNEL_FPU
48 #define HAVE_UNDERSCORE_KERNEL_FPU (0)
51 #define SIMD_STAT_PRINT(s, feat, val) \
52 kmem_scnprintf(s + off, MAX(4095-off, 0), "%-16s\t%1d\n", feat, (val))
55 simd_stat_kstat_data(char *buf
, size_t size
, void *data
)
59 static char simd_stat_kstat_payload
[4096] = {0};
63 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
64 "kfpu_allowed", kfpu_allowed());
65 #if defined(__x86_64__) || defined(__i386__)
66 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
67 "kfpu", HAVE_KERNEL_FPU
);
68 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
69 "kfpu_internal", HAVE_KERNEL_FPU_INTERNAL
);
70 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
71 "__kernel_fpu", HAVE_UNDERSCORE_KERNEL_FPU
);
72 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
73 "sse", zfs_sse_available());
74 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
75 "sse2", zfs_sse2_available());
76 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
77 "sse3", zfs_sse3_available());
78 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
79 "ssse3", zfs_ssse3_available());
80 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
81 "sse41", zfs_sse4_1_available());
82 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
83 "sse42", zfs_sse4_2_available());
84 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
85 "avx", zfs_avx_available());
86 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
87 "avx2", zfs_avx2_available());
88 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
89 "avx512f", zfs_avx512f_available());
90 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
91 "avx512cd", zfs_avx512cd_available());
92 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
93 "avx512er", zfs_avx512er_available());
94 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
95 "avx512pf", zfs_avx512pf_available());
96 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
97 "avx512bw", zfs_avx512bw_available());
98 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
99 "avx512dq", zfs_avx512dq_available());
100 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
101 "avx512vl", zfs_avx512vl_available());
102 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
103 "avx512ifma", zfs_avx512ifma_available());
104 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
105 "avx512vbmi", zfs_avx512vbmi_available());
106 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
107 "ymm", __ymm_enabled());
108 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
109 "zmm", __zmm_enabled());
110 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
111 "bmi1", zfs_bmi1_available());
112 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
113 "bmi2", zfs_bmi2_available());
114 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
115 "aes", zfs_aes_available());
116 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
117 "pclmulqdq", zfs_pclmulqdq_available());
118 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
119 "movbe", zfs_movbe_available());
121 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
122 "osxsave", boot_cpu_has(X86_FEATURE_OSXSAVE
));
123 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
124 "xsaves", static_cpu_has(X86_FEATURE_XSAVES
));
125 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
126 "xsaveopt", static_cpu_has(X86_FEATURE_XSAVEOPT
));
127 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
128 "xsave", static_cpu_has(X86_FEATURE_XSAVE
));
129 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
130 "fxsr", static_cpu_has(X86_FEATURE_FXSR
));
132 #if defined(__arm__) || defined(__aarch64__)
133 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
134 "kernel_neon", HAVE_KERNEL_NEON
);
135 #if defined(CONFIG_KERNEL_MODE_NEON)
136 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
137 "kernel_mode_neon", CONFIG_KERNEL_MODE_NEON
);
138 #endif /* CONFIG_KERNEL_MODE_NEON */
139 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
140 "neon", zfs_neon_available());
141 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
142 "sha256", zfs_sha256_available());
143 #if defined(__aarch64__)
145 * This technically can exist on 32b ARM but we don't
146 * define hooks to check for it and I didn't want to
147 * learn enough ARM ASM to add one.
149 off
+= SIMD_STAT_PRINT(simd_stat_kstat_payload
,
150 "sha512", zfs_sha512_available());
151 #endif /* __aarch64__ */
153 /* We want to short-circuit this on unsupported platforms. */
157 kmem_scnprintf(buf
, MIN(off
, size
), "%s", simd_stat_kstat_payload
);
158 #endif /* __linux__ */
166 static boolean_t simd_stat_initialized
= B_FALSE
;
168 if (!simd_stat_initialized
) {
170 /* Install kstats for all implementations */
171 simd_stat_kstat
= kstat_create("zfs", 0, "simd", "misc",
172 KSTAT_TYPE_RAW
, 0, KSTAT_FLAG_VIRTUAL
);
175 if (simd_stat_kstat
!= NULL
) {
176 simd_stat_kstat
->ks_data
= (void*)(uintptr_t)1;
177 simd_stat_kstat
->ks_ndata
= 1;
178 simd_stat_kstat
->ks_flags
|= KSTAT_FLAG_NO_HEADERS
;
179 kstat_set_raw_ops(simd_stat_kstat
,
181 simd_stat_kstat_data
,
183 kstat_install(simd_stat_kstat
);
187 /* Finish initialization */
188 simd_stat_initialized
= B_TRUE
;
195 if (simd_stat_kstat
!= NULL
) {
196 kstat_delete(simd_stat_kstat
);
197 simd_stat_kstat
= NULL
;
203 EXPORT_SYMBOL(simd_stat_init
);
204 EXPORT_SYMBOL(simd_stat_fini
);