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