net: hns3: Clear mac vlan table entries when unload driver or function reset
authorJian Shen <shenjian15@huawei.com>
Fri, 5 Oct 2018 17:03:25 +0000 (18:03 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 5 Oct 2018 19:01:54 +0000 (12:01 -0700)
In original codes, the mac vlan table entries are not cleared when
unload hns3 driver. The dirty mac vlan table entries will make the
result of looking up mac vlan table being unexpected.

When doing core reset or global reset, the firmware will clear all
the tables for driver, and driver shouldn't send any commands to
firmware during reset. But when doing function reset, the driver
needs to clear the tables itself.

This patch clears the mac vlan table entries for each client when
unload driver or reset.

Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c

index c2692563a4d9ff66433019752e1a450215ecd93d..d8b8ccffb4b859a90bd5582b47f00fd8d43576c2 100644 (file)
@@ -21,6 +21,7 @@
 
 static void hns3_clear_all_ring(struct hnae3_handle *h);
 static void hns3_force_clear_all_rx_ring(struct hnae3_handle *h);
+static void hns3_remove_hw_addr(struct net_device *netdev);
 
 static const char hns3_driver_name[] = "hns3";
 const char hns3_driver_version[] = VERMAGIC_STRING;
@@ -3155,15 +3156,6 @@ static void hns3_init_mac_addr(struct net_device *netdev, bool init)
 
 }
 
-static void hns3_uninit_mac_addr(struct net_device *netdev)
-{
-       struct hns3_nic_priv *priv = netdev_priv(netdev);
-       struct hnae3_handle *h = priv->ae_handle;
-
-       if (h->ae_algo->ops->rm_uc_addr)
-               h->ae_algo->ops->rm_uc_addr(h, netdev->dev_addr);
-}
-
 static int hns3_restore_fd_rules(struct net_device *netdev)
 {
        struct hnae3_handle *h = hns3_get_handle(netdev);
@@ -3296,6 +3288,8 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
        struct hns3_nic_priv *priv = netdev_priv(netdev);
        int ret;
 
+       hns3_remove_hw_addr(netdev);
+
        if (netdev->reg_state != NETREG_UNINITIALIZED)
                unregister_netdev(netdev);
 
@@ -3319,8 +3313,6 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
 
        priv->ring_data = NULL;
 
-       hns3_uninit_mac_addr(netdev);
-
        free_netdev(netdev);
 }
 
@@ -3392,6 +3384,25 @@ static void hns3_recover_hw_addr(struct net_device *ndev)
                hns3_nic_mc_sync(ndev, ha->addr);
 }
 
+static void hns3_remove_hw_addr(struct net_device *netdev)
+{
+       struct netdev_hw_addr_list *list;
+       struct netdev_hw_addr *ha, *tmp;
+
+       hns3_nic_uc_unsync(netdev, netdev->dev_addr);
+
+       /* go through and unsync uc_addr entries to the device */
+       list = &netdev->uc;
+       list_for_each_entry_safe(ha, tmp, &list->list, list)
+               hns3_nic_uc_unsync(netdev, ha->addr);
+
+       /* go through and unsync mc_addr entries to the device */
+       list = &netdev->mc;
+       list_for_each_entry_safe(ha, tmp, &list->list, list)
+               if (ha->refcount > 1)
+                       hns3_nic_mc_unsync(netdev, ha->addr);
+}
+
 static void hns3_clear_tx_ring(struct hns3_enet_ring *ring)
 {
        while (ring->next_to_clean != ring->next_to_use) {
@@ -3637,14 +3648,14 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
        if (ret)
                netdev_err(netdev, "uninit ring error\n");
 
-       hns3_uninit_mac_addr(netdev);
-
-       /* it is cumbersome for hardware to pick-and-choose rules for deletion
-        * from TCAM. Hence, for function reset software intervention is
-        * required to delete the rules
+       /* 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))
+       if (hns3_dev_ongoing_func_reset(ae_dev)) {
+               hns3_remove_hw_addr(netdev);
                hns3_del_all_fd_rules(netdev, false);
+       }
 
        return ret;
 }