]> www.infradead.org Git - users/hch/misc.git/commitdiff
hinic3: Command Queue flush interfaces
authorFan Gong <gongfan1@huawei.com>
Fri, 12 Sep 2025 06:28:22 +0000 (14:28 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 16 Sep 2025 08:49:06 +0000 (10:49 +0200)
Add the data structures and functions for command queue flushing.

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/2cfd5dfbccb5265e22bdb5a2b279122a57795bb1.1757653621.git.zhuyikai1@h-partners.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c
drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h
drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h
drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c
drivers/net/ethernet/huawei/hinic3/hinic3_hwif.c
drivers/net/ethernet/huawei/hinic3/hinic3_hwif.h

index 596b58245551fbf02f7b7e2bee5941695589c075..e2ed167423fcf8ad18c5bbb03d94864cf7c03f79 100644 (file)
@@ -237,3 +237,102 @@ int hinic3_set_cmdq_depth(struct hinic3_hwdev *hwdev, u16 cmdq_depth)
 
        return 0;
 }
+
+#define HINIC3_WAIT_CMDQ_IDLE_TIMEOUT    5000
+
+static enum hinic3_wait_return check_cmdq_stop_handler(void *priv_data)
+{
+       struct hinic3_hwdev *hwdev = priv_data;
+       enum hinic3_cmdq_type cmdq_type;
+       struct hinic3_cmdqs *cmdqs;
+
+       cmdqs = hwdev->cmdqs;
+       for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
+               if (!hinic3_cmdq_idle(&cmdqs->cmdq[cmdq_type]))
+                       return HINIC3_WAIT_PROCESS_WAITING;
+       }
+
+       return HINIC3_WAIT_PROCESS_CPL;
+}
+
+static int wait_cmdq_stop(struct hinic3_hwdev *hwdev)
+{
+       struct hinic3_cmdqs *cmdqs = hwdev->cmdqs;
+       enum hinic3_cmdq_type cmdq_type;
+       int err;
+
+       if (!(cmdqs->status & HINIC3_CMDQ_ENABLE))
+               return 0;
+
+       cmdqs->status &= ~HINIC3_CMDQ_ENABLE;
+       err = hinic3_wait_for_timeout(hwdev, check_cmdq_stop_handler,
+                                     HINIC3_WAIT_CMDQ_IDLE_TIMEOUT,
+                                     USEC_PER_MSEC);
+
+       if (err)
+               goto err_reenable_cmdq;
+
+       return 0;
+
+err_reenable_cmdq:
+       for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
+               if (!hinic3_cmdq_idle(&cmdqs->cmdq[cmdq_type]))
+                       dev_err(hwdev->dev, "Cmdq %d is busy\n", cmdq_type);
+       }
+       cmdqs->status |= HINIC3_CMDQ_ENABLE;
+
+       return err;
+}
+
+int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
+{
+       struct comm_cmd_clear_resource clear_db = {};
+       struct comm_cmd_clear_resource clr_res = {};
+       struct hinic3_hwif *hwif = hwdev->hwif;
+       struct mgmt_msg_params msg_params = {};
+       int ret = 0;
+       int err;
+
+       err = wait_cmdq_stop(hwdev);
+       if (err) {
+               dev_warn(hwdev->dev, "CMDQ is still working, CMDQ timeout value is unreasonable\n");
+               ret = err;
+       }
+
+       hinic3_toggle_doorbell(hwif, DISABLE_DOORBELL);
+
+       clear_db.func_id = hwif->attr.func_global_idx;
+       mgmt_msg_params_init_default(&msg_params, &clear_db, sizeof(clear_db));
+       err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
+                                      COMM_CMD_FLUSH_DOORBELL, &msg_params);
+       if (err || clear_db.head.status) {
+               dev_warn(hwdev->dev, "Failed to flush doorbell, err: %d, status: 0x%x\n",
+                        err, clear_db.head.status);
+               if (err)
+                       ret = err;
+               else
+                       ret = -EFAULT;
+       }
+
+       clr_res.func_id = hwif->attr.func_global_idx;
+       msg_params.buf_in = &clr_res;
+       msg_params.in_size = sizeof(clr_res);
+       err = hinic3_send_mbox_to_mgmt_no_ack(hwdev, MGMT_MOD_COMM,
+                                             COMM_CMD_START_FLUSH,
+                                             &msg_params);
+       if (err) {
+               dev_warn(hwdev->dev, "Failed to notice flush message, err: %d\n",
+                        err);
+               ret = err;
+       }
+
+       hinic3_toggle_doorbell(hwif, ENABLE_DOORBELL);
+
+       err = hinic3_reinit_cmdq_ctxts(hwdev);
+       if (err) {
+               dev_warn(hwdev->dev, "Failed to reinit cmdq\n");
+               ret = err;
+       }
+
+       return ret;
+}
index 478db3c1328162493cf7aeca6c2f10f72f0e0d63..35b93e36e004405d1ba61c723fd48955acdbd1fb 100644 (file)
@@ -39,5 +39,6 @@ int hinic3_set_dma_attr_tbl(struct hinic3_hwdev *hwdev, u8 entry_idx, u8 st,
 int hinic3_set_wq_page_size(struct hinic3_hwdev *hwdev, u16 func_idx,
                            u32 page_size);
 int hinic3_set_cmdq_depth(struct hinic3_hwdev *hwdev, u16 cmdq_depth);
+int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev);
 
 #endif
