From: Guojia Liao liaoguojia@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
Currently, the HNS3 would remove all vlan/uc mac/mc mac table entry no matter what kind of reset had triggered, and restore them after reset done.
Based on the analysis of different kind of reset, the entry table removing and restoring will take some change as below: 1.IMP/GLOBAL reseet HW would clear all hw table when resetting. -PF need to restore the table entry in sw list after reset done. -VF need to send a message to PF, request to restore table entry. 2.PF function reset/PF FLR reset/VF function reset In this case, reset as a status change and the table entry had no change. -So PF and VF needn't to take any operation on the table entry. 3.VF FLR reset PF would get a message when VF was in FLR status. Due to PF didn't know what kink of VF FLR status(init/uninit/reset). so PF would clear VF table entry and reclaim resources of table entry. -If VF init, PF would clear all the sw list avoid the sw list leftover. -If VF uninit, PF do nothing after clear VF table entry. -If VF reset, VF would send a message to PF, and request to restore the table entry in sw list.
Signed-off-by: Guojia Liao liaoguojia@huawei.com 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 | 6 + drivers/net/ethernet/hisilicon/hns3/hnae3.h | 3 - drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 80 ------- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 236 ++++++++++++++++----- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 3 +- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 58 +++-- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 47 +++- 7 files changed, 279 insertions(+), 154 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index e18e301..7b85b8d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -45,6 +45,7 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_GET_MEDIA_TYPE, /* (VF -> PF) get media type */ HCLGE_MBX_PUSH_PROMISC_INFO, /* (PF -> VF) push vf promisc info */ HCLGE_MBX_VF_UNINIT, /* (VF -> PF) vf is unintializing */ + HCLGE_MBX_HANDLE_VF_TBL, /* (VF -> PF) store/clear hw table */
HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ @@ -70,6 +71,11 @@ enum hclge_mbx_vlan_cfg_subcode { HCLGE_MBX_GET_PORT_BASE_VLAN_STATE, /* get port based vlan state */ };
+enum hclge_mbx_tbl_cfg_subcode { + HCLGE_MBX_HW_TBL_RESTORE, + HCLGE_MBX_VPORT_LIST_CLEAR, +}; + #define HCLGE_MBX_MAX_MSG_SIZE 14 #define HCLGE_MBX_MAX_RESP_DATA_SIZE 8 #define HCLGE_MBX_MAX_RING_CHAIN_PARAM_NUM 4 diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 126923f..261a2c1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -357,8 +357,6 @@ struct hnae3_ae_dev { * Set vlan filter config of Ports * set_vf_vlan_filter() * Set vlan filter config of vf - * restore_vlan_table() - * Restore vlan filter entries after reset * enable_hw_strip_rxvtag() * Enable/disable hardware strip vlan tag of packets received * set_gro_en @@ -536,7 +534,6 @@ struct hnae3_ae_ops { void (*set_timer_task)(struct hnae3_handle *handle, bool enable); int (*mac_connect_phy)(struct hnae3_handle *handle); void (*mac_disconnect_phy)(struct hnae3_handle *handle); - void (*restore_vlan_table)(struct hnae3_handle *handle); bool (*reset_done)(struct hnae3_handle *handle, bool done); void (*handle_imp_error)(struct hnae3_handle *handle); #ifdef CONFIG_HNS3_TEST diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 2e148de..3c306a8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3981,17 +3981,6 @@ static void hns3_uninit_phy(struct net_device *netdev) h->ae_algo->ops->mac_disconnect_phy(h); }
-static int hns3_restore_fd_rules(struct net_device *netdev) -{ - struct hnae3_handle *h = hns3_get_handle(netdev); - int ret = 0; - - if (h->ae_algo->ops->restore_fd_rules) - ret = h->ae_algo->ops->restore_fd_rules(h); - - return ret; -} - static void hns3_del_all_fd_rules(struct net_device *netdev, bool clear_list) { struct hnae3_handle *h = hns3_get_handle(netdev); @@ -4237,35 +4226,6 @@ static int hns3_client_setup_tc(struct hnae3_handle *handle, u8 tc) return hns3_nic_set_real_num_queue(ndev); }
-static int hns3_recover_hw_addr(struct net_device *ndev) -{ - struct netdev_hw_addr_list *list; - struct netdev_hw_addr *ha, *tmp; - int ret = 0; - - netif_addr_lock_bh(ndev); - /* go through and sync uc_addr entries to the device */ - list = &ndev->uc; - list_for_each_entry_safe(ha, tmp, &list->list, list) { - ret = hns3_nic_uc_sync(ndev, ha->addr); - if (ret) - goto out; - } - - /* go through and sync mc_addr entries to the device */ - list = &ndev->mc; - list_for_each_entry_safe(ha, tmp, &list->list, list) - if (ha->refcount > 1) { - ret = hns3_nic_mc_sync(ndev, ha->addr); - if (ret) - goto out; - } - -out: - netif_addr_unlock_bh(ndev); - return ret; -} - static void hns3_remove_hw_addr(struct net_device *netdev) { struct netdev_hw_addr_list *list; @@ -4446,7 +4406,6 @@ static void hns3_restore_coal(struct hns3_nic_priv *priv)
static int hns3_reset_notify_down_enet(struct hnae3_handle *handle) { - struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct net_device *ndev = kinfo->netdev; struct hns3_nic_priv *priv = netdev_priv(ndev); @@ -4454,15 +4413,6 @@ static int hns3_reset_notify_down_enet(struct hnae3_handle *handle) if (test_and_set_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) return 0;
- /* it is cumbersome for hardware to pick-and-choose entries for deletion - * from table space. Hence, for function reset software intervention is - * required to delete the entries - */ - if (hns3_dev_ongoing_func_reset(ae_dev)) { - hns3_remove_hw_addr(ndev); - hns3_del_all_fd_rules(ndev, false); - } - if (!netif_running(ndev)) return 0;
@@ -4554,33 +4504,6 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle) return ret; }
-static int hns3_reset_notify_restore_enet(struct hnae3_handle *handle) -{ - struct net_device *netdev = handle->kinfo.netdev; - bool vlan_filter_enable; - int ret; - - ret = hns3_init_mac_addr(netdev); - if (ret) - return ret; - - ret = hns3_recover_hw_addr(netdev); - if (ret) - return ret; - - ret = hns3_update_promisc_mode(netdev, handle->netdev_flags); - if (ret) - return ret; - - vlan_filter_enable = netdev->flags & IFF_PROMISC ? false : true; - hns3_enable_vlan_filter(netdev, vlan_filter_enable); - - if (handle->ae_algo->ops->restore_vlan_table) - handle->ae_algo->ops->restore_vlan_table(handle); - - return hns3_restore_fd_rules(netdev); -} - static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle) { struct net_device *netdev = handle->kinfo.netdev; @@ -4630,9 +4553,6 @@ static int hns3_reset_notify(struct hnae3_handle *handle, case HNAE3_UNINIT_CLIENT: ret = hns3_reset_notify_uninit_enet(handle); break; - case HNAE3_RESTORE_CLIENT: - ret = hns3_reset_notify_restore_enet(handle); - break; default: break; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 3993d4d..c75e24e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -69,6 +69,7 @@ static void hclge_reset_vf_rate(struct hclge_dev *hdev);
static void hclge_sync_mac_table(struct hclge_dev *hdev); +static int hclge_restore_hw_table(struct hclge_dev *hdev);
struct hnae3_ae_algo ae_algo;
@@ -3741,7 +3742,11 @@ static int hclge_reset_stack(struct hclge_dev *hdev) if (ret) return ret;
- return hclge_notify_client(hdev, HNAE3_RESTORE_CLIENT); + /* imp rest and global reset need to restore PF tbl */ + if (hdev->reset_type == HNAE3_IMP_RESET || + hdev->reset_type == HNAE3_GLOBAL_RESET) + return hclge_restore_hw_table(hdev); + return 0; }
static void hclge_reset(struct hclge_dev *hdev) @@ -7555,6 +7560,8 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport, ret = hclge_remove_mac_vlan_tbl(vport, &req); if (!ret) hclge_update_umv_space(vport, true); + else if (ret == -ENOENT) + ret = 0;
return ret; } @@ -7654,13 +7661,7 @@ int hclge_rm_mc_addr_common(struct hclge_vport *vport, /* Not all the vfid is zero, update the vfid */ status = hclge_add_mac_vlan_tbl(vport, &req, desc);
- } else { - /* Maybe this mac address is in mta table, but it cannot be - * deleted here because an entry of mta represents an address - * range rather than a specific address. the delete action to - * all entries will take effect in update_mta_status called by - * hns3_nic_set_rx_mode. - */ + } else if (status == -ENOENT) { status = 0; }
@@ -7874,7 +7875,7 @@ void hclge_add_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, return;
mac_cfg->hd_tbl_status = true; - memcpy(mac_cfg->mac_addr, mac_addr, ETH_ALEN); + ether_addr_copy(mac_cfg->mac_addr, mac_addr);
list = (mac_type == HCLGE_MAC_ADDR_UC) ? &vport->uc_mac_list : &vport->mc_mac_list; @@ -7883,27 +7884,16 @@ void hclge_add_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, }
void hclge_rm_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, - bool is_write_tbl, enum HCLGE_MAC_ADDR_TYPE mac_type) { struct hclge_vport_mac_addr_cfg *mac_cfg, *tmp; struct list_head *list; - bool uc_flag, mc_flag;
list = (mac_type == HCLGE_MAC_ADDR_UC) ? &vport->uc_mac_list : &vport->mc_mac_list;
- uc_flag = is_write_tbl && mac_type == HCLGE_MAC_ADDR_UC; - mc_flag = is_write_tbl && mac_type == HCLGE_MAC_ADDR_MC; - list_for_each_entry_safe(mac_cfg, tmp, list, node) { if (ether_addr_equal(mac_cfg->mac_addr, mac_addr)) { - if (uc_flag && mac_cfg->hd_tbl_status) - hclge_rm_uc_addr_common(vport, mac_addr); - - if (mc_flag && mac_cfg->hd_tbl_status) - hclge_rm_mc_addr_common(vport, mac_addr); - list_del(&mac_cfg->node); kfree(mac_cfg); break; @@ -8149,12 +8139,54 @@ static void hclge_get_mac_addr(struct hnae3_handle *handle, u8 *p) ether_addr_copy(p, hdev->hw.mac.mac_addr); }
+/* 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) +{ + struct hclge_vport_mac_addr_cfg *mac_node, *new_node; + + mac_node = hclge_find_mac_node(list, old_addr); + if (!mac_node) { + new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); + if (!new_node) + return; + new_node->state = HCLGE_MAC_ACTIVE; + ether_addr_copy(new_node->mac_addr, new_addr); + list_add_tail(&new_node->node, list); + return; + } + + mac_node->state = HCLGE_MAC_ACTIVE; + ether_addr_copy(mac_node->mac_addr, new_addr); + if (keep_old) { + new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); + if (!new_node) + return; + new_node->state = HCLGE_MAC_TO_DEL; + ether_addr_copy(new_node->mac_addr, old_addr); + list_add_tail(&new_node->node, list); + } +} + +static 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; + + mac_node = hclge_find_mac_node(list, addr); + if (mac_node) + mac_node->state = state; +} + static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, bool is_first) { const unsigned char *new_addr = (const unsigned char *)p; struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + bool old_mac_removed = true; int ret;
/* mac addr check */ @@ -8168,9 +8200,11 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, }
if ((!is_first || is_kdump_kernel()) && - hclge_rm_uc_addr_common(vport, hdev->hw.mac.mac_addr)) + hclge_rm_uc_addr_common(vport, hdev->hw.mac.mac_addr)) { dev_warn(&hdev->pdev->dev, "remove old uc mac address fail.\n"); + old_mac_removed = false; + }
ret = hclge_add_uc_addr_common(vport, new_addr); if (ret) { @@ -8178,14 +8212,38 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, "add uc mac address fail, ret =%d.\n", ret);
- if (!is_first && - hclge_add_uc_addr_common(vport, hdev->hw.mac.mac_addr)) - dev_err(&hdev->pdev->dev, - "restore uc mac address fail.\n"); + if (!is_first) { + ret = hclge_add_uc_addr_common(vport, + hdev->hw.mac.mac_addr); + if (ret) { + old_mac_removed = true; + dev_err(&hdev->pdev->dev, + "restore uc mac address fail.\n"); + } else { + old_mac_removed = false; + } + } + + /* if old dev addr restore failed, add to the uc mac list, + * and try to restore it in service task + */ + if (old_mac_removed) + hclge_modify_mac_node_state(&vport->uc_mac_list, + hdev->hw.mac.mac_addr, + HCLGE_MAC_TO_ADD);
return -EIO; }
+ /* new dev addr add success, replace the old dev addr in uc mac list. + * if old dev addr delete fail, keep it in the mac list, and try to del + * it in service task. + */ + spin_lock_bh(&vport->mac_list_lock); + hclge_replace_mac_node(&vport->uc_mac_list, hdev->hw.mac.mac_addr, + new_addr, !old_mac_removed); + spin_unlock_bh(&vport->mac_list_lock); + ret = hclge_pause_addr_cfg(hdev, new_addr); if (ret) { dev_err(&hdev->pdev->dev, @@ -8420,8 +8478,8 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto, if (is_kill && !test_and_clear_bit(vport_id, hdev->vlan_table[vlan_id])) { dev_err(&hdev->pdev->dev, - "Delete port vlan failed, vport %u is not in vlan %u\n", - vport_id, vlan_id); + "Delete port vlan failed, vlan %u is not in vport %u\n", + vlan_id, vport_id); return -EINVAL; }
@@ -8670,6 +8728,9 @@ static void hclge_add_vport_vlan_table(struct hclge_vport *vport, u16 vlan_id, { struct hclge_vport_vlan_cfg *vlan;
+ if (!list_empty(&vport->vlan_list) && !vlan_id) + return; + vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); if (!vlan) return; @@ -8732,6 +8793,9 @@ void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_list) struct hclge_dev *hdev = vport->back;
list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { + if (!vlan->vlan_id) + continue; + if (vlan->hd_tbl_status) hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), @@ -8763,42 +8827,101 @@ void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev) } }
-void hclge_restore_vlan_table(struct hnae3_handle *handle) +void hclge_restore_vport_vlan_table(struct hclge_vport *vport) { - struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev = vport->back; u16 vlan_proto; u16 state, vlan_id; - int i; + int ret;
- for (i = 0; i < hdev->num_alloc_vport; i++) { - vport = &hdev->vport[i]; - vlan_proto = vport->port_base_vlan_cfg.vlan_info.vlan_proto; - vlan_id = vport->port_base_vlan_cfg.vlan_info.vlan_tag; - state = vport->port_base_vlan_cfg.state; + vlan_proto = vport->port_base_vlan_cfg.vlan_info.vlan_proto; + vlan_id = vport->port_base_vlan_cfg.vlan_info.vlan_tag; + state = vport->port_base_vlan_cfg.state;
- if (state != HNAE3_PORT_BASE_VLAN_DISABLE) { - hclge_set_vlan_filter_hw(hdev, htons(vlan_proto), - vport->vport_id, vlan_id, - false); - continue; - } + if (state != HNAE3_PORT_BASE_VLAN_DISABLE) { + clear_bit(vport->vport_id, hdev->vlan_table[vlan_id]); + hclge_set_vlan_filter_hw(hdev, htons(vlan_proto), + vport->vport_id, vlan_id, + false); + return; + }
- list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { - int ret; + list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { + ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), + vport->vport_id, + vlan->vlan_id, false); + if (ret) + break; + vlan->hd_tbl_status = true; + } +}
- if (!vlan->hd_tbl_status) - continue; - ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), - vport->vport_id, - vlan->vlan_id, false); - if (ret) - break; +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, + * the mac addresses with state TO_DEL or DEL_FAIL are unnecessary to + * be restored after reset, so just remove these mac nodes from mac_list. + */ +static void hclge_mac_node_convert_for_reset(struct list_head *list) +{ + struct hclge_vport_mac_addr_cfg *mac_node, *tmp; + + list_for_each_entry_safe(mac_node, tmp, list, node) { + if (mac_node->state == HCLGE_MAC_ACTIVE) { + mac_node->state = HCLGE_MAC_TO_ADD; + } else if (mac_node->state == HCLGE_MAC_TO_DEL || + mac_node->state == HCLGE_MAC_DEL_FAIL) { + list_del(&mac_node->node); + kfree(mac_node); } } }
+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 + * we can add/delete these mac addr outside the spin lock + */ + 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); + + spin_unlock_bh(&vport->mac_list_lock); +} + +static int hclge_restore_hw_table(struct hclge_dev *hdev) +{ + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + + hclge_restore_pf_mac_table(vport); + hclge_restore_vport_vlan_table(vport); + + return hclge_restore_fd_entries(handle); +} + int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); @@ -8992,7 +9115,7 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, }
if (!ret) { - if (is_kill) + if (is_kill && vlan_id != 0) hclge_rm_vport_vlan_table(vport, vlan_id, false); else hclge_add_vport_vlan_table(vport, vlan_id, @@ -10168,8 +10291,14 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) set_bit(HCLGE_STATE_DOWN, &hdev->state);
hclge_stats_clear(hdev); - memset(hdev->vlan_table, 0, sizeof(hdev->vlan_table)); - memset(hdev->vf_vlan_full, 0, sizeof(hdev->vf_vlan_full)); + /* NOTE: pf reset needn't to clear or restore pf and vf table entry. + * so here should not clean table in memory. + */ + if (hdev->reset_type == HNAE3_IMP_RESET || + hdev->reset_type == HNAE3_GLOBAL_RESET) { + memset(hdev->vlan_table, 0, sizeof(hdev->vlan_table)); + memset(hdev->vf_vlan_full, 0, sizeof(hdev->vf_vlan_full)); + }
ret = hclge_cmd_init(hdev); if (ret) { @@ -11082,7 +11211,6 @@ struct hnae3_ae_ops hclge_ops = { .set_timer_task = hclge_set_timer_task, .mac_connect_phy = hclge_mac_connect_phy, .mac_disconnect_phy = hclge_mac_disconnect_phy, - .restore_vlan_table = hclge_restore_vlan_table, .reset_done = hclge_reset_done, .handle_imp_error = hclge_handle_imp_error, .get_vf_config = hclge_get_vf_config, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 3508e61..cfb9ba2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -1002,11 +1002,12 @@ int hclge_notify_client(struct hclge_dev *hdev, 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, - bool is_write_tbl, enum HCLGE_MAC_ADDR_TYPE mac_type); 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_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 d979f82..fc746ea 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -279,15 +279,22 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, !ether_addr_equal(mac_addr, vport->mac)) return -EPERM;
- 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); + 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); } else { - hclge_rm_vport_mac_table(vport, old_addr, - false, HCLGE_MAC_ADDR_UC); - hclge_add_vport_mac_table(vport, mac_addr, - HCLGE_MAC_ADDR_UC); + 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); + } } } else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_ADD) { status = hclge_add_uc_addr_common(vport, mac_addr); @@ -299,7 +306,7 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, status = hclge_rm_uc_addr_common(vport, mac_addr); if (!status) { hclge_rm_vport_mac_table(vport, mac_addr, - false, HCLGE_MAC_ADDR_UC); + HCLGE_MAC_ADDR_UC); } } else { dev_err(&hdev->pdev->dev, @@ -326,7 +333,7 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport, status = hclge_rm_mc_addr_common(vport, mac_addr); if (!status) hclge_rm_vport_mac_table(vport, mac_addr, - false, HCLGE_MAC_ADDR_MC); + HCLGE_MAC_ADDR_MC); } else { dev_err(&hdev->pdev->dev, "failed to set mcast mac addr, unknown subcode %u\n", @@ -645,6 +652,26 @@ static void hclge_handle_ncsi_error(struct hclge_dev *hdev) ae_dev->ops->reset_event(hdev->pdev, NULL); }
+static void hclge_handle_vf_tbl(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req) +{ + struct hclge_dev *hdev = vport->back; + 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) { + 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); + } else { + dev_warn(&hdev->pdev->dev, "Invalid cmd(%u)\n", + msg_cmd->subcode); + } +} + void hclge_mbx_handler(struct hclge_dev *hdev) { struct hclge_cmq_ring *crq = &hdev->hw.cmq.crq; @@ -652,6 +679,7 @@ void hclge_mbx_handler(struct hclge_dev *hdev) struct hclge_mbx_vf_to_pf_cmd *req; struct hclge_vport *vport; struct hclge_desc *desc; + bool is_del = false; unsigned int flag; int ret = 0;
@@ -767,11 +795,12 @@ void hclge_mbx_handler(struct hclge_dev *hdev) break; case HCLGE_MBX_GET_VF_FLR_STATUS: case HCLGE_MBX_VF_UNINIT: - hclge_rm_vport_all_mac_table(vport, true, + is_del = req->msg.code == HCLGE_MBX_VF_UNINIT; + hclge_rm_vport_all_mac_table(vport, is_del, HCLGE_MAC_ADDR_UC); - hclge_rm_vport_all_mac_table(vport, true, + hclge_rm_vport_all_mac_table(vport, is_del, HCLGE_MAC_ADDR_MC); - hclge_rm_vport_all_vlan_table(vport, true); + hclge_rm_vport_all_vlan_table(vport, is_del); break; case HCLGE_MBX_GET_MEDIA_TYPE: hclge_get_vf_media_type(vport, &resp_msg); @@ -785,6 +814,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev) case HCLGE_MBX_NCSI_ERROR: hclge_handle_ncsi_error(hdev); break; + case HCLGE_MBX_HANDLE_VF_TBL: + hclge_handle_vf_tbl(vport, req); + break; default: dev_err(&hdev->pdev->dev, "un-supported mailbox message, code = %u\n", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index aad348a..57ac897 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -15,6 +15,7 @@ #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; @@ -1253,10 +1254,12 @@ static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p, }
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_UNICAST, 0); - send_msg.subcode = is_first ? HCLGE_MBX_MAC_VLAN_UC_ADD : - HCLGE_MBX_MAC_VLAN_UC_MODIFY; + send_msg.subcode = HCLGE_MBX_MAC_VLAN_UC_MODIFY; ether_addr_copy(send_msg.data, new_mac_addr); - ether_addr_copy(&send_msg.data[ETH_ALEN], old_mac_addr); + if (is_first) + eth_zero_addr(&send_msg.data[ETH_ALEN]); + else + ether_addr_copy(&send_msg.data[ETH_ALEN], old_mac_addr); status = hclgevf_send_mbx_msg(hdev, &send_msg, true, NULL, 0); if (!status) ether_addr_copy(hdev->hw.mac.mac_addr, new_mac_addr); @@ -2719,6 +2722,28 @@ static int hclgevf_pci_reset(struct hclgevf_dev *hdev) return ret; }
+static int hclgevf_clear_vport_list(struct hclgevf_dev *hdev) +{ + struct hclge_vf_to_pf_msg send_msg; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_HANDLE_VF_TBL, + HCLGE_MBX_VPORT_LIST_CLEAR); + 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; @@ -2755,6 +2780,14 @@ 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; @@ -2826,6 +2859,14 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) goto err_config; }
+ /* ensure vf tbl list as empty before init*/ + ret = hclgevf_clear_vport_list(hdev); + if (ret) { + dev_err(&pdev->dev, + "failed(%d) to clear tbl list configuration\n", ret); + goto err_config; + } + ret = hclgevf_init_vlan_config(hdev); if (ret) { dev_err(&hdev->pdev->dev,