[v2,8/9] crypto/ionic: add a watchdog operation

Message ID 20240430202144.49899-9-andrew.boyer@amd.com (mailing list archive)
State New
Delegated to: akhil goyal
Headers
Series crypto/ionic: introduce AMD Pensando ionic crypto driver |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Andrew Boyer April 30, 2024, 8:21 p.m. UTC
  If no progress has been made within the timeout, post a dummy operation
using session 0. This will restart the queue in the rare case that a
doorbell is lost inside the device.

Signed-off-by: Andrew Boyer <andrew.boyer@amd.com>
---
 drivers/crypto/ionic/ionic_crypto.h      | 16 ++++
 drivers/crypto/ionic/ionic_crypto_main.c | 31 ++++++++
 drivers/crypto/ionic/ionic_crypto_ops.c  | 97 +++++++++++++++++++++++-
 3 files changed, 142 insertions(+), 2 deletions(-)
  

Patch

diff --git a/drivers/crypto/ionic/ionic_crypto.h b/drivers/crypto/ionic/ionic_crypto.h
index e05b458926..69c17887fb 100644
--- a/drivers/crypto/ionic/ionic_crypto.h
+++ b/drivers/crypto/ionic/ionic_crypto.h
@@ -89,6 +89,14 @@  struct iocpt_dev_bars {
 	uint32_t num_bars;
 };
 
+/* Queue watchdog */
+#define IOCPT_Q_WDOG_SESS_IDX		0
+#define IOCPT_Q_WDOG_KEY_LEN		16
+#define IOCPT_Q_WDOG_IV_LEN		12
+#define IOCPT_Q_WDOG_PLD_LEN		4
+#define IOCPT_Q_WDOG_TAG_LEN		16
+#define IOCPT_Q_WDOG_OP_TYPE		RTE_CRYPTO_OP_TYPE_UNDEFINED
+
 struct iocpt_qtype_info {
 	uint8_t	 version;
 	uint8_t	 supported;
@@ -162,7 +170,15 @@  struct iocpt_crypto_q {
 	IOCPT_COMMON_FIELDS;
 
 	/* cacheline2 */
+	uint64_t last_wdog_cycles;
 	uint16_t flags;
+
+	/* cacheline3 */
+	uint64_t enqueued_wdogs;
+	uint64_t dequeued_wdogs;
+	uint8_t wdog_iv[IOCPT_Q_WDOG_IV_LEN];
+	uint8_t wdog_pld[IOCPT_Q_WDOG_PLD_LEN];
+	uint8_t wdog_tag[IOCPT_Q_WDOG_TAG_LEN];
 };
 
 #define IOCPT_S_F_INITED	BIT(0)
diff --git a/drivers/crypto/ionic/ionic_crypto_main.c b/drivers/crypto/ionic/ionic_crypto_main.c
index 7693377831..113347c57a 100644
--- a/drivers/crypto/ionic/ionic_crypto_main.c
+++ b/drivers/crypto/ionic/ionic_crypto_main.c
@@ -172,6 +172,22 @@  iocpt_session_write(struct iocpt_session_priv *priv,
 	return 0;
 }
 
+static int
+iocpt_session_wdog(struct iocpt_dev *dev)
+{
+	struct iocpt_session_priv priv = {
+		.dev = dev,
+		.index = IOCPT_Q_WDOG_SESS_IDX,
+		.type = IOCPT_SESS_AEAD_AES_GCM,
+		.key_len = IOCPT_Q_WDOG_KEY_LEN,
+	};
+
+	/* Reserve session 0 for queue watchdog */
+	rte_bitmap_clear(dev->sess_bm, IOCPT_Q_WDOG_SESS_IDX);
+
+	return iocpt_session_write(&priv, IOCPT_SESS_INIT);
+}
+
 int
 iocpt_session_init(struct iocpt_session_priv *priv)
 {
@@ -491,6 +507,9 @@  iocpt_cryptoq_deinit(struct iocpt_crypto_q *cptq)
 		IOCPT_PRINT(DEBUG, "Deinit queue %u returned %d after %u ms",
 			cptq->q.index, err, sleep_cnt * 100);
 
+	IOCPT_PRINT(DEBUG, "Queue %u watchdog: enq %"PRIu64" deq %"PRIu64,
+		cptq->q.index, cptq->enqueued_wdogs, cptq->dequeued_wdogs);
+
 	cptq->flags &= ~IOCPT_Q_F_INITED;
 }
 
@@ -659,9 +678,21 @@  iocpt_init(struct iocpt_dev *dev)
 	if (err != 0)
 		return err;
 
+	/* Write the queue watchdog key */
+	err = iocpt_session_wdog(dev);
+	if (err != 0) {
+		IOCPT_PRINT(ERR, "Cannot setup watchdog session");
+		goto err_out_adminq_deinit;
+	}
+
 	dev->state |= IOCPT_DEV_F_INITED;
 
 	return 0;
+
+err_out_adminq_deinit:
+	iocpt_adminq_deinit(dev);
+
+	return err;
 }
 
 void
diff --git a/drivers/crypto/ionic/ionic_crypto_ops.c b/drivers/crypto/ionic/ionic_crypto_ops.c
index 28b099dea2..0330fd76ad 100644
--- a/drivers/crypto/ionic/ionic_crypto_ops.c
+++ b/drivers/crypto/ionic/ionic_crypto_ops.c
@@ -58,7 +58,8 @@  iocpt_op_info_get(struct rte_cryptodev *cdev, struct rte_cryptodev_info *info)
 	info->max_nb_queue_pairs = dev->max_qps;
 	info->feature_flags = dev->features;
 	info->capabilities = iocpt_get_caps(info->feature_flags);
