xref: /dpdk/drivers/crypto/ionic/ionic_crypto_ops.c (revision 54d56aba175f19918975bf5e88f5e39aca41c9bc)
1dddfb0d9SAndrew Boyer /* SPDX-License-Identifier: BSD-3-Clause
2dddfb0d9SAndrew Boyer  * Copyright 2021-2024 Advanced Micro Devices, Inc.
3dddfb0d9SAndrew Boyer  */
4dddfb0d9SAndrew Boyer 
5dddfb0d9SAndrew Boyer #include <rte_cryptodev.h>
6dddfb0d9SAndrew Boyer #include <cryptodev_pmd.h>
7dddfb0d9SAndrew Boyer #include <rte_errno.h>
8dddfb0d9SAndrew Boyer #include <rte_malloc.h>
9dddfb0d9SAndrew Boyer #include <rte_mempool.h>
10dddfb0d9SAndrew Boyer 
11dddfb0d9SAndrew Boyer #include "ionic_crypto.h"
12dddfb0d9SAndrew Boyer 
13dddfb0d9SAndrew Boyer static int
14dddfb0d9SAndrew Boyer iocpt_op_config(struct rte_cryptodev *cdev,
15dddfb0d9SAndrew Boyer 		struct rte_cryptodev_config *config __rte_unused)
16dddfb0d9SAndrew Boyer {
17dddfb0d9SAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
18dddfb0d9SAndrew Boyer 
19dddfb0d9SAndrew Boyer 	iocpt_configure(dev);
20dddfb0d9SAndrew Boyer 
21dddfb0d9SAndrew Boyer 	return 0;
22dddfb0d9SAndrew Boyer }
23dddfb0d9SAndrew Boyer 
24dddfb0d9SAndrew Boyer static int
2580518852SAndrew Boyer iocpt_op_start(struct rte_cryptodev *cdev)
2680518852SAndrew Boyer {
2780518852SAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
2880518852SAndrew Boyer 
2980518852SAndrew Boyer 	return iocpt_start(dev);
3080518852SAndrew Boyer }
3180518852SAndrew Boyer 
3280518852SAndrew Boyer static void
3380518852SAndrew Boyer iocpt_op_stop(struct rte_cryptodev *cdev)
3480518852SAndrew Boyer {
3580518852SAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
3680518852SAndrew Boyer 
3780518852SAndrew Boyer 	return iocpt_stop(dev);
3880518852SAndrew Boyer }
3980518852SAndrew Boyer 
4080518852SAndrew Boyer static int
41dddfb0d9SAndrew Boyer iocpt_op_close(struct rte_cryptodev *cdev)
42dddfb0d9SAndrew Boyer {
43dddfb0d9SAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
44dddfb0d9SAndrew Boyer 
45dddfb0d9SAndrew Boyer 	iocpt_deinit(dev);
46dddfb0d9SAndrew Boyer 
47dddfb0d9SAndrew Boyer 	return 0;
48dddfb0d9SAndrew Boyer }
49dddfb0d9SAndrew Boyer 
50dddfb0d9SAndrew Boyer static void
51dddfb0d9SAndrew Boyer iocpt_op_info_get(struct rte_cryptodev *cdev, struct rte_cryptodev_info *info)
52dddfb0d9SAndrew Boyer {
53dddfb0d9SAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
54dddfb0d9SAndrew Boyer 
55dddfb0d9SAndrew Boyer 	if (info == NULL)
56dddfb0d9SAndrew Boyer 		return;
57dddfb0d9SAndrew Boyer 
58dddfb0d9SAndrew Boyer 	info->max_nb_queue_pairs = dev->max_qps;
59dddfb0d9SAndrew Boyer 	info->feature_flags = dev->features;
60dddfb0d9SAndrew Boyer 	info->capabilities = iocpt_get_caps(info->feature_flags);
61*54d56abaSAndrew Boyer 	/* Reserve one session for watchdog */
62*54d56abaSAndrew Boyer 	info->sym.max_nb_sessions = dev->max_sessions - 1;
63dddfb0d9SAndrew Boyer 	info->driver_id = dev->driver_id;
64dddfb0d9SAndrew Boyer 	info->min_mbuf_headroom_req = 0;
65dddfb0d9SAndrew Boyer 	info->min_mbuf_tailroom_req = 0;
66dddfb0d9SAndrew Boyer }
67dddfb0d9SAndrew Boyer 
6880518852SAndrew Boyer static int
6980518852SAndrew Boyer iocpt_op_queue_release(struct rte_cryptodev *cdev, uint16_t queue_id)
7080518852SAndrew Boyer {
7180518852SAndrew Boyer 	struct iocpt_crypto_q *cptq = cdev->data->queue_pairs[queue_id];
7280518852SAndrew Boyer 
7380518852SAndrew Boyer 	IOCPT_PRINT(DEBUG, "queue_id %u", queue_id);
7480518852SAndrew Boyer 
7580518852SAndrew Boyer 	assert(!(cptq->flags & IOCPT_Q_F_INITED));
7680518852SAndrew Boyer 
7780518852SAndrew Boyer 	iocpt_cryptoq_free(cptq);
7880518852SAndrew Boyer 
7980518852SAndrew Boyer 	cdev->data->queue_pairs[queue_id] = NULL;
8080518852SAndrew Boyer 
8180518852SAndrew Boyer 	return 0;
8280518852SAndrew Boyer }
8380518852SAndrew Boyer 
8480518852SAndrew Boyer static int
8580518852SAndrew Boyer iocpt_op_queue_setup(struct rte_cryptodev *cdev, uint16_t queue_id,
8680518852SAndrew Boyer 		const struct rte_cryptodev_qp_conf *qp_conf,
8780518852SAndrew Boyer 		int socket_id)
8880518852SAndrew Boyer {
8980518852SAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
9080518852SAndrew Boyer 	int err;
9180518852SAndrew Boyer 
9280518852SAndrew Boyer 	if (cdev->data->queue_pairs[queue_id] != NULL)
9380518852SAndrew Boyer 		iocpt_op_queue_release(cdev, queue_id);
9480518852SAndrew Boyer 
9580518852SAndrew Boyer 	if (qp_conf->nb_descriptors < (1 << IOCPT_QSIZE_MIN_LG2) ||
9680518852SAndrew Boyer 	    qp_conf->nb_descriptors > (1 << IOCPT_QSIZE_MAX_LG2)) {
9780518852SAndrew Boyer 		IOCPT_PRINT(ERR, "invalid nb_descriptors %u, use range %u..%u",
9880518852SAndrew Boyer 			qp_conf->nb_descriptors,
9980518852SAndrew Boyer 			1 << IOCPT_QSIZE_MIN_LG2, 1 << IOCPT_QSIZE_MAX_LG2);
10080518852SAndrew Boyer 		return -ERANGE;
10180518852SAndrew Boyer 	}
10280518852SAndrew Boyer 
10380518852SAndrew Boyer 	IOCPT_PRINT(DEBUG, "queue_id %u", queue_id);
10480518852SAndrew Boyer 
10580518852SAndrew Boyer 	err = iocpt_cryptoq_alloc(dev, socket_id, queue_id,
10680518852SAndrew Boyer 				qp_conf->nb_descriptors);
10780518852SAndrew Boyer 	if (err != 0)
10880518852SAndrew Boyer 		return err;
10980518852SAndrew Boyer 
11080518852SAndrew Boyer 	cdev->data->queue_pairs[queue_id] = dev->cryptoqs[queue_id];
11180518852SAndrew Boyer 
11280518852SAndrew Boyer 	return 0;
11380518852SAndrew Boyer }
11480518852SAndrew Boyer 
1156bc7f2cfSAndrew Boyer static unsigned int
1166bc7f2cfSAndrew Boyer iocpt_op_get_session_size(struct rte_cryptodev *cdev __rte_unused)
1176bc7f2cfSAndrew Boyer {
1186bc7f2cfSAndrew Boyer 	return iocpt_session_size();
1196bc7f2cfSAndrew Boyer }
1206bc7f2cfSAndrew Boyer 
1216bc7f2cfSAndrew Boyer static inline int
1226bc7f2cfSAndrew Boyer iocpt_is_algo_supported(struct rte_crypto_sym_xform *xform)
1236bc7f2cfSAndrew Boyer {
1246bc7f2cfSAndrew Boyer 	if (xform->next != NULL) {
1256bc7f2cfSAndrew Boyer 		IOCPT_PRINT(ERR, "chaining not supported");
1266bc7f2cfSAndrew Boyer 		return -ENOTSUP;
1276bc7f2cfSAndrew Boyer 	}
1286bc7f2cfSAndrew Boyer 
1296bc7f2cfSAndrew Boyer 	if (xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) {
1306bc7f2cfSAndrew Boyer 		IOCPT_PRINT(ERR, "xform->type %d not supported", xform->type);
1316bc7f2cfSAndrew Boyer 		return -ENOTSUP;
1326bc7f2cfSAndrew Boyer 	}
1336bc7f2cfSAndrew Boyer 
1346bc7f2cfSAndrew Boyer 	return 0;
1356bc7f2cfSAndrew Boyer }
1366bc7f2cfSAndrew Boyer 
1376bc7f2cfSAndrew Boyer static __rte_always_inline int
1386bc7f2cfSAndrew Boyer iocpt_fill_sess_aead(struct rte_crypto_sym_xform *xform,
1396bc7f2cfSAndrew Boyer 		struct iocpt_session_priv *priv)
1406bc7f2cfSAndrew Boyer {
1416bc7f2cfSAndrew Boyer 	struct rte_crypto_aead_xform *aead_form = &xform->aead;
1426bc7f2cfSAndrew Boyer 
1436bc7f2cfSAndrew Boyer 	if (aead_form->algo != RTE_CRYPTO_AEAD_AES_GCM) {
1446bc7f2cfSAndrew Boyer 		IOCPT_PRINT(ERR, "Unknown algo");
1456bc7f2cfSAndrew Boyer 		return -EINVAL;
1466bc7f2cfSAndrew Boyer 	}
1476bc7f2cfSAndrew Boyer 	if (aead_form->op == RTE_CRYPTO_AEAD_OP_ENCRYPT) {
1486bc7f2cfSAndrew Boyer 		priv->op = IOCPT_DESC_OPCODE_GCM_AEAD_ENCRYPT;
1496bc7f2cfSAndrew Boyer 	} else if (aead_form->op == RTE_CRYPTO_AEAD_OP_DECRYPT) {
1506bc7f2cfSAndrew Boyer 		priv->op = IOCPT_DESC_OPCODE_GCM_AEAD_DECRYPT;
1516bc7f2cfSAndrew Boyer 	} else {
1526bc7f2cfSAndrew Boyer 		IOCPT_PRINT(ERR, "Unknown cipher operations");
1536bc7f2cfSAndrew Boyer 		return -1;
1546bc7f2cfSAndrew Boyer 	}
1556bc7f2cfSAndrew Boyer 
1566bc7f2cfSAndrew Boyer 	if (aead_form->key.length < IOCPT_SESS_KEY_LEN_MIN ||
1576bc7f2cfSAndrew Boyer 	    aead_form->key.length > IOCPT_SESS_KEY_LEN_MAX_SYMM) {
1586bc7f2cfSAndrew Boyer 		IOCPT_PRINT(ERR, "Invalid cipher keylen %u",
1596bc7f2cfSAndrew Boyer 			aead_form->key.length);
1606bc7f2cfSAndrew Boyer 		return -1;
1616bc7f2cfSAndrew Boyer 	}
1626bc7f2cfSAndrew Boyer 	priv->key_len = aead_form->key.length;
1636bc7f2cfSAndrew Boyer 	memcpy(priv->key, aead_form->key.data, priv->key_len);
1646bc7f2cfSAndrew Boyer 
1656bc7f2cfSAndrew Boyer 	priv->type = IOCPT_SESS_AEAD_AES_GCM;
1666bc7f2cfSAndrew Boyer 	priv->iv_offset = aead_form->iv.offset;
1676bc7f2cfSAndrew Boyer 	priv->iv_length = aead_form->iv.length;
1686bc7f2cfSAndrew Boyer 	priv->digest_length = aead_form->digest_length;
1696bc7f2cfSAndrew Boyer 	priv->aad_length = aead_form->aad_length;
1706bc7f2cfSAndrew Boyer 
1716bc7f2cfSAndrew Boyer 	return 0;
1726bc7f2cfSAndrew Boyer }
1736bc7f2cfSAndrew Boyer 
1746bc7f2cfSAndrew Boyer static int
1756bc7f2cfSAndrew Boyer iocpt_session_cfg(struct iocpt_dev *dev,
1766bc7f2cfSAndrew Boyer 		struct rte_crypto_sym_xform *xform,
1776bc7f2cfSAndrew Boyer 		struct rte_cryptodev_sym_session *sess)
1786bc7f2cfSAndrew Boyer {
1796bc7f2cfSAndrew Boyer 	struct rte_crypto_sym_xform *chain;
1806bc7f2cfSAndrew Boyer 	struct iocpt_session_priv *priv = NULL;
1816bc7f2cfSAndrew Boyer 
1826bc7f2cfSAndrew Boyer 	if (iocpt_is_algo_supported(xform) < 0)
1836bc7f2cfSAndrew Boyer 		return -ENOTSUP;
1846bc7f2cfSAndrew Boyer 
1856bc7f2cfSAndrew Boyer 	if (unlikely(sess == NULL)) {
1866bc7f2cfSAndrew Boyer 		IOCPT_PRINT(ERR, "invalid session");
1876bc7f2cfSAndrew Boyer 		return -EINVAL;
1886bc7f2cfSAndrew Boyer 	}
1896bc7f2cfSAndrew Boyer 
1906bc7f2cfSAndrew Boyer 	priv = CRYPTODEV_GET_SYM_SESS_PRIV(sess);
1916bc7f2cfSAndrew Boyer 	priv->dev = dev;
1926bc7f2cfSAndrew Boyer 
1936bc7f2cfSAndrew Boyer 	chain = xform;
1946bc7f2cfSAndrew Boyer 	while (chain) {
1956bc7f2cfSAndrew Boyer 		switch (chain->type) {
1966bc7f2cfSAndrew Boyer 		case RTE_CRYPTO_SYM_XFORM_AEAD:
1976bc7f2cfSAndrew Boyer 			if (iocpt_fill_sess_aead(chain, priv))
1986bc7f2cfSAndrew Boyer 				return -EIO;
1996bc7f2cfSAndrew Boyer 			break;
2006bc7f2cfSAndrew Boyer 		default:
2016bc7f2cfSAndrew Boyer 			IOCPT_PRINT(ERR, "invalid crypto xform type %d",
2026bc7f2cfSAndrew Boyer 				chain->type);
2036bc7f2cfSAndrew Boyer 			return -ENOTSUP;
2046bc7f2cfSAndrew Boyer 		}
2056bc7f2cfSAndrew Boyer 		chain = chain->next;
2066bc7f2cfSAndrew Boyer 	}
2076bc7f2cfSAndrew Boyer 
2086bc7f2cfSAndrew Boyer 	return iocpt_session_init(priv);
2096bc7f2cfSAndrew Boyer }
2106bc7f2cfSAndrew Boyer 
2116bc7f2cfSAndrew Boyer static int
2126bc7f2cfSAndrew Boyer iocpt_op_session_cfg(struct rte_cryptodev *cdev,
2136bc7f2cfSAndrew Boyer 		struct rte_crypto_sym_xform *xform,
2146bc7f2cfSAndrew Boyer 		struct rte_cryptodev_sym_session *sess)
2156bc7f2cfSAndrew Boyer {
2166bc7f2cfSAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
2176bc7f2cfSAndrew Boyer 
2186bc7f2cfSAndrew Boyer 	return iocpt_session_cfg(dev, xform, sess);
2196bc7f2cfSAndrew Boyer }
2206bc7f2cfSAndrew Boyer 
2216bc7f2cfSAndrew Boyer static void
2226bc7f2cfSAndrew Boyer iocpt_session_clear(struct rte_cryptodev_sym_session *sess)
2236bc7f2cfSAndrew Boyer {
2246bc7f2cfSAndrew Boyer 	iocpt_session_deinit(CRYPTODEV_GET_SYM_SESS_PRIV(sess));
2256bc7f2cfSAndrew Boyer }
2266bc7f2cfSAndrew Boyer 
2276bc7f2cfSAndrew Boyer static void
2286bc7f2cfSAndrew Boyer iocpt_op_session_clear(struct rte_cryptodev *cdev __rte_unused,
2296bc7f2cfSAndrew Boyer 		struct rte_cryptodev_sym_session *sess)
2306bc7f2cfSAndrew Boyer {
2316bc7f2cfSAndrew Boyer 	iocpt_session_clear(sess);
2326bc7f2cfSAndrew Boyer }
2336bc7f2cfSAndrew Boyer 
23480518852SAndrew Boyer static inline void
23580518852SAndrew Boyer iocpt_fill_sge(struct iocpt_crypto_sg_elem *arr, uint8_t idx,
23680518852SAndrew Boyer 		uint64_t addr, uint16_t len)
23780518852SAndrew Boyer {
23880518852SAndrew Boyer 	arr[idx].addr = rte_cpu_to_le_64(addr);
23980518852SAndrew Boyer 	arr[idx].len = rte_cpu_to_le_16(len);
24080518852SAndrew Boyer }
24180518852SAndrew Boyer 
24280518852SAndrew Boyer static __rte_always_inline int
24380518852SAndrew Boyer iocpt_enq_one_aead(struct iocpt_crypto_q *cptq,
24480518852SAndrew Boyer 		struct iocpt_session_priv *priv, struct rte_crypto_op *op)
24580518852SAndrew Boyer {
24680518852SAndrew Boyer 	struct rte_crypto_sym_op *sym_op = op->sym;
24780518852SAndrew Boyer 	struct iocpt_queue *q = &cptq->q;
24880518852SAndrew Boyer 	struct iocpt_crypto_desc *desc, *desc_base = q->base;
24980518852SAndrew Boyer 	struct iocpt_crypto_sg_desc *sg_desc, *sg_desc_base = q->sg_base;
25080518852SAndrew Boyer 	struct iocpt_crypto_sg_elem *src, *dst;
25180518852SAndrew Boyer 	rte_iova_t aad_addr, digest_addr, iv_addr, seg_addr;
25280518852SAndrew Boyer 	uint32_t data_len, data_offset, seg_len;
25380518852SAndrew Boyer 	uint8_t nsge_src = 0, nsge_dst = 0, flags = 0;
25480518852SAndrew Boyer 	struct rte_mbuf *m;
25580518852SAndrew Boyer 
25680518852SAndrew Boyer 	desc = &desc_base[q->head_idx];
25780518852SAndrew Boyer 	sg_desc = &sg_desc_base[q->head_idx];
25880518852SAndrew Boyer 	src = sg_desc->src_elems;
25980518852SAndrew Boyer 	dst = sg_desc->dst_elems;
26080518852SAndrew Boyer 
26180518852SAndrew Boyer 	/* Fill the first SGE with the IV / Nonce */
26280518852SAndrew Boyer 	iv_addr = rte_crypto_op_ctophys_offset(op, priv->iv_offset);
26380518852SAndrew Boyer 	iocpt_fill_sge(src, nsge_src++, iv_addr, priv->iv_length);
26480518852SAndrew Boyer 
26580518852SAndrew Boyer 	/* Fill the second SGE with the AAD, if applicable */
26680518852SAndrew Boyer 	if (priv->aad_length > 0) {
26780518852SAndrew Boyer 		aad_addr = sym_op->aead.aad.phys_addr;
26880518852SAndrew Boyer 		iocpt_fill_sge(src, nsge_src++, aad_addr, priv->aad_length);
26980518852SAndrew Boyer 		flags |= IOCPT_DESC_F_AAD_VALID;
27080518852SAndrew Boyer 	}
27180518852SAndrew Boyer 
27280518852SAndrew Boyer 	m = sym_op->m_src;
27380518852SAndrew Boyer 	data_len = sym_op->aead.data.length;
27480518852SAndrew Boyer 
27580518852SAndrew Boyer 	/* Fast-forward through mbuf chain to account for data offset */
27680518852SAndrew Boyer 	data_offset = sym_op->aead.data.offset;
27780518852SAndrew Boyer 	while (m != NULL && data_offset >= m->data_len) {
27880518852SAndrew Boyer 		data_offset -= m->data_len;
27980518852SAndrew Boyer 		m = m->next;
28080518852SAndrew Boyer 	}
28180518852SAndrew Boyer 
28280518852SAndrew Boyer 	/* Fill the next SGEs with the payload segments */
28380518852SAndrew Boyer 	while (m != NULL && data_len > 0) {
28480518852SAndrew Boyer 		seg_addr = rte_mbuf_data_iova(m) + data_offset;
28580518852SAndrew Boyer 		seg_len = RTE_MIN(m->data_len - data_offset, data_len);
28680518852SAndrew Boyer 		data_offset = 0;
28780518852SAndrew Boyer 		data_len -= seg_len;
28880518852SAndrew Boyer 
28980518852SAndrew Boyer 		/* Use -1 to save room for digest */
29080518852SAndrew Boyer 		if (nsge_src >= IOCPT_CRYPTO_MAX_SG_ELEMS - 1)
29180518852SAndrew Boyer 			return -ERANGE;
29280518852SAndrew Boyer 
29380518852SAndrew Boyer 		iocpt_fill_sge(src, nsge_src++, seg_addr, seg_len);
29480518852SAndrew Boyer 
29580518852SAndrew Boyer 		m = m->next;
29680518852SAndrew Boyer 	}
29780518852SAndrew Boyer 
29880518852SAndrew Boyer 	/* AEAD AES-GCM: digest == authentication tag */
29980518852SAndrew Boyer 	digest_addr = sym_op->aead.digest.phys_addr;
30080518852SAndrew Boyer 	iocpt_fill_sge(src, nsge_src++, digest_addr, priv->digest_length);
30180518852SAndrew Boyer 
30280518852SAndrew Boyer 	/* Process Out-Of-Place destination SGL */
30380518852SAndrew Boyer 	if (sym_op->m_dst != NULL) {
30480518852SAndrew Boyer 		/* Put the AAD here, too */
30580518852SAndrew Boyer 		if (priv->aad_length > 0)
30680518852SAndrew Boyer 			iocpt_fill_sge(dst, nsge_dst++,
30780518852SAndrew Boyer 				sym_op->aead.aad.phys_addr, priv->aad_length);
30880518852SAndrew Boyer 
30980518852SAndrew Boyer 		m = sym_op->m_dst;
31080518852SAndrew Boyer 		data_len = sym_op->aead.data.length;
31180518852SAndrew Boyer 
31280518852SAndrew Boyer 		/* Fast-forward through chain to account for data offset */
31380518852SAndrew Boyer 		data_offset = sym_op->aead.data.offset;
31480518852SAndrew Boyer 		while (m != NULL && data_offset >= m->data_len) {
31580518852SAndrew Boyer 			data_offset -= m->data_len;
31680518852SAndrew Boyer 			m = m->next;
31780518852SAndrew Boyer 		}
31880518852SAndrew Boyer 
31980518852SAndrew Boyer 		/* Fill in the SGEs with the payload segments */
32080518852SAndrew Boyer 		while (m != NULL && data_len > 0) {
32180518852SAndrew Boyer 			seg_addr = rte_mbuf_data_iova(m) + data_offset;
32280518852SAndrew Boyer 			seg_len = RTE_MIN(m->data_len - data_offset, data_len);
32380518852SAndrew Boyer 			data_offset = 0;
32480518852SAndrew Boyer 			data_len -= seg_len;
32580518852SAndrew Boyer 
32680518852SAndrew Boyer 			if (nsge_dst >= IOCPT_CRYPTO_MAX_SG_ELEMS)
32780518852SAndrew Boyer 				return -ERANGE;
32880518852SAndrew Boyer 
32980518852SAndrew Boyer 			iocpt_fill_sge(dst, nsge_dst++, seg_addr, seg_len);
33080518852SAndrew Boyer 
33180518852SAndrew Boyer 			m = m->next;
33280518852SAndrew Boyer 		}
33380518852SAndrew Boyer 	}
33480518852SAndrew Boyer 
33580518852SAndrew Boyer 	desc->opcode = priv->op;
33680518852SAndrew Boyer 	desc->flags = flags;
33780518852SAndrew Boyer 	desc->num_src_dst_sgs = iocpt_encode_nsge_src_dst(nsge_src, nsge_dst);
33880518852SAndrew Boyer 	desc->session_tag = rte_cpu_to_le_32(priv->index);
33980518852SAndrew Boyer 
34080518852SAndrew Boyer 	op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
34180518852SAndrew Boyer 	q->info[q->head_idx] = op;
34280518852SAndrew Boyer 	q->head_idx = Q_NEXT_TO_POST(q, 1);
34380518852SAndrew Boyer 
34480518852SAndrew Boyer 	return 0;
34580518852SAndrew Boyer }
34680518852SAndrew Boyer 
34780518852SAndrew Boyer static uint16_t
34880518852SAndrew Boyer iocpt_enqueue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
34980518852SAndrew Boyer {
35080518852SAndrew Boyer 	struct iocpt_crypto_q *cptq = qp;
35180518852SAndrew Boyer 	struct rte_crypto_op *op;
35280518852SAndrew Boyer 	struct iocpt_session_priv *priv;
35380518852SAndrew Boyer 	uint16_t avail, count;
35480518852SAndrew Boyer 	int err;
35580518852SAndrew Boyer 
35680518852SAndrew Boyer 	avail = iocpt_q_space_avail(&cptq->q);
35780518852SAndrew Boyer 	if (unlikely(nb_ops > avail))
35880518852SAndrew Boyer 		nb_ops = avail;
35980518852SAndrew Boyer 
36080518852SAndrew Boyer 	count = 0;
36180518852SAndrew Boyer 	while (likely(count < nb_ops)) {
36280518852SAndrew Boyer 		op = ops[count];
36380518852SAndrew Boyer 
36480518852SAndrew Boyer 		if (unlikely(op->sess_type != RTE_CRYPTO_OP_WITH_SESSION)) {
36580518852SAndrew Boyer 			op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
36680518852SAndrew Boyer 			break;
36780518852SAndrew Boyer 		}
36880518852SAndrew Boyer 
36980518852SAndrew Boyer 		priv = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
37080518852SAndrew Boyer 		if (unlikely(priv == NULL)) {
37180518852SAndrew Boyer 			op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
37280518852SAndrew Boyer 			break;
37380518852SAndrew Boyer 		}
37480518852SAndrew Boyer 
37580518852SAndrew Boyer 		err = iocpt_enq_one_aead(cptq, priv, op);
37680518852SAndrew Boyer 		if (unlikely(err != 0)) {
37780518852SAndrew Boyer 			op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
37880518852SAndrew Boyer 			break;
37980518852SAndrew Boyer 		}
38080518852SAndrew Boyer 
38180518852SAndrew Boyer 		count++;
38280518852SAndrew Boyer 	}
38380518852SAndrew Boyer 
384*54d56abaSAndrew Boyer 	if (likely(count > 0)) {
38580518852SAndrew Boyer 		iocpt_q_flush(&cptq->q);
38680518852SAndrew Boyer 
387*54d56abaSAndrew Boyer 		/* Restart timer if ops are being enqueued */
388*54d56abaSAndrew Boyer 		cptq->last_wdog_cycles = rte_get_timer_cycles();
389*54d56abaSAndrew Boyer 	}
390*54d56abaSAndrew Boyer 
39180518852SAndrew Boyer 	return count;
39280518852SAndrew Boyer }
39380518852SAndrew Boyer 
394*54d56abaSAndrew Boyer static void
395*54d56abaSAndrew Boyer iocpt_enqueue_wdog(struct iocpt_crypto_q *cptq)
396*54d56abaSAndrew Boyer {
397*54d56abaSAndrew Boyer 	struct iocpt_queue *q = &cptq->q;
398*54d56abaSAndrew Boyer 	struct iocpt_crypto_desc *desc, *desc_base = q->base;
399*54d56abaSAndrew Boyer 	struct iocpt_crypto_sg_desc *sg_desc, *sg_desc_base = q->sg_base;
400*54d56abaSAndrew Boyer 	struct iocpt_crypto_sg_elem *src;
401*54d56abaSAndrew Boyer 	struct rte_crypto_op *wdog_op;
402*54d56abaSAndrew Boyer 	rte_iova_t iv_addr, pld_addr, tag_addr;
403*54d56abaSAndrew Boyer 	uint8_t nsge_src = 0;
404*54d56abaSAndrew Boyer 	uint16_t avail;
405*54d56abaSAndrew Boyer 
406*54d56abaSAndrew Boyer 	avail = iocpt_q_space_avail(&cptq->q);
407*54d56abaSAndrew Boyer 	if (avail < 1)
408*54d56abaSAndrew Boyer 		goto out_flush;
409*54d56abaSAndrew Boyer 
410*54d56abaSAndrew Boyer 	wdog_op = rte_zmalloc_socket("iocpt", sizeof(*wdog_op),
411*54d56abaSAndrew Boyer 				RTE_CACHE_LINE_SIZE, rte_socket_id());
412*54d56abaSAndrew Boyer 	if (wdog_op == NULL)
413*54d56abaSAndrew Boyer 		goto out_flush;
414*54d56abaSAndrew Boyer 
415*54d56abaSAndrew Boyer 	wdog_op->type = IOCPT_Q_WDOG_OP_TYPE;
416*54d56abaSAndrew Boyer 	wdog_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
417*54d56abaSAndrew Boyer 
418*54d56abaSAndrew Boyer 	desc = &desc_base[q->head_idx];
419*54d56abaSAndrew Boyer 	sg_desc = &sg_desc_base[q->head_idx];
420*54d56abaSAndrew Boyer 	src = sg_desc->src_elems;
421*54d56abaSAndrew Boyer 
422*54d56abaSAndrew Boyer 	/* Fill the first SGE with the IV / Nonce */
423*54d56abaSAndrew Boyer 	iv_addr = rte_mem_virt2iova(cptq->wdog_iv);
424*54d56abaSAndrew Boyer 	iocpt_fill_sge(src, nsge_src++, iv_addr, IOCPT_Q_WDOG_IV_LEN);
425*54d56abaSAndrew Boyer 
426*54d56abaSAndrew Boyer 	/* Fill the second SGE with the payload segment */
427*54d56abaSAndrew Boyer 	pld_addr = rte_mem_virt2iova(cptq->wdog_pld);
428*54d56abaSAndrew Boyer 	iocpt_fill_sge(src, nsge_src++, pld_addr, IOCPT_Q_WDOG_PLD_LEN);
429*54d56abaSAndrew Boyer 
430*54d56abaSAndrew Boyer 	/* AEAD AES-GCM: digest == authentication tag */
431*54d56abaSAndrew Boyer 	tag_addr = rte_mem_virt2iova(cptq->wdog_tag);
432*54d56abaSAndrew Boyer 	iocpt_fill_sge(src, nsge_src++, tag_addr, IOCPT_Q_WDOG_TAG_LEN);
433*54d56abaSAndrew Boyer 
434*54d56abaSAndrew Boyer 	desc->opcode = IOCPT_DESC_OPCODE_GCM_AEAD_ENCRYPT;
435*54d56abaSAndrew Boyer 	desc->flags = 0;
436*54d56abaSAndrew Boyer 	desc->num_src_dst_sgs = iocpt_encode_nsge_src_dst(nsge_src, 0);
437*54d56abaSAndrew Boyer 	desc->session_tag = rte_cpu_to_le_32(IOCPT_Q_WDOG_SESS_IDX);
438*54d56abaSAndrew Boyer 
439*54d56abaSAndrew Boyer 	q->info[q->head_idx] = wdog_op;
440*54d56abaSAndrew Boyer 	q->head_idx = Q_NEXT_TO_POST(q, 1);
441*54d56abaSAndrew Boyer 
442*54d56abaSAndrew Boyer 	IOCPT_PRINT(DEBUG, "Queue %u wdog enq %p",
443*54d56abaSAndrew Boyer 		q->index, wdog_op);
444*54d56abaSAndrew Boyer 	cptq->enqueued_wdogs++;
445*54d56abaSAndrew Boyer 
446*54d56abaSAndrew Boyer out_flush:
447*54d56abaSAndrew Boyer 	iocpt_q_flush(q);
448*54d56abaSAndrew Boyer }
449*54d56abaSAndrew Boyer 
45080518852SAndrew Boyer static uint16_t
45180518852SAndrew Boyer iocpt_dequeue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
45280518852SAndrew Boyer {
45380518852SAndrew Boyer 	struct iocpt_crypto_q *cptq = qp;
45480518852SAndrew Boyer 	struct iocpt_queue *q = &cptq->q;
45580518852SAndrew Boyer 	struct iocpt_cq *cq = &cptq->cq;
45680518852SAndrew Boyer 	struct rte_crypto_op *op;
45780518852SAndrew Boyer 	struct iocpt_crypto_comp *cq_desc_base = cq->base;
45880518852SAndrew Boyer 	volatile struct iocpt_crypto_comp *cq_desc;
459*54d56abaSAndrew Boyer 	uint64_t then, now, hz, delta;
46080518852SAndrew Boyer 	uint16_t count = 0;
46180518852SAndrew Boyer 
46280518852SAndrew Boyer 	cq_desc = &cq_desc_base[cq->tail_idx];
46380518852SAndrew Boyer 
46480518852SAndrew Boyer 	/* First walk the CQ to update any completed op's status
46580518852SAndrew Boyer 	 * NB: These can arrive out of order!
46680518852SAndrew Boyer 	 */
46780518852SAndrew Boyer 	while ((cq_desc->color & 0x1) == cq->done_color) {
46880518852SAndrew Boyer 		cq->tail_idx = Q_NEXT_TO_SRVC(cq, 1);
46980518852SAndrew Boyer 		if (unlikely(cq->tail_idx == 0))
47080518852SAndrew Boyer 			cq->done_color = !cq->done_color;
47180518852SAndrew Boyer 
47280518852SAndrew Boyer 		op = q->info[rte_le_to_cpu_16(cq_desc->comp_index)];
47380518852SAndrew Boyer 
47480518852SAndrew Boyer 		/* Process returned CQ descriptor status */
47580518852SAndrew Boyer 		if (unlikely(cq_desc->status)) {
47680518852SAndrew Boyer 			switch (cq_desc->status) {
47780518852SAndrew Boyer 			case IOCPT_COMP_SYMM_AUTH_VERIFY_ERROR:
47880518852SAndrew Boyer 				op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
47980518852SAndrew Boyer 				break;
48080518852SAndrew Boyer 			case IOCPT_COMP_INVAL_OPCODE_ERROR:
48180518852SAndrew Boyer 			case IOCPT_COMP_UNSUPP_OPCODE_ERROR:
48280518852SAndrew Boyer 			case IOCPT_COMP_SYMM_SRC_SG_ERROR:
48380518852SAndrew Boyer 			case IOCPT_COMP_SYMM_DST_SG_ERROR:
48480518852SAndrew Boyer 			case IOCPT_COMP_SYMM_SRC_DST_LEN_MISMATCH:
48580518852SAndrew Boyer 			case IOCPT_COMP_SYMM_KEY_IDX_ERROR:
48680518852SAndrew Boyer 				op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
48780518852SAndrew Boyer 				break;
48880518852SAndrew Boyer 			default:
48980518852SAndrew Boyer 				op->status = RTE_CRYPTO_OP_STATUS_ERROR;
49080518852SAndrew Boyer 				break;
49180518852SAndrew Boyer 			}
49280518852SAndrew Boyer 		} else
49380518852SAndrew Boyer 			op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
49480518852SAndrew Boyer 
49580518852SAndrew Boyer 		cq_desc = &cq_desc_base[cq->tail_idx];
49680518852SAndrew Boyer 	}
49780518852SAndrew Boyer 
49880518852SAndrew Boyer 	/* Next walk the SQ to pop off completed ops in-order */
49980518852SAndrew Boyer 	while (count < nb_ops) {
50080518852SAndrew Boyer 		op = q->info[q->tail_idx];
50180518852SAndrew Boyer 
50280518852SAndrew Boyer 		/* No more completions */
50380518852SAndrew Boyer 		if (op == NULL ||
50480518852SAndrew Boyer 		    op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
50580518852SAndrew Boyer 			break;
50680518852SAndrew Boyer 
507*54d56abaSAndrew Boyer 		/* Handle watchdog operations */
508*54d56abaSAndrew Boyer 		if (unlikely(op->type == IOCPT_Q_WDOG_OP_TYPE)) {
509*54d56abaSAndrew Boyer 			IOCPT_PRINT(DEBUG, "Queue %u wdog deq %p st %d",
510*54d56abaSAndrew Boyer 				q->index, op, op->status);
511*54d56abaSAndrew Boyer 			q->info[q->tail_idx] = NULL;
512*54d56abaSAndrew Boyer 			q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
513*54d56abaSAndrew Boyer 			cptq->dequeued_wdogs++;
514*54d56abaSAndrew Boyer 			rte_free(op);
515*54d56abaSAndrew Boyer 			continue;
516*54d56abaSAndrew Boyer 		}
517*54d56abaSAndrew Boyer 
51880518852SAndrew Boyer 		ops[count] = op;
51980518852SAndrew Boyer 		q->info[q->tail_idx] = NULL;
52080518852SAndrew Boyer 
52180518852SAndrew Boyer 		q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
52280518852SAndrew Boyer 		count++;
52380518852SAndrew Boyer 	}
52480518852SAndrew Boyer 
525*54d56abaSAndrew Boyer 	if (!count) {
526*54d56abaSAndrew Boyer 		/*
527*54d56abaSAndrew Boyer 		 * Ring the doorbell again if no work was dequeued and work
528*54d56abaSAndrew Boyer 		 * is still pending after the deadline.
529*54d56abaSAndrew Boyer 		 */
530*54d56abaSAndrew Boyer 		if (q->head_idx != q->tail_idx) {
531*54d56abaSAndrew Boyer 			then = cptq->last_wdog_cycles;
532*54d56abaSAndrew Boyer 			now = rte_get_timer_cycles();
533*54d56abaSAndrew Boyer 			hz = rte_get_timer_hz();
534*54d56abaSAndrew Boyer 			delta = (now - then) * 1000;
535*54d56abaSAndrew Boyer 
536*54d56abaSAndrew Boyer 			if (delta >= hz * IONIC_Q_WDOG_MS) {
537*54d56abaSAndrew Boyer 				iocpt_enqueue_wdog(cptq);
538*54d56abaSAndrew Boyer 				cptq->last_wdog_cycles = now;
539*54d56abaSAndrew Boyer 			}
540*54d56abaSAndrew Boyer 		}
541*54d56abaSAndrew Boyer 	} else
542*54d56abaSAndrew Boyer 		/* Restart timer if the queue is making progress */
543*54d56abaSAndrew Boyer 		cptq->last_wdog_cycles = rte_get_timer_cycles();
544*54d56abaSAndrew Boyer 
54580518852SAndrew Boyer 	return count;
54680518852SAndrew Boyer }
54780518852SAndrew Boyer 
548dddfb0d9SAndrew Boyer static struct rte_cryptodev_ops iocpt_ops = {
549dddfb0d9SAndrew Boyer 	.dev_configure = iocpt_op_config,
55080518852SAndrew Boyer 	.dev_start = iocpt_op_start,
55180518852SAndrew Boyer 	.dev_stop = iocpt_op_stop,
552dddfb0d9SAndrew Boyer 	.dev_close = iocpt_op_close,
553dddfb0d9SAndrew Boyer 	.dev_infos_get = iocpt_op_info_get,
5546bc7f2cfSAndrew Boyer 
55580518852SAndrew Boyer 	.queue_pair_setup = iocpt_op_queue_setup,
55680518852SAndrew Boyer 	.queue_pair_release = iocpt_op_queue_release,
55780518852SAndrew Boyer 
5586bc7f2cfSAndrew Boyer 	.sym_session_get_size = iocpt_op_get_session_size,
5596bc7f2cfSAndrew Boyer 	.sym_session_configure = iocpt_op_session_cfg,
5606bc7f2cfSAndrew Boyer 	.sym_session_clear = iocpt_op_session_clear,
561dddfb0d9SAndrew Boyer };
562dddfb0d9SAndrew Boyer 
563dddfb0d9SAndrew Boyer int
564dddfb0d9SAndrew Boyer iocpt_assign_ops(struct rte_cryptodev *cdev)
565dddfb0d9SAndrew Boyer {
566dddfb0d9SAndrew Boyer 	struct iocpt_dev *dev = cdev->data->dev_private;
567dddfb0d9SAndrew Boyer 
568dddfb0d9SAndrew Boyer 	cdev->dev_ops = &iocpt_ops;
569dddfb0d9SAndrew Boyer 	cdev->feature_flags = dev->features;
570dddfb0d9SAndrew Boyer 
57180518852SAndrew Boyer 	if (dev->features & RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO) {
57280518852SAndrew Boyer 		cdev->enqueue_burst = iocpt_enqueue_sym;
57380518852SAndrew Boyer 		cdev->dequeue_burst = iocpt_dequeue_sym;
57480518852SAndrew Boyer 	}
57580518852SAndrew Boyer 
576dddfb0d9SAndrew Boyer 	return 0;
577dddfb0d9SAndrew Boyer }
578