xref: /freebsd-src/sys/contrib/openzfs/module/icp/include/generic_impl.c (revision 2a58b312b62f908ec92311d1bd8536dbaeb8e55b)
1*2a58b312SMartin Matuska /*
2*2a58b312SMartin Matuska  * CDDL HEADER START
3*2a58b312SMartin Matuska  *
4*2a58b312SMartin Matuska  * The contents of this file are subject to the terms of the
5*2a58b312SMartin Matuska  * Common Development and Distribution License (the "License").
6*2a58b312SMartin Matuska  * You may not use this file except in compliance with the License.
7*2a58b312SMartin Matuska  *
8*2a58b312SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2a58b312SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10*2a58b312SMartin Matuska  * See the License for the specific language governing permissions
11*2a58b312SMartin Matuska  * and limitations under the License.
12*2a58b312SMartin Matuska  *
13*2a58b312SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14*2a58b312SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2a58b312SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16*2a58b312SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17*2a58b312SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2a58b312SMartin Matuska  *
19*2a58b312SMartin Matuska  * CDDL HEADER END
20*2a58b312SMartin Matuska  */
21*2a58b312SMartin Matuska 
22*2a58b312SMartin Matuska /*
23*2a58b312SMartin Matuska  * Copyright (c) 2003, 2010 Oracle and/or its affiliates.
24*2a58b312SMartin Matuska  * Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
25*2a58b312SMartin Matuska  */
26*2a58b312SMartin Matuska 
27*2a58b312SMartin Matuska /*
28*2a58b312SMartin Matuska  * This file gets included by c files for implementing the full set
29*2a58b312SMartin Matuska  * of zfs_impl.h defines.
30*2a58b312SMartin Matuska  *
31*2a58b312SMartin Matuska  * It's ment for easier maintaining multiple implementations of
32*2a58b312SMartin Matuska  * algorithms. Look into blake3_impl.c, sha256_impl.c or sha512_impl.c
33*2a58b312SMartin Matuska  * for reference.
34*2a58b312SMartin Matuska  */
35*2a58b312SMartin Matuska 
36*2a58b312SMartin Matuska #include <sys/zfs_context.h>
37*2a58b312SMartin Matuska #include <sys/zio_checksum.h>
38*2a58b312SMartin Matuska #include <sys/zfs_impl.h>
39*2a58b312SMartin Matuska 
40*2a58b312SMartin Matuska /* Two default implementations */
41*2a58b312SMartin Matuska #define	IMPL_FASTEST	(UINT32_MAX)
42*2a58b312SMartin Matuska #define	IMPL_CYCLE	(UINT32_MAX - 1)
43*2a58b312SMartin Matuska 
44*2a58b312SMartin Matuska #define	IMPL_READ(i)	(*(volatile uint32_t *) &(i))
45*2a58b312SMartin Matuska 
46*2a58b312SMartin Matuska /* Implementation that contains the fastest method */
47*2a58b312SMartin Matuska static IMPL_OPS_T generic_fastest_impl = {
48*2a58b312SMartin Matuska 	.name = "fastest"
49*2a58b312SMartin Matuska };
50*2a58b312SMartin Matuska 
51*2a58b312SMartin Matuska /* Hold all supported implementations */
52*2a58b312SMartin Matuska static const IMPL_OPS_T *generic_supp_impls[ARRAY_SIZE(IMPL_ARRAY)];
53*2a58b312SMartin Matuska static uint32_t generic_supp_impls_cnt = 0;
54*2a58b312SMartin Matuska 
55*2a58b312SMartin Matuska /* Currently selected implementation */
56*2a58b312SMartin Matuska static uint32_t generic_impl_chosen = IMPL_FASTEST;
57*2a58b312SMartin Matuska 
58*2a58b312SMartin Matuska static struct generic_impl_selector {
59*2a58b312SMartin Matuska 	const char *name;
60*2a58b312SMartin Matuska 	uint32_t sel;
61*2a58b312SMartin Matuska } generic_impl_selectors[] = {
62*2a58b312SMartin Matuska 	{ "cycle",	IMPL_CYCLE },
63*2a58b312SMartin Matuska 	{ "fastest",	IMPL_FASTEST }
64*2a58b312SMartin Matuska };
65*2a58b312SMartin Matuska 
66*2a58b312SMartin Matuska /* check the supported implementations */
67*2a58b312SMartin Matuska static void
generic_impl_init(void)68*2a58b312SMartin Matuska generic_impl_init(void)
69*2a58b312SMartin Matuska {
70*2a58b312SMartin Matuska 	int i, c;
71*2a58b312SMartin Matuska 
72*2a58b312SMartin Matuska 	/* init only once */
73*2a58b312SMartin Matuska 	if (likely(generic_supp_impls_cnt != 0))
74*2a58b312SMartin Matuska 		return;
75*2a58b312SMartin Matuska 
76*2a58b312SMartin Matuska 	/* Move supported implementations into generic_supp_impls */
77*2a58b312SMartin Matuska 	for (i = 0, c = 0; i < ARRAY_SIZE(IMPL_ARRAY); i++) {
78*2a58b312SMartin Matuska 		const IMPL_OPS_T *impl = IMPL_ARRAY[i];
79*2a58b312SMartin Matuska 
80*2a58b312SMartin Matuska 		if (impl->is_supported && impl->is_supported())
81*2a58b312SMartin Matuska 			generic_supp_impls[c++] = impl;
82*2a58b312SMartin Matuska 	}
83*2a58b312SMartin Matuska 	generic_supp_impls_cnt = c;
84*2a58b312SMartin Matuska 
85*2a58b312SMartin Matuska 	/* first init generic impl, may be changed via set_fastest() */
86*2a58b312SMartin Matuska 	memcpy(&generic_fastest_impl, generic_supp_impls[0],
87*2a58b312SMartin Matuska 	    sizeof (generic_fastest_impl));
88*2a58b312SMartin Matuska }
89*2a58b312SMartin Matuska 
90*2a58b312SMartin Matuska /* get number of supported implementations */
91*2a58b312SMartin Matuska static uint32_t
generic_impl_getcnt(void)92*2a58b312SMartin Matuska generic_impl_getcnt(void)
93*2a58b312SMartin Matuska {
94*2a58b312SMartin Matuska 	generic_impl_init();
95*2a58b312SMartin Matuska 	return (generic_supp_impls_cnt);
96*2a58b312SMartin Matuska }
97*2a58b312SMartin Matuska 
98*2a58b312SMartin Matuska /* get id of selected implementation */
99*2a58b312SMartin Matuska static uint32_t
generic_impl_getid(void)100*2a58b312SMartin Matuska generic_impl_getid(void)
101*2a58b312SMartin Matuska {
102*2a58b312SMartin Matuska 	generic_impl_init();
103*2a58b312SMartin Matuska 	return (IMPL_READ(generic_impl_chosen));
104*2a58b312SMartin Matuska }
105*2a58b312SMartin Matuska 
106*2a58b312SMartin Matuska /* get name of selected implementation */
107*2a58b312SMartin Matuska static const char *
generic_impl_getname(void)108*2a58b312SMartin Matuska generic_impl_getname(void)
109*2a58b312SMartin Matuska {
110*2a58b312SMartin Matuska 	uint32_t impl = IMPL_READ(generic_impl_chosen);
111*2a58b312SMartin Matuska 
112*2a58b312SMartin Matuska 	generic_impl_init();
113*2a58b312SMartin Matuska 	switch (impl) {
114*2a58b312SMartin Matuska 	case IMPL_FASTEST:
115*2a58b312SMartin Matuska 		return ("fastest");
116*2a58b312SMartin Matuska 	case IMPL_CYCLE:
117*2a58b312SMartin Matuska 		return ("cycle");
118*2a58b312SMartin Matuska 	default:
119*2a58b312SMartin Matuska 		return (generic_supp_impls[impl]->name);
120*2a58b312SMartin Matuska 	}
121*2a58b312SMartin Matuska }
122*2a58b312SMartin Matuska 
123*2a58b312SMartin Matuska /* set implementation by id */
124*2a58b312SMartin Matuska static void
generic_impl_setid(uint32_t id)125*2a58b312SMartin Matuska generic_impl_setid(uint32_t id)
126*2a58b312SMartin Matuska {
127*2a58b312SMartin Matuska 	generic_impl_init();
128*2a58b312SMartin Matuska 	switch (id) {
129*2a58b312SMartin Matuska 	case IMPL_FASTEST:
130*2a58b312SMartin Matuska 		atomic_swap_32(&generic_impl_chosen, IMPL_FASTEST);
131*2a58b312SMartin Matuska 		break;
132*2a58b312SMartin Matuska 	case IMPL_CYCLE:
133*2a58b312SMartin Matuska 		atomic_swap_32(&generic_impl_chosen, IMPL_CYCLE);
134*2a58b312SMartin Matuska 		break;
135*2a58b312SMartin Matuska 	default:
136*2a58b312SMartin Matuska 		ASSERT3U(id, <, generic_supp_impls_cnt);
137*2a58b312SMartin Matuska 		atomic_swap_32(&generic_impl_chosen, id);
138*2a58b312SMartin Matuska 		break;
139*2a58b312SMartin Matuska 	}
140*2a58b312SMartin Matuska }
141*2a58b312SMartin Matuska 
142*2a58b312SMartin Matuska /* set implementation by name */
143*2a58b312SMartin Matuska static int
generic_impl_setname(const char * val)144*2a58b312SMartin Matuska generic_impl_setname(const char *val)
145*2a58b312SMartin Matuska {
146*2a58b312SMartin Matuska 	uint32_t impl = IMPL_READ(generic_impl_chosen);
147*2a58b312SMartin Matuska 	size_t val_len;
148*2a58b312SMartin Matuska 	int i, err = -EINVAL;
149*2a58b312SMartin Matuska 
150*2a58b312SMartin Matuska 	generic_impl_init();
151*2a58b312SMartin Matuska 	val_len = strlen(val);
152*2a58b312SMartin Matuska 	while ((val_len > 0) && !!isspace(val[val_len-1])) /* trim '\n' */
153*2a58b312SMartin Matuska 		val_len--;
154*2a58b312SMartin Matuska 
155*2a58b312SMartin Matuska 	/* check mandatory implementations */
156*2a58b312SMartin Matuska 	for (i = 0; i < ARRAY_SIZE(generic_impl_selectors); i++) {
157*2a58b312SMartin Matuska 		const char *name = generic_impl_selectors[i].name;
158*2a58b312SMartin Matuska 
159*2a58b312SMartin Matuska 		if (val_len == strlen(name) &&
160*2a58b312SMartin Matuska 		    strncmp(val, name, val_len) == 0) {
161*2a58b312SMartin Matuska 			impl = generic_impl_selectors[i].sel;
162*2a58b312SMartin Matuska 			err = 0;
163*2a58b312SMartin Matuska 			break;
164*2a58b312SMartin Matuska 		}
165*2a58b312SMartin Matuska 	}
166*2a58b312SMartin Matuska 
167*2a58b312SMartin Matuska 	/* check all supported implementations */
168*2a58b312SMartin Matuska 	if (err != 0) {
169*2a58b312SMartin Matuska 		for (i = 0; i < generic_supp_impls_cnt; i++) {
170*2a58b312SMartin Matuska 			const char *name = generic_supp_impls[i]->name;
171*2a58b312SMartin Matuska 
172*2a58b312SMartin Matuska 			if (val_len == strlen(name) &&
173*2a58b312SMartin Matuska 			    strncmp(val, name, val_len) == 0) {
174*2a58b312SMartin Matuska 				impl = i;
175*2a58b312SMartin Matuska 				err = 0;
176*2a58b312SMartin Matuska 				break;
177*2a58b312SMartin Matuska 			}
178*2a58b312SMartin Matuska 		}
179*2a58b312SMartin Matuska 	}
180*2a58b312SMartin Matuska 
181*2a58b312SMartin Matuska 	if (err == 0) {
182*2a58b312SMartin Matuska 		atomic_swap_32(&generic_impl_chosen, impl);
183*2a58b312SMartin Matuska 	}
184*2a58b312SMartin Matuska 
185*2a58b312SMartin Matuska 	return (err);
186*2a58b312SMartin Matuska }
187*2a58b312SMartin Matuska 
188*2a58b312SMartin Matuska /* setup id as fastest implementation */
189*2a58b312SMartin Matuska static void
generic_impl_set_fastest(uint32_t id)190*2a58b312SMartin Matuska generic_impl_set_fastest(uint32_t id)
191*2a58b312SMartin Matuska {
192*2a58b312SMartin Matuska 	generic_impl_init();
193*2a58b312SMartin Matuska 	memcpy(&generic_fastest_impl, generic_supp_impls[id],
194*2a58b312SMartin Matuska 	    sizeof (generic_fastest_impl));
195*2a58b312SMartin Matuska }
196*2a58b312SMartin Matuska 
197*2a58b312SMartin Matuska /* return impl iterating functions */
198*2a58b312SMartin Matuska const zfs_impl_t ZFS_IMPL_OPS = {
199*2a58b312SMartin Matuska 	.name = IMPL_NAME,
200*2a58b312SMartin Matuska 	.getcnt = generic_impl_getcnt,
201*2a58b312SMartin Matuska 	.getid = generic_impl_getid,
202*2a58b312SMartin Matuska 	.getname = generic_impl_getname,
203*2a58b312SMartin Matuska 	.set_fastest = generic_impl_set_fastest,
204*2a58b312SMartin Matuska 	.setid = generic_impl_setid,
205*2a58b312SMartin Matuska 	.setname = generic_impl_setname
206*2a58b312SMartin Matuska };
207*2a58b312SMartin Matuska 
208*2a58b312SMartin Matuska /* get impl ops_t of selected implementation */
209*2a58b312SMartin Matuska const IMPL_OPS_T *
IMPL_GET_OPS(void)210*2a58b312SMartin Matuska IMPL_GET_OPS(void)
211*2a58b312SMartin Matuska {
212*2a58b312SMartin Matuska 	const IMPL_OPS_T *ops = NULL;
213*2a58b312SMartin Matuska 	uint32_t idx, impl = IMPL_READ(generic_impl_chosen);
214*2a58b312SMartin Matuska 	static uint32_t cycle_count = 0;
215*2a58b312SMartin Matuska 
216*2a58b312SMartin Matuska 	generic_impl_init();
217*2a58b312SMartin Matuska 	switch (impl) {
218*2a58b312SMartin Matuska 	case IMPL_FASTEST:
219*2a58b312SMartin Matuska 		ops = &generic_fastest_impl;
220*2a58b312SMartin Matuska 		break;
221*2a58b312SMartin Matuska 	case IMPL_CYCLE:
222*2a58b312SMartin Matuska 		idx = (++cycle_count) % generic_supp_impls_cnt;
223*2a58b312SMartin Matuska 		ops = generic_supp_impls[idx];
224*2a58b312SMartin Matuska 		break;
225*2a58b312SMartin Matuska 	default:
226*2a58b312SMartin Matuska 		ASSERT3U(impl, <, generic_supp_impls_cnt);
227*2a58b312SMartin Matuska 		ops = generic_supp_impls[impl];
228*2a58b312SMartin Matuska 		break;
229*2a58b312SMartin Matuska 	}
230*2a58b312SMartin Matuska 
231*2a58b312SMartin Matuska 	ASSERT3P(ops, !=, NULL);
232*2a58b312SMartin Matuska 	return (ops);
233*2a58b312SMartin Matuska }
234