From 10feb6c7f8d76aeba30e33048a28a9edf7492d90 Mon Sep 17 00:00:00 2001 From: shenjian Date: Thu, 27 Jun 2019 15:36:12 +0800 Subject: [PATCH] net: hns3: add link change event report driver inclusion category: bugfix bugzilla: NA CVE: NA Previously, PF update link status per seconed. For some scenario, such as storage, 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: shenjian (K) Reviewed-by: lipeng Reviewed-by: Yang Yingliang Signed-off-by: Yang Yingliang --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 1 + .../hisilicon/hns3/hns3pf/hclge_cmd.c | 22 ++++++++++ .../hisilicon/hns3/hns3pf/hclge_cmd.h | 8 ++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 18 ++++++-- .../hisilicon/hns3/hns3pf/hclge_main.h | 9 ++++ .../hisilicon/hns3/hns3pf/hclge_mbx.c | 41 +++++++++++++++++++ 6 files changed, 95 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 70848afd19dc..ea779759ac04 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 flr status */ + HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ HCLGE_MBX_NCSI_ERROR = 202, /* (M7 -> PF) receive a NCSI error */ }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index fad6b010d8d7..c0c521e9fc15 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -382,6 +382,20 @@ 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; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_COMPAT_CFG, false); + + req = (struct hclge_firmware_compat_cmd *)desc.data; + hnae3_set_bit(req->compat, HCLGE_LINK_EVENT_REPORT_EN_B, 1); + hnae3_set_bit(req->compat, HCLGE_NCSI_ERROR_REPORT_EN_B, 1); + + return hclge_cmd_send(&hdev->hw, &desc, 1); +} + int hclge_cmd_init(struct hclge_dev *hdev) { u32 version; @@ -420,6 +434,14 @@ int hclge_cmd_init(struct hclge_dev *hdev) dev_info(&hdev->pdev->dev, "The firmware version is %08x\n", version); + /* ask the firmware to enable some features, driver can work without + * it. + */ + clear_bit(HCLGE_STATE_LINK_CHANGE_REPORT_EN, &hdev->state); + ret = hclge_firmware_compat_config(hdev); + if (!ret) + set_bit(HCLGE_STATE_LINK_CHANGE_REPORT_EN, &hdev->state); + 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 f5c81f30f274..f138765147b5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -263,6 +263,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, @@ -1026,6 +1027,13 @@ struct hclge_query_ppu_pf_other_int_dfx_cmd { u8 rsv[4]; }; +#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]; +}; + 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 00c083a4f696..f211bbfb54fe 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2546,18 +2546,17 @@ static int hclge_get_mac_phy_link(struct hclge_dev *hdev) return !!link_stat; } -static void hclge_update_link_status(struct hclge_dev *hdev) +void hclge_link_status_change(struct hclge_dev *hdev, int state) { struct hnae3_client *rclient = hdev->roce_client; struct hnae3_client *client = hdev->nic_client; struct hnae3_handle *rhandle; struct hnae3_handle *handle; - int state; int i; if (!client) return; - state = hclge_get_mac_phy_link(hdev); + if (state != hdev->hw.mac.link) { for (i = 0; i < hdev->num_vmdq_vport + 1; i++) { handle = &hdev->vport[i].nic; @@ -2572,6 +2571,15 @@ static void hclge_update_link_status(struct hclge_dev *hdev) } } +static void hclge_update_link_status(struct hclge_dev *hdev) +{ + int state; + + state = hclge_get_mac_phy_link(hdev); + + hclge_link_status_change(hdev, state); +} + static void hclge_update_port_capability(struct hclge_mac *mac) { #ifdef HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE @@ -6465,7 +6473,9 @@ static void hclge_ae_stop(struct hnae3_handle *handle) hclge_reset_tqp_stats(handle); del_timer_sync(&hdev->service_timer); cancel_work_sync(&hdev->service_task); - hclge_update_link_status(hdev); + + if (!test_bit(HCLGE_STATE_LINK_CHANGE_REPORT_EN, &hdev->state)) + hclge_update_link_status(hdev); } int hclge_vport_start(struct hclge_vport *vport) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 1c313b2c3f65..eaeb84e1a500 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -158,6 +158,7 @@ enum HCLGE_DEV_STATE { HCLGE_STATE_MBX_HANDLING, HCLGE_STATE_STATISTICS_UPDATING, HCLGE_STATE_CMD_DISABLE, + HCLGE_STATE_LINK_CHANGE_REPORT_EN, HCLGE_STATE_MAX }; @@ -249,6 +250,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 @@ -967,4 +975,5 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid, u16 vlan_proto); enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev, unsigned long *addr); +void hclge_link_status_change(struct hclge_dev *hdev, int state); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 02b7cb99055d..4046518f6997 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -572,6 +572,44 @@ 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 + + struct phy_device *phydev = hdev->hw.mac.phydev; + int link_status = req->msg[LINK_STATUS_OFFSET]; + + if (phydev) { + if (phydev->state == PHY_RUNNING) + link_status = link_status & phydev->link; + else + link_status = 0; + } + + hclge_link_status_change(hdev, link_status); + if (!link_status) + 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); @@ -739,6 +777,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev) dev_warn(&hdev->pdev->dev, "requesting reset due to NCSI error\n"); ae_dev->ops->reset_event(hdev->pdev, NULL); 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", -- GitLab