From 42815023f104f1d9bab88f0003dbc99a704db782 Mon Sep 17 00:00:00 2001 From: shenjian Date: Fri, 24 May 2019 10:27:32 +0800 Subject: [PATCH] net: hns3: fix vlan filter mismatch issue 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: Yang Yingliang Signed-off-by: Yang Yingliang --- .../hisilicon/hns3/hns3pf/hclge_main.c | 30 ++++++++---- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 49 +++++++++++++++++-- .../hisilicon/hns3/hns3vf/hclgevf_main.h | 3 ++ 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 3fc707d58129..c3f5534c4303 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -7223,12 +7223,13 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid, if (!req0->resp_code) return 0; - if (req0->resp_code == HCLGE_VF_VLAN_DEL_NO_FOUND) { - dev_warn(&hdev->pdev->dev, - "vlan %d filter is not in vf vlan table\n", - vlan); + /* vf vlan filter is disabled when vf vlan table is full, + * then new vlan id will not be added into vf vlan table. + * Just return 0 without warning, avoid massive verbose + * print logs when unload. + */ + if (req0->resp_code == HCLGE_VF_VLAN_DEL_NO_FOUND) return 0; - } dev_err(&hdev->pdev->dev, "Kill vf vlan filter fail, ret =%d.\n", @@ -7323,11 +7324,20 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, bool writen_to_tbl = false; int ret = 0; + /* When device is resetting, firmware is unable to handle + * mailbox. Just record the vlan id, and remove it after + * reset finished. + */ + if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) && is_kill) { + set_bit(vlan_id, vport->vlan_del_fail_bmap); + return -EBUSY; + } + /* when port base vlan enabled, we use port base vlan as the vlan * filter condition. In this case, we don't update vlan filter table * when user add new vlan or remove exist vlan, just update the vport * vlan list. The vlan id in vlan list will be writen in vlan filter - * table until port base vlan disabled + * table until port base vlan disabled. */ if (handle->port_base_vlan_state == HNAE3_PORT_BASE_VLAN_DISABLE) { ret = hclge_set_vlan_filter_hw(hdev, proto, vport->vport_id, @@ -7344,9 +7354,8 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, } 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 + * with stack. */ - hclge_rm_vport_vlan_table(vport, vlan_id, false); set_bit(vlan_id, vport->vlan_del_fail_bmap); } return ret; @@ -7883,8 +7892,11 @@ static void hclge_sync_vlan_filter(struct hclge_dev *hdev) ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, vlan_id, 0, true); - if (!ret || ret == -EINVAL) + if (!ret || ret == -EINVAL) { clear_bit(vlan_id, vport->vlan_del_fail_bmap); + hclge_rm_vport_vlan_table(vport, vlan_id, + false); + } sync_cnt++; if (sync_cnt >= HCLGE_MAX_SYNC_COUNT) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 98e2dc409292..1fe5c4eaec23 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1209,6 +1209,7 @@ static int hclgevf_set_vlan_filter(struct hnae3_handle *handle, #define HCLGEVF_VLAN_MBX_MSG_LEN 5 struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); u8 msg_data[HCLGEVF_VLAN_MBX_MSG_LEN]; + int ret; if (vlan_id > MAX_VLAN_ID) return -EINVAL; @@ -1216,12 +1217,52 @@ static int hclgevf_set_vlan_filter(struct hnae3_handle *handle, if (proto != htons(ETH_P_8021Q)) return -EPROTONOSUPPORT; + /* When device is resetting, firmware is unable to handle + * mailbox. Just record the vlan id, and remove it after + * reset finished. + */ + if (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state) && is_kill) { + set_bit(vlan_id, hdev->vlan_del_fail_bmap); + return -EBUSY; + } + msg_data[0] = is_kill; memcpy(&msg_data[1], &vlan_id, sizeof(vlan_id)); memcpy(&msg_data[3], &proto, sizeof(proto)); - return hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN, - HCLGE_MBX_VLAN_FILTER, msg_data, - HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0); + ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN, + HCLGE_MBX_VLAN_FILTER, msg_data, + HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0); + + /* when remove hw vlan filter failed, record the vlan id, + * and try to remove it from hw later, to be consistence + * with stack. + */ + if (is_kill && ret) + set_bit(vlan_id, hdev->vlan_del_fail_bmap); + + return ret; +} + +static void hclgevf_sync_vlan_filter(struct hclgevf_dev *hdev) +{ +#define HCLGEVF_MAX_SYNC_COUNT 60 + struct hnae3_handle *handle = &hdev->nic; + int ret, sync_cnt = 0; + u16 vlan_id; + + vlan_id = find_first_bit(hdev->vlan_del_fail_bmap, VLAN_N_VID); + while (vlan_id != VLAN_N_VID) { + ret = hclgevf_set_vlan_filter(handle, htons(ETH_P_8021Q), + vlan_id, true); + if (!ret) + clear_bit(vlan_id, hdev->vlan_del_fail_bmap); + + sync_cnt++; + if (sync_cnt >= HCLGEVF_MAX_SYNC_COUNT) + return; + + vlan_id = find_first_bit(hdev->vlan_del_fail_bmap, VLAN_N_VID); + } } static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) @@ -1801,6 +1842,8 @@ static void hclgevf_service_task(struct work_struct *work) hclgevf_update_link_mode(hdev); + hclgevf_sync_vlan_filter(hdev); + hclgevf_deferred_task_schedule(hdev); clear_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index eab24b90c5ea..b9f35d532ee3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -4,6 +4,7 @@ #ifndef __HCLGEVF_MAIN_H #define __HCLGEVF_MAIN_H #include +#include #include #include "hclge_mbx.h" #include "hclgevf_cmd.h" @@ -221,6 +222,8 @@ struct hclgevf_dev { u16 *vector_status; int *vector_irq; + unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)]; + bool mbx_event_pending; struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */ struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */ -- GitLab