index 87b43a123edb85be90a83c218ee7f97f63554892..623cf2d14cbc7910eb61ac2f03e421c515203519 100644 (file)
@@ -245,6 +245,12 @@ struct comm_cmd_set_cmdq_ctxt {
        struct comm_cmdq_ctxt_info ctxt;
 };
 
+struct comm_cmd_clear_resource {
+       struct mgmt_msg_head head;
+       u16                  func_id;
+       u16                  rsvd1[3];
+};
+
 /* Services supported by HW. HW uses these values when delivering events.
  * HW supports multiple services that are not yet supported by driver
  * (e.g. RoCE).
index 258e96ac9b76f4150c01e6ad2848ac7f95e211ce..fa418e4f2654878162c734c60777df1ab097df14 100644 (file)
@@ -514,6 +514,7 @@ void hinic3_free_hwdev(struct hinic3_hwdev *hwdev)
        u64 drv_features[COMM_MAX_FEATURE_QWORD] = {};
 
        hinic3_set_comm_features(hwdev, drv_features, COMM_MAX_FEATURE_QWORD);
+       hinic3_func_rx_tx_flush(hwdev);
        hinic3_uninit_comm_ch(hwdev);
        hinic3_free_cfg_mgmt(hwdev);
        destroy_workqueue(hwdev->workq);
index f07bcab51ba58ebbf1717f19ac06e452eab74ece..f76f140fb6f7657b0f33d4bbe6fd00ac35c7cd7e 100644 (file)
@@ -173,6 +173,20 @@ static enum hinic3_outbound_ctrl hinic3_get_outbound_ctrl_status(struct hinic3_h
        return HINIC3_AF5_GET(attr5, OUTBOUND_CTRL);
 }
 
+void hinic3_toggle_doorbell(struct hinic3_hwif *hwif,
+                           enum hinic3_doorbell_ctrl flag)
+{
+       u32 addr, attr4;
+
+       addr = HINIC3_CSR_FUNC_ATTR4_ADDR;
+       attr4 = hinic3_hwif_read_reg(hwif, addr);
+
+       attr4 &= ~HINIC3_AF4_DOORBELL_CTRL_MASK;
+       attr4 |= HINIC3_AF4_SET(flag, DOORBELL_CTRL);
+
+       hinic3_hwif_write_reg(hwif, addr, attr4);
+}
+
 static int db_area_idx_init(struct hinic3_hwif *hwif, u64 db_base_phy,
                            u8 __iomem *db_base, u64 db_dwqe_len)
 {
index 48e43bfdbfbe9755aca52a975c2d8e9ba5aa6bb5..c02904e861cc302b8c3aa9d0f2f9d86ca73180b9 100644 (file)
@@ -68,6 +68,9 @@ enum hinic3_msix_auto_mask {
 u32 hinic3_hwif_read_reg(struct hinic3_hwif *hwif, u32 reg);
 void hinic3_hwif_write_reg(struct hinic3_hwif *hwif, u32 reg, u32 val);
 
+void hinic3_toggle_doorbell(struct hinic3_hwif *hwif,
+                           enum hinic3_doorbell_ctrl flag);
+
 int hinic3_alloc_db_addr(struct hinic3_hwdev *hwdev, void __iomem **db_base,
                         void __iomem **dwqe_base);
 void hinic3_free_db_addr(struct hinic3_hwdev *hwdev, const u8 __iomem *db_base);