161145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
27a7741afSMartin Matuska /*
37a7741afSMartin Matuska * CDDL HEADER START
47a7741afSMartin Matuska *
57a7741afSMartin Matuska * The contents of this file are subject to the terms of the
67a7741afSMartin Matuska * Common Development and Distribution License (the "License").
77a7741afSMartin Matuska * You may not use this file except in compliance with the License.
87a7741afSMartin Matuska *
97a7741afSMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107a7741afSMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
117a7741afSMartin Matuska * See the License for the specific language governing permissions
127a7741afSMartin Matuska * and limitations under the License.
137a7741afSMartin Matuska *
147a7741afSMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each
157a7741afSMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167a7741afSMartin Matuska * If applicable, add the following below this CDDL HEADER, with the
177a7741afSMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying
187a7741afSMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner]
197a7741afSMartin Matuska *
207a7741afSMartin Matuska * CDDL HEADER END
217a7741afSMartin Matuska */
227a7741afSMartin Matuska /*
237a7741afSMartin Matuska * Copyright 2024 Google, Inc. All rights reserved.
247a7741afSMartin Matuska */
257a7741afSMartin Matuska #include <sys/zfs_context.h>
267a7741afSMartin Matuska #include <sys/kstat.h>
277a7741afSMartin Matuska #include <sys/simd.h>
287a7741afSMartin Matuska
297a7741afSMartin Matuska
307a7741afSMartin Matuska #ifdef _KERNEL
317a7741afSMartin Matuska #ifdef __linux__
327a7741afSMartin Matuska #include <linux/simd.h>
337a7741afSMartin Matuska #endif /* __linux__ */
347a7741afSMartin Matuska kstat_t *simd_stat_kstat;
357a7741afSMartin Matuska #endif /* _KERNEL */
367a7741afSMartin Matuska
377a7741afSMartin Matuska #ifdef _KERNEL
387a7741afSMartin Matuska /* Sometimes, we don't define these at all. */
397a7741afSMartin Matuska #ifndef HAVE_KERNEL_FPU
407a7741afSMartin Matuska #define HAVE_KERNEL_FPU (0)
417a7741afSMartin Matuska #endif
427a7741afSMartin Matuska #ifndef HAVE_KERNEL_NEON
437a7741afSMartin Matuska #define HAVE_KERNEL_NEON (0)
447a7741afSMartin Matuska #endif
457a7741afSMartin Matuska #ifndef HAVE_KERNEL_FPU_INTERNAL
467a7741afSMartin Matuska #define HAVE_KERNEL_FPU_INTERNAL (0)
477a7741afSMartin Matuska #endif
487a7741afSMartin Matuska #ifndef HAVE_UNDERSCORE_KERNEL_FPU
497a7741afSMartin Matuska #define HAVE_UNDERSCORE_KERNEL_FPU (0)
507a7741afSMartin Matuska #endif
517a7741afSMartin Matuska
527a7741afSMartin Matuska #define SIMD_STAT_PRINT(s, feat, val) \
537a7741afSMartin Matuska kmem_scnprintf(s + off, MAX(4095-off, 0), "%-16s\t%1d\n", feat, (val))
547a7741afSMartin Matuska
557a7741afSMartin Matuska static int
simd_stat_kstat_data(char * buf,size_t size,void * data)567a7741afSMartin Matuska simd_stat_kstat_data(char *buf, size_t size, void *data)
577a7741afSMartin Matuska {
587a7741afSMartin Matuska (void) data;
597a7741afSMartin Matuska
607a7741afSMartin Matuska static char simd_stat_kstat_payload[4096] = {0};
617a7741afSMartin Matuska static int off = 0;
627a7741afSMartin Matuska #ifdef __linux__
637a7741afSMartin Matuska if (off == 0) {
647a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
657a7741afSMartin Matuska "kfpu_allowed", kfpu_allowed());
667a7741afSMartin Matuska #if defined(__x86_64__) || defined(__i386__)
677a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
687a7741afSMartin Matuska "kfpu", HAVE_KERNEL_FPU);
697a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
707a7741afSMartin Matuska "kfpu_internal", HAVE_KERNEL_FPU_INTERNAL);
717a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
727a7741afSMartin Matuska "__kernel_fpu", HAVE_UNDERSCORE_KERNEL_FPU);
737a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
747a7741afSMartin Matuska "sse", zfs_sse_available());
757a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
767a7741afSMartin Matuska "sse2", zfs_sse2_available());
777a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
787a7741afSMartin Matuska "sse3", zfs_sse3_available());
797a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
807a7741afSMartin Matuska "ssse3", zfs_ssse3_available());
817a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
827a7741afSMartin Matuska "sse41", zfs_sse4_1_available());
837a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
847a7741afSMartin Matuska "sse42", zfs_sse4_2_available());
857a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
867a7741afSMartin Matuska "avx", zfs_avx_available());
877a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
887a7741afSMartin Matuska "avx2", zfs_avx2_available());
897a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
907a7741afSMartin Matuska "avx512f", zfs_avx512f_available());
917a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
927a7741afSMartin Matuska "avx512cd", zfs_avx512cd_available());
937a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
947a7741afSMartin Matuska "avx512er", zfs_avx512er_available());
957a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
967a7741afSMartin Matuska "avx512pf", zfs_avx512pf_available());
977a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
987a7741afSMartin Matuska "avx512bw", zfs_avx512bw_available());
997a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1007a7741afSMartin Matuska "avx512dq", zfs_avx512dq_available());
1017a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1027a7741afSMartin Matuska "avx512vl", zfs_avx512vl_available());
1037a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1047a7741afSMartin Matuska "avx512ifma", zfs_avx512ifma_available());
1057a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1067a7741afSMartin Matuska "avx512vbmi", zfs_avx512vbmi_available());
1077a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1087a7741afSMartin Matuska "ymm", __ymm_enabled());
1097a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1107a7741afSMartin Matuska "zmm", __zmm_enabled());
1117a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1127a7741afSMartin Matuska "bmi1", zfs_bmi1_available());
1137a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1147a7741afSMartin Matuska "bmi2", zfs_bmi2_available());
1157a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1167a7741afSMartin Matuska "aes", zfs_aes_available());
1177a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1187a7741afSMartin Matuska "pclmulqdq", zfs_pclmulqdq_available());
1197a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1207a7741afSMartin Matuska "movbe", zfs_movbe_available());
121*53a2e263SMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
122*53a2e263SMartin Matuska "vaes", zfs_vaes_available());
123*53a2e263SMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
124*53a2e263SMartin Matuska "vpclmulqdq", zfs_vpclmulqdq_available());
1257a7741afSMartin Matuska
1267a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1277a7741afSMartin Matuska "osxsave", boot_cpu_has(X86_FEATURE_OSXSAVE));
1287a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1297a7741afSMartin Matuska "xsaves", static_cpu_has(X86_FEATURE_XSAVES));
1307a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1317a7741afSMartin Matuska "xsaveopt", static_cpu_has(X86_FEATURE_XSAVEOPT));
1327a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1337a7741afSMartin Matuska "xsave", static_cpu_has(X86_FEATURE_XSAVE));
1347a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1357a7741afSMartin Matuska "fxsr", static_cpu_has(X86_FEATURE_FXSR));
1367a7741afSMartin Matuska #endif /* __x86__ */
1377a7741afSMartin Matuska #if defined(__arm__) || defined(__aarch64__)
1387a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1397a7741afSMartin Matuska "kernel_neon", HAVE_KERNEL_NEON);
140dd215568SMartin Matuska #if defined(CONFIG_KERNEL_MODE_NEON)
1417a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1427a7741afSMartin Matuska "kernel_mode_neon", CONFIG_KERNEL_MODE_NEON);
143dd215568SMartin Matuska #endif /* CONFIG_KERNEL_MODE_NEON */
1447a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1457a7741afSMartin Matuska "neon", zfs_neon_available());
1467a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1477a7741afSMartin Matuska "sha256", zfs_sha256_available());
1487a7741afSMartin Matuska #if defined(__aarch64__)
1497a7741afSMartin Matuska /*
1507a7741afSMartin Matuska * This technically can exist on 32b ARM but we don't
1517a7741afSMartin Matuska * define hooks to check for it and I didn't want to
1527a7741afSMartin Matuska * learn enough ARM ASM to add one.
1537a7741afSMartin Matuska */
1547a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1557a7741afSMartin Matuska "sha512", zfs_sha512_available());
1567a7741afSMartin Matuska #endif /* __aarch64__ */
1577a7741afSMartin Matuska #endif /* __arm__ */
1587a7741afSMartin Matuska /* We want to short-circuit this on unsupported platforms. */
1597a7741afSMartin Matuska off += 1;
1607a7741afSMartin Matuska }
1617a7741afSMartin Matuska
1627a7741afSMartin Matuska kmem_scnprintf(buf, MIN(off, size), "%s", simd_stat_kstat_payload);
1637a7741afSMartin Matuska #endif /* __linux__ */
1647a7741afSMartin Matuska return (0);
1657a7741afSMartin Matuska }
1667a7741afSMartin Matuska #endif /* _KERNEL */
1677a7741afSMartin Matuska
1687a7741afSMartin Matuska void
simd_stat_init(void)1697a7741afSMartin Matuska simd_stat_init(void)
1707a7741afSMartin Matuska {
1717a7741afSMartin Matuska static boolean_t simd_stat_initialized = B_FALSE;
1727a7741afSMartin Matuska
1737a7741afSMartin Matuska if (!simd_stat_initialized) {
1747a7741afSMartin Matuska #if defined(_KERNEL)
1757a7741afSMartin Matuska /* Install kstats for all implementations */
1767a7741afSMartin Matuska simd_stat_kstat = kstat_create("zfs", 0, "simd", "misc",
1777a7741afSMartin Matuska KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
1787a7741afSMartin Matuska
1797a7741afSMartin Matuska
1807a7741afSMartin Matuska if (simd_stat_kstat != NULL) {
1817a7741afSMartin Matuska simd_stat_kstat->ks_data = (void*)(uintptr_t)1;
1827a7741afSMartin Matuska simd_stat_kstat->ks_ndata = 1;
1837a7741afSMartin Matuska simd_stat_kstat->ks_flags |= KSTAT_FLAG_NO_HEADERS;
1847a7741afSMartin Matuska kstat_set_raw_ops(simd_stat_kstat,
1857a7741afSMartin Matuska NULL,
1867a7741afSMartin Matuska simd_stat_kstat_data,
1877a7741afSMartin Matuska NULL);
1887a7741afSMartin Matuska kstat_install(simd_stat_kstat);
1897a7741afSMartin Matuska }
1907a7741afSMartin Matuska #endif /* _KERNEL */
1917a7741afSMartin Matuska }
1927a7741afSMartin Matuska /* Finish initialization */
1937a7741afSMartin Matuska simd_stat_initialized = B_TRUE;
1947a7741afSMartin Matuska }
1957a7741afSMartin Matuska
1967a7741afSMartin Matuska void
simd_stat_fini(void)1977a7741afSMartin Matuska simd_stat_fini(void)
1987a7741afSMartin Matuska {
1997a7741afSMartin Matuska #if defined(_KERNEL)
2007a7741afSMartin Matuska if (simd_stat_kstat != NULL) {
2017a7741afSMartin Matuska kstat_delete(simd_stat_kstat);
2027a7741afSMartin Matuska simd_stat_kstat = NULL;
2037a7741afSMartin Matuska }
2047a7741afSMartin Matuska #endif
2057a7741afSMartin Matuska }
2067a7741afSMartin Matuska
2077a7741afSMartin Matuska #ifdef _KERNEL
2087a7741afSMartin Matuska EXPORT_SYMBOL(simd_stat_init);
2097a7741afSMartin Matuska EXPORT_SYMBOL(simd_stat_fini);
2107a7741afSMartin Matuska #endif
211