net: hns3: Add reset handle for flow director
authorJian Shen <shenjian15@huawei.com>
Mon, 1 Oct 2018 11:46:45 +0000 (12:46 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 2 Oct 2018 05:57:45 +0000 (22:57 -0700)
When doing reset, remove all entries in TCAM block, and keep flow
director rules list. After finishing reset, restore all entries.

Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Peng Li <lipeng321@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/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c

index fac84d8f3c43e2c9a9aab1d18357eea60b476922..e185d0485468589fa33e8091a2db35ab90a322cd 100644 (file)
@@ -179,6 +179,7 @@ struct hnae3_ae_dev {
        struct list_head node;
        u32 flag;
        enum hnae3_dev_type dev_type;
+       enum hnae3_reset_type reset_type;
        void *priv;
 };
 
@@ -420,12 +421,15 @@ struct hnae3_ae_ops {
                            struct ethtool_rxnfc *cmd);
        int (*del_fd_entry)(struct hnae3_handle *handle,
                            struct ethtool_rxnfc *cmd);
+       void (*del_all_fd_entries)(struct hnae3_handle *handle,
+                                  bool clear_list);
        int (*get_fd_rule_cnt)(struct hnae3_handle *handle,
                               struct ethtool_rxnfc *cmd);
        int (*get_fd_rule_info)(struct hnae3_handle *handle,
                                struct ethtool_rxnfc *cmd);
        int (*get_fd_all_rules)(struct hnae3_handle *handle,
                                struct ethtool_rxnfc *cmd, u32 *rule_locs);
+       int (*restore_fd_rules)(struct hnae3_handle *handle);
 };
 
 struct hnae3_dcb_ops {
index 605f029427ee000aeb9047c5a92e606f79ad8800..df4410eea27bf0b4315c0faa63d95d8f423b8788 100644 (file)
@@ -1654,6 +1654,7 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        ae_dev->pdev = pdev;
        ae_dev->flag = ent->driver_data;
        ae_dev->dev_type = HNAE3_DEV_KNIC;
+       ae_dev->reset_type = HNAE3_NONE_RESET;
        hns3_get_dev_capability(pdev, ae_dev);
        pci_set_drvdata(pdev, ae_dev);
 
@@ -3150,6 +3151,25 @@ static void hns3_uninit_mac_addr(struct net_device *netdev)
                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);
+       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);
+
+       if (h->ae_algo->ops->del_all_fd_entries)
+               h->ae_algo->ops->del_all_fd_entries(h, clear_list);
+}
+
 static void hns3_nic_set_priv_ops(struct net_device *netdev)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
@@ -3561,6 +3581,8 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
        if (!(handle->flags & HNAE3_SUPPORT_VF))
                hns3_restore_vlan(netdev);
 
+       hns3_restore_fd_rules(netdev);
+
        /* Carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);
 
@@ -3581,6 +3603,7 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
 
 static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
 {
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
        struct net_device *netdev = handle->kinfo.netdev;
        struct hns3_nic_priv *priv = netdev_priv(netdev);
        int ret;
@@ -3601,6 +3624,13 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
 
        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
+        */
+       if (hns3_dev_ongoing_func_reset(ae_dev))
+               hns3_del_all_fd_rules(netdev, false);
+
        return ret;
 }
 
index 27d704f4b306b07a74c261e7a15936886cd4912e..ac881e8fc05d7fad0173e3f7e97f47b5b0aa1445 100644 (file)
@@ -585,6 +585,11 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
        writel(value, reg_addr + reg);
 }
 
+static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev)
+{
+       return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET));
+}
+
 #define hns3_write_dev(a, reg, value) \
        hns3_write_reg((a)->io_base, (reg), (value))
 
index 1e2d78007129bdad04ef4e9b66b6cd55c0f9a680..90701affd7d725f9aed7142974f0ca85f3a60c1b 100644 (file)
@@ -2513,8 +2513,13 @@ static void hclge_clear_reset_cause(struct hclge_dev *hdev)
 
 static void hclge_reset(struct hclge_dev *hdev)
 {
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
        struct hnae3_handle *handle;
 
+       /* Initialize ae_dev reset status as well, in case enet layer wants to
+        * know if device is undergoing reset
+        */
+       ae_dev->reset_type = hdev->reset_type;
        /* perform reset of the stack & ae device for a client */
        handle = &hdev->vport[0].nic;
        rtnl_lock();
@@ -2535,6 +2540,7 @@ static void hclge_reset(struct hclge_dev *hdev)
        hclge_notify_client(hdev, HNAE3_UP_CLIENT);
        handle->last_reset_time = jiffies;
        rtnl_unlock();
+       ae_dev->reset_type = HNAE3_NONE_RESET;
 }
 
 static void hclge_reset_event(struct hnae3_handle *handle)
@@ -4299,6 +4305,62 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle,
                                         false);
 }
 
+static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
+                                    bool clear_list)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       struct hclge_fd_rule *rule;
+       struct hlist_node *node;
+
+       if (!hnae3_dev_fd_supported(hdev))
+               return;
+
+       if (clear_list) {
+               hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
+                                         rule_node) {
+                       hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
+                                            rule->location, NULL, false);
+                       hlist_del(&rule->rule_node);
+                       kfree(rule);
+                       hdev->hclge_fd_rule_num--;
+               }
+       } else {
+               hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
+                                         rule_node)
+                       hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
+                                            rule->location, NULL, false);
+       }
+}
+
+static int hclge_restore_fd_entries(struct hnae3_handle *handle)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       struct hclge_fd_rule *rule;
+       struct hlist_node *node;
+       int ret;
+
+       if (!hnae3_dev_fd_supported(hdev))
+               return -EOPNOTSUPP;
+
+       hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
+               ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
+               if (!ret)
+                       ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
+
+               if (ret) {
+                       dev_warn(&hdev->pdev->dev,
+                                "Restore rule %d failed, remove it\n",
+                                rule->location);
+                       hlist_del(&rule->rule_node);
+                       kfree(rule);
+                       hdev->hclge_fd_rule_num--;
+               }
+       }
+       return 0;
+}
+
 static int hclge_get_fd_rule_cnt(struct hnae3_handle *handle,
                                 struct ethtool_rxnfc *cmd)
 {
@@ -7270,9 +7332,11 @@ static const struct hnae3_ae_ops hclge_ops = {
        .get_link_mode = hclge_get_link_mode,
        .add_fd_entry = hclge_add_fd_entry,
        .del_fd_entry = hclge_del_fd_entry,
+       .del_all_fd_entries = hclge_del_all_fd_entries,
        .get_fd_rule_cnt = hclge_get_fd_rule_cnt,
        .get_fd_rule_info = hclge_get_fd_rule_info,
        .get_fd_all_rules = hclge_get_all_rules,
+       .restore_fd_rules = hclge_restore_fd_entries,
 };
 
 static struct hnae3_ae_algo ae_algo = {