return ret;
 }
 
+/**
+ * hns3_clean_vf_config
+ * @pdev: pointer to a pci_dev structure
+ * @num_vfs: number of VFs allocated
+ *
+ * Clean residual vf config after disable sriov
+ **/
+static void hns3_clean_vf_config(struct pci_dev *pdev, int num_vfs)
+{
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+
+       if (ae_dev->ops->clean_vf_config)
+               ae_dev->ops->clean_vf_config(ae_dev, num_vfs);
+}
+
 /* hns3_remove - Device removal routine
  * @pdev: PCI device information struct
  */
                else
                        return num_vfs;
        } else if (!pci_vfs_assigned(pdev)) {
+               int num_vfs_pre = pci_num_vf(pdev);
+
                pci_disable_sriov(pdev);
+               hns3_clean_vf_config(pdev, num_vfs_pre);
        } else {
                dev_warn(&pdev->dev,
                         "Unable to free VFs because some are assigned to VMs.\n");
 
        return 0;
 }
 
+/* After disable sriov, VF still has some config and info need clean,
+ * which configed by PF.
+ */
+static void hclge_clear_vport_vf_info(struct hclge_vport *vport, int vfid)
+{
+       struct hclge_dev *hdev = vport->back;
+       struct hclge_vlan_info vlan_info;
+       int ret;
+
+       /* after disable sriov, clean VF rate configured by PF */
+       ret = hclge_tm_qs_shaper_cfg(vport, 0);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "failed to clean vf%d rate config, ret = %d\n",
+                       vfid, ret);
+
+       vlan_info.vlan_tag = 0;
+       vlan_info.qos = 0;
+       vlan_info.vlan_proto = ETH_P_8021Q;
+       ret = hclge_update_port_base_vlan_cfg(vport,
+                                             HNAE3_PORT_BASE_VLAN_DISABLE,
+                                             &vlan_info);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "failed to clean vf%d port base vlan, ret = %d\n",
+                       vfid, ret);
+
+       ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, false);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "failed to clean vf%d spoof config, ret = %d\n",
+                       vfid, ret);
+
+       memset(&vport->vf_info, 0, sizeof(vport->vf_info));
+}
+
+static void hclge_clean_vport_config(struct hnae3_ae_dev *ae_dev, int num_vfs)
+{
+       struct hclge_dev *hdev = ae_dev->priv;
+       struct hclge_vport *vport;
+       int i;
+
+       for (i = 0; i < num_vfs; i++) {
+               vport = &hdev->vport[i + HCLGE_VF_VPORT_START_NUM];
+
+               hclge_clear_vport_vf_info(vport, i);
+       }
+}
+
 static const struct hnae3_ae_ops hclge_ops = {
        .init_ae_dev = hclge_init_ae_dev,
        .uninit_ae_dev = hclge_uninit_ae_dev,
        .get_rx_hwts = hclge_ptp_get_rx_hwts,
        .get_ts_info = hclge_ptp_get_ts_info,
        .get_link_diagnosis_info = hclge_get_link_diagnosis_info,
+       .clean_vf_config = hclge_clean_vport_config,
 };
 
 static struct hnae3_ae_algo ae_algo = {