From c03aa9dd26534846f94a974c651c584379b73cf7 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Tue, 16 Jul 2019 16:57:59 +0800 Subject: [PATCH] net: hns3: fix some reset handshake issue driver inclusion category: bugfix bugzilla: NA CVE: NA Currently, the driver will clear the handshake status when re-intializing the CMDQ, and does not recover this status when reset fail. This will cause the hardware cannot get the handshake and do nothing anymore. So this patch delays clearing handshake status just before UP, and recovers this status when reset fail. Fixes: ada13ee3db7b ("net: hns3: add handshake with hardware while doing reset") Feature or Bugfix:Bugfix Signed-off-by: Huazhong Tan Reviewed-by: lipeng Reviewed-by: Yunsheng Lin Reviewed-by: Yang Yingliang Signed-off-by: Yang Yingliang --- .../ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 7 +++++-- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 ++++++ .../ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c | 4 +++- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 16 ++++++++-------- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index b91309c5abca..4682f23297e8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -105,14 +105,17 @@ static void hclge_cmd_config_regs(struct hclge_cmq_ring *ring) dma_addr_t dma = ring->desc_dma_addr; struct hclge_dev *hdev = ring->dev; struct hclge_hw *hw = &hdev->hw; + u32 reg_val; if (ring->ring_type == HCLGE_TYPE_CSQ) { hclge_write_dev(hw, HCLGE_NIC_CSQ_BASEADDR_L_REG, lower_32_bits(dma)); hclge_write_dev(hw, HCLGE_NIC_CSQ_BASEADDR_H_REG, upper_32_bits(dma)); - hclge_write_dev(hw, HCLGE_NIC_CSQ_DEPTH_REG, - ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S); + reg_val = hclge_read_dev(hw, HCLGE_NIC_CSQ_DEPTH_REG); + reg_val &= HCLGE_NIC_CMQ_ENABLE; + reg_val |= ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S; + hclge_write_dev(hw, HCLGE_NIC_CSQ_DEPTH_REG, reg_val); hclge_write_dev(hw, HCLGE_NIC_CSQ_HEAD_REG, 0); hclge_write_dev(hw, HCLGE_NIC_CSQ_TAIL_REG, 0); } else { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index f6a9ec3c75eb..46a95bba6148 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3461,6 +3461,7 @@ static int hclge_set_rst_done(struct hclge_dev *hdev) static int hclge_reset_prepare_up(struct hclge_dev *hdev) { + u32 reg_val; int ret = 0; switch (hdev->reset_type) { @@ -3478,6 +3479,11 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev) break; } + /* clear handshake status with IMP */ + reg_val = hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG) & + ~HCLGE_NIC_CMQ_ENABLE; + hclge_write_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG, reg_val); + return ret; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index e11bb4664a66..ca7829d2d107 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -99,7 +99,9 @@ static void hclgevf_cmd_config_regs(struct hclgevf_cmq_ring *ring) HCLGEVF_RING_BASEADDR_SHIFT); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_BASEADDR_H_REG, reg_val); - reg_val = (ring->desc_num >> HCLGEVF_NIC_CMQ_DESC_NUM_S); + reg_val = hclgevf_read_dev(hw, HCLGEVF_NIC_CSQ_DEPTH_REG); + reg_val &= HCLGEVF_NIC_CMQ_ENABLE; + reg_val |= (ring->desc_num >> HCLGEVF_NIC_CMQ_DESC_NUM_S); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_DEPTH_REG, reg_val); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_HEAD_REG, 0); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 8fac3c90ef44..d0fe758de9e8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1412,6 +1412,7 @@ static int hclgevf_reset_wait(struct hclgevf_dev *hdev) static int hclgevf_reset_stack(struct hclgevf_dev *hdev) { + u32 reg_val; int ret; /* uninitialize the nic client */ @@ -1436,6 +1437,10 @@ static int hclgevf_reset_stack(struct hclgevf_dev *hdev) if (ret) return ret; + /* clear handshake status with IMP */ + reg_val = hclgevf_read_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG) & + ~HCLGEVF_NIC_CMQ_ENABLE; + hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG, reg_val); return 0; } @@ -1473,11 +1478,9 @@ static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev) static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev) { - /* When VF reset failed, only the higher level reset asserted by PF - * can restore it, so re-initialize the command queue to receive - * this higher reset event. - */ - hclgevf_cmd_init(hdev); + /* recover handshake status with IMP when reset fail */ + hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG, + HCLGEVF_NIC_CMQ_ENABLE); hdev->rst_stats.rst_fail_cnt++; dev_err(&hdev->pdev->dev, "failed to reset VF(%d)\n", hdev->rst_stats.rst_fail_cnt); @@ -1488,9 +1491,6 @@ static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev) if (hclgevf_is_reset_pending(hdev)) { set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state); hclgevf_reset_task_schedule(hdev); - } else { - hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG, - HCLGEVF_NIC_CMQ_ENABLE); } } -- GitLab