xref: /dpdk/drivers/net/nfp/nfp_mtr.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2022 Corigine, Inc.
3  * All rights reserved.
4  */
5 
6 #include "nfp_mtr.h"
7 
8 #include <rte_alarm.h>
9 #include <rte_malloc.h>
10 #include <rte_mtr_driver.h>
11 
12 #include "flower/nfp_flower_representor.h"
13 #include "nfp_logs.h"
14 
15 #define NFP_MAX_POLICY_CNT             NFP_MAX_MTR_CNT
16 #define NFP_MAX_PROFILE_CNT            NFP_MAX_MTR_CNT
17 
18 #define NFP_FL_QOS_PPS          RTE_BIT32(15)
19 #define NFP_FL_QOS_METER        RTE_BIT32(10)
20 #define NFP_FL_QOS_RFC2697      RTE_BIT32(0)
21 
22 /* Alarm timeout value in microseconds */
23 #define NFP_METER_STATS_INTERVAL 1000000  /* 1 second */
24 
25 /**
26  * Callback to get MTR capabilities.
27  *
28  * @param[in] dev
29  *   Pointer to the device (unused).
30  * @param[out] cap
31  *   Pointer to the meter object capabilities.
32  * @param[out] error
33  *   Pointer to the error (unused).
34  *
35  * @returns
36  *   0 on success, a negative value otherwise and rte_errno is set.
37  */
38 static int
39 nfp_mtr_cap_get(struct rte_eth_dev *dev __rte_unused,
40 		struct rte_mtr_capabilities *cap,
41 		struct rte_mtr_error *error)
42 {
43 	if (cap == NULL) {
44 		return -rte_mtr_error_set(error, EINVAL,
45 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
46 				NULL, "NULL pointer for capabilitie argument.");
47 	}
48 
49 	memset(cap, 0, sizeof(struct rte_mtr_capabilities));
50 
51 	cap->n_max                               = NFP_MAX_MTR_CNT;
52 	cap->n_shared_max                        = NFP_MAX_MTR_CNT;
53 	cap->identical                           = 1;
54 	cap->shared_identical                    = 1;
55 	cap->chaining_n_mtrs_per_flow_max        = 1;
56 	cap->meter_srtcm_rfc2697_n_max           = NFP_MAX_MTR_CNT;
57 	cap->meter_trtcm_rfc2698_n_max           = NFP_MAX_MTR_CNT;
58 	cap->meter_rate_max                      = UINT64_MAX;
59 	cap->meter_policy_n_max                  = NFP_MAX_POLICY_CNT;
60 	cap->srtcm_rfc2697_byte_mode_supported   = 1;
61 	cap->srtcm_rfc2697_packet_mode_supported = 1;
62 	cap->trtcm_rfc2698_byte_mode_supported   = 1;
63 	cap->trtcm_rfc2698_packet_mode_supported = 1;
64 	cap->stats_mask = RTE_MTR_STATS_N_PKTS_GREEN |
65 			RTE_MTR_STATS_N_PKTS_DROPPED |
66 			RTE_MTR_STATS_N_BYTES_GREEN |
67 			RTE_MTR_STATS_N_BYTES_DROPPED;
68 
69 	return 0;
70 }
71 
72 static int
73 nfp_mtr_profile_validate(uint32_t mtr_profile_id,
74 		struct rte_mtr_meter_profile *profile,
75 		struct rte_mtr_error *error)
76 {
77 	/* Profile must not be NULL. */
78 	if (profile == NULL) {
79 		return -rte_mtr_error_set(error, EINVAL,
80 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
81 				NULL, "Meter profile is null.");
82 	}
83 
84 	/* Meter profile ID must be valid. */
85 	if (mtr_profile_id >= NFP_MAX_PROFILE_CNT) {
86 		return -rte_mtr_error_set(error, EINVAL,
87 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
88 				NULL, "Meter profile id not valid.");
89 	}
90 
91 	switch (profile->alg) {
92 	case RTE_MTR_SRTCM_RFC2697:
93 	case RTE_MTR_TRTCM_RFC2698:
94 		return 0;
95 	case RTE_MTR_TRTCM_RFC4115:
96 		return -rte_mtr_error_set(error, ENOTSUP,
97 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
98 				NULL, "Unsupported metering algorithm.");
99 	default:
100 		return -rte_mtr_error_set(error, ENOTSUP,
101 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
102 				NULL, "Unknown metering algorithm.");
103 	}
104 }
105 
106 static void
107 nfp_mtr_profile_config_2698(uint32_t mtr_profile_id,
108 		struct rte_mtr_meter_profile *profile,
109 		struct nfp_profile_conf *conf)
110 {
111 	if (profile->packet_mode != 0)
112 		conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_PPS);
113 
114 	conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_METER);
115 	conf->head.profile_id = rte_cpu_to_be_32(mtr_profile_id);
116 
117 	conf->bkt_tkn_c = rte_cpu_to_be_32(profile->trtcm_rfc2698.cbs);
118 	conf->bkt_tkn_p = rte_cpu_to_be_32(profile->trtcm_rfc2698.pbs);
119 	conf->cbs = rte_cpu_to_be_32(profile->trtcm_rfc2698.cbs);
120 	conf->pbs = rte_cpu_to_be_32(profile->trtcm_rfc2698.pbs);
121 	conf->cir = rte_cpu_to_be_32(profile->trtcm_rfc2698.cir);
122 	conf->pir = rte_cpu_to_be_32(profile->trtcm_rfc2698.pir);
123 }
124 
125 static void
126 nfp_mtr_profile_config_2697(uint32_t mtr_profile_id,
127 		struct rte_mtr_meter_profile *profile,
128 		struct nfp_profile_conf *conf)
129 {
130 	if (profile->packet_mode != 0)
131 		conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_PPS);
132 
133 	conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_RFC2697);
134 	conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_METER);
135 	conf->head.profile_id = rte_cpu_to_be_32(mtr_profile_id);
136 
137 	conf->bkt_tkn_c = rte_cpu_to_be_32(profile->srtcm_rfc2697.cbs);
138 	conf->bkt_tkn_p = rte_cpu_to_be_32(profile->srtcm_rfc2697.ebs);
139 	conf->cbs = rte_cpu_to_be_32(profile->srtcm_rfc2697.cbs);
140 	conf->pbs = rte_cpu_to_be_32(profile->srtcm_rfc2697.ebs);
141 	conf->cir = rte_cpu_to_be_32(profile->srtcm_rfc2697.cir);
142 	conf->pir = rte_cpu_to_be_32(profile->srtcm_rfc2697.cir);
143 }
144 
145 static int
146 nfp_mtr_profile_conf_mod(uint32_t mtr_profile_id,
147 		struct rte_mtr_meter_profile *profile,
148 		struct nfp_profile_conf *conf)
149 {
150 	switch (profile->alg) {
151 	case RTE_MTR_SRTCM_RFC2697:
152 		nfp_mtr_profile_config_2697(mtr_profile_id, profile, conf);
153 		return 0;
154 	case RTE_MTR_TRTCM_RFC2698:
155 		nfp_mtr_profile_config_2698(mtr_profile_id, profile, conf);
156 		return 0;
157 	case RTE_MTR_TRTCM_RFC4115:
158 		return -ENOTSUP;
159 	default:
160 		return -EINVAL;
161 	}
162 }
163 
164 static int
165 nfp_mtr_profile_conf_insert(uint32_t mtr_profile_id,
166 		struct rte_mtr_meter_profile *profile,
167 		struct nfp_mtr_profile *mtr_profile)
168 {
169 	mtr_profile->profile_id = mtr_profile_id;
170 	mtr_profile->in_use = false;
171 
172 	return nfp_mtr_profile_conf_mod(mtr_profile_id, profile,
173 			&mtr_profile->conf);
174 }
175 
176 static struct nfp_mtr_profile *
177 nfp_mtr_profile_search(struct nfp_mtr_priv *priv, uint32_t mtr_profile_id)
178 {
179 	struct nfp_mtr_profile *mtr_profile;
180 
181 	LIST_FOREACH(mtr_profile, &priv->profiles, next)
182 		if (mtr_profile->profile_id == mtr_profile_id)
183 			break;
184 
185 	return mtr_profile;
186 }
187 
188 static int
189 nfp_mtr_profile_insert(struct nfp_app_fw_flower *app_fw_flower,
190 		struct rte_mtr_meter_profile *profile,
191 		uint32_t mtr_profile_id,
192 		struct rte_mtr_error *error)
193 {
194 	int ret;
195 	struct nfp_mtr_priv *priv;
196 	struct nfp_mtr_profile *mtr_profile;
197 
198 	priv = app_fw_flower->mtr_priv;
199 
200 	/* Meter profile memory allocation. */
201 	mtr_profile = rte_zmalloc(NULL, sizeof(struct nfp_mtr_profile), 0);
202 	if (mtr_profile == NULL) {
203 		return -rte_mtr_error_set(error, ENOMEM,
204 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
205 				NULL, "Meter profile alloc failed.");
206 	}
207 
208 	ret = nfp_mtr_profile_conf_insert(mtr_profile_id,
209 			profile, mtr_profile);
210 	if (ret != 0) {
211 		rte_mtr_error_set(error, EINVAL,
212 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
213 				NULL, "Insert profile config failed.");
214 		goto free_profile;
215 	}
216 
217 	ret = nfp_flower_cmsg_qos_add(app_fw_flower, &mtr_profile->conf);
218 	if (ret != 0) {
219 		rte_mtr_error_set(error, EINVAL,
220 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
221 				NULL, "Add meter to firmware failed.");
222 		goto free_profile;
223 	}
224 
225 	/* Insert profile into profile list */
226 	LIST_INSERT_HEAD(&priv->profiles, mtr_profile, next);
227 
228 	return 0;
229 
230 free_profile:
231 	rte_free(mtr_profile);
232 
233 	return ret;
234 }
235 
236 static int
237 nfp_mtr_profile_mod(struct nfp_app_fw_flower *app_fw_flower,
238 		struct rte_mtr_meter_profile *profile,
239 		struct nfp_mtr_profile *mtr_profile,
240 		struct rte_mtr_error *error)
241 {
242 	int ret;
243 	struct nfp_profile_conf old_conf;
244 
245 	/* Get the old profile config */
246 	rte_memcpy(&old_conf, &mtr_profile->conf, sizeof(old_conf));
247 
248 	memset(&mtr_profile->conf, 0, sizeof(struct nfp_profile_conf));
249 
250 	ret = nfp_mtr_profile_conf_mod(mtr_profile->profile_id,
251 			profile, &mtr_profile->conf);
252 	if (ret != 0) {
253 		rte_mtr_error_set(error, EINVAL,
254 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
255 				NULL, "Mod profile config failed.");
256 		goto rollback;
257 	}
258 
259 	ret = nfp_flower_cmsg_qos_add(app_fw_flower, &mtr_profile->conf);
260 	if (ret != 0) {
261 		rte_mtr_error_set(error, EINVAL,
262 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
263 				NULL, "Mod meter to firmware failed.");
264 		goto rollback;
265 	}
266 
267 	return 0;
268 
269 rollback:
270 	rte_memcpy(&mtr_profile->conf, &old_conf, sizeof(old_conf));
271 
272 	return ret;
273 }
274 
275 /**
276  * Callback to add MTR profile.
277  *
278  * @param[in] dev
279  *   Pointer to Ethernet device.
280  * @param[in] mtr_profile_id
281  *   Meter profile id.
282  * @param[in] profile
283  *   Pointer to meter profile detail.
284  * @param[out] error
285  *   Pointer to the error structure.
286  *
287  * @return
288  *   0 on success, a negative value otherwise and rte_errno is set.
289  */
290 static int
291 nfp_mtr_profile_add(struct rte_eth_dev *dev,
292 		uint32_t mtr_profile_id,
293 		struct rte_mtr_meter_profile *profile,
294 		struct rte_mtr_error *error)
295 {
296 	int ret;
297 	struct nfp_mtr_priv *priv;
298 	struct nfp_mtr_profile *mtr_profile;
299 	struct nfp_app_fw_flower *app_fw_flower;
300 	struct nfp_flower_representor *representor;
301 
302 	representor = dev->data->dev_private;
303 	app_fw_flower = representor->app_fw_flower;
304 	priv = app_fw_flower->mtr_priv;
305 
306 	/* Check input params */
307 	ret = nfp_mtr_profile_validate(mtr_profile_id, profile, error);
308 	if (ret != 0)
309 		return ret;
310 
311 	/* Check if mtr profile id exist */
312 	mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id);
313 	if (mtr_profile == NULL) {
314 		ret = nfp_mtr_profile_insert(app_fw_flower,
315 				profile, mtr_profile_id, error);
316 	} else {
317 		ret = nfp_mtr_profile_mod(app_fw_flower,
318 				profile, mtr_profile, error);
319 	}
320 
321 	return ret;
322 }
323 
324 /**
325  * Callback to delete MTR profile.
326  *
327  * @param[in] dev
328  *   Pointer to Ethernet device.
329  * @param[in] mtr_profile_id
330  *   Meter profile id.
331  * @param[out] error
332  *   Pointer to the error structure.
333  *
334  * @return
335  *   0 on success, a negative value otherwise and rte_errno is set.
336  */
337 static int
338 nfp_mtr_profile_delete(struct rte_eth_dev *dev,
339 		uint32_t mtr_profile_id,
340 		struct rte_mtr_error *error)
341 {
342 	int ret;
343 	struct nfp_mtr_priv *priv;
344 	struct nfp_mtr_profile *mtr_profile;
345 	struct nfp_app_fw_flower *app_fw_flower;
346 	struct nfp_flower_representor *representor;
347 
348 	representor = dev->data->dev_private;
349 	app_fw_flower = representor->app_fw_flower;
350 	priv = app_fw_flower->mtr_priv;
351 
352 	/* Check if mtr profile id exist */
353 	mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id);
354 	if (mtr_profile == NULL) {
355 		return -rte_mtr_error_set(error, EINVAL,
356 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
357 				NULL, "Request meter profile not exist.");
358 	}
359 
360 	if (mtr_profile->in_use) {
361 		return -rte_mtr_error_set(error, EINVAL,
362 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
363 				NULL, "Request meter profile is been used.");
364 	}
365 
366 	ret = nfp_flower_cmsg_qos_delete(app_fw_flower, &mtr_profile->conf);
367 	if (ret != 0) {
368 		return -rte_mtr_error_set(error, EINVAL,
369 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
370 				NULL, "Delete meter from firmware failed.");
371 	}
372 
373 	/* Remove profile from profile list */
374 	LIST_REMOVE(mtr_profile, next);
375 	rte_free(mtr_profile);
376 
377 	return 0;
378 }
379 
380 static struct nfp_mtr_policy *
381 nfp_mtr_policy_search(struct nfp_mtr_priv *priv, uint32_t mtr_policy_id)
382 {
383 	struct nfp_mtr_policy *mtr_policy;
384 
385 	LIST_FOREACH(mtr_policy, &priv->policies, next)
386 		if (mtr_policy->policy_id == mtr_policy_id)
387 			break;
388 
389 	return mtr_policy;
390 }
391 
392 static int
393 nfp_mtr_policy_validate(uint32_t mtr_policy_id,
394 		struct rte_mtr_meter_policy_params *policy,
395 		struct rte_mtr_error *error)
396 {
397 	const struct rte_flow_action *action;
398 
399 	/* Policy must not be NULL */
400 	if (policy == NULL) {
401 		return -rte_mtr_error_set(error, EINVAL,
402 				RTE_MTR_ERROR_TYPE_METER_POLICY,
403 				NULL, "Meter policy is null.");
404 	}
405 
406 	/* Meter policy ID must be valid. */
407 	if (mtr_policy_id >= NFP_MAX_POLICY_CNT) {
408 		return -rte_mtr_error_set(error, EINVAL,
409 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
410 				NULL, "Meter policy id not valid.");
411 	}
412 
413 	/* Check green action
414 	 * Actions equal NULL means end action
415 	 */
416 	action = policy->actions[RTE_COLOR_GREEN];
417 	if (action != NULL && action->type != RTE_FLOW_ACTION_TYPE_VOID) {
418 		return -rte_mtr_error_set(error, EINVAL,
419 				RTE_MTR_ERROR_TYPE_METER_POLICY,
420 				NULL, "Green action must be void or end.");
421 	}
422 
423 	/* Check yellow action
424 	 * Actions equal NULL means end action
425 	 */
426 	action = policy->actions[RTE_COLOR_YELLOW];
427 	if (action != NULL && action->type != RTE_FLOW_ACTION_TYPE_VOID) {
428 		return -rte_mtr_error_set(error, EINVAL,
429 				RTE_MTR_ERROR_TYPE_METER_POLICY,
430 				NULL, "Yellow action must be void or end.");
431 	}
432 
433 	/* Check red action */
434 	action = policy->actions[RTE_COLOR_RED];
435 	if (action == NULL || action->type != RTE_FLOW_ACTION_TYPE_DROP) {
436 		return -rte_mtr_error_set(error, EINVAL,
437 				RTE_MTR_ERROR_TYPE_METER_POLICY,
438 				NULL, "Red action must be drop.");
439 	}
440 
441 	return 0;
442 }
443 
444 /**
445  * Callback to add MTR policy.
446  *
447  * @param[in] dev
448  *   Pointer to Ethernet device.
449  * @param[in] mtr_policy_id
450  *   Meter policy id.
451  * @param[in] policy
452  *   Pointer to meter policy detail.
453  * @param[out] error
454  *   Pointer to the error structure.
455  *
456  * @return
457  *   0 on success, a negative value otherwise and rte_errno is set.
458  */
459 static int
460 nfp_mtr_policy_add(struct rte_eth_dev *dev,
461 		uint32_t mtr_policy_id,
462 		struct rte_mtr_meter_policy_params *policy,
463 		struct rte_mtr_error *error)
464 {
465 	int ret;
466 	struct nfp_mtr_priv *priv;
467 	struct nfp_mtr_policy *mtr_policy;
468 	struct nfp_flower_representor *representor;
469 
470 	representor = dev->data->dev_private;
471 	priv = representor->app_fw_flower->mtr_priv;
472 
473 	/* Check if mtr policy id exist */
474 	mtr_policy = nfp_mtr_policy_search(priv, mtr_policy_id);
475 	if (mtr_policy != NULL) {
476 		return -rte_mtr_error_set(error, EEXIST,
477 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
478 				NULL, "Meter policy already exist.");
479 	}
480 
481 	/* Check input params */
482 	ret = nfp_mtr_policy_validate(mtr_policy_id, policy, error);
483 	if (ret != 0)
484 		return ret;
485 
486 	/* Meter policy memory alloc */
487 	mtr_policy = rte_zmalloc(NULL, sizeof(struct nfp_mtr_policy), 0);
488 	if (mtr_policy == NULL) {
489 		return -rte_mtr_error_set(error, ENOMEM,
490 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
491 				NULL, "Meter policy alloc failed.");
492 	}
493 
494 	mtr_policy->policy_id = mtr_policy_id;
495 	rte_memcpy(&mtr_policy->policy, policy,
496 			sizeof(struct rte_mtr_meter_policy_params));
497 
498 	/* Insert policy into policy list */
499 	LIST_INSERT_HEAD(&priv->policies, mtr_policy, next);
500 
501 	return 0;
502 }
503 
504 /**
505  * Callback to delete MTR policy.
506  *
507  * @param[in] dev
508  *   Pointer to Ethernet device.
509  * @param[in] mtr_policy_id
510  *   Meter policy id.
511  * @param[out] error
512  *   Pointer to the error structure.
513  *
514  * @return
515  *   0 on success, a negative value otherwise and rte_errno is set.
516  */
517 static int
518 nfp_mtr_policy_delete(struct rte_eth_dev *dev,
519 		uint32_t mtr_policy_id,
520 		struct rte_mtr_error *error)
521 {
522 	struct nfp_mtr_priv *priv;
523 	struct nfp_mtr_policy *mtr_policy;
524 	struct nfp_flower_representor *representor;
525 
526 	representor = dev->data->dev_private;
527 	priv = representor->app_fw_flower->mtr_priv;
528 
529 	/* Check if mtr policy id exist */
530 	mtr_policy = nfp_mtr_policy_search(priv, mtr_policy_id);
531 	if (mtr_policy == NULL) {
532 		return -rte_mtr_error_set(error, EINVAL,
533 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
534 				NULL, "Request meter policy not exist.");
535 	}
536 
537 	if (mtr_policy->ref_cnt > 0) {
538 		return -rte_mtr_error_set(error, EBUSY,
539 				RTE_MTR_ERROR_TYPE_METER_POLICY,
540 				NULL, "Request mtr policy is been used.");
541 	}
542 
543 	/* Remove profile from profile list */
544 	LIST_REMOVE(mtr_policy, next);
545 	rte_free(mtr_policy);
546 
547 	return 0;
548 }
549 
550 struct nfp_mtr *
551 nfp_mtr_find_by_mtr_id(struct nfp_mtr_priv *priv, uint32_t mtr_id)
552 {
553 	struct nfp_mtr *mtr;
554 
555 	LIST_FOREACH(mtr, &priv->mtrs, next)
556 		if (mtr->mtr_id == mtr_id)
557 			break;
558 
559 	return mtr;
560 }
561 
562 struct nfp_mtr *
563 nfp_mtr_find_by_profile_id(struct nfp_mtr_priv *priv, uint32_t profile_id)
564 {
565 	struct nfp_mtr *mtr;
566 
567 	LIST_FOREACH(mtr, &priv->mtrs, next)
568 		if (mtr->mtr_profile->profile_id == profile_id)
569 			break;
570 
571 	return mtr;
572 }
573 
574 static int
575 nfp_mtr_stats_mask_validate(uint64_t stats_mask, struct rte_mtr_error *error)
576 {
577 	if ((stats_mask & RTE_MTR_STATS_N_PKTS_YELLOW) != 0) {
578 		return -rte_mtr_error_set(error, EINVAL,
579 				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
580 				NULL, "RTE_MTR_STATS_N_PKTS_YELLOW not support.");
581 	}
582 
583 	if ((stats_mask & RTE_MTR_STATS_N_PKTS_RED) != 0) {
584 		return -rte_mtr_error_set(error, EINVAL,
585 				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
586 				NULL, "RTE_MTR_STATS_N_PKTS_RED not support.");
587 	}
588 
589 	if ((stats_mask & RTE_MTR_STATS_N_BYTES_YELLOW) != 0) {
590 		return -rte_mtr_error_set(error, EINVAL,
591 				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
592 				NULL, "RTE_MTR_STATS_N_BYTES_YELLOW not support.");
593 	}
594 
595 	if ((stats_mask & RTE_MTR_STATS_N_BYTES_RED) != 0) {
596 		return -rte_mtr_error_set(error, EINVAL,
597 				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
598 				NULL, "RTE_MTR_STATS_N_BYTES_RED not support.");
599 	}
600 
601 	return 0;
602 }
603 
604 static int
605 nfp_mtr_validate(uint32_t meter_id,
606 		struct rte_mtr_params *params,
607 		struct rte_mtr_error *error)
608 {
609 	/* Params must not be NULL */
610 	if (params == NULL) {
611 		return -rte_mtr_error_set(error, EINVAL,
612 				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
613 				NULL, "Meter params is null.");
614 	}
615 
616 	/* Meter policy ID must be valid. */
617 	if (meter_id >= NFP_MAX_MTR_CNT) {
618 		return -rte_mtr_error_set(error, EINVAL,
619 				RTE_MTR_ERROR_TYPE_MTR_ID,
620 				NULL, "Meter id not valid.");
621 	}
622 
623 	if (params->use_prev_mtr_color != 0) {
624 		return -rte_mtr_error_set(error, EINVAL,
625 				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
626 				NULL, "Feature use_prev_mtr_color not support.");
627 	}
628 
629 	return nfp_mtr_stats_mask_validate(params->stats_mask, error);
630 }
631 
632 static void
633 nfp_mtr_config(uint32_t mtr_id,
634 		int shared,
635 		struct rte_mtr_params *params,
636 		struct nfp_mtr_profile *mtr_profile,
637 		struct nfp_mtr_policy *mtr_policy,
638 		struct nfp_mtr *mtr)
639 {
640 	mtr->mtr_id = mtr_id;
641 
642 	if (shared != 0)
643 		mtr->shared = true;
644 
645 	if (params->meter_enable != 0)
646 		mtr->enable = true;
647 
648 	mtr->mtr_profile = mtr_profile;
649 	mtr->mtr_policy = mtr_policy;
650 	mtr->stats_mask = params->stats_mask;
651 }
652 
653 /**
654  * Create meter rules.
655  *
656  * @param[in] dev
657  *   Pointer to Ethernet device.
658  * @param[in] mtr_id
659  *   Meter id.
660  * @param[in] params
661  *   Pointer to rte meter parameters.
662  * @param[in] shared
663  *   Meter shared with other flow or not.
664  * @param[out] error
665  *   Pointer to rte meter error structure.
666  *
667  * @return
668  *   0 on success, a negative value otherwise and rte_errno is set.
669  */
670 static int
671 nfp_mtr_create(struct rte_eth_dev *dev,
672 		uint32_t mtr_id,
673 		struct rte_mtr_params *params,
674 		int shared,
675 		struct rte_mtr_error *error)
676 {
677 	int ret;
678 	struct nfp_mtr *mtr;
679 	struct nfp_mtr_priv *priv;
680 	struct nfp_mtr_policy *mtr_policy;
681 	struct nfp_mtr_profile *mtr_profile;
682 	struct nfp_flower_representor *representor;
683 
684 	representor = dev->data->dev_private;
685 	priv = representor->app_fw_flower->mtr_priv;
686 
687 	/* Check if meter id exist */
688 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
689 	if (mtr != NULL) {
690 		return -rte_mtr_error_set(error, EEXIST,
691 				RTE_MTR_ERROR_TYPE_MTR_ID,
692 				NULL, "Meter already exist.");
693 	}
694 
695 	/* Check input meter params */
696 	ret = nfp_mtr_validate(mtr_id, params, error);
697 	if (ret != 0)
698 		return ret;
699 
700 	mtr_profile = nfp_mtr_profile_search(priv, params->meter_profile_id);
701 	if (mtr_profile == NULL) {
702 		return -rte_mtr_error_set(error, EINVAL,
703 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
704 				NULL, "Request meter profile not exist.");
705 	}
706 
707 	if (mtr_profile->in_use) {
708 		return -rte_mtr_error_set(error, EINVAL,
709 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
710 				NULL, "Request meter profile is been used.");
711 	}
712 
713 	mtr_policy = nfp_mtr_policy_search(priv, params->meter_policy_id);
714 	if (mtr_policy == NULL) {
715 		return -rte_mtr_error_set(error, EINVAL,
716 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
717 				NULL, "Request meter policy not exist.");
718 	}
719 
720 	/* Meter param memory alloc */
721 	mtr = rte_zmalloc(NULL, sizeof(struct nfp_mtr), 0);
722 	if (mtr == NULL) {
723 		return -rte_mtr_error_set(error, ENOMEM,
724 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
725 				NULL, "Meter param alloc failed.");
726 	}
727 
728 	nfp_mtr_config(mtr_id, shared, params, mtr_profile, mtr_policy, mtr);
729 
730 	/* Update profile/policy status */
731 	mtr->mtr_policy->ref_cnt++;
732 	mtr->mtr_profile->in_use = true;
733 
734 	/* Insert mtr into mtr list */
735 	LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
736 
737 	return 0;
738 }
739 
740 /**
741  * Destroy meter rules.
742  *
743  * @param[in] dev
744  *   Pointer to Ethernet device.
745  * @param[in] mtr_id
746  *   Meter id.
747  * @param[out] error
748  *   Pointer to rte meter error structure.
749  *
750  * @return
751  *   0 on success, a negative value otherwise and rte_errno is set.
752  */
753 static int
754 nfp_mtr_destroy(struct rte_eth_dev *dev,
755 		uint32_t mtr_id,
756 		struct rte_mtr_error *error)
757 {
758 	struct nfp_mtr *mtr;
759 	struct nfp_mtr_priv *priv;
760 	struct nfp_flower_representor *representor;
761 
762 	representor = dev->data->dev_private;
763 	priv = representor->app_fw_flower->mtr_priv;
764 
765 	/* Check if meter id exist */
766 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
767 	if (mtr == NULL) {
768 		return -rte_mtr_error_set(error, EINVAL,
769 				RTE_MTR_ERROR_TYPE_MTR_ID,
770 				NULL, "Request meter not exist.");
771 	}
772 
773 	if (mtr->ref_cnt > 0) {
774 		return -rte_mtr_error_set(error, EINVAL,
775 				RTE_MTR_ERROR_TYPE_MTR_ID,
776 				NULL, "Meter object is being used.");
777 	}
778 
779 	/* Update profile/policy status */
780 	mtr->mtr_policy->ref_cnt--;
781 	mtr->mtr_profile->in_use = false;
782 
783 	/* Remove mtr from mtr list */
784 	LIST_REMOVE(mtr, next);
785 	rte_free(mtr);
786 
787 	return 0;
788 }
789 
790 /**
791  * Enable meter object.
792  *
793  * @param[in] dev
794  *   Pointer to the device.
795  * @param[in] mtr_id
796  *   Id of the meter.
797  * @param[out] error
798  *   Pointer to the error.
799  *
800  * @returns
801  *   0 in success, negative value otherwise and rte_errno is set..
802  */
803 static int
804 nfp_mtr_enable(struct rte_eth_dev *dev,
805 		uint32_t mtr_id,
806 		struct rte_mtr_error *error)
807 {
808 	struct nfp_mtr *mtr;
809 	struct nfp_mtr_priv *priv;
810 	struct nfp_flower_representor *representor;
811 
812 	representor = dev->data->dev_private;
813 	priv = representor->app_fw_flower->mtr_priv;
814 
815 	/* Check if meter id exist */
816 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
817 	if (mtr == NULL) {
818 		return -rte_mtr_error_set(error, EINVAL,
819 				RTE_MTR_ERROR_TYPE_MTR_ID,
820 				NULL, "Request meter not exist.");
821 	}
822 
823 	mtr->enable = true;
824 
825 	return 0;
826 }
827 
828 /**
829  * Disable meter object.
830  *
831  * @param[in] dev
832  *   Pointer to the device.
833  * @param[in] mtr_id
834  *   Id of the meter.
835  * @param[out] error
836  *   Pointer to the error.
837  *
838  * @returns
839  *   0 on success, negative value otherwise and rte_errno is set..
840  */
841 static int
842 nfp_mtr_disable(struct rte_eth_dev *dev,
843 		uint32_t mtr_id,
844 		struct rte_mtr_error *error)
845 {
846 	struct nfp_mtr *mtr;
847 	struct nfp_mtr_priv *priv;
848 	struct nfp_flower_representor *representor;
849 
850 	representor = dev->data->dev_private;
851 	priv = representor->app_fw_flower->mtr_priv;
852 
853 	/* Check if meter id exist */
854 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
855 	if (mtr == NULL) {
856 		return -rte_mtr_error_set(error, EINVAL,
857 				RTE_MTR_ERROR_TYPE_MTR_ID,
858 				NULL, "Request meter not exist.");
859 	}
860 
861 	if (mtr->ref_cnt > 0) {
862 		return -rte_mtr_error_set(error, EINVAL,
863 				RTE_MTR_ERROR_TYPE_MTR_ID,
864 				NULL, "Can not disable a used meter.");
865 	}
866 
867 	mtr->enable = false;
868 
869 	return 0;
870 }
871 
872 /**
873  * Callback to update meter profile.
874  *
875  * @param[in] dev
876  *   Pointer to Ethernet device.
877  * @param[in] mtr_id
878  *   Meter id.
879  * @param[in] mtr_profile_id
880  *   To be updated meter profile id.
881  * @param[out] error
882  *   Pointer to rte meter error structure.
883  *
884  * @return
885  *   0 on success, a negative value otherwise and rte_errno is set.
886  */
887 static int
888 nfp_mtr_profile_update(struct rte_eth_dev *dev,
889 		uint32_t mtr_id,
890 		uint32_t mtr_profile_id,
891 		struct rte_mtr_error *error)
892 {
893 	struct nfp_mtr *mtr;
894 	struct nfp_mtr_priv *priv;
895 	struct nfp_mtr_profile *mtr_profile;
896 	struct nfp_flower_representor *representor;
897 
898 	representor = dev->data->dev_private;
899 	priv = representor->app_fw_flower->mtr_priv;
900 
901 	/* Check if meter id exist */
902 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
903 	if (mtr == NULL) {
904 		return -rte_mtr_error_set(error, EINVAL,
905 				RTE_MTR_ERROR_TYPE_MTR_ID,
906 				NULL, "Request meter not exist.");
907 	}
908 
909 	if (mtr->ref_cnt > 0) {
910 		return -rte_mtr_error_set(error, EINVAL,
911 				RTE_MTR_ERROR_TYPE_MTR_ID,
912 				NULL, "Request meter is been used.");
913 	}
914 
915 	if (mtr->mtr_profile->profile_id == mtr_profile_id)
916 		return 0;
917 
918 	mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id);
919 	if (mtr_profile == NULL) {
920 		return -rte_mtr_error_set(error, EINVAL,
921 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
922 				NULL, "Request meter profile not exist.");
923 	}
924 
925 	if (mtr_profile->in_use) {
926 		return -rte_mtr_error_set(error, EINVAL,
927 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
928 				NULL, "Request meter profile is been used.");
929 	}
930 
931 	mtr_profile->in_use = true;
932 	mtr->mtr_profile->in_use = false;
933 	mtr->mtr_profile = mtr_profile;
934 
935 	return 0;
936 }
937 
938 /**
939  * Callback to update meter stats mask.
940  *
941  * @param[in] dev
942  *   Pointer to Ethernet device.
943  * @param[in] mtr_id
944  *   Meter id.
945  * @param[in] stats_mask
946  *   To be updated stats_mask.
947  * @param[out] error
948  *   Pointer to rte meter error structure.
949  *
950  * @return
951  *   0 on success, a negative value otherwise and rte_errno is set.
952  */
953 static int
954 nfp_mtr_stats_update(struct rte_eth_dev *dev,
955 		uint32_t mtr_id,
956 		uint64_t stats_mask,
957 		struct rte_mtr_error *error)
958 {
959 	int ret;
960 	struct nfp_mtr *mtr;
961 	struct nfp_mtr_priv *priv;
962 	struct nfp_flower_representor *representor;
963 
964 	representor = dev->data->dev_private;
965 	priv = representor->app_fw_flower->mtr_priv;
966 
967 	/* Check if meter id exist */
968 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
969 	if (mtr == NULL) {
970 		return -rte_mtr_error_set(error, EEXIST,
971 				RTE_MTR_ERROR_TYPE_MTR_ID,
972 				NULL, "Request meter id not exist.");
973 	}
974 
975 	ret = nfp_mtr_stats_mask_validate(stats_mask, error);
976 	if (ret != 0)
977 		return ret;
978 
979 	mtr->stats_mask = stats_mask;
980 
981 	return 0;
982 }
983 
984 /**
985  * Callback to read meter statistics.
986  *
987  * @param[in] dev
988  *   Pointer to Ethernet device.
989  * @param[in] mtr_id
990  *   Meter id.
991  * @param[out] stats
992  *   Pointer to store the statistics.
993  * @param[out] stats_mask
994  *   Pointer to store the stats_mask.
995  * @param[in] clear
996  *   Statistic to be cleared after read or not.
997  * @param[out] error
998  *   Pointer to rte meter error structure.
999  *
1000  * @return
1001  *   0 on success, a negative value otherwise and rte_errno is set.
1002  */
1003 static int
1004 nfp_mtr_stats_read(struct rte_eth_dev *dev,
1005 		uint32_t mtr_id,
1006 		struct rte_mtr_stats *stats,
1007 		uint64_t *stats_mask,
1008 		int clear,
1009 		struct rte_mtr_error *error)
1010 {
1011 	struct nfp_mtr *mtr;
1012 	struct nfp_mtr_priv *priv;
1013 	struct nfp_mtr_stats curr;
1014 	struct nfp_mtr_stats *prev;
1015 	struct nfp_flower_representor *representor;
1016 
1017 	representor = dev->data->dev_private;
1018 	priv = representor->app_fw_flower->mtr_priv;
1019 
1020 	/* Check if meter id exist */
1021 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
1022 	if (mtr == NULL) {
1023 		return -rte_mtr_error_set(error, EINVAL,
1024 				RTE_MTR_ERROR_TYPE_MTR_ID,
1025 				NULL, "Request meter not exist.");
1026 	}
1027 
1028 	*stats_mask = mtr->stats_mask;
1029 
1030 	rte_spinlock_lock(&priv->mtr_stats_lock);
1031 	rte_memcpy(&curr, &mtr->mtr_stats.curr, sizeof(curr));
1032 	rte_spinlock_unlock(&priv->mtr_stats_lock);
1033 
1034 	prev = &mtr->mtr_stats.prev;
1035 
1036 	stats->n_pkts[RTE_COLOR_GREEN] = curr.pass_pkts - prev->pass_pkts;
1037 	stats->n_bytes[RTE_COLOR_GREEN] = curr.pass_bytes - prev->pass_bytes;
1038 	stats->n_pkts_dropped = curr.drop_pkts - prev->drop_pkts;
1039 	stats->n_bytes_dropped = curr.drop_bytes - prev->drop_bytes;
1040 
1041 	if (clear != 0) {
1042 		prev->pass_pkts = curr.pass_pkts;
1043 		prev->pass_bytes = curr.pass_bytes;
1044 		prev->drop_pkts = curr.drop_pkts;
1045 		prev->drop_bytes = curr.drop_bytes;
1046 	}
1047 
1048 	return 0;
1049 }
1050 
1051 static const struct rte_mtr_ops nfp_mtr_ops = {
1052 	.capabilities_get      = nfp_mtr_cap_get,
1053 	.meter_profile_add     = nfp_mtr_profile_add,
1054 	.meter_profile_delete  = nfp_mtr_profile_delete,
1055 	.meter_policy_add      = nfp_mtr_policy_add,
1056 	.meter_policy_delete   = nfp_mtr_policy_delete,
1057 	.create                = nfp_mtr_create,
1058 	.destroy               = nfp_mtr_destroy,
1059 	.meter_enable          = nfp_mtr_enable,
1060 	.meter_disable         = nfp_mtr_disable,
1061 	.meter_profile_update  = nfp_mtr_profile_update,
1062 	.stats_update          = nfp_mtr_stats_update,
1063 	.stats_read            = nfp_mtr_stats_read,
1064 };
1065 
1066 int
1067 nfp_net_mtr_ops_get(struct rte_eth_dev *dev, void *arg)
1068 {
1069 	if (!rte_eth_dev_is_repr(dev)) {
1070 		PMD_DRV_LOG(ERR, "Port is not a representor.");
1071 		return -EINVAL;
1072 	}
1073 
1074 	*(const struct rte_mtr_ops **)arg = &nfp_mtr_ops;
1075 
1076 	return 0;
1077 }
1078 
1079 static void
1080 nfp_mtr_stats_request(void *arg)
1081 {
1082 	struct nfp_mtr *mtr;
1083 	struct nfp_app_fw_flower *app_fw_flower = arg;
1084 
1085 	LIST_FOREACH(mtr, &app_fw_flower->mtr_priv->mtrs, next)
1086 		nfp_flower_cmsg_qos_stats(app_fw_flower, &mtr->mtr_profile->conf.head);
1087 
1088 	rte_eal_alarm_set(NFP_METER_STATS_INTERVAL, nfp_mtr_stats_request, arg);
1089 }
1090 
1091 int
1092 nfp_mtr_priv_init(struct nfp_pf_dev *pf_dev)
1093 {
1094 	int ret;
1095 	struct nfp_mtr_priv *priv;
1096 	struct nfp_app_fw_flower *app_fw_flower;
1097 
1098 	priv = rte_zmalloc("nfp_app_mtr_priv", sizeof(struct nfp_mtr_priv), 0);
1099 	if (priv == NULL) {
1100 		PMD_INIT_LOG(ERR, "NFP app mtr priv creation failed.");
1101 		return -ENOMEM;
1102 	}
1103 
1104 	app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv);
1105 	app_fw_flower->mtr_priv = priv;
1106 
1107 	ret = rte_eal_alarm_set(NFP_METER_STATS_INTERVAL, nfp_mtr_stats_request,
1108 			(void *)app_fw_flower);
1109 	if (ret < 0) {
1110 		PMD_INIT_LOG(ERR, "NFP mtr timer init failed.");
1111 		rte_free(priv);
1112 		return ret;
1113 	}
1114 
1115 	LIST_INIT(&priv->mtrs);
1116 	LIST_INIT(&priv->profiles);
1117 	LIST_INIT(&priv->policies);
1118 
1119 	rte_spinlock_init(&priv->mtr_stats_lock);
1120 
1121 	return 0;
1122 }
1123 
1124 void
1125 nfp_mtr_priv_uninit(struct nfp_pf_dev *pf_dev)
1126 {
1127 	struct nfp_mtr *mtr;
1128 	struct nfp_mtr_priv *priv;
1129 	struct nfp_mtr_policy *mtr_policy;
1130 	struct nfp_mtr_profile *mtr_profile;
1131 	struct nfp_app_fw_flower *app_fw_flower;
1132 
1133 	app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv);
1134 	priv = app_fw_flower->mtr_priv;
1135 
1136 	rte_eal_alarm_cancel(nfp_mtr_stats_request, (void *)app_fw_flower);
1137 
1138 	LIST_FOREACH(mtr, &priv->mtrs, next) {
1139 		LIST_REMOVE(mtr, next);
1140 		rte_free(mtr);
1141 	}
1142 
1143 	LIST_FOREACH(mtr_profile, &priv->profiles, next) {
1144 		LIST_REMOVE(mtr_profile, next);
1145 		rte_free(mtr_profile);
1146 	}
1147 
1148 	LIST_FOREACH(mtr_policy, &priv->policies, next) {
1149 		LIST_REMOVE(mtr_policy, next);
1150 		rte_free(mtr_policy);
1151 	}
1152 
1153 	rte_free(priv);
1154 }
1155 
1156 int
1157 nfp_mtr_update_ref_cnt(struct nfp_mtr_priv *priv,
1158 		uint32_t mtr_id,
1159 		bool add)
1160 {
1161 	struct nfp_mtr *mtr;
1162 
1163 	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
1164 	if (mtr == NULL)
1165 		return -EINVAL;
1166 
1167 	mtr->ref_cnt += add ? 1 : -1;
1168 
1169 	return 0;
1170 }
1171