xref: /dpdk/drivers/net/mlx5/mlx5_flow_meter.c (revision 61a810617ec864aa30b36d7aaffc0bda4cc28f54)
1d740eb50SSuanming Mou // SPDX-License-Identifier: BSD-3-Clause
2d740eb50SSuanming Mou /*
3d740eb50SSuanming Mou  * Copyright 2018 Mellanox Technologies, Ltd
4d740eb50SSuanming Mou  */
5d740eb50SSuanming Mou #include <math.h>
6d740eb50SSuanming Mou 
702e76468SSuanming Mou #include <rte_tailq.h>
83bd26b23SSuanming Mou #include <rte_malloc.h>
9d740eb50SSuanming Mou #include <rte_mtr.h>
10d740eb50SSuanming Mou #include <rte_mtr_driver.h>
11d740eb50SSuanming Mou 
127b4f1e6bSMatan Azrad #include <mlx5_devx_cmds.h>
1383c2047cSSuanming Mou #include <mlx5_malloc.h>
147b4f1e6bSMatan Azrad 
15d740eb50SSuanming Mou #include "mlx5.h"
166bc327b9SSuanming Mou #include "mlx5_flow.h"
176bc327b9SSuanming Mou 
18bf5c4d0bSDariusz Sosnowski #ifdef HAVE_MLX5_HWS_SUPPORT
19bf5c4d0bSDariusz Sosnowski 
20ddbb689bSDariusz Sosnowski static void
21ddbb689bSDariusz Sosnowski mlx5_flow_meter_uninit_guest(struct rte_eth_dev *dev)
22ddbb689bSDariusz Sosnowski {
23ddbb689bSDariusz Sosnowski 	struct mlx5_priv *priv = dev->data->dev_private;
24ddbb689bSDariusz Sosnowski 
25ddbb689bSDariusz Sosnowski 	if (priv->hws_mpool) {
26ddbb689bSDariusz Sosnowski 		if (priv->hws_mpool->action) {
27ddbb689bSDariusz Sosnowski 			claim_zero(mlx5dr_action_destroy(priv->hws_mpool->action));
28ddbb689bSDariusz Sosnowski 			priv->hws_mpool->action = NULL;
29ddbb689bSDariusz Sosnowski 		}
30ddbb689bSDariusz Sosnowski 		priv->hws_mpool->devx_obj = NULL;
31ddbb689bSDariusz Sosnowski 		priv->hws_mpool->idx_pool = NULL;
32ddbb689bSDariusz Sosnowski 		mlx5_free(priv->hws_mpool);
33ddbb689bSDariusz Sosnowski 		priv->hws_mpool = NULL;
34ddbb689bSDariusz Sosnowski 	}
35ddbb689bSDariusz Sosnowski }
36ddbb689bSDariusz Sosnowski 
37bf5c4d0bSDariusz Sosnowski void
38bf5c4d0bSDariusz Sosnowski mlx5_flow_meter_uninit(struct rte_eth_dev *dev)
39bf5c4d0bSDariusz Sosnowski {
40bf5c4d0bSDariusz Sosnowski 	struct mlx5_priv *priv = dev->data->dev_private;
41bf5c4d0bSDariusz Sosnowski 
42ddbb689bSDariusz Sosnowski 	if (priv->shared_host) {
43ddbb689bSDariusz Sosnowski 		mlx5_flow_meter_uninit_guest(dev);
44ddbb689bSDariusz Sosnowski 		return;
45ddbb689bSDariusz Sosnowski 	}
46bf5c4d0bSDariusz Sosnowski 	if (priv->mtr_policy_arr) {
47bf5c4d0bSDariusz Sosnowski 		mlx5_free(priv->mtr_policy_arr);
48bf5c4d0bSDariusz Sosnowski 		priv->mtr_policy_arr = NULL;
49bf5c4d0bSDariusz Sosnowski 	}
50bf5c4d0bSDariusz Sosnowski 	if (priv->mtr_profile_arr) {
51bf5c4d0bSDariusz Sosnowski 		mlx5_free(priv->mtr_profile_arr);
52bf5c4d0bSDariusz Sosnowski 		priv->mtr_profile_arr = NULL;
53bf5c4d0bSDariusz Sosnowski 	}
54bf5c4d0bSDariusz Sosnowski 	if (priv->hws_mpool) {
55bf5c4d0bSDariusz Sosnowski 		mlx5_aso_mtr_queue_uninit(priv->sh, priv->hws_mpool, NULL);
56bf5c4d0bSDariusz Sosnowski 		mlx5_ipool_destroy(priv->hws_mpool->idx_pool);
57bf5c4d0bSDariusz Sosnowski 		mlx5_free(priv->hws_mpool);
58bf5c4d0bSDariusz Sosnowski 		priv->hws_mpool = NULL;
59bf5c4d0bSDariusz Sosnowski 	}
60bf5c4d0bSDariusz Sosnowski 	if (priv->mtr_bulk.aso) {
61bf5c4d0bSDariusz Sosnowski 		mlx5_free(priv->mtr_bulk.aso);
62bf5c4d0bSDariusz Sosnowski 		priv->mtr_bulk.aso = NULL;
63bf5c4d0bSDariusz Sosnowski 		priv->mtr_bulk.size = 0;
64bf5c4d0bSDariusz Sosnowski 		mlx5_aso_queue_uninit(priv->sh, ASO_OPC_MOD_POLICER);
65bf5c4d0bSDariusz Sosnowski 	}
66bf5c4d0bSDariusz Sosnowski 	if (priv->mtr_bulk.action) {
67bf5c4d0bSDariusz Sosnowski 		mlx5dr_action_destroy(priv->mtr_bulk.action);
68bf5c4d0bSDariusz Sosnowski 		priv->mtr_bulk.action = NULL;
69bf5c4d0bSDariusz Sosnowski 	}
70bf5c4d0bSDariusz Sosnowski 	if (priv->mtr_bulk.devx_obj) {
71bf5c4d0bSDariusz Sosnowski 		claim_zero(mlx5_devx_cmd_destroy(priv->mtr_bulk.devx_obj));
72bf5c4d0bSDariusz Sosnowski 		priv->mtr_bulk.devx_obj = NULL;
73bf5c4d0bSDariusz Sosnowski 	}
74bf5c4d0bSDariusz Sosnowski }
75bf5c4d0bSDariusz Sosnowski 
76ddbb689bSDariusz Sosnowski static int
77ddbb689bSDariusz Sosnowski mlx5_flow_meter_init_guest(struct rte_eth_dev *dev)
78ddbb689bSDariusz Sosnowski {
79ddbb689bSDariusz Sosnowski 	struct mlx5_priv *priv = dev->data->dev_private;
80ddbb689bSDariusz Sosnowski 	struct rte_eth_dev *host_dev = priv->shared_host;
81ddbb689bSDariusz Sosnowski 	struct mlx5_priv *host_priv = host_dev->data->dev_private;
82ddbb689bSDariusz Sosnowski 	int reg_id = 0;
83ddbb689bSDariusz Sosnowski 	uint32_t flags;
84ddbb689bSDariusz Sosnowski 	int ret = 0;
85ddbb689bSDariusz Sosnowski 
86ddbb689bSDariusz Sosnowski 	MLX5_ASSERT(priv->shared_host);
87ddbb689bSDariusz Sosnowski 	reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, NULL);
88ddbb689bSDariusz Sosnowski 	if (reg_id < 0) {
89ddbb689bSDariusz Sosnowski 		rte_errno = ENOMEM;
90ddbb689bSDariusz Sosnowski 		ret = -rte_errno;
91ddbb689bSDariusz Sosnowski 		DRV_LOG(ERR, "Meter register is not available.");
92ddbb689bSDariusz Sosnowski 		goto err;
93ddbb689bSDariusz Sosnowski 	}
94ddbb689bSDariusz Sosnowski 	priv->hws_mpool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_aso_mtr_pool),
95ddbb689bSDariusz Sosnowski 				      RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
96ddbb689bSDariusz Sosnowski 	if (!priv->hws_mpool) {
97ddbb689bSDariusz Sosnowski 		rte_errno = ENOMEM;
98ddbb689bSDariusz Sosnowski 		ret = -rte_errno;
99ddbb689bSDariusz Sosnowski 		DRV_LOG(ERR, "Meter ipool allocation failed.");
100ddbb689bSDariusz Sosnowski 		goto err;
101ddbb689bSDariusz Sosnowski 	}
102ddbb689bSDariusz Sosnowski 	MLX5_ASSERT(host_priv->hws_mpool->idx_pool);
103ddbb689bSDariusz Sosnowski 	MLX5_ASSERT(host_priv->hws_mpool->devx_obj);
104ddbb689bSDariusz Sosnowski 	priv->hws_mpool->idx_pool = host_priv->hws_mpool->idx_pool;
105ddbb689bSDariusz Sosnowski 	priv->hws_mpool->devx_obj = host_priv->hws_mpool->devx_obj;
106ddbb689bSDariusz Sosnowski 	flags = MLX5DR_ACTION_FLAG_HWS_RX | MLX5DR_ACTION_FLAG_HWS_TX;
107ddbb689bSDariusz Sosnowski 	if (priv->sh->config.dv_esw_en && priv->master)
108ddbb689bSDariusz Sosnowski 		flags |= MLX5DR_ACTION_FLAG_HWS_FDB;
109ddbb689bSDariusz Sosnowski 	priv->hws_mpool->action = mlx5dr_action_create_aso_meter
110ddbb689bSDariusz Sosnowski 			(priv->dr_ctx, (struct mlx5dr_devx_obj *)priv->hws_mpool->devx_obj,
111ddbb689bSDariusz Sosnowski 			 reg_id - REG_C_0, flags);
112ddbb689bSDariusz Sosnowski 	if (!priv->hws_mpool->action) {
113ddbb689bSDariusz Sosnowski 		rte_errno = ENOMEM;
114ddbb689bSDariusz Sosnowski 		ret = -rte_errno;
115ddbb689bSDariusz Sosnowski 		DRV_LOG(ERR, "Meter action creation failed.");
116ddbb689bSDariusz Sosnowski 		goto err;
117ddbb689bSDariusz Sosnowski 	}
118ddbb689bSDariusz Sosnowski 	return 0;
119ddbb689bSDariusz Sosnowski err:
120ddbb689bSDariusz Sosnowski 	mlx5_flow_meter_uninit(dev);
121ddbb689bSDariusz Sosnowski 	return ret;
122ddbb689bSDariusz Sosnowski }
123ddbb689bSDariusz Sosnowski 
124bf5c4d0bSDariusz Sosnowski int
125bf5c4d0bSDariusz Sosnowski mlx5_flow_meter_init(struct rte_eth_dev *dev,
126bf5c4d0bSDariusz Sosnowski 		     uint32_t nb_meters,
127bf5c4d0bSDariusz Sosnowski 		     uint32_t nb_meter_profiles,
128bf5c4d0bSDariusz Sosnowski 		     uint32_t nb_meter_policies,
129bf5c4d0bSDariusz Sosnowski 		     uint32_t nb_queues)
130bf5c4d0bSDariusz Sosnowski {
131bf5c4d0bSDariusz Sosnowski 	struct mlx5_priv *priv = dev->data->dev_private;
132bf5c4d0bSDariusz Sosnowski 	struct mlx5_devx_obj *dcs = NULL;
133bf5c4d0bSDariusz Sosnowski 	uint32_t log_obj_size;
134bf5c4d0bSDariusz Sosnowski 	int ret = 0;
135bf5c4d0bSDariusz Sosnowski 	int reg_id;
136bf5c4d0bSDariusz Sosnowski 	struct mlx5_aso_mtr *aso;
137bf5c4d0bSDariusz Sosnowski 	uint32_t i;
138bf5c4d0bSDariusz Sosnowski 	struct rte_flow_error error;
139bf5c4d0bSDariusz Sosnowski 	uint32_t flags;
140bf5c4d0bSDariusz Sosnowski 	uint32_t nb_mtrs = rte_align32pow2(nb_meters);
141bf5c4d0bSDariusz Sosnowski 	struct mlx5_indexed_pool_config cfg = {
142bf5c4d0bSDariusz Sosnowski 		.size = sizeof(struct mlx5_aso_mtr),
143bf5c4d0bSDariusz Sosnowski 		.trunk_size = 1 << 12,
144bf5c4d0bSDariusz Sosnowski 		.per_core_cache = 1 << 13,
145bf5c4d0bSDariusz Sosnowski 		.need_lock = 1,
146bf5c4d0bSDariusz Sosnowski 		.release_mem_en = !!priv->sh->config.reclaim_mode,
147bf5c4d0bSDariusz Sosnowski 		.malloc = mlx5_malloc,
148bf5c4d0bSDariusz Sosnowski 		.max_idx = nb_meters,
149bf5c4d0bSDariusz Sosnowski 		.free = mlx5_free,
150bf5c4d0bSDariusz Sosnowski 		.type = "mlx5_hw_mtr_mark_action",
151bf5c4d0bSDariusz Sosnowski 	};
152bf5c4d0bSDariusz Sosnowski 
153ddbb689bSDariusz Sosnowski 	if (priv->shared_host)
154ddbb689bSDariusz Sosnowski 		return mlx5_flow_meter_init_guest(dev);
155bf5c4d0bSDariusz Sosnowski 	if (!nb_meters) {
156bf5c4d0bSDariusz Sosnowski 		ret = ENOTSUP;
157bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
158bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
159bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter configuration is invalid.");
160bf5c4d0bSDariusz Sosnowski 		goto err;
161bf5c4d0bSDariusz Sosnowski 	}
162bf5c4d0bSDariusz Sosnowski 	if (!priv->mtr_en || !priv->sh->meter_aso_en) {
163bf5c4d0bSDariusz Sosnowski 		ret = ENOTSUP;
164bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
165bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
166bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter ASO is not supported.");
167bf5c4d0bSDariusz Sosnowski 		goto err;
168bf5c4d0bSDariusz Sosnowski 	}
169bf5c4d0bSDariusz Sosnowski 	priv->mtr_config.nb_meters = nb_meters;
170bf5c4d0bSDariusz Sosnowski 	log_obj_size = rte_log2_u32(nb_meters >> 1);
171bf5c4d0bSDariusz Sosnowski 	dcs = mlx5_devx_cmd_create_flow_meter_aso_obj
172bf5c4d0bSDariusz Sosnowski 		(priv->sh->cdev->ctx, priv->sh->cdev->pdn,
173bf5c4d0bSDariusz Sosnowski 			log_obj_size);
174bf5c4d0bSDariusz Sosnowski 	if (!dcs) {
175bf5c4d0bSDariusz Sosnowski 		ret = ENOMEM;
176bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
177bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
178bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter ASO object allocation failed.");
179bf5c4d0bSDariusz Sosnowski 		goto err;
180bf5c4d0bSDariusz Sosnowski 	}
181bf5c4d0bSDariusz Sosnowski 	priv->mtr_bulk.devx_obj = dcs;
182bf5c4d0bSDariusz Sosnowski 	reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, NULL);
183bf5c4d0bSDariusz Sosnowski 	if (reg_id < 0) {
184bf5c4d0bSDariusz Sosnowski 		ret = ENOTSUP;
185bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
186bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
187bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter register is not available.");
188bf5c4d0bSDariusz Sosnowski 		goto err;
189bf5c4d0bSDariusz Sosnowski 	}
190bf5c4d0bSDariusz Sosnowski 	flags = MLX5DR_ACTION_FLAG_HWS_RX | MLX5DR_ACTION_FLAG_HWS_TX;
191bf5c4d0bSDariusz Sosnowski 	if (priv->sh->config.dv_esw_en && priv->master)
192bf5c4d0bSDariusz Sosnowski 		flags |= MLX5DR_ACTION_FLAG_HWS_FDB;
193bf5c4d0bSDariusz Sosnowski 	priv->mtr_bulk.action = mlx5dr_action_create_aso_meter
194bf5c4d0bSDariusz Sosnowski 			(priv->dr_ctx, (struct mlx5dr_devx_obj *)dcs,
195bf5c4d0bSDariusz Sosnowski 				reg_id - REG_C_0, flags);
196bf5c4d0bSDariusz Sosnowski 	if (!priv->mtr_bulk.action) {
197bf5c4d0bSDariusz Sosnowski 		ret = ENOMEM;
198bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
199bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
200bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter action creation failed.");
201bf5c4d0bSDariusz Sosnowski 		goto err;
202bf5c4d0bSDariusz Sosnowski 	}
203bf5c4d0bSDariusz Sosnowski 	priv->mtr_bulk.aso = mlx5_malloc(MLX5_MEM_ZERO,
204bf5c4d0bSDariusz Sosnowski 					 sizeof(struct mlx5_aso_mtr) *
205bf5c4d0bSDariusz Sosnowski 					 nb_meters,
206bf5c4d0bSDariusz Sosnowski 					 RTE_CACHE_LINE_SIZE,
207bf5c4d0bSDariusz Sosnowski 					 SOCKET_ID_ANY);
208bf5c4d0bSDariusz Sosnowski 	if (!priv->mtr_bulk.aso) {
209bf5c4d0bSDariusz Sosnowski 		ret = ENOMEM;
210bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
211bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
212bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter bulk ASO allocation failed.");
213bf5c4d0bSDariusz Sosnowski 		goto err;
214bf5c4d0bSDariusz Sosnowski 	}
215bf5c4d0bSDariusz Sosnowski 	priv->mtr_bulk.size = nb_meters;
216bf5c4d0bSDariusz Sosnowski 	aso = priv->mtr_bulk.aso;
217bf5c4d0bSDariusz Sosnowski 	for (i = 0; i < priv->mtr_bulk.size; i++) {
218bf5c4d0bSDariusz Sosnowski 		aso->type = ASO_METER_DIRECT;
219bf5c4d0bSDariusz Sosnowski 		aso->state = ASO_METER_WAIT;
220bf5c4d0bSDariusz Sosnowski 		aso->offset = i;
221bf5c4d0bSDariusz Sosnowski 		aso++;
222bf5c4d0bSDariusz Sosnowski 	}
223bf5c4d0bSDariusz Sosnowski 	priv->hws_mpool = mlx5_malloc(MLX5_MEM_ZERO,
224bf5c4d0bSDariusz Sosnowski 				sizeof(struct mlx5_aso_mtr_pool),
225bf5c4d0bSDariusz Sosnowski 				RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
226bf5c4d0bSDariusz Sosnowski 	if (!priv->hws_mpool) {
227bf5c4d0bSDariusz Sosnowski 		ret = ENOMEM;
228bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
229bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
230bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter ipool allocation failed.");
231bf5c4d0bSDariusz Sosnowski 		goto err;
232bf5c4d0bSDariusz Sosnowski 	}
233bf5c4d0bSDariusz Sosnowski 	priv->hws_mpool->devx_obj = priv->mtr_bulk.devx_obj;
234bf5c4d0bSDariusz Sosnowski 	priv->hws_mpool->action = priv->mtr_bulk.action;
235bf5c4d0bSDariusz Sosnowski 	priv->hws_mpool->nb_sq = nb_queues;
236bf5c4d0bSDariusz Sosnowski 	if (mlx5_aso_mtr_queue_init(priv->sh, priv->hws_mpool,
237bf5c4d0bSDariusz Sosnowski 				    &priv->sh->mtrmng->pools_mng, nb_queues)) {
238bf5c4d0bSDariusz Sosnowski 		ret = ENOMEM;
239bf5c4d0bSDariusz Sosnowski 		rte_flow_error_set(&error, ENOMEM,
240bf5c4d0bSDariusz Sosnowski 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
241bf5c4d0bSDariusz Sosnowski 				  NULL, "Meter ASO queue allocation failed.");
242bf5c4d0bSDariusz Sosnowski 		goto err;
243bf5c4d0bSDariusz Sosnowski 	}
244bf5c4d0bSDariusz Sosnowski 	/*
245bf5c4d0bSDariusz Sosnowski 	 * No need for local cache if Meter number is a small number.
246bf5c4d0bSDariusz Sosnowski 	 * Since flow insertion rate will be very limited in that case.
247bf5c4d0bSDariusz Sosnowski 	 * Here let's set the number to less than default trunk size 4K.
248bf5c4d0bSDariusz Sosnowski 	 */
249bf5c4d0bSDariusz Sosnowski 	if (nb_mtrs <= cfg.trunk_size) {
250bf5c4d0bSDariusz Sosnowski 		cfg.per_core_cache = 0;
251bf5c4d0bSDariusz Sosnowski 		cfg.trunk_size = nb_mtrs;
252bf5c4d0bSDariusz Sosnowski 	} else if (nb_mtrs <= MLX5_HW_IPOOL_SIZE_THRESHOLD) {
253bf5c4d0bSDariusz Sosnowski 		cfg.per_core_cache = MLX5_HW_IPOOL_CACHE_MIN;
254bf5c4d0bSDariusz Sosnowski 	}
255bf5c4d0bSDariusz Sosnowski 	priv->hws_mpool->idx_pool = mlx5_ipool_create(&cfg);
256bf5c4d0bSDariusz Sosnowski 	if (nb_meter_profiles) {
257bf5c4d0bSDariusz Sosnowski 		priv->mtr_config.nb_meter_profiles = nb_meter_profiles;
258bf5c4d0bSDariusz Sosnowski 		priv->mtr_profile_arr =
259bf5c4d0bSDariusz Sosnowski 			mlx5_malloc(MLX5_MEM_ZERO,
260bf5c4d0bSDariusz Sosnowski 				    sizeof(struct mlx5_flow_meter_profile) *
261bf5c4d0bSDariusz Sosnowski 				    nb_meter_profiles,
262bf5c4d0bSDariusz Sosnowski 				    RTE_CACHE_LINE_SIZE,
263bf5c4d0bSDariusz Sosnowski 				    SOCKET_ID_ANY);
264bf5c4d0bSDariusz Sosnowski 		if (!priv->mtr_profile_arr) {
265bf5c4d0bSDariusz Sosnowski 			ret = ENOMEM;
266bf5c4d0bSDariusz Sosnowski 			rte_flow_error_set(&error, ENOMEM,
267bf5c4d0bSDariusz Sosnowski 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
268bf5c4d0bSDariusz Sosnowski 					   NULL, "Meter profile allocation failed.");
269bf5c4d0bSDariusz Sosnowski 			goto err;
270bf5c4d0bSDariusz Sosnowski 		}
271bf5c4d0bSDariusz Sosnowski 	}
272bf5c4d0bSDariusz Sosnowski 	if (nb_meter_policies) {
273bf5c4d0bSDariusz Sosnowski 		priv->mtr_config.nb_meter_policies = nb_meter_policies;
274bf5c4d0bSDariusz Sosnowski 		priv->mtr_policy_arr =
275bf5c4d0bSDariusz Sosnowski 			mlx5_malloc(MLX5_MEM_ZERO,
276bf5c4d0bSDariusz Sosnowski 				    sizeof(struct mlx5_flow_meter_policy) *
277bf5c4d0bSDariusz Sosnowski 				    nb_meter_policies,
278bf5c4d0bSDariusz Sosnowski 				    RTE_CACHE_LINE_SIZE,
279bf5c4d0bSDariusz Sosnowski 				    SOCKET_ID_ANY);
280bf5c4d0bSDariusz Sosnowski 		if (!priv->mtr_policy_arr) {
281bf5c4d0bSDariusz Sosnowski 			ret = ENOMEM;
282bf5c4d0bSDariusz Sosnowski 			rte_flow_error_set(&error, ENOMEM,
283bf5c4d0bSDariusz Sosnowski 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
284bf5c4d0bSDariusz Sosnowski 					   NULL, "Meter policy allocation failed.");
285bf5c4d0bSDariusz Sosnowski 			goto err;
286bf5c4d0bSDariusz Sosnowski 		}
287bf5c4d0bSDariusz Sosnowski 	}
288bf5c4d0bSDariusz Sosnowski 	return 0;
289bf5c4d0bSDariusz Sosnowski err:
290bf5c4d0bSDariusz Sosnowski 	mlx5_flow_meter_uninit(dev);
291bf5c4d0bSDariusz Sosnowski 	return ret;
292bf5c4d0bSDariusz Sosnowski }
293bf5c4d0bSDariusz Sosnowski 
294bf5c4d0bSDariusz Sosnowski #endif /* HAVE_MLX5_HWS_SUPPORT */
295bf5c4d0bSDariusz Sosnowski 
296c3130c78SRongwei Liu static int mlx5_flow_meter_disable(struct rte_eth_dev *dev,
297c3130c78SRongwei Liu 		uint32_t meter_id, struct rte_mtr_error *error);
298c3130c78SRongwei Liu 
2996bc327b9SSuanming Mou /**
300266e9f3dSSuanming Mou  * Create the meter action.
301266e9f3dSSuanming Mou  *
302266e9f3dSSuanming Mou  * @param priv
303266e9f3dSSuanming Mou  *   Pointer to mlx5_priv.
304266e9f3dSSuanming Mou  * @param[in] fm
305266e9f3dSSuanming Mou  *   Pointer to flow meter to be converted.
306266e9f3dSSuanming Mou  *
307266e9f3dSSuanming Mou  * @return
308266e9f3dSSuanming Mou  *   Pointer to the meter action on success, NULL otherwise.
309266e9f3dSSuanming Mou  */
310266e9f3dSSuanming Mou static void *
311266e9f3dSSuanming Mou mlx5_flow_meter_action_create(struct mlx5_priv *priv,
312e6100c7bSLi Zhang 			      struct mlx5_flow_meter_info *fm)
313266e9f3dSSuanming Mou {
314266e9f3dSSuanming Mou #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
315266e9f3dSSuanming Mou 	struct mlx5dv_dr_flow_meter_attr mtr_init;
316e6100c7bSLi Zhang 	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
317266e9f3dSSuanming Mou 	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
318266e9f3dSSuanming Mou 						     &fm->profile->srtcm_prm;
319e6100c7bSLi Zhang 	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
320e6100c7bSLi Zhang 	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
321e6100c7bSLi Zhang 	uint32_t val;
322afb4aa4fSLi Zhang 	enum mlx5_meter_domain domain =
323afb4aa4fSLi Zhang 		fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
324afb4aa4fSLi Zhang 			fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
325afb4aa4fSLi Zhang 				MLX5_MTR_DOMAIN_INGRESS;
326afb4aa4fSLi Zhang 	struct mlx5_flow_meter_def_policy *def_policy =
327afb4aa4fSLi Zhang 		priv->sh->mtrmng->def_policy[domain];
328266e9f3dSSuanming Mou 
329e6100c7bSLi Zhang 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
330e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
331e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1);
332e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp,
333266e9f3dSSuanming Mou 		start_color, MLX5_FLOW_COLOR_GREEN);
334e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0);
335e6100c7bSLi Zhang 	val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
336e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val);
337e6100c7bSLi Zhang 	val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
338e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val);
33933a7493cSBing Zhao 	val = (cbs_cir >> ASO_DSEG_XIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
340e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val);
341e6100c7bSLi Zhang 	val = (cbs_cir & ASO_DSEG_MAN_MASK);
342e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val);
343e6100c7bSLi Zhang 	val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
344e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
345e6100c7bSLi Zhang 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
346e6100c7bSLi Zhang 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
347afb4aa4fSLi Zhang 	mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
3485e9f9a28SGregory Etelson 	mtr_init.reg_c_index = priv->sh->registers.aso_reg - REG_C_0;
349e6100c7bSLi Zhang 	mtr_init.flow_meter_parameter = fmp;
350e6100c7bSLi Zhang 	mtr_init.flow_meter_parameter_sz =
351e6100c7bSLi Zhang 		MLX5_ST_SZ_BYTES(flow_meter_parameters);
352266e9f3dSSuanming Mou 	mtr_init.active = fm->active_state;
353266e9f3dSSuanming Mou 	return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
354266e9f3dSSuanming Mou #else
355266e9f3dSSuanming Mou 	(void)priv;
356266e9f3dSSuanming Mou 	(void)fm;
357266e9f3dSSuanming Mou 	return NULL;
358266e9f3dSSuanming Mou #endif
359266e9f3dSSuanming Mou }
360266e9f3dSSuanming Mou 
361266e9f3dSSuanming Mou /**
3623bd26b23SSuanming Mou  * Find meter profile by id.
3633bd26b23SSuanming Mou  *
3643bd26b23SSuanming Mou  * @param priv
3653bd26b23SSuanming Mou  *   Pointer to mlx5_priv.
3663bd26b23SSuanming Mou  * @param meter_profile_id
3673bd26b23SSuanming Mou  *   Meter profile id.
3683bd26b23SSuanming Mou  *
3693bd26b23SSuanming Mou  * @return
3703bd26b23SSuanming Mou  *   Pointer to the profile found on success, NULL otherwise.
3713bd26b23SSuanming Mou  */
3723bd26b23SSuanming Mou static struct mlx5_flow_meter_profile *
3733bd26b23SSuanming Mou mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
3743bd26b23SSuanming Mou {
3753bd26b23SSuanming Mou 	struct mlx5_flow_meter_profile *fmp;
376a295c69aSShun Hao 	union mlx5_l3t_data data;
377a295c69aSShun Hao 	int32_t ret;
3783bd26b23SSuanming Mou 
37924865366SAlexander Kozyrev 	if (priv->mtr_profile_arr)
38024865366SAlexander Kozyrev 		return &priv->mtr_profile_arr[meter_profile_id];
3814dd46d38SShun Hao 	if (!priv->mtr_profile_tbl ||
3824dd46d38SShun Hao 	    mlx5_l3t_get_entry(priv->mtr_profile_tbl, meter_profile_id, &data) || !data.ptr)
3833bd26b23SSuanming Mou 		return NULL;
384a295c69aSShun Hao 	fmp = data.ptr;
385a295c69aSShun Hao 	/* Remove reference taken by the mlx5_l3t_get_entry. */
386a295c69aSShun Hao 	ret = mlx5_l3t_clear_entry(priv->mtr_profile_tbl,
387a295c69aSShun Hao 				   meter_profile_id);
388a295c69aSShun Hao 	if (!ret || ret == -1)
389a295c69aSShun Hao 		return NULL;
390a295c69aSShun Hao 	return fmp;
3913bd26b23SSuanming Mou }
3923bd26b23SSuanming Mou 
3933bd26b23SSuanming Mou /**
394e0583a52SSuanming Mou  * Validate the MTR profile.
395e0583a52SSuanming Mou  *
396e0583a52SSuanming Mou  * @param[in] dev
397e0583a52SSuanming Mou  *   Pointer to Ethernet device.
398e0583a52SSuanming Mou  * @param[in] meter_profile_id
399e0583a52SSuanming Mou  *   Meter profile id.
400e0583a52SSuanming Mou  * @param[in] profile
401e0583a52SSuanming Mou  *   Pointer to meter profile detail.
402e0583a52SSuanming Mou  * @param[out] error
403e0583a52SSuanming Mou  *   Pointer to the error structure.
404e0583a52SSuanming Mou  *
405e0583a52SSuanming Mou  * @return
406e0583a52SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
407e0583a52SSuanming Mou  */
408e0583a52SSuanming Mou static int
409e0583a52SSuanming Mou mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
410e0583a52SSuanming Mou 				 uint32_t meter_profile_id,
411e0583a52SSuanming Mou 				 struct rte_mtr_meter_profile *profile,
412e0583a52SSuanming Mou 				 struct rte_mtr_error *error)
413e0583a52SSuanming Mou {
414e0583a52SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
415e0583a52SSuanming Mou 	struct mlx5_flow_meter_profile *fmp;
4168a0fca11SBing Zhao 	uint32_t ls_factor;
4178a0fca11SBing Zhao 	int ret;
4188a0fca11SBing Zhao 	uint64_t cir, cbs;
4198a0fca11SBing Zhao 	uint64_t eir, ebs;
4208a0fca11SBing Zhao 	uint64_t pir, pbs;
421e0583a52SSuanming Mou 
422e0583a52SSuanming Mou 	/* Profile must not be NULL. */
423e0583a52SSuanming Mou 	if (profile == NULL)
424e0583a52SSuanming Mou 		return -rte_mtr_error_set(error, EINVAL,
425e0583a52SSuanming Mou 					  RTE_MTR_ERROR_TYPE_METER_PROFILE,
426e0583a52SSuanming Mou 					  NULL, "Meter profile is null.");
427e0583a52SSuanming Mou 	/* Meter profile ID must be valid. */
42824865366SAlexander Kozyrev 	if (priv->mtr_profile_arr) {
42924865366SAlexander Kozyrev 		if (meter_profile_id >= priv->mtr_config.nb_meter_profiles)
43024865366SAlexander Kozyrev 			return -rte_mtr_error_set(error, EINVAL,
43124865366SAlexander Kozyrev 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
43224865366SAlexander Kozyrev 					NULL, "Meter profile id not valid.");
43324865366SAlexander Kozyrev 		fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
43424865366SAlexander Kozyrev 		/* Meter profile must not exist. */
43524865366SAlexander Kozyrev 		if (fmp->initialized)
43624865366SAlexander Kozyrev 			return -rte_mtr_error_set(error, EEXIST,
43724865366SAlexander Kozyrev 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
43824865366SAlexander Kozyrev 					NULL, "Meter profile already exists.");
43924865366SAlexander Kozyrev 	} else {
440e0583a52SSuanming Mou 		if (meter_profile_id == UINT32_MAX)
441e0583a52SSuanming Mou 			return -rte_mtr_error_set(error, EINVAL,
442e0583a52SSuanming Mou 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
443e0583a52SSuanming Mou 					NULL, "Meter profile id not valid.");
444e0583a52SSuanming Mou 		fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
44524865366SAlexander Kozyrev 		/* Meter profile must not exist. */
446e0583a52SSuanming Mou 		if (fmp)
447e0583a52SSuanming Mou 			return -rte_mtr_error_set(error, EEXIST,
448e0583a52SSuanming Mou 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
44924865366SAlexander Kozyrev 					NULL, "Meter profile already exists.");
45024865366SAlexander Kozyrev 	}
4518a0fca11SBing Zhao 	if (!priv->sh->meter_aso_en) {
4528a0fca11SBing Zhao 		/* Old version is even not supported. */
45353820561SMichael Baum 		if (!priv->sh->cdev->config.hca_attr.qos.flow_meter_old)
454e0583a52SSuanming Mou 			return -rte_mtr_error_set(error, ENOTSUP,
455e0583a52SSuanming Mou 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
4568a0fca11SBing Zhao 				NULL, "Metering is not supported.");
4578a0fca11SBing Zhao 		/* Old FW metering only supports srTCM. */
4588a0fca11SBing Zhao 		if (profile->alg != RTE_MTR_SRTCM_RFC2697) {
4598a0fca11SBing Zhao 			return -rte_mtr_error_set(error, ENOTSUP,
4608a0fca11SBing Zhao 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
4618a0fca11SBing Zhao 				NULL, "Metering algorithm is not supported.");
4628a0fca11SBing Zhao 		} else if (profile->srtcm_rfc2697.ebs) {
4638a0fca11SBing Zhao 			/* EBS is not supported for old metering. */
4648a0fca11SBing Zhao 			return -rte_mtr_error_set(error, ENOTSUP,
4658a0fca11SBing Zhao 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
4668a0fca11SBing Zhao 				NULL, "EBS is not supported.");
4678a0fca11SBing Zhao 		}
4688a0fca11SBing Zhao 		if (profile->packet_mode)
4698a0fca11SBing Zhao 			return -rte_mtr_error_set(error, ENOTSUP,
4708a0fca11SBing Zhao 				RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
4718a0fca11SBing Zhao 				"Metering algorithm packet mode is not supported.");
4728a0fca11SBing Zhao 	}
4738a0fca11SBing Zhao 	ls_factor = profile->packet_mode ? MLX5_MTRS_PPS_MAP_BPS_SHIFT : 0;
4748a0fca11SBing Zhao 	switch (profile->alg) {
4758a0fca11SBing Zhao 	case RTE_MTR_SRTCM_RFC2697:
4768a0fca11SBing Zhao 		cir = profile->srtcm_rfc2697.cir << ls_factor;
4778a0fca11SBing Zhao 		cbs = profile->srtcm_rfc2697.cbs << ls_factor;
4788a0fca11SBing Zhao 		ebs = profile->srtcm_rfc2697.ebs << ls_factor;
4798a0fca11SBing Zhao 		/* EBS could be zero for old metering. */
4808a0fca11SBing Zhao 		if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX &&
4818a0fca11SBing Zhao 		    cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX &&
4828a0fca11SBing Zhao 		    ebs <= MLX5_SRTCM_XBS_MAX) {
4838a0fca11SBing Zhao 			ret = 0;
4848a0fca11SBing Zhao 		} else {
4858a0fca11SBing Zhao 			ret = -rte_mtr_error_set(error, ENOTSUP,
4868a0fca11SBing Zhao 					RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
4878a0fca11SBing Zhao 					"Profile values out of range.");
4888a0fca11SBing Zhao 		}
4898a0fca11SBing Zhao 		break;
4908a0fca11SBing Zhao 	case RTE_MTR_TRTCM_RFC2698:
4918a0fca11SBing Zhao 		cir = profile->trtcm_rfc2698.cir << ls_factor;
4928a0fca11SBing Zhao 		cbs = profile->trtcm_rfc2698.cbs << ls_factor;
4938a0fca11SBing Zhao 		pir = profile->trtcm_rfc2698.pir << ls_factor;
4948a0fca11SBing Zhao 		pbs = profile->trtcm_rfc2698.pbs << ls_factor;
4958a0fca11SBing Zhao 		if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX &&
4968a0fca11SBing Zhao 		    cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX &&
4978a0fca11SBing Zhao 		    pir >= cir && pir <= (MLX5_SRTCM_XIR_MAX * 2) &&
4988a0fca11SBing Zhao 		    pbs >= cbs && pbs <= (MLX5_SRTCM_XBS_MAX * 2)) {
4998a0fca11SBing Zhao 			ret = 0;
5008a0fca11SBing Zhao 		} else {
5018a0fca11SBing Zhao 			ret = -rte_mtr_error_set(error, ENOTSUP,
5028a0fca11SBing Zhao 					RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
5038a0fca11SBing Zhao 					"Profile values out of range.");
5048a0fca11SBing Zhao 		}
5058a0fca11SBing Zhao 		break;
5068a0fca11SBing Zhao 	case RTE_MTR_TRTCM_RFC4115:
5078a0fca11SBing Zhao 		cir = profile->trtcm_rfc4115.cir << ls_factor;
5088a0fca11SBing Zhao 		cbs = profile->trtcm_rfc4115.cbs << ls_factor;
5098a0fca11SBing Zhao 		eir = profile->trtcm_rfc4115.eir << ls_factor;
5108a0fca11SBing Zhao 		ebs = profile->trtcm_rfc4115.ebs << ls_factor;
5118a0fca11SBing Zhao 		if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX &&
5128a0fca11SBing Zhao 		    cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX &&
5138a0fca11SBing Zhao 		    eir <= MLX5_SRTCM_XIR_MAX && ebs <= MLX5_SRTCM_XBS_MAX) {
5148a0fca11SBing Zhao 			ret = 0;
5158a0fca11SBing Zhao 		} else {
5168a0fca11SBing Zhao 			ret = -rte_mtr_error_set(error, ENOTSUP,
5178a0fca11SBing Zhao 					RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
5188a0fca11SBing Zhao 					"Profile values out of range.");
5198a0fca11SBing Zhao 		}
5208a0fca11SBing Zhao 		break;
5218a0fca11SBing Zhao 	default:
5228a0fca11SBing Zhao 		ret = -rte_mtr_error_set(error, ENOTSUP,
5238a0fca11SBing Zhao 					 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
5248a0fca11SBing Zhao 					 "Unknown metering algorithm.");
5258a0fca11SBing Zhao 		break;
5268a0fca11SBing Zhao 	}
5278a0fca11SBing Zhao 	return ret;
528e0583a52SSuanming Mou }
529e0583a52SSuanming Mou 
53033a7493cSBing Zhao /*
53133a7493cSBing Zhao  * Calculate mantissa and exponent for cir / eir.
5323bd26b23SSuanming Mou  *
53333a7493cSBing Zhao  * @param[in] xir
5343bd26b23SSuanming Mou  *   Value to be calculated.
5353bd26b23SSuanming Mou  * @param[out] man
5363bd26b23SSuanming Mou  *   Pointer to the mantissa.
5373bd26b23SSuanming Mou  * @param[out] exp
5383bd26b23SSuanming Mou  *   Pointer to the exp.
5393bd26b23SSuanming Mou  */
54033a7493cSBing Zhao static inline void
54133a7493cSBing Zhao mlx5_flow_meter_xir_man_exp_calc(int64_t xir, uint8_t *man, uint8_t *exp)
5423bd26b23SSuanming Mou {
543a9e3a4a9SBing Zhao 	int64_t _xir;
5443bd26b23SSuanming Mou 	int64_t delta = INT64_MAX;
5453bd26b23SSuanming Mou 	uint8_t _man = 0;
5463bd26b23SSuanming Mou 	uint8_t _exp = 0;
5473bd26b23SSuanming Mou 	uint64_t m, e;
5483bd26b23SSuanming Mou 
5497be78d02SJosh Soref 	/* Special case xir == 0 ? both exp and mantissa are 0. */
550a9e3a4a9SBing Zhao 	if (xir == 0) {
551a9e3a4a9SBing Zhao 		*man = 0;
552a9e3a4a9SBing Zhao 		*exp = 0;
553a9e3a4a9SBing Zhao 		return;
554a9e3a4a9SBing Zhao 	}
5553bd26b23SSuanming Mou 	for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
5563bd26b23SSuanming Mou 		for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
557a9e3a4a9SBing Zhao 			_xir = (1000000000ULL * m) >> e;
558a9e3a4a9SBing Zhao 			if (llabs(xir - _xir) <= delta) {
559a9e3a4a9SBing Zhao 				delta = llabs(xir - _xir);
5603bd26b23SSuanming Mou 				_man = m;
5613bd26b23SSuanming Mou 				_exp = e;
5623bd26b23SSuanming Mou 			}
5633bd26b23SSuanming Mou 		}
5643bd26b23SSuanming Mou 	}
5653bd26b23SSuanming Mou 	*man = _man;
5663bd26b23SSuanming Mou 	*exp = _exp;
5673bd26b23SSuanming Mou }
5683bd26b23SSuanming Mou 
56933a7493cSBing Zhao /*
5703bd26b23SSuanming Mou  * Calculate mantissa and exponent for xbs.
5713bd26b23SSuanming Mou  *
5723bd26b23SSuanming Mou  * @param[in] xbs
5733bd26b23SSuanming Mou  *   Value to be calculated.
5743bd26b23SSuanming Mou  * @param[out] man
5753bd26b23SSuanming Mou  *   Pointer to the mantissa.
5763bd26b23SSuanming Mou  * @param[out] exp
5773bd26b23SSuanming Mou  *   Pointer to the exp.
5783bd26b23SSuanming Mou  */
57933a7493cSBing Zhao static inline void
5803bd26b23SSuanming Mou mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
5813bd26b23SSuanming Mou {
5823bd26b23SSuanming Mou 	int _exp;
5833bd26b23SSuanming Mou 	double _man;
5843bd26b23SSuanming Mou 
5857be78d02SJosh Soref 	/* Special case xbs == 0 ? both exp and mantissa are 0. */
5863bd26b23SSuanming Mou 	if (xbs == 0) {
5873bd26b23SSuanming Mou 		*man = 0;
5883bd26b23SSuanming Mou 		*exp = 0;
5893bd26b23SSuanming Mou 		return;
5903bd26b23SSuanming Mou 	}
5913bd26b23SSuanming Mou 	/* xbs = xbs_mantissa * 2^xbs_exponent */
5923bd26b23SSuanming Mou 	_man = frexp(xbs, &_exp);
59321fdeab4SAlexander Kozyrev 	if (_exp >= MLX5_MAN_WIDTH) {
5943bd26b23SSuanming Mou 		_man = _man * pow(2, MLX5_MAN_WIDTH);
5953bd26b23SSuanming Mou 		_exp = _exp - MLX5_MAN_WIDTH;
59621fdeab4SAlexander Kozyrev 	}
5973bd26b23SSuanming Mou 	*man = (uint8_t)ceil(_man);
5983bd26b23SSuanming Mou 	*exp = _exp;
5993bd26b23SSuanming Mou }
6003bd26b23SSuanming Mou 
6013bd26b23SSuanming Mou /**
6023bd26b23SSuanming Mou  * Fill the prm meter parameter.
6033bd26b23SSuanming Mou  *
6043bd26b23SSuanming Mou  * @param[in,out] fmp
6057be78d02SJosh Soref  *   Pointer to meter profile to be converted.
6063bd26b23SSuanming Mou  * @param[out] error
6073bd26b23SSuanming Mou  *   Pointer to the error structure.
6083bd26b23SSuanming Mou  *
6093bd26b23SSuanming Mou  * @return
6103bd26b23SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
6113bd26b23SSuanming Mou  */
6123bd26b23SSuanming Mou static int
6133bd26b23SSuanming Mou mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
6148a0fca11SBing Zhao 			   struct rte_mtr_error *error)
6153bd26b23SSuanming Mou {
6163bd26b23SSuanming Mou 	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
6173bd26b23SSuanming Mou 	uint8_t man, exp;
618e6100c7bSLi Zhang 	uint32_t cbs_exp, cbs_man, cir_exp, cir_man;
61933a7493cSBing Zhao 	uint32_t eir_exp, eir_man, ebs_exp, ebs_man;
62033a7493cSBing Zhao 	uint64_t cir, cbs, eir, ebs;
6213bd26b23SSuanming Mou 
62233a7493cSBing Zhao 	switch (fmp->profile.alg) {
62333a7493cSBing Zhao 	case RTE_MTR_SRTCM_RFC2697:
624aa065a9cSLi Zhang 		cir = fmp->profile.srtcm_rfc2697.cir;
625aa065a9cSLi Zhang 		cbs = fmp->profile.srtcm_rfc2697.cbs;
62633a7493cSBing Zhao 		eir = 0;
627aa065a9cSLi Zhang 		ebs = fmp->profile.srtcm_rfc2697.ebs;
62833a7493cSBing Zhao 		break;
62933a7493cSBing Zhao 	case RTE_MTR_TRTCM_RFC2698:
63033a7493cSBing Zhao 		MLX5_ASSERT(fmp->profile.trtcm_rfc2698.pir >
63133a7493cSBing Zhao 			    fmp->profile.trtcm_rfc2698.cir &&
63233a7493cSBing Zhao 			    fmp->profile.trtcm_rfc2698.pbs >
63333a7493cSBing Zhao 			    fmp->profile.trtcm_rfc2698.cbs);
63433a7493cSBing Zhao 		cir = fmp->profile.trtcm_rfc2698.cir;
63533a7493cSBing Zhao 		cbs = fmp->profile.trtcm_rfc2698.cbs;
63633a7493cSBing Zhao 		/* EIR / EBS are filled with PIR / PBS. */
63733a7493cSBing Zhao 		eir = fmp->profile.trtcm_rfc2698.pir;
63833a7493cSBing Zhao 		ebs = fmp->profile.trtcm_rfc2698.pbs;
63933a7493cSBing Zhao 		break;
64033a7493cSBing Zhao 	case RTE_MTR_TRTCM_RFC4115:
64133a7493cSBing Zhao 		cir = fmp->profile.trtcm_rfc4115.cir;
64233a7493cSBing Zhao 		cbs = fmp->profile.trtcm_rfc4115.cbs;
64333a7493cSBing Zhao 		eir = fmp->profile.trtcm_rfc4115.eir;
64433a7493cSBing Zhao 		ebs = fmp->profile.trtcm_rfc4115.ebs;
64533a7493cSBing Zhao 		break;
64633a7493cSBing Zhao 	default:
64733a7493cSBing Zhao 		return -rte_mtr_error_set(error, EINVAL,
64833a7493cSBing Zhao 				RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
64933a7493cSBing Zhao 				"Metering algorithm mode is invalid");
65033a7493cSBing Zhao 	}
65133a7493cSBing Zhao 	/* Adjust the values for PPS mode. */
65233a7493cSBing Zhao 	if (fmp->profile.packet_mode) {
65333a7493cSBing Zhao 		cir <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
65433a7493cSBing Zhao 		cbs <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
65533a7493cSBing Zhao 		eir <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
65633a7493cSBing Zhao 		ebs <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
657aa065a9cSLi Zhang 	}
6583bd26b23SSuanming Mou 	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
65933a7493cSBing Zhao 	mlx5_flow_meter_xir_man_exp_calc(cir, &man, &exp);
6603bd26b23SSuanming Mou 	/* Check if cir mantissa is too large. */
66133a7493cSBing Zhao 	if (exp > ASO_DSEG_XIR_EXP_MASK)
662e6100c7bSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
6633bd26b23SSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
66433a7493cSBing Zhao 					  "meter profile parameter cir is not supported.");
665e6100c7bSLi Zhang 	cir_man = man;
666e6100c7bSLi Zhang 	cir_exp = exp;
667e6100c7bSLi Zhang 	 /* cbs = cbs_mantissa * 2^cbs_exponent */
668aa065a9cSLi Zhang 	mlx5_flow_meter_xbs_man_exp_calc(cbs, &man, &exp);
669e6100c7bSLi Zhang 	/* Check if cbs mantissa is too large. */
670e6100c7bSLi Zhang 	if (exp > ASO_DSEG_EXP_MASK)
671e6100c7bSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
672e6100c7bSLi Zhang 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
67333a7493cSBing Zhao 					  "meter profile parameter cbs is not supported.");
674e6100c7bSLi Zhang 	cbs_man = man;
675e6100c7bSLi Zhang 	cbs_exp = exp;
676e6100c7bSLi Zhang 	srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET |
677e6100c7bSLi Zhang 					  cbs_man << ASO_DSEG_CBS_MAN_OFFSET |
67833a7493cSBing Zhao 					  cir_exp << ASO_DSEG_XIR_EXP_OFFSET |
679e6100c7bSLi Zhang 					  cir_man);
68033a7493cSBing Zhao 	mlx5_flow_meter_xir_man_exp_calc(eir, &man, &exp);
68133a7493cSBing Zhao 	/* Check if eir mantissa is too large. */
68233a7493cSBing Zhao 	if (exp > ASO_DSEG_XIR_EXP_MASK)
68333a7493cSBing Zhao 		return -rte_mtr_error_set(error, ENOTSUP,
68433a7493cSBing Zhao 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
68533a7493cSBing Zhao 					  "meter profile parameter eir is not supported.");
68633a7493cSBing Zhao 	eir_man = man;
68733a7493cSBing Zhao 	eir_exp = exp;
688aa065a9cSLi Zhang 	mlx5_flow_meter_xbs_man_exp_calc(ebs, &man, &exp);
689e6100c7bSLi Zhang 	/* Check if ebs mantissa is too large. */
690e6100c7bSLi Zhang 	if (exp > ASO_DSEG_EXP_MASK)
691e6100c7bSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
692e6100c7bSLi Zhang 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
69333a7493cSBing Zhao 					  "meter profile parameter ebs is not supported.");
694e6100c7bSLi Zhang 	ebs_man = man;
695e6100c7bSLi Zhang 	ebs_exp = exp;
696e6100c7bSLi Zhang 	srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET |
69733a7493cSBing Zhao 					  ebs_man << ASO_DSEG_EBS_MAN_OFFSET |
69833a7493cSBing Zhao 					  eir_exp << ASO_DSEG_XIR_EXP_OFFSET |
69933a7493cSBing Zhao 					  eir_man);
7004d648fadSBing Zhao 	if (srtcm->cbs_cir)
7014d648fadSBing Zhao 		fmp->g_support = 1;
7024d648fadSBing Zhao 	if (srtcm->ebs_eir)
7034d648fadSBing Zhao 		fmp->y_support = 1;
7043bd26b23SSuanming Mou 	return 0;
7053bd26b23SSuanming Mou }
7063bd26b23SSuanming Mou 
7073bd26b23SSuanming Mou /**
708bae983b8SMaayan Kashani  * Callback to get MTR maximum objects number.
709bae983b8SMaayan Kashani  *
710bae983b8SMaayan Kashani  * @param[in] priv
711bae983b8SMaayan Kashani  *   Pointer to Ethernet device.
712bae983b8SMaayan Kashani  *
713bae983b8SMaayan Kashani  * @return
714bae983b8SMaayan Kashani  *   Max number of meters.
715bae983b8SMaayan Kashani  */
716bae983b8SMaayan Kashani uint32_t
717bae983b8SMaayan Kashani mlx5_flow_mtr_max_get(struct mlx5_priv *priv)
718bae983b8SMaayan Kashani {
719bae983b8SMaayan Kashani 	struct mlx5_hca_qos_attr *qattr = &priv->sh->cdev->config.hca_attr.qos;
720bae983b8SMaayan Kashani 
721bae983b8SMaayan Kashani 	/* Max number of meters. */
722bae983b8SMaayan Kashani 	return ((priv->sh->meter_aso_en) ?
723bae983b8SMaayan Kashani 	1 << (qattr->log_max_num_meter_aso + 1) :
724bae983b8SMaayan Kashani 	qattr->log_max_flow_meter);
725bae983b8SMaayan Kashani }
726bae983b8SMaayan Kashani 
727bae983b8SMaayan Kashani /**
7286bc327b9SSuanming Mou  * Callback to get MTR capabilities.
7296bc327b9SSuanming Mou  *
7306bc327b9SSuanming Mou  * @param[in] dev
7316bc327b9SSuanming Mou  *   Pointer to Ethernet device.
7326bc327b9SSuanming Mou  * @param[out] cap
7336bc327b9SSuanming Mou  *   Pointer to save MTR capabilities.
7346bc327b9SSuanming Mou  * @param[out] error
7356bc327b9SSuanming Mou  *   Pointer to the error structure.
7366bc327b9SSuanming Mou  *
7376bc327b9SSuanming Mou  * @return
7386bc327b9SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
7396bc327b9SSuanming Mou  */
7406bc327b9SSuanming Mou static int
7416bc327b9SSuanming Mou mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
7426bc327b9SSuanming Mou 		 struct rte_mtr_capabilities *cap,
7436bc327b9SSuanming Mou 		 struct rte_mtr_error *error __rte_unused)
7446bc327b9SSuanming Mou {
7456bc327b9SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
74653820561SMichael Baum 	struct mlx5_hca_qos_attr *qattr = &priv->sh->cdev->config.hca_attr.qos;
7476bc327b9SSuanming Mou 
748*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL))
749*61a81061SGregory Etelson 		return -rte_mtr_error_set(error, EINVAL,
750*61a81061SGregory Etelson 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
751*61a81061SGregory Etelson 					  "non-template flow engine was not configured");
7526bc327b9SSuanming Mou 	if (!priv->mtr_en)
7536bc327b9SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
7546bc327b9SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
7553efac808SAli Alnubani 					  "Meter is not supported");
7566bc327b9SSuanming Mou 	memset(cap, 0, sizeof(*cap));
757bae983b8SMaayan Kashani 	cap->n_max = mlx5_flow_mtr_max_get(priv);
758aa065a9cSLi Zhang 	if (priv->sh->meter_aso_en) {
759aa065a9cSLi Zhang 		cap->srtcm_rfc2697_packet_mode_supported = 1;
760eb11edd9SAlexander Kozyrev 		cap->trtcm_rfc2698_packet_mode_supported = 1;
761eb11edd9SAlexander Kozyrev 		cap->trtcm_rfc4115_packet_mode_supported = 1;
762aa065a9cSLi Zhang 	}
763aa065a9cSLi Zhang 	cap->srtcm_rfc2697_byte_mode_supported = 1;
764eb11edd9SAlexander Kozyrev 	cap->trtcm_rfc2698_byte_mode_supported = 1;
765eb11edd9SAlexander Kozyrev 	cap->trtcm_rfc4115_byte_mode_supported = 1;
7666bc327b9SSuanming Mou 	cap->n_shared_max = cap->n_max;
7676bc327b9SSuanming Mou 	cap->identical = 1;
7686bc327b9SSuanming Mou 	cap->shared_identical = 1;
7696bc327b9SSuanming Mou 	cap->shared_n_flows_per_mtr_max = 4 << 20;
7706bc327b9SSuanming Mou 	/* 2M flows can share the same meter. */
7716bc327b9SSuanming Mou 	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
772b6505738SDekel Peled 	cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
773eb11edd9SAlexander Kozyrev 	cap->meter_trtcm_rfc2698_n_max = qattr->flow_meter_old ? cap->n_max : 0;
774eb11edd9SAlexander Kozyrev 	cap->meter_trtcm_rfc4115_n_max = qattr->flow_meter_old ? cap->n_max : 0;
7756bc327b9SSuanming Mou 	cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
776eb11edd9SAlexander Kozyrev 	cap->meter_policy_n_max = cap->n_max;
7776bc327b9SSuanming Mou 	cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
7786bc327b9SSuanming Mou 			  RTE_MTR_STATS_N_PKTS_DROPPED;
7796bc327b9SSuanming Mou 	return 0;
7806bc327b9SSuanming Mou }
781d740eb50SSuanming Mou 
7823bd26b23SSuanming Mou /**
7833bd26b23SSuanming Mou  * Callback to add MTR profile.
7843bd26b23SSuanming Mou  *
7853bd26b23SSuanming Mou  * @param[in] dev
7863bd26b23SSuanming Mou  *   Pointer to Ethernet device.
7873bd26b23SSuanming Mou  * @param[in] meter_profile_id
7883bd26b23SSuanming Mou  *   Meter profile id.
7893bd26b23SSuanming Mou  * @param[in] profile
7903bd26b23SSuanming Mou  *   Pointer to meter profile detail.
7913bd26b23SSuanming Mou  * @param[out] error
7923bd26b23SSuanming Mou  *   Pointer to the error structure.
7933bd26b23SSuanming Mou  *
7943bd26b23SSuanming Mou  * @return
7953bd26b23SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
7963bd26b23SSuanming Mou  */
7973bd26b23SSuanming Mou static int
7983bd26b23SSuanming Mou mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
7993bd26b23SSuanming Mou 		       uint32_t meter_profile_id,
8003bd26b23SSuanming Mou 		       struct rte_mtr_meter_profile *profile,
8013bd26b23SSuanming Mou 		       struct rte_mtr_error *error)
8023bd26b23SSuanming Mou {
8033bd26b23SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
8043bd26b23SSuanming Mou 	struct mlx5_flow_meter_profile *fmp;
805a295c69aSShun Hao 	union mlx5_l3t_data data;
8063bd26b23SSuanming Mou 	int ret;
8073bd26b23SSuanming Mou 
8083bd26b23SSuanming Mou 	if (!priv->mtr_en)
8093bd26b23SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
8103bd26b23SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
8113efac808SAli Alnubani 					  "Meter is not supported");
812e0583a52SSuanming Mou 	/* Check input params. */
813e0583a52SSuanming Mou 	ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
814e0583a52SSuanming Mou 					       profile, error);
815e0583a52SSuanming Mou 	if (ret)
816e0583a52SSuanming Mou 		return ret;
8173bd26b23SSuanming Mou 	/* Meter profile memory allocation. */
81883c2047cSSuanming Mou 	fmp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flow_meter_profile),
81983c2047cSSuanming Mou 			  RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
8203bd26b23SSuanming Mou 	if (fmp == NULL)
8213bd26b23SSuanming Mou 		return -rte_mtr_error_set(error, ENOMEM,
8223bd26b23SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
8233bd26b23SSuanming Mou 					  NULL, "Meter profile memory "
8243bd26b23SSuanming Mou 					  "alloc failed.");
8253bd26b23SSuanming Mou 	/* Fill profile info. */
826e6100c7bSLi Zhang 	fmp->id = meter_profile_id;
8273bd26b23SSuanming Mou 	fmp->profile = *profile;
8283bd26b23SSuanming Mou 	/* Fill the flow meter parameters for the PRM. */
8298a0fca11SBing Zhao 	ret = mlx5_flow_meter_param_fill(fmp, error);
8303bd26b23SSuanming Mou 	if (ret)
8313bd26b23SSuanming Mou 		goto error;
832a295c69aSShun Hao 	data.ptr = fmp;
833a295c69aSShun Hao 	ret = mlx5_l3t_set_entry(priv->mtr_profile_tbl,
834a295c69aSShun Hao 				 meter_profile_id, &data);
835a295c69aSShun Hao 	if (ret)
836a295c69aSShun Hao 		return -rte_mtr_error_set(error, ENOTSUP,
837a295c69aSShun Hao 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
838a295c69aSShun Hao 					  NULL, "Meter profile insert fail.");
8393bd26b23SSuanming Mou 	return 0;
8403bd26b23SSuanming Mou error:
84183c2047cSSuanming Mou 	mlx5_free(fmp);
8423bd26b23SSuanming Mou 	return ret;
8433bd26b23SSuanming Mou }
8443bd26b23SSuanming Mou 
8453bd26b23SSuanming Mou /**
8463bd26b23SSuanming Mou  * Callback to delete MTR profile.
8473bd26b23SSuanming Mou  *
8483bd26b23SSuanming Mou  * @param[in] dev
8493bd26b23SSuanming Mou  *   Pointer to Ethernet device.
8503bd26b23SSuanming Mou  * @param[in] meter_profile_id
8513bd26b23SSuanming Mou  *   Meter profile id.
8523bd26b23SSuanming Mou  * @param[out] error
8533bd26b23SSuanming Mou  *   Pointer to the error structure.
8543bd26b23SSuanming Mou  *
8553bd26b23SSuanming Mou  * @return
8563bd26b23SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
8573bd26b23SSuanming Mou  */
8583bd26b23SSuanming Mou static int
8593bd26b23SSuanming Mou mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
8603bd26b23SSuanming Mou 			  uint32_t meter_profile_id,
8613bd26b23SSuanming Mou 			  struct rte_mtr_error *error)
8623bd26b23SSuanming Mou {
8633bd26b23SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
8643bd26b23SSuanming Mou 	struct mlx5_flow_meter_profile *fmp;
8653bd26b23SSuanming Mou 
8663bd26b23SSuanming Mou 	if (!priv->mtr_en)
8673bd26b23SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
8683bd26b23SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
8693efac808SAli Alnubani 					  "Meter is not supported");
8703bd26b23SSuanming Mou 	/* Meter profile must exist. */
8713bd26b23SSuanming Mou 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
8723bd26b23SSuanming Mou 	if (fmp == NULL)
8733bd26b23SSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
8743bd26b23SSuanming Mou 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
8753bd26b23SSuanming Mou 					  &meter_profile_id,
8763efac808SAli Alnubani 					  "Meter profile id is invalid.");
8773bd26b23SSuanming Mou 	/* Check profile is unused. */
8783bd26b23SSuanming Mou 	if (fmp->ref_cnt)
8793bd26b23SSuanming Mou 		return -rte_mtr_error_set(error, EBUSY,
8803bd26b23SSuanming Mou 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
8813efac808SAli Alnubani 					  NULL, "Meter profile is in use.");
882a295c69aSShun Hao 	if (mlx5_l3t_clear_entry(priv->mtr_profile_tbl, meter_profile_id))
883a295c69aSShun Hao 		return -rte_mtr_error_set(error, EBUSY,
884a295c69aSShun Hao 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
885a295c69aSShun Hao 					  NULL, "Meter profile remove fail.");
88683c2047cSSuanming Mou 	mlx5_free(fmp);
8873bd26b23SSuanming Mou 	return 0;
8883bd26b23SSuanming Mou }
8893bd26b23SSuanming Mou 
8903f373f35SSuanming Mou /**
89148fbb0e9SAlexander Kozyrev  * Callback to get MTR profile.
89248fbb0e9SAlexander Kozyrev  *
89348fbb0e9SAlexander Kozyrev  * @param[in] dev
89448fbb0e9SAlexander Kozyrev  *   Pointer to Ethernet device.
89548fbb0e9SAlexander Kozyrev  * @param[in] meter_profile_id
89648fbb0e9SAlexander Kozyrev  *   Meter profile id.
89748fbb0e9SAlexander Kozyrev  * @param[out] error
89848fbb0e9SAlexander Kozyrev  *   Pointer to the error structure.
89948fbb0e9SAlexander Kozyrev  *
90048fbb0e9SAlexander Kozyrev  * @return
90148fbb0e9SAlexander Kozyrev  *   A valid handle in case of success, NULL otherwise.
90248fbb0e9SAlexander Kozyrev  */
90348fbb0e9SAlexander Kozyrev static struct rte_flow_meter_profile *
90448fbb0e9SAlexander Kozyrev mlx5_flow_meter_profile_get(struct rte_eth_dev *dev,
90548fbb0e9SAlexander Kozyrev 			  uint32_t meter_profile_id,
90648fbb0e9SAlexander Kozyrev 			  struct rte_mtr_error *error)
90748fbb0e9SAlexander Kozyrev {
90848fbb0e9SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
90948fbb0e9SAlexander Kozyrev 
910*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL)) {
911*61a81061SGregory Etelson 		rte_mtr_error_set(error, EINVAL,
912*61a81061SGregory Etelson 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
913*61a81061SGregory Etelson 				  "non-template flow engine was not configured");
914*61a81061SGregory Etelson 		return NULL;
915*61a81061SGregory Etelson 	}
91648fbb0e9SAlexander Kozyrev 	if (!priv->mtr_en) {
91748fbb0e9SAlexander Kozyrev 		rte_mtr_error_set(error, ENOTSUP,
91848fbb0e9SAlexander Kozyrev 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
91948fbb0e9SAlexander Kozyrev 				  "Meter is not supported");
92048fbb0e9SAlexander Kozyrev 		return NULL;
92148fbb0e9SAlexander Kozyrev 	}
92248fbb0e9SAlexander Kozyrev 	return (void *)(uintptr_t)mlx5_flow_meter_profile_find(priv,
92348fbb0e9SAlexander Kozyrev 							meter_profile_id);
92448fbb0e9SAlexander Kozyrev }
92548fbb0e9SAlexander Kozyrev 
9267576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
92748fbb0e9SAlexander Kozyrev /**
92824865366SAlexander Kozyrev  * Callback to add MTR profile with HWS.
92924865366SAlexander Kozyrev  *
93024865366SAlexander Kozyrev  * @param[in] dev
93124865366SAlexander Kozyrev  *   Pointer to Ethernet device.
93224865366SAlexander Kozyrev  * @param[in] meter_profile_id
93324865366SAlexander Kozyrev  *   Meter profile id.
93424865366SAlexander Kozyrev  * @param[in] profile
93524865366SAlexander Kozyrev  *   Pointer to meter profile detail.
93624865366SAlexander Kozyrev  * @param[out] error
93724865366SAlexander Kozyrev  *   Pointer to the error structure.
93824865366SAlexander Kozyrev  *
93924865366SAlexander Kozyrev  * @return
94024865366SAlexander Kozyrev  *   0 on success, a negative errno value otherwise and rte_errno is set.
94124865366SAlexander Kozyrev  */
94224865366SAlexander Kozyrev static int
94324865366SAlexander Kozyrev mlx5_flow_meter_profile_hws_add(struct rte_eth_dev *dev,
94424865366SAlexander Kozyrev 			uint32_t meter_profile_id,
94524865366SAlexander Kozyrev 			struct rte_mtr_meter_profile *profile,
94624865366SAlexander Kozyrev 			struct rte_mtr_error *error)
94724865366SAlexander Kozyrev {
94824865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
94924865366SAlexander Kozyrev 	struct mlx5_flow_meter_profile *fmp;
95024865366SAlexander Kozyrev 	int ret;
95124865366SAlexander Kozyrev 
952*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL))
953*61a81061SGregory Etelson 		return -rte_mtr_error_set(error, EINVAL,
954*61a81061SGregory Etelson 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
955*61a81061SGregory Etelson 					  "non-template flow engine was not configured");
956ddbb689bSDariusz Sosnowski 	if (priv->shared_host)
957ddbb689bSDariusz Sosnowski 		return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
958ddbb689bSDariusz Sosnowski 					  "Meter profiles cannot be created on guest port");
95924865366SAlexander Kozyrev 	if (!priv->mtr_profile_arr)
960077eb39fSAlexander Kozyrev 		return mlx5_flow_meter_profile_add(dev, meter_profile_id, profile, error);
96124865366SAlexander Kozyrev 	/* Check input params. */
96224865366SAlexander Kozyrev 	ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
96324865366SAlexander Kozyrev 					       profile, error);
96424865366SAlexander Kozyrev 	if (ret)
96524865366SAlexander Kozyrev 		return ret;
96624865366SAlexander Kozyrev 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
96724865366SAlexander Kozyrev 	/* Fill profile info. */
96824865366SAlexander Kozyrev 	fmp->id = meter_profile_id;
96924865366SAlexander Kozyrev 	fmp->profile = *profile;
97024865366SAlexander Kozyrev 	fmp->initialized = 1;
97124865366SAlexander Kozyrev 	/* Fill the flow meter parameters for the PRM. */
97224865366SAlexander Kozyrev 	return mlx5_flow_meter_param_fill(fmp, error);
97324865366SAlexander Kozyrev }
97424865366SAlexander Kozyrev 
97524865366SAlexander Kozyrev /**
97624865366SAlexander Kozyrev  * Callback to delete MTR profile with HWS.
97724865366SAlexander Kozyrev  *
97824865366SAlexander Kozyrev  * @param[in] dev
97924865366SAlexander Kozyrev  *   Pointer to Ethernet device.
98024865366SAlexander Kozyrev  * @param[in] meter_profile_id
98124865366SAlexander Kozyrev  *   Meter profile id.
98224865366SAlexander Kozyrev  * @param[out] error
98324865366SAlexander Kozyrev  *   Pointer to the error structure.
98424865366SAlexander Kozyrev  *
98524865366SAlexander Kozyrev  * @return
98624865366SAlexander Kozyrev  *   0 on success, a negative errno value otherwise and rte_errno is set.
98724865366SAlexander Kozyrev  */
98824865366SAlexander Kozyrev static int
98924865366SAlexander Kozyrev mlx5_flow_meter_profile_hws_delete(struct rte_eth_dev *dev,
99024865366SAlexander Kozyrev 			uint32_t meter_profile_id,
99124865366SAlexander Kozyrev 			struct rte_mtr_error *error)
99224865366SAlexander Kozyrev {
99324865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
99424865366SAlexander Kozyrev 	struct mlx5_flow_meter_profile *fmp;
99524865366SAlexander Kozyrev 
996ddbb689bSDariusz Sosnowski 	if (priv->shared_host)
997ddbb689bSDariusz Sosnowski 		return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
998ddbb689bSDariusz Sosnowski 					  "Meter profiles cannot be destroyed through guest port");
99924865366SAlexander Kozyrev 	if (!priv->mtr_profile_arr)
1000077eb39fSAlexander Kozyrev 		return mlx5_flow_meter_profile_delete(dev, meter_profile_id, error);
100124865366SAlexander Kozyrev 	/* Meter profile must exist. */
100224865366SAlexander Kozyrev 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
100324865366SAlexander Kozyrev 	if (!fmp->initialized)
100424865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOENT,
100524865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
100624865366SAlexander Kozyrev 					  &meter_profile_id,
100724865366SAlexander Kozyrev 					  "Meter profile id is invalid.");
100824865366SAlexander Kozyrev 	/* Check profile is unused. */
100924865366SAlexander Kozyrev 	if (fmp->ref_cnt)
101024865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, EBUSY,
101124865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
101224865366SAlexander Kozyrev 					  NULL, "Meter profile is in use.");
101324865366SAlexander Kozyrev 	memset(fmp, 0, sizeof(struct mlx5_flow_meter_profile));
101424865366SAlexander Kozyrev 	return 0;
101524865366SAlexander Kozyrev }
10167576c32eSGregory Etelson #endif
101724865366SAlexander Kozyrev 
101824865366SAlexander Kozyrev /**
1019afb4aa4fSLi Zhang  * Find policy by id.
1020afb4aa4fSLi Zhang  *
1021afb4aa4fSLi Zhang  * @param[in] dev
1022afb4aa4fSLi Zhang  *   Pointer to Ethernet device.
1023afb4aa4fSLi Zhang  * @param policy_id
1024afb4aa4fSLi Zhang  *   Policy id.
1025afb4aa4fSLi Zhang  *
1026afb4aa4fSLi Zhang  * @return
1027afb4aa4fSLi Zhang  *   Pointer to the policy found on success, NULL otherwise.
1028afb4aa4fSLi Zhang  */
1029afb4aa4fSLi Zhang struct mlx5_flow_meter_policy *
1030afb4aa4fSLi Zhang mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
1031afb4aa4fSLi Zhang 			    uint32_t policy_id,
1032afb4aa4fSLi Zhang 			    uint32_t *policy_idx)
1033afb4aa4fSLi Zhang {
1034afb4aa4fSLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
1035afb4aa4fSLi Zhang 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
1036afb4aa4fSLi Zhang 	union mlx5_l3t_data data;
1037afb4aa4fSLi Zhang 
103824865366SAlexander Kozyrev 	if (priv->mtr_policy_arr) {
103924865366SAlexander Kozyrev 		if (policy_idx)
104024865366SAlexander Kozyrev 			*policy_idx = policy_id;
104124865366SAlexander Kozyrev 		return &priv->mtr_policy_arr[policy_id];
104224865366SAlexander Kozyrev 	}
1043efcce4dcSShun Hao 	if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM || !priv->policy_idx_tbl)
1044afb4aa4fSLi Zhang 		return NULL;
1045efcce4dcSShun Hao 	if (mlx5_l3t_get_entry(priv->policy_idx_tbl, policy_id, &data) ||
1046afb4aa4fSLi Zhang 				!data.dword)
1047afb4aa4fSLi Zhang 		return NULL;
1048afb4aa4fSLi Zhang 	if (policy_idx)
1049afb4aa4fSLi Zhang 		*policy_idx = data.dword;
1050afb4aa4fSLi Zhang 	sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
1051afb4aa4fSLi Zhang 					data.dword);
1052afb4aa4fSLi Zhang 	/* Remove reference taken by the mlx5_l3t_get_entry. */
1053efcce4dcSShun Hao 	mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id);
1054afb4aa4fSLi Zhang 	if (sub_policy)
1055afb4aa4fSLi Zhang 		if (sub_policy->main_policy_id)
1056afb4aa4fSLi Zhang 			return sub_policy->main_policy;
1057afb4aa4fSLi Zhang 	return NULL;
1058afb4aa4fSLi Zhang }
1059afb4aa4fSLi Zhang 
1060afb4aa4fSLi Zhang /**
1061bf62fb76SShun Hao  * Get the next meter from one meter's policy in hierarchy chain.
1062bf62fb76SShun Hao  * Lock free, mutex should be acquired by caller.
1063bf62fb76SShun Hao  *
1064bf62fb76SShun Hao  * @param[in] priv
1065bf62fb76SShun Hao  *   Pointer to mlx5_priv.
1066bf62fb76SShun Hao  * @param[in] policy
1067bf62fb76SShun Hao  *   Pointer to flow meter policy.
1068bf62fb76SShun Hao  * @param[out] mtr_idx
1069bf62fb76SShun Hao  *   Pointer to Meter index.
1070bf62fb76SShun Hao  *
1071bf62fb76SShun Hao  * @return
1072bf62fb76SShun Hao  *   Pointer to the next meter, or NULL when fail.
1073bf62fb76SShun Hao  */
1074bf62fb76SShun Hao struct mlx5_flow_meter_info *
1075bf62fb76SShun Hao mlx5_flow_meter_hierarchy_next_meter(struct mlx5_priv *priv,
1076bf62fb76SShun Hao 				     struct mlx5_flow_meter_policy *policy,
1077bf62fb76SShun Hao 				     uint32_t *mtr_idx)
1078bf62fb76SShun Hao {
1079bf62fb76SShun Hao 	int i;
1080bf62fb76SShun Hao 
1081bf62fb76SShun Hao 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
1082bf62fb76SShun Hao 		if (policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
1083bf62fb76SShun Hao 			return mlx5_flow_meter_find(priv,
1084bf62fb76SShun Hao 						    policy->act_cnt[i].next_mtr_id,
1085bf62fb76SShun Hao 						    mtr_idx);
1086bf62fb76SShun Hao 	}
1087bf62fb76SShun Hao 	return NULL;
1088bf62fb76SShun Hao }
1089bf62fb76SShun Hao 
1090bf62fb76SShun Hao /**
109150cc92ddSShun Hao  * Get the last meter's policy from one meter's policy in hierarchy.
109250cc92ddSShun Hao  *
109350cc92ddSShun Hao  * @param[in] dev
109450cc92ddSShun Hao  *   Pointer to Ethernet device.
109550cc92ddSShun Hao  * @param[in] policy
109650cc92ddSShun Hao  *   Pointer to flow meter policy.
109750cc92ddSShun Hao  *
109850cc92ddSShun Hao  * @return
109950cc92ddSShun Hao  *   Pointer to the final meter's policy, or NULL when fail.
110050cc92ddSShun Hao  */
110150cc92ddSShun Hao struct mlx5_flow_meter_policy *
110250cc92ddSShun Hao mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
110350cc92ddSShun Hao 					struct mlx5_flow_meter_policy *policy)
110450cc92ddSShun Hao {
110550cc92ddSShun Hao 	struct mlx5_priv *priv = dev->data->dev_private;
110650cc92ddSShun Hao 	struct mlx5_flow_meter_info *next_fm;
110750cc92ddSShun Hao 	struct mlx5_flow_meter_policy *next_policy = policy;
110850cc92ddSShun Hao 
110950cc92ddSShun Hao 	while (next_policy->is_hierarchy) {
1110bf62fb76SShun Hao 		rte_spinlock_lock(&next_policy->sl);
1111bf62fb76SShun Hao 		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, next_policy, NULL);
1112bf62fb76SShun Hao 		rte_spinlock_unlock(&next_policy->sl);
111350cc92ddSShun Hao 		if (!next_fm || next_fm->def_policy)
111450cc92ddSShun Hao 			return NULL;
111550cc92ddSShun Hao 		next_policy = mlx5_flow_meter_policy_find(dev,
111650cc92ddSShun Hao 						next_fm->policy_id, NULL);
111750cc92ddSShun Hao 		MLX5_ASSERT(next_policy);
111850cc92ddSShun Hao 	}
111950cc92ddSShun Hao 	return next_policy;
112050cc92ddSShun Hao }
112150cc92ddSShun Hao 
112250cc92ddSShun Hao /**
1123afb4aa4fSLi Zhang  * Callback to check MTR policy action validate
1124afb4aa4fSLi Zhang  *
1125afb4aa4fSLi Zhang  * @param[in] dev
1126afb4aa4fSLi Zhang  *   Pointer to Ethernet device.
1127afb4aa4fSLi Zhang  * @param[in] actions
1128afb4aa4fSLi Zhang  *   Pointer to meter policy action detail.
1129afb4aa4fSLi Zhang  * @param[out] error
1130afb4aa4fSLi Zhang  *   Pointer to the error structure.
1131afb4aa4fSLi Zhang  *
1132afb4aa4fSLi Zhang  * @return
1133afb4aa4fSLi Zhang  *   0 on success, a negative errno value otherwise and rte_errno is set.
1134afb4aa4fSLi Zhang  */
1135afb4aa4fSLi Zhang static int
1136afb4aa4fSLi Zhang mlx5_flow_meter_policy_validate(struct rte_eth_dev *dev,
1137afb4aa4fSLi Zhang 	struct rte_mtr_meter_policy_params *policy,
1138afb4aa4fSLi Zhang 	struct rte_mtr_error *error)
1139afb4aa4fSLi Zhang {
1140afb4aa4fSLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
1141a13ec19cSMichael Baum 	struct rte_flow_attr attr = { .transfer = priv->sh->config.dv_esw_en ?
1142a13ec19cSMichael Baum 						  1 : 0 };
1143afb4aa4fSLi Zhang 	bool is_rss = false;
11444b7bf3ffSBing Zhao 	uint8_t policy_mode;
1145afb4aa4fSLi Zhang 	uint8_t domain_bitmap;
1146afb4aa4fSLi Zhang 	int ret;
1147afb4aa4fSLi Zhang 
1148afb4aa4fSLi Zhang 	if (!priv->mtr_en || !priv->sh->meter_aso_en)
1149afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
1150afb4aa4fSLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY,
1151afb4aa4fSLi Zhang 				NULL, "meter policy unsupported.");
1152afb4aa4fSLi Zhang 	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
11534b7bf3ffSBing Zhao 			&is_rss, &domain_bitmap, &policy_mode, error);
1154afb4aa4fSLi Zhang 	if (ret)
1155afb4aa4fSLi Zhang 		return ret;
1156afb4aa4fSLi Zhang 	return 0;
1157afb4aa4fSLi Zhang }
1158afb4aa4fSLi Zhang 
11597576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
116024865366SAlexander Kozyrev /**
116124865366SAlexander Kozyrev  * Callback to check MTR policy action validate for HWS
116224865366SAlexander Kozyrev  *
116324865366SAlexander Kozyrev  * @param[in] dev
116424865366SAlexander Kozyrev  *   Pointer to Ethernet device.
116524865366SAlexander Kozyrev  * @param[in] actions
116624865366SAlexander Kozyrev  *   Pointer to meter policy action detail.
116724865366SAlexander Kozyrev  * @param[out] error
116824865366SAlexander Kozyrev  *   Pointer to the error structure.
116924865366SAlexander Kozyrev  *
117024865366SAlexander Kozyrev  * @return
117124865366SAlexander Kozyrev  *   0 on success, a negative errno value otherwise and rte_errno is set.
117224865366SAlexander Kozyrev  */
117324865366SAlexander Kozyrev static int
117424865366SAlexander Kozyrev mlx5_flow_meter_policy_hws_validate(struct rte_eth_dev *dev,
117524865366SAlexander Kozyrev 	struct rte_mtr_meter_policy_params *policy,
117624865366SAlexander Kozyrev 	struct rte_mtr_error *error)
117724865366SAlexander Kozyrev {
117824865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
117924865366SAlexander Kozyrev 	const struct rte_flow_actions_template_attr attr = {
118024865366SAlexander Kozyrev 		.transfer = priv->sh->config.dv_esw_en ? 1 : 0 };
118124865366SAlexander Kozyrev 	int ret;
118224865366SAlexander Kozyrev 	int i;
118324865366SAlexander Kozyrev 
1184*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL))
1185*61a81061SGregory Etelson 		return -rte_mtr_error_set(error, EINVAL,
1186*61a81061SGregory Etelson 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1187*61a81061SGregory Etelson 					  "non-template flow engine was not configured");
118824865366SAlexander Kozyrev 	if (!priv->mtr_en || !priv->sh->meter_aso_en)
118924865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOTSUP,
119024865366SAlexander Kozyrev 				RTE_MTR_ERROR_TYPE_METER_POLICY,
119124865366SAlexander Kozyrev 				NULL, "meter policy unsupported.");
119224865366SAlexander Kozyrev 	for (i = 0; i < RTE_COLORS; i++) {
119324865366SAlexander Kozyrev 		ret = mlx5_flow_actions_validate(dev, &attr, policy->actions[i],
119424865366SAlexander Kozyrev 						 policy->actions[i], NULL);
119524865366SAlexander Kozyrev 		if (ret)
119624865366SAlexander Kozyrev 			return ret;
119724865366SAlexander Kozyrev 	}
119824865366SAlexander Kozyrev 	return 0;
119924865366SAlexander Kozyrev }
12007576c32eSGregory Etelson #endif
120124865366SAlexander Kozyrev 
1202afb4aa4fSLi Zhang static int
1203afb4aa4fSLi Zhang __mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
1204afb4aa4fSLi Zhang 			uint32_t policy_id,
1205afb4aa4fSLi Zhang 			struct mlx5_flow_meter_policy *mtr_policy,
1206035f4c23SLi Zhang 			struct rte_mtr_error *error,
1207035f4c23SLi Zhang 			bool clear_l3t)
1208afb4aa4fSLi Zhang {
1209afb4aa4fSLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
1210afb4aa4fSLi Zhang 	struct mlx5_flow_meter_sub_policy *sub_policy;
1211afb4aa4fSLi Zhang 	uint32_t i, j;
1212afb4aa4fSLi Zhang 	uint16_t sub_policy_num;
1213afb4aa4fSLi Zhang 
1214afb4aa4fSLi Zhang 	rte_spinlock_lock(&mtr_policy->sl);
1215afb4aa4fSLi Zhang 	if (mtr_policy->ref_cnt) {
1216afb4aa4fSLi Zhang 		rte_spinlock_unlock(&mtr_policy->sl);
1217afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, EBUSY,
1218afb4aa4fSLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1219afb4aa4fSLi Zhang 				 NULL,
1220afb4aa4fSLi Zhang 				"Meter policy object is being used.");
1221afb4aa4fSLi Zhang 	}
1222afb4aa4fSLi Zhang 	mlx5_flow_destroy_policy_rules(dev, mtr_policy);
1223afb4aa4fSLi Zhang 	mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
1224afb4aa4fSLi Zhang 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
1225afb4aa4fSLi Zhang 		sub_policy_num = (mtr_policy->sub_policy_num >>
1226afb4aa4fSLi Zhang 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
1227afb4aa4fSLi Zhang 			MLX5_MTR_SUB_POLICY_NUM_MASK;
1228afb4aa4fSLi Zhang 		if (sub_policy_num) {
1229afb4aa4fSLi Zhang 			for (j = 0; j < sub_policy_num; j++) {
1230afb4aa4fSLi Zhang 				sub_policy = mtr_policy->sub_policys[i][j];
1231afb4aa4fSLi Zhang 				if (sub_policy)
1232afb4aa4fSLi Zhang 					mlx5_ipool_free
1233afb4aa4fSLi Zhang 					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
1234afb4aa4fSLi Zhang 					sub_policy->idx);
1235afb4aa4fSLi Zhang 			}
1236afb4aa4fSLi Zhang 		}
1237afb4aa4fSLi Zhang 	}
1238efcce4dcSShun Hao 	if (priv->policy_idx_tbl && clear_l3t) {
1239efcce4dcSShun Hao 		if (mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id)) {
1240afb4aa4fSLi Zhang 			rte_spinlock_unlock(&mtr_policy->sl);
1241afb4aa4fSLi Zhang 			return -rte_mtr_error_set(error, ENOTSUP,
1242afb4aa4fSLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
1243afb4aa4fSLi Zhang 				"Fail to delete policy in index table.");
1244afb4aa4fSLi Zhang 		}
1245afb4aa4fSLi Zhang 	}
1246afb4aa4fSLi Zhang 	rte_spinlock_unlock(&mtr_policy->sl);
1247afb4aa4fSLi Zhang 	return 0;
1248afb4aa4fSLi Zhang }
1249afb4aa4fSLi Zhang 
1250afb4aa4fSLi Zhang /**
1251afb4aa4fSLi Zhang  * Callback to add MTR policy.
1252afb4aa4fSLi Zhang  *
1253afb4aa4fSLi Zhang  * @param[in] dev
1254afb4aa4fSLi Zhang  *   Pointer to Ethernet device.
1255afb4aa4fSLi Zhang  * @param[out] policy_id
1256afb4aa4fSLi Zhang  *   Pointer to policy id
1257afb4aa4fSLi Zhang  * @param[in] actions
1258afb4aa4fSLi Zhang  *   Pointer to meter policy action detail.
1259afb4aa4fSLi Zhang  * @param[out] error
1260afb4aa4fSLi Zhang  *   Pointer to the error structure.
1261afb4aa4fSLi Zhang  *
1262afb4aa4fSLi Zhang  * @return
1263afb4aa4fSLi Zhang  *   0 on success, a negative errno value otherwise and rte_errno is set.
1264afb4aa4fSLi Zhang  */
1265afb4aa4fSLi Zhang static int
1266afb4aa4fSLi Zhang mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
1267afb4aa4fSLi Zhang 			uint32_t policy_id,
1268afb4aa4fSLi Zhang 			struct rte_mtr_meter_policy_params *policy,
1269afb4aa4fSLi Zhang 			struct rte_mtr_error *error)
1270afb4aa4fSLi Zhang {
1271afb4aa4fSLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
1272a13ec19cSMichael Baum 	struct rte_flow_attr attr = { .transfer = priv->sh->config.dv_esw_en ?
1273a13ec19cSMichael Baum 						  1 : 0 };
1274afb4aa4fSLi Zhang 	uint32_t sub_policy_idx = 0;
1275afb4aa4fSLi Zhang 	uint32_t policy_idx = 0;
1276afb4aa4fSLi Zhang 	struct mlx5_flow_meter_policy *mtr_policy = NULL;
1277afb4aa4fSLi Zhang 	struct mlx5_flow_meter_sub_policy *sub_policy;
1278afb4aa4fSLi Zhang 	bool is_rss = false;
12794b7bf3ffSBing Zhao 	uint8_t policy_mode;
1280afb4aa4fSLi Zhang 	uint32_t i;
1281afb4aa4fSLi Zhang 	int ret;
1282afb4aa4fSLi Zhang 	uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
1283afb4aa4fSLi Zhang 	uint16_t sub_policy_num;
1284afb4aa4fSLi Zhang 	uint8_t domain_bitmap = 0;
1285afb4aa4fSLi Zhang 	union mlx5_l3t_data data;
128650cc92ddSShun Hao 	bool skip_rule = false;
1287afb4aa4fSLi Zhang 
1288afb4aa4fSLi Zhang 	if (!priv->mtr_en)
1289afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
1290afb4aa4fSLi Zhang 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
1291afb4aa4fSLi Zhang 					  NULL, "meter policy unsupported. ");
1292afb4aa4fSLi Zhang 	if (policy_id == MLX5_INVALID_POLICY_ID)
1293afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
1294fa31a5edSBing Zhao 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1295fa31a5edSBing Zhao 					  NULL, "policy ID is invalid. ");
1296afb4aa4fSLi Zhang 	if (policy_id == priv->sh->mtrmng->def_policy_id)
1297afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, EEXIST,
1298fa31a5edSBing Zhao 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1299fa31a5edSBing Zhao 					  NULL, "default policy ID exists. ");
1300fa31a5edSBing Zhao 	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
1301afb4aa4fSLi Zhang 	if (mtr_policy)
1302afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, EEXIST,
1303fa31a5edSBing Zhao 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1304fa31a5edSBing Zhao 					  NULL, "policy ID exists. ");
1305afb4aa4fSLi Zhang 	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
13064b7bf3ffSBing Zhao 					  &is_rss, &domain_bitmap,
13074b7bf3ffSBing Zhao 					  &policy_mode, error);
1308afb4aa4fSLi Zhang 	if (ret)
1309afb4aa4fSLi Zhang 		return ret;
1310afb4aa4fSLi Zhang 	if (!domain_bitmap)
1311afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
1312afb4aa4fSLi Zhang 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
1313afb4aa4fSLi Zhang 					  NULL, "fail to find policy domain.");
13144b7bf3ffSBing Zhao 	if (policy_mode == MLX5_MTR_POLICY_MODE_DEF) {
1315afb4aa4fSLi Zhang 		if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID)
1316afb4aa4fSLi Zhang 			return -rte_mtr_error_set(error, EEXIST,
1317afb4aa4fSLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1318afb4aa4fSLi Zhang 				NULL, "a policy with similar actions "
1319afb4aa4fSLi Zhang 				"is already configured");
1320afb4aa4fSLi Zhang 		if (mlx5_flow_create_def_policy(dev))
1321afb4aa4fSLi Zhang 			return -rte_mtr_error_set(error, ENOTSUP,
1322afb4aa4fSLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY,
1323afb4aa4fSLi Zhang 				NULL,
1324afb4aa4fSLi Zhang 				"fail to create non-terminated policy.");
1325afb4aa4fSLi Zhang 		priv->sh->mtrmng->def_policy_id = policy_id;
1326afb4aa4fSLi Zhang 		return 0;
1327afb4aa4fSLi Zhang 	}
1328afb4aa4fSLi Zhang 	if (!priv->sh->meter_aso_en)
1329afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
1330afb4aa4fSLi Zhang 			RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
1331afb4aa4fSLi Zhang 			"no ASO capability to support the policy ");
1332afb4aa4fSLi Zhang 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
1333afb4aa4fSLi Zhang 		if (!(domain_bitmap & (1 << i)))
1334afb4aa4fSLi Zhang 			continue;
1335fa31a5edSBing Zhao 		/*
1336fa31a5edSBing Zhao 		 * If RSS is found, it means that only the ingress domain can
1337fa31a5edSBing Zhao 		 * be supported. It is invalid to support RSS for one color
1338fa31a5edSBing Zhao 		 * and egress / transfer domain actions for another. Drop and
1339fa31a5edSBing Zhao 		 * jump action should have no impact.
1340fa31a5edSBing Zhao 		 */
1341afb4aa4fSLi Zhang 		if (is_rss) {
1342afb4aa4fSLi Zhang 			policy_size +=
1343afb4aa4fSLi Zhang 				sizeof(struct mlx5_flow_meter_sub_policy *) *
1344afb4aa4fSLi Zhang 				MLX5_MTR_RSS_MAX_SUB_POLICY;
1345afb4aa4fSLi Zhang 			break;
1346afb4aa4fSLi Zhang 		}
1347afb4aa4fSLi Zhang 		policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
1348afb4aa4fSLi Zhang 	}
1349afb4aa4fSLi Zhang 	mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
1350afb4aa4fSLi Zhang 				 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1351afb4aa4fSLi Zhang 	if (!mtr_policy)
1352afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, ENOMEM,
1353afb4aa4fSLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
1354afb4aa4fSLi Zhang 				"Memory alloc failed for meter policy.");
13554d648fadSBing Zhao 	if (policy_mode == MLX5_MTR_POLICY_MODE_OG)
13564d648fadSBing Zhao 		mtr_policy->skip_y = 1;
13574d648fadSBing Zhao 	else if (policy_mode == MLX5_MTR_POLICY_MODE_OY)
13584d648fadSBing Zhao 		mtr_policy->skip_g = 1;
1359afb4aa4fSLi Zhang 	policy_size = sizeof(struct mlx5_flow_meter_policy);
1360afb4aa4fSLi Zhang 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
1361afb4aa4fSLi Zhang 		if (!(domain_bitmap & (1 << i)))
1362afb4aa4fSLi Zhang 			continue;
136344432018SLi Zhang 		if (i == MLX5_MTR_DOMAIN_INGRESS)
136444432018SLi Zhang 			mtr_policy->ingress = 1;
136544432018SLi Zhang 		if (i == MLX5_MTR_DOMAIN_EGRESS)
136644432018SLi Zhang 			mtr_policy->egress = 1;
136744432018SLi Zhang 		if (i == MLX5_MTR_DOMAIN_TRANSFER)
136844432018SLi Zhang 			mtr_policy->transfer = 1;
1369afb4aa4fSLi Zhang 		sub_policy = mlx5_ipool_zmalloc
1370afb4aa4fSLi Zhang 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
1371afb4aa4fSLi Zhang 				 &sub_policy_idx);
1372fa31a5edSBing Zhao 		if (!sub_policy ||
1373fa31a5edSBing Zhao 		    sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
1374afb4aa4fSLi Zhang 			goto policy_add_err;
1375afb4aa4fSLi Zhang 		sub_policy->idx = sub_policy_idx;
1376afb4aa4fSLi Zhang 		sub_policy->main_policy = mtr_policy;
1377afb4aa4fSLi Zhang 		if (!policy_idx) {
1378afb4aa4fSLi Zhang 			policy_idx = sub_policy_idx;
1379afb4aa4fSLi Zhang 			sub_policy->main_policy_id = 1;
1380afb4aa4fSLi Zhang 		}
1381afb4aa4fSLi Zhang 		mtr_policy->sub_policys[i] =
1382afb4aa4fSLi Zhang 			(struct mlx5_flow_meter_sub_policy **)
1383afb4aa4fSLi Zhang 			((uint8_t *)mtr_policy + policy_size);
1384afb4aa4fSLi Zhang 		mtr_policy->sub_policys[i][0] = sub_policy;
1385afb4aa4fSLi Zhang 		sub_policy_num = (mtr_policy->sub_policy_num >>
1386afb4aa4fSLi Zhang 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
1387afb4aa4fSLi Zhang 			MLX5_MTR_SUB_POLICY_NUM_MASK;
1388afb4aa4fSLi Zhang 		sub_policy_num++;
1389afb4aa4fSLi Zhang 		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
1390afb4aa4fSLi Zhang 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
1391afb4aa4fSLi Zhang 		mtr_policy->sub_policy_num |=
1392afb4aa4fSLi Zhang 			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
1393afb4aa4fSLi Zhang 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
1394fa31a5edSBing Zhao 		/*
1395fa31a5edSBing Zhao 		 * If RSS is found, it means that only the ingress domain can
1396fa31a5edSBing Zhao 		 * be supported. It is invalid to support RSS for one color
1397fa31a5edSBing Zhao 		 * and egress / transfer domain actions for another. Drop and
1398fa31a5edSBing Zhao 		 * jump action should have no impact.
1399fa31a5edSBing Zhao 		 */
1400afb4aa4fSLi Zhang 		if (is_rss) {
1401afb4aa4fSLi Zhang 			mtr_policy->is_rss = 1;
1402afb4aa4fSLi Zhang 			break;
1403afb4aa4fSLi Zhang 		}
1404afb4aa4fSLi Zhang 		policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
1405afb4aa4fSLi Zhang 	}
1406afb4aa4fSLi Zhang 	rte_spinlock_init(&mtr_policy->sl);
1407afb4aa4fSLi Zhang 	ret = mlx5_flow_create_mtr_acts(dev, mtr_policy,
14086431068dSSean Zhang 					policy->actions, &attr, error);
1409afb4aa4fSLi Zhang 	if (ret)
1410afb4aa4fSLi Zhang 		goto policy_add_err;
141150cc92ddSShun Hao 	if (mtr_policy->is_hierarchy) {
141250cc92ddSShun Hao 		struct mlx5_flow_meter_policy *final_policy;
141350cc92ddSShun Hao 
141450cc92ddSShun Hao 		final_policy =
141550cc92ddSShun Hao 		mlx5_flow_meter_hierarchy_get_final_policy(dev, mtr_policy);
141650cc92ddSShun Hao 		if (!final_policy)
141750cc92ddSShun Hao 			goto policy_add_err;
141850cc92ddSShun Hao 		skip_rule = (final_policy->is_rss || final_policy->is_queue);
141950cc92ddSShun Hao 	}
1420fa31a5edSBing Zhao 	/*
1421fa31a5edSBing Zhao 	 * If either Green or Yellow has queue / RSS action, all the policy
1422fa31a5edSBing Zhao 	 * rules will be created later in the flow splitting stage.
1423fa31a5edSBing Zhao 	 */
142450cc92ddSShun Hao 	if (!is_rss && !mtr_policy->is_queue && !skip_rule) {
1425afb4aa4fSLi Zhang 		/* Create policy rules in HW. */
1426afb4aa4fSLi Zhang 		ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
1427afb4aa4fSLi Zhang 		if (ret)
1428afb4aa4fSLi Zhang 			goto policy_add_err;
1429afb4aa4fSLi Zhang 	}
1430afb4aa4fSLi Zhang 	data.dword = policy_idx;
1431efcce4dcSShun Hao 	if (!priv->policy_idx_tbl) {
1432efcce4dcSShun Hao 		priv->policy_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
1433efcce4dcSShun Hao 		if (!priv->policy_idx_tbl)
1434afb4aa4fSLi Zhang 			goto policy_add_err;
1435afb4aa4fSLi Zhang 	}
1436efcce4dcSShun Hao 	if (mlx5_l3t_set_entry(priv->policy_idx_tbl, policy_id, &data))
1437afb4aa4fSLi Zhang 		goto policy_add_err;
1438afb4aa4fSLi Zhang 	return 0;
1439afb4aa4fSLi Zhang policy_add_err:
1440afb4aa4fSLi Zhang 	if (mtr_policy) {
1441afb4aa4fSLi Zhang 		ret = __mlx5_flow_meter_policy_delete(dev, policy_id,
1442035f4c23SLi Zhang 			mtr_policy, error, false);
1443afb4aa4fSLi Zhang 		mlx5_free(mtr_policy);
1444afb4aa4fSLi Zhang 		if (ret)
1445afb4aa4fSLi Zhang 			return ret;
1446afb4aa4fSLi Zhang 	}
1447afb4aa4fSLi Zhang 	return -rte_mtr_error_set(error, ENOTSUP,
1448afb4aa4fSLi Zhang 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1449afb4aa4fSLi Zhang 				  NULL, "Failed to create devx policy.");
1450afb4aa4fSLi Zhang }
1451afb4aa4fSLi Zhang 
1452afb4aa4fSLi Zhang /**
1453afb4aa4fSLi Zhang  * Callback to delete MTR policy.
1454afb4aa4fSLi Zhang  *
1455afb4aa4fSLi Zhang  * @param[in] dev
1456afb4aa4fSLi Zhang  *   Pointer to Ethernet device.
1457afb4aa4fSLi Zhang  * @param[in] policy_id
1458afb4aa4fSLi Zhang  *   Meter policy id.
1459afb4aa4fSLi Zhang  * @param[out] error
1460afb4aa4fSLi Zhang  *   Pointer to the error structure.
1461afb4aa4fSLi Zhang  *
1462afb4aa4fSLi Zhang  * @return
1463afb4aa4fSLi Zhang  *   0 on success, a negative errno value otherwise and rte_errno is set.
1464afb4aa4fSLi Zhang  */
1465afb4aa4fSLi Zhang static int
1466afb4aa4fSLi Zhang mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
1467afb4aa4fSLi Zhang 			  uint32_t policy_id,
1468afb4aa4fSLi Zhang 			  struct rte_mtr_error *error)
1469afb4aa4fSLi Zhang {
1470afb4aa4fSLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
1471afb4aa4fSLi Zhang 	struct mlx5_flow_meter_policy *mtr_policy;
1472afb4aa4fSLi Zhang 	uint32_t policy_idx;
1473afb4aa4fSLi Zhang 	int ret;
1474afb4aa4fSLi Zhang 
1475afb4aa4fSLi Zhang 	if (policy_id == priv->sh->mtrmng->def_policy_id) {
1476afb4aa4fSLi Zhang 		if (priv->sh->mtrmng->def_policy_ref_cnt > 0)
1477afb4aa4fSLi Zhang 			return -rte_mtr_error_set(error, ENOTSUP,
1478afb4aa4fSLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
1479afb4aa4fSLi Zhang 				"Meter policy object is being used.");
1480afb4aa4fSLi Zhang 		priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
1481afb4aa4fSLi Zhang 		return 0;
1482afb4aa4fSLi Zhang 	}
1483afb4aa4fSLi Zhang 	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
1484afb4aa4fSLi Zhang 	if (!mtr_policy)
1485afb4aa4fSLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
1486afb4aa4fSLi Zhang 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
1487afb4aa4fSLi Zhang 			"Meter policy id is invalid. ");
1488afb4aa4fSLi Zhang 	ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
1489035f4c23SLi Zhang 						error, true);
1490afb4aa4fSLi Zhang 	if (ret)
1491afb4aa4fSLi Zhang 		return ret;
1492afb4aa4fSLi Zhang 	mlx5_free(mtr_policy);
1493afb4aa4fSLi Zhang 	return 0;
1494afb4aa4fSLi Zhang }
1495afb4aa4fSLi Zhang 
1496afb4aa4fSLi Zhang /**
149748fbb0e9SAlexander Kozyrev  * Callback to get MTR policy.
149848fbb0e9SAlexander Kozyrev  *
149948fbb0e9SAlexander Kozyrev  * @param[in] dev
150048fbb0e9SAlexander Kozyrev  *   Pointer to Ethernet device.
150148fbb0e9SAlexander Kozyrev  * @param[in] policy_id
150248fbb0e9SAlexander Kozyrev  *   Meter policy id.
150348fbb0e9SAlexander Kozyrev  * @param[out] error
150448fbb0e9SAlexander Kozyrev  *   Pointer to the error structure.
150548fbb0e9SAlexander Kozyrev  *
150648fbb0e9SAlexander Kozyrev  * @return
150748fbb0e9SAlexander Kozyrev  *   A valid handle in case of success, NULL otherwise.
150848fbb0e9SAlexander Kozyrev  */
150948fbb0e9SAlexander Kozyrev static struct rte_flow_meter_policy *
151048fbb0e9SAlexander Kozyrev mlx5_flow_meter_policy_get(struct rte_eth_dev *dev,
151148fbb0e9SAlexander Kozyrev 			  uint32_t policy_id,
151248fbb0e9SAlexander Kozyrev 			  struct rte_mtr_error *error)
151348fbb0e9SAlexander Kozyrev {
151448fbb0e9SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
151548fbb0e9SAlexander Kozyrev 	uint32_t policy_idx;
151648fbb0e9SAlexander Kozyrev 
1517*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL)) {
1518*61a81061SGregory Etelson 		rte_mtr_error_set(error, EINVAL,
1519*61a81061SGregory Etelson 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1520*61a81061SGregory Etelson 				  "non-template flow engine was not configured");
1521*61a81061SGregory Etelson 		return NULL;
1522*61a81061SGregory Etelson 	}
152348fbb0e9SAlexander Kozyrev 	if (!priv->mtr_en) {
152448fbb0e9SAlexander Kozyrev 		rte_mtr_error_set(error, ENOTSUP,
152548fbb0e9SAlexander Kozyrev 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
152648fbb0e9SAlexander Kozyrev 				  "Meter is not supported");
152748fbb0e9SAlexander Kozyrev 		return NULL;
152848fbb0e9SAlexander Kozyrev 	}
152948fbb0e9SAlexander Kozyrev 	return (void *)(uintptr_t)mlx5_flow_meter_policy_find(dev, policy_id,
153048fbb0e9SAlexander Kozyrev 							      &policy_idx);
153148fbb0e9SAlexander Kozyrev }
153248fbb0e9SAlexander Kozyrev 
15337576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
153448fbb0e9SAlexander Kozyrev /**
153524865366SAlexander Kozyrev  * Callback to delete MTR policy for HWS.
153624865366SAlexander Kozyrev  *
153724865366SAlexander Kozyrev  * @param[in] dev
153824865366SAlexander Kozyrev  *   Pointer to Ethernet device.
153924865366SAlexander Kozyrev  * @param[in] policy_id
154024865366SAlexander Kozyrev  *   Meter policy id.
154124865366SAlexander Kozyrev  * @param[out] error
154224865366SAlexander Kozyrev  *   Pointer to the error structure.
154324865366SAlexander Kozyrev  *
154424865366SAlexander Kozyrev  * @return
154524865366SAlexander Kozyrev  *   0 on success, a negative errno value otherwise and rte_errno is set.
154624865366SAlexander Kozyrev  */
154724865366SAlexander Kozyrev static int
154824865366SAlexander Kozyrev mlx5_flow_meter_policy_hws_delete(struct rte_eth_dev *dev,
154924865366SAlexander Kozyrev 			  uint32_t policy_id,
155024865366SAlexander Kozyrev 			  struct rte_mtr_error *error)
155124865366SAlexander Kozyrev {
155224865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
155324865366SAlexander Kozyrev 	struct mlx5_flow_meter_policy *mtr_policy;
155424865366SAlexander Kozyrev 	uint32_t i, j;
155524865366SAlexander Kozyrev 	uint32_t nb_flows = 0;
155624865366SAlexander Kozyrev 	int ret;
155724865366SAlexander Kozyrev 	struct rte_flow_op_attr op_attr = { .postpone = 1 };
155824865366SAlexander Kozyrev 	struct rte_flow_op_result result[RTE_COLORS * MLX5_MTR_DOMAIN_MAX];
155924865366SAlexander Kozyrev 
156024865366SAlexander Kozyrev 	if (!priv->mtr_policy_arr)
1561077eb39fSAlexander Kozyrev 		return mlx5_flow_meter_policy_delete(dev, policy_id, error);
156224865366SAlexander Kozyrev 	/* Meter policy must exist. */
156324865366SAlexander Kozyrev 	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
156424865366SAlexander Kozyrev 	if (!mtr_policy->initialized)
156524865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOENT,
156624865366SAlexander Kozyrev 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
156724865366SAlexander Kozyrev 			"Meter policy does not exists.");
156824865366SAlexander Kozyrev 	/* Check policy is unused. */
156924865366SAlexander Kozyrev 	if (mtr_policy->ref_cnt)
157024865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, EBUSY,
157124865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
157224865366SAlexander Kozyrev 					  NULL, "Meter policy is in use.");
157324865366SAlexander Kozyrev 	rte_spinlock_lock(&priv->hw_ctrl_lock);
157424865366SAlexander Kozyrev 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
157524865366SAlexander Kozyrev 		for (j = 0; j < RTE_COLORS; j++) {
157624865366SAlexander Kozyrev 			if (mtr_policy->hws_flow_rule[i][j]) {
157724865366SAlexander Kozyrev 				ret = rte_flow_async_destroy(dev->data->port_id,
157824865366SAlexander Kozyrev 					CTRL_QUEUE_ID(priv), &op_attr,
157924865366SAlexander Kozyrev 					mtr_policy->hws_flow_rule[i][j],
158024865366SAlexander Kozyrev 					NULL, NULL);
158124865366SAlexander Kozyrev 				if (ret < 0)
158224865366SAlexander Kozyrev 					continue;
158324865366SAlexander Kozyrev 				nb_flows++;
158424865366SAlexander Kozyrev 			}
158524865366SAlexander Kozyrev 		}
158624865366SAlexander Kozyrev 	}
158724865366SAlexander Kozyrev 	ret = rte_flow_push(dev->data->port_id, CTRL_QUEUE_ID(priv), NULL);
158824865366SAlexander Kozyrev 	while (nb_flows && (ret >= 0)) {
158924865366SAlexander Kozyrev 		ret = rte_flow_pull(dev->data->port_id,
159024865366SAlexander Kozyrev 					CTRL_QUEUE_ID(priv), result,
159124865366SAlexander Kozyrev 					nb_flows, NULL);
159224865366SAlexander Kozyrev 		nb_flows -= ret;
159324865366SAlexander Kozyrev 	}
159424865366SAlexander Kozyrev 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
159524865366SAlexander Kozyrev 		if (mtr_policy->hws_flow_table[i])
159624865366SAlexander Kozyrev 			rte_flow_template_table_destroy(dev->data->port_id,
159724865366SAlexander Kozyrev 				 mtr_policy->hws_flow_table[i], NULL);
159824865366SAlexander Kozyrev 	}
159924865366SAlexander Kozyrev 	for (i = 0; i < RTE_COLORS; i++) {
160024865366SAlexander Kozyrev 		if (mtr_policy->hws_act_templ[i])
160124865366SAlexander Kozyrev 			rte_flow_actions_template_destroy(dev->data->port_id,
160224865366SAlexander Kozyrev 				 mtr_policy->hws_act_templ[i], NULL);
160324865366SAlexander Kozyrev 	}
160424865366SAlexander Kozyrev 	if (mtr_policy->hws_item_templ)
160524865366SAlexander Kozyrev 		rte_flow_pattern_template_destroy(dev->data->port_id,
160624865366SAlexander Kozyrev 				mtr_policy->hws_item_templ, NULL);
160724865366SAlexander Kozyrev 	rte_spinlock_unlock(&priv->hw_ctrl_lock);
160824865366SAlexander Kozyrev 	memset(mtr_policy, 0, sizeof(struct mlx5_flow_meter_policy));
160924865366SAlexander Kozyrev 	return 0;
161024865366SAlexander Kozyrev }
161124865366SAlexander Kozyrev 
161224865366SAlexander Kozyrev /**
161324865366SAlexander Kozyrev  * Callback to add MTR policy for HWS.
161424865366SAlexander Kozyrev  *
161524865366SAlexander Kozyrev  * @param[in] dev
161624865366SAlexander Kozyrev  *   Pointer to Ethernet device.
161724865366SAlexander Kozyrev  * @param[out] policy_id
161824865366SAlexander Kozyrev  *   Pointer to policy id
161924865366SAlexander Kozyrev  * @param[in] actions
162024865366SAlexander Kozyrev  *   Pointer to meter policy action detail.
162124865366SAlexander Kozyrev  * @param[out] error
162224865366SAlexander Kozyrev  *   Pointer to the error structure.
162324865366SAlexander Kozyrev  *
162424865366SAlexander Kozyrev  * @return
162524865366SAlexander Kozyrev  *   0 on success, a negative errno value otherwise and rte_errno is set.
162624865366SAlexander Kozyrev  */
162724865366SAlexander Kozyrev static int
162824865366SAlexander Kozyrev mlx5_flow_meter_policy_hws_add(struct rte_eth_dev *dev,
162924865366SAlexander Kozyrev 			uint32_t policy_id,
163024865366SAlexander Kozyrev 			struct rte_mtr_meter_policy_params *policy,
163124865366SAlexander Kozyrev 			struct rte_mtr_error *error)
163224865366SAlexander Kozyrev {
163324865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
163424865366SAlexander Kozyrev 	struct mlx5_flow_meter_policy *mtr_policy = NULL;
163524865366SAlexander Kozyrev 	const struct rte_flow_action *act;
163624865366SAlexander Kozyrev 	const struct rte_flow_action_meter *mtr;
163724865366SAlexander Kozyrev 	struct mlx5_flow_meter_info *fm;
163824865366SAlexander Kozyrev 	struct mlx5_flow_meter_policy *plc;
163924865366SAlexander Kozyrev 	uint8_t domain_color = MLX5_MTR_ALL_DOMAIN_BIT;
164024865366SAlexander Kozyrev 	bool is_rss = false;
164124865366SAlexander Kozyrev 	bool is_hierarchy = false;
164224865366SAlexander Kozyrev 	int i, j;
164324865366SAlexander Kozyrev 	uint32_t nb_colors = 0;
164424865366SAlexander Kozyrev 	uint32_t nb_flows = 0;
164524865366SAlexander Kozyrev 	int color;
164624865366SAlexander Kozyrev 	int ret;
164724865366SAlexander Kozyrev 	struct rte_flow_pattern_template_attr pta = {0};
164824865366SAlexander Kozyrev 	struct rte_flow_actions_template_attr ata = {0};
164924865366SAlexander Kozyrev 	struct rte_flow_template_table_attr ta = { {0}, 0 };
165024865366SAlexander Kozyrev 	struct rte_flow_op_attr op_attr = { .postpone = 1 };
165124865366SAlexander Kozyrev 	struct rte_flow_op_result result[RTE_COLORS * MLX5_MTR_DOMAIN_MAX];
165224865366SAlexander Kozyrev 	const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
165324865366SAlexander Kozyrev 	int color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,
165424865366SAlexander Kozyrev 						   0, NULL);
165524865366SAlexander Kozyrev 	struct rte_flow_item_tag tag_spec = {
165624865366SAlexander Kozyrev 		.data = 0,
165724865366SAlexander Kozyrev 		.index = color_reg_c_idx
165824865366SAlexander Kozyrev 	};
165924865366SAlexander Kozyrev 	struct rte_flow_item_tag tag_mask = {
166024865366SAlexander Kozyrev 		.data = color_mask,
166124865366SAlexander Kozyrev 		.index = 0xff};
166224865366SAlexander Kozyrev 	struct rte_flow_item pattern[] = {
166324865366SAlexander Kozyrev 		[0] = {
166424865366SAlexander Kozyrev 			.type = (enum rte_flow_item_type)
166524865366SAlexander Kozyrev 				MLX5_RTE_FLOW_ITEM_TYPE_TAG,
166624865366SAlexander Kozyrev 			.spec = &tag_spec,
166724865366SAlexander Kozyrev 			.mask = &tag_mask,
166824865366SAlexander Kozyrev 		},
166924865366SAlexander Kozyrev 		[1] = { .type = RTE_FLOW_ITEM_TYPE_END }
167024865366SAlexander Kozyrev 	};
167124865366SAlexander Kozyrev 
1672*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL))
1673*61a81061SGregory Etelson 		return -rte_mtr_error_set(error, EINVAL,
1674*61a81061SGregory Etelson 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1675*61a81061SGregory Etelson 					  "non-template flow engine was not configured");
167624865366SAlexander Kozyrev 	if (!priv->mtr_policy_arr)
1677077eb39fSAlexander Kozyrev 		return mlx5_flow_meter_policy_add(dev, policy_id, policy, error);
167824865366SAlexander Kozyrev 	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
167924865366SAlexander Kozyrev 	if (mtr_policy->initialized)
168024865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, EEXIST,
168124865366SAlexander Kozyrev 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
168224865366SAlexander Kozyrev 			NULL, "Meter policy already exists.");
168324865366SAlexander Kozyrev 	if (!policy ||
168448fbb0e9SAlexander Kozyrev 	    (!policy->actions[RTE_COLOR_RED] &&
168548fbb0e9SAlexander Kozyrev 	    !policy->actions[RTE_COLOR_YELLOW] &&
168648fbb0e9SAlexander Kozyrev 	    !policy->actions[RTE_COLOR_GREEN]))
168724865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, EINVAL,
168824865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
168924865366SAlexander Kozyrev 					  NULL, "Meter policy actions are not valid.");
169024865366SAlexander Kozyrev 	if (policy->actions[RTE_COLOR_RED] == RTE_FLOW_ACTION_TYPE_END)
169124865366SAlexander Kozyrev 		mtr_policy->skip_r = 1;
169224865366SAlexander Kozyrev 	if (policy->actions[RTE_COLOR_YELLOW] == RTE_FLOW_ACTION_TYPE_END)
169324865366SAlexander Kozyrev 		mtr_policy->skip_y = 1;
169424865366SAlexander Kozyrev 	if (policy->actions[RTE_COLOR_GREEN] == RTE_FLOW_ACTION_TYPE_END)
169524865366SAlexander Kozyrev 		mtr_policy->skip_g = 1;
169624865366SAlexander Kozyrev 	if (mtr_policy->skip_r && mtr_policy->skip_y && mtr_policy->skip_g)
169724865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOTSUP,
169824865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
169924865366SAlexander Kozyrev 					  NULL, "Meter policy actions are empty.");
170024865366SAlexander Kozyrev 	for (i = 0; i < RTE_COLORS; i++) {
170124865366SAlexander Kozyrev 		act = policy->actions[i];
170224865366SAlexander Kozyrev 		while (act && act->type != RTE_FLOW_ACTION_TYPE_END) {
170324865366SAlexander Kozyrev 			switch (act->type) {
170424865366SAlexander Kozyrev 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
170524865366SAlexander Kozyrev 				/* fall-through. */
170624865366SAlexander Kozyrev 			case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
170724865366SAlexander Kozyrev 				domain_color &= ~(MLX5_MTR_DOMAIN_INGRESS_BIT |
170824865366SAlexander Kozyrev 						  MLX5_MTR_DOMAIN_EGRESS_BIT);
170924865366SAlexander Kozyrev 				break;
171024865366SAlexander Kozyrev 			case RTE_FLOW_ACTION_TYPE_RSS:
171124865366SAlexander Kozyrev 				is_rss = true;
171224865366SAlexander Kozyrev 				/* fall-through. */
171324865366SAlexander Kozyrev 			case RTE_FLOW_ACTION_TYPE_QUEUE:
171424865366SAlexander Kozyrev 				domain_color &= ~(MLX5_MTR_DOMAIN_EGRESS_BIT |
171524865366SAlexander Kozyrev 						  MLX5_MTR_DOMAIN_TRANSFER_BIT);
171624865366SAlexander Kozyrev 				break;
171724865366SAlexander Kozyrev 			case RTE_FLOW_ACTION_TYPE_METER:
171824865366SAlexander Kozyrev 				is_hierarchy = true;
171924865366SAlexander Kozyrev 				mtr = act->conf;
172024865366SAlexander Kozyrev 				fm = mlx5_flow_meter_find(priv,
172124865366SAlexander Kozyrev 							  mtr->mtr_id, NULL);
172224865366SAlexander Kozyrev 				if (!fm)
172324865366SAlexander Kozyrev 					return -rte_mtr_error_set(error, EINVAL,
172424865366SAlexander Kozyrev 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
172524865366SAlexander Kozyrev 						"Meter not found in meter hierarchy.");
172624865366SAlexander Kozyrev 				plc = mlx5_flow_meter_policy_find(dev,
172724865366SAlexander Kozyrev 								  fm->policy_id,
172824865366SAlexander Kozyrev 								  NULL);
172924865366SAlexander Kozyrev 				MLX5_ASSERT(plc);
173024865366SAlexander Kozyrev 				domain_color &= MLX5_MTR_ALL_DOMAIN_BIT &
173124865366SAlexander Kozyrev 					(plc->ingress <<
173224865366SAlexander Kozyrev 					 MLX5_MTR_DOMAIN_INGRESS);
173324865366SAlexander Kozyrev 				domain_color &= MLX5_MTR_ALL_DOMAIN_BIT &
173424865366SAlexander Kozyrev 					(plc->egress <<
173524865366SAlexander Kozyrev 					 MLX5_MTR_DOMAIN_EGRESS);
173624865366SAlexander Kozyrev 				domain_color &= MLX5_MTR_ALL_DOMAIN_BIT &
173724865366SAlexander Kozyrev 					(plc->transfer <<
173824865366SAlexander Kozyrev 					 MLX5_MTR_DOMAIN_TRANSFER);
173924865366SAlexander Kozyrev 				break;
174024865366SAlexander Kozyrev 			default:
174124865366SAlexander Kozyrev 				break;
174224865366SAlexander Kozyrev 			}
174324865366SAlexander Kozyrev 			act++;
174424865366SAlexander Kozyrev 		}
174524865366SAlexander Kozyrev 	}
174648fbb0e9SAlexander Kozyrev 	if (priv->sh->config.dv_esw_en)
174748fbb0e9SAlexander Kozyrev 		domain_color &= ~(MLX5_MTR_DOMAIN_EGRESS_BIT |
174848fbb0e9SAlexander Kozyrev 				  MLX5_MTR_DOMAIN_TRANSFER_BIT);
174948fbb0e9SAlexander Kozyrev 	else
175048fbb0e9SAlexander Kozyrev 		domain_color &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
175124865366SAlexander Kozyrev 	if (!domain_color)
175224865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOTSUP,
175324865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
175424865366SAlexander Kozyrev 					  NULL, "Meter policy domains are conflicting.");
175524865366SAlexander Kozyrev 	mtr_policy->is_rss = is_rss;
175624865366SAlexander Kozyrev 	mtr_policy->ingress = !!(domain_color & MLX5_MTR_DOMAIN_INGRESS_BIT);
175724865366SAlexander Kozyrev 	pta.ingress = mtr_policy->ingress;
175824865366SAlexander Kozyrev 	mtr_policy->egress = !!(domain_color & MLX5_MTR_DOMAIN_EGRESS_BIT);
175924865366SAlexander Kozyrev 	pta.egress = mtr_policy->egress;
176024865366SAlexander Kozyrev 	mtr_policy->transfer = !!(domain_color & MLX5_MTR_DOMAIN_TRANSFER_BIT);
176124865366SAlexander Kozyrev 	pta.transfer = mtr_policy->transfer;
176224865366SAlexander Kozyrev 	mtr_policy->group = MLX5_FLOW_TABLE_HWS_POLICY - policy_id;
176324865366SAlexander Kozyrev 	mtr_policy->is_hierarchy = is_hierarchy;
176424865366SAlexander Kozyrev 	mtr_policy->initialized = 1;
176524865366SAlexander Kozyrev 	rte_spinlock_lock(&priv->hw_ctrl_lock);
176624865366SAlexander Kozyrev 	mtr_policy->hws_item_templ =
176724865366SAlexander Kozyrev 		rte_flow_pattern_template_create(dev->data->port_id,
176824865366SAlexander Kozyrev 						 &pta, pattern, NULL);
176924865366SAlexander Kozyrev 	if (!mtr_policy->hws_item_templ)
177024865366SAlexander Kozyrev 		goto policy_add_err;
177124865366SAlexander Kozyrev 	for (i = 0; i < RTE_COLORS; i++) {
177224865366SAlexander Kozyrev 		if (mtr_policy->skip_g && i == RTE_COLOR_GREEN)
177324865366SAlexander Kozyrev 			continue;
177424865366SAlexander Kozyrev 		if (mtr_policy->skip_y && i == RTE_COLOR_YELLOW)
177524865366SAlexander Kozyrev 			continue;
177624865366SAlexander Kozyrev 		if (mtr_policy->skip_r && i == RTE_COLOR_RED)
177724865366SAlexander Kozyrev 			continue;
177824865366SAlexander Kozyrev 		mtr_policy->hws_act_templ[nb_colors] =
177924865366SAlexander Kozyrev 			rte_flow_actions_template_create(dev->data->port_id,
178024865366SAlexander Kozyrev 						&ata, policy->actions[i],
178124865366SAlexander Kozyrev 						policy->actions[i], NULL);
178224865366SAlexander Kozyrev 		if (!mtr_policy->hws_act_templ[nb_colors])
178324865366SAlexander Kozyrev 			goto policy_add_err;
178424865366SAlexander Kozyrev 		nb_colors++;
178524865366SAlexander Kozyrev 	}
178624865366SAlexander Kozyrev 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
178724865366SAlexander Kozyrev 		memset(&ta, 0, sizeof(ta));
178824865366SAlexander Kozyrev 		ta.nb_flows = RTE_COLORS;
178924865366SAlexander Kozyrev 		ta.flow_attr.group = mtr_policy->group;
179024865366SAlexander Kozyrev 		if (i == MLX5_MTR_DOMAIN_INGRESS) {
179124865366SAlexander Kozyrev 			if (!mtr_policy->ingress)
179224865366SAlexander Kozyrev 				continue;
179324865366SAlexander Kozyrev 			ta.flow_attr.ingress = 1;
179424865366SAlexander Kozyrev 		} else if (i == MLX5_MTR_DOMAIN_EGRESS) {
179524865366SAlexander Kozyrev 			if (!mtr_policy->egress)
179624865366SAlexander Kozyrev 				continue;
179724865366SAlexander Kozyrev 			ta.flow_attr.egress = 1;
179824865366SAlexander Kozyrev 		} else if (i == MLX5_MTR_DOMAIN_TRANSFER) {
179924865366SAlexander Kozyrev 			if (!mtr_policy->transfer)
180024865366SAlexander Kozyrev 				continue;
180124865366SAlexander Kozyrev 			ta.flow_attr.transfer = 1;
180224865366SAlexander Kozyrev 		}
180324865366SAlexander Kozyrev 		mtr_policy->hws_flow_table[i] =
180424865366SAlexander Kozyrev 			rte_flow_template_table_create(dev->data->port_id,
180524865366SAlexander Kozyrev 					&ta, &mtr_policy->hws_item_templ, 1,
180624865366SAlexander Kozyrev 					mtr_policy->hws_act_templ, nb_colors,
180724865366SAlexander Kozyrev 					NULL);
180824865366SAlexander Kozyrev 		if (!mtr_policy->hws_flow_table[i])
180924865366SAlexander Kozyrev 			goto policy_add_err;
181024865366SAlexander Kozyrev 		nb_colors = 0;
181124865366SAlexander Kozyrev 		for (j = 0; j < RTE_COLORS; j++) {
181224865366SAlexander Kozyrev 			if (mtr_policy->skip_g && j == RTE_COLOR_GREEN)
181324865366SAlexander Kozyrev 				continue;
181424865366SAlexander Kozyrev 			if (mtr_policy->skip_y && j == RTE_COLOR_YELLOW)
181524865366SAlexander Kozyrev 				continue;
181624865366SAlexander Kozyrev 			if (mtr_policy->skip_r && j == RTE_COLOR_RED)
181724865366SAlexander Kozyrev 				continue;
181824865366SAlexander Kozyrev 			color = rte_col_2_mlx5_col((enum rte_color)j);
181924865366SAlexander Kozyrev 			tag_spec.data = color;
182024865366SAlexander Kozyrev 			mtr_policy->hws_flow_rule[i][j] =
182124865366SAlexander Kozyrev 				rte_flow_async_create(dev->data->port_id,
182224865366SAlexander Kozyrev 					CTRL_QUEUE_ID(priv), &op_attr,
182324865366SAlexander Kozyrev 					mtr_policy->hws_flow_table[i],
182424865366SAlexander Kozyrev 					pattern, 0, policy->actions[j],
182524865366SAlexander Kozyrev 					nb_colors, NULL, NULL);
182624865366SAlexander Kozyrev 			if (!mtr_policy->hws_flow_rule[i][j])
182724865366SAlexander Kozyrev 				goto policy_add_err;
182824865366SAlexander Kozyrev 			nb_colors++;
182924865366SAlexander Kozyrev 			nb_flows++;
183024865366SAlexander Kozyrev 		}
183124865366SAlexander Kozyrev 		ret = rte_flow_push(dev->data->port_id,
183224865366SAlexander Kozyrev 				    CTRL_QUEUE_ID(priv), NULL);
183324865366SAlexander Kozyrev 		if (ret < 0)
183424865366SAlexander Kozyrev 			goto policy_add_err;
183524865366SAlexander Kozyrev 		while (nb_flows) {
183624865366SAlexander Kozyrev 			ret = rte_flow_pull(dev->data->port_id,
183724865366SAlexander Kozyrev 					    CTRL_QUEUE_ID(priv), result,
183824865366SAlexander Kozyrev 					    nb_flows, NULL);
183924865366SAlexander Kozyrev 			if (ret < 0)
184024865366SAlexander Kozyrev 				goto policy_add_err;
184124865366SAlexander Kozyrev 			for (j = 0; j < ret; j++) {
184224865366SAlexander Kozyrev 				if (result[j].status == RTE_FLOW_OP_ERROR)
184324865366SAlexander Kozyrev 					goto policy_add_err;
184424865366SAlexander Kozyrev 			}
184524865366SAlexander Kozyrev 			nb_flows -= ret;
184624865366SAlexander Kozyrev 		}
184724865366SAlexander Kozyrev 	}
184824865366SAlexander Kozyrev 	rte_spinlock_unlock(&priv->hw_ctrl_lock);
184924865366SAlexander Kozyrev 	return 0;
185024865366SAlexander Kozyrev policy_add_err:
185124865366SAlexander Kozyrev 	rte_spinlock_unlock(&priv->hw_ctrl_lock);
185224865366SAlexander Kozyrev 	ret = mlx5_flow_meter_policy_hws_delete(dev, policy_id, error);
185324865366SAlexander Kozyrev 	memset(mtr_policy, 0, sizeof(struct mlx5_flow_meter_policy));
185424865366SAlexander Kozyrev 	if (ret)
185524865366SAlexander Kozyrev 		return ret;
185624865366SAlexander Kozyrev 	return -rte_mtr_error_set(error, ENOTSUP,
185724865366SAlexander Kozyrev 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
185824865366SAlexander Kozyrev 				  NULL, "Failed to create meter policy.");
185924865366SAlexander Kozyrev }
18607576c32eSGregory Etelson #endif
186124865366SAlexander Kozyrev /**
186244432018SLi Zhang  * Check meter validation.
186344432018SLi Zhang  *
186444432018SLi Zhang  * @param[in] priv
186544432018SLi Zhang  *   Pointer to mlx5 private data structure.
186644432018SLi Zhang  * @param[in] meter_id
186744432018SLi Zhang  *   Meter id.
186844432018SLi Zhang  * @param[in] params
186944432018SLi Zhang  *   Pointer to rte meter parameters.
187044432018SLi Zhang  * @param[out] error
187144432018SLi Zhang  *   Pointer to rte meter error structure.
187244432018SLi Zhang  *
187344432018SLi Zhang  * @return
187444432018SLi Zhang  *   0 on success, a negative errno value otherwise and rte_errno is set.
187544432018SLi Zhang  */
187644432018SLi Zhang static int
187744432018SLi Zhang mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
187844432018SLi Zhang 			 struct rte_mtr_params *params,
187944432018SLi Zhang 			 struct rte_mtr_error *error)
188044432018SLi Zhang {
188144432018SLi Zhang 	/* Meter must use global drop action. */
188244432018SLi Zhang 	if (!priv->sh->dr_drop_action)
188344432018SLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
188444432018SLi Zhang 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
188544432018SLi Zhang 					  NULL,
188644432018SLi Zhang 					  "No drop action ready for meter.");
188744432018SLi Zhang 	/* Meter params must not be NULL. */
188844432018SLi Zhang 	if (params == NULL)
188944432018SLi Zhang 		return -rte_mtr_error_set(error, EINVAL,
189044432018SLi Zhang 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
189144432018SLi Zhang 					  NULL, "Meter object params null.");
189244432018SLi Zhang 	/* Previous meter color is not supported. */
18936b838de3SShun Hao 	if (params->use_prev_mtr_color && !priv->sh->meter_aso_en)
189444432018SLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
189544432018SLi Zhang 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
189644432018SLi Zhang 					  NULL,
189744432018SLi Zhang 					  "Previous meter color "
189844432018SLi Zhang 					  "not supported.");
189944432018SLi Zhang 	if (params->meter_policy_id == MLX5_INVALID_POLICY_ID)
190044432018SLi Zhang 		return -rte_mtr_error_set(error, ENOENT,
190144432018SLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
190244432018SLi Zhang 				NULL, "Meter policy id not valid.");
190344432018SLi Zhang 	/* Validate meter id. */
190444432018SLi Zhang 	if (mlx5_flow_meter_find(priv, meter_id, NULL))
190544432018SLi Zhang 		return -rte_mtr_error_set(error, EEXIST,
190644432018SLi Zhang 			RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
190744432018SLi Zhang 			"Meter object already exists.");
190844432018SLi Zhang 	return 0;
190944432018SLi Zhang }
191044432018SLi Zhang 
191144432018SLi Zhang /**
191233e01809SSuanming Mou  * Modify the flow meter action.
191333e01809SSuanming Mou  *
191433e01809SSuanming Mou  * @param[in] priv
191533e01809SSuanming Mou  *   Pointer to mlx5 private data structure.
191633e01809SSuanming Mou  * @param[in] fm
191733e01809SSuanming Mou  *   Pointer to flow meter to be modified.
191833e01809SSuanming Mou  * @param[in] srtcm
191933e01809SSuanming Mou  *   Pointer to meter srtcm description parameter.
192033e01809SSuanming Mou  * @param[in] modify_bits
192133e01809SSuanming Mou  *   The bit in srtcm to be updated.
192233e01809SSuanming Mou  * @param[in] active_state
192333e01809SSuanming Mou  *   The state to be updated.
192433e01809SSuanming Mou  * @return
192533e01809SSuanming Mou  *   0 on success, o negative value otherwise.
192633e01809SSuanming Mou  */
192733e01809SSuanming Mou static int
192833e01809SSuanming Mou mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
1929e6100c7bSLi Zhang 		struct mlx5_flow_meter_info *fm,
193033e01809SSuanming Mou 		const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
1931e93c58daSLi Zhang 		uint64_t modify_bits, uint32_t active_state, uint32_t is_enable)
193233e01809SSuanming Mou {
193333e01809SSuanming Mou #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
193404e740e6SGregory Etelson 	struct mlx5_dev_ctx_shared *sh = priv->sh;
193533e01809SSuanming Mou 	uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
193633e01809SSuanming Mou 	uint32_t *attr;
193733e01809SSuanming Mou 	struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
193833e01809SSuanming Mou 	int ret;
1939e93c58daSLi Zhang 	struct mlx5_aso_mtr *aso_mtr = NULL;
1940e6100c7bSLi Zhang 	uint32_t cbs_cir, ebs_eir, val;
194133e01809SSuanming Mou 
194204e740e6SGregory Etelson 	if (sh->meter_aso_en) {
1943e93c58daSLi Zhang 		fm->is_enable = !!is_enable;
1944e93c58daSLi Zhang 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
19450c37d8f7SGregory Etelson 		aso_mtr->state = ASO_METER_WAIT;
19464359d9d1SGregory Etelson 		ret = mlx5_aso_meter_update_by_wqe(priv, MLX5_HW_INV_QUEUE,
194704e740e6SGregory Etelson 						   aso_mtr, &priv->mtr_bulk,
194804e740e6SGregory Etelson 						   NULL, true);
1949e93c58daSLi Zhang 		if (ret)
1950e93c58daSLi Zhang 			return ret;
19514359d9d1SGregory Etelson 		ret = mlx5_aso_mtr_wait(priv, aso_mtr, false);
1952e93c58daSLi Zhang 		if (ret)
1953e93c58daSLi Zhang 			return ret;
1954e93c58daSLi Zhang 	} else {
195533e01809SSuanming Mou 		/* Fill command parameters. */
19565e9f9a28SGregory Etelson 		mod_attr.reg_c_index = sh->registers.aso_reg - REG_C_0;
195733e01809SSuanming Mou 		mod_attr.flow_meter_parameter = in;
1958e6100c7bSLi Zhang 		mod_attr.flow_meter_parameter_sz =
1959e6100c7bSLi Zhang 				MLX5_ST_SZ_BYTES(flow_meter_parameters);
196033e01809SSuanming Mou 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
196133e01809SSuanming Mou 			mod_attr.active = !!active_state;
196233e01809SSuanming Mou 		else
196333e01809SSuanming Mou 			mod_attr.active = 0;
196433e01809SSuanming Mou 		attr = in;
1965e6100c7bSLi Zhang 		cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
1966e6100c7bSLi Zhang 		ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
196733e01809SSuanming Mou 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
1968e93c58daSLi Zhang 			val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) &
1969e93c58daSLi Zhang 				ASO_DSEG_EXP_MASK;
1970e93c58daSLi Zhang 			MLX5_SET(flow_meter_parameters, attr,
1971e93c58daSLi Zhang 				cbs_exponent, val);
1972e93c58daSLi Zhang 			val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) &
1973e93c58daSLi Zhang 				ASO_DSEG_MAN_MASK;
1974e93c58daSLi Zhang 			MLX5_SET(flow_meter_parameters, attr,
1975e93c58daSLi Zhang 				cbs_mantissa, val);
197633e01809SSuanming Mou 		}
197733e01809SSuanming Mou 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
197833a7493cSBing Zhao 			val = (cbs_cir >> ASO_DSEG_XIR_EXP_OFFSET) &
1979e93c58daSLi Zhang 				ASO_DSEG_EXP_MASK;
1980e93c58daSLi Zhang 			MLX5_SET(flow_meter_parameters, attr,
1981e93c58daSLi Zhang 				cir_exponent, val);
1982e6100c7bSLi Zhang 			val = cbs_cir & ASO_DSEG_MAN_MASK;
1983e93c58daSLi Zhang 			MLX5_SET(flow_meter_parameters, attr,
1984e93c58daSLi Zhang 				cir_mantissa, val);
198533e01809SSuanming Mou 		}
198633e01809SSuanming Mou 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
1987e93c58daSLi Zhang 			val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) &
1988e93c58daSLi Zhang 				ASO_DSEG_EXP_MASK;
1989e93c58daSLi Zhang 			MLX5_SET(flow_meter_parameters, attr,
1990e93c58daSLi Zhang 				ebs_exponent, val);
1991e93c58daSLi Zhang 			val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) &
1992e93c58daSLi Zhang 				ASO_DSEG_MAN_MASK;
1993e93c58daSLi Zhang 			MLX5_SET(flow_meter_parameters, attr,
1994e93c58daSLi Zhang 				ebs_mantissa, val);
199533e01809SSuanming Mou 		}
199633e01809SSuanming Mou 		/* Apply modifications to meter only if it was created. */
1997bf62fb76SShun Hao 		if (fm->meter_action_g) {
199833e01809SSuanming Mou 			ret = mlx5_glue->dv_modify_flow_action_meter
1999bf62fb76SShun Hao 					(fm->meter_action_g, &mod_attr,
200033e01809SSuanming Mou 					rte_cpu_to_be_64(modify_bits));
200133e01809SSuanming Mou 			if (ret)
200233e01809SSuanming Mou 				return ret;
200333e01809SSuanming Mou 		}
20047be78d02SJosh Soref 		/* Update succeeded modify meter parameters. */
200533e01809SSuanming Mou 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
200633e01809SSuanming Mou 			fm->active_state = !!active_state;
2007e93c58daSLi Zhang 	}
200833e01809SSuanming Mou 	return 0;
200933e01809SSuanming Mou #else
201033e01809SSuanming Mou 	(void)priv;
201133e01809SSuanming Mou 	(void)fm;
201233e01809SSuanming Mou 	(void)srtcm;
201333e01809SSuanming Mou 	(void)modify_bits;
201433e01809SSuanming Mou 	(void)active_state;
2015c99b4f8bSLi Zhang 	(void)is_enable;
201633e01809SSuanming Mou 	return -ENOTSUP;
201733e01809SSuanming Mou #endif
201833e01809SSuanming Mou }
201933e01809SSuanming Mou 
202044432018SLi Zhang static int
202144432018SLi Zhang mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
202244432018SLi Zhang 				struct mlx5_flow_meter_info *fm,
20235df35867SLi Zhang 				uint64_t stats_mask)
20245df35867SLi Zhang {
20255df35867SLi Zhang 	fm->bytes_dropped =
20265df35867SLi Zhang 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
20275df35867SLi Zhang 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
202844432018SLi Zhang 	if (fm->bytes_dropped || fm->pkts_dropped) {
202944432018SLi Zhang 		if (!fm->drop_cnt) {
203044432018SLi Zhang 			/* Alloc policer counters. */
203144432018SLi Zhang 			fm->drop_cnt = mlx5_counter_alloc(dev);
203244432018SLi Zhang 			if (!fm->drop_cnt)
203344432018SLi Zhang 				return -1;
203444432018SLi Zhang 		}
203544432018SLi Zhang 	} else {
203644432018SLi Zhang 		if (fm->drop_cnt) {
203744432018SLi Zhang 			mlx5_counter_free(dev, fm->drop_cnt);
203844432018SLi Zhang 			fm->drop_cnt = 0;
203944432018SLi Zhang 		}
204044432018SLi Zhang 	}
204144432018SLi Zhang 	return 0;
204244432018SLi Zhang }
204344432018SLi Zhang 
204444432018SLi Zhang /**
204544432018SLi Zhang  * Create meter rules.
204644432018SLi Zhang  *
204744432018SLi Zhang  * @param[in] dev
204844432018SLi Zhang  *   Pointer to Ethernet device.
204944432018SLi Zhang  * @param[in] meter_id
205044432018SLi Zhang  *   Meter id.
205144432018SLi Zhang  * @param[in] params
205244432018SLi Zhang  *   Pointer to rte meter parameters.
205344432018SLi Zhang  * @param[in] shared
205444432018SLi Zhang  *   Meter shared with other flow or not.
205544432018SLi Zhang  * @param[out] error
205644432018SLi Zhang  *   Pointer to rte meter error structure.
205744432018SLi Zhang  *
205844432018SLi Zhang  * @return
205944432018SLi Zhang  *   0 on success, a negative errno value otherwise and rte_errno is set.
206044432018SLi Zhang  */
206144432018SLi Zhang static int
206244432018SLi Zhang mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
206344432018SLi Zhang 		       struct rte_mtr_params *params, int shared,
206444432018SLi Zhang 		       struct rte_mtr_error *error)
206544432018SLi Zhang {
206644432018SLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
206744432018SLi Zhang 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
206844432018SLi Zhang 	struct mlx5_flow_meter_profile *fmp;
206944432018SLi Zhang 	struct mlx5_flow_meter_info *fm;
2070be8cda49SDmitry Kozlyuk 	/* GCC fails to infer legacy_fm is set when !priv->sh->meter_aso_en. */
2071be8cda49SDmitry Kozlyuk 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
207244432018SLi Zhang 	struct mlx5_flow_meter_policy *mtr_policy = NULL;
207344432018SLi Zhang 	struct mlx5_indexed_pool_config flow_ipool_cfg = {
207444432018SLi Zhang 		.size = 0,
207544432018SLi Zhang 		.trunk_size = 64,
207644432018SLi Zhang 		.need_lock = 1,
207744432018SLi Zhang 		.type = "mlx5_flow_mtr_flow_id_pool",
207844432018SLi Zhang 	};
207944432018SLi Zhang 	struct mlx5_aso_mtr *aso_mtr;
208044432018SLi Zhang 	uint32_t mtr_idx, policy_idx;
208144432018SLi Zhang 	union mlx5_l3t_data data;
208244432018SLi Zhang 	int ret;
208344432018SLi Zhang 	uint8_t domain_bitmap;
208444432018SLi Zhang 	uint8_t mtr_id_bits;
208544432018SLi Zhang 	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
208644432018SLi Zhang 				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
208744432018SLi Zhang 
208844432018SLi Zhang 	if (!priv->mtr_en)
208944432018SLi Zhang 		return -rte_mtr_error_set(error, ENOTSUP,
209044432018SLi Zhang 					RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
209144432018SLi Zhang 					"Meter is not supported");
209244432018SLi Zhang 	/* Validate the parameters. */
209344432018SLi Zhang 	ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
209444432018SLi Zhang 	if (ret)
209544432018SLi Zhang 		return ret;
209644432018SLi Zhang 	/* Meter profile must exist. */
209744432018SLi Zhang 	fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
209844432018SLi Zhang 	if (fmp == NULL)
209944432018SLi Zhang 		return -rte_mtr_error_set(error, ENOENT,
210044432018SLi Zhang 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
210144432018SLi Zhang 			NULL, "Meter profile id not valid.");
210244432018SLi Zhang 	/* Meter policy must exist. */
210344432018SLi Zhang 	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
2104e12a0166STyler Retzlaff 		rte_atomic_fetch_add_explicit
210544432018SLi Zhang 			(&priv->sh->mtrmng->def_policy_ref_cnt,
2106e12a0166STyler Retzlaff 			1, rte_memory_order_relaxed);
210744432018SLi Zhang 		domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
2108a13ec19cSMichael Baum 		if (!priv->sh->config.dv_esw_en)
210944432018SLi Zhang 			domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
211044432018SLi Zhang 	} else {
211144432018SLi Zhang 		if (!priv->sh->meter_aso_en)
211244432018SLi Zhang 			return -rte_mtr_error_set(error, ENOTSUP,
211344432018SLi Zhang 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
211444432018SLi Zhang 				"Part of the policies cannot be "
211544432018SLi Zhang 				"supported without ASO ");
21164d648fadSBing Zhao 		mtr_policy = mlx5_flow_meter_policy_find(dev,
21174d648fadSBing Zhao 				params->meter_policy_id, &policy_idx);
211844432018SLi Zhang 		if (!mtr_policy)
211944432018SLi Zhang 			return -rte_mtr_error_set(error, ENOENT,
212044432018SLi Zhang 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
212144432018SLi Zhang 				NULL, "Meter policy id not valid.");
212244432018SLi Zhang 		domain_bitmap = (mtr_policy->ingress ?
212344432018SLi Zhang 					MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
212444432018SLi Zhang 				(mtr_policy->egress ?
212544432018SLi Zhang 					MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
212644432018SLi Zhang 				(mtr_policy->transfer ?
212744432018SLi Zhang 					MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
21284d648fadSBing Zhao 		if (fmp->g_support && mtr_policy->skip_g)
21294d648fadSBing Zhao 			return -rte_mtr_error_set(error, ENOTSUP,
21304d648fadSBing Zhao 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
21314d648fadSBing Zhao 					NULL, "Meter green policy is empty.");
21324d648fadSBing Zhao 		if (fmp->y_support && mtr_policy->skip_y)
21334d648fadSBing Zhao 			return -rte_mtr_error_set(error, ENOTSUP,
21344d648fadSBing Zhao 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
21354d648fadSBing Zhao 					NULL, "Meter yellow policy is empty.");
213644432018SLi Zhang 	}
213744432018SLi Zhang 	/* Allocate the flow meter memory. */
213844432018SLi Zhang 	if (priv->sh->meter_aso_en) {
213944432018SLi Zhang 		mtr_idx = mlx5_flow_mtr_alloc(dev);
214044432018SLi Zhang 		if (!mtr_idx)
214144432018SLi Zhang 			return -rte_mtr_error_set(error, ENOMEM,
214244432018SLi Zhang 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
214344432018SLi Zhang 				"Memory alloc failed for meter.");
214444432018SLi Zhang 		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
214544432018SLi Zhang 		fm = &aso_mtr->fm;
214644432018SLi Zhang 	} else {
21478a0fca11SBing Zhao 		if (fmp->y_support)
21488a0fca11SBing Zhao 			return -rte_mtr_error_set(error, ENOMEM,
21498a0fca11SBing Zhao 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
21508a0fca11SBing Zhao 				"Unsupported profile with yellow.");
215144432018SLi Zhang 		legacy_fm = mlx5_ipool_zmalloc
215244432018SLi Zhang 				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
215344432018SLi Zhang 		if (legacy_fm == NULL)
215444432018SLi Zhang 			return -rte_mtr_error_set(error, ENOMEM,
215544432018SLi Zhang 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
215644432018SLi Zhang 				"Memory alloc failed for meter.");
215744432018SLi Zhang 		legacy_fm->idx = mtr_idx;
215844432018SLi Zhang 		fm = &legacy_fm->fm;
215944432018SLi Zhang 	}
21603d4e27fdSDavid Marchand 	mtr_id_bits = MLX5_REG_BITS - rte_clz32(mtr_idx);
216144432018SLi Zhang 	if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
216244432018SLi Zhang 	    mtr_reg_bits) {
216344432018SLi Zhang 		DRV_LOG(ERR, "Meter number exceeds max limit.");
216444432018SLi Zhang 		goto error;
216544432018SLi Zhang 	}
216644432018SLi Zhang 	if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
216744432018SLi Zhang 		priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
216844432018SLi Zhang 	/* Fill the flow meter parameters. */
216944432018SLi Zhang 	fm->meter_id = meter_id;
217044432018SLi Zhang 	fm->policy_id = params->meter_policy_id;
217144432018SLi Zhang 	fm->profile = fmp;
217244432018SLi Zhang 	if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
217344432018SLi Zhang 		goto error;
217444432018SLi Zhang 	if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
217544432018SLi Zhang 		goto error;
217644432018SLi Zhang 	/* Add to the flow meter list. */
2177be8cda49SDmitry Kozlyuk 	if (!priv->sh->meter_aso_en) {
2178be8cda49SDmitry Kozlyuk 		MLX5_ASSERT(legacy_fm != NULL);
217944432018SLi Zhang 		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
2180be8cda49SDmitry Kozlyuk 	}
218144432018SLi Zhang 	/* Add to the flow meter list. */
218244432018SLi Zhang 	fm->active_state = 1; /* Config meter starts as active. */
2183c3130c78SRongwei Liu 	fm->is_enable = params->meter_enable;
218444432018SLi Zhang 	fm->shared = !!shared;
21856b838de3SShun Hao 	fm->color_aware = !!params->use_prev_mtr_color;
2186e12a0166STyler Retzlaff 	rte_atomic_fetch_add_explicit(&fm->profile->ref_cnt, 1, rte_memory_order_relaxed);
218744432018SLi Zhang 	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
218844432018SLi Zhang 		fm->def_policy = 1;
218944432018SLi Zhang 		fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
219044432018SLi Zhang 		if (!fm->flow_ipool)
219144432018SLi Zhang 			goto error;
219244432018SLi Zhang 	}
219344432018SLi Zhang 	rte_spinlock_init(&fm->sl);
219444432018SLi Zhang 	/* If ASO meter supported, update ASO flow meter by wqe. */
219544432018SLi Zhang 	if (priv->sh->meter_aso_en) {
219644432018SLi Zhang 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
21970c37d8f7SGregory Etelson 		aso_mtr->state = ASO_METER_WAIT;
21984359d9d1SGregory Etelson 		ret = mlx5_aso_meter_update_by_wqe(priv, MLX5_HW_INV_QUEUE,
2199478ba4bbSSuanming Mou 						   aso_mtr, &priv->mtr_bulk, NULL, true);
220044432018SLi Zhang 		if (ret)
220144432018SLi Zhang 			goto error;
220244432018SLi Zhang 		if (!priv->mtr_idx_tbl) {
220344432018SLi Zhang 			priv->mtr_idx_tbl =
220444432018SLi Zhang 				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
220544432018SLi Zhang 			if (!priv->mtr_idx_tbl)
220644432018SLi Zhang 				goto error;
220744432018SLi Zhang 		}
220844432018SLi Zhang 		data.dword = mtr_idx;
220944432018SLi Zhang 		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
221044432018SLi Zhang 			goto error;
2211c3130c78SRongwei Liu 	} else if (!params->meter_enable && mlx5_flow_meter_disable(dev, meter_id, error)) {
2212c3130c78SRongwei Liu 		goto error;
221344432018SLi Zhang 	}
2214c3130c78SRongwei Liu 	fm->active_state = params->meter_enable;
221544432018SLi Zhang 	if (mtr_policy)
2216e12a0166STyler Retzlaff 		rte_atomic_fetch_add_explicit(&mtr_policy->ref_cnt, 1, rte_memory_order_relaxed);
221744432018SLi Zhang 	return 0;
221844432018SLi Zhang error:
221944432018SLi Zhang 	mlx5_flow_destroy_mtr_tbls(dev, fm);
222044432018SLi Zhang 	/* Free policer counters. */
222144432018SLi Zhang 	if (fm->drop_cnt)
222244432018SLi Zhang 		mlx5_counter_free(dev, fm->drop_cnt);
222344432018SLi Zhang 	if (priv->sh->meter_aso_en)
222444432018SLi Zhang 		mlx5_flow_mtr_free(dev, mtr_idx);
222544432018SLi Zhang 	else
222644432018SLi Zhang 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
222744432018SLi Zhang 	return -rte_mtr_error_set(error, ENOTSUP,
222844432018SLi Zhang 		RTE_MTR_ERROR_TYPE_UNSPECIFIED,
222944432018SLi Zhang 		NULL, "Failed to create devx meter.");
22305df35867SLi Zhang }
22315df35867SLi Zhang 
22327576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
223324865366SAlexander Kozyrev /**
223424865366SAlexander Kozyrev  * Create meter rules.
223524865366SAlexander Kozyrev  *
223624865366SAlexander Kozyrev  * @param[in] dev
223724865366SAlexander Kozyrev  *   Pointer to Ethernet device.
223824865366SAlexander Kozyrev  * @param[in] meter_id
223924865366SAlexander Kozyrev  *   Meter id.
224024865366SAlexander Kozyrev  * @param[in] params
224124865366SAlexander Kozyrev  *   Pointer to rte meter parameters.
224224865366SAlexander Kozyrev  * @param[in] shared
224324865366SAlexander Kozyrev  *   Meter shared with other flow or not.
224424865366SAlexander Kozyrev  * @param[out] error
224524865366SAlexander Kozyrev  *   Pointer to rte meter error structure.
224624865366SAlexander Kozyrev  *
224724865366SAlexander Kozyrev  * @return
224824865366SAlexander Kozyrev  *   0 on success, a negative errno value otherwise and rte_errno is set.
224924865366SAlexander Kozyrev  */
225024865366SAlexander Kozyrev static int
225124865366SAlexander Kozyrev mlx5_flow_meter_hws_create(struct rte_eth_dev *dev, uint32_t meter_id,
225224865366SAlexander Kozyrev 		       struct rte_mtr_params *params, int shared,
225324865366SAlexander Kozyrev 		       struct rte_mtr_error *error)
225424865366SAlexander Kozyrev {
225524865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
225624865366SAlexander Kozyrev 	struct mlx5_flow_meter_profile *profile;
225724865366SAlexander Kozyrev 	struct mlx5_flow_meter_info *fm;
225824865366SAlexander Kozyrev 	struct mlx5_flow_meter_policy *policy = NULL;
225924865366SAlexander Kozyrev 	struct mlx5_aso_mtr *aso_mtr;
22604359d9d1SGregory Etelson 	struct mlx5_hw_q_job *job;
226124865366SAlexander Kozyrev 	int ret;
226224865366SAlexander Kozyrev 
2263*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL))
2264*61a81061SGregory Etelson 		return -rte_mtr_error_set(error, EINVAL,
2265*61a81061SGregory Etelson 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
2266*61a81061SGregory Etelson 					  "non-template flow engine was not configured");
226724865366SAlexander Kozyrev 	if (!priv->mtr_profile_arr ||
226824865366SAlexander Kozyrev 	    !priv->mtr_policy_arr ||
226924865366SAlexander Kozyrev 	    !priv->mtr_bulk.aso)
227024865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOTSUP,
227124865366SAlexander Kozyrev 			RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
227224865366SAlexander Kozyrev 			"Meter bulk array is not allocated.");
227324865366SAlexander Kozyrev 	/* Meter profile must exist. */
227424865366SAlexander Kozyrev 	profile = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
227524865366SAlexander Kozyrev 	if (!profile->initialized)
227624865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOENT,
227724865366SAlexander Kozyrev 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
227824865366SAlexander Kozyrev 			NULL, "Meter profile id not valid.");
227924865366SAlexander Kozyrev 	/* Meter policy must exist. */
228024865366SAlexander Kozyrev 	policy = mlx5_flow_meter_policy_find(dev,
228124865366SAlexander Kozyrev 			params->meter_policy_id, NULL);
228224865366SAlexander Kozyrev 	if (!policy->initialized)
228324865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOENT,
228424865366SAlexander Kozyrev 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
228524865366SAlexander Kozyrev 			NULL, "Meter policy id not valid.");
228624865366SAlexander Kozyrev 	/* Meter ID must be valid. */
228724865366SAlexander Kozyrev 	if (meter_id >= priv->mtr_config.nb_meters)
228824865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, EINVAL,
228924865366SAlexander Kozyrev 			RTE_MTR_ERROR_TYPE_MTR_ID,
229024865366SAlexander Kozyrev 			NULL, "Meter id not valid.");
229124865366SAlexander Kozyrev 	/* Find ASO object. */
229224865366SAlexander Kozyrev 	aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
229324865366SAlexander Kozyrev 	fm = &aso_mtr->fm;
229424865366SAlexander Kozyrev 	if (fm->initialized)
229524865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOENT,
229624865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_MTR_ID,
229724865366SAlexander Kozyrev 					  NULL, "Meter object already exists.");
229824865366SAlexander Kozyrev 	/* Fill the flow meter parameters. */
229924865366SAlexander Kozyrev 	fm->meter_id = meter_id;
230024865366SAlexander Kozyrev 	fm->policy_id = params->meter_policy_id;
230124865366SAlexander Kozyrev 	fm->profile = profile;
230224865366SAlexander Kozyrev 	fm->meter_offset = meter_id;
230324865366SAlexander Kozyrev 	fm->group = policy->group;
230424865366SAlexander Kozyrev 	/* Add to the flow meter list. */
230524865366SAlexander Kozyrev 	fm->active_state = 1; /* Config meter starts as active. */
230624865366SAlexander Kozyrev 	fm->is_enable = params->meter_enable;
230724865366SAlexander Kozyrev 	fm->shared = !!shared;
230824865366SAlexander Kozyrev 	fm->initialized = 1;
230924865366SAlexander Kozyrev 	/* Update ASO flow meter by wqe. */
23104359d9d1SGregory Etelson 	job = mlx5_flow_action_job_init(priv, MLX5_HW_INV_QUEUE, NULL, NULL,
23114359d9d1SGregory Etelson 					NULL, MLX5_HW_Q_JOB_TYPE_CREATE, NULL);
23124359d9d1SGregory Etelson 	if (!job)
23134359d9d1SGregory Etelson 		return -rte_mtr_error_set(error, ENOMEM,
23144359d9d1SGregory Etelson 					  RTE_MTR_ERROR_TYPE_MTR_ID,
23154359d9d1SGregory Etelson 					  NULL, "No job context.");
23164359d9d1SGregory Etelson 	ret = mlx5_aso_meter_update_by_wqe(priv, MLX5_HW_INV_QUEUE, aso_mtr,
23174359d9d1SGregory Etelson 					   &priv->mtr_bulk, job, true);
23184359d9d1SGregory Etelson 	if (ret) {
2319dc7faa13SGregory Etelson 		flow_hw_job_put(priv, job, CTRL_QUEUE_ID(priv));
232024865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOTSUP,
232124865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
232224865366SAlexander Kozyrev 					  NULL, "Failed to create devx meter.");
23234359d9d1SGregory Etelson 	}
232424865366SAlexander Kozyrev 	fm->active_state = params->meter_enable;
2325e12a0166STyler Retzlaff 	rte_atomic_fetch_add_explicit(&fm->profile->ref_cnt, 1, rte_memory_order_relaxed);
2326e12a0166STyler Retzlaff 	rte_atomic_fetch_add_explicit(&policy->ref_cnt, 1, rte_memory_order_relaxed);
232724865366SAlexander Kozyrev 	return 0;
232824865366SAlexander Kozyrev }
23297576c32eSGregory Etelson #endif
233024865366SAlexander Kozyrev 
2331e6100c7bSLi Zhang static int
2332e6100c7bSLi Zhang mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
2333e6100c7bSLi Zhang 			struct mlx5_flow_meter_info *fm,
2334e6100c7bSLi Zhang 			uint32_t mtr_idx)
2335e6100c7bSLi Zhang {
2336e6100c7bSLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
2337e6100c7bSLi Zhang 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
2338e6100c7bSLi Zhang 	struct mlx5_flow_meter_profile *fmp;
2339e6100c7bSLi Zhang 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
234044432018SLi Zhang 	struct mlx5_flow_meter_policy *mtr_policy;
2341e6100c7bSLi Zhang 
2342e6100c7bSLi Zhang 	/* Meter object must not have any owner. */
2343e6100c7bSLi Zhang 	MLX5_ASSERT(!fm->ref_cnt);
2344e6100c7bSLi Zhang 	/* Get meter profile. */
2345e6100c7bSLi Zhang 	fmp = fm->profile;
2346e6100c7bSLi Zhang 	if (fmp == NULL)
2347e6100c7bSLi Zhang 		return -1;
2348e6100c7bSLi Zhang 	/* Update dependencies. */
2349e12a0166STyler Retzlaff 	rte_atomic_fetch_sub_explicit(&fmp->ref_cnt, 1, rte_memory_order_relaxed);
235044432018SLi Zhang 	fm->profile = NULL;
2351e6100c7bSLi Zhang 	/* Remove from list. */
2352e6100c7bSLi Zhang 	if (!priv->sh->meter_aso_en) {
235344432018SLi Zhang 		legacy_fm = container_of(fm,
235444432018SLi Zhang 			struct mlx5_legacy_flow_meter, fm);
2355e6100c7bSLi Zhang 		TAILQ_REMOVE(fms, legacy_fm, next);
2356e6100c7bSLi Zhang 	}
23575f0d54f3SLi Zhang 	/* Free drop counters. */
23585f0d54f3SLi Zhang 	if (fm->drop_cnt)
23595f0d54f3SLi Zhang 		mlx5_counter_free(dev, fm->drop_cnt);
2360e6100c7bSLi Zhang 	/* Free meter flow table. */
236144432018SLi Zhang 	if (fm->flow_ipool) {
2362e6100c7bSLi Zhang 		mlx5_ipool_destroy(fm->flow_ipool);
236344432018SLi Zhang 		fm->flow_ipool = 0;
236444432018SLi Zhang 	}
236544432018SLi Zhang 	mlx5_flow_destroy_mtr_tbls(dev, fm);
236644432018SLi Zhang 	if (fm->def_policy)
2367e12a0166STyler Retzlaff 		rte_atomic_fetch_sub_explicit(&priv->sh->mtrmng->def_policy_ref_cnt,
2368e12a0166STyler Retzlaff 				1, rte_memory_order_relaxed);
236944432018SLi Zhang 	if (priv->sh->meter_aso_en) {
237044432018SLi Zhang 		if (!fm->def_policy) {
237144432018SLi Zhang 			mtr_policy = mlx5_flow_meter_policy_find(dev,
237244432018SLi Zhang 						fm->policy_id, NULL);
237344432018SLi Zhang 			if (mtr_policy)
2374e12a0166STyler Retzlaff 				rte_atomic_fetch_sub_explicit(&mtr_policy->ref_cnt,
2375e12a0166STyler Retzlaff 						1, rte_memory_order_relaxed);
237644432018SLi Zhang 			fm->policy_id = 0;
237744432018SLi Zhang 		}
237844432018SLi Zhang 		fm->def_policy = 0;
237944432018SLi Zhang 		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
238044432018SLi Zhang 			return -1;
2381e6100c7bSLi Zhang 		mlx5_flow_mtr_free(dev, mtr_idx);
238244432018SLi Zhang 	} else {
2383e6100c7bSLi Zhang 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
2384e6100c7bSLi Zhang 					legacy_fm->idx);
238544432018SLi Zhang 	}
2386e6100c7bSLi Zhang 	return 0;
2387e6100c7bSLi Zhang }
2388e6100c7bSLi Zhang 
23893f373f35SSuanming Mou /**
23903f373f35SSuanming Mou  * Destroy meter rules.
23913f373f35SSuanming Mou  *
23923f373f35SSuanming Mou  * @param[in] dev
23933f373f35SSuanming Mou  *   Pointer to Ethernet device.
23943f373f35SSuanming Mou  * @param[in] meter_id
23953f373f35SSuanming Mou  *   Meter id.
23963f373f35SSuanming Mou  * @param[out] error
23973f373f35SSuanming Mou  *   Pointer to rte meter error structure.
23983f373f35SSuanming Mou  *
23993f373f35SSuanming Mou  * @return
24003f373f35SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
24013f373f35SSuanming Mou  */
24023f373f35SSuanming Mou static int
24033f373f35SSuanming Mou mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
24043f373f35SSuanming Mou 			struct rte_mtr_error *error)
24053f373f35SSuanming Mou {
24063f373f35SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
2407e6100c7bSLi Zhang 	struct mlx5_flow_meter_info *fm;
2408e6100c7bSLi Zhang 	uint32_t mtr_idx = 0;
24093f373f35SSuanming Mou 
24103f373f35SSuanming Mou 	if (!priv->mtr_en)
24113f373f35SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
241244432018SLi Zhang 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
241344432018SLi Zhang 					  NULL,
24143efac808SAli Alnubani 					  "Meter is not supported");
24153f373f35SSuanming Mou 	/* Meter object must exist. */
2416e6100c7bSLi Zhang 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
24173f373f35SSuanming Mou 	if (fm == NULL)
24183f373f35SSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
24193f373f35SSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_ID,
242044432018SLi Zhang 					  NULL,
242144432018SLi Zhang 					  "Meter object id not valid.");
24223f373f35SSuanming Mou 	/* Meter object must not have any owner. */
24233f373f35SSuanming Mou 	if (fm->ref_cnt > 0)
24243f373f35SSuanming Mou 		return -rte_mtr_error_set(error, EBUSY,
24253f373f35SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
242644432018SLi Zhang 					  NULL,
242744432018SLi Zhang 					  "Meter object is being used.");
2428e6100c7bSLi Zhang 	/* Destroy the meter profile. */
24295f0d54f3SLi Zhang 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
2430e6100c7bSLi Zhang 		return -rte_mtr_error_set(error, EINVAL,
2431e6100c7bSLi Zhang 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
243244432018SLi Zhang 					NULL,
243344432018SLi Zhang 					"MTR object meter profile invalid.");
24343f373f35SSuanming Mou 	return 0;
24353f373f35SSuanming Mou }
24363f373f35SSuanming Mou 
243733e01809SSuanming Mou /**
243824865366SAlexander Kozyrev  * Destroy meter rules.
243924865366SAlexander Kozyrev  *
244024865366SAlexander Kozyrev  * @param[in] dev
244124865366SAlexander Kozyrev  *   Pointer to Ethernet device.
244224865366SAlexander Kozyrev  * @param[in] meter_id
244324865366SAlexander Kozyrev  *   Meter id.
244424865366SAlexander Kozyrev  * @param[out] error
244524865366SAlexander Kozyrev  *   Pointer to rte meter error structure.
244624865366SAlexander Kozyrev  *
244724865366SAlexander Kozyrev  * @return
244824865366SAlexander Kozyrev  *   0 on success, a negative errno value otherwise and rte_errno is set.
244924865366SAlexander Kozyrev  */
245024865366SAlexander Kozyrev static int
245124865366SAlexander Kozyrev mlx5_flow_meter_hws_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
245224865366SAlexander Kozyrev 			struct rte_mtr_error *error)
245324865366SAlexander Kozyrev {
245424865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
245524865366SAlexander Kozyrev 	struct mlx5_aso_mtr *aso_mtr;
245624865366SAlexander Kozyrev 	struct mlx5_flow_meter_info *fm;
245724865366SAlexander Kozyrev 	struct mlx5_flow_meter_policy *policy;
245824865366SAlexander Kozyrev 
245924865366SAlexander Kozyrev 	if (!priv->mtr_profile_arr ||
246024865366SAlexander Kozyrev 	    !priv->mtr_policy_arr ||
246124865366SAlexander Kozyrev 	    !priv->mtr_bulk.aso)
246224865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOTSUP,
246324865366SAlexander Kozyrev 			RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
246424865366SAlexander Kozyrev 			"Meter bulk array is not allocated.");
246524865366SAlexander Kozyrev 	/* Find ASO object. */
246624865366SAlexander Kozyrev 	aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
246724865366SAlexander Kozyrev 	fm = &aso_mtr->fm;
246824865366SAlexander Kozyrev 	if (!fm->initialized)
246924865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, ENOENT,
247024865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_MTR_ID,
247124865366SAlexander Kozyrev 					  NULL, "Meter object id not valid.");
247224865366SAlexander Kozyrev 	/* Meter object must not have any owner. */
247324865366SAlexander Kozyrev 	if (fm->ref_cnt > 0)
247424865366SAlexander Kozyrev 		return -rte_mtr_error_set(error, EBUSY,
247524865366SAlexander Kozyrev 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
247624865366SAlexander Kozyrev 					  NULL, "Meter object is being used.");
247724865366SAlexander Kozyrev 	/* Destroy the meter profile. */
2478e12a0166STyler Retzlaff 	rte_atomic_fetch_sub_explicit(&fm->profile->ref_cnt,
2479e12a0166STyler Retzlaff 						1, rte_memory_order_relaxed);
248024865366SAlexander Kozyrev 	/* Destroy the meter policy. */
248124865366SAlexander Kozyrev 	policy = mlx5_flow_meter_policy_find(dev,
248224865366SAlexander Kozyrev 			fm->policy_id, NULL);
2483e12a0166STyler Retzlaff 	rte_atomic_fetch_sub_explicit(&policy->ref_cnt,
2484e12a0166STyler Retzlaff 						1, rte_memory_order_relaxed);
248524865366SAlexander Kozyrev 	memset(fm, 0, sizeof(struct mlx5_flow_meter_info));
248624865366SAlexander Kozyrev 	return 0;
248724865366SAlexander Kozyrev }
248824865366SAlexander Kozyrev 
248924865366SAlexander Kozyrev /**
249033e01809SSuanming Mou  * Modify meter state.
249133e01809SSuanming Mou  *
249233e01809SSuanming Mou  * @param[in] priv
249333e01809SSuanming Mou  *   Pointer to mlx5 private data structure.
249433e01809SSuanming Mou  * @param[in] fm
249533e01809SSuanming Mou  *   Pointer to flow meter.
249633e01809SSuanming Mou  * @param[in] new_state
249733e01809SSuanming Mou  *   New state to update.
249833e01809SSuanming Mou  * @param[out] error
249933e01809SSuanming Mou  *   Pointer to rte meter error structure.
250033e01809SSuanming Mou  *
250133e01809SSuanming Mou  * @return
250233e01809SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
250333e01809SSuanming Mou  */
250433e01809SSuanming Mou static int
250533e01809SSuanming Mou mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
2506e6100c7bSLi Zhang 			     struct mlx5_flow_meter_info *fm,
250733e01809SSuanming Mou 			     uint32_t new_state,
250833e01809SSuanming Mou 			     struct rte_mtr_error *error)
250933e01809SSuanming Mou {
251033e01809SSuanming Mou 	static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
2511e6100c7bSLi Zhang 		.cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL),
2512e6100c7bSLi Zhang 		.ebs_eir = 0,
251333e01809SSuanming Mou 	};
251433e01809SSuanming Mou 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
251533e01809SSuanming Mou 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
251633e01809SSuanming Mou 	int ret;
251733e01809SSuanming Mou 
251833e01809SSuanming Mou 	if (new_state == MLX5_FLOW_METER_DISABLE)
2519e93c58daSLi Zhang 		ret = mlx5_flow_meter_action_modify(priv, fm,
2520e93c58daSLi Zhang 				&srtcm, modify_bits, 0, 0);
252133e01809SSuanming Mou 	else
252233e01809SSuanming Mou 		ret = mlx5_flow_meter_action_modify(priv, fm,
252333e01809SSuanming Mou 						    &fm->profile->srtcm_prm,
2524e93c58daSLi Zhang 						    modify_bits, 0, 1);
252533e01809SSuanming Mou 	if (ret)
252633e01809SSuanming Mou 		return -rte_mtr_error_set(error, -ret,
252733e01809SSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
252833e01809SSuanming Mou 					  NULL,
252933e01809SSuanming Mou 					  new_state ?
253033e01809SSuanming Mou 					  "Failed to enable meter." :
253133e01809SSuanming Mou 					  "Failed to disable meter.");
253233e01809SSuanming Mou 	return 0;
253333e01809SSuanming Mou }
253433e01809SSuanming Mou 
253533e01809SSuanming Mou /**
253633e01809SSuanming Mou  * Callback to enable flow meter.
253733e01809SSuanming Mou  *
253833e01809SSuanming Mou  * @param[in] dev
253933e01809SSuanming Mou  *   Pointer to Ethernet device.
254033e01809SSuanming Mou  * @param[in] meter_id
254133e01809SSuanming Mou  *   Meter id.
254233e01809SSuanming Mou  * @param[out] error
254333e01809SSuanming Mou  *   Pointer to rte meter error structure.
254433e01809SSuanming Mou  *
254533e01809SSuanming Mou  * @return
254633e01809SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
254733e01809SSuanming Mou  */
254833e01809SSuanming Mou static int
254933e01809SSuanming Mou mlx5_flow_meter_enable(struct rte_eth_dev *dev,
255033e01809SSuanming Mou 		       uint32_t meter_id,
255133e01809SSuanming Mou 		       struct rte_mtr_error *error)
255233e01809SSuanming Mou {
255333e01809SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
2554e6100c7bSLi Zhang 	struct mlx5_flow_meter_info *fm;
255533e01809SSuanming Mou 	int ret;
255633e01809SSuanming Mou 
2557*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL))
2558*61a81061SGregory Etelson 		return -rte_mtr_error_set(error, EINVAL,
2559*61a81061SGregory Etelson 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
2560*61a81061SGregory Etelson 					  "non-template flow engine was not configured");
256133e01809SSuanming Mou 	if (!priv->mtr_en)
256233e01809SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
256333e01809SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
25643efac808SAli Alnubani 					  "Meter is not supported");
256533e01809SSuanming Mou 	/* Meter object must exist. */
2566e6100c7bSLi Zhang 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
256733e01809SSuanming Mou 	if (fm == NULL)
256833e01809SSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
256933e01809SSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_ID,
257033e01809SSuanming Mou 					  NULL, "Meter not found.");
257133e01809SSuanming Mou 	if (fm->active_state == MLX5_FLOW_METER_ENABLE)
257233e01809SSuanming Mou 		return 0;
257333e01809SSuanming Mou 	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
257433e01809SSuanming Mou 					   error);
257533e01809SSuanming Mou 	if (!ret)
257633e01809SSuanming Mou 		fm->active_state = MLX5_FLOW_METER_ENABLE;
257733e01809SSuanming Mou 	return ret;
257833e01809SSuanming Mou }
257933e01809SSuanming Mou 
258033e01809SSuanming Mou /**
258133e01809SSuanming Mou  * Callback to disable flow meter.
258233e01809SSuanming Mou  *
258333e01809SSuanming Mou  * @param[in] dev
258433e01809SSuanming Mou  *   Pointer to Ethernet device.
258533e01809SSuanming Mou  * @param[in] meter_id
258633e01809SSuanming Mou  *   Meter id.
258733e01809SSuanming Mou  * @param[out] error
258833e01809SSuanming Mou  *   Pointer to rte meter error structure.
258933e01809SSuanming Mou  *
259033e01809SSuanming Mou  * @return
259133e01809SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
259233e01809SSuanming Mou  */
259333e01809SSuanming Mou static int
259433e01809SSuanming Mou mlx5_flow_meter_disable(struct rte_eth_dev *dev,
259533e01809SSuanming Mou 			uint32_t meter_id,
259633e01809SSuanming Mou 			struct rte_mtr_error *error)
259733e01809SSuanming Mou {
259833e01809SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
2599e6100c7bSLi Zhang 	struct mlx5_flow_meter_info *fm;
260033e01809SSuanming Mou 	int ret;
260133e01809SSuanming Mou 
260233e01809SSuanming Mou 	if (!priv->mtr_en)
260333e01809SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
260433e01809SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
26053efac808SAli Alnubani 					  "Meter is not supported");
260633e01809SSuanming Mou 	/* Meter object must exist. */
2607e6100c7bSLi Zhang 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
260833e01809SSuanming Mou 	if (fm == NULL)
260933e01809SSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
261033e01809SSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_ID,
261133e01809SSuanming Mou 					  NULL, "Meter not found.");
261233e01809SSuanming Mou 	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
261333e01809SSuanming Mou 		return 0;
261433e01809SSuanming Mou 	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
261533e01809SSuanming Mou 					   error);
261633e01809SSuanming Mou 	if (!ret)
261733e01809SSuanming Mou 		fm->active_state = MLX5_FLOW_METER_DISABLE;
261833e01809SSuanming Mou 	return ret;
261933e01809SSuanming Mou }
262033e01809SSuanming Mou 
262163ffeb2fSSuanming Mou /**
262263ffeb2fSSuanming Mou  * Callback to update meter profile.
262363ffeb2fSSuanming Mou  *
262463ffeb2fSSuanming Mou  * @param[in] dev
262563ffeb2fSSuanming Mou  *   Pointer to Ethernet device.
262663ffeb2fSSuanming Mou  * @param[in] meter_id
262763ffeb2fSSuanming Mou  *   Meter id.
262863ffeb2fSSuanming Mou  * @param[in] meter_profile_id
262963ffeb2fSSuanming Mou  *   To be updated meter profile id.
263063ffeb2fSSuanming Mou  * @param[out] error
263163ffeb2fSSuanming Mou  *   Pointer to rte meter error structure.
263263ffeb2fSSuanming Mou  *
263363ffeb2fSSuanming Mou  * @return
263463ffeb2fSSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
263563ffeb2fSSuanming Mou  */
263663ffeb2fSSuanming Mou static int
263763ffeb2fSSuanming Mou mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
263863ffeb2fSSuanming Mou 			       uint32_t meter_id,
263963ffeb2fSSuanming Mou 			       uint32_t meter_profile_id,
264063ffeb2fSSuanming Mou 			       struct rte_mtr_error *error)
264163ffeb2fSSuanming Mou {
264263ffeb2fSSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
264363ffeb2fSSuanming Mou 	struct mlx5_flow_meter_profile *fmp;
264463ffeb2fSSuanming Mou 	struct mlx5_flow_meter_profile *old_fmp;
2645e6100c7bSLi Zhang 	struct mlx5_flow_meter_info *fm;
264663ffeb2fSSuanming Mou 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
264763ffeb2fSSuanming Mou 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
264863ffeb2fSSuanming Mou 	int ret;
264963ffeb2fSSuanming Mou 
2650*61a81061SGregory Etelson 	if (mlx5_hws_active(dev) && !mlx5_hw_ctx_validate(dev, NULL))
2651*61a81061SGregory Etelson 		return -rte_mtr_error_set(error, EINVAL,
2652*61a81061SGregory Etelson 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
2653*61a81061SGregory Etelson 					  "non-template flow engine was not configured");
265463ffeb2fSSuanming Mou 	if (!priv->mtr_en)
265563ffeb2fSSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
265663ffeb2fSSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
26573efac808SAli Alnubani 					  "Meter is not supported");
265863ffeb2fSSuanming Mou 	/* Meter profile must exist. */
265963ffeb2fSSuanming Mou 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
266063ffeb2fSSuanming Mou 	if (fmp == NULL)
266163ffeb2fSSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
266263ffeb2fSSuanming Mou 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
266363ffeb2fSSuanming Mou 					  NULL, "Meter profile not found.");
266463ffeb2fSSuanming Mou 	/* Meter object must exist. */
2665e6100c7bSLi Zhang 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
266663ffeb2fSSuanming Mou 	if (fm == NULL)
266763ffeb2fSSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
266863ffeb2fSSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_ID,
266963ffeb2fSSuanming Mou 					  NULL, "Meter not found.");
267063ffeb2fSSuanming Mou 	/* MTR object already set to meter profile id. */
267163ffeb2fSSuanming Mou 	old_fmp = fm->profile;
267263ffeb2fSSuanming Mou 	if (fmp == old_fmp)
267363ffeb2fSSuanming Mou 		return 0;
267463ffeb2fSSuanming Mou 	/* Update the profile. */
267563ffeb2fSSuanming Mou 	fm->profile = fmp;
267663ffeb2fSSuanming Mou 	/* Update meter params in HW (if not disabled). */
267763ffeb2fSSuanming Mou 	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
26789b7fcf39SShun Hao 		goto dec_ref_cnt;
267963ffeb2fSSuanming Mou 	ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
2680e93c58daSLi Zhang 					      modify_bits, fm->active_state, 1);
268163ffeb2fSSuanming Mou 	if (ret) {
268263ffeb2fSSuanming Mou 		fm->profile = old_fmp;
268363ffeb2fSSuanming Mou 		return -rte_mtr_error_set(error, -ret,
268463ffeb2fSSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
268563ffeb2fSSuanming Mou 					  NULL, "Failed to update meter"
26867be78d02SJosh Soref 					  " parameters in hardware.");
268763ffeb2fSSuanming Mou 	}
26889b7fcf39SShun Hao dec_ref_cnt:
268963ffeb2fSSuanming Mou 	old_fmp->ref_cnt--;
269063ffeb2fSSuanming Mou 	fmp->ref_cnt++;
269163ffeb2fSSuanming Mou 	return 0;
269263ffeb2fSSuanming Mou }
269363ffeb2fSSuanming Mou 
2694fab7f7d4SSuanming Mou /**
2695fab7f7d4SSuanming Mou  * Callback to update meter stats mask.
2696fab7f7d4SSuanming Mou  *
2697fab7f7d4SSuanming Mou  * @param[in] dev
2698fab7f7d4SSuanming Mou  *   Pointer to Ethernet device.
2699fab7f7d4SSuanming Mou  * @param[in] meter_id
2700fab7f7d4SSuanming Mou  *   Meter id.
2701fab7f7d4SSuanming Mou  * @param[in] stats_mask
2702fab7f7d4SSuanming Mou  *   To be updated stats_mask.
2703fab7f7d4SSuanming Mou  * @param[out] error
2704fab7f7d4SSuanming Mou  *   Pointer to rte meter error structure.
2705fab7f7d4SSuanming Mou  *
2706fab7f7d4SSuanming Mou  * @return
2707fab7f7d4SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
2708fab7f7d4SSuanming Mou  */
2709fab7f7d4SSuanming Mou static int
2710fab7f7d4SSuanming Mou mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
2711fab7f7d4SSuanming Mou 			     uint32_t meter_id,
2712fab7f7d4SSuanming Mou 			     uint64_t stats_mask,
2713fab7f7d4SSuanming Mou 			     struct rte_mtr_error *error)
2714fab7f7d4SSuanming Mou {
2715fab7f7d4SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
2716e6100c7bSLi Zhang 	struct mlx5_flow_meter_info *fm;
2717fab7f7d4SSuanming Mou 
2718fab7f7d4SSuanming Mou 	if (!priv->mtr_en)
2719fab7f7d4SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
2720fab7f7d4SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
27213efac808SAli Alnubani 					  "Meter is not supported");
2722fab7f7d4SSuanming Mou 	/* Meter object must exist. */
2723e6100c7bSLi Zhang 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
2724fab7f7d4SSuanming Mou 	if (fm == NULL)
2725fab7f7d4SSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
2726fab7f7d4SSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_ID,
2727fab7f7d4SSuanming Mou 					  NULL, "Meter object id not valid.");
272844432018SLi Zhang 	if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
272944432018SLi Zhang 		return -rte_mtr_error_set(error, ENOENT,
273044432018SLi Zhang 					  RTE_MTR_ERROR_TYPE_MTR_ID,
273144432018SLi Zhang 					  NULL, "Fail to allocate "
273244432018SLi Zhang 					  "counter for meter.");
2733fab7f7d4SSuanming Mou 	return 0;
2734fab7f7d4SSuanming Mou }
2735fab7f7d4SSuanming Mou 
2736fab7f7d4SSuanming Mou /**
2737fab7f7d4SSuanming Mou  * Callback to read meter statistics.
2738fab7f7d4SSuanming Mou  *
2739fab7f7d4SSuanming Mou  * @param[in] dev
2740fab7f7d4SSuanming Mou  *   Pointer to Ethernet device.
2741fab7f7d4SSuanming Mou  * @param[in] meter_id
2742fab7f7d4SSuanming Mou  *   Meter id.
2743fab7f7d4SSuanming Mou  * @param[out] stats
2744fab7f7d4SSuanming Mou  *   Pointer to store the statistics.
2745fab7f7d4SSuanming Mou  * @param[out] stats_mask
2746fab7f7d4SSuanming Mou  *   Pointer to store the stats_mask.
2747fab7f7d4SSuanming Mou  * @param[in] clear
2748fab7f7d4SSuanming Mou  *   Statistic to be cleared after read or not.
2749fab7f7d4SSuanming Mou  * @param[out] error
2750fab7f7d4SSuanming Mou  *   Pointer to rte meter error structure.
2751fab7f7d4SSuanming Mou  *
2752fab7f7d4SSuanming Mou  * @return
2753fab7f7d4SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
2754fab7f7d4SSuanming Mou  */
2755fab7f7d4SSuanming Mou static int
2756fab7f7d4SSuanming Mou mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
2757fab7f7d4SSuanming Mou 			   uint32_t meter_id,
2758fab7f7d4SSuanming Mou 			   struct rte_mtr_stats *stats,
2759fab7f7d4SSuanming Mou 			   uint64_t *stats_mask,
2760fab7f7d4SSuanming Mou 			   int clear,
2761fab7f7d4SSuanming Mou 			   struct rte_mtr_error *error)
2762fab7f7d4SSuanming Mou {
2763fab7f7d4SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
2764e6100c7bSLi Zhang 	struct mlx5_flow_meter_info *fm;
2765fab7f7d4SSuanming Mou 	uint64_t pkts;
2766fab7f7d4SSuanming Mou 	uint64_t bytes;
2767fab7f7d4SSuanming Mou 	int ret = 0;
2768fab7f7d4SSuanming Mou 
2769fab7f7d4SSuanming Mou 	if (!priv->mtr_en)
2770fab7f7d4SSuanming Mou 		return -rte_mtr_error_set(error, ENOTSUP,
2771fab7f7d4SSuanming Mou 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
27723efac808SAli Alnubani 					  "Meter is not supported");
2773fab7f7d4SSuanming Mou 	/* Meter object must exist. */
2774e6100c7bSLi Zhang 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
2775fab7f7d4SSuanming Mou 	if (fm == NULL)
2776fab7f7d4SSuanming Mou 		return -rte_mtr_error_set(error, ENOENT,
2777fab7f7d4SSuanming Mou 					  RTE_MTR_ERROR_TYPE_MTR_ID,
2778fab7f7d4SSuanming Mou 					  NULL, "Meter object id not valid.");
27795df35867SLi Zhang 	*stats_mask = 0;
27805df35867SLi Zhang 	if (fm->bytes_dropped)
27815df35867SLi Zhang 		*stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
27825df35867SLi Zhang 	if (fm->pkts_dropped)
27835df35867SLi Zhang 		*stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
27845df35867SLi Zhang 	memset(stats, 0, sizeof(*stats));
27855f0d54f3SLi Zhang 	if (fm->drop_cnt) {
27865f0d54f3SLi Zhang 		ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
27879b57df55SHaifei Luo 						 &bytes, NULL);
2788fab7f7d4SSuanming Mou 		if (ret)
2789fab7f7d4SSuanming Mou 			goto error;
2790fab7f7d4SSuanming Mou 		/* If need to read the packets, set it. */
27915df35867SLi Zhang 		if (fm->pkts_dropped)
2792fab7f7d4SSuanming Mou 			stats->n_pkts_dropped = pkts;
2793fab7f7d4SSuanming Mou 		/* If need to read the bytes, set it. */
27945df35867SLi Zhang 		if (fm->bytes_dropped)
2795fab7f7d4SSuanming Mou 			stats->n_bytes_dropped = bytes;
2796fab7f7d4SSuanming Mou 	}
2797fab7f7d4SSuanming Mou 	return 0;
2798fab7f7d4SSuanming Mou error:
2799fab7f7d4SSuanming Mou 	return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
28005f0d54f3SLi Zhang 				 "Failed to read meter drop counters.");
2801fab7f7d4SSuanming Mou }
2802fab7f7d4SSuanming Mou 
2803d740eb50SSuanming Mou static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
28046bc327b9SSuanming Mou 	.capabilities_get = mlx5_flow_mtr_cap_get,
28053bd26b23SSuanming Mou 	.meter_profile_add = mlx5_flow_meter_profile_add,
28063bd26b23SSuanming Mou 	.meter_profile_delete = mlx5_flow_meter_profile_delete,
280748fbb0e9SAlexander Kozyrev 	.meter_profile_get = mlx5_flow_meter_profile_get,
2808afb4aa4fSLi Zhang 	.meter_policy_validate = mlx5_flow_meter_policy_validate,
2809afb4aa4fSLi Zhang 	.meter_policy_add = mlx5_flow_meter_policy_add,
2810afb4aa4fSLi Zhang 	.meter_policy_delete = mlx5_flow_meter_policy_delete,
281148fbb0e9SAlexander Kozyrev 	.meter_policy_get = mlx5_flow_meter_policy_get,
281244432018SLi Zhang 	.create = mlx5_flow_meter_create,
28133f373f35SSuanming Mou 	.destroy = mlx5_flow_meter_destroy,
281433e01809SSuanming Mou 	.meter_enable = mlx5_flow_meter_enable,
281533e01809SSuanming Mou 	.meter_disable = mlx5_flow_meter_disable,
281663ffeb2fSSuanming Mou 	.meter_profile_update = mlx5_flow_meter_profile_update,
2817d740eb50SSuanming Mou 	.meter_dscp_table_update = NULL,
2818fab7f7d4SSuanming Mou 	.stats_update = mlx5_flow_meter_stats_update,
2819fab7f7d4SSuanming Mou 	.stats_read = mlx5_flow_meter_stats_read,
2820d740eb50SSuanming Mou };
2821d740eb50SSuanming Mou 
28227576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
282324865366SAlexander Kozyrev static const struct rte_mtr_ops mlx5_flow_mtr_hws_ops = {
282424865366SAlexander Kozyrev 	.capabilities_get = mlx5_flow_mtr_cap_get,
282524865366SAlexander Kozyrev 	.meter_profile_add = mlx5_flow_meter_profile_hws_add,
282624865366SAlexander Kozyrev 	.meter_profile_delete = mlx5_flow_meter_profile_hws_delete,
282748fbb0e9SAlexander Kozyrev 	.meter_profile_get = mlx5_flow_meter_profile_get,
282824865366SAlexander Kozyrev 	.meter_policy_validate = mlx5_flow_meter_policy_hws_validate,
282924865366SAlexander Kozyrev 	.meter_policy_add = mlx5_flow_meter_policy_hws_add,
283024865366SAlexander Kozyrev 	.meter_policy_delete = mlx5_flow_meter_policy_hws_delete,
283148fbb0e9SAlexander Kozyrev 	.meter_policy_get = mlx5_flow_meter_policy_get,
283224865366SAlexander Kozyrev 	.create = mlx5_flow_meter_hws_create,
283324865366SAlexander Kozyrev 	.destroy = mlx5_flow_meter_hws_destroy,
283424865366SAlexander Kozyrev 	.meter_enable = mlx5_flow_meter_enable,
283524865366SAlexander Kozyrev 	.meter_disable = mlx5_flow_meter_disable,
283624865366SAlexander Kozyrev 	.meter_profile_update = mlx5_flow_meter_profile_update,
283724865366SAlexander Kozyrev 	.meter_dscp_table_update = NULL,
283824865366SAlexander Kozyrev 	.stats_update = NULL,
283924865366SAlexander Kozyrev 	.stats_read = NULL,
284024865366SAlexander Kozyrev };
28417576c32eSGregory Etelson #endif
284224865366SAlexander Kozyrev 
2843d740eb50SSuanming Mou /**
2844d740eb50SSuanming Mou  * Get meter operations.
2845d740eb50SSuanming Mou  *
2846d740eb50SSuanming Mou  * @param dev
2847d740eb50SSuanming Mou  *   Pointer to Ethernet device structure.
2848d740eb50SSuanming Mou  * @param arg
2849d740eb50SSuanming Mou  *   Pointer to set the mtr operations.
2850d740eb50SSuanming Mou  *
2851d740eb50SSuanming Mou  * @return
2852d740eb50SSuanming Mou  *   Always 0.
2853d740eb50SSuanming Mou  */
2854d740eb50SSuanming Mou int
2855d740eb50SSuanming Mou mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
2856d740eb50SSuanming Mou {
28577576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
285824865366SAlexander Kozyrev 	struct mlx5_priv *priv = dev->data->dev_private;
285924865366SAlexander Kozyrev 
286024865366SAlexander Kozyrev 	if (priv->sh->config.dv_flow_en == 2)
286124865366SAlexander Kozyrev 		*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_hws_ops;
286224865366SAlexander Kozyrev 	else
2863d740eb50SSuanming Mou 		*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
28647576c32eSGregory Etelson #else
28657576c32eSGregory Etelson 	*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
28667576c32eSGregory Etelson #endif
2867d740eb50SSuanming Mou 	return 0;
2868d740eb50SSuanming Mou }
28693f373f35SSuanming Mou 
28703f373f35SSuanming Mou /**
28713f373f35SSuanming Mou  * Find meter by id.
28723f373f35SSuanming Mou  *
28733f373f35SSuanming Mou  * @param priv
28743f373f35SSuanming Mou  *   Pointer to mlx5_priv.
28753f373f35SSuanming Mou  * @param meter_id
28763f373f35SSuanming Mou  *   Meter id.
2877e93c58daSLi Zhang  * @param mtr_idx
2878e93c58daSLi Zhang  *   Pointer to Meter index.
28793f373f35SSuanming Mou  *
28803f373f35SSuanming Mou  * @return
288144432018SLi Zhang  *   Pointer to the meter info found on success, NULL otherwise.
28823f373f35SSuanming Mou  */
2883e6100c7bSLi Zhang struct mlx5_flow_meter_info *
2884e6100c7bSLi Zhang mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
2885e6100c7bSLi Zhang 		uint32_t *mtr_idx)
28863f373f35SSuanming Mou {
2887e6100c7bSLi Zhang 	struct mlx5_legacy_flow_meter *legacy_fm;
2888e6100c7bSLi Zhang 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
2889e6100c7bSLi Zhang 	struct mlx5_aso_mtr *aso_mtr;
2890afb4aa4fSLi Zhang 	struct mlx5_aso_mtr_pools_mng *pools_mng =
2891afb4aa4fSLi Zhang 				&priv->sh->mtrmng->pools_mng;
2892e6100c7bSLi Zhang 	union mlx5_l3t_data data;
28937797b0feSJiawei Wang 	uint16_t n_valid;
28943f373f35SSuanming Mou 
289524865366SAlexander Kozyrev 	if (priv->mtr_bulk.aso) {
289624865366SAlexander Kozyrev 		if (mtr_idx)
289724865366SAlexander Kozyrev 			*mtr_idx = meter_id;
289824865366SAlexander Kozyrev 		aso_mtr = priv->mtr_bulk.aso + meter_id;
289924865366SAlexander Kozyrev 		return &aso_mtr->fm;
290024865366SAlexander Kozyrev 	}
2901e6100c7bSLi Zhang 	if (priv->sh->meter_aso_en) {
29027797b0feSJiawei Wang 		rte_rwlock_read_lock(&pools_mng->resize_mtrwl);
29037797b0feSJiawei Wang 		n_valid = pools_mng->n_valid;
29047797b0feSJiawei Wang 		rte_rwlock_read_unlock(&pools_mng->resize_mtrwl);
29057797b0feSJiawei Wang 		if (!n_valid || !priv->mtr_idx_tbl ||
29067797b0feSJiawei Wang 		    (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
29077797b0feSJiawei Wang 		    !data.dword))
290844432018SLi Zhang 			return NULL;
2909e6100c7bSLi Zhang 		if (mtr_idx)
2910e6100c7bSLi Zhang 			*mtr_idx = data.dword;
2911e6100c7bSLi Zhang 		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
2912e93c58daSLi Zhang 		/* Remove reference taken by the mlx5_l3t_get_entry. */
291329efa63aSLi Zhang 		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
2914afb4aa4fSLi Zhang 		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
2915afb4aa4fSLi Zhang 			return NULL;
2916e6100c7bSLi Zhang 		return &aso_mtr->fm;
2917e6100c7bSLi Zhang 	}
2918e6100c7bSLi Zhang 	TAILQ_FOREACH(legacy_fm, fms, next)
291944432018SLi Zhang 		if (meter_id == legacy_fm->fm.meter_id) {
2920e93c58daSLi Zhang 			if (mtr_idx)
2921e93c58daSLi Zhang 				*mtr_idx = legacy_fm->idx;
2922e6100c7bSLi Zhang 			return &legacy_fm->fm;
2923e6100c7bSLi Zhang 		}
2924e6100c7bSLi Zhang 	return NULL;
2925e6100c7bSLi Zhang }
2926e6100c7bSLi Zhang 
2927e6100c7bSLi Zhang /**
2928e6100c7bSLi Zhang  * Find meter by index.
2929e6100c7bSLi Zhang  *
2930e6100c7bSLi Zhang  * @param priv
2931e6100c7bSLi Zhang  *   Pointer to mlx5_priv.
2932e6100c7bSLi Zhang  * @param idx
2933e6100c7bSLi Zhang  *   Meter index.
2934e6100c7bSLi Zhang  *
2935e6100c7bSLi Zhang  * @return
293644432018SLi Zhang  *   Pointer to the meter info found on success, NULL otherwise.
2937e6100c7bSLi Zhang  */
2938e6100c7bSLi Zhang struct mlx5_flow_meter_info *
2939e6100c7bSLi Zhang flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
2940e6100c7bSLi Zhang {
2941e6100c7bSLi Zhang 	struct mlx5_aso_mtr *aso_mtr;
2942e6100c7bSLi Zhang 
2943e6100c7bSLi Zhang 	if (priv->sh->meter_aso_en) {
2944e6100c7bSLi Zhang 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
294544432018SLi Zhang 		if (!aso_mtr)
294644432018SLi Zhang 			return NULL;
2947e6100c7bSLi Zhang 		return &aso_mtr->fm;
2948e6100c7bSLi Zhang 	} else {
2949e6100c7bSLi Zhang 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
2950e6100c7bSLi Zhang 	}
2951e6100c7bSLi Zhang }
2952266e9f3dSSuanming Mou 
2953266e9f3dSSuanming Mou /**
2954266e9f3dSSuanming Mou  * Attach meter to flow.
2955266e9f3dSSuanming Mou  * Unidirectional Meter creation can only be done
2956266e9f3dSSuanming Mou  * when flow direction is known, i.e. when calling meter_attach.
2957266e9f3dSSuanming Mou  *
2958266e9f3dSSuanming Mou  * @param [in] priv
2959266e9f3dSSuanming Mou  *  Pointer to mlx5 private data.
296083306d6cSShun Hao  * @param[in] fm
296183306d6cSShun Hao  *   Pointer to flow meter.
2962266e9f3dSSuanming Mou  * @param [in] attr
2963266e9f3dSSuanming Mou  *  Pointer to flow attributes.
2964266e9f3dSSuanming Mou  * @param [out] error
2965266e9f3dSSuanming Mou  *  Pointer to error structure.
2966266e9f3dSSuanming Mou  *
296783306d6cSShun Hao  * @return
296883306d6cSShun Hao  *   0 on success, a negative errno value otherwise and rte_errno is set.
2969266e9f3dSSuanming Mou  */
297083306d6cSShun Hao int
297183306d6cSShun Hao mlx5_flow_meter_attach(struct mlx5_priv *priv,
2972e6100c7bSLi Zhang 		       struct mlx5_flow_meter_info *fm,
2973266e9f3dSSuanming Mou 		       const struct rte_flow_attr *attr,
2974266e9f3dSSuanming Mou 		       struct rte_flow_error *error)
2975266e9f3dSSuanming Mou {
297689a8e3c4SSuanming Mou 	int ret = 0;
2977266e9f3dSSuanming Mou 
2978c99b4f8bSLi Zhang 	if (priv->sh->meter_aso_en) {
2979c99b4f8bSLi Zhang 		struct mlx5_aso_mtr *aso_mtr;
2980c99b4f8bSLi Zhang 
2981c99b4f8bSLi Zhang 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
29824359d9d1SGregory Etelson 		if (mlx5_aso_mtr_wait(priv, aso_mtr, false)) {
2983c99b4f8bSLi Zhang 			return rte_flow_error_set(error, ENOENT,
2984c99b4f8bSLi Zhang 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2985c99b4f8bSLi Zhang 					NULL,
2986c99b4f8bSLi Zhang 					"Timeout in meter configuration");
2987c99b4f8bSLi Zhang 		}
298889a8e3c4SSuanming Mou 		rte_spinlock_lock(&fm->sl);
2989c99b4f8bSLi Zhang 		if (fm->shared || !fm->ref_cnt) {
2990c99b4f8bSLi Zhang 			fm->ref_cnt++;
2991c99b4f8bSLi Zhang 		} else {
2992c99b4f8bSLi Zhang 			rte_flow_error_set(error, EINVAL,
2993c99b4f8bSLi Zhang 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2994c99b4f8bSLi Zhang 				   "Meter cannot be shared");
2995c99b4f8bSLi Zhang 			ret = -1;
2996c99b4f8bSLi Zhang 		}
2997c99b4f8bSLi Zhang 		rte_spinlock_unlock(&fm->sl);
2998c99b4f8bSLi Zhang 	} else {
2999c99b4f8bSLi Zhang 		rte_spinlock_lock(&fm->sl);
3000bf62fb76SShun Hao 		if (fm->meter_action_g) {
300189a8e3c4SSuanming Mou 			if (fm->shared &&
300289a8e3c4SSuanming Mou 			    attr->transfer == fm->transfer &&
300389a8e3c4SSuanming Mou 			    attr->ingress == fm->ingress &&
3004c99b4f8bSLi Zhang 			    attr->egress == fm->egress) {
300589a8e3c4SSuanming Mou 				fm->ref_cnt++;
3006c99b4f8bSLi Zhang 			} else {
3007c99b4f8bSLi Zhang 				rte_flow_error_set(error, EINVAL,
3008c99b4f8bSLi Zhang 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3009c99b4f8bSLi Zhang 					fm->shared ?
3010c99b4f8bSLi Zhang 					"Meter attr not match." :
3011c99b4f8bSLi Zhang 					"Meter cannot be shared.");
301289a8e3c4SSuanming Mou 				ret = -1;
3013c99b4f8bSLi Zhang 			}
301489a8e3c4SSuanming Mou 		} else {
301578466e08SWentao Cui 			fm->ingress = attr->ingress;
301678466e08SWentao Cui 			fm->egress = attr->egress;
301778466e08SWentao Cui 			fm->transfer = attr->transfer;
301889a8e3c4SSuanming Mou 			fm->ref_cnt = 1;
3019266e9f3dSSuanming Mou 			/* This also creates the meter object. */
3020bf62fb76SShun Hao 			fm->meter_action_g = mlx5_flow_meter_action_create(priv,
3021266e9f3dSSuanming Mou 									 fm);
3022bf62fb76SShun Hao 			if (!fm->meter_action_g) {
302389a8e3c4SSuanming Mou 				fm->ref_cnt = 0;
302489a8e3c4SSuanming Mou 				fm->ingress = 0;
302589a8e3c4SSuanming Mou 				fm->egress = 0;
302689a8e3c4SSuanming Mou 				fm->transfer = 0;
3027c99b4f8bSLi Zhang 				rte_flow_error_set(error, EINVAL,
3028c99b4f8bSLi Zhang 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3029c99b4f8bSLi Zhang 					"Meter action create failed.");
303089a8e3c4SSuanming Mou 				ret = -1;
3031266e9f3dSSuanming Mou 			}
3032266e9f3dSSuanming Mou 		}
303389a8e3c4SSuanming Mou 		rte_spinlock_unlock(&fm->sl);
3034c99b4f8bSLi Zhang 	}
303583306d6cSShun Hao 	return ret ? -rte_errno : 0;
3036266e9f3dSSuanming Mou }
3037266e9f3dSSuanming Mou 
3038266e9f3dSSuanming Mou /**
3039266e9f3dSSuanming Mou  * Detach meter from flow.
3040266e9f3dSSuanming Mou  *
3041c99b4f8bSLi Zhang  * @param [in] priv
3042c99b4f8bSLi Zhang  *  Pointer to mlx5 private data.
3043266e9f3dSSuanming Mou  * @param [in] fm
3044266e9f3dSSuanming Mou  *  Pointer to flow meter.
3045266e9f3dSSuanming Mou  */
3046266e9f3dSSuanming Mou void
3047c99b4f8bSLi Zhang mlx5_flow_meter_detach(struct mlx5_priv *priv,
3048c99b4f8bSLi Zhang 		       struct mlx5_flow_meter_info *fm)
3049266e9f3dSSuanming Mou {
30501e577c9eSOphir Munk #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
305189a8e3c4SSuanming Mou 	rte_spinlock_lock(&fm->sl);
30528e46d4e1SAlexander Kozyrev 	MLX5_ASSERT(fm->ref_cnt);
3053c99b4f8bSLi Zhang 	if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
3054bf62fb76SShun Hao 		mlx5_glue->destroy_flow_action(fm->meter_action_g);
3055bf62fb76SShun Hao 		fm->meter_action_g = NULL;
305678466e08SWentao Cui 		fm->ingress = 0;
305778466e08SWentao Cui 		fm->egress = 0;
305878466e08SWentao Cui 		fm->transfer = 0;
305989a8e3c4SSuanming Mou 	}
306089a8e3c4SSuanming Mou 	rte_spinlock_unlock(&fm->sl);
30611e577c9eSOphir Munk #else
3062c99b4f8bSLi Zhang 	(void)priv;
30631e577c9eSOphir Munk 	(void)fm;
30641e577c9eSOphir Munk #endif
3065266e9f3dSSuanming Mou }
306602e76468SSuanming Mou 
306702e76468SSuanming Mou /**
3068ec962badSLi Zhang  * Flush meter with Rx queue configuration.
3069ec962badSLi Zhang  *
3070ec962badSLi Zhang  * @param[in] dev
3071ec962badSLi Zhang  *   Pointer to Ethernet device.
3072ec962badSLi Zhang  */
3073ec962badSLi Zhang void
3074ec962badSLi Zhang mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev)
3075ec962badSLi Zhang {
3076ec962badSLi Zhang 	struct mlx5_priv *priv = dev->data->dev_private;
3077ec962badSLi Zhang 	struct mlx5_flow_meter_sub_policy *sub_policy;
3078ec962badSLi Zhang 	struct mlx5_flow_meter_policy *mtr_policy;
3079ec962badSLi Zhang 	void *entry;
3080ec962badSLi Zhang 	uint32_t i, policy_idx;
3081ec962badSLi Zhang 
3082ec962badSLi Zhang 	if (!priv->mtr_en)
3083ec962badSLi Zhang 		return;
3084efcce4dcSShun Hao 	if (priv->policy_idx_tbl) {
3085efcce4dcSShun Hao 		MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
3086ec962badSLi Zhang 			policy_idx = *(uint32_t *)entry;
3087ec962badSLi Zhang 			sub_policy = mlx5_ipool_get
3088ec962badSLi Zhang 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
3089ec962badSLi Zhang 				policy_idx);
3090ec962badSLi Zhang 			if (!sub_policy || !sub_policy->main_policy)
3091ec962badSLi Zhang 				continue;
3092ec962badSLi Zhang 			mtr_policy = sub_policy->main_policy;
3093ec962badSLi Zhang 			if (mtr_policy->is_queue || mtr_policy->is_rss)
3094ec962badSLi Zhang 				mlx5_flow_destroy_sub_policy_with_rxq(dev,
3095ec962badSLi Zhang 					mtr_policy);
3096ec962badSLi Zhang 		}
3097ec962badSLi Zhang 	}
3098ec962badSLi Zhang }
3099ec962badSLi Zhang 
3100ec962badSLi Zhang /**
3101f890b030SShun Hao  * Iterate a meter hierarchy and flush all meters and policies if possible.
3102f890b030SShun Hao  *
3103f890b030SShun Hao  * @param[in] dev
3104f890b030SShun Hao  *   Pointer to Ethernet device.
3105f890b030SShun Hao  * @param[in] fm
3106f890b030SShun Hao  *   Pointer to flow meter.
3107f890b030SShun Hao  * @param[in] mtr_idx
3108f890b030SShun Hao  *   .Meter's index
3109f890b030SShun Hao  * @param[out] error
3110f890b030SShun Hao  *   Pointer to rte meter error structure.
3111f890b030SShun Hao  *
3112f890b030SShun Hao  * @return
3113f890b030SShun Hao  *   0 on success, a negative errno value otherwise and rte_errno is set.
3114f890b030SShun Hao  */
3115f890b030SShun Hao static int
3116f890b030SShun Hao mlx5_flow_meter_flush_hierarchy(struct rte_eth_dev *dev,
3117f890b030SShun Hao 				struct mlx5_flow_meter_info *fm,
3118f890b030SShun Hao 				uint32_t mtr_idx,
3119f890b030SShun Hao 				struct rte_mtr_error *error)
3120f890b030SShun Hao {
3121f890b030SShun Hao 	struct mlx5_priv *priv = dev->data->dev_private;
3122f890b030SShun Hao 	struct mlx5_flow_meter_policy *policy;
3123f890b030SShun Hao 	uint32_t policy_id;
3124f890b030SShun Hao 	struct mlx5_flow_meter_info *next_fm;
3125f890b030SShun Hao 	uint32_t next_mtr_idx;
3126f890b030SShun Hao 	struct mlx5_flow_meter_policy *next_policy = NULL;
3127f890b030SShun Hao 
3128f890b030SShun Hao 	policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
3129f890b030SShun Hao 	MLX5_ASSERT(policy);
3130f890b030SShun Hao 	while (!fm->ref_cnt && policy->is_hierarchy) {
3131f890b030SShun Hao 		policy_id = fm->policy_id;
3132bf62fb76SShun Hao 		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &next_mtr_idx);
3133f890b030SShun Hao 		if (next_fm) {
3134f890b030SShun Hao 			next_policy = mlx5_flow_meter_policy_find(dev,
3135f890b030SShun Hao 							next_fm->policy_id,
3136f890b030SShun Hao 							NULL);
3137f890b030SShun Hao 			MLX5_ASSERT(next_policy);
3138f890b030SShun Hao 		}
3139f890b030SShun Hao 		if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
3140f890b030SShun Hao 			return -rte_mtr_error_set(error, ENOTSUP,
3141f890b030SShun Hao 						RTE_MTR_ERROR_TYPE_MTR_ID,
3142f890b030SShun Hao 						NULL,
3143f890b030SShun Hao 						"Failed to flush meter.");
3144f890b030SShun Hao 		if (policy->ref_cnt)
3145f890b030SShun Hao 			break;
3146f890b030SShun Hao 		if (__mlx5_flow_meter_policy_delete(dev, policy_id,
3147f890b030SShun Hao 						policy, error, true))
3148f890b030SShun Hao 			return -rte_errno;
3149f890b030SShun Hao 		mlx5_free(policy);
3150f890b030SShun Hao 		if (!next_fm || !next_policy)
3151f890b030SShun Hao 			break;
3152f890b030SShun Hao 		fm = next_fm;
3153f890b030SShun Hao 		mtr_idx = next_mtr_idx;
3154f890b030SShun Hao 		policy = next_policy;
3155f890b030SShun Hao 	}
3156f890b030SShun Hao 	return 0;
3157f890b030SShun Hao }
3158f890b030SShun Hao 
3159f890b030SShun Hao /**
3160f890b030SShun Hao  * Flush all the hierarchy meters and their policies.
3161f890b030SShun Hao  *
3162f890b030SShun Hao  * @param[in] dev
3163f890b030SShun Hao  *   Pointer to Ethernet device.
3164f890b030SShun Hao  * @param[out] error
3165f890b030SShun Hao  *   Pointer to rte meter error structure.
3166f890b030SShun Hao  *
3167f890b030SShun Hao  * @return
3168f890b030SShun Hao  *   0 on success, a negative errno value otherwise and rte_errno is set.
3169f890b030SShun Hao  */
3170f890b030SShun Hao static int
3171f890b030SShun Hao mlx5_flow_meter_flush_all_hierarchies(struct rte_eth_dev *dev,
3172f890b030SShun Hao 				      struct rte_mtr_error *error)
3173f890b030SShun Hao {
3174f890b030SShun Hao 	struct mlx5_priv *priv = dev->data->dev_private;
3175f890b030SShun Hao 	struct mlx5_flow_meter_info *fm;
3176f890b030SShun Hao 	struct mlx5_flow_meter_policy *policy;
3177f890b030SShun Hao 	struct mlx5_flow_meter_sub_policy *sub_policy;
3178f890b030SShun Hao 	struct mlx5_flow_meter_info *next_fm;
3179f890b030SShun Hao 	struct mlx5_aso_mtr *aso_mtr;
3180f890b030SShun Hao 	uint32_t mtr_idx = 0;
3181f890b030SShun Hao 	uint32_t i, policy_idx;
3182f890b030SShun Hao 	void *entry;
3183f890b030SShun Hao 
3184f890b030SShun Hao 	if (!priv->mtr_idx_tbl || !priv->policy_idx_tbl)
3185f890b030SShun Hao 		return 0;
3186f890b030SShun Hao 	MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
3187f890b030SShun Hao 		mtr_idx = *(uint32_t *)entry;
3188f890b030SShun Hao 		if (!mtr_idx)
3189f890b030SShun Hao 			continue;
3190f890b030SShun Hao 		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
3191f890b030SShun Hao 		fm = &aso_mtr->fm;
3192f890b030SShun Hao 		if (fm->ref_cnt || fm->def_policy)
3193f890b030SShun Hao 			continue;
3194f890b030SShun Hao 		if (mlx5_flow_meter_flush_hierarchy(dev, fm, mtr_idx, error))
3195f890b030SShun Hao 			return -rte_errno;
3196f890b030SShun Hao 	}
3197f890b030SShun Hao 	MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
3198f890b030SShun Hao 		policy_idx = *(uint32_t *)entry;
3199f890b030SShun Hao 		sub_policy = mlx5_ipool_get
3200f890b030SShun Hao 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
3201f890b030SShun Hao 				policy_idx);
3202f890b030SShun Hao 		if (!sub_policy)
3203f890b030SShun Hao 			return -rte_mtr_error_set(error,
3204f890b030SShun Hao 					EINVAL,
3205f890b030SShun Hao 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
3206f890b030SShun Hao 					NULL, "Meter policy invalid.");
3207f890b030SShun Hao 		policy = sub_policy->main_policy;
3208f890b030SShun Hao 		if (!policy || !policy->is_hierarchy || policy->ref_cnt)
3209f890b030SShun Hao 			continue;
3210bf62fb76SShun Hao 		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &mtr_idx);
3211f890b030SShun Hao 		if (__mlx5_flow_meter_policy_delete(dev, i, policy,
3212f890b030SShun Hao 						    error, true))
3213f890b030SShun Hao 			return -rte_mtr_error_set(error,
3214f890b030SShun Hao 					EINVAL,
3215f890b030SShun Hao 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
3216f890b030SShun Hao 					NULL, "Meter policy invalid.");
3217f890b030SShun Hao 		mlx5_free(policy);
3218f890b030SShun Hao 		if (!next_fm || next_fm->ref_cnt || next_fm->def_policy)
3219f890b030SShun Hao 			continue;
3220f890b030SShun Hao 		if (mlx5_flow_meter_flush_hierarchy(dev, next_fm,
3221f890b030SShun Hao 						    mtr_idx, error))
3222f890b030SShun Hao 			return -rte_errno;
3223f890b030SShun Hao 	}
3224f890b030SShun Hao 	return 0;
3225f890b030SShun Hao }
3226f890b030SShun Hao /**
322702e76468SSuanming Mou  * Flush meter configuration.
322802e76468SSuanming Mou  *
322902e76468SSuanming Mou  * @param[in] dev
323002e76468SSuanming Mou  *   Pointer to Ethernet device.
323102e76468SSuanming Mou  * @param[out] error
323202e76468SSuanming Mou  *   Pointer to rte meter error structure.
323302e76468SSuanming Mou  *
323402e76468SSuanming Mou  * @return
323502e76468SSuanming Mou  *   0 on success, a negative errno value otherwise and rte_errno is set.
323602e76468SSuanming Mou  */
323702e76468SSuanming Mou int
323802e76468SSuanming Mou mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
323902e76468SSuanming Mou {
324002e76468SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
3241e6100c7bSLi Zhang 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
324202e76468SSuanming Mou 	struct mlx5_flow_meter_profile *fmp;
3243e6100c7bSLi Zhang 	struct mlx5_legacy_flow_meter *legacy_fm;
3244e6100c7bSLi Zhang 	struct mlx5_flow_meter_info *fm;
3245afb4aa4fSLi Zhang 	struct mlx5_flow_meter_sub_policy *sub_policy;
324602e76468SSuanming Mou 	void *tmp;
324744432018SLi Zhang 	uint32_t i, mtr_idx, policy_idx;
3248afb4aa4fSLi Zhang 	void *entry;
324944432018SLi Zhang 	struct mlx5_aso_mtr *aso_mtr;
325002e76468SSuanming Mou 
3251afb4aa4fSLi Zhang 	if (!priv->mtr_en)
3252afb4aa4fSLi Zhang 		return 0;
3253e6100c7bSLi Zhang 	if (priv->sh->meter_aso_en) {
3254f890b030SShun Hao 		if (mlx5_flow_meter_flush_all_hierarchies(dev, error))
3255f890b030SShun Hao 			return -rte_errno;
325644432018SLi Zhang 		if (priv->mtr_idx_tbl) {
325744432018SLi Zhang 			MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
325844432018SLi Zhang 				mtr_idx = *(uint32_t *)entry;
325944432018SLi Zhang 				if (mtr_idx) {
326044432018SLi Zhang 					aso_mtr =
326144432018SLi Zhang 					mlx5_aso_meter_by_idx(priv, mtr_idx);
326244432018SLi Zhang 					fm = &aso_mtr->fm;
3263afb4aa4fSLi Zhang 					(void)mlx5_flow_meter_params_flush(dev,
3264afb4aa4fSLi Zhang 						fm, mtr_idx);
3265e6100c7bSLi Zhang 				}
3266e6100c7bSLi Zhang 			}
326744432018SLi Zhang 			mlx5_l3t_destroy(priv->mtr_idx_tbl);
326844432018SLi Zhang 			priv->mtr_idx_tbl = NULL;
326944432018SLi Zhang 		}
3270e6100c7bSLi Zhang 	} else {
3271f1f6ebc0SWilliam Tu 		RTE_TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
3272e6100c7bSLi Zhang 			fm = &legacy_fm->fm;
32735f0d54f3SLi Zhang 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
327402e76468SSuanming Mou 				return -rte_mtr_error_set(error, EINVAL,
327502e76468SSuanming Mou 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
327602e76468SSuanming Mou 				NULL, "MTR object meter profile invalid.");
3277e6100c7bSLi Zhang 		}
327802e76468SSuanming Mou 	}
327924865366SAlexander Kozyrev 	if (priv->mtr_bulk.aso) {
328048fbb0e9SAlexander Kozyrev 		for (i = 0; i < priv->mtr_config.nb_meters; i++) {
328124865366SAlexander Kozyrev 			aso_mtr = mlx5_aso_meter_by_idx(priv, i);
328224865366SAlexander Kozyrev 			fm = &aso_mtr->fm;
328324865366SAlexander Kozyrev 			if (fm->initialized)
328424865366SAlexander Kozyrev 				mlx5_flow_meter_hws_destroy(dev, i, error);
328524865366SAlexander Kozyrev 		}
328624865366SAlexander Kozyrev 	}
3287efcce4dcSShun Hao 	if (priv->policy_idx_tbl) {
3288efcce4dcSShun Hao 		MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
3289afb4aa4fSLi Zhang 			policy_idx = *(uint32_t *)entry;
3290afb4aa4fSLi Zhang 			sub_policy = mlx5_ipool_get
3291afb4aa4fSLi Zhang 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
3292afb4aa4fSLi Zhang 				policy_idx);
3293afb4aa4fSLi Zhang 			if (!sub_policy)
3294afb4aa4fSLi Zhang 				return -rte_mtr_error_set(error,
3295afb4aa4fSLi Zhang 						EINVAL,
3296afb4aa4fSLi Zhang 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
3297afb4aa4fSLi Zhang 						NULL, "MTR object "
3298afb4aa4fSLi Zhang 						"meter policy invalid.");
3299afb4aa4fSLi Zhang 			if (__mlx5_flow_meter_policy_delete(dev, i,
3300afb4aa4fSLi Zhang 						sub_policy->main_policy,
3301035f4c23SLi Zhang 						error, true))
3302afb4aa4fSLi Zhang 				return -rte_mtr_error_set(error,
3303afb4aa4fSLi Zhang 						EINVAL,
3304afb4aa4fSLi Zhang 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
3305afb4aa4fSLi Zhang 						NULL, "MTR object "
3306afb4aa4fSLi Zhang 						"meter policy invalid.");
3307afb4aa4fSLi Zhang 			mlx5_free(sub_policy->main_policy);
3308afb4aa4fSLi Zhang 		}
3309efcce4dcSShun Hao 		mlx5_l3t_destroy(priv->policy_idx_tbl);
3310efcce4dcSShun Hao 		priv->policy_idx_tbl = NULL;
3311afb4aa4fSLi Zhang 	}
33127576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
331324865366SAlexander Kozyrev 	if (priv->mtr_policy_arr) {
33147576c32eSGregory Etelson 		struct mlx5_flow_meter_policy *policy;
33157576c32eSGregory Etelson 
331624865366SAlexander Kozyrev 		for (i = 0; i < priv->mtr_config.nb_meter_policies; i++) {
331724865366SAlexander Kozyrev 			policy = mlx5_flow_meter_policy_find(dev, i,
331824865366SAlexander Kozyrev 							     &policy_idx);
33197576c32eSGregory Etelson 			if (policy->initialized) {
332024865366SAlexander Kozyrev 				mlx5_flow_meter_policy_hws_delete(dev, i,
332124865366SAlexander Kozyrev 								  error);
332224865366SAlexander Kozyrev 			}
332324865366SAlexander Kozyrev 		}
33247576c32eSGregory Etelson 	}
33257576c32eSGregory Etelson #endif
3326a295c69aSShun Hao 	if (priv->mtr_profile_tbl) {
3327a295c69aSShun Hao 		MLX5_L3T_FOREACH(priv->mtr_profile_tbl, i, entry) {
3328a295c69aSShun Hao 			fmp = entry;
3329a295c69aSShun Hao 			if (mlx5_flow_meter_profile_delete(dev, fmp->id,
3330a295c69aSShun Hao 							   error))
3331a295c69aSShun Hao 				return -rte_mtr_error_set(error, EINVAL,
3332a295c69aSShun Hao 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
3333a295c69aSShun Hao 						NULL, "Fail to destroy "
3334a295c69aSShun Hao 						"meter profile.");
3335a295c69aSShun Hao 		}
3336a295c69aSShun Hao 		mlx5_l3t_destroy(priv->mtr_profile_tbl);
3337a295c69aSShun Hao 		priv->mtr_profile_tbl = NULL;
333802e76468SSuanming Mou 	}
33397576c32eSGregory Etelson #if defined(HAVE_MLX5_HWS_SUPPORT)
334024865366SAlexander Kozyrev 	if (priv->mtr_profile_arr) {
334124865366SAlexander Kozyrev 		for (i = 0; i < priv->mtr_config.nb_meter_profiles; i++) {
334224865366SAlexander Kozyrev 			fmp = mlx5_flow_meter_profile_find(priv, i);
33437576c32eSGregory Etelson 			if (fmp->initialized) {
334424865366SAlexander Kozyrev 				mlx5_flow_meter_profile_hws_delete(dev, i,
334524865366SAlexander Kozyrev 								   error);
334624865366SAlexander Kozyrev 			}
334724865366SAlexander Kozyrev 		}
33487576c32eSGregory Etelson 	}
33497576c32eSGregory Etelson #endif
3350afb4aa4fSLi Zhang 	/* Delete default policy table. */
3351afb4aa4fSLi Zhang 	mlx5_flow_destroy_def_policy(dev);
335244432018SLi Zhang 	if (priv->sh->refcnt == 1)
3353afb4aa4fSLi Zhang 		mlx5_flow_destroy_mtr_drop_tbls(dev);
335424865366SAlexander Kozyrev #ifdef HAVE_MLX5_HWS_SUPPORT
335524865366SAlexander Kozyrev 	/* Destroy HWS configuration. */
335624865366SAlexander Kozyrev 	mlx5_flow_meter_uninit(dev);
335724865366SAlexander Kozyrev #endif
335802e76468SSuanming Mou 	return 0;
335902e76468SSuanming Mou }
3360