From: Roi Dayan <roid@nvidia.com>
Date: Sun, 24 Jul 2022 14:14:55 +0300
Subject: net/mlx5e: TC, Separate get/update/replace meter functions
Patch-mainline: v6.0-rc1
Git-commit: f8e9d413a28a36f7451ca3b53306a6a8daa7b997
References: jsc#PED-1549

mlx5e_tc_meter_get() to get an existing meter.
mlx5e_tc_meter_update() to update an existing meter without refcount.
mlx5e_tc_meter_replace() to get/create a meter and update if needed.

Signed-off-by: Roi Dayan <roid@nvidia.com>
Reviewed-by: Jianbo Liu <jianbol@nvidia.com>
Reviewed-by: Oz Shlomo <ozsh@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c |  132 ++++++++++++++----
 drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.h |    5 
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c       |    2 
 3 files changed, 112 insertions(+), 27 deletions(-)

--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c
@@ -344,69 +344,149 @@ __mlx5e_flow_meter_free(struct mlx5e_flo
 	kfree(meter);
 }
 
+static struct mlx5e_flow_meter_handle *
+__mlx5e_tc_meter_get(struct mlx5e_flow_meters *flow_meters, u32 index)
+{
+	struct mlx5e_flow_meter_handle *meter;
+
+	hash_for_each_possible(flow_meters->hashtbl, meter, hlist, index)
+		if (meter->params.index == index)
+			goto add_ref;
+
+	return ERR_PTR(-ENOENT);
+
+add_ref:
+	meter->refcnt++;
+
+	return meter;
+}
+
 struct mlx5e_flow_meter_handle *
 mlx5e_tc_meter_get(struct mlx5_core_dev *mdev, struct mlx5e_flow_meter_params *params)
 {
 	struct mlx5e_flow_meters *flow_meters;
 	struct mlx5e_flow_meter_handle *meter;
-	int err;
 
 	flow_meters = mlx5e_get_flow_meters(mdev);
 	if (!flow_meters)
 		return ERR_PTR(-EOPNOTSUPP);
 
 	mutex_lock(&flow_meters->sync_lock);
-	hash_for_each_possible(flow_meters->hashtbl, meter, hlist, params->index)
-		if (meter->params.index == params->index)
-			goto add_ref;
+	meter = __mlx5e_tc_meter_get(flow_meters, params->index);
+	mutex_unlock(&flow_meters->sync_lock);
 
-	meter = __mlx5e_flow_meter_alloc(flow_meters);
-	if (IS_ERR(meter)) {
-		err = PTR_ERR(meter);
-		goto err_alloc;
+	return meter;
+}
+
+static void
+__mlx5e_tc_meter_put(struct mlx5e_flow_meter_handle *meter)
+{
+	if (--meter->refcnt == 0) {
+		hash_del(&meter->hlist);
+		__mlx5e_flow_meter_free(meter);
 	}
+}
+
+void
+mlx5e_tc_meter_put(struct mlx5e_flow_meter_handle *meter)
+{
+	struct mlx5e_flow_meters *flow_meters = meter->flow_meters;
+
+	mutex_lock(&flow_meters->sync_lock);
+	__mlx5e_tc_meter_put(meter);
+	mutex_unlock(&flow_meters->sync_lock);
+}
+
+static struct mlx5e_flow_meter_handle *
+mlx5e_tc_meter_alloc(struct mlx5e_flow_meters *flow_meters,
+		     struct mlx5e_flow_meter_params *params)
+{
+	struct mlx5e_flow_meter_handle *meter;
+
+	meter = __mlx5e_flow_meter_alloc(flow_meters);
+	if (IS_ERR(meter))
+		return meter;
 
 	hash_add(flow_meters->hashtbl, &meter->hlist, params->index);
 	meter->params.index = params->index;
-
-add_ref:
 	meter->refcnt++;
 
+	return meter;
+}
+
+static int
+__mlx5e_tc_meter_update(struct mlx5e_flow_meter_handle *meter,
+			struct mlx5e_flow_meter_params *params)
+{
+	struct mlx5_core_dev *mdev = meter->flow_meters->mdev;
+	int err = 0;
+
 	if (meter->params.mode != params->mode || meter->params.rate != params->rate ||
 	    meter->params.burst != params->burst) {
 		err = mlx5e_tc_meter_modify(mdev, meter, params);
 		if (err)
-			goto err_update;
+			goto out;
 
 		meter->params.mode = params->mode;
 		meter->params.rate = params->rate;
 		meter->params.burst = params->burst;
 	}
 
-	mutex_unlock(&flow_meters->sync_lock);
-	return meter;
+out:
+	return err;
+}
 
-err_update:
-	if (--meter->refcnt == 0) {
-		hash_del(&meter->hlist);
-		__mlx5e_flow_meter_free(meter);
-	}
-err_alloc:
+int
+mlx5e_tc_meter_update(struct mlx5e_flow_meter_handle *meter,
+		      struct mlx5e_flow_meter_params *params)
+{
+	struct mlx5_core_dev *mdev = meter->flow_meters->mdev;
+	struct mlx5e_flow_meters *flow_meters;
+	int err;
+
+	flow_meters = mlx5e_get_flow_meters(mdev);
+	if (!flow_meters)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&flow_meters->sync_lock);
+	err = __mlx5e_tc_meter_update(meter, params);
 	mutex_unlock(&flow_meters->sync_lock);
-	return ERR_PTR(err);
+	return err;
 }
 
