1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2021 Marvell.
5 #include "cnxk_ethdev.h"
6 #include <rte_mtr_driver.h>
8 #define NIX_MTR_COUNT_MAX 73 /* 64(leaf) + 8(mid) + 1(top) */
9 #define NIX_MTR_COUNT_PER_FLOW 3 /* 1(leaf) + 1(mid) + 1(top) */
11 static const enum roc_nix_bpf_level_flag lvl_map[] = {ROC_NIX_BPF_LEVEL_F_LEAF,
12 ROC_NIX_BPF_LEVEL_F_MID,
13 ROC_NIX_BPF_LEVEL_F_TOP};
15 static struct rte_mtr_capabilities mtr_capa = {
16 .n_max = NIX_MTR_COUNT_MAX,
17 .n_shared_max = NIX_MTR_COUNT_PER_FLOW,
19 .shared_identical = true,
20 /* .shared_n_flows_per_mtr_max = ,*/
21 .chaining_n_mtrs_per_flow_max = NIX_MTR_COUNT_PER_FLOW,
22 .chaining_use_prev_mtr_color_supported = true,
23 .chaining_use_prev_mtr_color_enforced = true,
24 .meter_srtcm_rfc2697_n_max = NIX_MTR_COUNT_MAX,
25 .meter_trtcm_rfc2698_n_max = NIX_MTR_COUNT_MAX,
26 .meter_trtcm_rfc4115_n_max = NIX_MTR_COUNT_MAX,
27 .meter_rate_max = NIX_BPF_RATE_MAX / 8, /* Bytes per second */
28 .meter_policy_n_max = NIX_MTR_COUNT_MAX,
29 .color_aware_srtcm_rfc2697_supported = true,
30 .color_aware_trtcm_rfc2698_supported = true,
31 .color_aware_trtcm_rfc4115_supported = true,
32 .srtcm_rfc2697_byte_mode_supported = true,
33 .srtcm_rfc2697_packet_mode_supported = true,
34 .trtcm_rfc2698_byte_mode_supported = true,
35 .trtcm_rfc2698_packet_mode_supported = true,
36 .trtcm_rfc4115_byte_mode_supported = true,
37 .trtcm_rfc4115_packet_mode_supported = true,
38 .stats_mask = RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_PKTS_YELLOW |
39 RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_PKTS_DROPPED |
40 RTE_MTR_STATS_N_BYTES_GREEN |
41 RTE_MTR_STATS_N_BYTES_YELLOW | RTE_MTR_STATS_N_BYTES_RED |
42 RTE_MTR_STATS_N_BYTES_DROPPED};
44 static struct cnxk_meter_node *
45 nix_mtr_find(struct cnxk_eth_dev *dev, uint32_t meter_id)
47 struct cnxk_mtr *fms = &dev->mtr;
48 struct cnxk_meter_node *fm;
50 TAILQ_FOREACH(fm, fms, next)
51 if (meter_id == fm->id)
56 static struct cnxk_mtr_profile_node *
57 nix_mtr_profile_find(struct cnxk_eth_dev *dev, uint32_t profile_id)
59 struct cnxk_mtr_profiles *fmps = &dev->mtr_profiles;
60 struct cnxk_mtr_profile_node *fmp;
62 TAILQ_FOREACH(fmp, fmps, next)
63 if (profile_id == fmp->id)
69 static struct cnxk_mtr_policy_node *
70 nix_mtr_policy_find(struct cnxk_eth_dev *dev, uint32_t meter_policy_id)
72 struct cnxk_mtr_policy *fmps = &dev->mtr_policy;
73 struct cnxk_mtr_policy_node *fmp;
75 TAILQ_FOREACH(fmp, fmps, next)
76 if (meter_policy_id == fmp->id)
82 nix_mtr_profile_validate(struct cnxk_eth_dev *dev, uint32_t profile_id,
83 struct rte_mtr_meter_profile *profile,
84 struct rte_mtr_error *error)
91 return -rte_mtr_error_set(error, EINVAL,
92 RTE_MTR_ERROR_TYPE_METER_PROFILE,
93 NULL, "Meter profile is null.");
95 if (profile_id == UINT32_MAX)
96 return -rte_mtr_error_set(error, EINVAL,
97 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
98 NULL, "Meter profile id not valid.");
100 switch (profile->alg) {
101 case RTE_MTR_SRTCM_RFC2697:
102 if (profile->srtcm_rfc2697.cir > mtr_capa.meter_rate_max)
103 rc = -rte_mtr_error_set(error, EINVAL,
104 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
105 "CIR exceeds max meter rate");
107 if (profile->srtcm_rfc2697.cbs > NIX_BPF_BURST_MAX)
108 rc = -rte_mtr_error_set(error, EINVAL,
109 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
110 "CBS exceeds max meter burst size");
112 if (profile->srtcm_rfc2697.ebs > NIX_BPF_BURST_MAX)
113 rc = -rte_mtr_error_set(error, EINVAL,
114 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
115 "EBS exceeds max meter burst size");
118 case RTE_MTR_TRTCM_RFC2698:
119 if (profile->trtcm_rfc2698.cir > mtr_capa.meter_rate_max)
120 rc = -rte_mtr_error_set(error, EINVAL,
121 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
122 "CIR exceeds max meter rate");
124 if (profile->trtcm_rfc2698.pir > mtr_capa.meter_rate_max)
125 rc = -rte_mtr_error_set(error, EINVAL,
126 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
127 "PIR exceeds max meter rate");
129 if (profile->trtcm_rfc2698.cbs > NIX_BPF_BURST_MAX)
130 rc = -rte_mtr_error_set(error, EINVAL,
131 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
132 "CBS exceeds max meter burst size");
134 if (profile->trtcm_rfc2698.pbs > NIX_BPF_BURST_MAX)
135 rc = -rte_mtr_error_set(error, EINVAL,
136 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
137 "PBS exceeds max meter burst size");
140 case RTE_MTR_TRTCM_RFC4115:
141 if ((profile->trtcm_rfc4115.cir + profile->trtcm_rfc4115.eir) >
142 mtr_capa.meter_rate_max)
143 rc = -rte_mtr_error_set(error, EINVAL,
144 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
145 "PIR + EIR exceeds max rate");
147 if (profile->trtcm_rfc4115.cbs > NIX_BPF_BURST_MAX)
148 rc = -rte_mtr_error_set(error, EINVAL,
149 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
150 "CBS exceeds max meter burst size");
152 if (profile->trtcm_rfc4115.ebs > NIX_BPF_BURST_MAX)
153 rc = -rte_mtr_error_set(error, EINVAL,
154 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
155 "PBS exceeds max meter burst size");
159 rc = -rte_mtr_error_set(error, EINVAL,
160 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
169 cnxk_nix_mtr_capabilities_get(struct rte_eth_dev *dev,
170 struct rte_mtr_capabilities *capa,
171 struct rte_mtr_error *error)
176 return -rte_mtr_error_set(error, EINVAL,
177 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
178 "NULL input parameter");
184 cnxk_nix_mtr_profile_add(struct rte_eth_dev *eth_dev, uint32_t profile_id,
185 struct rte_mtr_meter_profile *profile,
186 struct rte_mtr_error *error)
188 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
189 struct cnxk_mtr_profiles *fmps = &dev->mtr_profiles;
190 struct cnxk_mtr_profile_node *fmp;
193 /* Check input params. */
194 ret = nix_mtr_profile_validate(dev, profile_id, profile, error);
198 fmp = nix_mtr_profile_find(dev, profile_id);
200 return -rte_mtr_error_set(error, EEXIST,
201 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
202 NULL, "Profile already exist");
205 fmp = plt_zmalloc(sizeof(struct cnxk_mtr_profile_node), ROC_ALIGN);
207 return -rte_mtr_error_set(error, ENOMEM,
208 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
209 "Meter profile memory "
212 fmp->id = profile_id;
213 fmp->profile = *profile;
215 TAILQ_INSERT_TAIL(fmps, fmp, next);
221 cnxk_nix_mtr_profile_delete(struct rte_eth_dev *eth_dev, uint32_t profile_id,
222 struct rte_mtr_error *error)
224 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
225 struct cnxk_mtr_profile_node *fmp;
227 if (profile_id == UINT32_MAX)
228 return -rte_mtr_error_set(error, EINVAL,
229 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
230 NULL, "Meter profile id not valid.");
232 fmp = nix_mtr_profile_find(dev, profile_id);
234 return -rte_mtr_error_set(error, ENOENT,
235 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
237 "Meter profile is invalid.");
240 return -rte_mtr_error_set(error, EBUSY,
241 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
242 NULL, "Meter profile is in use.");
244 TAILQ_REMOVE(&dev->mtr_profiles, fmp, next);
250 cnxk_nix_mtr_policy_validate(struct rte_eth_dev *dev,
251 struct rte_mtr_meter_policy_params *policy,
252 struct rte_mtr_error *error)
254 static const char *const action_color[] = {"Green", "Yellow", "Red"};
255 bool supported[RTE_COLORS] = {false, false, false};
256 const struct rte_flow_action *action;
263 return 0; /* Nothing to be validated */
265 for (i = 0; i < RTE_COLORS; i++) {
266 if (policy->actions[i]) {
267 for (action = policy->actions[i];
268 action->type != RTE_FLOW_ACTION_TYPE_END;
270 if (action->type == RTE_FLOW_ACTION_TYPE_METER)
273 if (action->type == RTE_FLOW_ACTION_TYPE_DROP)
278 "%s action is not valid",
280 return -rte_mtr_error_set(error,
282 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
287 sprintf(message, "%s action is null", action_color[i]);
288 return -rte_mtr_error_set(error, EINVAL,
289 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
298 cnxk_fill_policy_actions(struct cnxk_mtr_policy_node *fmp,
299 struct rte_mtr_meter_policy_params *policy)
302 const struct rte_flow_action_meter *mtr;
303 const struct rte_flow_action *action;
306 for (i = 0; i < RTE_COLORS; i++) {
307 if (policy->actions[i]) {
308 for (action = policy->actions[i];
309 action->type != RTE_FLOW_ACTION_TYPE_END;
312 RTE_FLOW_ACTION_TYPE_METER) {
313 fmp->actions[i].action_fate =
316 rte_flow_action_meter *)
318 fmp->actions[i].mtr_id = mtr->mtr_id;
321 if (action->type == RTE_FLOW_ACTION_TYPE_DROP) {
322 fmp->actions[i].action_fate =
331 cnxk_nix_mtr_policy_add(struct rte_eth_dev *eth_dev, uint32_t policy_id,
332 struct rte_mtr_meter_policy_params *policy,
333 struct rte_mtr_error *error)
335 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
336 struct cnxk_mtr_policy *fmps = &dev->mtr_policy;
337 struct cnxk_mtr_policy_node *fmp;
340 fmp = nix_mtr_policy_find(dev, policy_id);
342 return -rte_mtr_error_set(error, EEXIST,
343 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
344 NULL, "Policy already exist");
347 fmp = plt_zmalloc(sizeof(struct cnxk_mtr_policy_node), ROC_ALIGN);
349 return -rte_mtr_error_set(error, ENOMEM,
350 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
351 "Memory allocation failure");
353 rc = cnxk_nix_mtr_policy_validate(eth_dev, policy, error);
359 cnxk_fill_policy_actions(fmp, policy);
360 TAILQ_INSERT_TAIL(fmps, fmp, next);
369 cnxk_nix_mtr_policy_delete(struct rte_eth_dev *eth_dev, uint32_t policy_id,
370 struct rte_mtr_error *error)
372 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
373 struct cnxk_mtr_policy_node *fmp;
375 fmp = nix_mtr_policy_find(dev, policy_id);
377 return -rte_mtr_error_set(error, ENOENT,
378 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
379 NULL, "No policy found");
383 return -rte_mtr_error_set(error, EBUSY,
384 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
385 NULL, "Meter policy is in use.");
387 TAILQ_REMOVE(&dev->mtr_policy, fmp, next);
394 cnxk_nix_mtr_create(struct rte_eth_dev *eth_dev, uint32_t mtr_id,
395 struct rte_mtr_params *params, int shared,
396 struct rte_mtr_error *error)
398 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
399 struct cnxk_mtr_profile_node *profile;
400 struct cnxk_mtr_policy_node *policy;
401 struct cnxk_mtr *fm = &dev->mtr;
402 struct cnxk_meter_node *mtr;
405 RTE_SET_USED(shared);
408 return -rte_mtr_error_set(error, ENOENT,
409 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
410 "Meter params are invalid.");
412 profile = nix_mtr_profile_find(dev, params->meter_profile_id);
414 return -rte_mtr_error_set(error, ENOENT,
415 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
416 ¶ms->meter_profile_id,
417 "Meter profile is invalid.");
419 policy = nix_mtr_policy_find(dev, params->meter_policy_id);
421 return -rte_mtr_error_set(error, ENOENT,
422 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
423 ¶ms->meter_policy_id,
424 "Meter policy is invalid.");
426 mtr = nix_mtr_find(dev, mtr_id);
428 return -rte_mtr_error_set(error, EEXIST,
429 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
430 "Meter already exist");
433 mtr = plt_zmalloc(sizeof(struct cnxk_meter_node), ROC_ALIGN);
435 return -rte_mtr_error_set(error, ENOMEM,
436 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
437 "Meter memory alloc failed.");
441 mtr->profile = profile;
442 mtr->policy = policy;
443 mtr->params = *params;
444 mtr->bpf_id = ROC_NIX_BPF_ID_INVALID;
446 for (i = 0; i < MAX_PRV_MTR_NODES; i++)
447 mtr->prev_id[i] = ROC_NIX_BPF_ID_INVALID;
449 mtr->next_id = ROC_NIX_BPF_ID_INVALID;
450 mtr->is_next = false;
451 mtr->level = ROC_NIX_BPF_LEVEL_IDX_INVALID;
453 if (params->dscp_table) {
454 mtr->params.dscp_table =
455 plt_zmalloc(ROC_NIX_BPF_PRE_COLOR_MAX, ROC_ALIGN);
456 if (mtr->params.dscp_table == NULL) {
458 return -rte_mtr_error_set(error, ENOMEM,
459 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
460 NULL, "Memory alloc failed.");
463 for (i = 0; i < ROC_NIX_BPF_PRE_COLOR_MAX; i++)
464 mtr->params.dscp_table[i] = params->dscp_table[i];
469 TAILQ_INSERT_TAIL(fm, mtr, next);
474 cnxk_nix_mtr_destroy(struct rte_eth_dev *eth_dev, uint32_t mtr_id,
475 struct rte_mtr_error *error)
477 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
478 struct roc_nix_bpf_objs profs = {0};
479 struct cnxk_mtr *fm = &dev->mtr;
480 struct roc_nix *nix = &dev->nix;
481 struct cnxk_meter_node *mtr;
482 struct cnxk_meter_node *mid_mtr;
483 struct cnxk_meter_node *top_mtr;
486 mtr = nix_mtr_find(dev, mtr_id);
488 return -rte_mtr_error_set(error, ENOENT,
489 RTE_MTR_ERROR_TYPE_MTR_ID, &mtr_id,
490 "Meter id is invalid.");
494 return -rte_mtr_error_set(error, EADDRINUSE,
495 RTE_MTR_ERROR_TYPE_MTR_ID, &mtr_id,
499 switch (lvl_map[mtr->level]) {
500 case ROC_NIX_BPF_LEVEL_F_LEAF:
502 rc = roc_nix_bpf_connect(nix, ROC_NIX_BPF_LEVEL_F_LEAF,
504 ROC_NIX_BPF_ID_INVALID);
507 case ROC_NIX_BPF_LEVEL_F_MID:
508 while ((mtr->prev_cnt) + 1) {
510 nix_mtr_find(dev, mtr->prev_id[mtr->prev_cnt]);
511 rc = roc_nix_bpf_connect(nix, ROC_NIX_BPF_LEVEL_F_LEAF,
513 ROC_NIX_BPF_ID_INVALID);
517 rc = roc_nix_bpf_connect(nix, ROC_NIX_BPF_LEVEL_F_MID,
519 ROC_NIX_BPF_ID_INVALID);
522 case ROC_NIX_BPF_LEVEL_F_TOP:
523 while (mtr->prev_cnt) {
525 nix_mtr_find(dev, mtr->prev_id[mtr->prev_cnt]);
526 rc = roc_nix_bpf_connect(nix, ROC_NIX_BPF_LEVEL_F_MID,
528 ROC_NIX_BPF_ID_INVALID);
533 return -rte_mtr_error_set(error, EINVAL,
534 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
535 "Invalid meter level");
541 profs.level = mtr->level;
543 profs.ids[0] = mtr->bpf_id;
544 rc = roc_nix_bpf_free(nix, &profs, 1);
548 mtr->policy->ref_cnt--;
549 mtr->profile->ref_cnt--;
550 TAILQ_REMOVE(fm, mtr, next);
551 plt_free(mtr->params.dscp_table);
558 const struct rte_mtr_ops nix_mtr_ops = {
559 .capabilities_get = cnxk_nix_mtr_capabilities_get,
560 .meter_profile_add = cnxk_nix_mtr_profile_add,
561 .meter_profile_delete = cnxk_nix_mtr_profile_delete,
562 .meter_policy_validate = cnxk_nix_mtr_policy_validate,
563 .meter_policy_add = cnxk_nix_mtr_policy_add,
564 .meter_policy_delete = cnxk_nix_mtr_policy_delete,
565 .create = cnxk_nix_mtr_create,
566 .destroy = cnxk_nix_mtr_destroy,
570 cnxk_nix_mtr_ops_get(struct rte_eth_dev *dev, void *ops)
574 *(const void **)ops = &nix_mtr_ops;