[01/11] common/cnxk: free pending sqe buffers

Message ID 20221128095442.3185112-1-ndabilpuram@marvell.com (mailing list archive)
State Accepted, archived
Delegated to: Jerin Jacob
Headers
Series [01/11] common/cnxk: free pending sqe buffers |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/loongarch-compilation warning apply patch failure
ci/iol-testing warning apply patch failure

Commit Message

Nithin Dabilpuram Nov. 28, 2022, 9:54 a.m. UTC
  From: Satha Rao <skoteshwar@marvell.com>

This patch provides a callback mechanism when SQ receives MNQ_ERR.
Even when SQ got MNQ_ERR interrupt application still enqueue
packets for sending they will be struck at SQ, so we are freeing
all these pending packets when we called SQ finish.

Signed-off-by: Satha Rao <skoteshwar@marvell.com>
---

Depends-on: series-25794 ("net/cnxk: rework no-fast-free offload handling")

 drivers/common/cnxk/roc_dev_priv.h  |   4 +
 drivers/common/cnxk/roc_nix.h       |   5 +
 drivers/common/cnxk/roc_nix_irq.c   |  11 ++-
 drivers/common/cnxk/roc_nix_priv.h  |   2 +
 drivers/common/cnxk/roc_nix_queue.c |  32 +++++--
 drivers/common/cnxk/roc_nix_tm.c    | 141 +++++++++++++++++++++++++++-
 drivers/common/cnxk/version.map     |   2 +
 7 files changed, 186 insertions(+), 11 deletions(-)
  

Patch