-	info->sym.max_nb_sessions = dev->max_sessions;
+	/* Reserve one session for watchdog */
+	info->sym.max_nb_sessions = dev->max_sessions - 1;
 	info->driver_id = dev->driver_id;
 	info->min_mbuf_headroom_req = 0;
 	info->min_mbuf_tailroom_req = 0;
@@ -380,12 +381,72 @@  iocpt_enqueue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		count++;
 	}
 
-	if (likely(count > 0))
+	if (likely(count > 0)) {
 		iocpt_q_flush(&cptq->q);
 
+		/* Restart timer if ops are being enqueued */
+		cptq->last_wdog_cycles = rte_get_timer_cycles();
+	}
+
 	return count;
 }
 
+static void
+iocpt_enqueue_wdog(struct iocpt_crypto_q *cptq)
+{
+	struct iocpt_queue *q = &cptq->q;
+	struct iocpt_crypto_desc *desc, *desc_base = q->base;
+	struct iocpt_crypto_sg_desc *sg_desc, *sg_desc_base = q->sg_base;
+	struct iocpt_crypto_sg_elem *src;
+	struct rte_crypto_op *wdog_op;
+	rte_iova_t iv_addr, pld_addr, tag_addr;
+	uint8_t nsge_src = 0;
+	uint16_t avail;
+
+	avail = iocpt_q_space_avail(&cptq->q);
+	if (avail < 1)
+		goto out_flush;
+
+	wdog_op = rte_zmalloc_socket("iocpt", sizeof(*wdog_op),
+				RTE_CACHE_LINE_SIZE, rte_socket_id());
+	if (wdog_op == NULL)
+		goto out_flush;
+
+	wdog_op->type = IOCPT_Q_WDOG_OP_TYPE;
+	wdog_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+	desc = &desc_base[q->head_idx];
+	sg_desc = &sg_desc_base[q->head_idx];
+	src = sg_desc->src_elems;
+
+	/* Fill the first SGE with the IV / Nonce */
+	iv_addr = rte_mem_virt2iova(cptq->wdog_iv);
+	iocpt_fill_sge(src, nsge_src++, iv_addr, IOCPT_Q_WDOG_IV_LEN);
+
+	/* Fill the second SGE with the payload segment */
+	pld_addr = rte_mem_virt2iova(cptq->wdog_pld);
+	iocpt_fill_sge(src, nsge_src++, pld_addr, IOCPT_Q_WDOG_PLD_LEN);
+
+	/* AEAD AES-GCM: digest == authentication tag */
+	tag_addr = rte_mem_virt2iova(cptq->wdog_tag);
+	iocpt_fill_sge(src, nsge_src++, tag_addr, IOCPT_Q_WDOG_TAG_LEN);
+
+	desc->opcode = IOCPT_DESC_OPCODE_GCM_AEAD_ENCRYPT;
+	desc->flags = 0;
+	desc->num_src_dst_sgs = iocpt_encode_nsge_src_dst(nsge_src, 0);
+	desc->session_tag = rte_cpu_to_le_32(IOCPT_Q_WDOG_SESS_IDX);
+
+	q->info[q->head_idx] = wdog_op;
+	q->head_idx = Q_NEXT_TO_POST(q, 1);
+
+	IOCPT_PRINT(DEBUG, "Queue %u wdog enq %p",
+		q->index, wdog_op);
+	cptq->enqueued_wdogs++;
+
+out_flush:
+	iocpt_q_flush(q);
+}
+
 static uint16_t
 iocpt_dequeue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 {
@@ -395,6 +456,7 @@  iocpt_dequeue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	struct rte_crypto_op *op;
 	struct iocpt_crypto_comp *cq_desc_base = cq->base;
 	volatile struct iocpt_crypto_comp *cq_desc;
+	uint64_t then, now, hz, delta;
 	uint16_t count = 0;
 
 	cq_desc = &cq_desc_base[cq->tail_idx];
@@ -442,6 +504,17 @@  iocpt_dequeue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		    op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
 			break;
 
+		/* Handle watchdog operations */
+		if (unlikely(op->type == IOCPT_Q_WDOG_OP_TYPE)) {
+			IOCPT_PRINT(DEBUG, "Queue %u wdog deq %p st %d",
+				q->index, op, op->status);
+			q->info[q->tail_idx] = NULL;
+			q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
+			cptq->dequeued_wdogs++;
+			rte_free(op);
+			continue;
+		}
+
 		ops[count] = op;
 		q->info[q->tail_idx] = NULL;
 
@@ -449,6 +522,26 @@  iocpt_dequeue_sym(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		count++;
 	}
 
+	if (!count) {
+		/*
+		 * Ring the doorbell again if no work was dequeued and work
+		 * is still pending after the deadline.
+		 */
+		if (q->head_idx != q->tail_idx) {
+			then = cptq->last_wdog_cycles;
+			now = rte_get_timer_cycles();
+			hz = rte_get_timer_hz();
+			delta = (now - then) * 1000;
+
+			if (delta >= hz * IONIC_Q_WDOG_MS) {
+				iocpt_enqueue_wdog(cptq);
+				cptq->last_wdog_cycles = now;
+			}
+		}
+	} else
+		/* Restart timer if the queue is making progress */
+		cptq->last_wdog_cycles = rte_get_timer_cycles();
+
 	return count;
 }