From: Guojia Liao <liaoguo...@huawei.com>

[ Upstream commit efe3fa45f770f1d66e2734ee7a3523c75694ff04 ]

When user had created a FD rule, all the aRFS rules should be clear up.
HNS3 process flow as below:
1.get spin lock of fd_ruls_list
2.clear up all aRFS rules
3.release lock
4.get spin lock of fd_ruls_list
5.creat a rules
6.release lock;

There is a short period of time between step 3 and step 4, which would
creatting some new aRFS FD rules if driver was receiving packet.
So refactor the fd_rule_lock to fix it.

Fixes: 441228875706 ("net: hns3: refine the flow director handle")
Signed-off-by: Guojia Liao <liaoguo...@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazh...@huawei.com>
Signed-off-by: David S. Miller <da...@davemloft.net>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 .../hisilicon/hns3/hns3pf/hclge_main.c        | 28 ++++++++++---------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c 
b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index b66b93f320b42..ae4c415b97e45 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -5737,9 +5737,9 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
        /* to avoid rule conflict, when user configure rule by ethtool,
         * we need to clear all arfs rules
         */
+       spin_lock_bh(&hdev->fd_rule_lock);
        hclge_clear_arfs_rules(handle);
 
-       spin_lock_bh(&hdev->fd_rule_lock);
        ret = hclge_fd_config_rule(hdev, rule);
 
        spin_unlock_bh(&hdev->fd_rule_lock);
@@ -5782,6 +5782,7 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle,
        return ret;
 }
 
+/* make sure being called after lock up with fd_rule_lock */
 static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
                                     bool clear_list)
 {
@@ -5794,7 +5795,6 @@ static void hclge_del_all_fd_entries(struct hnae3_handle 
*handle,
        if (!hnae3_dev_fd_supported(hdev))
                return;
 
-       spin_lock_bh(&hdev->fd_rule_lock);
        for_each_set_bit(location, hdev->fd_bmap,
                         hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
                hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, location,
@@ -5811,8 +5811,6 @@ static void hclge_del_all_fd_entries(struct hnae3_handle 
*handle,
                bitmap_zero(hdev->fd_bmap,
                            hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
        }
-
-       spin_unlock_bh(&hdev->fd_rule_lock);
 }
 
 static int hclge_restore_fd_entries(struct hnae3_handle *handle)
@@ -6179,7 +6177,7 @@ static int hclge_add_fd_entry_by_arfs(struct hnae3_handle 
*handle, u16 queue_id,
                                      u16 flow_id, struct flow_keys *fkeys)
 {
        struct hclge_vport *vport = hclge_get_vport(handle);
-       struct hclge_fd_rule_tuples new_tuples;
+       struct hclge_fd_rule_tuples new_tuples = {};
        struct hclge_dev *hdev = vport->back;
        struct hclge_fd_rule *rule;
        u16 tmp_queue_id;
@@ -6189,20 +6187,18 @@ static int hclge_add_fd_entry_by_arfs(struct 
hnae3_handle *handle, u16 queue_id,
        if (!hnae3_dev_fd_supported(hdev))
                return -EOPNOTSUPP;
 
-       memset(&new_tuples, 0, sizeof(new_tuples));
-       hclge_fd_get_flow_tuples(fkeys, &new_tuples);
-
-       spin_lock_bh(&hdev->fd_rule_lock);
-
        /* when there is already fd rule existed add by user,
         * arfs should not work
         */
+       spin_lock_bh(&hdev->fd_rule_lock);
        if (hdev->fd_active_type == HCLGE_FD_EP_ACTIVE) {
                spin_unlock_bh(&hdev->fd_rule_lock);
 
                return -EOPNOTSUPP;
        }
 
+       hclge_fd_get_flow_tuples(fkeys, &new_tuples);
+
        /* check is there flow director filter existed for this flow,
         * if not, create a new filter for it;
         * if filter exist with different queue id, modify the filter;
@@ -6287,6 +6283,7 @@ static void hclge_rfs_filter_expire(struct hclge_dev 
*hdev)
 #endif
 }
 
+/* make sure being called after lock up with fd_rule_lock */
 static void hclge_clear_arfs_rules(struct hnae3_handle *handle)
 {
 #ifdef CONFIG_RFS_ACCEL
@@ -6331,10 +6328,14 @@ static void hclge_enable_fd(struct hnae3_handle 
*handle, bool enable)
 
        hdev->fd_en = enable;
        clear = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE;
-       if (!enable)
+
+       if (!enable) {
+               spin_lock_bh(&hdev->fd_rule_lock);
                hclge_del_all_fd_entries(handle, clear);
-       else
+               spin_unlock_bh(&hdev->fd_rule_lock);
+       } else {
                hclge_restore_fd_entries(handle);
+       }
 }
 
 static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
@@ -6799,8 +6800,9 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
        int i;
 
        set_bit(HCLGE_STATE_DOWN, &hdev->state);
-
+       spin_lock_bh(&hdev->fd_rule_lock);
        hclge_clear_arfs_rules(handle);
+       spin_unlock_bh(&hdev->fd_rule_lock);
 
        /* If it is not PF reset, the firmware will disable the MAC,
         * so it only need to stop phy here.
-- 
2.25.1



Reply via email to