From: Vlad Buslov <vla...@mellanox.com>

In order to remove dependency on rtnl lock for protecting unready_flows
list when reoffloading unready flows on workqueue, extend representor
uplink private structure with dedicated 'unready_flows_lock' mutex. Take
the lock in all users of unready_flows list before accessing it. Implement
helper functions to add and delete unready flow.

Signed-off-by: Vlad Buslov <vla...@mellanox.com>
Reviewed-by: Jianbo Liu <jian...@mellanox.com>
Reviewed-by: Roi Dayan <r...@mellanox.com>
Signed-off-by: Saeed Mahameed <sae...@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en_rep.c  |  2 +
 .../net/ethernet/mellanox/mlx5/core/en_rep.h  |  2 +
 .../net/ethernet/mellanox/mlx5/core/en_tc.c   | 43 ++++++++++++++++---
 3 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 69f7ac8fc9be..6edf0aeb1e26 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -1560,6 +1560,7 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
        if (rpriv->rep->vport == MLX5_VPORT_UPLINK) {
                uplink_priv = &rpriv->uplink_priv;
 
+               mutex_init(&uplink_priv->unready_flows_lock);
                INIT_LIST_HEAD(&uplink_priv->unready_flows);
 
                /* init shared tc flow table */
@@ -1604,6 +1605,7 @@ static void mlx5e_cleanup_rep_tx(struct mlx5e_priv *priv)
 
                /* delete shared tc flow table */
                mlx5e_tc_esw_cleanup(&rpriv->uplink_priv.tc_ht);
+               mutex_destroy(&rpriv->uplink_priv.unready_flows_lock);
        }
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h 
b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
index c56e6ee4350c..10fafd5fa17b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
@@ -75,6 +75,8 @@ struct mlx5_rep_uplink_priv {
 
        struct mlx5_tun_entropy tun_entropy;
 
+       /* protects unready_flows */
+       struct mutex                unready_flows_lock;
        struct list_head            unready_flows;
        struct work_struct          reoffload_flows_work;
 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index a39f8a07de0a..714aa9d7180b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -996,6 +996,25 @@ mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw,
        flow_flag_clear(flow, SLOW);
 }
 
+/* Caller must obtain uplink_priv->unready_flows_lock mutex before calling this
+ * function.
+ */
+static void unready_flow_add(struct mlx5e_tc_flow *flow,
+                            struct list_head *unready_flows)
+{
+       flow_flag_set(flow, NOT_READY);
+       list_add_tail(&flow->unready, unready_flows);
+}
+
+/* Caller must obtain uplink_priv->unready_flows_lock mutex before calling this
+ * function.
+ */
+static void unready_flow_del(struct mlx5e_tc_flow *flow)
+{
+       list_del(&flow->unready);
+       flow_flag_clear(flow, NOT_READY);
+}
+
 static void add_unready_flow(struct mlx5e_tc_flow *flow)
 {
        struct mlx5_rep_uplink_priv *uplink_priv;
@@ -1006,14 +1025,24 @@ static void add_unready_flow(struct mlx5e_tc_flow *flow)
        rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
        uplink_priv = &rpriv->uplink_priv;
 
-       flow_flag_set(flow, NOT_READY);
-       list_add_tail(&flow->unready, &uplink_priv->unready_flows);
+       mutex_lock(&uplink_priv->unready_flows_lock);
+       unready_flow_add(flow, &uplink_priv->unready_flows);
+       mutex_unlock(&uplink_priv->unready_flows_lock);
 }
 
 static void remove_unready_flow(struct mlx5e_tc_flow *flow)
 {
-       list_del(&flow->unready);
-       flow_flag_clear(flow, NOT_READY);
+       struct mlx5_rep_uplink_priv *uplink_priv;
+       struct mlx5e_rep_priv *rpriv;
+       struct mlx5_eswitch *esw;
+
+       esw = flow->priv->mdev->priv.eswitch;
+       rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
+       uplink_priv = &rpriv->uplink_priv;
+
+       mutex_lock(&uplink_priv->unready_flows_lock);
+       unready_flow_del(flow);
+       mutex_unlock(&uplink_priv->unready_flows_lock);
 }
 
 static int
@@ -3723,10 +3752,10 @@ void mlx5e_tc_reoffload_flows_work(struct work_struct 
*work)
                             reoffload_flows_work);
        struct mlx5e_tc_flow *flow, *tmp;
 
-       rtnl_lock();
+       mutex_lock(&rpriv->unready_flows_lock);
        list_for_each_entry_safe(flow, tmp, &rpriv->unready_flows, unready) {
                if (!mlx5e_tc_add_fdb_flow(flow->priv, flow, NULL))
-                       remove_unready_flow(flow);
+                       unready_flow_del(flow);
        }
-       rtnl_unlock();
+       mutex_unlock(&rpriv->unready_flows_lock);
 }
-- 
2.21.0

Reply via email to