-void
-mlx5e_tc_meter_put(struct mlx5e_flow_meter_handle *meter)
+struct mlx5e_flow_meter_handle *
+mlx5e_tc_meter_replace(struct mlx5_core_dev *mdev, struct mlx5e_flow_meter_params *params)
 {
-	struct mlx5e_flow_meters *flow_meters = meter->flow_meters;
+	struct mlx5e_flow_meters *flow_meters;
+	struct mlx5e_flow_meter_handle *meter;
+	int err;
+
+	flow_meters = mlx5e_get_flow_meters(mdev);
+	if (!flow_meters)
+		return ERR_PTR(-EOPNOTSUPP);
 
 	mutex_lock(&flow_meters->sync_lock);
-	if (--meter->refcnt == 0) {
-		hash_del(&meter->hlist);
-		__mlx5e_flow_meter_free(meter);
+	meter = __mlx5e_tc_meter_get(flow_meters, params->index);
+	if (IS_ERR(meter)) {
+		meter = mlx5e_tc_meter_alloc(flow_meters, params);
+		if (IS_ERR(meter)) {
+			err = PTR_ERR(meter);
+			goto err_get;
+		}
 	}
+
+	err = __mlx5e_tc_meter_update(meter, params);
+	if (err)
+		goto err_update;
+
 	mutex_unlock(&flow_meters->sync_lock);
+	return meter;
+
+err_update:
+	__mlx5e_tc_meter_put(meter);
+err_get:
+	mutex_unlock(&flow_meters->sync_lock);
+	return ERR_PTR(err);
 }
 
 enum mlx5_flow_namespace_type
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.h
@@ -51,6 +51,11 @@ struct mlx5e_flow_meter_handle *
 mlx5e_tc_meter_get(struct mlx5_core_dev *mdev, struct mlx5e_flow_meter_params *params);
 void
 mlx5e_tc_meter_put(struct mlx5e_flow_meter_handle *meter);
+int
+mlx5e_tc_meter_update(struct mlx5e_flow_meter_handle *meter,
+		      struct mlx5e_flow_meter_params *params);
+struct mlx5e_flow_meter_handle *
+mlx5e_tc_meter_replace(struct mlx5_core_dev *mdev, struct mlx5e_flow_meter_params *params);
 
 enum mlx5_flow_namespace_type
 mlx5e_tc_meter_get_namespace(struct mlx5e_flow_meters *flow_meters);
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -361,7 +361,7 @@ mlx5e_tc_add_flow_meter(struct mlx5e_pri
 	enum mlx5_flow_namespace_type ns_type;
 	struct mlx5e_flow_meter_handle *meter;
 
-	meter = mlx5e_tc_meter_get(priv->mdev, &attr->meter_attr.params);
+	meter = mlx5e_tc_meter_replace(priv->mdev, &attr->meter_attr.params);
 	if (IS_ERR(meter)) {
 		mlx5_core_err(priv->mdev, "Failed to get flow meter\n");
 		return PTR_ERR(meter);
