diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 70848afd19dc73ee098c27bec83d8a127b639ecc..ea779759ac04f9e51479478aa483d596b8f2f4e8 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 fad6b010d8d7d19018bf2b8f542f638ca7011af8..c0c521e9fc1569dac95031bb1d5957dc89efa973 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 f5c81f30f274a87ea569abfe5bdffbc88ac8fd96..f138765147b53494cc44e9b98f573635c8ebcc4a 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 00c083a4f6965607f317ca4704541865d2c97dba..f211bbfb54feae86157e100727012656235b5c11 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 1c313b2c3f65013d2a44b8049a321e2fc63aa01d..eaeb84e1a5006027517ceea9708623340dcf10d9 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 02b7cb99055db5ae7d3a3f26fe346629d7290867..4046518f69978c16cb6f8ab39b79446256a4237b 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",