From: Jian Shen shenjian15@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
Currently, the HNS3 driver sync and unsync mac address in function hns3_set_rx_mode(). For VF, it sends mailbox messages to PF to request adding or deleting mac address in the path of function hns3_set_rx_mode(), no matter the address is configured success. This patch refines it by sending the mac address configure request in the service task of VF, and adding or deleting these mac addresses in the service task. Either is failed, it will retry in the next schedule of service task.
Signed-off-by: Jian Shen shenjian15@huawei.com Reviewed-by: Peng Li lipeng321@huawei.com Reviewed-by: Zhong Zhaohui zhongzhaohui@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 1 - drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 - drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 1 - drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 9 - .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 177 ++++++++------- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 18 +- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 80 ++++--- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 241 ++++++++++++++++----- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 26 +++ 9 files changed, 351 insertions(+), 203 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 7b85b8d..a4dd3aef 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -72,7 +72,6 @@ enum hclge_mbx_vlan_cfg_subcode { };
enum hclge_mbx_tbl_cfg_subcode { - HCLGE_MBX_HW_TBL_RESTORE, HCLGE_MBX_VPORT_LIST_CLEAR, };
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 261a2c1..92854cc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -232,7 +232,6 @@ struct hnae3_ae_dev { struct list_head node; u32 flag; unsigned long hw_err_reset_req; - enum hnae3_reset_type reset_type; void *priv; };
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 3c306a8..9c79f46d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2143,7 +2143,6 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ae_dev->pdev = pdev; ae_dev->flag = ent->driver_data; - ae_dev->reset_type = HNAE3_NONE_RESET; hns3_get_dev_capability(pdev, ae_dev); pci_set_drvdata(pdev, ae_dev);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index a4cf1a8..98cd8a1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -575,15 +575,6 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value) writel(value, reg_addr + reg); }
-static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev) -{ - return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET || - ae_dev->reset_type == HNAE3_FLR_RESET || - ae_dev->reset_type == HNAE3_VF_FUNC_RESET || - ae_dev->reset_type == HNAE3_VF_FULL_RESET || - ae_dev->reset_type == HNAE3_VF_PF_FUNC_RESET)); -} - #define hns3_read_dev(a, reg) \ hns3_read_reg((a)->io_base, (reg))
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 24c6498..02f35fc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3756,10 +3756,6 @@ static void hclge_reset(struct hclge_dev *hdev) enum hnae3_reset_type reset_level; int ret;
- /* Initialize ae_dev reset status as well, in case enet layer wants to - * know if device is undergoing reset - */ - ae_dev->reset_type = hdev->reset_type; hdev->rst_stats.reset_cnt++; /* perform reset of the stack & ae device for a client */ ret = hclge_notify_roce_client(hdev, HNAE3_DOWN_CLIENT); @@ -3827,7 +3823,6 @@ static void hclge_reset(struct hclge_dev *hdev) hdev->last_reset_time = jiffies; hdev->rst_stats.reset_fail_cnt = 0; hdev->rst_stats.reset_done_cnt++; - ae_dev->reset_type = HNAE3_NONE_RESET;
/* if default_reset_request has a higher level reset request, * it should be handled as soon as possible. since some errors @@ -6985,8 +6980,17 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
int hclge_vport_start(struct hclge_vport *vport) { + struct hclge_dev *hdev = vport->back; + set_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); vport->last_active_jiffies = jiffies; + + /* when received vport start mbx, it means the VF is start now */ + if (test_and_clear_bit(HCLGE_VPORT_STATE_BLOCK_CONFIG, &vport->state) || + test_and_clear_bit(vport->vport_id, hdev->need_restore_vf_table)) { + hclge_restore_mac_table_common(vport); + hclge_restore_vport_vlan_table(vport); + } return 0; }
@@ -7409,12 +7413,11 @@ static void hclge_mac_node_convert(struct hclge_vport_mac_addr_cfg *mac_node, } }
-static int hclge_update_mac_list(struct hnae3_handle *handle, - enum HCLGE_MAC_ADDR_STATE state, - enum HCLGE_MAC_ADDR_TYPE mac_type, - const unsigned char *addr) +int hclge_update_mac_list(struct hclge_vport *vport, + enum HCLGE_MAC_ADDR_STATE state, + enum HCLGE_MAC_ADDR_TYPE mac_type, + const unsigned char *addr) { - struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport_mac_addr_cfg *mac_node; struct list_head *list;
@@ -7455,7 +7458,7 @@ static int hclge_add_uc_addr(struct hnae3_handle *handle, int ret;
spin_lock_bh(&vport->mac_list_lock); - ret = hclge_update_mac_list(handle, HCLGE_MAC_TO_ADD, HCLGE_MAC_ADDR_UC, + ret = hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, HCLGE_MAC_ADDR_UC, addr); spin_unlock_bh(&vport->mac_list_lock);
@@ -7536,7 +7539,7 @@ static int hclge_rm_uc_addr(struct hnae3_handle *handle, int ret;
spin_lock_bh(&vport->mac_list_lock); - ret = hclge_update_mac_list(handle, HCLGE_MAC_TO_DEL, HCLGE_MAC_ADDR_UC, + ret = hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL, HCLGE_MAC_ADDR_UC, addr); spin_unlock_bh(&vport->mac_list_lock);
@@ -7581,7 +7584,7 @@ static int hclge_add_mc_addr(struct hnae3_handle *handle, int ret;
spin_lock_bh(&vport->mac_list_lock); - ret = hclge_update_mac_list(handle, HCLGE_MAC_TO_ADD, HCLGE_MAC_ADDR_MC, + ret = hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, HCLGE_MAC_ADDR_MC, addr); spin_unlock_bh(&vport->mac_list_lock);
@@ -7630,7 +7633,7 @@ static int hclge_rm_mc_addr(struct hnae3_handle *handle, int ret;
spin_lock_bh(&vport->mac_list_lock); - ret = hclge_update_mac_list(handle, HCLGE_MAC_TO_DEL, HCLGE_MAC_ADDR_MC, + ret = hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL, HCLGE_MAC_ADDR_MC, addr); spin_unlock_bh(&vport->mac_list_lock);
@@ -7856,79 +7859,81 @@ static void hclge_sync_vport_mac_table(struct hclge_vport *vport, spin_unlock_bh(&vport->mac_list_lock); }
-static void hclge_sync_mac_table(struct hclge_dev *hdev) -{ - struct hclge_vport *vport = &hdev->vport[0]; - - if (hdev->serv_processed_cnt % HCLGE_MAC_TBL_SYNC_INTERVAL && - !test_and_clear_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, - &vport->state)) - return; - - hclge_sync_vport_mac_table(vport, HCLGE_MAC_ADDR_UC); - hclge_sync_vport_mac_table(vport, HCLGE_MAC_ADDR_MC); -} - -void hclge_add_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, - enum HCLGE_MAC_ADDR_TYPE mac_type) +static bool hclge_need_sync_mac_table(struct hclge_vport *vport) { - struct hclge_vport_mac_addr_cfg *mac_cfg; - struct list_head *list; - - if (!vport->vport_id) - return; - - mac_cfg = kzalloc(sizeof(*mac_cfg), GFP_KERNEL); - if (!mac_cfg) - return; + struct hclge_dev *hdev = vport->back; + bool time_up;
- mac_cfg->hd_tbl_status = true; - ether_addr_copy(mac_cfg->mac_addr, mac_addr); + if (test_bit(HCLGE_VPORT_STATE_BLOCK_CONFIG, &vport->state)) + return false;
- list = (mac_type == HCLGE_MAC_ADDR_UC) ? - &vport->uc_mac_list : &vport->mc_mac_list; + time_up = !(hdev->serv_processed_cnt % HCLGE_MAC_TBL_SYNC_INTERVAL); + if (time_up || + test_and_clear_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state)) + return true;
- list_add_tail(&mac_cfg->node, list); + return false; }
-void hclge_rm_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, - enum HCLGE_MAC_ADDR_TYPE mac_type) +static void hclge_sync_mac_table(struct hclge_dev *hdev) { - struct hclge_vport_mac_addr_cfg *mac_cfg, *tmp; - struct list_head *list; + struct hclge_vport *vport = &hdev->vport[0]; + int i;
- list = (mac_type == HCLGE_MAC_ADDR_UC) ? - &vport->uc_mac_list : &vport->mc_mac_list; + for (i = 0; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i];
- list_for_each_entry_safe(mac_cfg, tmp, list, node) { - if (ether_addr_equal(mac_cfg->mac_addr, mac_addr)) { - list_del(&mac_cfg->node); - kfree(mac_cfg); - break; - } + if (!hclge_need_sync_mac_table(vport)) + continue; + + hclge_sync_vport_mac_table(vport, HCLGE_MAC_ADDR_UC); + hclge_sync_vport_mac_table(vport, HCLGE_MAC_ADDR_MC); } }
void hclge_rm_vport_all_mac_table(struct hclge_vport *vport, bool is_del_list, enum HCLGE_MAC_ADDR_TYPE mac_type) { + int (*unsync)(struct hclge_vport *vport, const unsigned char *addr); struct hclge_vport_mac_addr_cfg *mac_cfg, *tmp; struct list_head *list; + int ret;
- list = (mac_type == HCLGE_MAC_ADDR_UC) ? - &vport->uc_mac_list : &vport->mc_mac_list; + if (mac_type == HCLGE_MAC_ADDR_UC) { + list = &vport->uc_mac_list; + unsync = hclge_rm_uc_addr_common; + } else { + list = &vport->mc_mac_list; + unsync = hclge_rm_mc_addr_common; + }
- list_for_each_entry_safe(mac_cfg, tmp, list, node) { - if (mac_type == HCLGE_MAC_ADDR_UC && mac_cfg->hd_tbl_status) - hclge_rm_uc_addr_common(vport, mac_cfg->mac_addr); + if (!is_del_list) + set_bit(HCLGE_VPORT_STATE_BLOCK_CONFIG, &vport->state);
- if (mac_type == HCLGE_MAC_ADDR_MC && mac_cfg->hd_tbl_status) - hclge_rm_mc_addr_common(vport, mac_cfg->mac_addr); + list_for_each_entry_safe(mac_cfg, tmp, list, node) { + if (mac_cfg->state == HCLGE_MAC_TO_ADD) { + if (is_del_list) { + list_del(&mac_cfg->node); + kfree(mac_cfg); + } + continue; + }
- mac_cfg->hd_tbl_status = false; - if (is_del_list) { - list_del(&mac_cfg->node); - kfree(mac_cfg); + ret = unsync(vport, mac_cfg->mac_addr); + if (!ret || ret == -ENOENT) { + /* clear all mac addr from hardware, but remain these + * mac addr in the mac list, and restore them after + * vf reset finished. + */ + if (!is_del_list && + mac_cfg->state == HCLGE_MAC_ACTIVE) { + mac_cfg->state = HCLGE_MAC_TO_ADD; + } else { + list_del(&mac_cfg->node); + kfree(mac_cfg); + } + } else if (is_del_list) { + mac_cfg->state = HCLGE_MAC_TO_DEL; } } } @@ -8150,8 +8155,8 @@ static void hclge_get_mac_addr(struct hnae3_handle *handle, u8 *p) /* use new node to replace old node in the list, if old address is still in * mac table, add it to list tail, and try to remove in service task */ -static void hclge_replace_mac_node(struct list_head *list, const u8 *old_addr, - const u8 *new_addr, bool keep_old) +void hclge_replace_mac_node(struct list_head *list, const u8 *old_addr, + const u8 *new_addr, bool keep_old) { struct hclge_vport_mac_addr_cfg *mac_node, *new_node;
@@ -8178,8 +8183,8 @@ static void hclge_replace_mac_node(struct list_head *list, const u8 *old_addr, } }
-static void hclge_modify_mac_node_state(struct list_head *list, const u8 *addr, - enum HCLGE_MAC_ADDR_STATE state) +void hclge_modify_mac_node_state(struct list_head *list, const u8 *addr, + enum HCLGE_MAC_ADDR_STATE state) { struct hclge_vport_mac_addr_cfg *mac_node;
@@ -8865,26 +8870,6 @@ void hclge_restore_vport_vlan_table(struct hclge_vport *vport) } }
-void hclge_restore_vport_mac_table(struct hclge_vport *vport) -{ - struct hclge_vport_mac_addr_cfg *mac_cfg, *tmp; - int ret; - - list_for_each_entry_safe(mac_cfg, tmp, &vport->uc_mac_list, node) { - ret = hclge_add_uc_addr_common(vport, mac_cfg->mac_addr); - if (!ret) - mac_cfg->hd_tbl_status = true; - else if (ret == -ENOSPC) - break; - } - - list_for_each_entry_safe(mac_cfg, tmp, &vport->mc_mac_list, node) { - ret = hclge_add_mc_addr_common(vport, mac_cfg->mac_addr); - if (!ret) - mac_cfg->hd_tbl_status = true; - } -} - /* For global reset and imp reset, hardware will clear the mac table, * so we change the mac address state from ACTIVE to TO_ADD, then they * can be restored in the service task after reset complete. Furtherly, @@ -8906,6 +8891,13 @@ static void hclge_mac_node_convert_for_reset(struct list_head *list) } }
+void hclge_restore_mac_table_common(struct hclge_vport *vport) +{ + hclge_mac_node_convert_for_reset(&vport->uc_mac_list); + hclge_mac_node_convert_for_reset(&vport->mc_mac_list); + clear_bit(HCLGE_VPORT_STATE_BLOCK_CONFIG, &vport->state); +} + static void hclge_restore_pf_mac_table(struct hclge_vport *vport) { /* move the mac addr to the tmp_add_list and tmp_del_list, then @@ -8913,8 +8905,7 @@ static void hclge_restore_pf_mac_table(struct hclge_vport *vport) */ spin_lock_bh(&vport->mac_list_lock);
- hclge_mac_node_convert_for_reset(&vport->uc_mac_list); - hclge_mac_node_convert_for_reset(&vport->mc_mac_list); + hclge_restore_mac_table_common(vport);
spin_unlock_bh(&vport->mac_list_lock); } @@ -8924,6 +8915,8 @@ static int hclge_restore_hw_table(struct hclge_dev *hdev) struct hclge_vport *vport = &hdev->vport[0]; struct hnae3_handle *handle = &vport->nic;
+ bitmap_set(hdev->need_restore_vf_table, 0, hdev->num_alloc_vport); + hclge_restore_pf_mac_table(vport); hclge_restore_vport_vlan_table(vport);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 68ea032..05ab6c1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -644,7 +644,6 @@ enum HCLGE_MAC_ADDR_STATE {
struct hclge_vport_mac_addr_cfg { struct list_head node; - int hd_tbl_status; enum HCLGE_MAC_ADDR_STATE state; u8 mac_addr[ETH_ALEN]; }; @@ -815,6 +814,8 @@ struct hclge_dev { unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)]; unsigned long vf_vlan_full[BITS_TO_LONGS(HCLGE_VPORT_NUM)];
+ unsigned long need_restore_vf_table[BITS_TO_LONGS(HCLGE_VPORT_NUM)]; + struct hclge_fd_cfg fd_cfg; struct hlist_head fd_rule_list; spinlock_t fd_rule_lock; /* protect fd_rule_list and fd_bmap */ @@ -878,6 +879,7 @@ struct hclge_rss_tuple_cfg { enum HCLGE_VPORT_STATE { HCLGE_VPORT_STATE_ALIVE, HCLGE_VPORT_STATE_MAC_TBL_CHANGE, + HCLGE_VPORT_STATE_BLOCK_CONFIG, /* blocking mac configuration */ HCLGE_VPORT_STATE_MAX };
@@ -998,15 +1000,19 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle, u16 queue_id); int hclge_notify_client(struct hclge_dev *hdev, enum hnae3_reset_notify_type type); -void hclge_add_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, - enum HCLGE_MAC_ADDR_TYPE mac_type); -void hclge_rm_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, - enum HCLGE_MAC_ADDR_TYPE mac_type); +int hclge_update_mac_list(struct hclge_vport *vport, + enum HCLGE_MAC_ADDR_STATE state, + enum HCLGE_MAC_ADDR_TYPE mac_type, + const unsigned char *addr); +void hclge_replace_mac_node(struct list_head *list, const u8 *old_addr, + const u8 *new_addr, bool keep_old); +void hclge_modify_mac_node_state(struct list_head *list, const u8 *addr, + enum HCLGE_MAC_ADDR_STATE state); void hclge_rm_vport_all_mac_table(struct hclge_vport *vport, bool is_del_list, enum HCLGE_MAC_ADDR_TYPE mac_type); void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_list); +void hclge_restore_mac_table_common(struct hclge_vport *vport); void hclge_restore_vport_vlan_table(struct hclge_vport *vport); -void hclge_restore_vport_mac_table(struct hclge_vport *vport); int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state, struct hclge_vlan_info *vlan_info); int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index fc746ea..e93e8d7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -263,13 +263,38 @@ void hclge_inform_vf_promisc_info(struct hclge_vport *vport) HCLGE_MBX_PUSH_PROMISC_INFO, dest_vfid); }
+static int hclge_modify_vf_mac_addr(struct hclge_vport *vport, + const u8 *old_addr, const u8 *new_addr) +{ + bool old_mac_removed = true; + int ret; + + ret = hclge_rm_uc_addr_common(vport, old_addr); + if (ret) + old_mac_removed = false; + + ret = hclge_add_uc_addr_common(vport, new_addr); + if (ret) { + ret = hclge_add_uc_addr_common(vport, old_addr); + if (ret) + hclge_modify_mac_node_state(&vport->uc_mac_list, + old_addr, HCLGE_MAC_TO_ADD); + return -EIO; + + } else { + hclge_replace_mac_node(&vport->uc_mac_list, old_addr, new_addr, + !old_mac_removed); + } + return ret; +} + static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *mbx_req) { #define HCLGE_MBX_VF_OLD_MAC_ADDR_OFFSET 6 const u8 *mac_addr = (const u8 *)(mbx_req->msg.data); struct hclge_dev *hdev = vport->back; - int status; + int status = 0;
if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_MODIFY) { const u8 *old_addr = (const u8 *) @@ -282,32 +307,22 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, if (is_zero_ether_addr(old_addr)) { status = hclge_add_uc_addr_common(vport, mac_addr); if (!status) - hclge_add_vport_mac_table(vport, mac_addr, - HCLGE_MAC_ADDR_UC); + hclge_update_mac_list(vport, HCLGE_MAC_ACTIVE, + HCLGE_MAC_ADDR_UC, + mac_addr); + else + hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, + HCLGE_MAC_ADDR_UC, + mac_addr); } else { - hclge_rm_uc_addr_common(vport, old_addr); - status = hclge_add_uc_addr_common(vport, mac_addr); - if (status) { - hclge_add_uc_addr_common(vport, old_addr); - } else { - hclge_rm_vport_mac_table(vport, old_addr, - HCLGE_MAC_ADDR_UC); - hclge_add_vport_mac_table(vport, mac_addr, - HCLGE_MAC_ADDR_UC); - } + hclge_modify_vf_mac_addr(vport, old_addr, mac_addr); } } else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_ADD) { - status = hclge_add_uc_addr_common(vport, mac_addr); - if (!status) { - hclge_add_vport_mac_table(vport, mac_addr, - HCLGE_MAC_ADDR_UC); - } + hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, + HCLGE_MAC_ADDR_UC, mac_addr); } else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_REMOVE) { - status = hclge_rm_uc_addr_common(vport, mac_addr); - if (!status) { - hclge_rm_vport_mac_table(vport, mac_addr, - HCLGE_MAC_ADDR_UC); - } + hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL, + HCLGE_MAC_ADDR_UC, mac_addr); } else { dev_err(&hdev->pdev->dev, "failed to set unicast mac addr, unknown subcode %u\n", @@ -322,18 +337,14 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport, { const u8 *mac_addr = (const u8 *)(mbx_req->msg.data); struct hclge_dev *hdev = vport->back; - int status; + int status = 0;
if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_MC_ADD) { - status = hclge_add_mc_addr_common(vport, mac_addr); - if (!status) - hclge_add_vport_mac_table(vport, mac_addr, - HCLGE_MAC_ADDR_MC); + hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, + HCLGE_MAC_ADDR_MC, mac_addr); } else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_MC_REMOVE) { - status = hclge_rm_mc_addr_common(vport, mac_addr); - if (!status) - hclge_rm_vport_mac_table(vport, mac_addr, - HCLGE_MAC_ADDR_MC); + hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL, + HCLGE_MAC_ADDR_MC, mac_addr); } else { dev_err(&hdev->pdev->dev, "failed to set mcast mac addr, unknown subcode %u\n", @@ -659,10 +670,7 @@ static void hclge_handle_vf_tbl(struct hclge_vport *vport, struct hclge_vf_vlan_cfg *msg_cmd;
msg_cmd = (struct hclge_vf_vlan_cfg *)&mbx_req->msg; - if (msg_cmd->subcode == HCLGE_MBX_HW_TBL_RESTORE) { - hclge_restore_vport_mac_table(vport); - hclge_restore_vport_vlan_table(vport); - } else if (msg_cmd->subcode == HCLGE_MBX_VPORT_LIST_CLEAR) { + if (msg_cmd->subcode == HCLGE_MBX_VPORT_LIST_CLEAR) { hclge_rm_vport_all_mac_table(vport, true, HCLGE_MAC_ADDR_UC); hclge_rm_vport_all_mac_table(vport, true, HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(vport, true); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 57ac897..c52b070 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -15,7 +15,6 @@ #define HCLGEVF_RESET_MAX_FAIL_CNT 5
static int hclgevf_reset_hdev(struct hclgevf_dev *hdev); -static int hclgevf_restore_hw_table(struct hclgevf_dev *hdev); static struct hnae3_ae_algo ae_algovf;
static struct workqueue_struct *hclgevf_wq; @@ -1267,54 +1266,206 @@ static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p, return status; }
-static int hclgevf_add_uc_addr(struct hnae3_handle *handle, - const unsigned char *addr) +static struct hclgevf_mac_addr_node * +hclgevf_find_mac_node(struct list_head *list, const u8 *mac_addr) +{ + struct hclgevf_mac_addr_node *mac_node, *tmp; + + list_for_each_entry_safe(mac_node, tmp, list, node) { + if (ether_addr_equal(mac_addr, mac_node->mac_addr)) + return mac_node; + } + return NULL; +} + +static int hclgevf_update_mac_list(struct hnae3_handle *handle, + enum HCLGEVF_MAC_ADDR_STATE state, + enum HCLGEVF_MAC_ADDR_TYPE mac_type, + const unsigned char *addr) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct hclge_vf_to_pf_msg send_msg; + struct hclgevf_mac_addr_node *mac_node; + struct list_head *list;
- hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_UNICAST, - HCLGE_MBX_MAC_VLAN_UC_ADD); - ether_addr_copy(send_msg.data, addr); - return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + list = (mac_type == HCLGEVF_MAC_ADDR_UC) ? + &hdev->mac_table.uc_mac_list : &hdev->mac_table.mc_mac_list; + + spin_lock_bh(&hdev->mac_table.mac_list_lock); + + mac_node = kzalloc(sizeof(*mac_node), GFP_ATOMIC); + if (!mac_node) { + spin_unlock_bh(&hdev->mac_table.mac_list_lock); + return -ENOMEM; + } + + mac_node->state = state; + ether_addr_copy(mac_node->mac_addr, addr); + list_add_tail(&mac_node->node, list); + + spin_unlock_bh(&hdev->mac_table.mac_list_lock); + return 0; +} + +static int hclgevf_add_uc_addr(struct hnae3_handle *handle, + const unsigned char *addr) +{ + return hclgevf_update_mac_list(handle, HCLGEVF_MAC_TO_ADD, + HCLGEVF_MAC_ADDR_UC, addr); }
static int hclgevf_rm_uc_addr(struct hnae3_handle *handle, const unsigned char *addr) { - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct hclge_vf_to_pf_msg send_msg; - - hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_UNICAST, - HCLGE_MBX_MAC_VLAN_UC_REMOVE); - ether_addr_copy(send_msg.data, addr); - return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + return hclgevf_update_mac_list(handle, HCLGEVF_MAC_TO_DEL, + HCLGEVF_MAC_ADDR_UC, addr); }
static int hclgevf_add_mc_addr(struct hnae3_handle *handle, const unsigned char *addr) { - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct hclge_vf_to_pf_msg send_msg; - - hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_MULTICAST, - HCLGE_MBX_MAC_VLAN_MC_ADD); - ether_addr_copy(send_msg.data, addr); - return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + return hclgevf_update_mac_list(handle, HCLGEVF_MAC_TO_ADD, + HCLGEVF_MAC_ADDR_MC, addr); }
static int hclgevf_rm_mc_addr(struct hnae3_handle *handle, const unsigned char *addr) { - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + return hclgevf_update_mac_list(handle, HCLGEVF_MAC_TO_DEL, + HCLGEVF_MAC_ADDR_MC, addr); +} + +static int hclgevf_add_del_mac_addr(struct hclgevf_dev *hdev, + struct hclgevf_mac_addr_node *mac_node, + enum HCLGEVF_MAC_ADDR_TYPE mac_type) +{ struct hclge_vf_to_pf_msg send_msg; + u8 code, subcode; + + if (mac_type == HCLGEVF_MAC_ADDR_UC) { + code = HCLGE_MBX_SET_UNICAST; + if (mac_node->state == HCLGEVF_MAC_TO_ADD) + subcode = HCLGE_MBX_MAC_VLAN_UC_ADD; + else + subcode = HCLGE_MBX_MAC_VLAN_UC_REMOVE; + } else { + code = HCLGE_MBX_SET_MULTICAST; + if (mac_node->state == HCLGEVF_MAC_TO_ADD) + subcode = HCLGE_MBX_MAC_VLAN_MC_ADD; + else + subcode = HCLGE_MBX_MAC_VLAN_MC_REMOVE; + }
- hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_MULTICAST, - HCLGE_MBX_MAC_VLAN_MC_REMOVE); - ether_addr_copy(send_msg.data, addr); + hclgevf_build_send_msg(&send_msg, code, subcode); + ether_addr_copy(send_msg.data, mac_node->mac_addr); return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); }
+static void hclgevf_config_mac_list(struct hclgevf_dev *hdev, + struct list_head *list, + enum HCLGEVF_MAC_ADDR_TYPE mac_type) +{ + struct hclgevf_mac_addr_node *mac_node, *tmp; + int ret; + + list_for_each_entry_safe(mac_node, tmp, list, node) { + ret = hclgevf_add_del_mac_addr(hdev, mac_node, mac_type); + if (ret) { + dev_err(&hdev->pdev->dev, + "request configure mac %pM failed, state=%d, ret=%d\n", + mac_node->mac_addr, mac_node->state, ret); + mac_node->state = HCLGEVF_MAC_REQ_FAIL; + return; + } + mac_node->state = HCLGEVF_MAC_REQ_SUC; + } +} + +static void hclgevf_sync_from_tmp_list(struct list_head *tmp_list, + struct list_head *mac_list) +{ + struct hclgevf_mac_addr_node *mac_node, *tmp, *new_node; + + list_for_each_entry_safe(mac_node, tmp, tmp_list, node) { + new_node = hclgevf_find_mac_node(mac_list, mac_node->mac_addr); + if (new_node) { + if (mac_node->state == HCLGEVF_MAC_REQ_SUC) { + list_del(&new_node->node); + kfree(new_node); + } + } + list_del(&mac_node->node); + kfree(mac_node); + } +} + +static void hclgevf_clear_list(struct list_head *list) +{ + struct hclgevf_mac_addr_node *mac_node, *tmp; + + list_for_each_entry_safe(mac_node, tmp, list, node) { + list_del(&mac_node->node); + kfree(mac_node); + } +} + +/* For PF handle VF's the mac configure request asynchronously, so VF + * is unware that whether the mac address is exist in the mac table. + * VF has to record the mac address from set_rx_mode, and send request + * one by one. After finish all request, then update the mac address + * state in mac list. + */ +static void hclgevf_sync_mac_list(struct hclgevf_dev *hdev, + enum HCLGEVF_MAC_ADDR_TYPE mac_type) +{ + struct hclgevf_mac_addr_node *mac_node, *tmp, *new_node; + struct list_head tmp_list, *list; + + INIT_LIST_HEAD(&tmp_list); + + list = (mac_type == HCLGEVF_MAC_ADDR_UC) ? + &hdev->mac_table.uc_mac_list : &hdev->mac_table.mc_mac_list; + + spin_lock_bh(&hdev->mac_table.mac_list_lock); + + list_for_each_entry_safe(mac_node, tmp, list, node) { + new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); + if (!new_node) { + hclgevf_clear_list(&tmp_list); + spin_unlock_bh(&hdev->mac_table.mac_list_lock); + return; + } + ether_addr_copy(new_node->mac_addr, mac_node->mac_addr); + new_node->state = mac_node->state; + list_add_tail(&new_node->node, &tmp_list); + } + + spin_unlock_bh(&hdev->mac_table.mac_list_lock); + + hclgevf_config_mac_list(hdev, &tmp_list, mac_type); + + spin_lock_bh(&hdev->mac_table.mac_list_lock); + + hclgevf_sync_from_tmp_list(&tmp_list, list); + + spin_unlock_bh(&hdev->mac_table.mac_list_lock); +} + +static void hclgevf_sync_mac_table(struct hclgevf_dev *hdev) +{ + hclgevf_sync_mac_list(hdev, HCLGEVF_MAC_ADDR_UC); + hclgevf_sync_mac_list(hdev, HCLGEVF_MAC_ADDR_MC); +} + +static void hclgevf_uninit_mac_list(struct hclgevf_dev *hdev) +{ + spin_lock_bh(&hdev->mac_table.mac_list_lock); + + hclgevf_clear_list(&hdev->mac_table.uc_mac_list); + hclgevf_clear_list(&hdev->mac_table.mc_mac_list); + + spin_unlock_bh(&hdev->mac_table.mac_list_lock); +} + static int hclgevf_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, u16 vlan_id, bool is_kill) @@ -1555,10 +1706,6 @@ static int hclgevf_reset_stack(struct hclgevf_dev *hdev) if (ret) return ret;
- ret = hclgevf_notify_client(hdev, HNAE3_RESTORE_CLIENT); - if (ret) - return ret; - /* clear handshake status with IMP */ hclgevf_reset_handshake(hdev, false);
@@ -1643,13 +1790,8 @@ static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev)
static int hclgevf_reset(struct hclgevf_dev *hdev) { - struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); int ret;
- /* Initialize ae_dev reset status as well, in case enet layer wants to - * know if device is undergoing reset - */ - ae_dev->reset_type = hdev->reset_type; hdev->rst_stats.rst_cnt++; rtnl_lock();
@@ -1694,7 +1836,6 @@ static int hclgevf_reset(struct hclgevf_dev *hdev)
rtnl_unlock();
- ae_dev->reset_type = HNAE3_NONE_RESET; hdev->rst_stats.rst_done_cnt++; hdev->rst_stats.rst_fail_cnt = 0;
@@ -1973,6 +2114,8 @@ static void hclgevf_periodical_service_task(struct hclgevf_dev *hdev)
hclgevf_sync_vlan_filter(hdev);
+ hclgevf_sync_mac_table(hdev); + hdev->last_serv_processed = jiffies;
out: @@ -2333,6 +2476,10 @@ static void hclgevf_state_init(struct hclgevf_dev *hdev)
mutex_init(&hdev->mbx_resp.mbx_mutex);
+ spin_lock_init(&hdev->mac_table.mac_list_lock); + INIT_LIST_HEAD(&hdev->mac_table.uc_mac_list); + INIT_LIST_HEAD(&hdev->mac_table.mc_mac_list); + /* bring the device down */ set_bit(HCLGEVF_STATE_DOWN, &hdev->state); } @@ -2731,19 +2878,6 @@ static int hclgevf_clear_vport_list(struct hclgevf_dev *hdev) return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); }
-static int hclgevf_restore_hw_table(struct hclgevf_dev *hdev) -{ - struct hclge_vf_to_pf_msg send_msg; - - if (hdev->reset_type == HNAE3_VF_RESET || - hdev->reset_type == HNAE3_FLR_RESET) { - hclgevf_build_send_msg(&send_msg, HCLGE_MBX_HANDLE_VF_TBL, - HCLGE_MBX_HW_TBL_RESTORE); - return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); - } - return 0; -} - static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) { struct pci_dev *pdev = hdev->pdev; @@ -2780,14 +2914,6 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) return ret; }
- /* VF_RESET & VF_FLR_RESET need to request to restore hw table */ - ret = hclgevf_restore_hw_table(hdev); - if (ret) { - dev_err(&hdev->pdev->dev, - "failed(%d) to restore hw table\n", ret); - return ret; - } - dev_info(&hdev->pdev->dev, "Reset done\n");
return 0; @@ -2911,6 +3037,7 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev)
hclgevf_pci_uninit(hdev); hclgevf_cmd_uninit(hdev); + hclgevf_uninit_mac_list(hdev); }
static int hclgevf_init_ae_dev(struct hnae3_ae_dev *ae_dev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 92bbe15..cb62472 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -236,6 +236,30 @@ struct hclgevf_rst_stats { u32 rst_fail_cnt; /* the number of VF reset fail */ };
+enum HCLGEVF_MAC_ADDR_TYPE { + HCLGEVF_MAC_ADDR_UC, + HCLGEVF_MAC_ADDR_MC +}; + +enum HCLGEVF_MAC_ADDR_STATE { + HCLGEVF_MAC_TO_ADD, + HCLGEVF_MAC_TO_DEL, + HCLGEVF_MAC_REQ_SUC, /* send request mbx success */ + HCLGEVF_MAC_REQ_FAIL, /* send request mbx fail */ +}; + +struct hclgevf_mac_addr_node { + struct list_head node; + enum HCLGEVF_MAC_ADDR_STATE state; + u8 mac_addr[ETH_ALEN]; +}; + +struct hclgevf_mac_table_cfg { + spinlock_t mac_list_lock; /* protect mac address need to add/detele */ + struct list_head uc_mac_list; + struct list_head mc_mac_list; +}; + struct hclgevf_dev { struct pci_dev *pdev; struct hnae3_ae_dev *ae_dev; @@ -283,6 +307,8 @@ struct hclgevf_dev {
unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)];
+ struct hclgevf_mac_table_cfg mac_table; + bool mbx_event_pending; struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */ struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */