xref: /dpdk/drivers/crypto/scheduler/scheduler_pmd.c (revision 3998e2a07220844d3f3c17f76a781ced3efe0de0)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 #include <rte_common.h>
5 #include <rte_hexdump.h>
6 #include <rte_cryptodev.h>
7 #include <rte_cryptodev_pmd.h>
8 #include <rte_bus_vdev.h>
9 #include <rte_malloc.h>
10 #include <rte_cpuflags.h>
11 #include <rte_reorder.h>
12 
13 #include "rte_cryptodev_scheduler.h"
14 #include "scheduler_pmd_private.h"
15 
16 uint8_t cryptodev_driver_id;
17 
18 struct scheduler_init_params {
19 	struct rte_cryptodev_pmd_init_params def_p;
20 	uint32_t nb_slaves;
21 	enum rte_cryptodev_scheduler_mode mode;
22 	uint32_t enable_ordering;
23 	uint64_t wcmask;
24 	char slave_names[RTE_CRYPTODEV_SCHEDULER_MAX_NB_SLAVES]
25 			[RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN];
26 };
27 
28 #define RTE_CRYPTODEV_VDEV_NAME			("name")
29 #define RTE_CRYPTODEV_VDEV_SLAVE		("slave")
30 #define RTE_CRYPTODEV_VDEV_MODE			("mode")
31 #define RTE_CRYPTODEV_VDEV_ORDERING		("ordering")
32 #define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG	("max_nb_queue_pairs")
33 #define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG	("max_nb_sessions")
34 #define RTE_CRYPTODEV_VDEV_SOCKET_ID		("socket_id")
35 #define RTE_CRYPTODEV_VDEV_COREMASK		("coremask")
36 #define RTE_CRYPTODEV_VDEV_CORELIST		("corelist")
37 
38 const char *scheduler_valid_params[] = {
39 	RTE_CRYPTODEV_VDEV_NAME,
40 	RTE_CRYPTODEV_VDEV_SLAVE,
41 	RTE_CRYPTODEV_VDEV_MODE,
42 	RTE_CRYPTODEV_VDEV_ORDERING,
43 	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
44 	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
45 	RTE_CRYPTODEV_VDEV_SOCKET_ID,
46 	RTE_CRYPTODEV_VDEV_COREMASK,
47 	RTE_CRYPTODEV_VDEV_CORELIST
48 };
49 
50 struct scheduler_parse_map {
51 	const char *name;
52 	uint32_t val;
53 };
54 
55 const struct scheduler_parse_map scheduler_mode_map[] = {
56 	{RTE_STR(SCHEDULER_MODE_NAME_ROUND_ROBIN),
57 			CDEV_SCHED_MODE_ROUNDROBIN},
58 	{RTE_STR(SCHEDULER_MODE_NAME_PKT_SIZE_DISTR),
59 			CDEV_SCHED_MODE_PKT_SIZE_DISTR},
60 	{RTE_STR(SCHEDULER_MODE_NAME_FAIL_OVER),
61 			CDEV_SCHED_MODE_FAILOVER},
62 	{RTE_STR(SCHEDULER_MODE_NAME_MULTI_CORE),
63 			CDEV_SCHED_MODE_MULTICORE}
64 };
65 
66 const struct scheduler_parse_map scheduler_ordering_map[] = {
67 		{"enable", 1},
68 		{"disable", 0}
69 };
70 
71 static int
72 cryptodev_scheduler_create(const char *name,
73 		struct rte_vdev_device *vdev,
74 		struct scheduler_init_params *init_params)
75 {
76 	struct rte_cryptodev *dev;
77 	struct scheduler_ctx *sched_ctx;
78 	uint32_t i;
79 	int ret;
80 
81 	dev = rte_cryptodev_pmd_create(name, &vdev->device,
82 			&init_params->def_p);
83 	if (dev == NULL) {
84 		CS_LOG_ERR("driver %s: failed to create cryptodev vdev",
85 			name);
86 		return -EFAULT;
87 	}
88 
89 	if (init_params->wcmask != 0)
90 		RTE_LOG(INFO, PMD, "  workers core mask = %"PRIx64"\n",
91 			init_params->wcmask);
92 
93 	dev->driver_id = cryptodev_driver_id;
94 	dev->dev_ops = rte_crypto_scheduler_pmd_ops;
95 
96 	sched_ctx = dev->data->dev_private;
97 	sched_ctx->max_nb_queue_pairs =
98 			init_params->def_p.max_nb_queue_pairs;
99 
100 	if (init_params->mode == CDEV_SCHED_MODE_MULTICORE) {
101 		uint16_t i;
102 
103 		sched_ctx->nb_wc = 0;
104 
105 		for (i = 0; i < RTE_CRYPTODEV_SCHEDULER_MAX_NB_WORKER_CORES; i++) {
106 			if (init_params->wcmask & (1ULL << i)) {
107 				sched_ctx->wc_pool[sched_ctx->nb_wc++] = i;
108 				RTE_LOG(INFO, PMD,
109 					"  Worker core[%u]=%u added\n",
110 					sched_ctx->nb_wc-1, i);
111 			}
112 		}
113 	}
114 
115 	if (init_params->mode > CDEV_SCHED_MODE_USERDEFINED &&
116 			init_params->mode < CDEV_SCHED_MODE_COUNT) {
117 		ret = rte_cryptodev_scheduler_mode_set(dev->data->dev_id,
118 			init_params->mode);
119 		if (ret < 0) {
120 			rte_cryptodev_pmd_release_device(dev);
121 			return ret;
122 		}
123 
124 		for (i = 0; i < RTE_DIM(scheduler_mode_map); i++) {
125 			if (scheduler_mode_map[i].val != sched_ctx->mode)
126 				continue;
127 
128 			RTE_LOG(INFO, PMD, "  Scheduling mode = %s\n",
129 					scheduler_mode_map[i].name);
130 			break;
131 		}
132 	}
133 
134 	sched_ctx->reordering_enabled = init_params->enable_ordering;
135 
136 	for (i = 0; i < RTE_DIM(scheduler_ordering_map); i++) {
137 		if (scheduler_ordering_map[i].val !=
138 				sched_ctx->reordering_enabled)
139 			continue;
140 
141 		RTE_LOG(INFO, PMD, "  Packet ordering = %s\n",
142 				scheduler_ordering_map[i].name);
143 
144 		break;
145 	}
146 
147 	for (i = 0; i < init_params->nb_slaves; i++) {
148 		sched_ctx->init_slave_names[sched_ctx->nb_init_slaves] =
149 			rte_zmalloc_socket(
150 				NULL,
151 				RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN, 0,
152 				SOCKET_ID_ANY);
153 
154 		if (!sched_ctx->init_slave_names[
155 				sched_ctx->nb_init_slaves]) {
156 			CS_LOG_ERR("driver %s: Insufficient memory",
157 					name);
158 			return -ENOMEM;
159 		}
160 
161 		strncpy(sched_ctx->init_slave_names[
162 					sched_ctx->nb_init_slaves],
163 				init_params->slave_names[i],
164 				RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN - 1);
165 
166 		sched_ctx->nb_init_slaves++;
167 	}
168 
169 	/*
170 	 * Initialize capabilities structure as an empty structure,
171 	 * in case device information is requested when no slaves are attached
172 	 */
173 	sched_ctx->capabilities = rte_zmalloc_socket(NULL,
174 			sizeof(struct rte_cryptodev_capabilities),
175 			0, SOCKET_ID_ANY);
176 
177 	if (!sched_ctx->capabilities) {
178 		RTE_LOG(ERR, PMD, "Not enough memory for capability "
179 				"information\n");
180 		return -ENOMEM;
181 	}
182 
183 	return 0;
184 }
185 
186 static int
187 cryptodev_scheduler_remove(struct rte_vdev_device *vdev)
188 {
189 	const char *name;
190 	struct rte_cryptodev *dev;
191 	struct scheduler_ctx *sched_ctx;
192 
193 	if (vdev == NULL)
194 		return -EINVAL;
195 
196 	name = rte_vdev_device_name(vdev);
197 	dev = rte_cryptodev_pmd_get_named_dev(name);
198 	if (dev == NULL)
199 		return -EINVAL;
200 
201 	sched_ctx = dev->data->dev_private;
202 
203 	if (sched_ctx->nb_slaves) {
204 		uint32_t i;
205 
206 		for (i = 0; i < sched_ctx->nb_slaves; i++)
207 			rte_cryptodev_scheduler_slave_detach(dev->data->dev_id,
208 					sched_ctx->slaves[i].dev_id);
209 	}
210 
211 	return rte_cryptodev_pmd_destroy(dev);
212 }
213 
214 /** Parse integer from integer argument */
215 static int
216 parse_integer_arg(const char *key __rte_unused,
217 		const char *value, void *extra_args)
218 {
219 	int *i = (int *) extra_args;
220 
221 	*i = atoi(value);
222 	if (*i < 0) {
223 		CS_LOG_ERR("Argument has to be positive.\n");
224 		return -EINVAL;
225 	}
226 
227 	return 0;
228 }
229 
230 /** Parse integer from hexadecimal integer argument */
231 static int
232 parse_coremask_arg(const char *key __rte_unused,
233 		const char *value, void *extra_args)
234 {
235 	struct scheduler_init_params *params = extra_args;
236 
237 	params->wcmask = strtoull(value, NULL, 16);
238 
239 	return 0;
240 }
241 
242 /** Parse integer from list of integers argument */
243 static int
244 parse_corelist_arg(const char *key __rte_unused,
245 		const char *value, void *extra_args)
246 {
247 	struct scheduler_init_params *params = extra_args;
248 
249 	params->wcmask = 0ULL;
250 
251 	const char *token = value;
252 
253 	while (isdigit(token[0])) {
254 		char *rval;
255 		unsigned int core = strtoul(token, &rval, 10);
256 
257 		params->wcmask |= 1ULL << core;
258 		token = (const char *)rval;
259 		if (token[0] == '\0')
260 			break;
261 		token++;
262 	}
263 
264 	return 0;
265 }
266 
267 /** Parse name */
268 static int
269 parse_name_arg(const char *key __rte_unused,
270 		const char *value, void *extra_args)
271 {
272 	struct rte_cryptodev_pmd_init_params *params = extra_args;
273 
274 	if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) {
275 		CS_LOG_ERR("Invalid name %s, should be less than "
276 				"%u bytes.\n", value,
277 				RTE_CRYPTODEV_NAME_MAX_LEN - 1);
278 		return -EINVAL;
279 	}
280 
281 	strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN);
282 
283 	return 0;
284 }
285 
286 /** Parse slave */
287 static int
288 parse_slave_arg(const char *key __rte_unused,
289 		const char *value, void *extra_args)
290 {
291 	struct scheduler_init_params *param = extra_args;
292 
293 	if (param->nb_slaves >= RTE_CRYPTODEV_SCHEDULER_MAX_NB_SLAVES) {
294 		CS_LOG_ERR("Too many slaves.\n");
295 		return -ENOMEM;
296 	}
297 
298 	strncpy(param->slave_names[param->nb_slaves++], value,
299 			RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN - 1);
300 
301 	return 0;
302 }
303 
304 static int
305 parse_mode_arg(const char *key __rte_unused,
306 		const char *value, void *extra_args)
307 {
308 	struct scheduler_init_params *param = extra_args;
309 	uint32_t i;
310 
311 	for (i = 0; i < RTE_DIM(scheduler_mode_map); i++) {
312 		if (strcmp(value, scheduler_mode_map[i].name) == 0) {
313 			param->mode = (enum rte_cryptodev_scheduler_mode)
314 					scheduler_mode_map[i].val;
315 			break;
316 		}
317 	}
318 
319 	if (i == RTE_DIM(scheduler_mode_map)) {
320 		CS_LOG_ERR("Unrecognized input.\n");
321 		return -EINVAL;
322 	}
323 
324 	return 0;
325 }
326 
327 static int
328 parse_ordering_arg(const char *key __rte_unused,
329 		const char *value, void *extra_args)
330 {
331 	struct scheduler_init_params *param = extra_args;
332 	uint32_t i;
333 
334 	for (i = 0; i < RTE_DIM(scheduler_ordering_map); i++) {
335 		if (strcmp(value, scheduler_ordering_map[i].name) == 0) {
336 			param->enable_ordering =
337 					scheduler_ordering_map[i].val;
338 			break;
339 		}
340 	}
341 
342 	if (i == RTE_DIM(scheduler_ordering_map)) {
343 		CS_LOG_ERR("Unrecognized input.\n");
344 		return -EINVAL;
345 	}
346 
347 	return 0;
348 }
349 
350 static int
351 scheduler_parse_init_params(struct scheduler_init_params *params,
352 		const char *input_args)
353 {
354 	struct rte_kvargs *kvlist = NULL;
355 	int ret = 0;
356 
357 	if (params == NULL)
358 		return -EINVAL;
359 
360 	if (input_args) {
361 		kvlist = rte_kvargs_parse(input_args,
362 				scheduler_valid_params);
363 		if (kvlist == NULL)
364 			return -1;
365 
366 		ret = rte_kvargs_process(kvlist,
367 				RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
368 				&parse_integer_arg,
369 				&params->def_p.max_nb_queue_pairs);
370 		if (ret < 0)
371 			goto free_kvlist;
372 
373 		ret = rte_kvargs_process(kvlist,
374 				RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
375 				&parse_integer_arg,
376 				&params->def_p.max_nb_sessions);
377 		if (ret < 0)
378 			goto free_kvlist;
379 
380 		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
381 				&parse_integer_arg,
382 				&params->def_p.socket_id);
383 		if (ret < 0)
384 			goto free_kvlist;
385 
386 		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_COREMASK,
387 				&parse_coremask_arg,
388 				params);
389 		if (ret < 0)
390 			goto free_kvlist;
391 
392 		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_CORELIST,
393 				&parse_corelist_arg,
394 				params);
395 		if (ret < 0)
396 			goto free_kvlist;
397 
398 		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_NAME,
399 				&parse_name_arg,
400 				&params->def_p);
401 		if (ret < 0)
402 			goto free_kvlist;
403 
404 		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SLAVE,
405 				&parse_slave_arg, params);
406 		if (ret < 0)
407 			goto free_kvlist;
408 
409 		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_MODE,
410 				&parse_mode_arg, params);
411 		if (ret < 0)
412 			goto free_kvlist;
413 
414 		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_ORDERING,
415 				&parse_ordering_arg, params);
416 		if (ret < 0)
417 			goto free_kvlist;
418 	}
419 
420 free_kvlist:
421 	rte_kvargs_free(kvlist);
422 	return ret;
423 }
424 
425 static int
426 cryptodev_scheduler_probe(struct rte_vdev_device *vdev)
427 {
428 	struct scheduler_init_params init_params = {
429 		.def_p = {
430 			"",
431 			sizeof(struct scheduler_ctx),
432 			rte_socket_id(),
433 			RTE_CRYPTODEV_PMD_DEFAULT_MAX_NB_QUEUE_PAIRS,
434 			RTE_CRYPTODEV_PMD_DEFAULT_MAX_NB_SESSIONS
435 		},
436 		.nb_slaves = 0,
437 		.mode = CDEV_SCHED_MODE_NOT_SET,
438 		.enable_ordering = 0,
439 		.slave_names = { {0} }
440 	};
441 	const char *name;
442 
443 	name = rte_vdev_device_name(vdev);
444 	if (name == NULL)
445 		return -EINVAL;
446 
447 	scheduler_parse_init_params(&init_params,
448 				    rte_vdev_device_args(vdev));
449 
450 
451 	return cryptodev_scheduler_create(name,
452 					vdev,
453 					&init_params);
454 }
455 
456 static struct rte_vdev_driver cryptodev_scheduler_pmd_drv = {
457 	.probe = cryptodev_scheduler_probe,
458 	.remove = cryptodev_scheduler_remove
459 };
460 
461 static struct cryptodev_driver scheduler_crypto_drv;
462 
463 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_SCHEDULER_PMD,
464 	cryptodev_scheduler_pmd_drv);
465 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_SCHEDULER_PMD,
466 	"max_nb_queue_pairs=<int> "
467 	"max_nb_sessions=<int> "
468 	"socket_id=<int> "
469 	"slave=<name>");
470 RTE_PMD_REGISTER_CRYPTO_DRIVER(scheduler_crypto_drv,
471 		cryptodev_scheduler_pmd_drv,
472 		cryptodev_driver_id);
473