From af21392dc0789d6c54fa013808a27e95b3c157cf Mon Sep 17 00:00:00 2001 From: shenjian Date: Tue, 23 Apr 2019 18:36:22 +0800 Subject: [PATCH] net: hns3: sync vlan filter entries when kill vlan id failed driver inclusion category: bugfix bugzilla: NA CVE: NA When hw is resetting, firmware is unable to handle commands from driver. So if remove vlan device from stack at this time, it will fail to remove the vlan id from from hw vlan filter, then the vlan filter status is unsynced with stack. This patch fixes it by recording the vlan id delete failed, and remove them again when reset complete. Signed-off-by: shenjian (K) Reviewed-by: lipeng Reviewed-by: Hanjun Guo Signed-off-by: Yang Yingliang --- .../hisilicon/hns3/hns3pf/hclge_main.c | 41 +++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 1 + 2 files changed, 42 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2901e83c8dfe..d728332432ac 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -36,6 +36,7 @@ static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps); static int hclge_init_vlan_config(struct hclge_dev *hdev); +static void hclge_sync_vlan_filter(struct hclge_dev *hdev); static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev); static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle); static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size, @@ -3502,6 +3503,7 @@ static void hclge_service_task(struct work_struct *work) hclge_update_port_info(hdev); hclge_update_link_status(hdev); hclge_update_vport_alive(hdev); + hclge_sync_vlan_filter(hdev); if (hdev->fd_arfs_expire_timer >= HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL) { hclge_rfs_filter_expire(hdev); @@ -7253,6 +7255,13 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, else hclge_add_vport_vlan_table(vport, vlan_id, writen_to_tbl); + } else if (is_kill) { + /* when remove hw vlan filter failed, record the vlan id, + * and try to remove it from hw later, to be consistence + * with stack + */ + hclge_rm_vport_vlan_table(vport, vlan_id, false); + set_bit(vlan_id, vport->vlan_del_fail_bmap); } return ret; } @@ -7769,6 +7778,38 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid, } } +static void hclge_sync_vlan_filter(struct hclge_dev *hdev) +{ +#define HCLGE_MAX_SYNC_COUNT 60 + + int sync_cnt = 0; + u16 vlan_id; + int ret; + int i; + + /* start from vport 1 for PF is always alive */ + for (i = 0; i < hdev->num_alloc_vport; i++) { + struct hclge_vport *vport = &hdev->vport[i]; + + vlan_id = find_first_bit(vport->vlan_del_fail_bmap, + VLAN_N_VID); + while (vlan_id != VLAN_N_VID) { + ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), + vport->vport_id, vlan_id, + 0, true); + if (!ret || ret == -EINVAL) + clear_bit(vlan_id, vport->vlan_del_fail_bmap); + + sync_cnt++; + if (sync_cnt >= HCLGE_MAX_SYNC_COUNT) + return; + + vlan_id = find_first_bit(vport->vlan_del_fail_bmap, + VLAN_N_VID); + } + } +} + static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps) { struct hclge_config_max_frm_size_cmd *req; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 1fa49e8e4c77..4562c5a7e1f9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -873,6 +873,7 @@ struct hclge_vport { u32 bw_limit; /* VSI BW Limit (0 = disabled) */ u8 dwrr; + unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)]; struct list_head vlan_list; /* Store VF vlan table */ struct hclge_port_base_vlan_config port_base_vlan_cfg; struct hclge_tx_vtag_cfg txvlan_cfg; -- GitLab