[PATCH net-next v02 2/9] hinic3: Add Command Queue/Async Event Queue/Complete Event Queue/Mailbox dump interfaces

From: Fan Gong

Date: Sat Mar 07 2026 - 01:45:32 EST


Add dump interfaces for CMDQ, AEQ, CEQ and mailbox to enhance debugging
capabilities.
Dump the WQE header for CMDQ.
Dump the detailed queue information for AEQ and CEQ.
Dump the related register status for mailbox.

Co-developed-by: Zhu Yikai <zhuyikai1@xxxxxxxxxxxxxx>
Signed-off-by: Zhu Yikai <zhuyikai1@xxxxxxxxxxxxxx>
Signed-off-by: Fan Gong <gongfan1@xxxxxxxxxx>
---
.../net/ethernet/huawei/hinic3/hinic3_cmdq.c | 19 ++++++
.../net/ethernet/huawei/hinic3/hinic3_csr.h | 2 +
.../net/ethernet/huawei/hinic3/hinic3_eqs.c | 65 +++++++++++++++++++
.../net/ethernet/huawei/hinic3/hinic3_eqs.h | 5 ++
.../net/ethernet/huawei/hinic3/hinic3_mbox.c | 15 +++++
5 files changed, 106 insertions(+)

diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c
index f71c3c734f6e..c033d9a13652 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c
@@ -6,12 +6,14 @@
#include <linux/dma-mapping.h>

#include "hinic3_cmdq.h"
+#include "hinic3_eqs.h"
#include "hinic3_hwdev.h"
#include "hinic3_hwif.h"
#include "hinic3_mbox.h"

#define CMDQ_BUF_SIZE 2048
#define CMDQ_WQEBB_SIZE 64
+#define CMDQ_WQE_HEAD_LEN 32