diff --git a/drivers/common/cnxk/roc_dev_priv.h b/drivers/common/cnxk/roc_dev_priv.h
index 302dc0feb0..e21a7154c0 100644
--- a/drivers/common/cnxk/roc_dev_priv.h
+++ b/drivers/common/cnxk/roc_dev_priv.h
@@ -30,6 +30,9 @@  typedef void (*link_info_t)(void *roc_nix,
 /* PTP info callback */
 typedef int (*ptp_info_t)(void *roc_nix, bool enable);
 
+/* Queue Error get callback */
+typedef void (*q_err_cb_t)(void *roc_nix, void *data);
+
 /* Link status get callback */
 typedef void (*link_status_get_t)(void *roc_nix,
 				  struct cgx_link_user_info *link);
@@ -38,6 +41,7 @@  struct dev_ops {
 	link_info_t link_status_update;
 	ptp_info_t ptp_info_update;
 	link_status_get_t link_status_get;
+	q_err_cb_t q_err_cb;
 };
 
 #define dev_is_vf(dev) ((dev)->hwcap & DEV_HWCAP_F_VF)
diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h
index 6654a2df78..dfc87e8758 100644
--- a/drivers/common/cnxk/roc_nix.h
+++ b/drivers/common/cnxk/roc_nix.h
@@ -405,6 +405,9 @@  typedef void (*link_status_t)(struct roc_nix *roc_nix,
 /* PTP info update callback */
 typedef int (*ptp_info_update_t)(struct roc_nix *roc_nix, bool enable);
 
+/* Queue Error get callback */
+typedef void (*q_err_get_t)(struct roc_nix *roc_nix, void *data);
+
 /* Link status get callback */
 typedef void (*link_info_get_t)(struct roc_nix *roc_nix,
 				struct roc_nix_link_info *link);
@@ -783,6 +786,8 @@  void __roc_api roc_nix_mac_link_cb_unregister(struct roc_nix *roc_nix);
 int __roc_api roc_nix_mac_link_info_get_cb_register(
 	struct roc_nix *roc_nix, link_info_get_t link_info_get);
 void __roc_api roc_nix_mac_link_info_get_cb_unregister(struct roc_nix *roc_nix);
+int __roc_api roc_nix_q_err_cb_register(struct roc_nix *roc_nix, q_err_get_t sq_err_handle);
+void __roc_api roc_nix_q_err_cb_unregister(struct roc_nix *roc_nix);
 
 /* Ops */
 int __roc_api roc_nix_switch_hdr_set(struct roc_nix *roc_nix,
diff --git a/drivers/common/cnxk/roc_nix_irq.c b/drivers/common/cnxk/roc_nix_irq.c
index d72980fb18..661af79193 100644
--- a/drivers/common/cnxk/roc_nix_irq.c
+++ b/drivers/common/cnxk/roc_nix_irq.c
@@ -249,9 +249,9 @@  nix_lf_q_irq(void *param)
 {
 	struct nix_qint *qint = (struct nix_qint *)param;
 	uint8_t irq, qintx = qint->qintx;
+	int q, cq, rq, sq, intr_cb = 0;
 	struct nix *nix = qint->nix;
 	struct dev *dev = &nix->dev;
-	int q, cq, rq, sq;
 	uint64_t intr;
 	uint8_t rc;
 
@@ -301,8 +301,10 @@  nix_lf_q_irq(void *param)
 
 		/* Detect Meta-descriptor enqueue error */
 		rc = nix_lf_sq_debug_reg(nix, NIX_LF_MNQ_ERR_DBG);
-		if (rc)
+		if (rc) {
 			plt_err("SQ=%d NIX_SQINT_MNQ_ERR, errcode %x", sq, rc);
+			intr_cb = 1;
+		}
 
 		/* Detect Send error */
 		rc = nix_lf_sq_debug_reg(nix, NIX_LF_SEND_ERR_DBG);
@@ -321,6 +323,11 @@  nix_lf_q_irq(void *param)
 	/* Dump registers to std out */
 	roc_nix_lf_reg_dump(nix_priv_to_roc_nix(nix), NULL);
 	roc_nix_queues_ctx_dump(nix_priv_to_roc_nix(nix), NULL);
+
+	/* Call reset callback */
+	if (intr_cb)
+		if (dev->ops->q_err_cb)
+			dev->ops->q_err_cb(nix_priv_to_roc_nix(nix), NULL);
 }
 
 int
diff --git a/drivers/common/cnxk/roc_nix_priv.h b/drivers/common/cnxk/roc_nix_priv.h
index 2eba44c248..02290a1b86 100644
--- a/drivers/common/cnxk/roc_nix_priv.h
+++ b/drivers/common/cnxk/roc_nix_priv.h
@@ -406,6 +406,8 @@  int nix_tm_bp_config_set(struct roc_nix *roc_nix, uint16_t sq, uint16_t tc,
 			 bool enable, bool force_flush);
 void nix_rq_vwqe_flush(struct roc_nix_rq *rq, uint16_t vwqe_interval);
 int nix_tm_mark_init(struct nix *nix);
+void nix_tm_sq_free_sqe_buffer(uint64_t *sqe, int head_off, int end_off, int instr_sz);
+int roc_nix_tm_sq_free_pending_sqe(struct nix *nix, int q);
 
 /*
  * TM priv utils.
diff --git a/drivers/common/cnxk/roc_nix_queue.c b/drivers/common/cnxk/roc_nix_queue.c
index 1cb1fd2101..8a84a34bef 100644
--- a/drivers/common/cnxk/roc_nix_queue.c
+++ b/drivers/common/cnxk/roc_nix_queue.c
@@ -1089,9 +1089,8 @@  sq_cn9k_fini(struct nix *nix, struct roc_nix_sq *sq)
 	while (count) {
 		void *next_sqb;
 
-		next_sqb = *(void **)((uintptr_t)sqb_buf +
-				      (uint32_t)((sqes_per_sqb - 1) *
-						 sq->max_sqe_sz));
+		next_sqb = *(void **)((uint64_t *)sqb_buf +
+				      (uint32_t)((sqes_per_sqb - 1) * (0x2 >> sq->max_sqe_sz) * 8));
 		roc_npa_aura_op_free(sq->aura_handle, 1, (uint64_t)sqb_buf);
 		sqb_buf = next_sqb;
 		count--;
@@ -1206,9 +1205,8 @@  sq_fini(struct nix *nix, struct roc_nix_sq *sq)
 	while (count) {
 		void *next_sqb;
 
-		next_sqb = *(void **)((uintptr_t)sqb_buf +
-				      (uint32_t)((sqes_per_sqb - 1) *
-						 sq->max_sqe_sz));
+		next_sqb = *(void **)((uint64_t *)sqb_buf +
+				      (uint32_t)((sqes_per_sqb - 1) * (0x2 >> sq->max_sqe_sz) * 8));
 		roc_npa_aura_op_free(sq->aura_handle, 1, (uint64_t)sqb_buf);
 		sqb_buf = next_sqb;
 		count--;
@@ -1386,3 +1384,25 @@  roc_nix_sq_head_tail_get(struct roc_nix *roc_nix, uint16_t qid, uint32_t *head,
 	/* Update tail index as per used sqb count */
 	*tail += (sqes_per_sqb * (sqb_cnt - 1));
 }
+
+int
+roc_nix_q_err_cb_register(struct roc_nix *roc_nix, q_err_get_t sq_err_handle)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct dev *dev = &nix->dev;
+
+	if (sq_err_handle == NULL)
+		return NIX_ERR_PARAM;
+
+	dev->ops->q_err_cb = (q_err_cb_t)sq_err_handle;
+	return 0;
+}
+
+void
+roc_nix_q_err_cb_unregister(struct roc_nix *roc_nix)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct dev *dev = &nix->dev;
+
+	dev->ops->q_err_cb = NULL;
+}
diff --git a/drivers/common/cnxk/roc_nix_tm.c b/drivers/common/cnxk/roc_nix_tm.c
index be8da714cd..255ca83f48 100644
--- a/drivers/common/cnxk/roc_nix_tm.c
+++ b/drivers/common/cnxk/roc_nix_tm.c
@@ -607,6 +607,136 @@  roc_nix_tm_sq_flush_spin(struct roc_nix_sq *sq)
 	return -EFAULT;
 }
 
