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