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