+void
+nix_tm_sq_free_sqe_buffer(uint64_t *sqe, int head_off, int end_off, int instr_sz)
+{
+	int i, j, inc = (8 * (0x2 >> instr_sz)), segs;
+	struct nix_send_hdr_s *send_hdr;
+	uint64_t *ptr, aura_handle;
+	struct idev_cfg *idev;
+
+	if (!sqe)
+		return;
+
+	idev = idev_get_cfg();
+	if (idev == NULL)
+		return;
+
+	ptr = sqe + (head_off * inc);
+	for (i = head_off; i < end_off; i++) {
+		ptr = sqe + (i * inc);
+		send_hdr = (struct nix_send_hdr_s *)(ptr);
+		aura_handle = roc_npa_aura_handle_gen(send_hdr->w0.aura, idev->npa->base);
+		ptr += 2;
+		if (((*ptr >> 60) & 0xF) == NIX_SUBDC_EXT)
+			ptr += 2;
+		if (((*ptr >> 60) & 0xF) == NIX_SUBDC_AGE_AND_STATS)
+			ptr += 2;
+		if (((*ptr >> 60) & 0xF) == NIX_SUBDC_JUMP) {
+			ptr += 1;
+			ptr = (uint64_t *)*ptr;
+		}
+		if (((*ptr >> 60) & 0xF) == NIX_SUBDC_CRC)
+			ptr += 2;
+		/* We are not parsing immediate send descriptor */
+		if (((*ptr >> 60) & 0xF) == NIX_SUBDC_IMM)
+			continue;
+		while (1) {
+			if (((*ptr >> 60) & 0xF) == NIX_SUBDC_SG) {
+				segs = (*ptr >> 48) & 0x3;
+				ptr += 1;
+				for (j = 0; j < segs; j++) {
+					roc_npa_aura_op_free(aura_handle, 0, *ptr);
+					ptr += 1;
+				}
+				if (segs == 2)
+					ptr += 1;
+			} else if (((*ptr >> 60) & 0xF) == NIX_SUBDC_SG2) {
+				uint64_t aura = (*ptr >> 16) & 0xFFFFF;
+
+				aura = roc_npa_aura_handle_gen(aura, idev->npa->base);
+				ptr += 1;
+				roc_npa_aura_op_free(aura, 0, *ptr);
+				ptr += 1;
+			} else
+				break;
+		}
+	}
+}
+
+int
+roc_nix_tm_sq_free_pending_sqe(struct nix *nix, int q)
+{
+	int head_off, count, rc = 0, tail_off;
+	struct roc_nix_sq *sq = nix->sqs[q];
+	void *sqb_buf, *dat, *tail_sqb;
+	struct dev *dev = &nix->dev;
+	struct ndc_sync_op *ndc_req;
+	uint16_t sqes_per_sqb;
+	struct mbox *mbox;
+
+	mbox = dev->mbox;
+	/* Sync NDC-NIX-TX for LF */
+	ndc_req = mbox_alloc_msg_ndc_sync_op(mbox);
+	if (ndc_req == NULL)
+		return -EFAULT;
+
+	ndc_req->nix_lf_tx_sync = 1;
+	if (mbox_process(mbox))
+		rc |= NIX_ERR_NDC_SYNC;
+
+	if (rc)
+		plt_err("NDC_SYNC failed rc %d", rc);
+
+	rc = nix_q_ctx_get(dev, NIX_AQ_CTYPE_SQ, q, (void *)&dat);
+
+	if (roc_model_is_cn9k()) {
+		volatile struct nix_sq_ctx_s *ctx = (struct nix_sq_ctx_s *)dat;
+
+		/* We will cleanup SQE buffers only when we received MNQ interrupt */
+		if (!ctx->mnq_dis)
+			return -EFAULT;
+
+		count = ctx->sqb_count;
+		sqb_buf = (void *)ctx->head_sqb;
+		tail_sqb = (void *)ctx->tail_sqb;
+		head_off = ctx->head_offset;
+		tail_off = ctx->tail_offset;
+	} else {
+		volatile struct nix_cn10k_sq_ctx_s *ctx = (struct nix_cn10k_sq_ctx_s *)dat;
+
+		/* We will cleanup SQE buffers only when we received MNQ interrupt */
+		if (!ctx->mnq_dis)
+			return -EFAULT;
+
+		count = ctx->sqb_count;
+		/* Free SQB's that are used */
+		sqb_buf = (void *)ctx->head_sqb;
+		tail_sqb = (void *)ctx->tail_sqb;
+		head_off = ctx->head_offset;
+		tail_off = ctx->tail_offset;
+	}
+	sqes_per_sqb = 1 << sq->sqes_per_sqb_log2;
+	/* Free SQB's that are used */
+	while (count) {
+		void *next_sqb;
+
+		if (sqb_buf == tail_sqb)
+			nix_tm_sq_free_sqe_buffer(sqb_buf, head_off, tail_off, sq->max_sqe_sz);
+		else
+			nix_tm_sq_free_sqe_buffer(sqb_buf, head_off, (sqes_per_sqb - 1),
+						  sq->max_sqe_sz);
+		next_sqb = *(void **)((uint64_t *)sqb_buf +
+				      (uint32_t)((sqes_per_sqb - 1) * (0x2 >> sq->max_sqe_sz) * 8));
+		roc_npa_aura_op_free(sq->aura_handle, 1, (uint64_t)sqb_buf);
+		sqb_buf = next_sqb;
+		head_off = 0;
+		count--;
+	}
+
+	return 0;
+}
+
 /* Flush and disable tx queue and its parent SMQ */
 int
 nix_tm_sq_flush_pre(struct roc_nix_sq *sq)
