struct net_device *netdev = handle->kinfo.netdev;
        struct hclge_mac *mac = &hdev->hw.mac;
        u8 mac_mask[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+       struct hclge_vport *vport;
        int mtu;
        int ret;
+       int i;
 
        ret = hclge_cfg_mac_speed_dup(hdev, hdev->hw.mac.speed, HCLGE_MAC_FULL);
        if (ret) {
        mac->link = 0;
 
        /* Initialize the MTA table work mode */
-       hdev->accept_mta_mc     = true;
        hdev->enable_mta        = true;
        hdev->mta_mac_sel_type  = HCLGE_MAC_ADDR_47_36;
 
                return ret;
        }
 
-       ret = hclge_cfg_func_mta_filter(hdev, 0, hdev->accept_mta_mc);
-       if (ret) {
-               dev_err(&hdev->pdev->dev,
-                       "set mta filter mode fail ret=%d\n", ret);
-               return ret;
+       for (i = 0; i < hdev->num_alloc_vport; i++) {
+               vport = &hdev->vport[i];
+               vport->accept_mta_mc = false;
+
+               memset(vport->mta_shadow, 0, sizeof(vport->mta_shadow));
+               ret = hclge_cfg_func_mta_filter(hdev, vport->vport_id, false);
+               if (ret) {
+                       dev_err(&hdev->pdev->dev,
+                               "set mta filter mode fail ret=%d\n", ret);
+                       return ret;
+               }
        }
 
        ret = hclge_set_default_mac_vlan_mask(hdev, true, mac_mask);
                return ret;
        }
 
+       if (enable)
+               set_bit(idx, vport->mta_shadow);
+       else
+               clear_bit(idx, vport->mta_shadow);
+
        return 0;
 }
 
+static int hclge_update_mta_status(struct hnae3_handle *handle)
+{
+       unsigned long mta_status[BITS_TO_LONGS(HCLGE_MTA_TBL_SIZE)];
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct net_device *netdev = handle->kinfo.netdev;
+       struct netdev_hw_addr *ha;
+       u16 tbl_idx;
+
+       memset(mta_status, 0, sizeof(mta_status));
+
+       /* update mta_status from mc addr list */
+       netdev_for_each_mc_addr(ha, netdev) {
+               tbl_idx = hclge_get_mac_addr_to_mta_index(vport, ha->addr);
+               set_bit(tbl_idx, mta_status);
+       }
+
+       return hclge_update_mta_status_common(vport, mta_status,
+                                       0, HCLGE_MTA_TBL_SIZE, true);
+}
+
+int hclge_update_mta_status_common(struct hclge_vport *vport,
+                                  unsigned long *status,
+                                  u16 idx,
+                                  u16 count,
+                                  bool update_filter)
+{
+       struct hclge_dev *hdev = vport->back;
+       u16 update_max = idx + count;
+       u16 check_max;
+       int ret = 0;
+       bool used;
+       u16 i;
+
+       /* setup mta check range */
+       if (update_filter) {
+               i = 0;
+               check_max = HCLGE_MTA_TBL_SIZE;
+       } else {
+               i = idx;
+               check_max = update_max;
+       }
+
+       used = false;
+       /* check and update all mta item */
+       for (; i < check_max; i++) {
+               /* ignore unused item */
+               if (!test_bit(i, vport->mta_shadow))
+                       continue;
+
+               /* if i in update range then update it */
+               if (i >= idx && i < update_max)
+                       if (!test_bit(i - idx, status))
+                               hclge_set_mta_table_item(vport, i, false);
+
+               if (!used && test_bit(i, vport->mta_shadow))
+                       used = true;
+       }
+
+       /* no longer use mta, disable it */
+       if (vport->accept_mta_mc && update_filter && !used) {
+               ret = hclge_cfg_func_mta_filter(hdev,
+                                               vport->vport_id,
+                                               false);
+               if (ret)
+                       dev_err(&hdev->pdev->dev,
+                               "disable func mta filter fail ret=%d\n",
+                               ret);
+               else
+                       vport->accept_mta_mc = false;
+       }
+
+       return ret;
+}
+
 static int hclge_remove_mac_vlan_tbl(struct hclge_vport *vport,
                                     struct hclge_mac_vlan_tbl_entry_cmd *req)
 {
                status = hclge_add_mac_vlan_tbl(vport, &req, desc);
        }
 
-       /* Set MTA table for this MAC address */
-       tbl_idx = hclge_get_mac_addr_to_mta_index(vport, addr);
-       status = hclge_set_mta_table_item(vport, tbl_idx, true);
+       /* If mc mac vlan table is full, use MTA table */
+       if (status == -ENOSPC) {
+               if (!vport->accept_mta_mc) {
+                       status = hclge_cfg_func_mta_filter(hdev,
+                                                          vport->vport_id,
+                                                          true);
+                       if (status) {
+                               dev_err(&hdev->pdev->dev,
+                                       "set mta filter mode fail ret=%d\n",
+                                       status);
+                               return status;
+                       }
+                       vport->accept_mta_mc = true;
+               }
+
+               /* Set MTA table for this MAC address */
+               tbl_idx = hclge_get_mac_addr_to_mta_index(vport, addr);
+               status = hclge_set_mta_table_item(vport, tbl_idx, true);
+       }
 
        return status;
 }
        struct hclge_mac_vlan_tbl_entry_cmd req;
        enum hclge_cmd_status status;
        struct hclge_desc desc[3];
-       u16 tbl_idx;
 
        /* mac addr check */
        if (!is_multicast_ether_addr(addr)) {
                        status = hclge_add_mac_vlan_tbl(vport, &req, desc);
 
        } else {
-               /* This mac addr do not exist, can't delete it */
-               dev_err(&hdev->pdev->dev,
-                       "Rm multicast mac addr failed, ret = %d.\n",
-                       status);
-               return -EIO;
+               /* 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.
+                */
+               status = 0;
        }
 
-       /* Set MTB table for this MAC address */
-       tbl_idx = hclge_get_mac_addr_to_mta_index(vport, addr);
-       status = hclge_set_mta_table_item(vport, tbl_idx, false);
-
        return status;
 }
 
        .rm_uc_addr = hclge_rm_uc_addr,
        .add_mc_addr = hclge_add_mc_addr,
        .rm_mc_addr = hclge_rm_mc_addr,
+       .update_mta_status = hclge_update_mta_status,
        .set_autoneg = hclge_set_autoneg,
        .get_autoneg = hclge_get_autoneg,
        .get_pauseparam = hclge_get_pauseparam,