Commit ed8fb4b2 authored by Jian Shen's avatar Jian Shen Committed by David S. Miller

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: default avatarJian Shen <shenjian15@huawei.com>
Reviewed-by: default avatarPeng Li <lipeng321@huawei.com>
Signed-off-by: default avatarHuazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0ae9fce3
......@@ -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 */
......
......@@ -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:
......
......@@ -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)
{
......
......@@ -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;
}
......
......@@ -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
......@@ -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",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment