From ed8fb4b262aed95974ccd624402a482c4d59c888 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 1 Aug 2019 11:55:34 +0800 Subject: [PATCH 01/12] net: hns3: add link change event report Previously, PF updates link status per second. For some scenario, it requires link down event being reported more quickly. To solve it, firmware pushes the link change event to PF with CMDQ message, and driver updates the link status directly. Signed-off-by: Jian Shen Reviewed-by: Peng Li Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 1 + .../hisilicon/hns3/hns3pf/hclge_cmd.c | 25 ++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_cmd.h | 7 ++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 9 ++--- .../hisilicon/hns3/hns3pf/hclge_main.h | 8 +++++ .../hisilicon/hns3/hns3pf/hclge_mbx.c | 33 +++++++++++++++++++ 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 75329ab775a61..1564be5e148b0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -47,6 +47,7 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_GET_MEDIA_TYPE, /* (VF -> PF) get media type */ HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */ + HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ }; /* below are per-VF mac-vlan subcodes */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index d9858f285460e..538d1017592a2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -383,6 +383,22 @@ int hclge_cmd_queue_init(struct hclge_dev *hdev) return ret; } +static int hclge_firmware_compat_config(struct hclge_dev *hdev) +{ + struct hclge_firmware_compat_cmd *req; + struct hclge_desc desc; + u32 compat = 0; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_COMPAT_CFG, false); + + req = (struct hclge_firmware_compat_cmd *)desc.data; + + hnae3_set_bit(compat, HCLGE_LINK_EVENT_REPORT_EN_B, 1); + req->compat = cpu_to_le32(compat); + + return hclge_cmd_send(&hdev->hw, &desc, 1); +} + int hclge_cmd_init(struct hclge_dev *hdev) { u32 version; @@ -429,6 +445,15 @@ int hclge_cmd_init(struct hclge_dev *hdev) hnae3_get_field(version, HNAE3_FW_VERSION_BYTE0_MASK, HNAE3_FW_VERSION_BYTE0_SHIFT)); + /* ask the firmware to enable some features, driver can work without + * it. + */ + ret = hclge_firmware_compat_config(hdev); + if (ret) + dev_warn(&hdev->pdev->dev, + "Firmware compatible features not enabled(%d).\n", + ret); + return 0; err_cmd_init: diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 96840d8f3e242..743c9f41c67ea 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -257,6 +257,7 @@ enum hclge_opcode_type { /* M7 stats command */ HCLGE_OPC_M7_STATS_BD = 0x7012, HCLGE_OPC_M7_STATS_INFO = 0x7013, + HCLGE_OPC_M7_COMPAT_CFG = 0x701A, /* SFP command */ HCLGE_OPC_GET_SFP_INFO = 0x7104, @@ -1009,6 +1010,12 @@ struct hclge_query_ppu_pf_other_int_dfx_cmd { u8 rsv[4]; }; +#define HCLGE_LINK_EVENT_REPORT_EN_B 0 +struct hclge_firmware_compat_cmd { + __le32 compat; + u8 rsv[20]; +}; + int hclge_cmd_init(struct hclge_dev *hdev); static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 4138780fca392..855b65e8ebf65 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2517,7 +2517,7 @@ static void hclge_reset_task_schedule(struct hclge_dev *hdev) &hdev->rst_service_task); } -static void hclge_task_schedule(struct hclge_dev *hdev) +void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time) { if (!test_bit(HCLGE_STATE_DOWN, &hdev->state) && !test_bit(HCLGE_STATE_REMOVING, &hdev->state) && @@ -2526,7 +2526,7 @@ static void hclge_task_schedule(struct hclge_dev *hdev) hdev->fd_arfs_expire_timer++; mod_delayed_work_on(cpumask_first(&hdev->affinity_mask), system_wq, &hdev->service_task, - round_jiffies_relative(HZ)); + delay_time); } } @@ -3636,7 +3636,7 @@ static void hclge_service_task(struct work_struct *work) hdev->fd_arfs_expire_timer = 0; } - hclge_task_schedule(hdev); + hclge_task_schedule(hdev, round_jiffies_relative(HZ)); } struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle) @@ -6175,7 +6175,7 @@ static void hclge_set_timer_task(struct hnae3_handle *handle, bool enable) struct hclge_dev *hdev = vport->back; if (enable) { - hclge_task_schedule(hdev); + hclge_task_schedule(hdev, round_jiffies_relative(HZ)); } else { /* Set the DOWN flag here to disable the service to be * scheduled again @@ -6220,6 +6220,7 @@ static void hclge_ae_stop(struct hnae3_handle *handle) if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) && hdev->reset_type != HNAE3_FUNC_RESET) { hclge_mac_stop_phy(hdev); + hclge_update_link_status(hdev); return; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 688e4250491dd..c9b9867fc226a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -302,6 +302,13 @@ enum hclge_fc_mode { HCLGE_FC_DEFAULT }; +enum hclge_link_fail_code { + HCLGE_LF_NORMAL, + HCLGE_LF_REF_CLOCK_LOST, + HCLGE_LF_XSFP_TX_DISABLE, + HCLGE_LF_XSFP_ABSENT, +}; + #define HCLGE_PG_NUM 4 #define HCLGE_SCH_MODE_SP 0 #define HCLGE_SCH_MODE_DWRR 1 @@ -1021,4 +1028,5 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state, int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid, u16 state, u16 vlan_tag, u16 qos, u16 vlan_proto); +void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 690b9990215ca..87de32dfa6c83 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -545,6 +545,36 @@ static int hclge_get_rss_key(struct hclge_vport *vport, HCLGE_RSS_MBX_RESP_LEN); } +static void hclge_link_fail_parse(struct hclge_dev *hdev, u8 link_fail_code) +{ + switch (link_fail_code) { + case HCLGE_LF_REF_CLOCK_LOST: + dev_warn(&hdev->pdev->dev, "Reference clock lost!\n"); + break; + case HCLGE_LF_XSFP_TX_DISABLE: + dev_warn(&hdev->pdev->dev, "SFP tx is disabled!\n"); + break; + case HCLGE_LF_XSFP_ABSENT: + dev_warn(&hdev->pdev->dev, "SFP is absent!\n"); + break; + default: + break; + } +} + +static void hclge_handle_link_change_event(struct hclge_dev *hdev, + struct hclge_mbx_vf_to_pf_cmd *req) +{ +#define LINK_STATUS_OFFSET 1 +#define LINK_FAIL_CODE_OFFSET 2 + + clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state); + hclge_task_schedule(hdev, 0); + + if (!req->msg[LINK_STATUS_OFFSET]) + hclge_link_fail_parse(hdev, req->msg[LINK_FAIL_CODE_OFFSET]); +} + static bool hclge_cmd_crq_empty(struct hclge_hw *hw) { u32 tail = hclge_read_dev(hw, HCLGE_NIC_CRQ_TAIL_REG); @@ -707,6 +737,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev) "PF fail(%d) to media type for VF\n", ret); break; + case HCLGE_MBX_PUSH_LINK_STATUS: + hclge_handle_link_change_event(hdev, req); + break; default: dev_err(&hdev->pdev->dev, "un-supported mailbox message, code = %d\n", From b18bf305c46c20e289c6d030b21b13b632e8a459 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Thu, 1 Aug 2019 11:55:35 +0800 Subject: [PATCH 02/12] net: hns3: add handler for NCSI error mailbox When NCSI has HW error, the IMP will report this error to the driver by sending a mailbox. After received this message, the driver should assert a global reset to fix this kind of HW error. Signed-off-by: Huazhong Tan Reviewed-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 1 + .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 1 + .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 1 + .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 12 ++++++++++++ 4 files changed, 15 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 1564be5e148b0..f8a87f8ca9833 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -48,6 +48,7 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ + HCLGE_MBX_NCSI_ERROR, /* (M7 -> PF) receive a NCSI error */ }; /* below are per-VF mac-vlan subcodes */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index 538d1017592a2..c20b972d21f78 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -394,6 +394,7 @@ static int hclge_firmware_compat_config(struct hclge_dev *hdev) req = (struct hclge_firmware_compat_cmd *)desc.data; hnae3_set_bit(compat, HCLGE_LINK_EVENT_REPORT_EN_B, 1); + hnae3_set_bit(compat, HCLGE_NCSI_ERROR_REPORT_EN_B, 1); req->compat = cpu_to_le32(compat); return hclge_cmd_send(&hdev->hw, &desc, 1); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 743c9f41c67ea..070b9ddb6ffe0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -1011,6 +1011,7 @@ struct hclge_query_ppu_pf_other_int_dfx_cmd { }; #define HCLGE_LINK_EVENT_REPORT_EN_B 0 +#define HCLGE_NCSI_ERROR_REPORT_EN_B 1 struct hclge_firmware_compat_cmd { __le32 compat; u8 rsv[20]; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 87de32dfa6c83..5a7221ee6bb96 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -582,6 +582,15 @@ static bool hclge_cmd_crq_empty(struct hclge_hw *hw) return tail == hw->cmq.crq.next_to_use; } +static void hclge_handle_ncsi_error(struct hclge_dev *hdev) +{ + struct hnae3_ae_dev *ae_dev = hdev->ae_dev; + + ae_dev->ops->set_default_reset_request(ae_dev, HNAE3_GLOBAL_RESET); + dev_warn(&hdev->pdev->dev, "requesting reset due to NCSI error\n"); + ae_dev->ops->reset_event(hdev->pdev, NULL); +} + void hclge_mbx_handler(struct hclge_dev *hdev) { struct hclge_cmq_ring *crq = &hdev->hw.cmq.crq; @@ -740,6 +749,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev) case HCLGE_MBX_PUSH_LINK_STATUS: hclge_handle_link_change_event(hdev, req); break; + case HCLGE_MBX_NCSI_ERROR: + hclge_handle_ncsi_error(hdev); + break; default: dev_err(&hdev->pdev->dev, "un-supported mailbox message, code = %d\n", From 3f0f325309aca23cb241c1aded0056d78d7366a1 Mon Sep 17 00:00:00 2001 From: Yufeng Mo Date: Thu, 1 Aug 2019 11:55:36 +0800 Subject: [PATCH 03/12] net: hns3: do not query unsupported commands in debugfs Some commands are not supported on DCB-unsupported ports. This patch distinguishes these commands and does not query unsupported commands in debugfs. This patch also fix an error in the dump "qos buf cfg" command in debugfs. Fixes: 2849d4e7a1be ("net: hns3: Add "tc config" info query function") Fixes: 7d9d7f8864ba ("net: hns3: Add "qos buffer" config info query function") Signed-off-by: Yufeng Mo Reviewed-by: Peng Li Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 70 ++++++++++++------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index ab625c757a955..e987d18ae18d0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -325,6 +325,12 @@ static void hclge_dbg_dump_tc(struct hclge_dev *hdev) struct hclge_desc desc; int i, ret; + if (!hnae3_dev_dcb_supported(hdev)) { + dev_info(&hdev->pdev->dev, + "Only DCB-supported dev supports tc\n"); + return; + } + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ETS_TC_WEIGHT, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -409,6 +415,12 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) dev_info(&hdev->pdev->dev, "QS_SCH qs_id: %u\n", desc.data[0]); + if (!hnae3_dev_dcb_supported(hdev)) { + dev_info(&hdev->pdev->dev, + "Only DCB-supported dev supports tm mapping\n"); + return; + } + cmd = HCLGE_OPC_TM_BP_TO_QSET_MAPPING; hclge_cmd_setup_basic_desc(&desc, cmd, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -590,6 +602,12 @@ static void hclge_dbg_dump_tm_map(struct hclge_dev *hdev, dev_info(&hdev->pdev->dev, "%04d | %04d | %02d | %02d\n", queue_id, qset_id, pri_id, tc_id); + if (!hnae3_dev_dcb_supported(hdev)) { + dev_info(&hdev->pdev->dev, + "Only DCB-supported dev supports tm mapping\n"); + return; + } + cmd = HCLGE_OPC_TM_BP_TO_QSET_MAPPING; bp_to_qs_map_cmd = (struct hclge_bp_to_qs_map_cmd *)desc.data; for (group_id = 0; group_id < 32; group_id++) { @@ -715,6 +733,34 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) dev_info(&hdev->pdev->dev, "rx_share_buf: 0x%x\n", rx_buf_cmd->shared_buf); + cmd = HCLGE_OPC_RX_COM_WL_ALLOC; + hclge_cmd_setup_basic_desc(desc, cmd, true); + ret = hclge_cmd_send(&hdev->hw, desc, 1); + if (ret) + goto err_qos_cmd_send; + + rx_com_wl = (struct hclge_rx_com_wl *)desc[0].data; + dev_info(&hdev->pdev->dev, "\n"); + dev_info(&hdev->pdev->dev, "rx_com_wl: high: 0x%x, low: 0x%x\n", + rx_com_wl->com_wl.high, rx_com_wl->com_wl.low); + + cmd = HCLGE_OPC_RX_GBL_PKT_CNT; + hclge_cmd_setup_basic_desc(desc, cmd, true); + ret = hclge_cmd_send(&hdev->hw, desc, 1); + if (ret) + goto err_qos_cmd_send; + + rx_packet_cnt = (struct hclge_rx_com_wl *)desc[0].data; + dev_info(&hdev->pdev->dev, + "rx_global_packet_cnt: high: 0x%x, low: 0x%x\n", + rx_packet_cnt->com_wl.high, rx_packet_cnt->com_wl.low); + dev_info(&hdev->pdev->dev, "\n"); + + if (!hnae3_dev_dcb_supported(hdev)) { + dev_info(&hdev->pdev->dev, + "Only DCB-supported dev supports rx priv wl\n"); + return; + } cmd = HCLGE_OPC_RX_PRIV_WL_ALLOC; hclge_cmd_setup_basic_desc(&desc[0], cmd, true); desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT); @@ -723,7 +769,6 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) if (ret) goto err_qos_cmd_send; - dev_info(&hdev->pdev->dev, "\n"); rx_priv_wl = (struct hclge_rx_priv_wl_buf *)desc[0].data; for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++) dev_info(&hdev->pdev->dev, @@ -758,29 +803,6 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) "rx_com_thrd_tc_%d: high: 0x%x, low: 0x%x\n", i + 4, rx_com_thrd->com_thrd[i].high, rx_com_thrd->com_thrd[i].low); - - cmd = HCLGE_OPC_RX_COM_WL_ALLOC; - hclge_cmd_setup_basic_desc(desc, cmd, true); - ret = hclge_cmd_send(&hdev->hw, desc, 1); - if (ret) - goto err_qos_cmd_send; - - rx_com_wl = (struct hclge_rx_com_wl *)desc[0].data; - dev_info(&hdev->pdev->dev, "\n"); - dev_info(&hdev->pdev->dev, "rx_com_wl: high: 0x%x, low: 0x%x\n", - rx_com_wl->com_wl.high, rx_com_wl->com_wl.low); - - cmd = HCLGE_OPC_RX_GBL_PKT_CNT; - hclge_cmd_setup_basic_desc(desc, cmd, true); - ret = hclge_cmd_send(&hdev->hw, desc, 1); - if (ret) - goto err_qos_cmd_send; - - rx_packet_cnt = (struct hclge_rx_com_wl *)desc[0].data; - dev_info(&hdev->pdev->dev, - "rx_global_packet_cnt: high: 0x%x, low: 0x%x\n", - rx_packet_cnt->com_wl.high, rx_packet_cnt->com_wl.low); - return; err_qos_cmd_send: From a723fb8efe29d3912d2be41edcf38b76f8d6ed36 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 1 Aug 2019 11:55:37 +0800 Subject: [PATCH 04/12] net: hns3: refine for set ring parameters Previously, when changing the ring parameters, we free the old ring resources firstly, and then setup the new ring resources. In some case of an memory allocation fail, there will be no resources to use. This patch refines it by setup new ring resources and free the old ring resources in order. Also reduce the max ring BD number to 32760 according to UM. Signed-off-by: Jian Shen Reviewed-by: Peng Li Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 2 +- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 3 +- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 88 +++++++++++++------ 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index d2df42d30d88f..79973a0167623 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3588,7 +3588,7 @@ static int hns3_alloc_ring_memory(struct hns3_enet_ring *ring) return ret; } -static void hns3_fini_ring(struct hns3_enet_ring *ring) +void hns3_fini_ring(struct hns3_enet_ring *ring) { hns3_free_desc(ring); devm_kfree(ring_to_dev(ring), ring->desc_cb); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 1a17856f9a3bc..0a970f5fed106 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -75,7 +75,7 @@ enum hns3_nic_state { #define HNS3_TX_TIMEOUT (5 * HZ) #define HNS3_RING_NAME_LEN 16 #define HNS3_BUFFER_SIZE_2048 2048 -#define HNS3_RING_MAX_PENDING 32768 +#define HNS3_RING_MAX_PENDING 32760 #define HNS3_RING_MIN_PENDING 24 #define HNS3_RING_BD_MULTIPLE 8 /* max frame size of mac */ @@ -642,6 +642,7 @@ void hns3_clean_tx_ring(struct hns3_enet_ring *ring); int hns3_init_all_ring(struct hns3_nic_priv *priv); int hns3_uninit_all_ring(struct hns3_nic_priv *priv); int hns3_nic_reset_all_ring(struct hnae3_handle *h); +void hns3_fini_ring(struct hns3_enet_ring *ring); netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev); bool hns3_is_phys_func(struct pci_dev *pdev); int hns3_clean_rx_ring( diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index fe0f82a972346..02f46c73ac3bc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -867,8 +867,8 @@ static int hns3_get_rxnfc(struct net_device *netdev, } } -static int hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv, - u32 tx_desc_num, u32 rx_desc_num) +static void hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv, + u32 tx_desc_num, u32 rx_desc_num) { struct hnae3_handle *h = priv->ae_handle; int i; @@ -881,21 +881,29 @@ static int hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv, priv->ring_data[i + h->kinfo.num_tqps].ring->desc_num = rx_desc_num; } - - return hns3_init_all_ring(priv); } -static int hns3_set_ringparam(struct net_device *ndev, - struct ethtool_ringparam *param) +static struct hns3_enet_ring *hns3_backup_ringparam(struct hns3_nic_priv *priv) { - struct hns3_nic_priv *priv = netdev_priv(ndev); - struct hnae3_handle *h = priv->ae_handle; - bool if_running = netif_running(ndev); - u32 old_tx_desc_num, new_tx_desc_num; - u32 old_rx_desc_num, new_rx_desc_num; - int queue_num = h->kinfo.num_tqps; - int ret; + struct hnae3_handle *handle = priv->ae_handle; + struct hns3_enet_ring *tmp_rings; + int i; + tmp_rings = kcalloc(handle->kinfo.num_tqps * 2, + sizeof(struct hns3_enet_ring), GFP_KERNEL); + if (!tmp_rings) + return NULL; + + for (i = 0; i < handle->kinfo.num_tqps * 2; i++) + memcpy(&tmp_rings[i], priv->ring_data[i].ring, + sizeof(struct hns3_enet_ring)); + + return tmp_rings; +} + +static int hns3_check_ringparam(struct net_device *ndev, + struct ethtool_ringparam *param) +{ if (hns3_nic_resetting(ndev)) return -EBUSY; @@ -911,6 +919,25 @@ static int hns3_set_ringparam(struct net_device *ndev, return -EINVAL; } + return 0; +} + +static int hns3_set_ringparam(struct net_device *ndev, + struct ethtool_ringparam *param) +{ + struct hns3_nic_priv *priv = netdev_priv(ndev); + struct hnae3_handle *h = priv->ae_handle; + struct hns3_enet_ring *tmp_rings; + bool if_running = netif_running(ndev); + u32 old_tx_desc_num, new_tx_desc_num; + u32 old_rx_desc_num, new_rx_desc_num; + u16 queue_num = h->kinfo.num_tqps; + int ret, i; + + ret = hns3_check_ringparam(ndev, param); + if (ret) + return ret; + /* Hardware requires that its descriptors must be multiple of eight */ new_tx_desc_num = ALIGN(param->tx_pending, HNS3_RING_BD_MULTIPLE); new_rx_desc_num = ALIGN(param->rx_pending, HNS3_RING_BD_MULTIPLE); @@ -920,6 +947,13 @@ static int hns3_set_ringparam(struct net_device *ndev, old_rx_desc_num == new_rx_desc_num) return 0; + tmp_rings = hns3_backup_ringparam(priv); + if (!tmp_rings) { + netdev_err(ndev, + "backup ring param failed by allocating memory fail\n"); + return -ENOMEM; + } + netdev_info(ndev, "Changing Tx/Rx ring depth from %d/%d to %d/%d\n", old_tx_desc_num, old_rx_desc_num, @@ -928,22 +962,24 @@ static int hns3_set_ringparam(struct net_device *ndev, if (if_running) ndev->netdev_ops->ndo_stop(ndev); - ret = hns3_uninit_all_ring(priv); - if (ret) - return ret; - - ret = hns3_change_all_ring_bd_num(priv, new_tx_desc_num, - new_rx_desc_num); + hns3_change_all_ring_bd_num(priv, new_tx_desc_num, new_rx_desc_num); + ret = hns3_init_all_ring(priv); if (ret) { - ret = hns3_change_all_ring_bd_num(priv, old_tx_desc_num, - old_rx_desc_num); - if (ret) { - netdev_err(ndev, - "Revert to old bd num fail, ret=%d.\n", ret); - return ret; - } + netdev_err(ndev, "Change bd num fail, revert to old value(%d)\n", + ret); + + hns3_change_all_ring_bd_num(priv, old_tx_desc_num, + old_rx_desc_num); + for (i = 0; i < h->kinfo.num_tqps * 2; i++) + memcpy(priv->ring_data[i].ring, &tmp_rings[i], + sizeof(struct hns3_enet_ring)); + } else { + for (i = 0; i < h->kinfo.num_tqps * 2; i++) + hns3_fini_ring(&tmp_rings[i]); } + kfree(tmp_rings); + if (if_running) ret = ndev->netdev_ops->ndo_open(ndev); From 6e4139f69163fb5769c92a97b969ea0d9a114ced Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 1 Aug 2019 11:55:38 +0800 Subject: [PATCH 05/12] net: hns3: remove unnecessary variable in hclge_get_mac_vlan_cmd_status() The local variable return_status in hclge_get_mac_val_cmd_status() is useless. So this patch returns the error code directly, instead of using this variable. Also, replace some '%d' with '%u' in hclge_get_mac_val_cmd_status(). Signed-off-by: Jian Shen Reviewed-by: Peng Li Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_main.c | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 855b65e8ebf65..4317c8fe68f37 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -6268,7 +6268,6 @@ static int hclge_get_mac_vlan_cmd_status(struct hclge_vport *vport, enum hclge_mac_vlan_tbl_opcode op) { struct hclge_dev *hdev = vport->back; - int return_status = -EIO; if (cmdq_resp) { dev_err(&hdev->pdev->dev, @@ -6279,52 +6278,53 @@ static int hclge_get_mac_vlan_cmd_status(struct hclge_vport *vport, if (op == HCLGE_MAC_VLAN_ADD) { if ((!resp_code) || (resp_code == 1)) { - return_status = 0; + return 0; } else if (resp_code == HCLGE_ADD_UC_OVERFLOW) { - return_status = -ENOSPC; dev_err(&hdev->pdev->dev, "add mac addr failed for uc_overflow.\n"); + return -ENOSPC; } else if (resp_code == HCLGE_ADD_MC_OVERFLOW) { - return_status = -ENOSPC; dev_err(&hdev->pdev->dev, "add mac addr failed for mc_overflow.\n"); - } else { - dev_err(&hdev->pdev->dev, - "add mac addr failed for undefined, code=%d.\n", - resp_code); + return -ENOSPC; } + + dev_err(&hdev->pdev->dev, + "add mac addr failed for undefined, code=%u.\n", + resp_code); + return -EIO; } else if (op == HCLGE_MAC_VLAN_REMOVE) { if (!resp_code) { - return_status = 0; + return 0; } else if (resp_code == 1) { - return_status = -ENOENT; dev_dbg(&hdev->pdev->dev, "remove mac addr failed for miss.\n"); - } else { - dev_err(&hdev->pdev->dev, - "remove mac addr failed for undefined, code=%d.\n", - resp_code); + return -ENOENT; } + + dev_err(&hdev->pdev->dev, + "remove mac addr failed for undefined, code=%u.\n", + resp_code); + return -EIO; } else if (op == HCLGE_MAC_VLAN_LKUP) { if (!resp_code) { - return_status = 0; + return 0; } else if (resp_code == 1) { - return_status = -ENOENT; dev_dbg(&hdev->pdev->dev, "lookup mac addr failed for miss.\n"); - } else { - dev_err(&hdev->pdev->dev, - "lookup mac addr failed for undefined, code=%d.\n", - resp_code); + return -ENOENT; } - } else { - return_status = -EINVAL; + dev_err(&hdev->pdev->dev, - "unknown opcode for get_mac_vlan_cmd_status,opcode=%d.\n", - op); + "lookup mac addr failed for undefined, code=%u.\n", + resp_code); + return -EIO; } - return return_status; + dev_err(&hdev->pdev->dev, + "unknown opcode for get_mac_vlan_cmd_status, opcode=%d.\n", op); + + return -EINVAL; } static int hclge_update_desc_vfid(struct hclge_desc *desc, int vfid, bool clr) From a4ee7624c003cc73a2eac9d9d5317b0c9fed89c4 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 1 Aug 2019 11:55:39 +0800 Subject: [PATCH 06/12] net: hns3: minor cleanup in hns3_clean_rx_ring The unused_count variable is used to indicate how many RX BD need attaching new buffer in hns3_clean_rx_ring, and the clean_count variable has the similar meaning. This patch removes the clean_count variable and use unused_count to uniformly indicate the RX BD that need attaching new buffer. This patch also clean up some coding style related to variable assignment in hns3_clean_rx_ring. Signed-off-by: Yunsheng Lin Reviewed-by: Peng Li Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 79973a0167623..ed05fb9f04edb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2909,24 +2909,22 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, void (*rx_fn)(struct hns3_enet_ring *, struct sk_buff *)) { #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16 - int recv_pkts, recv_bds, clean_count, err; int unused_count = hns3_desc_unused(ring); struct sk_buff *skb = ring->skb; - int num; + int recv_pkts = 0; + int recv_bds = 0; + int err, num; num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_FBDNUM_REG); rmb(); /* Make sure num taken effect before the other data is touched */ - recv_pkts = 0, recv_bds = 0, clean_count = 0; num -= unused_count; unused_count -= ring->pending_buf; while (recv_pkts < budget && recv_bds < num) { /* Reuse or realloc buffers */ - if (clean_count + unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) { - hns3_nic_alloc_rx_buffers(ring, - clean_count + unused_count); - clean_count = 0; + if (unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) { + hns3_nic_alloc_rx_buffers(ring, unused_count); unused_count = hns3_desc_unused(ring) - ring->pending_buf; } @@ -2940,7 +2938,7 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, goto out; } else if (unlikely(err)) { /* Do jump the err */ recv_bds += ring->pending_buf; - clean_count += ring->pending_buf; + unused_count += ring->pending_buf; ring->skb = NULL; ring->pending_buf = 0; continue; @@ -2948,7 +2946,7 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, rx_fn(ring, skb); recv_bds += ring->pending_buf; - clean_count += ring->pending_buf; + unused_count += ring->pending_buf; ring->skb = NULL; ring->pending_buf = 0; @@ -2957,8 +2955,8 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, out: /* Make all data has been write before submit */ - if (clean_count + unused_count > 0) - hns3_nic_alloc_rx_buffers(ring, clean_count + unused_count); + if (unused_count > 0) + hns3_nic_alloc_rx_buffers(ring, unused_count); return recv_pkts; } From b6872fd361056f3bce3e9fcfe9535c4b6b737531 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 1 Aug 2019 11:55:40 +0800 Subject: [PATCH 07/12] net: hns3: minior error handling change for hclge_tm_schd_info_init When hclge_tm_schd_info_update calls hclge_tm_schd_info_init to initialize the schedule info, hdev->tm_info.num_pg and hdev->tx_sch_mode is not changed, which makes the checking in hclge_tm_schd_info_init unnecessary. So this patch moves the hdev->tm_info.num_pg and hdev->tx_sch_mode checking into hclge_tm_schd_init and changes the return type of hclge_tm_schd_info_init from int to void. Signed-off-by: Yunsheng Lin Reviewed-by: Peng Li Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 3f41fa2bc4143..f30d1126d378c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -650,12 +650,8 @@ static void hclge_pfc_info_init(struct hclge_dev *hdev) } } -static int hclge_tm_schd_info_init(struct hclge_dev *hdev) +static void hclge_tm_schd_info_init(struct hclge_dev *hdev) { - if ((hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE) && - (hdev->tm_info.num_pg != 1)) - return -EINVAL; - hclge_tm_pg_info_init(hdev); hclge_tm_tc_info_init(hdev); @@ -663,8 +659,6 @@ static int hclge_tm_schd_info_init(struct hclge_dev *hdev) hclge_tm_vport_info_update(hdev); hclge_pfc_info_init(hdev); - - return 0; } static int hclge_tm_pg_to_pri_map(struct hclge_dev *hdev) @@ -1428,15 +1422,15 @@ int hclge_tm_init_hw(struct hclge_dev *hdev, bool init) int hclge_tm_schd_init(struct hclge_dev *hdev) { - int ret; - /* fc_mode is HCLGE_FC_FULL on reset */ hdev->tm_info.fc_mode = HCLGE_FC_FULL; hdev->fc_mode_last_time = hdev->tm_info.fc_mode; - ret = hclge_tm_schd_info_init(hdev); - if (ret) - return ret; + if (hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE && + hdev->tm_info.num_pg != 1) + return -EINVAL; + + hclge_tm_schd_info_init(hdev); return hclge_tm_init_hw(hdev, true); } From dbae56a33f5881bad631b0121f9b4a5e7b2a454d Mon Sep 17 00:00:00 2001 From: Weihang Li Date: Thu, 1 Aug 2019 11:55:41 +0800 Subject: [PATCH 08/12] net: hns3: simplify hclge_cmd_query_error() The 4th and 5th parameter of hclge_cmd_query_error is useless, so this patch removes them. Signed-off-by: Weihang Li Reviewed-by: Peng Li Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_err.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index 0a7243825e7ba..05a4cdbf903af 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -652,16 +652,11 @@ static void hclge_log_error(struct device *dev, char *reg, * @desc: descriptor for describing the command * @cmd: command opcode * @flag: flag for extended command structure - * @w_num: offset for setting the read interrupt type. - * @int_type: select which type of the interrupt for which the error - * info will be read(RAS-CE/RAS-NFE/RAS-FE etc). * * This function query the error info from hw register/s using command */ static int hclge_cmd_query_error(struct hclge_dev *hdev, - struct hclge_desc *desc, u32 cmd, - u16 flag, u8 w_num, - enum hclge_err_int_type int_type) + struct hclge_desc *desc, u32 cmd, u16 flag) { struct device *dev = &hdev->pdev->dev; int desc_num = 1; @@ -673,8 +668,6 @@ static int hclge_cmd_query_error(struct hclge_dev *hdev, hclge_cmd_setup_basic_desc(&desc[1], cmd, true); desc_num = 2; } - if (w_num) - desc[0].data[w_num] = cpu_to_le32(int_type); ret = hclge_cmd_send(&hdev->hw, &desc[0], desc_num); if (ret) @@ -872,8 +865,7 @@ static int hclge_config_tm_hw_err_int(struct hclge_dev *hdev, bool en) } /* configure TM QCN hw errors */ - ret = hclge_cmd_query_error(hdev, &desc, HCLGE_TM_QCN_MEM_INT_CFG, - 0, 0, 0); + ret = hclge_cmd_query_error(hdev, &desc, HCLGE_TM_QCN_MEM_INT_CFG, 0); if (ret) { dev_err(dev, "fail(%d) to read TM QCN CFG status\n", ret); return ret; @@ -1410,7 +1402,7 @@ static int hclge_log_rocee_ecc_error(struct hclge_dev *hdev) ret = hclge_cmd_query_error(hdev, &desc[0], HCLGE_QUERY_ROCEE_ECC_RAS_INFO_CMD, - HCLGE_CMD_FLAG_NEXT, 0, 0); + HCLGE_CMD_FLAG_NEXT); if (ret) { dev_err(dev, "failed(%d) to query ROCEE ECC error sts\n", ret); return ret; @@ -1434,7 +1426,7 @@ static int hclge_log_rocee_ovf_error(struct hclge_dev *hdev) /* read overflow error status */ ret = hclge_cmd_query_error(hdev, &desc[0], HCLGE_ROCEE_PF_RAS_INT_CMD, - 0, 0, 0); + 0); if (ret) { dev_err(dev, "failed(%d) to query ROCEE OVF error sts\n", ret); return ret; @@ -1483,8 +1475,7 @@ hclge_log_and_clear_rocee_ras_error(struct hclge_dev *hdev) /* read RAS error interrupt status */ ret = hclge_cmd_query_error(hdev, &desc[0], - HCLGE_QUERY_CLEAR_ROCEE_RAS_INT, - 0, 0, 0); + HCLGE_QUERY_CLEAR_ROCEE_RAS_INT, 0); if (ret) { dev_err(dev, "failed(%d) to query ROCEE RAS INT SRC\n", ret); /* reset everything for now */ From 6e6e7680630c1b80042a79f62509aab5f49e3e88 Mon Sep 17 00:00:00 2001 From: Guojia Liao Date: Thu, 1 Aug 2019 11:55:42 +0800 Subject: [PATCH 09/12] net: hns3: rename a member in struct hclge_mac_ethertype_idx_rd_cmd The member 'mac_add' defined in hclge_mac_ethertype_idx_rd_cmd means MAC address, so 'mac_addr' is a better name for it. Signed-off-by: Guojia Liao Signed-off-by: Guangbin Huang Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 070b9ddb6ffe0..cfa77dd19a7ee 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -828,7 +828,7 @@ struct hclge_mac_ethertype_idx_rd_cmd { u8 flags; u8 resp_code; __le16 vlan_tag; - u8 mac_add[6]; + u8 mac_addr[6]; __le16 index; __le16 ethter_type; __le16 egress_port; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index e987d18ae18d0..f16bfc67412a1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -847,9 +847,9 @@ static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev) memset(printf_buf, 0, HCLGE_DBG_BUF_LEN); snprintf(printf_buf, HCLGE_DBG_BUF_LEN, "%02u |%02x:%02x:%02x:%02x:%02x:%02x|", - req0->index, req0->mac_add[0], req0->mac_add[1], - req0->mac_add[2], req0->mac_add[3], req0->mac_add[4], - req0->mac_add[5]); + req0->index, req0->mac_addr[0], req0->mac_addr[1], + req0->mac_addr[2], req0->mac_addr[3], + req0->mac_addr[4], req0->mac_addr[5]); snprintf(printf_buf + strlen(printf_buf), HCLGE_DBG_BUF_LEN - strlen(printf_buf), From 6b428b4fbf986077d218287dd6f805f371cdf48f Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Thu, 1 Aug 2019 11:55:43 +0800 Subject: [PATCH 10/12] net: hns3: fix some reset handshake issue Currently, the driver sets handshake status to tell the hardware that the driver have downed the netdev and it can continue with reset process. The driver will clear the handshake status when re-initializing the CMDQ, and does not recover this status when reset fail, which may cause the hardware to wait for the handshake status to be set and not being able to continue with reset process. So this patch delays clearing handshake status just before UP, and recovers this status when reset fail. BTW, this patch adds a new function hclge(vf)_reset_handshake() to deal with the reset handshake issue, and renames HCLGE(VF)_NIC_CMQ_ENABLE to HCLGE(VF)_NIC_SW_RST_RDY which represents this register bit more accurately. Fixes: ada13ee3db7b ("net: hns3: add handshake with hardware while doing reset") Signed-off-by: Huazhong Tan Reviewed-by: Peng Li Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_cmd.c | 7 +++-- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 7 +++-- .../hisilicon/hns3/hns3pf/hclge_main.c | 23 ++++++++++++-- .../hisilicon/hns3/hns3vf/hclgevf_cmd.c | 4 ++- .../hisilicon/hns3/hns3vf/hclgevf_cmd.h | 7 +++-- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 31 +++++++++++++++---- 6 files changed, 64 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index c20b972d21f78..ecf58cfd253dc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -103,14 +103,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_SW_RST_RDY; + 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_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index cfa77dd19a7ee..63cf9a7d57201 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -907,8 +907,11 @@ struct hclge_serdes_lb_cmd { #define HCLGE_NIC_CRQ_DEPTH_REG 0x27020 #define HCLGE_NIC_CRQ_TAIL_REG 0x27024 #define HCLGE_NIC_CRQ_HEAD_REG 0x27028 -#define HCLGE_NIC_CMQ_EN_B 16 -#define HCLGE_NIC_CMQ_ENABLE BIT(HCLGE_NIC_CMQ_EN_B) + +/* this bit indicates that the driver is ready for hardware reset */ +#define HCLGE_NIC_SW_RST_RDY_B 16 +#define HCLGE_NIC_SW_RST_RDY BIT(HCLGE_NIC_SW_RST_RDY_B) + #define HCLGE_NIC_CMQ_DESC_NUM 1024 #define HCLGE_NIC_CMQ_DESC_NUM_S 3 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 4317c8fe68f37..abe4cee06d4ac 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3274,6 +3274,19 @@ static int hclge_reset_prepare_down(struct hclge_dev *hdev) return ret; } +static void hclge_reset_handshake(struct hclge_dev *hdev, bool enable) +{ + u32 reg_val; + + reg_val = hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG); + if (enable) + reg_val |= HCLGE_NIC_SW_RST_RDY; + else + reg_val &= ~HCLGE_NIC_SW_RST_RDY; + + hclge_write_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG, reg_val); +} + static int hclge_reset_prepare_wait(struct hclge_dev *hdev) { #define HCLGE_RESET_SYNC_TIME 100 @@ -3322,8 +3335,7 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev) /* inform hardware that preparatory work is done */ msleep(HCLGE_RESET_SYNC_TIME); - hclge_write_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG, - HCLGE_NIC_CMQ_ENABLE); + hclge_reset_handshake(hdev, true); dev_info(&hdev->pdev->dev, "prepare wait ok\n"); return ret; @@ -3354,6 +3366,10 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev) } hclge_clear_reset_cause(hdev); + + /* recover the handshake status when reset fail */ + hclge_reset_handshake(hdev, true); + dev_err(&hdev->pdev->dev, "Reset fail!\n"); return false; } @@ -3372,6 +3388,9 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev) break; } + /* clear up the handshake status after re-initialize done */ + hclge_reset_handshake(hdev, false); + 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 8f21eb3d9bd29..55d3c784f2d4e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -97,7 +97,9 @@ static void hclgevf_cmd_config_regs(struct hclgevf_cmq_ring *ring) reg_val = (u32)((ring->desc_dma_addr >> 31) >> 1); 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_SW_RST_RDY; + 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_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h index 127a434a56f34..f830eef02e5c0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h @@ -244,8 +244,11 @@ struct hclgevf_cfg_tx_queue_pointer_cmd { #define HCLGEVF_NIC_CRQ_DEPTH_REG 0x27020 #define HCLGEVF_NIC_CRQ_TAIL_REG 0x27024 #define HCLGEVF_NIC_CRQ_HEAD_REG 0x27028 -#define HCLGEVF_NIC_CMQ_EN_B 16 -#define HCLGEVF_NIC_CMQ_ENABLE BIT(HCLGEVF_NIC_CMQ_EN_B) + +/* this bit indicates that the driver is ready for hardware reset */ +#define HCLGEVF_NIC_SW_RST_RDY_B 16 +#define HCLGEVF_NIC_SW_RST_RDY BIT(HCLGEVF_NIC_SW_RST_RDY_B) + #define HCLGEVF_NIC_CMQ_DESC_NUM 1024 #define HCLGEVF_NIC_CMQ_DESC_NUM_S 3 #define HCLGEVF_NIC_CMDQ_INT_SRC_REG 0x27100 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index ae0e6a69d54bf..340d89eea2a80 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1426,6 +1426,20 @@ static int hclgevf_reset_wait(struct hclgevf_dev *hdev) return 0; } +static void hclgevf_reset_handshake(struct hclgevf_dev *hdev, bool enable) +{ + u32 reg_val; + + reg_val = hclgevf_read_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG); + if (enable) + reg_val |= HCLGEVF_NIC_SW_RST_RDY; + else + reg_val &= ~HCLGEVF_NIC_SW_RST_RDY; + + hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG, + reg_val); +} + static int hclgevf_reset_stack(struct hclgevf_dev *hdev) { int ret; @@ -1448,7 +1462,14 @@ static int hclgevf_reset_stack(struct hclgevf_dev *hdev) if (ret) return ret; - return hclgevf_notify_client(hdev, HNAE3_RESTORE_CLIENT); + ret = hclgevf_notify_client(hdev, HNAE3_RESTORE_CLIENT); + if (ret) + return ret; + + /* clear handshake status with IMP */ + hclgevf_reset_handshake(hdev, false); + + return 0; } static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev) @@ -1474,8 +1495,7 @@ static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev) set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state); /* inform hardware that preparatory work is done */ msleep(HCLGEVF_RESET_SYNC_TIME); - hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG, - HCLGEVF_NIC_CMQ_ENABLE); + hclgevf_reset_handshake(hdev, true); dev_info(&hdev->pdev->dev, "prepare reset(%d) wait done, ret:%d\n", hdev->reset_type, ret); @@ -1484,6 +1504,8 @@ static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev) static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev) { + /* recover handshake status with IMP when reset fail */ + hclgevf_reset_handshake(hdev, true); hdev->rst_stats.rst_fail_cnt++; dev_err(&hdev->pdev->dev, "failed to reset VF(%d)\n", hdev->rst_stats.rst_fail_cnt); @@ -1494,9 +1516,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); } } From 72e2fb07997c5ca2c73114624fd64c41be013bdc Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Thu, 1 Aug 2019 11:55:44 +0800 Subject: [PATCH 11/12] net: hns3: clear reset interrupt status in hclge_irq_handle() Currently, the reset interrupt is cleared in the reset task, which is too late. Since, when the hardware finish the previous reset, it can begin to do a new global/IMP reset, if this new coming reset type is same as the previous one, the driver will clear them together, then driver can not get that there is another reset, but the hardware still wait for the driver to deal with the second one. So this patch clears PF's reset interrupt status in the hclge_irq_handle(), the hardware waits for handshaking from driver before doing reset, so the driver and hardware deal with reset one by one. BTW, when VF doing global/IMP reset, it reads PF's reset interrupt register to get that whether PF driver's re-initialization is done, since VF's re-initialization should be done after PF's. So we add a new command and a register bit to do that. When VF receive reset interrupt, it sets up this bit, and PF finishes re-initialization send command to clear this bit, then VF do re-initialization. Fixes: 4ed340ab8f49 ("net: hns3: Add reset process in hclge_main") Signed-off-by: Huazhong Tan Reviewed-by: Yunsheng Lin Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 8 +++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 34 +++++++++++++++++-- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 29 ++++++++++------ .../hisilicon/hns3/hns3vf/hclgevf_main.h | 3 ++ 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 63cf9a7d57201..dade20a37d401 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -86,6 +86,7 @@ enum hclge_opcode_type { HCLGE_OPC_QUERY_PF_RSRC = 0x0023, HCLGE_OPC_QUERY_VF_RSRC = 0x0024, HCLGE_OPC_GET_CFG_PARAM = 0x0025, + HCLGE_OPC_PF_RST_DONE = 0x0026, HCLGE_OPC_STATS_64_BIT = 0x0030, HCLGE_OPC_STATS_32_BIT = 0x0031, @@ -878,6 +879,13 @@ struct hclge_reset_cmd { u8 rsv[22]; }; +#define HCLGE_PF_RESET_DONE_BIT BIT(0) + +struct hclge_pf_rst_done_cmd { + u8 pf_rst_done; + u8 rsv[23]; +}; + #define HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B BIT(0) #define HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B BIT(2) #define HCLGE_CMD_SERDES_DONE_B BIT(0) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index abe4cee06d4ac..c4841c3ea2e58 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2876,10 +2876,15 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data) break; } - /* clear the source of interrupt if it is not cause by reset */ + hclge_clear_event_cause(hdev, event_cause, clearval); + + /* Enable interrupt if it is not cause by reset. And when + * clearval equal to 0, it means interrupt status may be + * cleared by hardware before driver reads status register. + * For this case, vector0 interrupt also should be enabled. + */ if (!clearval || event_cause == HCLGE_VECTOR0_EVENT_MBX) { - hclge_clear_event_cause(hdev, event_cause, clearval); hclge_enable_vector(&hdev->misc_vector, true); } @@ -3253,7 +3258,13 @@ static void hclge_clear_reset_cause(struct hclge_dev *hdev) if (!clearval) return; - hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, clearval); + /* For revision 0x20, the reset interrupt source + * can only be cleared after hardware reset done + */ + if (hdev->pdev->revision == 0x20) + hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, + clearval); + hclge_enable_vector(&hdev->misc_vector, true); } @@ -3374,6 +3385,18 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev) return false; } +static int hclge_set_rst_done(struct hclge_dev *hdev) +{ + struct hclge_pf_rst_done_cmd *req; + struct hclge_desc desc; + + req = (struct hclge_pf_rst_done_cmd *)desc.data; + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PF_RST_DONE, false); + req->pf_rst_done |= HCLGE_PF_RESET_DONE_BIT; + + return hclge_cmd_send(&hdev->hw, &desc, 1); +} + static int hclge_reset_prepare_up(struct hclge_dev *hdev) { int ret = 0; @@ -3384,6 +3407,11 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev) case HNAE3_FLR_RESET: ret = hclge_set_all_vf_rst(hdev, false); break; + case HNAE3_GLOBAL_RESET: + /* fall through */ + case HNAE3_IMP_RESET: + ret = hclge_set_rst_done(hdev); + break; default: break; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 340d89eea2a80..ce82b2b0f8f54 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1396,19 +1396,22 @@ static int hclgevf_reset_wait(struct hclgevf_dev *hdev) u32 val; int ret; - /* wait to check the hardware reset completion status */ - val = hclgevf_read_dev(&hdev->hw, HCLGEVF_RST_ING); - dev_info(&hdev->pdev->dev, "checking vf resetting status: %x\n", val); - if (hdev->reset_type == HNAE3_FLR_RESET) return hclgevf_flr_poll_timeout(hdev, HCLGEVF_RESET_WAIT_US, HCLGEVF_RESET_WAIT_CNT); - - ret = readl_poll_timeout(hdev->hw.io_base + HCLGEVF_RST_ING, val, - !(val & HCLGEVF_RST_ING_BITS), - HCLGEVF_RESET_WAIT_US, - HCLGEVF_RESET_WAIT_TIMEOUT_US); + else if (hdev->reset_type == HNAE3_VF_RESET) + ret = readl_poll_timeout(hdev->hw.io_base + + HCLGEVF_VF_RST_ING, val, + !(val & HCLGEVF_VF_RST_ING_BIT), + HCLGEVF_RESET_WAIT_US, + HCLGEVF_RESET_WAIT_TIMEOUT_US); + else + ret = readl_poll_timeout(hdev->hw.io_base + + HCLGEVF_RST_ING, val, + !(val & HCLGEVF_RST_ING_BITS), + HCLGEVF_RESET_WAIT_US, + HCLGEVF_RESET_WAIT_TIMEOUT_US); /* hardware completion status should be available by this time */ if (ret) { @@ -1886,7 +1889,7 @@ static void hclgevf_clear_event_cause(struct hclgevf_dev *hdev, u32 regclr) static enum hclgevf_evt_cause hclgevf_check_evt_cause(struct hclgevf_dev *hdev, u32 *clearval) { - u32 cmdq_src_reg, rst_ing_reg; + u32 val, cmdq_src_reg, rst_ing_reg; /* fetch the events from their corresponding regs */ cmdq_src_reg = hclgevf_read_dev(&hdev->hw, @@ -1902,6 +1905,12 @@ static enum hclgevf_evt_cause hclgevf_check_evt_cause(struct hclgevf_dev *hdev, cmdq_src_reg &= ~BIT(HCLGEVF_VECTOR0_RST_INT_B); *clearval = cmdq_src_reg; hdev->rst_stats.vf_rst_cnt++; + /* set up VF hardware reset status, its PF will clear + * this status when PF has initialized done. + */ + val = hclgevf_read_dev(&hdev->hw, HCLGEVF_VF_RST_ING); + hclgevf_write_dev(&hdev->hw, HCLGEVF_VF_RST_ING, + val | HCLGEVF_VF_RST_ING_BIT); return HCLGEVF_VECTOR0_EVENT_RST; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 5a9e30998a8f5..f0736b0608849 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -103,6 +103,9 @@ (HCLGEVF_FUN_RST_ING_BIT | HCLGEVF_GLOBAL_RST_ING_BIT | \ HCLGEVF_CORE_RST_ING_BIT | HCLGEVF_IMP_RST_ING_BIT) +#define HCLGEVF_VF_RST_ING 0x07008 +#define HCLGEVF_VF_RST_ING_BIT BIT(16) + #define HCLGEVF_RSS_IND_TBL_SIZE 512 #define HCLGEVF_RSS_SET_BITMAP_MSK 0xffff #define HCLGEVF_RSS_KEY_SIZE 40 From 012fcb52f67cbba95c3e85010a4a9c40ea43866f Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Thu, 1 Aug 2019 11:55:45 +0800 Subject: [PATCH 12/12] net: hns3: activate reset timer when calling reset_event When calling hclge_reset_event() within HCLGE_RESET_INTERVAL, it returns directly now. If no one call it again, then the error which needs a reset to fix it can not be fixed. So this patch activates the reset timer for this case, and adds checking in the end of the reset procedure to make this error fixed earlier. Signed-off-by: Huazhong Tan Reviewed-by: Peng Li Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_main.c | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c4841c3ea2e58..b7399f5ba2c36 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3517,7 +3517,15 @@ static void hclge_reset(struct hclge_dev *hdev) hdev->reset_fail_cnt = 0; hdev->rst_stats.reset_done_cnt++; ae_dev->reset_type = HNAE3_NONE_RESET; - del_timer(&hdev->reset_timer); + + /* if default_reset_request has a higher level reset request, + * it should be handled as soon as possible. since some errors + * need this kind of reset to fix. + */ + hdev->reset_level = hclge_get_reset_level(ae_dev, + &hdev->default_reset_request); + if (hdev->reset_level != HNAE3_NONE_RESET) + set_bit(hdev->reset_level, &hdev->reset_request); return; @@ -3552,9 +3560,10 @@ static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle) handle = &hdev->vport[0].nic; if (time_before(jiffies, (hdev->last_reset_time + - HCLGE_RESET_INTERVAL))) + HCLGE_RESET_INTERVAL))) { + mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL); return; - else if (hdev->default_reset_request) + } else if (hdev->default_reset_request) hdev->reset_level = hclge_get_reset_level(ae_dev, &hdev->default_reset_request); @@ -3584,6 +3593,12 @@ static void hclge_reset_timer(struct timer_list *t) { struct hclge_dev *hdev = from_timer(hdev, t, reset_timer); + /* if default_reset_request has no value, it means that this reset + * request has already be handled, so just return here + */ + if (!hdev->default_reset_request) + return; + dev_info(&hdev->pdev->dev, "triggering reset in reset timer\n"); hclge_reset_event(hdev->pdev, NULL);