#define CMDQ_CMD_TIMEOUT 5000
#define CMDQ_ENABLE_WAIT_TIMEOUT 300
@@ -114,6 +116,20 @@ enum cmdq_cmd_type {

#define CMDQ_WQE_NUM_WQEBBS 1

+static void hinic3_dump_cmdq_wqe_head(struct hinic3_hwdev *hwdev,
+ struct cmdq_wqe *wqe)
+{
+ u32 *data = (u32 *)wqe;
+ u32 i;
+
+ for (i = 0; i < (CMDQ_WQE_HEAD_LEN / sizeof(u32)); i += 0x4) {
+ dev_dbg(hwdev->dev,
+ "wqe data: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ *(data + i), *(data + i + 0x1), *(data + i + 0x2),
+ *(data + i + 0x3));
+ }
+}
+
static struct cmdq_wqe *cmdq_read_wqe(struct hinic3_wq *wq, u16 *ci)
{
if (hinic3_wq_get_used(wq) == 0)
@@ -279,6 +295,7 @@ void hinic3_cmdq_ceq_handler(struct hinic3_hwdev *hwdev, __le32 ceqe_data)
case HINIC3_CMD_TYPE_TIMEOUT:
dev_warn(hwdev->dev, "Cmdq timeout, q_id: %u, ci: %u\n",
cmdq_type, ci);
+ hinic3_dump_cmdq_wqe_head(hwdev, wqe);
fallthrough;
case HINIC3_CMD_TYPE_FAKE_TIMEOUT:
cmdq_clear_cmd_buf(cmd_info, hwdev);
@@ -535,6 +552,8 @@ static int wait_cmdq_sync_cmd_completion(struct hinic3_cmdq *cmdq,
clear_cmd_info(cmd_info, saved_cmd_info);
spin_unlock_bh(&cmdq->cmdq_lock);

+ hinic3_dump_ceq_info(cmdq->hwdev);
+
return err;
}

diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_csr.h b/drivers/net/ethernet/huawei/hinic3/hinic3_csr.h
index f7083a6e7df9..0e32ff34919e 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_csr.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_csr.h
@@ -76,9 +76,11 @@

#define HINIC3_CSR_AEQ_CTRL_0_ADDR (HINIC3_CFG_REGS_FLAG + 0x200)
#define HINIC3_CSR_AEQ_CTRL_1_ADDR (HINIC3_CFG_REGS_FLAG + 0x204)
+#define HINIC3_CSR_AEQ_CONS_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x208)
#define HINIC3_CSR_AEQ_PROD_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x20C)
#define HINIC3_CSR_AEQ_CI_SIMPLE_INDIR_ADDR (HINIC3_CFG_REGS_FLAG + 0x50)

+#define HINIC3_CSR_CEQ_CONS_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x288)
#define HINIC3_CSR_CEQ_PROD_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x28c)
#define HINIC3_CSR_CEQ_CI_SIMPLE_INDIR_ADDR (HINIC3_CFG_REGS_FLAG + 0x54)

diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
index 13a0c6b07660..b8ac1d7bd82b 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
@@ -56,6 +56,10 @@
#define EQ_CI_SIMPLE_INDIR_SET(val, member) \
FIELD_PREP(EQ_CI_SIMPLE_INDIR_##member##_MASK, val)

+#define EQ_CONS_IDX_REG_ADDR(eq) \
+ (((eq)->type == HINIC3_AEQ) ? \
+ HINIC3_CSR_AEQ_CONS_IDX_ADDR : HINIC3_CSR_CEQ_CONS_IDX_ADDR)
+
#define EQ_CI_SIMPLE_INDIR_REG_ADDR(eq) \
(((eq)->type == HINIC3_AEQ) ? \
HINIC3_CSR_AEQ_CI_SIMPLE_INDIR_ADDR : \
@@ -353,6 +357,7 @@ static irqreturn_t ceq_interrupt(int irq, void *data)
struct hinic3_eq *ceq = data;
int err;

+ ceq->soft_intr_jif = jiffies;
/* clear resend timer counters */
hinic3_msix_intr_clear_resend_bit(ceq->hwdev, ceq->msix_entry_idx,
EQ_MSIX_RESEND_TIMER_CLEAR);
@@ -713,6 +718,39 @@ void hinic3_aeqs_free(struct hinic3_hwdev *hwdev)
kfree(aeqs);
}

+void hinic3_dump_aeq_info(struct hinic3_hwdev *hwdev)
+{
+ const struct hinic3_aeq_elem *aeqe_pos;
+ u32 addr, ci, pi, ctrl0, idx;
+ struct hinic3_eq *eq;
+ int q_id;
+
+ for (q_id = 0; q_id < hwdev->aeqs->num_aeqs; q_id++) {
+ eq = &hwdev->aeqs->aeq[q_id];
+ /* Indirect access should set q_id first */
+ hinic3_hwif_write_reg(eq->hwdev->hwif,
+ HINIC3_EQ_INDIR_IDX_ADDR(eq->type),
+ eq->q_id);
+
+ addr = HINIC3_CSR_AEQ_CTRL_0_ADDR;
+
+ ctrl0 = hinic3_hwif_read_reg(hwdev->hwif, addr);
+
+ idx = hinic3_hwif_read_reg(hwdev->hwif,
+ HINIC3_EQ_INDIR_IDX_ADDR(eq->type));
+
+ addr = EQ_CONS_IDX_REG_ADDR(eq);
+ ci = hinic3_hwif_read_reg(hwdev->hwif, addr);
+ addr = EQ_PROD_IDX_REG_ADDR(eq);
+ pi = hinic3_hwif_read_reg(hwdev->hwif, addr);
+ aeqe_pos = get_curr_aeq_elem(eq);
+ dev_err(hwdev->dev,
+ "Aeq id: %d, idx: %u, ctrl0: 0x%08x, ci: 0x%08x, pi: 0x%x, work_state: 0x%x, wrap: %u, desc: 0x%x swci:0x%x\n",
+ q_id, idx, ctrl0, ci, pi, work_busy(&eq->aeq_work),
+ eq->wrapped, be32_to_cpu(aeqe_pos->desc), eq->cons_idx);
+ }
+}
+
int hinic3_ceqs_init(struct hinic3_hwdev *hwdev, u16 num_ceqs,
struct msix_entry *msix_entries)
{
@@ -773,3 +811,30 @@ void hinic3_ceqs_free(struct hinic3_hwdev *hwdev)

kfree(ceqs);
}
+
+void hinic3_dump_ceq_info(struct hinic3_hwdev *hwdev)
+{
+ struct hinic3_eq *eq;
+ u32 addr, ci, pi;
+ int q_id;
+
+ for (q_id = 0; q_id < hwdev->ceqs->num_ceqs; q_id++) {
+ eq = &hwdev->ceqs->ceq[q_id];
+ /* Indirect access should set q_id first */
+ hinic3_hwif_write_reg(eq->hwdev->hwif,
+ HINIC3_EQ_INDIR_IDX_ADDR(eq->type),
+ eq->q_id);
+
+ addr = EQ_CONS_IDX_REG_ADDR(eq);
+ ci = hinic3_hwif_read_reg(hwdev->hwif, addr);
+ addr = EQ_PROD_IDX_REG_ADDR(eq);
+ pi = hinic3_hwif_read_reg(hwdev->hwif, addr);
+ dev_err(hwdev->dev,
+ "Ceq id: %d, ci: 0x%08x, sw_ci: 0x%08x, pi: 0x%x, wrap: %u, ceqe: 0x%x\n",
+ q_id, ci, eq->cons_idx, pi,
+ eq->wrapped, be32_to_cpu(*get_curr_ceq_elem(eq)));
+
+ dev_err(hwdev->dev, "Ceq last response soft interrupt time: %u\n",
+ jiffies_to_msecs(jiffies - eq->soft_intr_jif));
+ }
+}
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h
index 005a6e0745b3..c0fa237b270b 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h
@@ -56,6 +56,8 @@ struct hinic3_eq {
u16 msix_entry_idx;
char irq_name[HINIC3_EQ_IRQ_NAME_LEN];
struct work_struct aeq_work;
+
+ u64 soft_intr_jif;
};

struct hinic3_aeq_elem {
@@ -110,6 +112,8 @@ int hinic3_aeq_register_cb(struct hinic3_hwdev *hwdev,
hinic3_aeq_event_cb hwe_cb);
void hinic3_aeq_unregister_cb(struct hinic3_hwdev *hwdev,
enum hinic3_aeq_type event);
+void hinic3_dump_aeq_info(struct hinic3_hwdev *hwdev);
+
int hinic3_ceqs_init(struct hinic3_hwdev *hwdev, u16 num_ceqs,
struct msix_entry *msix_entries);
void hinic3_ceqs_free(struct hinic3_hwdev *hwdev);
@@ -118,5 +122,6 @@ int hinic3_ceq_register_cb(struct hinic3_hwdev *hwdev,
hinic3_ceq_event_cb callback);
void hinic3_ceq_unregister_cb(struct hinic3_hwdev *hwdev,
enum hinic3_ceq_event event);
+void hinic3_dump_ceq_info(struct hinic3_hwdev *hwdev);

#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
index 826fa8879a11..7d31e215b14f 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
@@ -5,6 +5,7 @@

#include "hinic3_common.h"
#include "hinic3_csr.h"
+#include "hinic3_eqs.h"
#include "hinic3_hwdev.h"
#include "hinic3_hwif.h"
#include "hinic3_mbox.h"
@@ -616,6 +617,18 @@ static void write_mbox_msg_attr(struct hinic3_mbox *mbox,
mbox_ctrl);
}

+static void hinic3_dump_mbox_reg(struct hinic3_hwdev *hwdev)
+{
+ u32 val;
+
+ val = hinic3_hwif_read_reg(hwdev->hwif,
+ HINIC3_FUNC_CSR_MAILBOX_CONTROL_OFF);
+ dev_err(hwdev->dev, "Mailbox control reg: 0x%x\n", val);
+ val = hinic3_hwif_read_reg(hwdev->hwif,
+ HINIC3_FUNC_CSR_MAILBOX_INT_OFF);
+ dev_err(hwdev->dev, "Mailbox interrupt offset: 0x%x\n", val);
+}
+
static u16 get_mbox_status(const struct hinic3_send_mbox *mbox)
{
__be64 *wb_status = mbox->wb_vaddr;
@@ -670,6 +683,7 @@ static int send_mbox_seg(struct hinic3_mbox *mbox, __le64 header,
if (err) {
dev_err(hwdev->dev, "Send mailbox segment timeout, wb status: 0x%x\n",
wb_status);
+ hinic3_dump_mbox_reg(hwdev);
return err;
}

@@ -825,6 +839,7 @@ int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
if (wait_mbox_msg_completion(mbox, msg_params->timeout_ms)) {
dev_err(hwdev->dev,
"Send mbox msg timeout, msg_id: %u\n", msg_info.msg_id);
+ hinic3_dump_aeq_info(mbox->hwdev);
err = -ETIMEDOUT;
goto err_send;
}
--
2.43.0