@@ -635,7 +765,7 @@  nix_tm_sq_flush_pre(struct roc_nix_sq *sq)
 
 	/* Find the node for this SQ */
 	node = nix_tm_node_search(nix, qid, tree);
-	if (!node || !(node->flags & NIX_TM_NODE_ENABLED)) {
+	if (!node) {
 		plt_err("Invalid node/state for sq %u", qid);
 		return -EFAULT;
 	}
@@ -691,8 +821,13 @@  nix_tm_sq_flush_pre(struct roc_nix_sq *sq)
 		/* Wait for sq entries to be flushed */
 		rc = roc_nix_tm_sq_flush_spin(sq);
 		if (rc) {
-			plt_err("Failed to drain sq %u, rc=%d\n", sq->qid, rc);
-			return rc;
+			rc = roc_nix_tm_sq_free_pending_sqe(nix, sq->qid);
+			if (rc) {
+				plt_err("Failed to drain sq %u, rc=%d\n", sq->qid, rc);
+				return rc;
+			}
+			/* Freed all pending SQEs for this SQ, so disable this node */
+			sibling->flags &= ~NIX_TM_NODE_ENABLED;
 		}
 	}
 
diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map
index 17f0ec6b48..70503c0470 100644
--- a/drivers/common/cnxk/version.map
+++ b/drivers/common/cnxk/version.map
@@ -224,6 +224,8 @@  INTERNAL {
 	roc_nix_ptp_rx_ena_dis;
 	roc_nix_ptp_sync_time_adjust;
 	roc_nix_ptp_tx_ena_dis;
+	roc_nix_q_err_cb_register;
+	roc_nix_q_err_cb_unregister;
 	roc_nix_queues_ctx_dump;
 	roc_nix_ras_intr_ena_dis;
 	roc_nix_reassembly_configure;