net: hns3: fix for vlan table lost problem when resetting
authorYunsheng Lin <linyunsheng@huawei.com>
Wed, 21 Mar 2018 07:49:22 +0000 (15:49 +0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 22 Mar 2018 17:12:01 +0000 (13:12 -0400)
The vlan table in hardware is clear after PF/Core/IMP/Global
reset, which will cause vlan tagged packets not being received
problem.

This patch fixes it by restoring the vlan table after reset.

Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h

index 94f0b92ead386f2f4db908a73b142ae211278c96..f700ec18a91f4e92aa7d2e229faf08106b0152f6 100644 (file)
@@ -1404,11 +1404,15 @@ static int hns3_vlan_rx_add_vid(struct net_device *netdev,
                                __be16 proto, u16 vid)
 {
        struct hnae3_handle *h = hns3_get_handle(netdev);
+       struct hns3_nic_priv *priv = netdev_priv(netdev);
        int ret = -EIO;
 
        if (h->ae_algo->ops->set_vlan_filter)
                ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, false);
 
+       if (!ret)
+               set_bit(vid, priv->active_vlans);
+
        return ret;
 }
 
@@ -1416,14 +1420,32 @@ static int hns3_vlan_rx_kill_vid(struct net_device *netdev,
                                 __be16 proto, u16 vid)
 {
        struct hnae3_handle *h = hns3_get_handle(netdev);
+       struct hns3_nic_priv *priv = netdev_priv(netdev);
        int ret = -EIO;
 
        if (h->ae_algo->ops->set_vlan_filter)
                ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, true);
 
+       if (!ret)
+               clear_bit(vid, priv->active_vlans);
+
        return ret;
 }
 
+static void hns3_restore_vlan(struct net_device *netdev)
+{
+       struct hns3_nic_priv *priv = netdev_priv(netdev);
+       u16 vid;
+       int ret;
+
+       for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
+               ret = hns3_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
+               if (ret)
+                       netdev_warn(netdev, "Restore vlan: %d filter, ret:%d\n",
+                                   vid, ret);
+       }
+}
+
 static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
                                u8 qos, __be16 vlan_proto)
 {
@@ -3341,6 +3363,10 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
        hns3_nic_set_rx_mode(netdev);
        hns3_recover_hw_addr(netdev);
 
+       /* Hardware table is only clear when pf resets */
+       if (!(handle->flags & HNAE3_SUPPORT_VF))
+               hns3_restore_vlan(netdev);
+
        /* Carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);
 
index a5f4550483d9346adc1ab95f1271cdbc1d6d08b3..c313780ef2a7941599d457898b26224abf9c6308 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef __HNS3_ENET_H
 #define __HNS3_ENET_H
 
+#include <linux/if_vlan.h>
+
 #include "hnae3.h"
 
 extern const char hns3_driver_version[];
@@ -539,6 +541,7 @@ struct hns3_nic_priv {
        struct notifier_block notifier_block;
        /* Vxlan/Geneve information */
        struct hns3_udp_tunnel udp_tnl[HNS3_UDP_TNL_MAX];
+       unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
 };
 
 union l3_hdr_info {