xref: /spdk/module/accel/dpdk_cryptodev/accel_dpdk_cryptodev.c (revision 0e483b98b40381b3258d9b9c1067224f7065382e)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2018 Intel Corporation.
3  *   Copyright (c) 2022, 2023 NVIDIA CORPORATION & AFFILIATES.
4  *   All rights reserved.
5  */
6 
7 #include "accel_dpdk_cryptodev.h"
8 
9 #include "spdk/accel.h"
10 #include "spdk/accel_module.h"
11 #include "spdk/env.h"
12 #include "spdk/likely.h"
13 #include "spdk/thread.h"
14 #include "spdk/util.h"
15 #include "spdk/log.h"
16 #include "spdk/json.h"
17 #include "spdk_internal/sgl.h"
18 
19 #include <rte_bus_vdev.h>
20 #include <rte_crypto.h>
21 #include <rte_cryptodev.h>
22 #include <rte_mbuf_dyn.h>
23 #include <rte_version.h>
24 
25 /* The VF spread is the number of queue pairs between virtual functions, we use this to
26  * load balance the QAT device.
27  */
28 #define ACCEL_DPDK_CRYPTODEV_QAT_VF_SPREAD		32
29 
30 /* This controls how many ops will be dequeued from the crypto driver in one run
31  * of the poller. It is mainly a performance knob as it effectively determines how
32  * much work the poller has to do.  However even that can vary between crypto drivers
33  * as the ACCEL_DPDK_CRYPTODEV_AESNI_MB driver for example does all the crypto work on dequeue whereas the
34  * QAT driver just dequeues what has been completed already.
35  */
36 #define ACCEL_DPDK_CRYPTODEV_MAX_DEQUEUE_BURST_SIZE	64
37 
38 #define ACCEL_DPDK_CRYPTODEV_MAX_ENQUEUE_ARRAY_SIZE (128)
39 
40 /* The number of MBUFS we need must be a power of two and to support other small IOs
41  * in addition to the limits mentioned above, we go to the next power of two. It is
42  * big number because it is one mempool for source and destination mbufs. It may
43  * need to be bigger to support multiple crypto drivers at once.
44  */
45 #define ACCEL_DPDK_CRYPTODEV_NUM_MBUFS			32768
46 #define ACCEL_DPDK_CRYPTODEV_POOL_CACHE_SIZE		256
47 #define ACCEL_DPDK_CRYPTODEV_MAX_CRYPTO_VOLUMES		128
48 #define ACCEL_DPDK_CRYPTODEV_NUM_SESSIONS		(2 * ACCEL_DPDK_CRYPTODEV_MAX_CRYPTO_VOLUMES)
49 #define ACCEL_DPDK_CRYPTODEV_SESS_MEMPOOL_CACHE_SIZE	0
50 
51 /* This is the max number of IOs we can supply to any crypto device QP at one time.
52  * It can vary between drivers.
53  */
54 #define ACCEL_DPDK_CRYPTODEV_QP_DESCRIPTORS		2048
55 
56 /* At this moment DPDK descriptors allocation for mlx5 has some issues. We use 512
57  * as a compromise value between performance and the time spent for initialization. */
58 #define ACCEL_DPDK_CRYPTODEV_QP_DESCRIPTORS_MLX5	512
59 
60 #define ACCEL_DPDK_CRYPTODEV_AESNI_MB_NUM_QP		64
61 
62 /* Common for suported devices. */
63 #define ACCEL_DPDK_CRYPTODEV_DEFAULT_NUM_XFORMS		2
64 #define ACCEL_DPDK_CRYPTODEV_IV_OFFSET (sizeof(struct rte_crypto_op) + \
65                 sizeof(struct rte_crypto_sym_op) + \
66                 (ACCEL_DPDK_CRYPTODEV_DEFAULT_NUM_XFORMS * \
67                  sizeof(struct rte_crypto_sym_xform)))
68 #define ACCEL_DPDK_CRYPTODEV_IV_LENGTH			16
69 
70 /* Driver names */
71 #define ACCEL_DPDK_CRYPTODEV_AESNI_MB	"crypto_aesni_mb"
72 #define ACCEL_DPDK_CRYPTODEV_QAT	"crypto_qat"
73 #define ACCEL_DPDK_CRYPTODEV_QAT_ASYM	"crypto_qat_asym"
74 #define ACCEL_DPDK_CRYPTODEV_MLX5	"mlx5_pci"
75 
76 /* Supported ciphers */
77 #define ACCEL_DPDK_CRYPTODEV_AES_CBC	"AES_CBC" /* QAT and ACCEL_DPDK_CRYPTODEV_AESNI_MB */
78 #define ACCEL_DPDK_CRYPTODEV_AES_XTS	"AES_XTS" /* QAT and MLX5 */
79 
80 /* Specific to AES_CBC. */
81 #define ACCEL_DPDK_CRYPTODEV_AES_CBC_KEY_LENGTH			16
82 #define ACCEL_DPDK_CRYPTODEV_AES_XTS_128_BLOCK_KEY_LENGTH	16 /* AES-XTS-128 block key size. */
83 #define ACCEL_DPDK_CRYPTODEV_AES_XTS_256_BLOCK_KEY_LENGTH	32 /* AES-XTS-256 block key size. */
84 
85 /* Limit of the max memory len attached to mbuf - rte_pktmbuf_attach_extbuf has uint16_t `buf_len`
86  * parameter, we use closes aligned value 32768 for better performance */
87 #define ACCEL_DPDK_CRYPTODEV_MAX_MBUF_LEN			32768
88 
89 /* Used to store IO context in mbuf */
90 static const struct rte_mbuf_dynfield rte_mbuf_dynfield_io_context = {
91 	.name = "context_accel_dpdk_cryptodev",
92 	.size = sizeof(uint64_t),
93 	.align = __alignof__(uint64_t),
94 	.flags = 0,
95 };
96 
97 struct accel_dpdk_cryptodev_device;
98 
99 enum accel_dpdk_cryptodev_driver_type {
100 	ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB = 0,
101 	ACCEL_DPDK_CRYPTODEV_DRIVER_QAT,
102 	ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI,
103 	ACCEL_DPDK_CRYPTODEV_DRIVER_LAST
104 };
105 
106 struct accel_dpdk_cryptodev_qp {
107 	struct accel_dpdk_cryptodev_device *device;	/* ptr to crypto device */
108 	uint32_t num_enqueued_ops;	/* Used to decide whether to poll the qp or not */
109 	uint8_t qp; /* queue identifier */
110 	bool in_use; /* whether this node is in use or not */
111 	uint8_t index; /* used by QAT to load balance placement of qpairs */
112 	TAILQ_ENTRY(accel_dpdk_cryptodev_qp) link;
113 };
114 
115 struct accel_dpdk_cryptodev_device {
116 	enum accel_dpdk_cryptodev_driver_type type;
117 	struct rte_cryptodev_info cdev_info; /* includes DPDK device friendly name */
118 	uint32_t qp_desc_nr; /* max number of qp descriptors to be enqueued in burst */
119 	uint8_t cdev_id; /* identifier for the device */
120 	TAILQ_HEAD(, accel_dpdk_cryptodev_qp) qpairs;
121 	TAILQ_ENTRY(accel_dpdk_cryptodev_device) link;
122 };
123 
124 struct accel_dpdk_cryptodev_key_handle {
125 	struct accel_dpdk_cryptodev_device *device;
126 	TAILQ_ENTRY(accel_dpdk_cryptodev_key_handle) link;
127 	void *session_encrypt;	/* encryption session for this key */
128 	void *session_decrypt;	/* decryption session for this key */
129 	struct rte_crypto_sym_xform cipher_xform;		/* crypto control struct for this key */
130 };
131 
132 struct accel_dpdk_cryptodev_key_priv {
133 	enum accel_dpdk_cryptodev_driver_type driver;
134 	enum spdk_accel_cipher cipher;
135 	char *xts_key;
136 	TAILQ_HEAD(, accel_dpdk_cryptodev_key_handle) dev_keys;
137 };
138 
139 /* The crypto channel struct. It is allocated and freed on my behalf by the io channel code.
140  * We store things in here that are needed on per thread basis like the base_channel for this thread,
141  * and the poller for this thread.
142  */
143 struct accel_dpdk_cryptodev_io_channel {
144 	/* completion poller */
145 	struct spdk_poller *poller;
146 	/* Array of qpairs for each available device. The specific device will be selected depending on the crypto key */
147 	struct accel_dpdk_cryptodev_qp *device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_LAST];
148 	/* Used to queue tasks when qpair is full or only part of crypto ops was submitted to the PMD */
149 	TAILQ_HEAD(, accel_dpdk_cryptodev_task) queued_tasks;
150 	/* Used to queue tasks that were completed in submission path - to avoid calling cpl_cb and possibly overflow
151 	 * call stack */
152 	TAILQ_HEAD(, accel_dpdk_cryptodev_task) completed_tasks;
153 };
154 
155 struct accel_dpdk_cryptodev_task {
156 	struct spdk_accel_task base;
157 	uint32_t cryop_completed;	/* The number of crypto operations completed by HW */
158 	uint32_t cryop_submitted;	/* The number of crypto operations submitted to HW */
159 	uint32_t cryop_total;		/* Total number of crypto operations in this task */
160 	bool is_failed;
161 	bool inplace;
162 	TAILQ_ENTRY(accel_dpdk_cryptodev_task) link;
163 };
164 
165 /* Shared mempools between all devices on this system */
166 static struct rte_mempool *g_session_mp = NULL;
167 static struct rte_mempool *g_session_mp_priv = NULL;
168 static struct rte_mempool *g_mbuf_mp = NULL;            /* mbuf mempool */
169 static int g_mbuf_offset;
170 static struct rte_mempool *g_crypto_op_mp = NULL;	/* crypto operations, must be rte* mempool */
171 
172 static struct rte_mbuf_ext_shared_info g_shinfo = {};   /* used by DPDK mbuf macro */
173 
174 static uint8_t g_qat_total_qp = 0;
175 static uint8_t g_next_qat_index;
176 
177 static const char *g_driver_names[] = {
178 	[ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB]	= ACCEL_DPDK_CRYPTODEV_AESNI_MB,
179 	[ACCEL_DPDK_CRYPTODEV_DRIVER_QAT]	= ACCEL_DPDK_CRYPTODEV_QAT,
180 	[ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI]	= ACCEL_DPDK_CRYPTODEV_MLX5
181 };
182 static const char *g_cipher_names[] = {
183 	[SPDK_ACCEL_CIPHER_AES_CBC]	= ACCEL_DPDK_CRYPTODEV_AES_CBC,
184 	[SPDK_ACCEL_CIPHER_AES_XTS]	= ACCEL_DPDK_CRYPTODEV_AES_XTS,
185 };
186 
187 static enum accel_dpdk_cryptodev_driver_type g_dpdk_cryptodev_driver =
188 	ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB;
189 
190 /* Global list of all crypto devices */
191 static TAILQ_HEAD(, accel_dpdk_cryptodev_device) g_crypto_devices = TAILQ_HEAD_INITIALIZER(
192 			g_crypto_devices);
193 static pthread_mutex_t g_device_lock = PTHREAD_MUTEX_INITIALIZER;
194 
195 static struct spdk_accel_module_if g_accel_dpdk_cryptodev_module;
196 
197 static int accel_dpdk_cryptodev_process_task(struct accel_dpdk_cryptodev_io_channel *crypto_ch,
198 		struct accel_dpdk_cryptodev_task *task);
199 
200 void
201 accel_dpdk_cryptodev_enable(void)
202 {
203 	spdk_accel_module_list_add(&g_accel_dpdk_cryptodev_module);
204 }
205 
206 int
207 accel_dpdk_cryptodev_set_driver(const char *driver_name)
208 {
209 	if (strcmp(driver_name, ACCEL_DPDK_CRYPTODEV_QAT) == 0) {
210 		g_dpdk_cryptodev_driver = ACCEL_DPDK_CRYPTODEV_DRIVER_QAT;
211 	} else if (strcmp(driver_name, ACCEL_DPDK_CRYPTODEV_AESNI_MB) == 0) {
212 		g_dpdk_cryptodev_driver = ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB;
213 	} else if (strcmp(driver_name, ACCEL_DPDK_CRYPTODEV_MLX5) == 0) {
214 		g_dpdk_cryptodev_driver = ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI;
215 	} else {
216 		SPDK_ERRLOG("Unsupported driver %s\n", driver_name);
217 		return -EINVAL;
218 	}
219 
220 	SPDK_NOTICELOG("Using driver %s\n", driver_name);
221 
222 	return 0;
223 }
224 
225 const char *
226 accel_dpdk_cryptodev_get_driver(void)
227 {
228 	return g_driver_names[g_dpdk_cryptodev_driver];
229 }
230 
231 static inline uint16_t
232 accel_dpdk_cryptodev_poll_qp(struct accel_dpdk_cryptodev_qp *qp,
233 			     struct accel_dpdk_cryptodev_io_channel *crypto_ch)
234 {
235 	struct rte_crypto_op *dequeued_ops[ACCEL_DPDK_CRYPTODEV_MAX_DEQUEUE_BURST_SIZE];
236 	struct rte_mbuf *mbufs_to_free[2 * ACCEL_DPDK_CRYPTODEV_MAX_DEQUEUE_BURST_SIZE];
237 	struct accel_dpdk_cryptodev_task *task;
238 	uint32_t num_mbufs = 0;
239 	int i;
240 	uint16_t num_dequeued_ops;
241 
242 	/* Each run of the poller will get just what the device has available
243 	 * at the moment we call it, we don't check again after draining the
244 	 * first batch.
245 	 */
246 	num_dequeued_ops = rte_cryptodev_dequeue_burst(qp->device->cdev_id, qp->qp,
247 			   dequeued_ops, ACCEL_DPDK_CRYPTODEV_MAX_DEQUEUE_BURST_SIZE);
248 	/* Check if operation was processed successfully */
249 	for (i = 0; i < num_dequeued_ops; i++) {
250 
251 		/* We don't know the order or association of the crypto ops wrt any
252 		 * particular task so need to look at each and determine if it's
253 		 * the last one for it's task or not.
254 		 */
255 		task = (struct accel_dpdk_cryptodev_task *)*RTE_MBUF_DYNFIELD(dequeued_ops[i]->sym->m_src,
256 				g_mbuf_offset, uint64_t *);
257 		assert(task != NULL);
258 
259 		if (dequeued_ops[i]->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
260 			SPDK_ERRLOG("error with op %d status %u\n", i, dequeued_ops[i]->status);
261 			/* Update the task status to error, we'll still process the
262 			 * rest of the crypto ops for this task though so they
263 			 * aren't left hanging.
264 			 */
265 			task->is_failed = true;
266 		}
267 
268 		/* Return the associated src and dst mbufs by collecting them into
269 		 * an array that we can use the bulk API to free after the loop.
270 		 */
271 		*RTE_MBUF_DYNFIELD(dequeued_ops[i]->sym->m_src, g_mbuf_offset, uint64_t *) = 0;
272 		mbufs_to_free[num_mbufs++] = (void *)dequeued_ops[i]->sym->m_src;
273 		if (dequeued_ops[i]->sym->m_dst) {
274 			mbufs_to_free[num_mbufs++] = (void *)dequeued_ops[i]->sym->m_dst;
275 		}
276 
277 		task->cryop_completed++;
278 		if (task->cryop_completed == task->cryop_total) {
279 			/* Complete the IO */
280 			spdk_accel_task_complete(&task->base, task->is_failed ? -EINVAL : 0);
281 		} else if (task->cryop_completed == task->cryop_submitted) {
282 			/* submit remaining crypto ops */
283 			int rc = accel_dpdk_cryptodev_process_task(crypto_ch, task);
284 
285 			if (spdk_unlikely(rc)) {
286 				if (rc == -ENOMEM) {
287 					TAILQ_INSERT_TAIL(&crypto_ch->queued_tasks, task, link);
288 					continue;
289 				} else if (rc == -EALREADY) {
290 					/* -EALREADY means that a task is completed, but it might be unsafe to complete
291 					 * it if we are in the submission path. Since we are in the poller context, we can
292 					 * complete th task immediately */
293 					rc = 0;
294 				}
295 				spdk_accel_task_complete(&task->base, rc);
296 			}
297 		}
298 	}
299 
300 	/* Now bulk free both mbufs and crypto operations. */
301 	if (num_dequeued_ops > 0) {
302 		rte_mempool_put_bulk(g_crypto_op_mp, (void **)dequeued_ops, num_dequeued_ops);
303 		assert(num_mbufs > 0);
304 		/* This also releases chained mbufs if any. */
305 		rte_pktmbuf_free_bulk(mbufs_to_free, num_mbufs);
306 	}
307 
308 	assert(qp->num_enqueued_ops >= num_dequeued_ops);
309 	qp->num_enqueued_ops -= num_dequeued_ops;
310 
311 	return num_dequeued_ops;
312 }
313 
314 /* This is the poller for the crypto module. It uses a single API to dequeue whatever is ready at
315  * the device. Then we need to decide if what we've got so far (including previous poller
316  * runs) totals up to one or more complete task */
317 static int
318 accel_dpdk_cryptodev_poller(void *args)
319 {
320 	struct accel_dpdk_cryptodev_io_channel *crypto_ch = args;
321 	struct accel_dpdk_cryptodev_qp *qp;
322 	struct accel_dpdk_cryptodev_task *task, *task_tmp;
323 	TAILQ_HEAD(, accel_dpdk_cryptodev_task) queued_tasks_tmp;
324 	uint32_t num_dequeued_ops = 0, num_enqueued_ops = 0, num_completed_tasks = 0;
325 	int i, rc;
326 
327 	for (i = 0; i < ACCEL_DPDK_CRYPTODEV_DRIVER_LAST; i++) {
328 		qp = crypto_ch->device_qp[i];
329 		/* Avoid polling "idle" qps since it may affect performance */
330 		if (qp && qp->num_enqueued_ops) {
331 			num_dequeued_ops += accel_dpdk_cryptodev_poll_qp(qp, crypto_ch);
332 		}
333 	}
334 
335 	if (!TAILQ_EMPTY(&crypto_ch->queued_tasks)) {
336 		TAILQ_INIT(&queued_tasks_tmp);
337 
338 		TAILQ_FOREACH_SAFE(task, &crypto_ch->queued_tasks, link, task_tmp) {
339 			TAILQ_REMOVE(&crypto_ch->queued_tasks, task, link);
340 			rc = accel_dpdk_cryptodev_process_task(crypto_ch, task);
341 			if (spdk_unlikely(rc)) {
342 				if (rc == -ENOMEM) {
343 					TAILQ_INSERT_TAIL(&queued_tasks_tmp, task, link);
344 					/* Other queued tasks may belong to other qpairs,
345 					 * so process the whole list */
346 					continue;
347 				} else if (rc == -EALREADY) {
348 					/* -EALREADY means that a task is completed, but it might be unsafe to complete
349 					 * it if we are in the submission path. Since we are in the poller context, we can
350 					 * complete th task immediately */
351 					rc = 0;
352 				}
353 				spdk_accel_task_complete(&task->base, rc);
354 				num_completed_tasks++;
355 			} else {
356 				num_enqueued_ops++;
357 			}
358 		}
359 
360 		TAILQ_SWAP(&crypto_ch->queued_tasks, &queued_tasks_tmp, accel_dpdk_cryptodev_task, link);
361 	}
362 
363 	TAILQ_FOREACH_SAFE(task, &crypto_ch->completed_tasks, link, task_tmp) {
364 		TAILQ_REMOVE(&crypto_ch->completed_tasks, task, link);
365 		spdk_accel_task_complete(&task->base, 0);
366 		num_completed_tasks++;
367 	}
368 
369 	return !!(num_dequeued_ops + num_enqueued_ops + num_completed_tasks);
370 }
371 
372 /* Allocate the new mbuf of @remainder size with data pointed by @addr and attach
373  * it to the @orig_mbuf. */
374 static inline int
375 accel_dpdk_cryptodev_mbuf_chain_remainder(struct accel_dpdk_cryptodev_task *task,
376 		struct rte_mbuf *orig_mbuf, uint8_t *addr, uint64_t *_remainder)
377 {
378 	uint64_t phys_addr, phys_len, remainder = *_remainder;
379 	struct rte_mbuf *chain_mbuf;
380 	int rc;
381 
382 	phys_len = remainder;
383 	phys_addr = spdk_vtophys((void *)addr, &phys_len);
384 	if (spdk_unlikely(phys_addr == SPDK_VTOPHYS_ERROR)) {
385 		return -EFAULT;
386 	}
387 	remainder = spdk_min(remainder, phys_len);
388 	remainder = spdk_min(remainder, ACCEL_DPDK_CRYPTODEV_MAX_MBUF_LEN);
389 	rc = rte_pktmbuf_alloc_bulk(g_mbuf_mp, (struct rte_mbuf **)&chain_mbuf, 1);
390 	if (spdk_unlikely(rc)) {
391 		return -ENOMEM;
392 	}
393 	/* Store context in every mbuf as we don't know anything about completion order */
394 	*RTE_MBUF_DYNFIELD(chain_mbuf, g_mbuf_offset, uint64_t *) = (uint64_t)task;
395 	rte_pktmbuf_attach_extbuf(chain_mbuf, addr, phys_addr, remainder, &g_shinfo);
396 	rte_pktmbuf_append(chain_mbuf, remainder);
397 
398 	/* Chained buffer is released by rte_pktbuf_free_bulk() automagicaly. */
399 	rte_pktmbuf_chain(orig_mbuf, chain_mbuf);
400 	*_remainder = remainder;
401 
402 	return 0;
403 }
404 
405 /* Attach data buffer pointed by @addr to @mbuf. Return utilized len of the
406  * contiguous space that was physically available. */
407 static inline uint64_t
408 accel_dpdk_cryptodev_mbuf_attach_buf(struct accel_dpdk_cryptodev_task *task, struct rte_mbuf *mbuf,
409 				     uint8_t *addr, uint32_t len)
410 {
411 	uint64_t phys_addr, phys_len;
412 
413 	/* Store context in every mbuf as we don't know anything about completion order */
414 	*RTE_MBUF_DYNFIELD(mbuf, g_mbuf_offset, uint64_t *) = (uint64_t)task;
415 
416 	phys_len = len;
417 	phys_addr = spdk_vtophys((void *)addr, &phys_len);
418 	if (spdk_unlikely(phys_addr == SPDK_VTOPHYS_ERROR || phys_len == 0)) {
419 		return 0;
420 	}
421 	assert(phys_len <= len);
422 	phys_len = spdk_min(phys_len, ACCEL_DPDK_CRYPTODEV_MAX_MBUF_LEN);
423 
424 	/* Set the mbuf elements address and length. */
425 	rte_pktmbuf_attach_extbuf(mbuf, addr, phys_addr, phys_len, &g_shinfo);
426 	rte_pktmbuf_append(mbuf, phys_len);
427 
428 	return phys_len;
429 }
430 
431 static inline struct accel_dpdk_cryptodev_key_handle *
432 accel_dpdk_find_key_handle_in_channel(struct accel_dpdk_cryptodev_io_channel *crypto_ch,
433 				      struct accel_dpdk_cryptodev_key_priv *key)
434 {
435 	struct accel_dpdk_cryptodev_key_handle *key_handle;
436 
437 	if (key->driver == ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI) {
438 		/* Crypto key is registered on all available devices while io_channel opens CQ/QP on a single device.
439 		 * We need to iterate a list of key entries to find a suitable device */
440 		TAILQ_FOREACH(key_handle, &key->dev_keys, link) {
441 			if (key_handle->device->cdev_id ==
442 			    crypto_ch->device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI]->device->cdev_id) {
443 				return key_handle;
444 			}
445 		}
446 		return NULL;
447 	} else {
448 		return TAILQ_FIRST(&key->dev_keys);
449 	}
450 }
451 
452 static inline int
453 accel_dpdk_cryptodev_task_alloc_resources(struct rte_mbuf **src_mbufs, struct rte_mbuf **dst_mbufs,
454 		struct rte_crypto_op **crypto_ops, int count)
455 {
456 	int rc;
457 
458 	/* Get the number of source mbufs that we need. These will always be 1:1 because we
459 	 * don't support chaining. The reason we don't is because of our decision to use
460 	 * LBA as IV, there can be no case where we'd need >1 mbuf per crypto op or the
461 	 * op would be > 1 LBA.
462 	 */
463 	rc = rte_pktmbuf_alloc_bulk(g_mbuf_mp, src_mbufs, count);
464 	if (rc) {
465 		SPDK_ERRLOG("Failed to get src_mbufs!\n");
466 		return -ENOMEM;
467 	}
468 
469 	/* Get the same amount to describe destination. If crypto operation is inline then we don't just skip it */
470 	if (dst_mbufs) {
471 		rc = rte_pktmbuf_alloc_bulk(g_mbuf_mp, dst_mbufs, count);
472 		if (rc) {
473 			SPDK_ERRLOG("Failed to get dst_mbufs!\n");
474 			goto err_free_src;
475 		}
476 	}
477 
478 #ifdef __clang_analyzer__
479 	/* silence scan-build false positive */
480 	SPDK_CLANG_ANALYZER_PREINIT_PTR_ARRAY(crypto_ops, ACCEL_DPDK_CRYPTODEV_MAX_ENQUEUE_ARRAY_SIZE,
481 					      0x1000);
482 #endif
483 	/* Allocate crypto operations. */
484 	rc = rte_crypto_op_bulk_alloc(g_crypto_op_mp,
485 				      RTE_CRYPTO_OP_TYPE_SYMMETRIC,
486 				      crypto_ops, count);
487 	if (rc < count) {
488 		SPDK_ERRLOG("Failed to allocate crypto ops! rc %d\n", rc);
489 		goto err_free_ops;
490 	}
491 
492 	return 0;
493 
494 err_free_ops:
495 	if (rc > 0) {
496 		rte_mempool_put_bulk(g_crypto_op_mp, (void **)crypto_ops, rc);
497 	}
498 	if (dst_mbufs) {
499 		/* This also releases chained mbufs if any. */
500 		rte_pktmbuf_free_bulk(dst_mbufs, count);
501 	}
502 err_free_src:
503 	/* This also releases chained mbufs if any. */
504 	rte_pktmbuf_free_bulk(src_mbufs, count);
505 
506 	return -ENOMEM;
507 }
508 
509 static inline int
510 accel_dpdk_cryptodev_mbuf_add_single_block(struct spdk_iov_sgl *sgl, struct rte_mbuf *mbuf,
511 		struct accel_dpdk_cryptodev_task *task)
512 {
513 	int rc;
514 	uint8_t *buf_addr;
515 	uint64_t phys_len;
516 	uint64_t remainder;
517 	uint64_t buf_len;
518 
519 	assert(sgl->iov->iov_len > sgl->iov_offset);
520 	buf_len = spdk_min(task->base.block_size, sgl->iov->iov_len - sgl->iov_offset);
521 	buf_addr = sgl->iov->iov_base + sgl->iov_offset;
522 	phys_len = accel_dpdk_cryptodev_mbuf_attach_buf(task, mbuf, buf_addr, buf_len);
523 	if (spdk_unlikely(phys_len == 0)) {
524 		return -EFAULT;
525 	}
526 	buf_len = spdk_min(buf_len, phys_len);
527 	spdk_iov_sgl_advance(sgl, buf_len);
528 
529 	/* Handle the case of page boundary. */
530 	assert(task->base.block_size >= buf_len);
531 	remainder = task->base.block_size - buf_len;
532 	while (remainder) {
533 		buf_len = spdk_min(remainder, sgl->iov->iov_len - sgl->iov_offset);
534 		buf_addr = sgl->iov->iov_base + sgl->iov_offset;
535 		rc = accel_dpdk_cryptodev_mbuf_chain_remainder(task, mbuf, buf_addr, &buf_len);
536 		if (spdk_unlikely(rc)) {
537 			return rc;
538 		}
539 		spdk_iov_sgl_advance(sgl, buf_len);
540 		remainder -= buf_len;
541 	}
542 
543 	return 0;
544 }
545 
546 static inline void
547 accel_dpdk_cryptodev_op_set_iv(struct rte_crypto_op *crypto_op, uint64_t iv)
548 {
549 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(crypto_op, uint8_t *, ACCEL_DPDK_CRYPTODEV_IV_OFFSET);
550 
551 	/* Set the IV - we use the LBA of the crypto_op */
552 	memset(iv_ptr, 0, ACCEL_DPDK_CRYPTODEV_IV_LENGTH);
553 	rte_memcpy(iv_ptr, &iv, sizeof(uint64_t));
554 }
555 
556 static inline void
557 accel_dpdk_cryptodev_update_resources_from_pools(struct rte_crypto_op **crypto_ops,
558 		struct rte_mbuf **src_mbufs, struct rte_mbuf **dst_mbufs,
559 		uint32_t num_enqueued_ops, uint32_t cryop_cnt)
560 {
561 	memmove(crypto_ops, &crypto_ops[num_enqueued_ops], sizeof(crypto_ops[0]) * cryop_cnt);
562 	memmove(src_mbufs, &src_mbufs[num_enqueued_ops], sizeof(src_mbufs[0]) * cryop_cnt);
563 	if (dst_mbufs) {
564 		memmove(dst_mbufs, &dst_mbufs[num_enqueued_ops], sizeof(dst_mbufs[0]) * cryop_cnt);
565 	}
566 }
567 
568 static int
569 accel_dpdk_cryptodev_process_task(struct accel_dpdk_cryptodev_io_channel *crypto_ch,
570 				  struct accel_dpdk_cryptodev_task *task)
571 {
572 	uint16_t num_enqueued_ops;
573 	uint32_t cryop_cnt;
574 	uint32_t crypto_len = task->base.block_size;
575 	uint64_t dst_length, total_length;
576 	uint32_t sgl_offset;
577 	uint32_t qp_capacity;
578 	uint64_t iv_start;
579 	uint32_t i, crypto_index;
580 	struct rte_crypto_op *crypto_ops[ACCEL_DPDK_CRYPTODEV_MAX_ENQUEUE_ARRAY_SIZE];
581 	struct rte_mbuf *src_mbufs[ACCEL_DPDK_CRYPTODEV_MAX_ENQUEUE_ARRAY_SIZE];
582 	struct rte_mbuf *dst_mbufs[ACCEL_DPDK_CRYPTODEV_MAX_ENQUEUE_ARRAY_SIZE];
583 	void *session;
584 	struct accel_dpdk_cryptodev_key_priv *priv;
585 	struct accel_dpdk_cryptodev_key_handle *key_handle;
586 	struct accel_dpdk_cryptodev_qp *qp;
587 	struct accel_dpdk_cryptodev_device *dev;
588 	struct spdk_iov_sgl src, dst = {};
589 	int rc;
590 	bool inplace = task->inplace;
591 
592 	if (spdk_unlikely(!task->base.crypto_key ||
593 			  task->base.crypto_key->module_if != &g_accel_dpdk_cryptodev_module)) {
594 		return -EINVAL;
595 	}
596 
597 	priv = task->base.crypto_key->priv;
598 	assert(priv->driver < ACCEL_DPDK_CRYPTODEV_DRIVER_LAST);
599 
600 	if (task->cryop_completed) {
601 		/* We continue to process remaining blocks */
602 		assert(task->cryop_submitted == task->cryop_completed);
603 		assert(task->cryop_total > task->cryop_completed);
604 		cryop_cnt = task->cryop_total - task->cryop_completed;
605 		sgl_offset = task->cryop_completed * crypto_len;
606 		iv_start = task->base.iv + task->cryop_completed;
607 	} else {
608 		/* That is a new task */
609 		total_length = 0;
610 		for (i = 0; i < task->base.s.iovcnt; i++) {
611 			total_length += task->base.s.iovs[i].iov_len;
612 		}
613 		dst_length = 0;
614 		for (i = 0; i < task->base.d.iovcnt; i++) {
615 			dst_length += task->base.d.iovs[i].iov_len;
616 		}
617 
618 		if (spdk_unlikely(total_length != dst_length || !total_length)) {
619 			return -ERANGE;
620 		}
621 		if (spdk_unlikely(total_length % task->base.block_size != 0)) {
622 			return -EINVAL;
623 		}
624 
625 		cryop_cnt = total_length / task->base.block_size;
626 		task->cryop_total = cryop_cnt;
627 		sgl_offset = 0;
628 		iv_start = task->base.iv;
629 	}
630 
631 	/* Limit the number of crypto ops that we can process once */
632 	cryop_cnt = spdk_min(cryop_cnt, ACCEL_DPDK_CRYPTODEV_MAX_ENQUEUE_ARRAY_SIZE);
633 
634 	qp = crypto_ch->device_qp[priv->driver];
635 	assert(qp);
636 	dev = qp->device;
637 	assert(dev);
638 	assert(dev->qp_desc_nr >= qp->num_enqueued_ops);
639 
640 	qp_capacity = dev->qp_desc_nr - qp->num_enqueued_ops;
641 	cryop_cnt = spdk_min(cryop_cnt, qp_capacity);
642 	if (spdk_unlikely(cryop_cnt == 0)) {
643 		/* QP is full */
644 		return -ENOMEM;
645 	}
646 
647 	key_handle = accel_dpdk_find_key_handle_in_channel(crypto_ch, priv);
648 	if (spdk_unlikely(!key_handle)) {
649 		SPDK_ERRLOG("Failed to find a key handle, driver %s, cipher %s\n", g_driver_names[priv->driver],
650 			    g_cipher_names[priv->cipher]);
651 		return -EINVAL;
652 	}
653 	/* mlx5_pci binds keys to a specific device, we can't use a key with any device */
654 	assert(dev == key_handle->device || priv->driver != ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI);
655 
656 	if (task->base.op_code == ACCEL_OPC_ENCRYPT) {
657 		session = key_handle->session_encrypt;
658 	} else if (task->base.op_code == ACCEL_OPC_DECRYPT) {
659 		session = key_handle->session_decrypt;
660 	} else {
661 		return -EINVAL;
662 	}
663 
664 	rc = accel_dpdk_cryptodev_task_alloc_resources(src_mbufs, inplace ? NULL : dst_mbufs,
665 			crypto_ops, cryop_cnt);
666 	if (rc) {
667 		return rc;
668 	}
669 
670 	/* As we don't support chaining because of a decision to use LBA as IV, construction
671 	 * of crypto operations is straightforward. We build both the op, the mbuf and the
672 	 * dst_mbuf in our local arrays by looping through the length of the accel task and
673 	 * picking off LBA sized blocks of memory from the IOVs as we walk through them. Each
674 	 * LBA sized chunk of memory will correspond 1:1 to a crypto operation and a single
675 	 * mbuf per crypto operation.
676 	 */
677 	spdk_iov_sgl_init(&src, task->base.s.iovs, task->base.s.iovcnt, 0);
678 	spdk_iov_sgl_advance(&src, sgl_offset);
679 	if (!inplace) {
680 		spdk_iov_sgl_init(&dst, task->base.d.iovs, task->base.d.iovcnt, 0);
681 		spdk_iov_sgl_advance(&dst, sgl_offset);
682 	}
683 
684 	for (crypto_index = 0; crypto_index < cryop_cnt; crypto_index++) {
685 		rc = accel_dpdk_cryptodev_mbuf_add_single_block(&src, src_mbufs[crypto_index], task);
686 		if (spdk_unlikely(rc)) {
687 			goto free_ops;
688 		}
689 		accel_dpdk_cryptodev_op_set_iv(crypto_ops[crypto_index], iv_start);
690 		iv_start++;
691 
692 		/* Set the data to encrypt/decrypt length */
693 		crypto_ops[crypto_index]->sym->cipher.data.length = crypto_len;
694 		crypto_ops[crypto_index]->sym->cipher.data.offset = 0;
695 		rte_crypto_op_attach_sym_session(crypto_ops[crypto_index], session);
696 
697 		/* link the mbuf to the crypto op. */
698 		crypto_ops[crypto_index]->sym->m_src = src_mbufs[crypto_index];
699 
700 		if (inplace) {
701 			crypto_ops[crypto_index]->sym->m_dst = NULL;
702 		} else {
703 #ifndef __clang_analyzer__
704 			/* scan-build thinks that dst_mbufs is not initialized */
705 			rc = accel_dpdk_cryptodev_mbuf_add_single_block(&dst, dst_mbufs[crypto_index], task);
706 			if (spdk_unlikely(rc)) {
707 				goto free_ops;
708 			}
709 			crypto_ops[crypto_index]->sym->m_dst = dst_mbufs[crypto_index];
710 #endif
711 		}
712 	}
713 
714 	/* Enqueue everything we've got but limit by the max number of descriptors we
715 	 * configured the crypto device for.
716 	 */
717 	num_enqueued_ops = rte_cryptodev_enqueue_burst(dev->cdev_id, qp->qp, crypto_ops, cryop_cnt);
718 	/* This value is used in the completion callback to determine when the accel task is complete. */
719 	task->cryop_submitted += num_enqueued_ops;
720 	qp->num_enqueued_ops += num_enqueued_ops;
721 	/* We were unable to enqueue everything but did get some, so need to decide what
722 	 * to do based on the status of the last op.
723 	 */
724 	if (num_enqueued_ops < cryop_cnt) {
725 		switch (crypto_ops[num_enqueued_ops]->status) {
726 		case RTE_CRYPTO_OP_STATUS_SUCCESS:
727 			/* Crypto operation might be completed successfully but enqueuing to a completion ring might fail.
728 			 * That might happen with SW PMDs like openssl
729 			 * We can't retry such operation on next turn since if crypto operation was inplace, we can encrypt/
730 			 * decrypt already processed buffer. See github issue #2907 for more details.
731 			 * Handle this case as the crypto op was completed successfully - increment cryop_submitted and
732 			 * cryop_completed.
733 			 * We won't receive a completion for such operation, so we need to cleanup mbufs and crypto_ops */
734 			assert(task->cryop_total > task->cryop_completed);
735 			task->cryop_completed++;
736 			task->cryop_submitted++;
737 			if (task->cryop_completed == task->cryop_total) {
738 				assert(num_enqueued_ops == 0);
739 				/* All crypto ops are completed. We can't complete the task immediately since this function might be
740 				 * called in scope of spdk_accel_submit_* function and user's logic in the completion callback
741 				 * might lead to stack overflow */
742 				cryop_cnt -= num_enqueued_ops;
743 				accel_dpdk_cryptodev_update_resources_from_pools(crypto_ops, src_mbufs, inplace ? NULL : dst_mbufs,
744 						num_enqueued_ops, cryop_cnt);
745 				rc = -EALREADY;
746 				goto free_ops;
747 			}
748 		/* fallthrough */
749 		case RTE_CRYPTO_OP_STATUS_NOT_PROCESSED:
750 			if (num_enqueued_ops == 0) {
751 				/* Nothing was submitted. Free crypto ops and mbufs, treat this case as NOMEM */
752 				rc = -ENOMEM;
753 				goto free_ops;
754 			}
755 			/* Part of the crypto operations were not submitted, release mbufs and crypto ops.
756 			 * The rest crypto ops will be submitted again once current batch is completed */
757 			cryop_cnt -= num_enqueued_ops;
758 			accel_dpdk_cryptodev_update_resources_from_pools(crypto_ops, src_mbufs, inplace ? NULL : dst_mbufs,
759 					num_enqueued_ops, cryop_cnt);
760 			rc = 0;
761 			goto free_ops;
762 		default:
763 			/* For all other statuses, mark task as failed so that the poller will pick
764 			 * the failure up for the overall task status.
765 			 */
766 			task->is_failed = true;
767 			if (num_enqueued_ops == 0) {
768 				/* If nothing was enqueued, but the last one wasn't because of
769 				 * busy, fail it now as the poller won't know anything about it.
770 				 */
771 				rc = -EINVAL;
772 				goto free_ops;
773 			}
774 			break;
775 		}
776 	}
777 
778 	return 0;
779 
780 	/* Error cleanup paths. */
781 free_ops:
782 	if (!inplace) {
783 		/* This also releases chained mbufs if any. */
784 		rte_pktmbuf_free_bulk(dst_mbufs, cryop_cnt);
785 	}
786 	rte_mempool_put_bulk(g_crypto_op_mp, (void **)crypto_ops, cryop_cnt);
787 	/* This also releases chained mbufs if any. */
788 	rte_pktmbuf_free_bulk(src_mbufs, cryop_cnt);
789 	return rc;
790 }
791 
792 static inline struct accel_dpdk_cryptodev_qp *
793 accel_dpdk_cryptodev_get_next_device_qpair(enum accel_dpdk_cryptodev_driver_type type)
794 {
795 	struct accel_dpdk_cryptodev_device *device, *device_tmp;
796 	struct accel_dpdk_cryptodev_qp *qpair;
797 
798 	TAILQ_FOREACH_SAFE(device, &g_crypto_devices, link, device_tmp) {
799 		if (device->type != type) {
800 			continue;
801 		}
802 		TAILQ_FOREACH(qpair, &device->qpairs, link) {
803 			if (!qpair->in_use) {
804 				qpair->in_use = true;
805 				return qpair;
806 			}
807 		}
808 	}
809 
810 	return NULL;
811 }
812 
813 /* Helper function for the channel creation callback.
814  * Returns the number of drivers assigned to the channel */
815 static uint32_t
816 accel_dpdk_cryptodev_assign_device_qps(struct accel_dpdk_cryptodev_io_channel *crypto_ch)
817 {
818 	struct accel_dpdk_cryptodev_device *device;
819 	struct accel_dpdk_cryptodev_qp *device_qp;
820 	uint32_t num_drivers = 0;
821 	bool qat_found = false;
822 
823 	pthread_mutex_lock(&g_device_lock);
824 
825 	TAILQ_FOREACH(device, &g_crypto_devices, link) {
826 		if (device->type == ACCEL_DPDK_CRYPTODEV_DRIVER_QAT && !qat_found) {
827 			/* For some QAT devices, the optimal qp to use is every 32nd as this spreads the
828 			 * workload out over the multiple virtual functions in the device. For the devices
829 			 * where this isn't the case, it doesn't hurt.
830 			 */
831 			TAILQ_FOREACH(device_qp, &device->qpairs, link) {
832 				if (device_qp->index != g_next_qat_index) {
833 					continue;
834 				}
835 				if (device_qp->in_use == false) {
836 					assert(crypto_ch->device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_QAT] == NULL);
837 					crypto_ch->device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_QAT] = device_qp;
838 					device_qp->in_use = true;
839 					g_next_qat_index = (g_next_qat_index + ACCEL_DPDK_CRYPTODEV_QAT_VF_SPREAD) % g_qat_total_qp;
840 					qat_found = true;
841 					num_drivers++;
842 					break;
843 				} else {
844 					/* if the preferred index is used, skip to the next one in this set. */
845 					g_next_qat_index = (g_next_qat_index + 1) % g_qat_total_qp;
846 				}
847 			}
848 		}
849 	}
850 
851 	/* For ACCEL_DPDK_CRYPTODEV_AESNI_MB and MLX5_PCI select devices in round-robin manner */
852 	device_qp = accel_dpdk_cryptodev_get_next_device_qpair(ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB);
853 	if (device_qp) {
854 		assert(crypto_ch->device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB] == NULL);
855 		crypto_ch->device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB] = device_qp;
856 		num_drivers++;
857 	}
858 
859 	device_qp = accel_dpdk_cryptodev_get_next_device_qpair(ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI);
860 	if (device_qp) {
861 		assert(crypto_ch->device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI] == NULL);
862 		crypto_ch->device_qp[ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI] = device_qp;
863 		num_drivers++;
864 	}
865 
866 	pthread_mutex_unlock(&g_device_lock);
867 
868 	return num_drivers;
869 }
870 
871 static void
872 _accel_dpdk_cryptodev_destroy_cb(void *io_device, void *ctx_buf)
873 {
874 	struct accel_dpdk_cryptodev_io_channel *crypto_ch = (struct accel_dpdk_cryptodev_io_channel *)
875 			ctx_buf;
876 	int i;
877 
878 	pthread_mutex_lock(&g_device_lock);
879 	for (i = 0; i < ACCEL_DPDK_CRYPTODEV_DRIVER_LAST; i++) {
880 		if (crypto_ch->device_qp[i]) {
881 			crypto_ch->device_qp[i]->in_use = false;
882 		}
883 	}
884 	pthread_mutex_unlock(&g_device_lock);
885 
886 	spdk_poller_unregister(&crypto_ch->poller);
887 }
888 
889 static int
890 _accel_dpdk_cryptodev_create_cb(void *io_device, void *ctx_buf)
891 {
892 	struct accel_dpdk_cryptodev_io_channel *crypto_ch = (struct accel_dpdk_cryptodev_io_channel *)
893 			ctx_buf;
894 
895 	crypto_ch->poller = SPDK_POLLER_REGISTER(accel_dpdk_cryptodev_poller, crypto_ch, 0);
896 	if (!accel_dpdk_cryptodev_assign_device_qps(crypto_ch)) {
897 		SPDK_ERRLOG("No crypto drivers assigned\n");
898 		spdk_poller_unregister(&crypto_ch->poller);
899 		return -EINVAL;
900 	}
901 
902 	/* We use this to queue tasks when qpair is full or no resources in pools */
903 	TAILQ_INIT(&crypto_ch->queued_tasks);
904 	TAILQ_INIT(&crypto_ch->completed_tasks);
905 
906 	return 0;
907 }
908 
909 static struct spdk_io_channel *
910 accel_dpdk_cryptodev_get_io_channel(void)
911 {
912 	return spdk_get_io_channel(&g_accel_dpdk_cryptodev_module);
913 }
914 
915 static size_t
916 accel_dpdk_cryptodev_ctx_size(void)
917 {
918 	return sizeof(struct accel_dpdk_cryptodev_task);
919 }
920 
921 static bool
922 accel_dpdk_cryptodev_supports_opcode(enum accel_opcode opc)
923 {
924 	switch (opc) {
925 	case ACCEL_OPC_ENCRYPT:
926 	case ACCEL_OPC_DECRYPT:
927 		return true;
928 	default:
929 		return false;
930 	}
931 }
932 
933 static int
934 accel_dpdk_cryptodev_submit_tasks(struct spdk_io_channel *_ch, struct spdk_accel_task *_task)
935 {
936 	struct accel_dpdk_cryptodev_task *task = SPDK_CONTAINEROF(_task, struct accel_dpdk_cryptodev_task,
937 			base);
938 	struct accel_dpdk_cryptodev_io_channel *ch = spdk_io_channel_get_ctx(_ch);
939 	int rc;
940 
941 	task->cryop_completed = 0;
942 	task->cryop_submitted = 0;
943 	task->cryop_total = 0;
944 	task->inplace = true;
945 	task->is_failed = false;
946 
947 	/* Check if crypto operation is inplace: no destination or source == destination */
948 	if (task->base.s.iovcnt == task->base.d.iovcnt) {
949 		if (memcmp(task->base.s.iovs, task->base.d.iovs, sizeof(struct iovec) * task->base.s.iovcnt) != 0) {
950 			task->inplace = false;
951 		}
952 	} else if (task->base.d.iovcnt != 0) {
953 		task->inplace = false;
954 	}
955 
956 	rc = accel_dpdk_cryptodev_process_task(ch, task);
957 	if (spdk_unlikely(rc)) {
958 		if (rc == -ENOMEM) {
959 			TAILQ_INSERT_TAIL(&ch->queued_tasks, task, link);
960 			rc = 0;
961 		} else if (rc == -EALREADY) {
962 			/* -EALREADY means that a task is completed, but it might be unsafe to complete
963 			 * it if we are in the submission path. Hence put it into a dedicated queue to and
964 			 * process it during polling */
965 			TAILQ_INSERT_TAIL(&ch->completed_tasks, task, link);
966 			rc = 0;
967 		}
968 	}
969 
970 	return rc;
971 }
972 
973 /* Dummy function used by DPDK to free ext attached buffers to mbufs, we free them ourselves but
974  * this callback has to be here. */
975 static void
976 shinfo_free_cb(void *arg1, void *arg2)
977 {
978 }
979 
980 static int
981 accel_dpdk_cryptodev_create(uint8_t index, uint16_t num_lcores)
982 {
983 	struct rte_cryptodev_qp_conf qp_conf = {
984 		.mp_session = g_session_mp,
985 #if RTE_VERSION < RTE_VERSION_NUM(22, 11, 0, 0)
986 		.mp_session_private = g_session_mp_priv
987 #endif
988 	};
989 	/* Setup queue pairs. */
990 	struct rte_cryptodev_config conf = { .socket_id = SPDK_ENV_SOCKET_ID_ANY };
991 	struct accel_dpdk_cryptodev_device *device;
992 	uint8_t j, cdev_id, cdrv_id;
993 	struct accel_dpdk_cryptodev_qp *dev_qp;
994 	int rc;
995 
996 	device = calloc(1, sizeof(*device));
997 	if (!device) {
998 		return -ENOMEM;
999 	}
1000 
1001 	/* Get details about this device. */
1002 	rte_cryptodev_info_get(index, &device->cdev_info);
1003 	cdrv_id = device->cdev_info.driver_id;
1004 	cdev_id = device->cdev_id = index;
1005 
1006 	if (strcmp(device->cdev_info.driver_name, ACCEL_DPDK_CRYPTODEV_QAT) == 0) {
1007 		device->qp_desc_nr = ACCEL_DPDK_CRYPTODEV_QP_DESCRIPTORS;
1008 		device->type = ACCEL_DPDK_CRYPTODEV_DRIVER_QAT;
1009 	} else if (strcmp(device->cdev_info.driver_name, ACCEL_DPDK_CRYPTODEV_AESNI_MB) == 0) {
1010 		device->qp_desc_nr = ACCEL_DPDK_CRYPTODEV_QP_DESCRIPTORS;
1011 		device->type = ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB;
1012 	} else if (strcmp(device->cdev_info.driver_name, ACCEL_DPDK_CRYPTODEV_MLX5) == 0) {
1013 		device->qp_desc_nr = ACCEL_DPDK_CRYPTODEV_QP_DESCRIPTORS_MLX5;
1014 		device->type = ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI;
1015 	} else if (strcmp(device->cdev_info.driver_name, ACCEL_DPDK_CRYPTODEV_QAT_ASYM) == 0) {
1016 		/* ACCEL_DPDK_CRYPTODEV_QAT_ASYM devices are not supported at this time. */
1017 		rc = 0;
1018 		goto err;
1019 	} else {
1020 		SPDK_ERRLOG("Failed to start device %u. Invalid driver name \"%s\"\n",
1021 			    cdev_id, device->cdev_info.driver_name);
1022 		rc = -EINVAL;
1023 		goto err;
1024 	}
1025 
1026 	/* Before going any further, make sure we have enough resources for this
1027 	 * device type to function.  We need a unique queue pair per core accross each
1028 	 * device type to remain lockless....
1029 	 */
1030 	if ((rte_cryptodev_device_count_by_driver(cdrv_id) *
1031 	     device->cdev_info.max_nb_queue_pairs) < num_lcores) {
1032 		SPDK_ERRLOG("Insufficient unique queue pairs available for %s\n",
1033 			    device->cdev_info.driver_name);
1034 		SPDK_ERRLOG("Either add more crypto devices or decrease core count\n");
1035 		rc = -EINVAL;
1036 		goto err;
1037 	}
1038 
1039 	conf.nb_queue_pairs = device->cdev_info.max_nb_queue_pairs;
1040 	rc = rte_cryptodev_configure(cdev_id, &conf);
1041 	if (rc < 0) {
1042 		SPDK_ERRLOG("Failed to configure cryptodev %u: error %d\n",
1043 			    cdev_id, rc);
1044 		rc = -EINVAL;
1045 		goto err;
1046 	}
1047 
1048 	/* Pre-setup all potential qpairs now and assign them in the channel
1049 	 * callback. If we were to create them there, we'd have to stop the
1050 	 * entire device affecting all other threads that might be using it
1051 	 * even on other queue pairs.
1052 	 */
1053 	qp_conf.nb_descriptors = device->qp_desc_nr;
1054 	for (j = 0; j < device->cdev_info.max_nb_queue_pairs; j++) {
1055 		rc = rte_cryptodev_queue_pair_setup(cdev_id, j, &qp_conf, SOCKET_ID_ANY);
1056 		if (rc < 0) {
1057 			SPDK_ERRLOG("Failed to setup queue pair %u on "
1058 				    "cryptodev %u: error %d\n", j, cdev_id, rc);
1059 			rc = -EINVAL;
1060 			goto err_qp_setup;
1061 		}
1062 	}
1063 
1064 	rc = rte_cryptodev_start(cdev_id);
1065 	if (rc < 0) {
1066 		SPDK_ERRLOG("Failed to start device %u: error %d\n", cdev_id, rc);
1067 		rc = -EINVAL;
1068 		goto err_dev_start;
1069 	}
1070 
1071 	TAILQ_INIT(&device->qpairs);
1072 	/* Build up lists of device/qp combinations per PMD */
1073 	for (j = 0; j < device->cdev_info.max_nb_queue_pairs; j++) {
1074 		dev_qp = calloc(1, sizeof(*dev_qp));
1075 		if (!dev_qp) {
1076 			rc = -ENOMEM;
1077 			goto err_qp_alloc;
1078 		}
1079 		dev_qp->device = device;
1080 		dev_qp->qp = j;
1081 		dev_qp->in_use = false;
1082 		TAILQ_INSERT_TAIL(&device->qpairs, dev_qp, link);
1083 		if (device->type == ACCEL_DPDK_CRYPTODEV_DRIVER_QAT) {
1084 			dev_qp->index = g_qat_total_qp++;
1085 		}
1086 	}
1087 	/* Add to our list of available crypto devices. */
1088 	TAILQ_INSERT_TAIL(&g_crypto_devices, device, link);
1089 
1090 	return 0;
1091 
1092 err_qp_alloc:
1093 	TAILQ_FOREACH(dev_qp, &device->qpairs, link) {
1094 		if (dev_qp->device->cdev_id != device->cdev_id) {
1095 			continue;
1096 		}
1097 		free(dev_qp);
1098 		if (device->type == ACCEL_DPDK_CRYPTODEV_DRIVER_QAT) {
1099 			assert(g_qat_total_qp);
1100 			g_qat_total_qp--;
1101 		}
1102 	}
1103 	rte_cryptodev_stop(cdev_id);
1104 err_dev_start:
1105 err_qp_setup:
1106 	rte_cryptodev_close(cdev_id);
1107 err:
1108 	free(device);
1109 
1110 	return rc;
1111 }
1112 
1113 static void
1114 accel_dpdk_cryptodev_release(struct accel_dpdk_cryptodev_device *device)
1115 {
1116 	struct accel_dpdk_cryptodev_qp *dev_qp, *tmp;
1117 
1118 	assert(device);
1119 
1120 	TAILQ_FOREACH_SAFE(dev_qp, &device->qpairs, link, tmp) {
1121 		free(dev_qp);
1122 	}
1123 	if (device->type == ACCEL_DPDK_CRYPTODEV_DRIVER_QAT) {
1124 		assert(g_qat_total_qp >= device->cdev_info.max_nb_queue_pairs);
1125 		g_qat_total_qp -= device->cdev_info.max_nb_queue_pairs;
1126 	}
1127 	rte_cryptodev_stop(device->cdev_id);
1128 	rte_cryptodev_close(device->cdev_id);
1129 	free(device);
1130 }
1131 
1132 static int
1133 accel_dpdk_cryptodev_init(void)
1134 {
1135 	uint8_t cdev_count;
1136 	uint8_t cdev_id;
1137 	int i, rc;
1138 	struct accel_dpdk_cryptodev_device *device, *tmp_dev;
1139 	unsigned int max_sess_size = 0, sess_size;
1140 	uint16_t num_lcores = rte_lcore_count();
1141 	char aesni_args[32];
1142 
1143 	/* Only the first call via module init should init the crypto drivers. */
1144 	if (g_session_mp != NULL) {
1145 		return 0;
1146 	}
1147 
1148 	/* We always init ACCEL_DPDK_CRYPTODEV_AESNI_MB */
1149 	snprintf(aesni_args, sizeof(aesni_args), "max_nb_queue_pairs=%d",
1150 		 ACCEL_DPDK_CRYPTODEV_AESNI_MB_NUM_QP);
1151 	rc = rte_vdev_init(ACCEL_DPDK_CRYPTODEV_AESNI_MB, aesni_args);
1152 	if (rc) {
1153 		SPDK_NOTICELOG("Failed to create virtual PMD %s: error %d. "
1154 			       "Possibly %s is not supported by DPDK library. "
1155 			       "Keep going...\n", ACCEL_DPDK_CRYPTODEV_AESNI_MB, rc, ACCEL_DPDK_CRYPTODEV_AESNI_MB);
1156 	}
1157 
1158 	/* If we have no crypto devices, there's no reason to continue. */
1159 	cdev_count = rte_cryptodev_count();
1160 	SPDK_NOTICELOG("Found crypto devices: %d\n", (int)cdev_count);
1161 	if (cdev_count == 0) {
1162 		return 0;
1163 	}
1164 
1165 	g_mbuf_offset = rte_mbuf_dynfield_register(&rte_mbuf_dynfield_io_context);
1166 	if (g_mbuf_offset < 0) {
1167 		SPDK_ERRLOG("error registering dynamic field with DPDK\n");
1168 		return -EINVAL;
1169 	}
1170 
1171 	/* Create global mempools, shared by all devices regardless of type */
1172 	/* First determine max session size, most pools are shared by all the devices,
1173 	 * so we need to find the global max sessions size. */
1174 	for (cdev_id = 0; cdev_id < cdev_count; cdev_id++) {
1175 		sess_size = rte_cryptodev_sym_get_private_session_size(cdev_id);
1176 		if (sess_size > max_sess_size) {
1177 			max_sess_size = sess_size;
1178 		}
1179 	}
1180 
1181 #if RTE_VERSION < RTE_VERSION_NUM(22, 11, 0, 0)
1182 	g_session_mp_priv = rte_mempool_create("dpdk_crypto_ses_mp_priv",
1183 					       ACCEL_DPDK_CRYPTODEV_NUM_SESSIONS, max_sess_size, ACCEL_DPDK_CRYPTODEV_SESS_MEMPOOL_CACHE_SIZE, 0,
1184 					       NULL, NULL, NULL, NULL, SOCKET_ID_ANY, 0);
1185 	if (g_session_mp_priv == NULL) {
1186 		SPDK_ERRLOG("Cannot create private session pool max size 0x%x\n", max_sess_size);
1187 		return -ENOMEM;
1188 	}
1189 
1190 	/* When session private data mempool allocated, the element size for the session mempool
1191 	 * should be 0. */
1192 	max_sess_size = 0;
1193 #endif
1194 
1195 	g_session_mp = rte_cryptodev_sym_session_pool_create("dpdk_crypto_ses_mp",
1196 			ACCEL_DPDK_CRYPTODEV_NUM_SESSIONS, max_sess_size, ACCEL_DPDK_CRYPTODEV_SESS_MEMPOOL_CACHE_SIZE, 0,
1197 			SOCKET_ID_ANY);
1198 	if (g_session_mp == NULL) {
1199 		SPDK_ERRLOG("Cannot create session pool max size 0x%x\n", max_sess_size);
1200 		rc = -ENOMEM;
1201 		goto error_create_session_mp;
1202 	}
1203 
1204 	g_mbuf_mp = rte_pktmbuf_pool_create("dpdk_crypto_mbuf_mp", ACCEL_DPDK_CRYPTODEV_NUM_MBUFS,
1205 					    ACCEL_DPDK_CRYPTODEV_POOL_CACHE_SIZE,
1206 					    0, 0, SPDK_ENV_SOCKET_ID_ANY);
1207 	if (g_mbuf_mp == NULL) {
1208 		SPDK_ERRLOG("Cannot create mbuf pool\n");
1209 		rc = -ENOMEM;
1210 		goto error_create_mbuf;
1211 	}
1212 
1213 	/* We use per op private data as suggested by DPDK and to store the IV and
1214 	 * our own struct for queueing ops. */
1215 	g_crypto_op_mp = rte_crypto_op_pool_create("dpdk_crypto_op_mp",
1216 			 RTE_CRYPTO_OP_TYPE_SYMMETRIC, ACCEL_DPDK_CRYPTODEV_NUM_MBUFS, ACCEL_DPDK_CRYPTODEV_POOL_CACHE_SIZE,
1217 			 (ACCEL_DPDK_CRYPTODEV_DEFAULT_NUM_XFORMS * sizeof(struct rte_crypto_sym_xform)) +
1218 			 ACCEL_DPDK_CRYPTODEV_IV_LENGTH, rte_socket_id());
1219 	if (g_crypto_op_mp == NULL) {
1220 		SPDK_ERRLOG("Cannot create op pool\n");
1221 		rc = -ENOMEM;
1222 		goto error_create_op;
1223 	}
1224 
1225 	/* Init all devices */
1226 	for (i = 0; i < cdev_count; i++) {
1227 		rc = accel_dpdk_cryptodev_create(i, num_lcores);
1228 		if (rc) {
1229 			goto err;
1230 		}
1231 	}
1232 
1233 	g_shinfo.free_cb = shinfo_free_cb;
1234 
1235 	spdk_io_device_register(&g_accel_dpdk_cryptodev_module, _accel_dpdk_cryptodev_create_cb,
1236 				_accel_dpdk_cryptodev_destroy_cb, sizeof(struct accel_dpdk_cryptodev_io_channel),
1237 				"accel_dpdk_cryptodev");
1238 
1239 	return 0;
1240 
1241 	/* Error cleanup paths. */
1242 err:
1243 	TAILQ_FOREACH_SAFE(device, &g_crypto_devices, link, tmp_dev) {
1244 		TAILQ_REMOVE(&g_crypto_devices, device, link);
1245 		accel_dpdk_cryptodev_release(device);
1246 	}
1247 	rte_mempool_free(g_crypto_op_mp);
1248 	g_crypto_op_mp = NULL;
1249 error_create_op:
1250 	rte_mempool_free(g_mbuf_mp);
1251 	g_mbuf_mp = NULL;
1252 error_create_mbuf:
1253 	rte_mempool_free(g_session_mp);
1254 	g_session_mp = NULL;
1255 error_create_session_mp:
1256 	if (g_session_mp_priv != NULL) {
1257 		rte_mempool_free(g_session_mp_priv);
1258 		g_session_mp_priv = NULL;
1259 	}
1260 	return rc;
1261 }
1262 
1263 static void
1264 accel_dpdk_cryptodev_fini_cb(void *io_device)
1265 {
1266 	struct accel_dpdk_cryptodev_device *device, *tmp;
1267 
1268 	TAILQ_FOREACH_SAFE(device, &g_crypto_devices, link, tmp) {
1269 		TAILQ_REMOVE(&g_crypto_devices, device, link);
1270 		accel_dpdk_cryptodev_release(device);
1271 	}
1272 	rte_vdev_uninit(ACCEL_DPDK_CRYPTODEV_AESNI_MB);
1273 
1274 	rte_mempool_free(g_crypto_op_mp);
1275 	rte_mempool_free(g_mbuf_mp);
1276 	rte_mempool_free(g_session_mp);
1277 	if (g_session_mp_priv != NULL) {
1278 		rte_mempool_free(g_session_mp_priv);
1279 	}
1280 
1281 	spdk_accel_module_finish();
1282 }
1283 
1284 /* Called when the entire module is being torn down. */
1285 static void
1286 accel_dpdk_cryptodev_fini(void *ctx)
1287 {
1288 	if (g_crypto_op_mp) {
1289 		spdk_io_device_unregister(&g_accel_dpdk_cryptodev_module, accel_dpdk_cryptodev_fini_cb);
1290 	}
1291 }
1292 
1293 static void
1294 accel_dpdk_cryptodev_key_handle_session_free(struct accel_dpdk_cryptodev_device *device,
1295 		void *session)
1296 {
1297 #if RTE_VERSION >= RTE_VERSION_NUM(22, 11, 0, 0)
1298 	assert(device != NULL);
1299 
1300 	rte_cryptodev_sym_session_free(device->cdev_id, session);
1301 #else
1302 	rte_cryptodev_sym_session_free(session);
1303 #endif
1304 }
1305 
1306 static void *
1307 accel_dpdk_cryptodev_key_handle_session_create(struct accel_dpdk_cryptodev_device *device,
1308 		struct rte_crypto_sym_xform *cipher_xform)
1309 {
1310 	void *session;
1311 
1312 #if RTE_VERSION >= RTE_VERSION_NUM(22, 11, 0, 0)
1313 	session = rte_cryptodev_sym_session_create(device->cdev_id, cipher_xform, g_session_mp);
1314 #else
1315 	session = rte_cryptodev_sym_session_create(g_session_mp);
1316 	if (!session) {
1317 		return NULL;
1318 	}
1319 
1320 	if (rte_cryptodev_sym_session_init(device->cdev_id, session, cipher_xform, g_session_mp_priv) < 0) {
1321 		accel_dpdk_cryptodev_key_handle_session_free(device, session);
1322 		return NULL;
1323 	}
1324 #endif
1325 
1326 	return session;
1327 }
1328 
1329 static int
1330 accel_dpdk_cryptodev_key_handle_configure(struct spdk_accel_crypto_key *key,
1331 		struct accel_dpdk_cryptodev_key_handle *key_handle)
1332 {
1333 	struct accel_dpdk_cryptodev_key_priv *priv = key->priv;
1334 
1335 	key_handle->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
1336 	key_handle->cipher_xform.cipher.iv.offset = ACCEL_DPDK_CRYPTODEV_IV_OFFSET;
1337 	key_handle->cipher_xform.cipher.iv.length = ACCEL_DPDK_CRYPTODEV_IV_LENGTH;
1338 
1339 	switch (priv->cipher) {
1340 	case SPDK_ACCEL_CIPHER_AES_CBC:
1341 		key_handle->cipher_xform.cipher.key.data = key->key;
1342 		key_handle->cipher_xform.cipher.key.length = key->key_size;
1343 		key_handle->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
1344 		break;
1345 	case SPDK_ACCEL_CIPHER_AES_XTS:
1346 		key_handle->cipher_xform.cipher.key.data = priv->xts_key;
1347 		key_handle->cipher_xform.cipher.key.length = key->key_size + key->key2_size;
1348 		key_handle->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_XTS;
1349 		break;
1350 	default:
1351 		SPDK_ERRLOG("Invalid cipher name %s.\n", key->param.cipher);
1352 		return -EINVAL;
1353 	}
1354 
1355 	key_handle->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
1356 	key_handle->session_encrypt = accel_dpdk_cryptodev_key_handle_session_create(key_handle->device,
1357 				      &key_handle->cipher_xform);
1358 	if (!key_handle->session_encrypt) {
1359 		SPDK_ERRLOG("Failed to init encrypt session\n");
1360 		return -EINVAL;
1361 	}
1362 
1363 	key_handle->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
1364 	key_handle->session_decrypt = accel_dpdk_cryptodev_key_handle_session_create(key_handle->device,
1365 				      &key_handle->cipher_xform);
1366 	if (!key_handle->session_decrypt) {
1367 		SPDK_ERRLOG("Failed to init decrypt session:");
1368 		accel_dpdk_cryptodev_key_handle_session_free(key_handle->device, key_handle->session_encrypt);
1369 		return -EINVAL;
1370 	}
1371 
1372 	return 0;
1373 }
1374 
1375 static int
1376 accel_dpdk_cryptodev_validate_parameters(enum accel_dpdk_cryptodev_driver_type driver,
1377 		struct spdk_accel_crypto_key *key)
1378 {
1379 	/* Check that all required parameters exist */
1380 	switch (key->cipher) {
1381 	case SPDK_ACCEL_CIPHER_AES_CBC:
1382 		if (!key->key || !key->key_size) {
1383 			SPDK_ERRLOG("ACCEL_DPDK_CRYPTODEV_AES_CBC requires a key\n");
1384 			return -1;
1385 		}
1386 		if (key->key2 || key->key2_size) {
1387 			SPDK_ERRLOG("ACCEL_DPDK_CRYPTODEV_AES_CBC doesn't use key2\n");
1388 			return -1;
1389 		}
1390 		break;
1391 	case SPDK_ACCEL_CIPHER_AES_XTS:
1392 		break;
1393 	default:
1394 		return -1;
1395 	}
1396 
1397 	/* Check driver/cipher combinations and key lengths */
1398 	switch (key->cipher) {
1399 	case SPDK_ACCEL_CIPHER_AES_CBC:
1400 		if (key->key_size != ACCEL_DPDK_CRYPTODEV_AES_CBC_KEY_LENGTH) {
1401 			SPDK_ERRLOG("Invalid key size %zu for cipher %s, should be %d\n", key->key_size,
1402 				    g_cipher_names[SPDK_ACCEL_CIPHER_AES_CBC], ACCEL_DPDK_CRYPTODEV_AES_CBC_KEY_LENGTH);
1403 			return -1;
1404 		}
1405 		break;
1406 	case SPDK_ACCEL_CIPHER_AES_XTS:
1407 		switch (driver) {
1408 		case ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI:
1409 			if (key->key_size != ACCEL_DPDK_CRYPTODEV_AES_XTS_128_BLOCK_KEY_LENGTH &&
1410 			    key->key_size != ACCEL_DPDK_CRYPTODEV_AES_XTS_256_BLOCK_KEY_LENGTH) {
1411 				SPDK_ERRLOG("Invalid key size %zu for driver %s, cipher %s, supported %d or %d\n",
1412 					    key->key_size, g_driver_names[ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI],
1413 					    g_cipher_names[SPDK_ACCEL_CIPHER_AES_XTS],
1414 					    ACCEL_DPDK_CRYPTODEV_AES_XTS_128_BLOCK_KEY_LENGTH,
1415 					    ACCEL_DPDK_CRYPTODEV_AES_XTS_256_BLOCK_KEY_LENGTH);
1416 				return -1;
1417 			}
1418 			break;
1419 		case ACCEL_DPDK_CRYPTODEV_DRIVER_QAT:
1420 		case ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB:
1421 			if (key->key_size != ACCEL_DPDK_CRYPTODEV_AES_XTS_128_BLOCK_KEY_LENGTH) {
1422 				SPDK_ERRLOG("Invalid key size %zu, supported %d\n", key->key_size,
1423 					    ACCEL_DPDK_CRYPTODEV_AES_XTS_128_BLOCK_KEY_LENGTH);
1424 				return -1;
1425 			}
1426 			break;
1427 		default:
1428 			SPDK_ERRLOG("Incorrect driver type %d\n", driver);
1429 			assert(0);
1430 			return -1;
1431 		}
1432 		break;
1433 	default:
1434 		assert(0);
1435 		return -1;
1436 	}
1437 
1438 	return 0;
1439 }
1440 
1441 static void
1442 accel_dpdk_cryptodev_key_deinit(struct spdk_accel_crypto_key *key)
1443 {
1444 	struct accel_dpdk_cryptodev_key_handle *key_handle, *key_handle_tmp;
1445 	struct accel_dpdk_cryptodev_key_priv *priv = key->priv;
1446 
1447 	TAILQ_FOREACH_SAFE(key_handle, &priv->dev_keys, link, key_handle_tmp) {
1448 		accel_dpdk_cryptodev_key_handle_session_free(key_handle->device, key_handle->session_encrypt);
1449 		accel_dpdk_cryptodev_key_handle_session_free(key_handle->device, key_handle->session_decrypt);
1450 		TAILQ_REMOVE(&priv->dev_keys, key_handle, link);
1451 		spdk_memset_s(key_handle, sizeof(*key_handle), 0, sizeof(*key_handle));
1452 		free(key_handle);
1453 	}
1454 
1455 	if (priv->xts_key) {
1456 		spdk_memset_s(priv->xts_key, key->key_size + key->key2_size, 0, key->key_size + key->key2_size);
1457 	}
1458 	free(priv->xts_key);
1459 	free(priv);
1460 }
1461 
1462 static bool
1463 accel_dpdk_cryptodev_supports_cipher(enum spdk_accel_cipher cipher)
1464 {
1465 	switch (g_dpdk_cryptodev_driver) {
1466 	case ACCEL_DPDK_CRYPTODEV_DRIVER_QAT:
1467 	case ACCEL_DPDK_CRYPTODEV_DRIVER_AESNI_MB:
1468 		return cipher == SPDK_ACCEL_CIPHER_AES_XTS || cipher == SPDK_ACCEL_CIPHER_AES_CBC;
1469 	case ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI:
1470 		return cipher == SPDK_ACCEL_CIPHER_AES_XTS;
1471 	default:
1472 		return false;
1473 	}
1474 }
1475 
1476 static int
1477 accel_dpdk_cryptodev_key_init(struct spdk_accel_crypto_key *key)
1478 {
1479 	struct accel_dpdk_cryptodev_device *device;
1480 	struct accel_dpdk_cryptodev_key_priv *priv;
1481 	struct accel_dpdk_cryptodev_key_handle *key_handle;
1482 	enum accel_dpdk_cryptodev_driver_type driver;
1483 	int rc;
1484 
1485 	driver = g_dpdk_cryptodev_driver;
1486 
1487 	if (accel_dpdk_cryptodev_validate_parameters(driver, key)) {
1488 		return -EINVAL;
1489 	}
1490 
1491 	priv = calloc(1, sizeof(*priv));
1492 	if (!priv) {
1493 		SPDK_ERRLOG("Memory allocation failed\n");
1494 		return -ENOMEM;
1495 	}
1496 	key->priv = priv;
1497 	priv->driver = driver;
1498 	priv->cipher = key->cipher;
1499 	TAILQ_INIT(&priv->dev_keys);
1500 
1501 	if (key->cipher == SPDK_ACCEL_CIPHER_AES_XTS) {
1502 		/* DPDK expects the keys to be concatenated together. */
1503 		priv->xts_key = calloc(key->key_size + key->key2_size + 1, sizeof(char));
1504 		if (!priv->xts_key) {
1505 			SPDK_ERRLOG("Memory allocation failed\n");
1506 			accel_dpdk_cryptodev_key_deinit(key);
1507 			return -ENOMEM;
1508 		}
1509 		memcpy(priv->xts_key, key->key, key->key_size);
1510 		memcpy(priv->xts_key + key->key_size, key->key2, key->key2_size);
1511 	}
1512 
1513 	pthread_mutex_lock(&g_device_lock);
1514 	TAILQ_FOREACH(device, &g_crypto_devices, link) {
1515 		if (device->type != driver) {
1516 			continue;
1517 		}
1518 		key_handle = calloc(1, sizeof(*key_handle));
1519 		if (!key_handle) {
1520 			pthread_mutex_unlock(&g_device_lock);
1521 			accel_dpdk_cryptodev_key_deinit(key);
1522 			return -ENOMEM;
1523 		}
1524 		key_handle->device = device;
1525 		TAILQ_INSERT_TAIL(&priv->dev_keys, key_handle, link);
1526 		rc = accel_dpdk_cryptodev_key_handle_configure(key, key_handle);
1527 		if (rc) {
1528 			pthread_mutex_unlock(&g_device_lock);
1529 			accel_dpdk_cryptodev_key_deinit(key);
1530 			return rc;
1531 		}
1532 		if (driver != ACCEL_DPDK_CRYPTODEV_DRIVER_MLX5_PCI) {
1533 			/* For MLX5_PCI we need to register a key on each device since
1534 			 * the key is bound to a specific Protection Domain,
1535 			 * so don't break the loop */
1536 			break;
1537 		}
1538 	}
1539 	pthread_mutex_unlock(&g_device_lock);
1540 
1541 	if (TAILQ_EMPTY(&priv->dev_keys)) {
1542 		free(priv);
1543 		return -ENODEV;
1544 	}
1545 
1546 	return 0;
1547 }
1548 
1549 static void
1550 accel_dpdk_cryptodev_write_config_json(struct spdk_json_write_ctx *w)
1551 {
1552 	spdk_json_write_object_begin(w);
1553 	spdk_json_write_named_string(w, "method", "dpdk_cryptodev_scan_accel_module");
1554 	spdk_json_write_object_end(w);
1555 
1556 	spdk_json_write_object_begin(w);
1557 	spdk_json_write_named_string(w, "method", "dpdk_cryptodev_set_driver");
1558 	spdk_json_write_named_object_begin(w, "params");
1559 	spdk_json_write_named_string(w, "driver_name", g_driver_names[g_dpdk_cryptodev_driver]);
1560 	spdk_json_write_object_end(w);
1561 	spdk_json_write_object_end(w);
1562 }
1563 
1564 static struct spdk_accel_module_if g_accel_dpdk_cryptodev_module = {
1565 	.module_init		= accel_dpdk_cryptodev_init,
1566 	.module_fini		= accel_dpdk_cryptodev_fini,
1567 	.write_config_json	= accel_dpdk_cryptodev_write_config_json,
1568 	.get_ctx_size		= accel_dpdk_cryptodev_ctx_size,
1569 	.name			= "dpdk_cryptodev",
1570 	.supports_opcode	= accel_dpdk_cryptodev_supports_opcode,
1571 	.get_io_channel		= accel_dpdk_cryptodev_get_io_channel,
1572 	.submit_tasks		= accel_dpdk_cryptodev_submit_tasks,
1573 	.crypto_key_init	= accel_dpdk_cryptodev_key_init,
1574 	.crypto_key_deinit	= accel_dpdk_cryptodev_key_deinit,
1575 	.crypto_supports_cipher	= accel_dpdk_cryptodev_supports_cipher,
1576 };
1577