DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] net/mlx5: add queue hardware object context dump
@ 2024-06-04 21:11 Kiran Vedere
  2024-06-10  5:59 ` Slava Ovsiienko
  0 siblings, 1 reply; 2+ messages in thread
From: Kiran Vedere @ 2024-06-04 21:11 UTC (permalink / raw)
  To: dev; +Cc: matan, rasland, viacheslavo, dsosnowski

Add debug capability to mlx5 PMD to dump SQ/RQ/CQ HW object context for
a given port/queue. The context dump can provide some real-time
information on cause of certain Tx/Rx Failures.

Signed-off-by: Kiran Vedere <kiranv@nvidia.com>
---
 .mailmap                               |   1 +
 doc/guides/nics/mlx5.rst               |  11 ++
 doc/guides/rel_notes/release_24_07.rst |   5 +
 drivers/common/mlx5/mlx5_devx_cmds.c   |  87 +++++++++++++
 drivers/common/mlx5/mlx5_devx_cmds.h   |   9 ++
 drivers/common/mlx5/mlx5_prm.h         |  30 +++++
 drivers/common/mlx5/version.map        |   3 +
 drivers/net/mlx5/mlx5_rx.c             |  82 ++++++++++++
 drivers/net/mlx5/mlx5_rxtx.c           |  24 ++++
 drivers/net/mlx5/mlx5_rxtx.h           |   2 +
 drivers/net/mlx5/mlx5_testpmd.c        | 174 +++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_tx.c             |  85 ++++++++++++
 drivers/net/mlx5/rte_pmd_mlx5.h        |  36 +++++
 drivers/net/mlx5/version.map           |   2 +
 14 files changed, 551 insertions(+)

diff --git a/.mailmap b/.mailmap
index 87fa24714e..a5ee56fe0c 100644
--- a/.mailmap
+++ b/.mailmap
@@ -762,6 +762,7 @@ Kiran KN <kirankn@juniper.net>
 Kiran Kumar K <kirankumark@marvell.com>
 Kiran Kumar <kkokkilagadda@caviumnetworks.com> <kiran.kokkilagadda@caviumnetworks.com>
 Kiran Patil <kiran.patil@intel.com>
+Kiran Vedere <kiranv@nvidia.com>
 Kirill Rybalchenko <kirill.rybalchenko@intel.com>
 Kishore Padmanabha <kishore.padmanabha@broadcom.com>
 Klaus Degner <kd@allegro-packets.com>
diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index b5928d40b2..40e36de7e8 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -2601,3 +2601,14 @@ Destroy GENEVE TLV parser for specific port::
 
 This command doesn't destroy the global list,
 For releasing options, ``flush`` command should be used.
+
+Dump RQ/SQ/CQ HW Context for debug purposes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Dump RQ/CQ HW Context for a given port/queue to a file:
+
+   testpmd> mlx5 port (port_id) queue (queue_id) dump rq_context (file_name)
+
+Dump SQ/CQ HW Context for a given port/queue to a file:
+
+   testpmd> mlx5 port (port_id) queue (queue_id) dump sq_context (file_name)
diff --git a/doc/guides/rel_notes/release_24_07.rst b/doc/guides/rel_notes/release_24_07.rst
index ffbe9ce051..c18a0be469 100644
--- a/doc/guides/rel_notes/release_24_07.rst
+++ b/doc/guides/rel_notes/release_24_07.rst
@@ -81,6 +81,11 @@ New Features
 
   * Added SSE/NEON vector datapath.
 
+* **Add Queue Hardware object context dump.**
+
+  * Added debug capability  to mlx5 PMD to dump SQ/RQ/CQ HW object context for
+    a given port/queue. The context dump could provide useful information when
+    debugging certain Rx/Tx Failures.
 
 Removed Items
 -------------
diff --git a/drivers/common/mlx5/mlx5_devx_cmds.c b/drivers/common/mlx5/mlx5_devx_cmds.c
index 9952733c90..8d8af700f2 100644
--- a/drivers/common/mlx5/mlx5_devx_cmds.c
+++ b/drivers/common/mlx5/mlx5_devx_cmds.c
@@ -1594,6 +1594,35 @@ mlx5_devx_cmd_modify_rq(struct mlx5_devx_obj *rq,
 	return ret;
 }
 
+/*
+ * Query RQ using DevX API.
+ *
+ * @param[in] rq_obj
+ *   RQ Devx Object
+ * @param[out] out
+ *   RQ Query Output
+ * @param[in] outlen
+ *   RQ Query Output Length
+ *
+ * @return
+ *   0 if Query successful, else non-zero return value from devx_obj_query API
+ */
+int
+mlx5_devx_cmd_query_rq(struct mlx5_devx_obj *rq_obj, void *out, size_t outlen)
+{
+	uint32_t in[MLX5_ST_SZ_DW(query_rq_in)] = {0};
+	int rc;
+
+	MLX5_SET(query_rq_in, in, opcode, MLX5_CMD_OP_QUERY_RQ);
+	MLX5_SET(query_rq_in, in, rqn, rq_obj->id);
+	rc = mlx5_glue->devx_obj_query(rq_obj->obj, in, sizeof(in), out, outlen);
+	if (rc || MLX5_FW_STATUS(out)) {
+		DEVX_DRV_LOG(ERR, out, "RQ query", "rq_id", rq_obj->id);
+		return MLX5_DEVX_ERR_RC(rc);
+	}
+	return 0;
+}
+
 /**
  * Create RMP using DevX API.
  *
@@ -2001,6 +2030,35 @@ mlx5_devx_cmd_modify_sq(struct mlx5_devx_obj *sq,
 	return ret;
 }
 
+/*
+ * Query SQ using DevX API.
+ *
+ * @param[in] sq_obj
+ *   SQ Devx Object
+ * @param[out] out
+ *   SQ Query Output
+ * @param[in] outlen
+ *   SQ Query Output Length
+ *
+ * @return
+ *   0 if Query successful, else non-zero return value from devx_obj_query API
+ */
+int
+mlx5_devx_cmd_query_sq(struct mlx5_devx_obj *sq_obj, void *out, size_t outlen)
+{
+	uint32_t in[MLX5_ST_SZ_DW(query_sq_in)] = {0};
+	int rc;
+
+	MLX5_SET(query_sq_in, in, opcode, MLX5_CMD_OP_QUERY_SQ);
+	MLX5_SET(query_sq_in, in, sqn, sq_obj->id);
+	rc = mlx5_glue->devx_obj_query(sq_obj->obj, in, sizeof(in), out, outlen);
+	if (rc || MLX5_FW_STATUS(out)) {
+		DEVX_DRV_LOG(ERR, out, "SQ query", "sq_id", sq_obj->id);
+		return MLX5_DEVX_ERR_RC(rc);
+	}
+	return 0;
+}
+
 /**
  * Create TIS using DevX API.
  *
@@ -2202,6 +2260,35 @@ mlx5_devx_cmd_create_cq(void *ctx, struct mlx5_devx_cq_attr *attr)
 	return cq_obj;
 }
 
+/*
+ * Query CQ using DevX API.
+ *
+ * @param[in] cq_obj
+ *   CQ Devx Object
+ * @param[out] out
+ *   CQ Query Output
+ * @param[in] outlen
+ *   CQ Query Output Length
+ *
+ * @return
+ *   0 if Query successful, else non-zero return value from devx_obj_query API
+ */
+int
+mlx5_devx_cmd_query_cq(struct mlx5_devx_obj *cq_obj, void *out, size_t outlen)
+{
+	uint32_t in[MLX5_ST_SZ_DW(query_cq_in)] = {0};
+	int rc;
+
+	MLX5_SET(query_cq_in, in, opcode, MLX5_CMD_OP_QUERY_CQ);
+	MLX5_SET(query_cq_in, in, cqn, cq_obj->id);
+	rc = mlx5_glue->devx_obj_query(cq_obj->obj, in, sizeof(in), out, outlen);
+	if (rc || MLX5_FW_STATUS(out)) {
+		DEVX_DRV_LOG(ERR, out, "CQ query", "cq_id", cq_obj->id);
+		return MLX5_DEVX_ERR_RC(rc);
+	}
+	return 0;
+}
+
 /**
  * Create VIRTQ using DevX API.
  *
diff --git a/drivers/common/mlx5/mlx5_devx_cmds.h b/drivers/common/mlx5/mlx5_devx_cmds.h
index c79f8dc48d..540f002088 100644
--- a/drivers/common/mlx5/mlx5_devx_cmds.h
+++ b/drivers/common/mlx5/mlx5_devx_cmds.h
@@ -735,6 +735,15 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_sq(void *ctx,
 __rte_internal
 int mlx5_devx_cmd_modify_sq(struct mlx5_devx_obj *sq,
 			    struct mlx5_devx_modify_sq_attr *sq_attr);
+__rte_internal
+int mlx5_devx_cmd_query_sq(struct mlx5_devx_obj *sq, void *out, size_t outlen);
+
+__rte_internal
+int mlx5_devx_cmd_query_cq(struct mlx5_devx_obj *cq, void *out, size_t outlen);
+
+__rte_internal
+int mlx5_devx_cmd_query_rq(struct mlx5_devx_obj *rq, void *out, size_t outlen);
+
 __rte_internal
 struct mlx5_devx_obj *mlx5_devx_cmd_create_tis(void *ctx,
 					   struct mlx5_devx_tis_attr *tis_attr);
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index 178a18a978..359f02f17c 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -1215,6 +1215,7 @@ enum {
 	MLX5_CMD_OP_QUERY_HCA_CAP = 0x100,
 	MLX5_CMD_OP_CREATE_MKEY = 0x200,
 	MLX5_CMD_OP_CREATE_CQ = 0x400,
+	MLX5_CMD_OP_QUERY_CQ = 0x402,
 	MLX5_CMD_OP_CREATE_QP = 0x500,
 	MLX5_CMD_OP_RST2INIT_QP = 0x502,
 	MLX5_CMD_OP_INIT2RTR_QP = 0x503,
@@ -1240,6 +1241,7 @@ enum {
 	MLX5_CMD_OP_MODIFY_TIR = 0x901,
 	MLX5_CMD_OP_CREATE_SQ = 0X904,
 	MLX5_CMD_OP_MODIFY_SQ = 0X905,
+	MLX5_CMD_OP_QUERY_SQ = 0x907,
 	MLX5_CMD_OP_CREATE_RQ = 0x908,
 	MLX5_CMD_OP_MODIFY_RQ = 0x909,
 	MLX5_CMD_OP_QUERY_RQ = 0x90b,
@@ -3140,6 +3142,14 @@ struct mlx5_ifc_sqc_bits {
 	struct mlx5_ifc_wq_bits wq;
 };
 
+struct mlx5_ifc_query_sq_out_bits {
+	u8 status[0x8];
+	u8 reserved_at_8[0x18];
+	u8 syndrome[0x20];
+	u8 reserved_at_40[0xc0];
+	struct mlx5_ifc_sqc_bits sq_context;
+};
+
 struct mlx5_ifc_query_sq_in_bits {
 	u8 opcode[0x10];
 	u8 reserved_at_10[0x10];
@@ -3361,6 +3371,26 @@ struct mlx5_ifc_create_cq_in_bits {
 	u8 pas[];
 };
 
+struct mlx5_ifc_query_cq_out_bits {
+	u8 status[0x8];
+	u8 reserved_at_8[0x18];
+	u8 syndrome[0x20];
+	u8 reserved_at_40[0x40];
+	struct mlx5_ifc_cqc_bits cq_context;
+	u8 reserved_at_280[0x600];
+	u8 pas[][0x40];
+};
+
+struct mlx5_ifc_query_cq_in_bits {
+	u8 opcode[0x10];
+	u8 reserved_at_10[0x10];
+	u8 reserved_at_20[0x10];
+	u8 op_mod[0x10];
+	u8 reserved_at_40[0x8];
+	u8 cqn[0x18];
+	u8 reserved_at_60[0x20];
+};
+
 enum {
 	MLX5_GENERAL_OBJ_TYPE_GENEVE_TLV_OPT = 0x000b,
 	MLX5_GENERAL_OBJ_TYPE_DEK = 0x000c,
diff --git a/drivers/common/mlx5/version.map b/drivers/common/mlx5/version.map
index 589a450145..a2f72ef46a 100644
--- a/drivers/common/mlx5/version.map
+++ b/drivers/common/mlx5/version.map
@@ -51,6 +51,9 @@ INTERNAL {
 	mlx5_devx_cmd_modify_rq;
 	mlx5_devx_cmd_modify_rqt;
 	mlx5_devx_cmd_modify_sq;
+	mlx5_devx_cmd_query_sq;
+	mlx5_devx_cmd_query_rq;
+	mlx5_devx_cmd_query_cq;
 	mlx5_devx_cmd_modify_tir;
 	mlx5_devx_cmd_modify_virtq;
 	mlx5_devx_cmd_qp_query_tis_td;
diff --git a/drivers/net/mlx5/mlx5_rx.c b/drivers/net/mlx5/mlx5_rx.c
index cc087348a4..f241809e08 100644
--- a/drivers/net/mlx5/mlx5_rx.c
+++ b/drivers/net/mlx5/mlx5_rx.c
@@ -1586,3 +1586,85 @@ int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate,
 	return mlxreg_host_shaper_config(dev, priv->sh->lwm_triggered,
 					 priv->sh->host_shaper_rate);
 }
+
+/**
+ * Dump RQ/CQ Context to a file.
+ *
+ * @param[in] port_id
+ *   Port ID
+ * @param[in] queue_id
+ *   Queue ID
+ * @param[in] filename
+ *   Name of file to dump the Rx Queue Context
+ *
+ * @return
+ *   0 for Success, non-zero value depending on failure type
+ */
+int rte_pmd_mlx5_rxq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename)
+{
+	struct rte_eth_dev *dev;
+	struct mlx5_rxq_priv *rxq;
+	struct mlx5_rxq_ctrl *rxq_ctrl;
+	struct mlx5_rxq_obj *rxq_obj;
+	struct mlx5_devx_rq *rq;
+	struct mlx5_devx_cq *cq;
+	struct mlx5_devx_obj *rq_devx_obj;
+	struct mlx5_devx_obj *cq_devx_obj;
+
+	uint32_t rq_out[MLX5_ST_SZ_DW(query_rq_out)] = {0};
+	uint32_t cq_out[MLX5_ST_SZ_DW(query_cq_out)] = {0};
+
+	int ret;
+	FILE *fd;
+	MKSTR(path, "./%s", filename);
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	if (rte_eth_rx_queue_is_valid(port_id, queue_id))
+		return -EINVAL;
+
+	fd = fopen(path, "w");
+	if (!fd) {
+		rte_errno = errno;
+		return -EIO;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	rxq = mlx5_rxq_ref(dev, queue_id);
+	rxq_ctrl = rxq->ctrl;
+	rxq_obj = rxq_ctrl->obj;
+	rq = &rxq->devx_rq;
+	cq = &rxq_obj->cq_obj;
+	rq_devx_obj = rq->rq;
+	cq_devx_obj = cq->cq;
+
+	do {
+		ret = mlx5_devx_cmd_query_rq(rq_devx_obj, rq_out, sizeof(rq_out));
+		if (ret)
+			break;
+
+		/* Dump rq query output to file */
+		MKSTR(rq_headline, "RQ DevX ID = %u Port = %u Queue index = %u ",
+					rq_devx_obj->id, port_id, queue_id);
+		mlx5_dump_to_file(fd, NULL, rq_headline, 0);
+		mlx5_dump_to_file(fd, "Query RQ Dump:",
+					(const void *)((uintptr_t)rq_out),
+					sizeof(rq_out));
+
+		ret = mlx5_devx_cmd_query_cq(cq_devx_obj, cq_out, sizeof(cq_out));
+		if (ret)
+			break;
+
+		/* Dump cq query output to file */
+		MKSTR(cq_headline, "CQ DevX ID = %u Port = %u Queue index = %u ",
+					cq_devx_obj->id, port_id, queue_id);
+		mlx5_dump_to_file(fd, NULL, cq_headline, 0);
+		mlx5_dump_to_file(fd, "Query CQ Dump:",
+					(const void *)((uintptr_t)cq_out),
+					sizeof(cq_out));
+	} while (false);
+
+	fclose(fd);
+	return ret;
+}
diff --git a/drivers/net/mlx5/mlx5_rxtx.c b/drivers/net/mlx5/mlx5_rxtx.c
index d3d4470acd..eadadcdffb 100644
--- a/drivers/net/mlx5/mlx5_rxtx.c
+++ b/drivers/net/mlx5/mlx5_rxtx.c
@@ -353,6 +353,30 @@ mlx5_dump_debug_information(const char *fname, const char *hex_title,
 	fclose(fd);
 }
 
+/**
+ * Dump information to a logfile
+ *
+ * @param fd
+ *   File descriptor to logfile. File descriptor open/close is managed by caller.
+ * @param title
+ *   If not NULL this string is printed as a header to the output
+ *   and the output will be in hexadecimal view.
+ * @param buf
+ *   This is the buffer address to print out.
+ * @param len
+ *   The number of bytes to dump out.
+ */
+void
+mlx5_dump_to_file(FILE *fd, const char *title,
+			    const void *buf, unsigned int len)
+{
+	if (title)
+		rte_hexdump(fd, title, buf, len);
+	else
+		fprintf(fd, "%s", (const char *)buf);
+	fprintf(fd, "\n\n\n");
+}
+
 /**
  * Modify a Verbs/DevX queue state.
  * This must be called from the primary process.
diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h
index b109d50758..3fa9245769 100644
--- a/drivers/net/mlx5/mlx5_rxtx.h
+++ b/drivers/net/mlx5/mlx5_rxtx.h
@@ -38,6 +38,8 @@ void mlx5_set_cksum_table(void);
 void mlx5_set_swp_types_table(void);
 void mlx5_dump_debug_information(const char *path, const char *title,
 				 const void *buf, unsigned int len);
+void mlx5_dump_to_file(FILE *fd, const char *title,
+				 const void *buf, unsigned int len);
 int mlx5_queue_state_modify_primary(struct rte_eth_dev *dev,
 			const struct mlx5_mp_arg_queue_state_modify *sm);
 int mlx5_queue_state_modify(struct rte_eth_dev *dev,
diff --git a/drivers/net/mlx5/mlx5_testpmd.c b/drivers/net/mlx5/mlx5_testpmd.c
index 5bc4dd0551..1bb5a89559 100644
--- a/drivers/net/mlx5/mlx5_testpmd.c
+++ b/drivers/net/mlx5/mlx5_testpmd.c
@@ -1201,6 +1201,170 @@ cmdline_parse_inst_t mlx5_cmd_destroy_tlv_options = {
 	}
 };
 
+/* Dump SQ Context for a given port/queue*/
+struct mlx5_cmd_dump_sq_context_options {
+	cmdline_fixed_string_t mlx5;
+	cmdline_fixed_string_t port;
+	portid_t port_id;
+	cmdline_fixed_string_t queue;
+	queueid_t queue_id;
+	cmdline_fixed_string_t dump;
+	cmdline_fixed_string_t sq_context;
+	cmdline_fixed_string_t file_name;
+};
+
+cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_mlx5 =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, mlx5,
+				 "mlx5");
+cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_port =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, port,
+				 "port");
+cmdline_parse_token_num_t mlx5_cmd_dump_sq_context_options_port_id =
+	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, port_id,
+			      RTE_UINT16);
+cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_queue =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, queue,
+				 "queue");
+cmdline_parse_token_num_t mlx5_cmd_dump_sq_context_options_queue_id =
+	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, queue_id,
+			      RTE_UINT16);
+cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_dump =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, dump,
+				 "dump");
+cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_sq_context =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, sq_context,
+				 "sq_context");
+cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_file_name =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, file_name,
+				 NULL);
+
+static void
+mlx5_cmd_dump_sq_context_options_parsed(void *parsed_result,
+				    __rte_unused struct cmdline *cl,
+				    __rte_unused void *data)
+{
+	struct mlx5_cmd_dump_sq_context_options *res = parsed_result;
+	int ret;
+
+	ret = rte_pmd_mlx5_txq_dump_contexts(res->port_id, res->queue_id, res->file_name);
+
+	switch (ret) {
+	case 0:
+		break;
+	case -EINVAL:
+		fprintf(stderr, "invalid queue index (%u), out of range\n",
+			res->queue_id);
+		break;
+	case -ENODEV:
+		fprintf(stderr, "invalid port_id %u\n", res->port_id);
+		break;
+	case -EIO:
+		fprintf(stderr, "File Access Error (%s)\n", strerror(rte_errno));
+		break;
+	default:
+		fprintf(stderr, "Unable to dump SQ/CQ HW Context (%s)\n", strerror(rte_errno));
+	}
+}
+
+cmdline_parse_inst_t mlx5_cmd_dump_sq_context_options = {
+	.f = mlx5_cmd_dump_sq_context_options_parsed,
+	.data = NULL,
+	.help_str = "mlx5 port <port_id> queue <queue_id> dump sq_context <file_name>",
+	.tokens = {
+		(void *)&mlx5_cmd_dump_sq_context_options_mlx5,
+		(void *)&mlx5_cmd_dump_sq_context_options_port,
+		(void *)&mlx5_cmd_dump_sq_context_options_port_id,
+		(void *)&mlx5_cmd_dump_sq_context_options_queue,
+		(void *)&mlx5_cmd_dump_sq_context_options_queue_id,
+		(void *)&mlx5_cmd_dump_sq_context_options_dump,
+		(void *)&mlx5_cmd_dump_sq_context_options_sq_context,
+		(void *)&mlx5_cmd_dump_sq_context_options_file_name,
+		NULL,
+	}
+};
+
+/* Dump RQ Context for a given port/queue*/
+struct mlx5_cmd_dump_rq_context_options {
+	cmdline_fixed_string_t mlx5;
+	cmdline_fixed_string_t port;
+	portid_t port_id;
+	cmdline_fixed_string_t queue;
+	queueid_t queue_id;
+	cmdline_fixed_string_t dump;
+	cmdline_fixed_string_t rq_context;
+	cmdline_fixed_string_t file_name;
+};
+
+cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_mlx5 =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, mlx5,
+				 "mlx5");
+cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_port =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, port,
+				 "port");
+cmdline_parse_token_num_t mlx5_cmd_dump_rq_context_options_port_id =
+	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, port_id,
+			      RTE_UINT16);
+cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_queue =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, queue,
+				 "queue");
+cmdline_parse_token_num_t mlx5_cmd_dump_rq_context_options_queue_id =
+	TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, queue_id,
+			      RTE_UINT16);
+cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_dump =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, dump,
+				 "dump");
+cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_rq_context =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, rq_context,
+				 "rq_context");
+cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_file_name =
+	TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, file_name,
+				 NULL);
+
+static void
+mlx5_cmd_dump_rq_context_options_parsed(void *parsed_result,
+				    __rte_unused struct cmdline *cl,
+				    __rte_unused void *data)
+{
+	struct mlx5_cmd_dump_rq_context_options *res = parsed_result;
+	int ret;
+
+	ret = rte_pmd_mlx5_rxq_dump_contexts(res->port_id, res->queue_id, res->file_name);
+
+	switch (ret) {
+	case 0:
+		break;
+	case -EINVAL:
+		fprintf(stderr, "invalid queue index (%u), out of range\n",
+			res->queue_id);
+		break;
+	case -ENODEV:
+		fprintf(stderr, "invalid port_id %u\n", res->port_id);
+		break;
+	case -EIO:
+		fprintf(stderr, "File Access Error (%s)\n", strerror(rte_errno));
+		break;
+	default:
+		fprintf(stderr, "Unable to dump RQ/CQ HW Context (%s)\n", strerror(rte_errno));
+	}
+}
+
+cmdline_parse_inst_t mlx5_cmd_dump_rq_context_options = {
+	.f = mlx5_cmd_dump_rq_context_options_parsed,
+	.data = NULL,
+	.help_str = "mlx5 port <port_id> queue <queue_id> dump rq_context <file_name>",
+	.tokens = {
+		(void *)&mlx5_cmd_dump_rq_context_options_mlx5,
+		(void *)&mlx5_cmd_dump_rq_context_options_port,
+		(void *)&mlx5_cmd_dump_rq_context_options_port_id,
+		(void *)&mlx5_cmd_dump_rq_context_options_queue,
+		(void *)&mlx5_cmd_dump_rq_context_options_queue_id,
+		(void *)&mlx5_cmd_dump_rq_context_options_dump,
+		(void *)&mlx5_cmd_dump_rq_context_options_rq_context,
+		(void *)&mlx5_cmd_dump_rq_context_options_file_name,
+		NULL,
+	}
+};
+
 static struct testpmd_driver_commands mlx5_driver_cmds = {
 	.commands = {
 		{
@@ -1266,6 +1430,16 @@ static struct testpmd_driver_commands mlx5_driver_cmds = {
 			.help = "mlx5 port (port_id) destroy tlv_options\n"
 				"    Destroy GENEVE TLV parser\n\n",
 		},
+		{
+			.ctx = &mlx5_cmd_dump_sq_context_options,
+			.help = "mlx5 port (port_id) queue (queue_id) dump sq_context (file_name)\n"
+				"    Dump mlx5 SQ Context\n\n",
+		},
+		{
+			.ctx = &mlx5_cmd_dump_rq_context_options,
+			.help = "mlx5 port (port_id) queue (queue_id) dump rq_context (file_name)\n"
+				"    Dump mlx5 RQ Context\n\n",
+		},
 		{
 			.ctx = NULL,
 		},
diff --git a/drivers/net/mlx5/mlx5_tx.c b/drivers/net/mlx5/mlx5_tx.c
index 1fe9521dfc..04f80bb9bd 100644
--- a/drivers/net/mlx5/mlx5_tx.c
+++ b/drivers/net/mlx5/mlx5_tx.c
@@ -761,3 +761,88 @@ mlx5_tx_burst_mode_get(struct rte_eth_dev *dev,
 	}
 	return -EINVAL;
 }
+
+/**
+ * Dump SQ/CQ Context to a file.
+ *
+ * @param[in] port_id
+ *   Port ID
+ * @param[in] queue_id
+ *   Queue ID
+ * @param[in] filename
+ *   Name of file to dump the Tx Queue Context
+ *
+ * @return
+ *   0 for success, non-zero value depending on failure.
+ *
+ */
+int rte_pmd_mlx5_txq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename)
+{
+	struct rte_eth_dev *dev;
+	struct mlx5_priv *priv;
+	struct mlx5_txq_data *txq_data;
+	struct mlx5_txq_ctrl *txq_ctrl;
+	struct mlx5_txq_obj *txq_obj;
+	struct mlx5_devx_sq *sq;
+	struct mlx5_devx_cq *cq;
+	struct mlx5_devx_obj *sq_devx_obj;
+	struct mlx5_devx_obj *cq_devx_obj;
+
+	uint32_t sq_out[MLX5_ST_SZ_DW(query_sq_out)] = {0};
+	uint32_t cq_out[MLX5_ST_SZ_DW(query_cq_out)] = {0};
+
+	int ret;
+	FILE *fd;
+	MKSTR(path, "./%s", filename);
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	if (rte_eth_tx_queue_is_valid(port_id, queue_id))
+		return -EINVAL;
+
+	fd = fopen(path, "w");
+	if (!fd) {
+		rte_errno = errno;
+		return -EIO;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	priv = dev->data->dev_private;
+	txq_data = (*priv->txqs)[queue_id];
+	txq_ctrl = container_of(txq_data, struct mlx5_txq_ctrl, txq);
+	txq_obj = txq_ctrl->obj;
+	sq = &txq_obj->sq_obj;
+	cq = &txq_obj->cq_obj;
+	sq_devx_obj = sq->sq;
+	cq_devx_obj = cq->cq;
+
+	do {
+		ret = mlx5_devx_cmd_query_sq(sq_devx_obj, sq_out, sizeof(sq_out));
+		if (ret)
+			break;
+
+		/* Dump sq query output to file */
+		MKSTR(sq_headline, "SQ DevX ID = %u Port = %u Queue index = %u ",
+					sq_devx_obj->id, port_id, queue_id);
+		mlx5_dump_to_file(fd, NULL, sq_headline, 0);
+		mlx5_dump_to_file(fd, "Query SQ Dump:",
+					(const void *)((uintptr_t)sq_out),
+					sizeof(sq_out));
+
+		ret = mlx5_devx_cmd_query_cq(cq_devx_obj, cq_out, sizeof(cq_out));
+		if (ret)
+			break;
+
+		/* Dump cq query output to file */
+		MKSTR(cq_headline, "CQ DevX ID = %u Port = %u Queue index = %u ",
+						cq_devx_obj->id, port_id, queue_id);
+		mlx5_dump_to_file(fd, NULL, cq_headline, 0);
+		mlx5_dump_to_file(fd, "Query CQ Dump:",
+					(const void *)((uintptr_t)cq_out),
+					sizeof(cq_out));
+	} while (false);
+
+	fclose(fd);
+	return ret;
+}
diff --git a/drivers/net/mlx5/rte_pmd_mlx5.h b/drivers/net/mlx5/rte_pmd_mlx5.h
index 004be0eea1..c823280717 100644
--- a/drivers/net/mlx5/rte_pmd_mlx5.h
+++ b/drivers/net/mlx5/rte_pmd_mlx5.h
@@ -331,6 +331,42 @@ __rte_experimental
 int
 rte_pmd_mlx5_destroy_geneve_tlv_parser(void *handle);
 
+/**
+ * Dump Rx Queue Context for a given port/queue
+ *
+ * @param[in] port_id
+ *   Port ID
+ * @param[in] queue_id
+ *   Queue ID
+ * @param[in] filename
+ *   Name of file to dump the Rx Queue Context
+ *
+ * @return
+ *   0 for success, non-zero value depending on failure type
+ */
+
+__rte_experimental
+int
+rte_pmd_mlx5_rxq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename);
+
+/**
+ * Dump Tx Queue Context for a given port/queue
+ *
+ * @param[in] port_id
+ *   Port ID
+ * @param[in] queue_id
+ *   Queue ID
+ * @param[in] filename
+ *   Name of file to dump the Tx Queue Context
+ *
+ * @return
+ *   0 for success, non-zero value depending on failure type
+ */
+
+__rte_experimental
+int
+rte_pmd_mlx5_txq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/drivers/net/mlx5/version.map b/drivers/net/mlx5/version.map
index 8fb0e07303..f76b7ec18f 100644
--- a/drivers/net/mlx5/version.map
+++ b/drivers/net/mlx5/version.map
@@ -20,4 +20,6 @@ EXPERIMENTAL {
 	# added in 24.03
 	rte_pmd_mlx5_create_geneve_tlv_parser;
 	rte_pmd_mlx5_destroy_geneve_tlv_parser;
+	rte_pmd_mlx5_txq_dump_contexts;
+	rte_pmd_mlx5_rxq_dump_contexts;
 };
-- 
2.34.1


^ permalink raw reply	[flat|nested] 2+ messages in thread

* RE: [PATCH] net/mlx5: add queue hardware object context dump
  2024-06-04 21:11 [PATCH] net/mlx5: add queue hardware object context dump Kiran Vedere
@ 2024-06-10  5:59 ` Slava Ovsiienko
  0 siblings, 0 replies; 2+ messages in thread
From: Slava Ovsiienko @ 2024-06-10  5:59 UTC (permalink / raw)
  To: Kiran Vedere, dev; +Cc: Matan Azrad, Raslan Darawsheh, Dariusz Sosnowski

> -----Original Message-----
> From: Kiran Vedere <kiranv@nvidia.com>
> Sent: Wednesday, June 5, 2024 12:12 AM
> To: dev@dpdk.org
> Cc: Matan Azrad <matan@nvidia.com>; Raslan Darawsheh
> <rasland@nvidia.com>; Slava Ovsiienko <viacheslavo@nvidia.com>; Dariusz
> Sosnowski <dsosnowski@nvidia.com>
> Subject: [PATCH] net/mlx5: add queue hardware object context dump
> 
> Add debug capability to mlx5 PMD to dump SQ/RQ/CQ HW object context for a
> given port/queue. The context dump can provide some real-time information on
> cause of certain Tx/Rx Failures.
> 
> Signed-off-by: Kiran Vedere <kiranv@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2024-06-10  5:59 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-04 21:11 [PATCH] net/mlx5: add queue hardware object context dump Kiran Vedere
2024-06-10  5:59 ` Slava Ovsiienko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).