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