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
iocpt_op_config(struct rte_cryptodev * cdev,struct rte_cryptodev_config * config __rte_unused)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
iocpt_op_start(struct rte_cryptodev * cdev)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
iocpt_op_stop(struct rte_cryptodev * cdev)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
iocpt_op_close(struct rte_cryptodev * cdev)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
iocpt_op_info_get(struct rte_cryptodev * cdev,struct rte_cryptodev_info * info)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);
6154d56abaSAndrew Boyer /* Reserve one session for watchdog */
6254d56abaSAndrew 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
68*aacc5f13SAndrew Boyer static void
iocpt_op_stats_get(struct rte_cryptodev * cdev,struct rte_cryptodev_stats * stats)69*aacc5f13SAndrew Boyer iocpt_op_stats_get(struct rte_cryptodev *cdev,
70*aacc5f13SAndrew Boyer struct rte_cryptodev_stats *stats)
71*aacc5f13SAndrew Boyer {
72*aacc5f13SAndrew Boyer struct iocpt_dev *dev = cdev->data->dev_private;
73*aacc5f13SAndrew Boyer
74*aacc5f13SAndrew Boyer iocpt_get_stats(dev, stats);
75*aacc5f13SAndrew Boyer }
76*aacc5f13SAndrew Boyer
77*aacc5f13SAndrew Boyer static void
iocpt_op_stats_reset(struct rte_cryptodev * cdev)78*aacc5f13SAndrew Boyer iocpt_op_stats_reset(struct rte_cryptodev *cdev)
79*aacc5f13SAndrew Boyer {
80*aacc5f13SAndrew Boyer struct iocpt_dev *dev = cdev->data->dev_private;
81*aacc5f13SAndrew Boyer
82*aacc5f13SAndrew Boyer iocpt_reset_stats(dev);
83*aacc5f13SAndrew Boyer }
84*aacc5f13SAndrew Boyer
8580518852SAndrew Boyer static int
iocpt_op_queue_release(struct rte_cryptodev * cdev,uint16_t queue_id)8680518852SAndrew Boyer iocpt_op_queue_release(struct rte_cryptodev *cdev, uint16_t queue_id)
8780518852SAndrew Boyer {
8880518852SAndrew Boyer struct iocpt_crypto_q *cptq = cdev->data->queue_pairs[queue_id];
8980518852SAndrew Boyer
9080518852SAndrew Boyer IOCPT_PRINT(DEBUG, "queue_id %u", queue_id);
9180518852SAndrew Boyer
9280518852SAndrew Boyer assert(!(cptq->flags & IOCPT_Q_F_INITED));
9380518852SAndrew Boyer
9480518852SAndrew Boyer iocpt_cryptoq_free(cptq);
9580518852SAndrew Boyer
9680518852SAndrew Boyer cdev->data->queue_pairs[queue_id] = NULL;
9780518852SAndrew Boyer
9880518852SAndrew Boyer return 0;
9980518852SAndrew Boyer }
10080518852SAndrew Boyer
10180518852SAndrew Boyer static int
iocpt_op_queue_setup(struct rte_cryptodev * cdev,uint16_t queue_id,const struct rte_cryptodev_qp_conf * qp_conf,int socket_id)10280518852SAndrew Boyer iocpt_op_queue_setup(struct rte_cryptodev *cdev, uint16_t queue_id,
10380518852SAndrew Boyer const struct rte_cryptodev_qp_conf *qp_conf,
10480518852SAndrew Boyer int socket_id)
10580518852SAndrew Boyer {
10680518852SAndrew Boyer struct iocpt_dev *dev = cdev->data->dev_private;
10780518852SAndrew Boyer int err;
10880518852SAndrew Boyer
10980518852SAndrew Boyer if (cdev->data->queue_pairs[queue_id] != NULL)
11080518852SAndrew Boyer iocpt_op_queue_release(cdev, queue_id);
11180518852SAndrew Boyer
11280518852SAndrew Boyer if (qp_conf->nb_descriptors < (1 << IOCPT_QSIZE_MIN_LG2) ||
11380518852SAndrew Boyer qp_conf->nb_descriptors > (1 << IOCPT_QSIZE_MAX_LG2)) {
11480518852SAndrew Boyer IOCPT_PRINT(ERR, "invalid nb_descriptors %u, use range %u..%u",
11580518852SAndrew Boyer qp_conf->nb_descriptors,
11680518852SAndrew Boyer 1 << IOCPT_QSIZE_MIN_LG2, 1 << IOCPT_QSIZE_MAX_LG2);
11780518852SAndrew Boyer return -ERANGE;
11880518852SAndrew Boyer }
11980518852SAndrew Boyer
12080518852SAndrew Boyer IOCPT_PRINT(DEBUG, "queue_id %u", queue_id);
12180518852SAndrew Boyer
12280518852SAndrew Boyer err = iocpt_cryptoq_alloc(dev, socket_id, queue_id,
12380518852SAndrew Boyer qp_conf->nb_descriptors);
12480518852SAndrew Boyer if (err != 0)
12580518852SAndrew Boyer return err;
12680518852SAndrew Boyer
12780518852SAndrew Boyer cdev->data->queue_pairs[queue_id] = dev->cryptoqs[queue_id];
12880518852SAndrew Boyer
12980518852SAndrew Boyer return 0;
13080518852SAndrew Boyer }
13180518852SAndrew Boyer
1326bc7f2cfSAndrew Boyer static unsigned int
iocpt_op_get_session_size(struct rte_cryptodev * cdev __rte_unused)1336bc7f2cfSAndrew Boyer iocpt_op_get_session_size(struct rte_cryptodev *cdev __rte_unused)
1346bc7f2cfSAndrew Boyer {
1356bc7f2cfSAndrew Boyer return iocpt_session_size();
1366bc7f2cfSAndrew Boyer }
1376bc7f2cfSAndrew Boyer
1386bc7f2cfSAndrew Boyer static inline int
iocpt_is_algo_supported(struct rte_crypto_sym_xform * xform)1396bc7f2cfSAndrew Boyer iocpt_is_algo_supported(struct rte_crypto_sym_xform *xform)
1406bc7f2cfSAndrew Boyer {
1416bc7f2cfSAndrew Boyer if (xform->next != NULL) {
1426bc7f2cfSAndrew Boyer IOCPT_PRINT(ERR, "chaining not supported");
1436bc7f2cfSAndrew Boyer return -ENOTSUP;
1446bc7f2cfSAndrew Boyer }
1456bc7f2cfSAndrew Boyer
1466bc7f2cfSAndrew Boyer if (xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) {
1476bc7f2cfSAndrew Boyer IOCPT_PRINT(ERR, "xform->type %d not supported", xform->type);
1486bc7f2cfSAndrew Boyer return -ENOTSUP;
1496bc7f2cfSAndrew Boyer }
1506bc7f2cfSAndrew Boyer
1516bc7f2cfSAndrew Boyer return 0;
1526bc7f2cfSAndrew Boyer }
1536bc7f2cfSAndrew Boyer
1546bc7f2cfSAndrew Boyer static __rte_always_inline int
iocpt_fill_sess_aead(struct rte_crypto_sym_xform * xform,struct iocpt_session_priv * priv)1556bc7f2cfSAndrew Boyer iocpt_fill_sess_aead(struct rte_crypto_sym_xform *xform,
1566bc7f2cfSAndrew Boyer struct iocpt_session_priv *priv)
1576bc7f2cfSAndrew Boyer {
1586bc7f2cfSAndrew Boyer struct rte_crypto_aead_xform *aead_form = &xform->aead;
1596bc7f2cfSAndrew Boyer
1606bc7f2cfSAndrew Boyer if (aead_form->algo != RTE_CRYPTO_AEAD_AES_GCM) {
1616bc7f2cfSAndrew Boyer IOCPT_PRINT(ERR, "Unknown algo");
1626bc7f2cfSAndrew Boyer return -EINVAL;
1636bc7f2cfSAndrew Boyer }
1646bc7f2cfSAndrew Boyer if (aead_form->op == RTE_CRYPTO_AEAD_OP_ENCRYPT) {
1656bc7f2cfSAndrew Boyer priv->op = IOCPT_DESC_OPCODE_GCM_AEAD_ENCRYPT;
1666bc7f2cfSAndrew Boyer } else if (aead_form->op == RTE_CRYPTO_AEAD_OP_DECRYPT) {
1676bc7f2cfSAndrew Boyer priv->op = IOCPT_DESC_OPCODE_GCM_AEAD_DECRYPT;
1686bc7f2cfSAndrew Boyer } else {
1696bc7f2cfSAndrew Boyer IOCPT_PRINT(ERR, "Unknown cipher operations");
1706bc7f2cfSAndrew Boyer return -1;
1716bc7f2cfSAndrew Boyer }
1726bc7f2cfSAndrew Boyer
1736bc7f2cfSAndrew Boyer if (aead_form->key.length < IOCPT_SESS_KEY_LEN_MIN ||
1746bc7f2cfSAndrew Boyer aead_form->key.length > IOCPT_SESS_KEY_LEN_MAX_SYMM) {
1756bc7f2cfSAndrew Boyer IOCPT_PRINT(ERR, "Invalid cipher keylen %u",
1766bc7f2cfSAndrew Boyer aead_form->key.length);
1776bc7f2cfSAndrew Boyer return -1;
1786bc7f2cfSAndrew Boyer }
1796bc7f2cfSAndrew Boyer priv->key_len = aead_form->key.length;
1806bc7f2cfSAndrew Boyer memcpy(priv->key, aead_form->key.data, priv->key_len);
1816bc7f2cfSAndrew Boyer
1826bc7f2cfSAndrew Boyer priv->type = IOCPT_SESS_AEAD_AES_GCM;
1836bc7f2cfSAndrew Boyer priv->iv_offset = aead_form->iv.offset;
1846bc7f2cfSAndrew Boyer priv->iv_length = aead_form->iv.length;
1856bc7f2cfSAndrew Boyer priv->digest_length = aead_form->digest_length;
1866bc7f2cfSAndrew Boyer priv->aad_length = aead_form->aad_length;
1876bc7f2cfSAndrew Boyer
1886bc7f2cfSAndrew Boyer return 0;
1896bc7f2cfSAndrew Boyer }
1906bc7f2cfSAndrew Boyer
1916bc7f2cfSAndrew Boyer static int
iocpt_session_cfg(struct iocpt_dev * dev,struct rte_crypto_sym_xform * xform,struct rte_cryptodev_sym_session * sess)1926bc7f2cfSAndrew Boyer iocpt_session_cfg(struct iocpt_dev *dev,
1936bc7f2cfSAndrew Boyer struct rte_crypto_sym_xform *xform,
1946bc7f2cfSAndrew Boyer struct rte_cryptodev_sym_session *sess)
1956bc7f2cfSAndrew Boyer {
1966bc7f2cfSAndrew Boyer struct rte_crypto_sym_xform *chain;
1976bc7f2cfSAndrew Boyer struct iocpt_session_priv *priv = NULL;
1986bc7f2cfSAndrew Boyer
1996bc7f2cfSAndrew Boyer if (iocpt_is_algo_supported(xform) < 0)
2006bc7f2cfSAndrew Boyer return -ENOTSUP;
2016bc7f2cfSAndrew Boyer
2026bc7f2cfSAndrew Boyer if (unlikely(sess == NULL)) {
2036bc7f2cfSAndrew Boyer IOCPT_PRINT(ERR, "invalid session");
2046bc7f2cfSAndrew Boyer return -EINVAL;
2056bc7f2cfSAndrew Boyer }
2066bc7f2cfSAndrew Boyer
2076bc7f2cfSAndrew Boyer priv = CRYPTODEV_GET_SYM_SESS_PRIV(sess);
2086bc7f2cfSAndrew Boyer priv->dev = dev;
2096bc7f2cfSAndrew Boyer
2106bc7f2cfSAndrew Boyer chain = xform;
2116bc7f2cfSAndrew Boyer while (chain) {
2126bc7f2cfSAndrew Boyer switch (chain->type) {
2136bc7f2cfSAndrew Boyer case RTE_CRYPTO_SYM_XFORM_AEAD:
2146bc7f2cfSAndrew Boyer if (iocpt_fill_sess_aead(chain, priv))
2156bc7f2cfSAndrew Boyer return -EIO;
2166bc7f2cfSAndrew Boyer break;
2176bc7f2cfSAndrew Boyer default:
2186bc7f2cfSAndrew Boyer IOCPT_PRINT(ERR, "invalid crypto xform type %d",
2196bc7f2cfSAndrew Boyer chain->type);
2206bc7f2cfSAndrew Boyer return -ENOTSUP;
2216bc7f2cfSAndrew Boyer }
2226bc7f2cfSAndrew Boyer chain = chain->next;
2236bc7f2cfSAndrew Boyer }
2246bc7f2cfSAndrew Boyer
2256bc7f2cfSAndrew Boyer return iocpt_session_init(priv);
2266bc7f2cfSAndrew Boyer }
2276bc7f2cfSAndrew Boyer
2286bc7f2cfSAndrew Boyer static int
iocpt_op_session_cfg(struct rte_cryptodev * cdev,struct rte_crypto_sym_xform * xform,struct rte_cryptodev_sym_session * sess)2296bc7f2cfSAndrew Boyer iocpt_op_session_cfg(struct rte_cryptodev *cdev,
2306bc7f2cfSAndrew Boyer struct rte_crypto_sym_xform *xform,
2316bc7f2cfSAndrew Boyer struct rte_cryptodev_sym_session *sess)
2326bc7f2cfSAndrew Boyer {
2336bc7f2cfSAndrew Boyer struct iocpt_dev *dev = cdev->data->dev_private;
2346bc7f2cfSAndrew Boyer
2356bc7f2cfSAndrew Boyer return iocpt_session_cfg(dev, xform, sess);
2366bc7f2cfSAndrew Boyer }
2376bc7f2cfSAndrew Boyer
2386bc7f2cfSAndrew Boyer static void
iocpt_session_clear(struct rte_cryptodev_sym_session * sess)2396bc7f2cfSAndrew Boyer iocpt_session_clear(struct rte_cryptodev_sym_session *sess)
2406bc7f2cfSAndrew Boyer {
2416bc7f2cfSAndrew Boyer iocpt_session_deinit(CRYPTODEV_GET_SYM_SESS_PRIV(sess));
2426bc7f2cfSAndrew Boyer }
2436bc7f2cfSAndrew Boyer
2446bc7f2cfSAndrew Boyer static void
iocpt_op_session_clear(struct rte_cryptodev * cdev __rte_unused,struct rte_cryptodev_sym_session * sess)2456bc7f2cfSAndrew Boyer iocpt_op_session_clear(struct rte_cryptodev *cdev __rte_unused,
2466bc7f2cfSAndrew Boyer struct rte_cryptodev_sym_session *sess)
2476bc7f2cfSAndrew Boyer {
2486bc7f2cfSAndrew Boyer iocpt_session_clear(sess);
2496bc7f2cfSAndrew Boyer }
2506bc7f2cfSAndrew Boyer
25180518852SAndrew Boyer static inline void
iocpt_fill_sge(struct iocpt_crypto_sg_elem * arr,uint8_t idx,uint64_t addr,uint16_t len)25280518852SAndrew Boyer iocpt_fill_sge(struct iocpt_crypto_sg_elem *arr, uint8_t idx,
25380518852SAndrew Boyer uint64_t addr, uint16_t len)
25480518852SAndrew Boyer {
25580518852SAndrew Boyer arr[idx].addr = rte_cpu_to_le_64(addr);
25680518852SAndrew Boyer arr[idx].len = rte_cpu_to_le_16(len);
25780518852SAndrew Boyer }
25880518852SAndrew Boyer
25980518852SAndrew Boyer static __rte_always_inline int
iocpt_enq_one_aead(struct iocpt_crypto_q * cptq,struct iocpt_session_priv * priv,struct rte_crypto_op * op)26080518852SAndrew Boyer iocpt_enq_one_aead(struct iocpt_crypto_q *cptq,
26180518852SAndrew Boyer struct iocpt_session_priv *priv, struct rte_crypto_op *op)
26280518852SAndrew Boyer {
26380518852SAndrew Boyer struct rte_crypto_sym_op *sym_op = op->sym;
26480518852SAndrew Boyer struct iocpt_queue *q = &cptq->q;
26580518852SAndrew Boyer struct iocpt_crypto_desc *desc, *desc_base = q->base;
26680518852SAndrew Boyer struct iocpt_crypto_sg_desc *sg_desc, *sg_desc_base = q->sg_base;
26780518852SAndrew Boyer struct iocpt_crypto_sg_elem *src, *dst;
26880518852SAndrew Boyer rte_iova_t aad_addr, digest_addr, iv_addr, seg_addr;
26980518852SAndrew Boyer uint32_t data_len, data_offset, seg_len;
27080518852SAndrew Boyer uint8_t nsge_src = 0, nsge_dst = 0, flags = 0;
27180518852SAndrew Boyer struct rte_mbuf *m;
27280518852SAndrew Boyer
27380518852SAndrew Boyer desc = &desc_base[q->head_idx];
27480518852SAndrew Boyer sg_desc = &sg_desc_base[q->head_idx];
27580518852SAndrew Boyer src = sg_desc->src_elems;
27680518852SAndrew Boyer dst = sg_desc->dst_elems;
27780518852SAndrew Boyer
27880518852SAndrew Boyer /* Fill the first SGE with the IV / Nonce */
27980518852SAndrew Boyer iv_addr = rte_crypto_op_ctophys_offset(op, priv->iv_offset);
28080518852SAndrew Boyer iocpt_fill_sge(src, nsge_src++, iv_addr, priv->iv_length);
28180518852SAndrew Boyer
28280518852SAndrew Boyer /* Fill the second SGE with the AAD, if applicable */
28380518852SAndrew Boyer if (priv->aad_length > 0) {
28480518852SAndrew Boyer aad_addr = sym_op->aead.aad.phys_addr;
28580518852SAndrew Boyer iocpt_fill_sge(src, nsge_src++, aad_addr, priv->aad_length);
28680518852SAndrew Boyer flags |= IOCPT_DESC_F_AAD_VALID;
28780518852SAndrew Boyer }
28880518852SAndrew Boyer
28980518852SAndrew Boyer m = sym_op->m_src;
29080518852SAndrew Boyer data_len = sym_op->aead.data.length;
29180518852SAndrew Boyer
29280518852SAndrew Boyer /* Fast-forward through mbuf chain to account for data offset */
29380518852SAndrew Boyer data_offset = sym_op->aead.data.offset;
29480518852SAndrew Boyer while (m != NULL && data_offset >= m->data_len) {
29580518852SAndrew Boyer data_offset -= m->data_len;
29680518852SAndrew Boyer m = m->next;
29780518852SAndrew Boyer }
29880518852SAndrew Boyer
29980518852SAndrew Boyer /* Fill the next SGEs with the payload segments */
30080518852SAndrew Boyer while (m != NULL && data_len > 0) {
30180518852SAndrew Boyer seg_addr = rte_mbuf_data_iova(m) + data_offset;
30280518852SAndrew Boyer seg_len = RTE_MIN(m->data_len - data_offset, data_len);
30380518852SAndrew Boyer data_offset = 0;
30480518852SAndrew Boyer data_len -= seg_len;
30580518852SAndrew Boyer
30680518852SAndrew Boyer /* Use -1 to save room for digest */
30780518852SAndrew Boyer if (nsge_src >= IOCPT_CRYPTO_MAX_SG_ELEMS - 1)
30880518852SAndrew Boyer return -ERANGE;
30980518852SAndrew Boyer
31080518852SAndrew Boyer iocpt_fill_sge(src, nsge_src++, seg_addr, seg_len);
31180518852SAndrew Boyer
31280518852SAndrew Boyer m = m->next;
31380518852SAndrew Boyer }
31480518852SAndrew Boyer
31580518852SAndrew Boyer /* AEAD AES-GCM: digest == authentication tag */
31680518852SAndrew Boyer digest_addr = sym_op->aead.digest.phys_addr;
31780518852SAndrew Boyer iocpt_fill_sge(src, nsge_src++, digest_addr, priv->digest_length);
31880518852SAndrew Boyer
31980518852SAndrew Boyer /* Process Out-Of-Place destination SGL */
32080518852SAndrew Boyer if (sym_op->m_dst != NULL) {
32180518852SAndrew Boyer /* Put the AAD here, too */
32280518852SAndrew Boyer if (priv->aad_length > 0)
32380518852SAndrew Boyer iocpt_fill_sge(dst, nsge_dst++,
32480518852SAndrew Boyer sym_op->aead.aad.phys_addr, priv->aad_length);
32580518852SAndrew Boyer
32680518852SAndrew Boyer m = sym_op->m_dst;
32780518852SAndrew Boyer data_len = sym_op->aead.data.length;
32880518852SAndrew Boyer
32980518852SAndrew Boyer /* Fast-forward through chain to account for data offset */
33080518852SAndrew Boyer data_offset = sym_op->aead.data.offset;
33180518852SAndrew Boyer while (m != NULL && data_offset >= m->data_len) {
33280518852SAndrew Boyer data_offset -= m->data_len;
33380518852SAndrew Boyer m = m->next;
33480518852SAndrew Boyer }
33580518852SAndrew Boyer
33680518852SAndrew Boyer /* Fill in the SGEs with the payload segments */
33780518852SAndrew Boyer while (m != NULL && data_len > 0) {
33880518852SAndrew Boyer seg_addr = rte_mbuf_data_iova(m) + data_offset;
33980518852SAndrew Boyer seg_len = RTE_MIN(m->data_len - data_offset, data_len);
34080518852SAndrew Boyer data_offset = 0;
34180518852SAndrew Boyer data_len -= seg_len;
34280518852SAndrew Boyer
34380518852SAndrew Boyer if (nsge_dst >= IOCPT_CRYPTO_MAX_SG_ELEMS)
34480518852SAndrew Boyer return -ERANGE;
34580518852SAndrew Boyer
34680518852SAndrew Boyer iocpt_fill_sge(dst, nsge_dst++, seg_addr, seg_len);
34780518852SAndrew Boyer
34880518852SAndrew Boyer m = m->next;
34980518852SAndrew Boyer }
35080518852SAndrew Boyer }
35180518852SAndrew Boyer
35280518852SAndrew Boyer desc->opcode = priv->op;
35380518852SAndrew Boyer desc->flags = flags;
35480518852SAndrew Boyer desc->num_src_dst_sgs = iocpt_encode_nsge_src_dst(nsge_src, nsge_dst);
35580518852SAndrew Boyer desc->session_tag = rte_cpu_to_le_32(priv->index);
35680518852SAndrew Boyer
35780518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
35880518852SAndrew Boyer q->info[q->head_idx] = op;
35980518852SAndrew Boyer q->head_idx = Q_NEXT_TO_POST(q, 1);
36080518852SAndrew Boyer
36180518852SAndrew Boyer return 0;
36280518852SAndrew Boyer }
36380518852SAndrew Boyer
36480518852SAndrew Boyer static uint16_t
iocpt_enqueue_sym(void * qp,struct rte_crypto_op ** ops,uint16_t nb_ops)36580518852SAndrew Boyer iocpt_enqueue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
36680518852SAndrew Boyer {
36780518852SAndrew Boyer struct iocpt_crypto_q *cptq = qp;
36880518852SAndrew Boyer struct rte_crypto_op *op;
36980518852SAndrew Boyer struct iocpt_session_priv *priv;
370*aacc5f13SAndrew Boyer struct rte_cryptodev_stats *stats = &cptq->stats;
37180518852SAndrew Boyer uint16_t avail, count;
37280518852SAndrew Boyer int err;
37380518852SAndrew Boyer
37480518852SAndrew Boyer avail = iocpt_q_space_avail(&cptq->q);
37580518852SAndrew Boyer if (unlikely(nb_ops > avail))
37680518852SAndrew Boyer nb_ops = avail;
37780518852SAndrew Boyer
37880518852SAndrew Boyer count = 0;
37980518852SAndrew Boyer while (likely(count < nb_ops)) {
38080518852SAndrew Boyer op = ops[count];
38180518852SAndrew Boyer
38280518852SAndrew Boyer if (unlikely(op->sess_type != RTE_CRYPTO_OP_WITH_SESSION)) {
38380518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
38480518852SAndrew Boyer break;
38580518852SAndrew Boyer }
38680518852SAndrew Boyer
38780518852SAndrew Boyer priv = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
38880518852SAndrew Boyer if (unlikely(priv == NULL)) {
38980518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
39080518852SAndrew Boyer break;
39180518852SAndrew Boyer }
39280518852SAndrew Boyer
39380518852SAndrew Boyer err = iocpt_enq_one_aead(cptq, priv, op);
39480518852SAndrew Boyer if (unlikely(err != 0)) {
39580518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
396*aacc5f13SAndrew Boyer stats->enqueue_err_count++;
39780518852SAndrew Boyer break;
39880518852SAndrew Boyer }
39980518852SAndrew Boyer
40080518852SAndrew Boyer count++;
40180518852SAndrew Boyer }
40280518852SAndrew Boyer
40354d56abaSAndrew Boyer if (likely(count > 0)) {
40480518852SAndrew Boyer iocpt_q_flush(&cptq->q);
40580518852SAndrew Boyer
40654d56abaSAndrew Boyer /* Restart timer if ops are being enqueued */
40754d56abaSAndrew Boyer cptq->last_wdog_cycles = rte_get_timer_cycles();
408*aacc5f13SAndrew Boyer
409*aacc5f13SAndrew Boyer stats->enqueued_count += count;
41054d56abaSAndrew Boyer }
41154d56abaSAndrew Boyer
41280518852SAndrew Boyer return count;
41380518852SAndrew Boyer }
41480518852SAndrew Boyer
41554d56abaSAndrew Boyer static void
iocpt_enqueue_wdog(struct iocpt_crypto_q * cptq)41654d56abaSAndrew Boyer iocpt_enqueue_wdog(struct iocpt_crypto_q *cptq)
41754d56abaSAndrew Boyer {
41854d56abaSAndrew Boyer struct iocpt_queue *q = &cptq->q;
41954d56abaSAndrew Boyer struct iocpt_crypto_desc *desc, *desc_base = q->base;
42054d56abaSAndrew Boyer struct iocpt_crypto_sg_desc *sg_desc, *sg_desc_base = q->sg_base;
42154d56abaSAndrew Boyer struct iocpt_crypto_sg_elem *src;
42254d56abaSAndrew Boyer struct rte_crypto_op *wdog_op;
42354d56abaSAndrew Boyer rte_iova_t iv_addr, pld_addr, tag_addr;
42454d56abaSAndrew Boyer uint8_t nsge_src = 0;
42554d56abaSAndrew Boyer uint16_t avail;
42654d56abaSAndrew Boyer
42754d56abaSAndrew Boyer avail = iocpt_q_space_avail(&cptq->q);
42854d56abaSAndrew Boyer if (avail < 1)
42954d56abaSAndrew Boyer goto out_flush;
43054d56abaSAndrew Boyer
43154d56abaSAndrew Boyer wdog_op = rte_zmalloc_socket("iocpt", sizeof(*wdog_op),
43254d56abaSAndrew Boyer RTE_CACHE_LINE_SIZE, rte_socket_id());
43354d56abaSAndrew Boyer if (wdog_op == NULL)
43454d56abaSAndrew Boyer goto out_flush;
43554d56abaSAndrew Boyer
43654d56abaSAndrew Boyer wdog_op->type = IOCPT_Q_WDOG_OP_TYPE;
43754d56abaSAndrew Boyer wdog_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
43854d56abaSAndrew Boyer
43954d56abaSAndrew Boyer desc = &desc_base[q->head_idx];
44054d56abaSAndrew Boyer sg_desc = &sg_desc_base[q->head_idx];
44154d56abaSAndrew Boyer src = sg_desc->src_elems;
44254d56abaSAndrew Boyer
44354d56abaSAndrew Boyer /* Fill the first SGE with the IV / Nonce */
44454d56abaSAndrew Boyer iv_addr = rte_mem_virt2iova(cptq->wdog_iv);
44554d56abaSAndrew Boyer iocpt_fill_sge(src, nsge_src++, iv_addr, IOCPT_Q_WDOG_IV_LEN);
44654d56abaSAndrew Boyer
44754d56abaSAndrew Boyer /* Fill the second SGE with the payload segment */
44854d56abaSAndrew Boyer pld_addr = rte_mem_virt2iova(cptq->wdog_pld);
44954d56abaSAndrew Boyer iocpt_fill_sge(src, nsge_src++, pld_addr, IOCPT_Q_WDOG_PLD_LEN);
45054d56abaSAndrew Boyer
45154d56abaSAndrew Boyer /* AEAD AES-GCM: digest == authentication tag */
45254d56abaSAndrew Boyer tag_addr = rte_mem_virt2iova(cptq->wdog_tag);
45354d56abaSAndrew Boyer iocpt_fill_sge(src, nsge_src++, tag_addr, IOCPT_Q_WDOG_TAG_LEN);
45454d56abaSAndrew Boyer
45554d56abaSAndrew Boyer desc->opcode = IOCPT_DESC_OPCODE_GCM_AEAD_ENCRYPT;
45654d56abaSAndrew Boyer desc->flags = 0;
45754d56abaSAndrew Boyer desc->num_src_dst_sgs = iocpt_encode_nsge_src_dst(nsge_src, 0);
45854d56abaSAndrew Boyer desc->session_tag = rte_cpu_to_le_32(IOCPT_Q_WDOG_SESS_IDX);
45954d56abaSAndrew Boyer
46054d56abaSAndrew Boyer q->info[q->head_idx] = wdog_op;
46154d56abaSAndrew Boyer q->head_idx = Q_NEXT_TO_POST(q, 1);
46254d56abaSAndrew Boyer
463*aacc5f13SAndrew Boyer IOCPT_PRINT(DEBUG, "Queue %u wdog enq %p ops %"PRIu64,
464*aacc5f13SAndrew Boyer q->index, wdog_op, cptq->stats.enqueued_count);
46554d56abaSAndrew Boyer cptq->enqueued_wdogs++;
46654d56abaSAndrew Boyer
46754d56abaSAndrew Boyer out_flush:
46854d56abaSAndrew Boyer iocpt_q_flush(q);
46954d56abaSAndrew Boyer }
47054d56abaSAndrew Boyer
47180518852SAndrew Boyer static uint16_t
iocpt_dequeue_sym(void * qp,struct rte_crypto_op ** ops,uint16_t nb_ops)47280518852SAndrew Boyer iocpt_dequeue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
47380518852SAndrew Boyer {
47480518852SAndrew Boyer struct iocpt_crypto_q *cptq = qp;
47580518852SAndrew Boyer struct iocpt_queue *q = &cptq->q;
47680518852SAndrew Boyer struct iocpt_cq *cq = &cptq->cq;
47780518852SAndrew Boyer struct rte_crypto_op *op;
47880518852SAndrew Boyer struct iocpt_crypto_comp *cq_desc_base = cq->base;
47980518852SAndrew Boyer volatile struct iocpt_crypto_comp *cq_desc;
480*aacc5f13SAndrew Boyer struct rte_cryptodev_stats *stats = &cptq->stats;
48154d56abaSAndrew Boyer uint64_t then, now, hz, delta;
48280518852SAndrew Boyer uint16_t count = 0;
48380518852SAndrew Boyer
48480518852SAndrew Boyer cq_desc = &cq_desc_base[cq->tail_idx];
48580518852SAndrew Boyer
48680518852SAndrew Boyer /* First walk the CQ to update any completed op's status
48780518852SAndrew Boyer * NB: These can arrive out of order!
48880518852SAndrew Boyer */
48980518852SAndrew Boyer while ((cq_desc->color & 0x1) == cq->done_color) {
49080518852SAndrew Boyer cq->tail_idx = Q_NEXT_TO_SRVC(cq, 1);
49180518852SAndrew Boyer if (unlikely(cq->tail_idx == 0))
49280518852SAndrew Boyer cq->done_color = !cq->done_color;
49380518852SAndrew Boyer
49480518852SAndrew Boyer op = q->info[rte_le_to_cpu_16(cq_desc->comp_index)];
49580518852SAndrew Boyer
49680518852SAndrew Boyer /* Process returned CQ descriptor status */
49780518852SAndrew Boyer if (unlikely(cq_desc->status)) {
49880518852SAndrew Boyer switch (cq_desc->status) {
49980518852SAndrew Boyer case IOCPT_COMP_SYMM_AUTH_VERIFY_ERROR:
50080518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
50180518852SAndrew Boyer break;
50280518852SAndrew Boyer case IOCPT_COMP_INVAL_OPCODE_ERROR:
50380518852SAndrew Boyer case IOCPT_COMP_UNSUPP_OPCODE_ERROR:
50480518852SAndrew Boyer case IOCPT_COMP_SYMM_SRC_SG_ERROR:
50580518852SAndrew Boyer case IOCPT_COMP_SYMM_DST_SG_ERROR:
50680518852SAndrew Boyer case IOCPT_COMP_SYMM_SRC_DST_LEN_MISMATCH:
50780518852SAndrew Boyer case IOCPT_COMP_SYMM_KEY_IDX_ERROR:
50880518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
50980518852SAndrew Boyer break;
51080518852SAndrew Boyer default:
51180518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_ERROR;
51280518852SAndrew Boyer break;
51380518852SAndrew Boyer }
51480518852SAndrew Boyer } else
51580518852SAndrew Boyer op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
51680518852SAndrew Boyer
51780518852SAndrew Boyer cq_desc = &cq_desc_base[cq->tail_idx];
51880518852SAndrew Boyer }
51980518852SAndrew Boyer
52080518852SAndrew Boyer /* Next walk the SQ to pop off completed ops in-order */
52180518852SAndrew Boyer while (count < nb_ops) {
52280518852SAndrew Boyer op = q->info[q->tail_idx];
52380518852SAndrew Boyer
52480518852SAndrew Boyer /* No more completions */
52580518852SAndrew Boyer if (op == NULL ||
52680518852SAndrew Boyer op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
52780518852SAndrew Boyer break;
52880518852SAndrew Boyer
52954d56abaSAndrew Boyer /* Handle watchdog operations */
53054d56abaSAndrew Boyer if (unlikely(op->type == IOCPT_Q_WDOG_OP_TYPE)) {
53154d56abaSAndrew Boyer IOCPT_PRINT(DEBUG, "Queue %u wdog deq %p st %d",
53254d56abaSAndrew Boyer q->index, op, op->status);
53354d56abaSAndrew Boyer q->info[q->tail_idx] = NULL;
53454d56abaSAndrew Boyer q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
53554d56abaSAndrew Boyer cptq->dequeued_wdogs++;
53654d56abaSAndrew Boyer rte_free(op);
53754d56abaSAndrew Boyer continue;
53854d56abaSAndrew Boyer }
53954d56abaSAndrew Boyer
540*aacc5f13SAndrew Boyer if (unlikely(op->status != RTE_CRYPTO_OP_STATUS_SUCCESS))
541*aacc5f13SAndrew Boyer stats->dequeue_err_count++;
542*aacc5f13SAndrew Boyer
54380518852SAndrew Boyer ops[count] = op;
54480518852SAndrew Boyer q->info[q->tail_idx] = NULL;
54580518852SAndrew Boyer
54680518852SAndrew Boyer q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
54780518852SAndrew Boyer count++;
54880518852SAndrew Boyer }
54980518852SAndrew Boyer
55054d56abaSAndrew Boyer if (!count) {
55154d56abaSAndrew Boyer /*
55254d56abaSAndrew Boyer * Ring the doorbell again if no work was dequeued and work
55354d56abaSAndrew Boyer * is still pending after the deadline.
55454d56abaSAndrew Boyer */
55554d56abaSAndrew Boyer if (q->head_idx != q->tail_idx) {
55654d56abaSAndrew Boyer then = cptq->last_wdog_cycles;
55754d56abaSAndrew Boyer now = rte_get_timer_cycles();
55854d56abaSAndrew Boyer hz = rte_get_timer_hz();
55954d56abaSAndrew Boyer delta = (now - then) * 1000;
56054d56abaSAndrew Boyer
56154d56abaSAndrew Boyer if (delta >= hz * IONIC_Q_WDOG_MS) {
56254d56abaSAndrew Boyer iocpt_enqueue_wdog(cptq);
56354d56abaSAndrew Boyer cptq->last_wdog_cycles = now;
56454d56abaSAndrew Boyer }
56554d56abaSAndrew Boyer }
56654d56abaSAndrew Boyer } else
56754d56abaSAndrew Boyer /* Restart timer if the queue is making progress */
56854d56abaSAndrew Boyer cptq->last_wdog_cycles = rte_get_timer_cycles();
56954d56abaSAndrew Boyer
570*aacc5f13SAndrew Boyer stats->dequeued_count += count;
571*aacc5f13SAndrew Boyer
57280518852SAndrew Boyer return count;
57380518852SAndrew Boyer }
57480518852SAndrew Boyer
575dddfb0d9SAndrew Boyer static struct rte_cryptodev_ops iocpt_ops = {
576dddfb0d9SAndrew Boyer .dev_configure = iocpt_op_config,
57780518852SAndrew Boyer .dev_start = iocpt_op_start,
57880518852SAndrew Boyer .dev_stop = iocpt_op_stop,
579dddfb0d9SAndrew Boyer .dev_close = iocpt_op_close,
580dddfb0d9SAndrew Boyer .dev_infos_get = iocpt_op_info_get,
5816bc7f2cfSAndrew Boyer
582*aacc5f13SAndrew Boyer .stats_get = iocpt_op_stats_get,
583*aacc5f13SAndrew Boyer .stats_reset = iocpt_op_stats_reset,
58480518852SAndrew Boyer .queue_pair_setup = iocpt_op_queue_setup,
58580518852SAndrew Boyer .queue_pair_release = iocpt_op_queue_release,
58680518852SAndrew Boyer
5876bc7f2cfSAndrew Boyer .sym_session_get_size = iocpt_op_get_session_size,
5886bc7f2cfSAndrew Boyer .sym_session_configure = iocpt_op_session_cfg,
5896bc7f2cfSAndrew Boyer .sym_session_clear = iocpt_op_session_clear,
590dddfb0d9SAndrew Boyer };
591dddfb0d9SAndrew Boyer
592dddfb0d9SAndrew Boyer int
iocpt_assign_ops(struct rte_cryptodev * cdev)593dddfb0d9SAndrew Boyer iocpt_assign_ops(struct rte_cryptodev *cdev)
594dddfb0d9SAndrew Boyer {
595dddfb0d9SAndrew Boyer struct iocpt_dev *dev = cdev->data->dev_private;
596dddfb0d9SAndrew Boyer
597dddfb0d9SAndrew Boyer cdev->dev_ops = &iocpt_ops;
598dddfb0d9SAndrew Boyer cdev->feature_flags = dev->features;
599dddfb0d9SAndrew Boyer
60080518852SAndrew Boyer if (dev->features & RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO) {
60180518852SAndrew Boyer cdev->enqueue_burst = iocpt_enqueue_sym;
60280518852SAndrew Boyer cdev->dequeue_burst = iocpt_dequeue_sym;
60380518852SAndrew Boyer }
60480518852SAndrew Boyer
605dddfb0d9SAndrew Boyer return 0;
606dddfb0d9SAndrew Boyer }
607