diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2901e83c8dfea20a2867682cf12975903653bd0e..d728332432ac923368227e4202c1bf489944c6e5 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 1fa49e8e4c7799bc872e8450d5765a73d73f7a1c..4562c5a7e1f9081d2289b0d5fb51047d0ea6149a 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;