From: Chiqijun chiqijun@huawei.com
driver inclusion category: bugfix bugzilla: 4472
-----------------------------------------------------------------------
When the VF loses interrupt, it may cause the driver to think that the message has timed out, and the driver reschedules the work to try to obtain the ack.
Signed-off-by: Chiqijun chiqijun@huawei.com Reviewed-by: Zengweiliang zengweiliang.zengweiliang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- .../net/ethernet/huawei/hinic/hinic_cmdq.c | 25 +++++++- drivers/net/ethernet/huawei/hinic/hinic_eqs.c | 18 ++++++ drivers/net/ethernet/huawei/hinic/hinic_eqs.h | 4 ++ .../net/ethernet/huawei/hinic/hinic_mbox.c | 58 +++++++++++++++---- 4 files changed, 93 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_cmdq.c b/drivers/net/ethernet/huawei/hinic/hinic_cmdq.c index d7802caca0a6..61bf9a829d0d 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_cmdq.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_cmdq.c @@ -38,6 +38,7 @@ #include "hinic_cmdq.h"
#define CMDQ_CMD_TIMEOUT 5000 /* millisecond */ +#define CMDQ_CMD_RETRY_TIMEOUT 1000 /* millisecond */
#define UPPER_8_BITS(data) (((data) >> 8) & 0xFF) #define LOWER_8_BITS(data) ((data) & 0xFF) @@ -557,6 +558,24 @@ static void __clear_cmd_info(struct hinic_cmdq_cmd_info *cmd_info, cmd_info->direct_resp = NULL; }
+static int cmdq_retry_get_ack(struct hinic_hwdev *hwdev, + struct completion *done, u8 ceq_id) +{ + ulong timeo = msecs_to_jiffies(CMDQ_CMD_RETRY_TIMEOUT); + int err; + + init_completion(done); + + err = hinic_reschedule_eq(hwdev, HINIC_CEQ, ceq_id); + if (err) + return err; + + if (!wait_for_completion_timeout(done, timeo)) + return -ETIMEDOUT; + + return 0; +} + static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq, enum hinic_ack_type ack_type, enum hinic_mod_type mod, u8 cmd, @@ -634,7 +653,8 @@ static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq, spin_unlock_bh(&cmdq->cmdq_lock);
timeo = msecs_to_jiffies(timeout ? timeout : CMDQ_CMD_TIMEOUT); - if (!wait_for_completion_timeout(&done, timeo)) { + if (!wait_for_completion_timeout(&done, timeo) && + cmdq_retry_get_ack(cmdq->hwdev, &done, HINIC_CEQ_ID_CMDQ)) { spin_lock_bh(&cmdq->cmdq_lock);
if (cmd_info->cmpt_code == &cmpt_code) @@ -759,7 +779,8 @@ static int cmdq_sync_cmd_detail_resp(struct hinic_cmdq *cmdq, spin_unlock_bh(&cmdq->cmdq_lock);
timeo = msecs_to_jiffies(timeout ? timeout : CMDQ_CMD_TIMEOUT); - if (!wait_for_completion_timeout(&done, timeo)) { + if (!wait_for_completion_timeout(&done, timeo) && + cmdq_retry_get_ack(cmdq->hwdev, &done, HINIC_CEQ_ID_CMDQ)) { spin_lock_bh(&cmdq->cmdq_lock);
if (cmd_info->cmpt_code == &cmpt_code) diff --git a/drivers/net/ethernet/huawei/hinic/hinic_eqs.c b/drivers/net/ethernet/huawei/hinic/hinic_eqs.c index b8ea8ed36b5b..ccac811f948d 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_eqs.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_eqs.c @@ -639,6 +639,24 @@ static void reschedule_eq_handler(struct hinic_eq *eq) } }
+int hinic_reschedule_eq(struct hinic_hwdev *hwdev, enum hinic_eq_type type, + u16 eq_id) +{ + if (type == HINIC_AEQ) { + if (eq_id >= hwdev->aeqs->num_aeqs) + return -EINVAL; + + reschedule_eq_handler(&hwdev->aeqs->aeq[eq_id]); + } else { + if (eq_id >= hwdev->ceqs->num_ceqs) + return -EINVAL; + + reschedule_eq_handler(&hwdev->ceqs->ceq[eq_id]); + } + + return 0; +} + /** * eq_irq_handler - handler for the eq event * @data: the event queue of the event diff --git a/drivers/net/ethernet/huawei/hinic/hinic_eqs.h b/drivers/net/ethernet/huawei/hinic/hinic_eqs.h index 5035f90c6ad6..dec541995ee2 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_eqs.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_eqs.h @@ -20,6 +20,7 @@
#define HINIC_EQ_PAGE_SIZE 0x00001000
+#define HINIC_HW_MAX_AEQS 4 #define HINIC_MAX_AEQS 3 #define HINIC_MAX_CEQS 32
@@ -179,4 +180,7 @@ void hinic_dump_ceq_info(struct hinic_hwdev *hwdev);
void hinic_dump_aeq_info(struct hinic_hwdev *hwdev);
+int hinic_reschedule_eq(struct hinic_hwdev *hwdev, enum hinic_eq_type type, + u16 eq_id); + #endif diff --git a/drivers/net/ethernet/huawei/hinic/hinic_mbox.c b/drivers/net/ethernet/huawei/hinic/hinic_mbox.c index bbc16cc38b33..7e77d0319931 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_mbox.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_mbox.c @@ -29,6 +29,7 @@ #include "hinic_hwdev.h" #include "hinic_csr.h" #include "hinic_hwif.h" +#include "hinic_eqs.h" #include "hinic_mbox.h"
#define HINIC_MBOX_INT_DST_FUNC_SHIFT 0 @@ -112,6 +113,7 @@ enum hinic_mbox_tx_status { #define HINIC_MBOX_SEG_LEN 48 #define HINIC_MBOX_COMP_TIME 8000U #define MBOX_MSG_POLLING_TIMEOUT 8000 +#define MBOX_MSG_RETRY_ACK_TIMEOUT 1000
#define HINIC_MBOX_DATA_SIZE 2040
@@ -975,14 +977,11 @@ static void mbox_copy_send_data(struct hinic_hwdev *hwdev, }
static void write_mbox_msg_attr(struct hinic_mbox_func_to_func *func_to_func, - u16 dst_func, u16 dst_aeqn, u16 seg_len, - int poll) + u16 dst_func, u16 dst_aeqn, u16 rsp_aeq, + u16 seg_len, int poll) { u32 mbox_int, mbox_ctrl;
- /* msg_len - the total mbox msg len */ - u16 rsp_aeq = (dst_aeqn == 0) ? 0 : HINIC_MBOX_RSP_AEQN; - mbox_int = HINIC_MBOX_INT_SET(dst_func, DST_FUNC) | HINIC_MBOX_INT_SET(dst_aeqn, DST_AEQN) | HINIC_MBOX_INT_SET(rsp_aeq, SRC_RESP_AEQN) | @@ -1030,6 +1029,38 @@ static u16 get_mbox_status(struct hinic_send_mbox *mbox) return (u16)(wb_val & MBOX_WB_STATUS_ERRCODE_MASK); }
+static u16 mbox_msg_ack_aeqn(struct hinic_hwdev *hwdev, + enum hinic_hwif_direction_type seq_dir) +{ + u8 num_aeqs = hwdev->hwif->attr.num_aeqs; + u16 dst_aeqn; + + if (num_aeqs >= HINIC_HW_MAX_AEQS) + dst_aeqn = HINIC_MBOX_RSP_AEQN; + else + dst_aeqn = 0; + + return dst_aeqn; +} + +static int mbox_retry_get_ack(struct hinic_mbox_func_to_func *func_to_func, + struct completion *done, u16 aeq_id) +{ + ulong timeo = msecs_to_jiffies(MBOX_MSG_RETRY_ACK_TIMEOUT); + int err; + + init_completion(done); + + err = hinic_reschedule_eq(func_to_func->hwdev, HINIC_AEQ, aeq_id); + if (err) + return err; + + if (!wait_for_completion_timeout(done, timeo)) + return -ETIMEDOUT; + + return 0; +} + static int send_mbox_seg(struct hinic_mbox_func_to_func *func_to_func, u64 header, u16 dst_func, void *seg, u16 seg_len, int poll, void *msg_info) @@ -1037,18 +1068,20 @@ static int send_mbox_seg(struct hinic_mbox_func_to_func *func_to_func, struct hinic_send_mbox *send_mbox = &func_to_func->send_mbox; struct hinic_hwdev *hwdev = func_to_func->hwdev; u8 num_aeqs = hwdev->hwif->attr.num_aeqs; - u16 dst_aeqn, wb_status = 0, errcode; + u16 dst_aeqn, wb_status = 0, errcode, rsp_aeq; u16 seq_dir = HINIC_MBOX_HEADER_GET(header, DIRECTION); struct completion *done = &send_mbox->send_done; ulong jif; u32 cnt = 0;
- if (num_aeqs >= 4) + if (num_aeqs >= HINIC_HW_MAX_AEQS) dst_aeqn = (seq_dir == HINIC_HWIF_DIRECT_SEND) ? HINIC_MBOX_RECV_AEQN : HINIC_MBOX_RSP_AEQN; else dst_aeqn = 0;
+ rsp_aeq = (dst_aeqn == 0) ? 0 : HINIC_MBOX_RSP_AEQN; + if (!poll) init_completion(done);
@@ -1058,7 +1091,8 @@ static int send_mbox_seg(struct hinic_mbox_func_to_func *func_to_func,
mbox_copy_send_data(hwdev, send_mbox, seg, seg_len);
- write_mbox_msg_attr(func_to_func, dst_func, dst_aeqn, seg_len, poll); + write_mbox_msg_attr(func_to_func, dst_func, dst_aeqn, rsp_aeq, + seg_len, poll);
wmb(); /* writing the mbox msg attributes */
@@ -1080,7 +1114,8 @@ static int send_mbox_seg(struct hinic_mbox_func_to_func *func_to_func, } } else { jif = msecs_to_jiffies(HINIC_MBOX_COMP_TIME); - if (!wait_for_completion_timeout(done, jif)) { + if (!wait_for_completion_timeout(done, jif) && + mbox_retry_get_ack(func_to_func, done, rsp_aeq)) { sdk_err(hwdev->dev_hdl, "Send mailbox segment timeout\n"); dump_mox_reg(hwdev); return -ETIMEDOUT; @@ -1206,7 +1241,10 @@ int hinic_mbox_to_func(struct hinic_mbox_func_to_func *func_to_func, }
timeo = msecs_to_jiffies(timeout ? timeout : HINIC_MBOX_COMP_TIME); - if (!wait_for_completion_timeout(&mbox_for_resp->recv_done, timeo)) { + if (!wait_for_completion_timeout(&mbox_for_resp->recv_done, timeo) && + mbox_retry_get_ack(func_to_func, &mbox_for_resp->recv_done, + mbox_msg_ack_aeqn(func_to_func->hwdev, + HINIC_HWIF_DIRECT_SEND))) { set_mbox_to_func_event(func_to_func, EVENT_TIMEOUT); sdk_err(func_to_func->hwdev->dev_hdl, "Send mbox msg timeout, msg_id: %d\n", msg_info.msg_id);