xref: /freebsd/sys/contrib/openzfs/module/icp/algs/blake3/blake3_impl.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1*61145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
21f1e2261SMartin Matuska /*
31f1e2261SMartin Matuska  * CDDL HEADER START
41f1e2261SMartin Matuska  *
51f1e2261SMartin Matuska  * The contents of this file are subject to the terms of the
61f1e2261SMartin Matuska  * Common Development and Distribution License (the "License").
71f1e2261SMartin Matuska  * You may not use this file except in compliance with the License.
81f1e2261SMartin Matuska  *
91f1e2261SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
111f1e2261SMartin Matuska  * See the License for the specific language governing permissions
121f1e2261SMartin Matuska  * and limitations under the License.
131f1e2261SMartin Matuska  *
141f1e2261SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
151f1e2261SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
161f1e2261SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
171f1e2261SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
181f1e2261SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
191f1e2261SMartin Matuska  *
201f1e2261SMartin Matuska  * CDDL HEADER END
211f1e2261SMartin Matuska  */
221f1e2261SMartin Matuska 
231f1e2261SMartin Matuska /*
241f1e2261SMartin Matuska  * Copyright (c) 2021-2022 Tino Reichardt <milky-zfs@mcmilk.de>
251f1e2261SMartin Matuska  */
261f1e2261SMartin Matuska 
272a58b312SMartin Matuska #include <sys/simd.h>
281f1e2261SMartin Matuska #include <sys/zfs_context.h>
292a58b312SMartin Matuska #include <sys/zfs_impl.h>
302a58b312SMartin Matuska #include <sys/blake3.h>
311f1e2261SMartin Matuska 
321f1e2261SMartin Matuska #include "blake3_impl.h"
331f1e2261SMartin Matuska 
346c8358cdSWarner Losh #if !defined(OMIT_SIMD) && (defined(__aarch64__) ||  \
352a58b312SMartin Matuska 	(defined(__x86_64) && defined(HAVE_SSE2)) || \
366c8358cdSWarner Losh     (defined(__PPC64__) && defined(__LITTLE_ENDIAN__)))
376c8358cdSWarner Losh #define USE_SIMD
386c8358cdSWarner Losh #endif
392a58b312SMartin Matuska 
406c8358cdSWarner Losh #ifdef USE_SIMD
412a58b312SMartin Matuska extern void ASMABI zfs_blake3_compress_in_place_sse2(uint32_t cv[8],
422a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
432a58b312SMartin Matuska     uint64_t counter, uint8_t flags);
442a58b312SMartin Matuska 
452a58b312SMartin Matuska extern void ASMABI zfs_blake3_compress_xof_sse2(const uint32_t cv[8],
462a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
472a58b312SMartin Matuska     uint64_t counter, uint8_t flags, uint8_t out[64]);
482a58b312SMartin Matuska 
492a58b312SMartin Matuska extern void ASMABI zfs_blake3_hash_many_sse2(const uint8_t * const *inputs,
502a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
512a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
522a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out);
532a58b312SMartin Matuska 
blake3_compress_in_place_sse2(uint32_t cv[8],const uint8_t block[BLAKE3_BLOCK_LEN],uint8_t block_len,uint64_t counter,uint8_t flags)542a58b312SMartin Matuska static void blake3_compress_in_place_sse2(uint32_t cv[8],
552a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
562a58b312SMartin Matuska     uint64_t counter, uint8_t flags) {
572a58b312SMartin Matuska 	kfpu_begin();
582a58b312SMartin Matuska 	zfs_blake3_compress_in_place_sse2(cv, block, block_len, counter,
592a58b312SMartin Matuska 	    flags);
602a58b312SMartin Matuska 	kfpu_end();
612a58b312SMartin Matuska }
622a58b312SMartin Matuska 
blake3_compress_xof_sse2(const uint32_t cv[8],const uint8_t block[BLAKE3_BLOCK_LEN],uint8_t block_len,uint64_t counter,uint8_t flags,uint8_t out[64])632a58b312SMartin Matuska static void blake3_compress_xof_sse2(const uint32_t cv[8],
642a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
652a58b312SMartin Matuska     uint64_t counter, uint8_t flags, uint8_t out[64]) {
662a58b312SMartin Matuska 	kfpu_begin();
672a58b312SMartin Matuska 	zfs_blake3_compress_xof_sse2(cv, block, block_len, counter, flags,
682a58b312SMartin Matuska 	    out);
692a58b312SMartin Matuska 	kfpu_end();
702a58b312SMartin Matuska }
712a58b312SMartin Matuska 
blake3_hash_many_sse2(const uint8_t * const * inputs,size_t num_inputs,size_t blocks,const uint32_t key[8],uint64_t counter,boolean_t increment_counter,uint8_t flags,uint8_t flags_start,uint8_t flags_end,uint8_t * out)722a58b312SMartin Matuska static void blake3_hash_many_sse2(const uint8_t * const *inputs,
732a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
742a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
752a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out) {
762a58b312SMartin Matuska 	kfpu_begin();
772a58b312SMartin Matuska 	zfs_blake3_hash_many_sse2(inputs, num_inputs, blocks, key, counter,
782a58b312SMartin Matuska 	    increment_counter, flags, flags_start, flags_end, out);
792a58b312SMartin Matuska 	kfpu_end();
802a58b312SMartin Matuska }
812a58b312SMartin Matuska 
blake3_is_sse2_supported(void)822a58b312SMartin Matuska static boolean_t blake3_is_sse2_supported(void)
832a58b312SMartin Matuska {
842a58b312SMartin Matuska #if defined(__x86_64)
852a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_sse2_available());
862a58b312SMartin Matuska #elif defined(__PPC64__)
872a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_vsx_available());
882a58b312SMartin Matuska #else
892a58b312SMartin Matuska 	return (kfpu_allowed());
902a58b312SMartin Matuska #endif
912a58b312SMartin Matuska }
922a58b312SMartin Matuska 
932a58b312SMartin Matuska const blake3_ops_t blake3_sse2_impl = {
942a58b312SMartin Matuska 	.compress_in_place = blake3_compress_in_place_sse2,
952a58b312SMartin Matuska 	.compress_xof = blake3_compress_xof_sse2,
962a58b312SMartin Matuska 	.hash_many = blake3_hash_many_sse2,
972a58b312SMartin Matuska 	.is_supported = blake3_is_sse2_supported,
982a58b312SMartin Matuska 	.degree = 4,
992a58b312SMartin Matuska 	.name = "sse2"
1002a58b312SMartin Matuska };
1012a58b312SMartin Matuska #endif
1022a58b312SMartin Matuska 
1036c8358cdSWarner Losh #ifdef USE_SIMD
1042a58b312SMartin Matuska 
1052a58b312SMartin Matuska extern void ASMABI zfs_blake3_compress_in_place_sse41(uint32_t cv[8],
1062a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
1072a58b312SMartin Matuska     uint64_t counter, uint8_t flags);
1082a58b312SMartin Matuska 
1092a58b312SMartin Matuska extern void ASMABI zfs_blake3_compress_xof_sse41(const uint32_t cv[8],
1102a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
1112a58b312SMartin Matuska     uint64_t counter, uint8_t flags, uint8_t out[64]);
1122a58b312SMartin Matuska 
1132a58b312SMartin Matuska extern void ASMABI zfs_blake3_hash_many_sse41(const uint8_t * const *inputs,
1142a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
1152a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
1162a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out);
1172a58b312SMartin Matuska 
blake3_compress_in_place_sse41(uint32_t cv[8],const uint8_t block[BLAKE3_BLOCK_LEN],uint8_t block_len,uint64_t counter,uint8_t flags)1182a58b312SMartin Matuska static void blake3_compress_in_place_sse41(uint32_t cv[8],
1192a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
1202a58b312SMartin Matuska     uint64_t counter, uint8_t flags) {
1212a58b312SMartin Matuska 	kfpu_begin();
1222a58b312SMartin Matuska 	zfs_blake3_compress_in_place_sse41(cv, block, block_len, counter,
1232a58b312SMartin Matuska 	    flags);
1242a58b312SMartin Matuska 	kfpu_end();
1252a58b312SMartin Matuska }
1262a58b312SMartin Matuska 
blake3_compress_xof_sse41(const uint32_t cv[8],const uint8_t block[BLAKE3_BLOCK_LEN],uint8_t block_len,uint64_t counter,uint8_t flags,uint8_t out[64])1272a58b312SMartin Matuska static void blake3_compress_xof_sse41(const uint32_t cv[8],
1282a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
1292a58b312SMartin Matuska     uint64_t counter, uint8_t flags, uint8_t out[64]) {
1302a58b312SMartin Matuska 	kfpu_begin();
1312a58b312SMartin Matuska 	zfs_blake3_compress_xof_sse41(cv, block, block_len, counter, flags,
1322a58b312SMartin Matuska 	    out);
1332a58b312SMartin Matuska 	kfpu_end();
1342a58b312SMartin Matuska }
1352a58b312SMartin Matuska 
blake3_hash_many_sse41(const uint8_t * const * inputs,size_t num_inputs,size_t blocks,const uint32_t key[8],uint64_t counter,boolean_t increment_counter,uint8_t flags,uint8_t flags_start,uint8_t flags_end,uint8_t * out)1362a58b312SMartin Matuska static void blake3_hash_many_sse41(const uint8_t * const *inputs,
1372a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
1382a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
1392a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out) {
1402a58b312SMartin Matuska 	kfpu_begin();
1412a58b312SMartin Matuska 	zfs_blake3_hash_many_sse41(inputs, num_inputs, blocks, key, counter,
1422a58b312SMartin Matuska 	    increment_counter, flags, flags_start, flags_end, out);
1432a58b312SMartin Matuska 	kfpu_end();
1442a58b312SMartin Matuska }
1452a58b312SMartin Matuska 
blake3_is_sse41_supported(void)1462a58b312SMartin Matuska static boolean_t blake3_is_sse41_supported(void)
1472a58b312SMartin Matuska {
1482a58b312SMartin Matuska #if defined(__x86_64)
1492a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_sse4_1_available());
1502a58b312SMartin Matuska #elif defined(__PPC64__)
1512a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_vsx_available());
1522a58b312SMartin Matuska #else
1532a58b312SMartin Matuska 	return (kfpu_allowed());
1542a58b312SMartin Matuska #endif
1552a58b312SMartin Matuska }
1562a58b312SMartin Matuska 
1572a58b312SMartin Matuska const blake3_ops_t blake3_sse41_impl = {
1582a58b312SMartin Matuska 	.compress_in_place = blake3_compress_in_place_sse41,
1592a58b312SMartin Matuska 	.compress_xof = blake3_compress_xof_sse41,
1602a58b312SMartin Matuska 	.hash_many = blake3_hash_many_sse41,
1612a58b312SMartin Matuska 	.is_supported = blake3_is_sse41_supported,
1622a58b312SMartin Matuska 	.degree = 4,
1632a58b312SMartin Matuska 	.name = "sse41"
1642a58b312SMartin Matuska };
1652a58b312SMartin Matuska #endif
1662a58b312SMartin Matuska 
1672a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_SSE4_1) && defined(HAVE_AVX2)
1682a58b312SMartin Matuska extern void ASMABI zfs_blake3_hash_many_avx2(const uint8_t * const *inputs,
1692a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
1702a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
1712a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out);
1722a58b312SMartin Matuska 
blake3_hash_many_avx2(const uint8_t * const * inputs,size_t num_inputs,size_t blocks,const uint32_t key[8],uint64_t counter,boolean_t increment_counter,uint8_t flags,uint8_t flags_start,uint8_t flags_end,uint8_t * out)1732a58b312SMartin Matuska static void blake3_hash_many_avx2(const uint8_t * const *inputs,
1742a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
1752a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
1762a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out) {
1772a58b312SMartin Matuska 	kfpu_begin();
1782a58b312SMartin Matuska 	zfs_blake3_hash_many_avx2(inputs, num_inputs, blocks, key, counter,
1792a58b312SMartin Matuska 	    increment_counter, flags, flags_start, flags_end, out);
1802a58b312SMartin Matuska 	kfpu_end();
1812a58b312SMartin Matuska }
1822a58b312SMartin Matuska 
blake3_is_avx2_supported(void)1832a58b312SMartin Matuska static boolean_t blake3_is_avx2_supported(void)
1842a58b312SMartin Matuska {
1852a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_sse4_1_available() &&
1862a58b312SMartin Matuska 	    zfs_avx2_available());
1872a58b312SMartin Matuska }
1882a58b312SMartin Matuska 
1892a58b312SMartin Matuska const blake3_ops_t
1902a58b312SMartin Matuska blake3_avx2_impl = {
1912a58b312SMartin Matuska 	.compress_in_place = blake3_compress_in_place_sse41,
1922a58b312SMartin Matuska 	.compress_xof = blake3_compress_xof_sse41,
1932a58b312SMartin Matuska 	.hash_many = blake3_hash_many_avx2,
1942a58b312SMartin Matuska 	.is_supported = blake3_is_avx2_supported,
1952a58b312SMartin Matuska 	.degree = 8,
1962a58b312SMartin Matuska 	.name = "avx2"
1972a58b312SMartin Matuska };
1982a58b312SMartin Matuska #endif
1992a58b312SMartin Matuska 
2002a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX512F) && defined(HAVE_AVX512VL)
2012a58b312SMartin Matuska extern void ASMABI zfs_blake3_compress_in_place_avx512(uint32_t cv[8],
2022a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
2032a58b312SMartin Matuska     uint64_t counter, uint8_t flags);
2042a58b312SMartin Matuska 
2052a58b312SMartin Matuska extern void ASMABI zfs_blake3_compress_xof_avx512(const uint32_t cv[8],
2062a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
2072a58b312SMartin Matuska     uint64_t counter, uint8_t flags, uint8_t out[64]);
2082a58b312SMartin Matuska 
2092a58b312SMartin Matuska extern void ASMABI zfs_blake3_hash_many_avx512(const uint8_t * const *inputs,
2102a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
2112a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
2122a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out);
2132a58b312SMartin Matuska 
blake3_compress_in_place_avx512(uint32_t cv[8],const uint8_t block[BLAKE3_BLOCK_LEN],uint8_t block_len,uint64_t counter,uint8_t flags)2142a58b312SMartin Matuska static void blake3_compress_in_place_avx512(uint32_t cv[8],
2152a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
2162a58b312SMartin Matuska     uint64_t counter, uint8_t flags) {
2172a58b312SMartin Matuska 	kfpu_begin();
2182a58b312SMartin Matuska 	zfs_blake3_compress_in_place_avx512(cv, block, block_len, counter,
2192a58b312SMartin Matuska 	    flags);
2202a58b312SMartin Matuska 	kfpu_end();
2212a58b312SMartin Matuska }
2222a58b312SMartin Matuska 
blake3_compress_xof_avx512(const uint32_t cv[8],const uint8_t block[BLAKE3_BLOCK_LEN],uint8_t block_len,uint64_t counter,uint8_t flags,uint8_t out[64])2232a58b312SMartin Matuska static void blake3_compress_xof_avx512(const uint32_t cv[8],
2242a58b312SMartin Matuska     const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len,
2252a58b312SMartin Matuska     uint64_t counter, uint8_t flags, uint8_t out[64]) {
2262a58b312SMartin Matuska 	kfpu_begin();
2272a58b312SMartin Matuska 	zfs_blake3_compress_xof_avx512(cv, block, block_len, counter, flags,
2282a58b312SMartin Matuska 	    out);
2292a58b312SMartin Matuska 	kfpu_end();
2302a58b312SMartin Matuska }
2312a58b312SMartin Matuska 
blake3_hash_many_avx512(const uint8_t * const * inputs,size_t num_inputs,size_t blocks,const uint32_t key[8],uint64_t counter,boolean_t increment_counter,uint8_t flags,uint8_t flags_start,uint8_t flags_end,uint8_t * out)2322a58b312SMartin Matuska static void blake3_hash_many_avx512(const uint8_t * const *inputs,
2332a58b312SMartin Matuska     size_t num_inputs, size_t blocks, const uint32_t key[8],
2342a58b312SMartin Matuska     uint64_t counter, boolean_t increment_counter, uint8_t flags,
2352a58b312SMartin Matuska     uint8_t flags_start, uint8_t flags_end, uint8_t *out) {
2362a58b312SMartin Matuska 	kfpu_begin();
2372a58b312SMartin Matuska 	zfs_blake3_hash_many_avx512(inputs, num_inputs, blocks, key, counter,
2382a58b312SMartin Matuska 	    increment_counter, flags, flags_start, flags_end, out);
2392a58b312SMartin Matuska 	kfpu_end();
2402a58b312SMartin Matuska }
2412a58b312SMartin Matuska 
blake3_is_avx512_supported(void)2422a58b312SMartin Matuska static boolean_t blake3_is_avx512_supported(void)
2432a58b312SMartin Matuska {
2442a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_avx512f_available() &&
2452a58b312SMartin Matuska 	    zfs_avx512vl_available());
2462a58b312SMartin Matuska }
2472a58b312SMartin Matuska 
2482a58b312SMartin Matuska const blake3_ops_t blake3_avx512_impl = {
2492a58b312SMartin Matuska 	.compress_in_place = blake3_compress_in_place_avx512,
2502a58b312SMartin Matuska 	.compress_xof = blake3_compress_xof_avx512,
2512a58b312SMartin Matuska 	.hash_many = blake3_hash_many_avx512,
2522a58b312SMartin Matuska 	.is_supported = blake3_is_avx512_supported,
2532a58b312SMartin Matuska 	.degree = 16,
2542a58b312SMartin Matuska 	.name = "avx512"
2552a58b312SMartin Matuska };
2562a58b312SMartin Matuska #endif
2572a58b312SMartin Matuska 
2582a58b312SMartin Matuska extern const blake3_ops_t blake3_generic_impl;
2592a58b312SMartin Matuska 
260c7046f76SMartin Matuska static const blake3_ops_t *const blake3_impls[] = {
2611f1e2261SMartin Matuska 	&blake3_generic_impl,
2626c8358cdSWarner Losh #ifdef USE_SIMD
2631f1e2261SMartin Matuska #if defined(__aarch64__) || \
2641f1e2261SMartin Matuska 	(defined(__x86_64) && defined(HAVE_SSE2)) || \
2651f1e2261SMartin Matuska 	(defined(__PPC64__) && defined(__LITTLE_ENDIAN__))
2661f1e2261SMartin Matuska 	&blake3_sse2_impl,
2671f1e2261SMartin Matuska #endif
2681f1e2261SMartin Matuska #if defined(__aarch64__) || \
2691f1e2261SMartin Matuska 	(defined(__x86_64) && defined(HAVE_SSE4_1)) || \
2701f1e2261SMartin Matuska 	(defined(__PPC64__) && defined(__LITTLE_ENDIAN__))
2711f1e2261SMartin Matuska 	&blake3_sse41_impl,
2721f1e2261SMartin Matuska #endif
2731f1e2261SMartin Matuska #if defined(__x86_64) && defined(HAVE_SSE4_1) && defined(HAVE_AVX2)
2741f1e2261SMartin Matuska 	&blake3_avx2_impl,
2751f1e2261SMartin Matuska #endif
2761f1e2261SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX512F) && defined(HAVE_AVX512VL)
2771f1e2261SMartin Matuska 	&blake3_avx512_impl,
2781f1e2261SMartin Matuska #endif
2796c8358cdSWarner Losh #endif
2801f1e2261SMartin Matuska };
2811f1e2261SMartin Matuska 
2822a58b312SMartin Matuska /* use the generic implementation functions */
2832a58b312SMartin Matuska #define	IMPL_NAME		"blake3"
2842a58b312SMartin Matuska #define	IMPL_OPS_T		blake3_ops_t
2852a58b312SMartin Matuska #define	IMPL_ARRAY		blake3_impls
2862a58b312SMartin Matuska #define	IMPL_GET_OPS		blake3_get_ops
2872a58b312SMartin Matuska #define	ZFS_IMPL_OPS		zfs_blake3_ops
2882a58b312SMartin Matuska #include <generic_impl.c>
2891f1e2261SMartin Matuska 
2902a58b312SMartin Matuska #ifdef _KERNEL
2911f1e2261SMartin Matuska void **blake3_per_cpu_ctx;
2921f1e2261SMartin Matuska 
2931f1e2261SMartin Matuska void
blake3_per_cpu_ctx_init(void)2941f1e2261SMartin Matuska blake3_per_cpu_ctx_init(void)
2951f1e2261SMartin Matuska {
2961f1e2261SMartin Matuska 	/*
2971f1e2261SMartin Matuska 	 * Create "The Godfather" ptr to hold all blake3 ctx
2981f1e2261SMartin Matuska 	 */
2991f1e2261SMartin Matuska 	blake3_per_cpu_ctx = kmem_alloc(max_ncpus * sizeof (void *), KM_SLEEP);
3001f1e2261SMartin Matuska 	for (int i = 0; i < max_ncpus; i++) {
3011f1e2261SMartin Matuska 		blake3_per_cpu_ctx[i] = kmem_alloc(sizeof (BLAKE3_CTX),
3021f1e2261SMartin Matuska 		    KM_SLEEP);
3031f1e2261SMartin Matuska 	}
3041f1e2261SMartin Matuska }
3051f1e2261SMartin Matuska 
3061f1e2261SMartin Matuska void
blake3_per_cpu_ctx_fini(void)3071f1e2261SMartin Matuska blake3_per_cpu_ctx_fini(void)
3081f1e2261SMartin Matuska {
3091f1e2261SMartin Matuska 	for (int i = 0; i < max_ncpus; i++) {
3101f1e2261SMartin Matuska 		memset(blake3_per_cpu_ctx[i], 0, sizeof (BLAKE3_CTX));
3111f1e2261SMartin Matuska 		kmem_free(blake3_per_cpu_ctx[i], sizeof (BLAKE3_CTX));
3121f1e2261SMartin Matuska 	}
3131f1e2261SMartin Matuska 	memset(blake3_per_cpu_ctx, 0, max_ncpus * sizeof (void *));
3141f1e2261SMartin Matuska 	kmem_free(blake3_per_cpu_ctx, max_ncpus * sizeof (void *));
3151f1e2261SMartin Matuska }
3161f1e2261SMartin Matuska 
317c7046f76SMartin Matuska #define	IMPL_FMT(impl, i)	(((impl) == (i)) ? "[%s] " : "%s ")
3181f1e2261SMartin Matuska 
319c7046f76SMartin Matuska #if defined(__linux__)
3201f1e2261SMartin Matuska 
3211f1e2261SMartin Matuska static int
blake3_param_get(char * buffer,zfs_kernel_param_t * unused)322c7046f76SMartin Matuska blake3_param_get(char *buffer, zfs_kernel_param_t *unused)
3231f1e2261SMartin Matuska {
3242a58b312SMartin Matuska 	const uint32_t impl = IMPL_READ(generic_impl_chosen);
3251f1e2261SMartin Matuska 	char *fmt;
326c7046f76SMartin Matuska 	int cnt = 0;
3271f1e2261SMartin Matuska 
3281f1e2261SMartin Matuska 	/* cycling */
329c7046f76SMartin Matuska 	fmt = IMPL_FMT(impl, IMPL_CYCLE);
330bb2d13b6SMartin Matuska 	cnt += kmem_scnprintf(buffer + cnt, PAGE_SIZE - cnt, fmt, "cycle");
3311f1e2261SMartin Matuska 
332c7046f76SMartin Matuska 	/* list fastest */
333c7046f76SMartin Matuska 	fmt = IMPL_FMT(impl, IMPL_FASTEST);
334bb2d13b6SMartin Matuska 	cnt += kmem_scnprintf(buffer + cnt, PAGE_SIZE - cnt, fmt, "fastest");
3351f1e2261SMartin Matuska 
336c7046f76SMartin Matuska 	/* list all supported implementations */
3372a58b312SMartin Matuska 	generic_impl_init();
3382a58b312SMartin Matuska 	for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
339c7046f76SMartin Matuska 		fmt = IMPL_FMT(impl, i);
340bb2d13b6SMartin Matuska 		cnt += kmem_scnprintf(buffer + cnt, PAGE_SIZE - cnt, fmt,
3412a58b312SMartin Matuska 		    blake3_impls[i]->name);
3421f1e2261SMartin Matuska 	}
3431f1e2261SMartin Matuska 
3441f1e2261SMartin Matuska 	return (cnt);
3451f1e2261SMartin Matuska }
3461f1e2261SMartin Matuska 
347c7046f76SMartin Matuska static int
blake3_param_set(const char * val,zfs_kernel_param_t * unused)348c7046f76SMartin Matuska blake3_param_set(const char *val, zfs_kernel_param_t *unused)
349c7046f76SMartin Matuska {
350c7046f76SMartin Matuska 	(void) unused;
3512a58b312SMartin Matuska 	return (generic_impl_setname(val));
352c7046f76SMartin Matuska }
353c7046f76SMartin Matuska 
354c7046f76SMartin Matuska #elif defined(__FreeBSD__)
355c7046f76SMartin Matuska 
356c7046f76SMartin Matuska #include <sys/sbuf.h>
357c7046f76SMartin Matuska 
358c7046f76SMartin Matuska static int
blake3_param(ZFS_MODULE_PARAM_ARGS)359c7046f76SMartin Matuska blake3_param(ZFS_MODULE_PARAM_ARGS)
360c7046f76SMartin Matuska {
361c7046f76SMartin Matuska 	int err;
362c7046f76SMartin Matuska 
3632a58b312SMartin Matuska 	generic_impl_init();
364c7046f76SMartin Matuska 	if (req->newptr == NULL) {
3652a58b312SMartin Matuska 		const uint32_t impl = IMPL_READ(generic_impl_chosen);
366c7046f76SMartin Matuska 		const int init_buflen = 64;
367c7046f76SMartin Matuska 		const char *fmt;
368c7046f76SMartin Matuska 		struct sbuf *s;
369c7046f76SMartin Matuska 
370c7046f76SMartin Matuska 		s = sbuf_new_for_sysctl(NULL, NULL, init_buflen, req);
371c7046f76SMartin Matuska 
372c7046f76SMartin Matuska 		/* cycling */
373c7046f76SMartin Matuska 		fmt = IMPL_FMT(impl, IMPL_CYCLE);
374c7046f76SMartin Matuska 		(void) sbuf_printf(s, fmt, "cycle");
375c7046f76SMartin Matuska 
376c7046f76SMartin Matuska 		/* list fastest */
377c7046f76SMartin Matuska 		fmt = IMPL_FMT(impl, IMPL_FASTEST);
378c7046f76SMartin Matuska 		(void) sbuf_printf(s, fmt, "fastest");
379c7046f76SMartin Matuska 
380c7046f76SMartin Matuska 		/* list all supported implementations */
3812a58b312SMartin Matuska 		for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
382c7046f76SMartin Matuska 			fmt = IMPL_FMT(impl, i);
3832a58b312SMartin Matuska 			(void) sbuf_printf(s, fmt, generic_supp_impls[i]->name);
384c7046f76SMartin Matuska 		}
385c7046f76SMartin Matuska 
386c7046f76SMartin Matuska 		err = sbuf_finish(s);
387c7046f76SMartin Matuska 		sbuf_delete(s);
388c7046f76SMartin Matuska 
389c7046f76SMartin Matuska 		return (err);
390c7046f76SMartin Matuska 	}
391c7046f76SMartin Matuska 
392c7046f76SMartin Matuska 	char buf[16];
393c7046f76SMartin Matuska 
394c7046f76SMartin Matuska 	err = sysctl_handle_string(oidp, buf, sizeof (buf), req);
395c7046f76SMartin Matuska 	if (err) {
396c7046f76SMartin Matuska 		return (err);
397c7046f76SMartin Matuska 	}
398c7046f76SMartin Matuska 
3992a58b312SMartin Matuska 	return (-generic_impl_setname(buf));
400c7046f76SMartin Matuska }
401c7046f76SMartin Matuska #endif
402c7046f76SMartin Matuska 
403c7046f76SMartin Matuska #undef IMPL_FMT
404c7046f76SMartin Matuska 
405c7046f76SMartin Matuska ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs, zfs_, blake3_impl,
406c7046f76SMartin Matuska     blake3_param_set, blake3_param_get, ZMOD_RW, \
407c7046f76SMartin Matuska 	"Select BLAKE3 implementation.");
4081f1e2261SMartin Matuska #endif
409