hinic3: Command Queue flush interfaces

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>
This commit is contained in:
Fan Gong 2025-09-12 14:28:22 +08:00 committed by Paolo Abeni
parent a0543a7935
commit b92e6c734d
6 changed files with 124 additions and 0 deletions

View 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;
}

View 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

View 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).

View 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);

View 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)
{

View 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);