]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
hinic3: Add Command Queue/Async Event Queue/Complete Event Queue/Mailbox dump interfaces
authorFan Gong <gongfan1@huawei.com>
Tue, 10 Mar 2026 01:04:50 +0000 (09:04 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 12 Mar 2026 11:13:48 +0000 (12:13 +0100)
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@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
Link: https://patch.msgid.link/1644c5021e2059594e878812339ea025ed677f71.1773062356.git.zhuyikai1@h-partners.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c
drivers/net/ethernet/huawei/hinic3/hinic3_csr.h
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h
drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c

index 4e63280beea504bd1f8dded69fc942eb69d5f8ae..946e699cbe1015b3e5e9749e1a3ffd0823b915dc 100644 (file)
@@ -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;
 }
 
index f7083a6e7df9e82f8e9d847e91db88b4cb462380..0e32ff34919eafbee0a48cd584adb0ce4768129d 100644 (file)
 
 #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)
 
index 13a0c6b07660124b3dd0c8914bcb1ab08c9edc8b..b8ac1d7bd82bff6bca3baf783e7215d3709e6632 100644 (file)
 #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));
+       }
+}
index 005a6e0745b3726e0761a482ded6ca4abed3b6d5..c0fa237b270b694c1c2ecac0e37825ffbdb9239a 100644 (file)
@@ -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
index 826fa8879a11379e7bf0dc0ee6836412d32f30ed..7d31e215b14fb1cd878efd196e9f906dd264694a 100644 (file)
@@ -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;
        }