1*61145dc2SMartin 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 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()); 1217a7741afSMartin Matuska 1227a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1237a7741afSMartin Matuska "osxsave", boot_cpu_has(X86_FEATURE_OSXSAVE)); 1247a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1257a7741afSMartin Matuska "xsaves", static_cpu_has(X86_FEATURE_XSAVES)); 1267a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1277a7741afSMartin Matuska "xsaveopt", static_cpu_has(X86_FEATURE_XSAVEOPT)); 1287a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1297a7741afSMartin Matuska "xsave", static_cpu_has(X86_FEATURE_XSAVE)); 1307a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1317a7741afSMartin Matuska "fxsr", static_cpu_has(X86_FEATURE_FXSR)); 1327a7741afSMartin Matuska #endif /* __x86__ */ 1337a7741afSMartin Matuska #if defined(__arm__) || defined(__aarch64__) 1347a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1357a7741afSMartin Matuska "kernel_neon", HAVE_KERNEL_NEON); 136dd215568SMartin Matuska #if defined(CONFIG_KERNEL_MODE_NEON) 1377a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1387a7741afSMartin Matuska "kernel_mode_neon", CONFIG_KERNEL_MODE_NEON); 139dd215568SMartin Matuska #endif /* CONFIG_KERNEL_MODE_NEON */ 1407a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1417a7741afSMartin Matuska "neon", zfs_neon_available()); 1427a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1437a7741afSMartin Matuska "sha256", zfs_sha256_available()); 1447a7741afSMartin Matuska #if defined(__aarch64__) 1457a7741afSMartin Matuska /* 1467a7741afSMartin Matuska * This technically can exist on 32b ARM but we don't 1477a7741afSMartin Matuska * define hooks to check for it and I didn't want to 1487a7741afSMartin Matuska * learn enough ARM ASM to add one. 1497a7741afSMartin Matuska */ 1507a7741afSMartin Matuska off += SIMD_STAT_PRINT(simd_stat_kstat_payload, 1517a7741afSMartin Matuska "sha512", zfs_sha512_available()); 1527a7741afSMartin Matuska #endif /* __aarch64__ */ 1537a7741afSMartin Matuska #endif /* __arm__ */ 1547a7741afSMartin Matuska /* We want to short-circuit this on unsupported platforms. */ 1557a7741afSMartin Matuska off += 1; 1567a7741afSMartin Matuska } 1577a7741afSMartin Matuska 1587a7741afSMartin Matuska kmem_scnprintf(buf, MIN(off, size), "%s", simd_stat_kstat_payload); 1597a7741afSMartin Matuska #endif /* __linux__ */ 1607a7741afSMartin Matuska return (0); 1617a7741afSMartin Matuska } 1627a7741afSMartin Matuska #endif /* _KERNEL */ 1637a7741afSMartin Matuska 1647a7741afSMartin Matuska void 1657a7741afSMartin Matuska simd_stat_init(void) 1667a7741afSMartin Matuska { 1677a7741afSMartin Matuska static boolean_t simd_stat_initialized = B_FALSE; 1687a7741afSMartin Matuska 1697a7741afSMartin Matuska if (!simd_stat_initialized) { 1707a7741afSMartin Matuska #if defined(_KERNEL) 1717a7741afSMartin Matuska /* Install kstats for all implementations */ 1727a7741afSMartin Matuska simd_stat_kstat = kstat_create("zfs", 0, "simd", "misc", 1737a7741afSMartin Matuska KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL); 1747a7741afSMartin Matuska 1757a7741afSMartin Matuska 1767a7741afSMartin Matuska if (simd_stat_kstat != NULL) { 1777a7741afSMartin Matuska simd_stat_kstat->ks_data = (void*)(uintptr_t)1; 1787a7741afSMartin Matuska simd_stat_kstat->ks_ndata = 1; 1797a7741afSMartin Matuska simd_stat_kstat->ks_flags |= KSTAT_FLAG_NO_HEADERS; 1807a7741afSMartin Matuska kstat_set_raw_ops(simd_stat_kstat, 1817a7741afSMartin Matuska NULL, 1827a7741afSMartin Matuska simd_stat_kstat_data, 1837a7741afSMartin Matuska NULL); 1847a7741afSMartin Matuska kstat_install(simd_stat_kstat); 1857a7741afSMartin Matuska } 1867a7741afSMartin Matuska #endif /* _KERNEL */ 1877a7741afSMartin Matuska } 1887a7741afSMartin Matuska /* Finish initialization */ 1897a7741afSMartin Matuska simd_stat_initialized = B_TRUE; 1907a7741afSMartin Matuska } 1917a7741afSMartin Matuska 1927a7741afSMartin Matuska void 1937a7741afSMartin Matuska simd_stat_fini(void) 1947a7741afSMartin Matuska { 1957a7741afSMartin Matuska #if defined(_KERNEL) 1967a7741afSMartin Matuska if (simd_stat_kstat != NULL) { 1977a7741afSMartin Matuska kstat_delete(simd_stat_kstat); 1987a7741afSMartin Matuska simd_stat_kstat = NULL; 1997a7741afSMartin Matuska } 2007a7741afSMartin Matuska #endif 2017a7741afSMartin Matuska } 2027a7741afSMartin Matuska 2037a7741afSMartin Matuska #ifdef _KERNEL 2047a7741afSMartin Matuska EXPORT_SYMBOL(simd_stat_init); 2057a7741afSMartin Matuska EXPORT_SYMBOL(simd_stat_fini); 2067a7741afSMartin Matuska #endif 207