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 <kir...@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 <kira...@juniper.net>
 Kiran Kumar K <kirankum...@marvell.com>
 Kiran Kumar <kkokkilaga...@caviumnetworks.com> 
<kiran.kokkilaga...@caviumnetworks.com>
 Kiran Patil <kiran.pa...@intel.com>
+Kiran Vedere <kir...@nvidia.com>
 Kirill Rybalchenko <kirill.rybalche...@intel.com>
 Kishore Padmanabha <kishore.padmana...@broadcom.com>
 Klaus Degner <k...@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

Reply via email to