提交 10feb6c7 编写于 作者: S shenjian 提交者: Xie XiuQi

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: Nshenjian (K) <shenjian15@huawei.com>
Reviewed-by: Nlipeng <lipeng321@huawei.com>
Reviewed-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 8c024f84
...@@ -47,6 +47,7 @@ enum HCLGE_MBX_OPCODE { ...@@ -47,6 +47,7 @@ enum HCLGE_MBX_OPCODE {
HCLGE_MBX_GET_MEDIA_TYPE, /* (VF -> PF) get media type */ 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_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 */ HCLGE_MBX_NCSI_ERROR = 202, /* (M7 -> PF) receive a NCSI error */
}; };
......
...@@ -382,6 +382,20 @@ int hclge_cmd_queue_init(struct hclge_dev *hdev) ...@@ -382,6 +382,20 @@ int hclge_cmd_queue_init(struct hclge_dev *hdev)
return ret; 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) int hclge_cmd_init(struct hclge_dev *hdev)
{ {
u32 version; u32 version;
...@@ -420,6 +434,14 @@ int hclge_cmd_init(struct hclge_dev *hdev) ...@@ -420,6 +434,14 @@ int hclge_cmd_init(struct hclge_dev *hdev)
dev_info(&hdev->pdev->dev, "The firmware version is %08x\n", version); 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; return 0;
err_cmd_init: err_cmd_init:
......
...@@ -263,6 +263,7 @@ enum hclge_opcode_type { ...@@ -263,6 +263,7 @@ enum hclge_opcode_type {
/* M7 stats command */ /* M7 stats command */
HCLGE_OPC_M7_STATS_BD = 0x7012, HCLGE_OPC_M7_STATS_BD = 0x7012,
HCLGE_OPC_M7_STATS_INFO = 0x7013, HCLGE_OPC_M7_STATS_INFO = 0x7013,
HCLGE_OPC_M7_COMPAT_CFG = 0x701A,
/* SFP command */ /* SFP command */
HCLGE_OPC_GET_SFP_INFO = 0x7104, HCLGE_OPC_GET_SFP_INFO = 0x7104,
...@@ -1026,6 +1027,13 @@ struct hclge_query_ppu_pf_other_int_dfx_cmd { ...@@ -1026,6 +1027,13 @@ struct hclge_query_ppu_pf_other_int_dfx_cmd {
u8 rsv[4]; 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); int hclge_cmd_init(struct hclge_dev *hdev);
static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value) static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
{ {
......
...@@ -2546,18 +2546,17 @@ static int hclge_get_mac_phy_link(struct hclge_dev *hdev) ...@@ -2546,18 +2546,17 @@ static int hclge_get_mac_phy_link(struct hclge_dev *hdev)
return !!link_stat; 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 *rclient = hdev->roce_client;
struct hnae3_client *client = hdev->nic_client; struct hnae3_client *client = hdev->nic_client;
struct hnae3_handle *rhandle; struct hnae3_handle *rhandle;
struct hnae3_handle *handle; struct hnae3_handle *handle;
int state;
int i; int i;
if (!client) if (!client)
return; return;
state = hclge_get_mac_phy_link(hdev);
if (state != hdev->hw.mac.link) { if (state != hdev->hw.mac.link) {
for (i = 0; i < hdev->num_vmdq_vport + 1; i++) { for (i = 0; i < hdev->num_vmdq_vport + 1; i++) {
handle = &hdev->vport[i].nic; handle = &hdev->vport[i].nic;
...@@ -2572,6 +2571,15 @@ static void hclge_update_link_status(struct hclge_dev *hdev) ...@@ -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) static void hclge_update_port_capability(struct hclge_mac *mac)
{ {
#ifdef HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE #ifdef HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE
...@@ -6465,7 +6473,9 @@ static void hclge_ae_stop(struct hnae3_handle *handle) ...@@ -6465,7 +6473,9 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
hclge_reset_tqp_stats(handle); hclge_reset_tqp_stats(handle);
del_timer_sync(&hdev->service_timer); del_timer_sync(&hdev->service_timer);
cancel_work_sync(&hdev->service_task); 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) int hclge_vport_start(struct hclge_vport *vport)
......
...@@ -158,6 +158,7 @@ enum HCLGE_DEV_STATE { ...@@ -158,6 +158,7 @@ enum HCLGE_DEV_STATE {
HCLGE_STATE_MBX_HANDLING, HCLGE_STATE_MBX_HANDLING,
HCLGE_STATE_STATISTICS_UPDATING, HCLGE_STATE_STATISTICS_UPDATING,
HCLGE_STATE_CMD_DISABLE, HCLGE_STATE_CMD_DISABLE,
HCLGE_STATE_LINK_CHANGE_REPORT_EN,
HCLGE_STATE_MAX HCLGE_STATE_MAX
}; };
...@@ -249,6 +250,13 @@ enum hclge_fc_mode { ...@@ -249,6 +250,13 @@ enum hclge_fc_mode {
HCLGE_FC_DEFAULT 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_PG_NUM 4
#define HCLGE_SCH_MODE_SP 0 #define HCLGE_SCH_MODE_SP 0
#define HCLGE_SCH_MODE_DWRR 1 #define HCLGE_SCH_MODE_DWRR 1
...@@ -967,4 +975,5 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid, ...@@ -967,4 +975,5 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
u16 vlan_proto); u16 vlan_proto);
enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev, enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev,
unsigned long *addr); unsigned long *addr);
void hclge_link_status_change(struct hclge_dev *hdev, int state);
#endif #endif
...@@ -572,6 +572,44 @@ static int hclge_get_rss_key(struct hclge_vport *vport, ...@@ -572,6 +572,44 @@ static int hclge_get_rss_key(struct hclge_vport *vport,
HCLGE_RSS_MBX_RESP_LEN); 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) static bool hclge_cmd_crq_empty(struct hclge_hw *hw)
{ {
u32 tail = hclge_read_dev(hw, HCLGE_NIC_CRQ_TAIL_REG); u32 tail = hclge_read_dev(hw, HCLGE_NIC_CRQ_TAIL_REG);
...@@ -739,6 +777,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev) ...@@ -739,6 +777,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
dev_warn(&hdev->pdev->dev, "requesting reset due to NCSI error\n"); dev_warn(&hdev->pdev->dev, "requesting reset due to NCSI error\n");
ae_dev->ops->reset_event(hdev->pdev, NULL); ae_dev->ops->reset_event(hdev->pdev, NULL);
break; break;
case HCLGE_MBX_PUSH_LINK_STATUS:
hclge_handle_link_change_event(hdev, req);
break;
default: default:
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"un-supported mailbox message, code = %d\n", "un-supported mailbox message, code = %d\n",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册