1 // SPDX-License-Identifier: BSD-3-Clause
3 * Copyright 2018 Mellanox Technologies, Ltd
8 #include <rte_malloc.h>
10 #include <rte_mtr_driver.h>
12 #include <mlx5_devx_cmds.h>
13 #include <mlx5_malloc.h>
16 #include "mlx5_flow.h"
19 * Create the meter action.
22 * Pointer to mlx5_priv.
24 * Pointer to flow meter to be converted.
27 * Pointer to the meter action on success, NULL otherwise.
30 mlx5_flow_meter_action_create(struct mlx5_priv *priv,
31 struct mlx5_flow_meter_info *fm)
33 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
34 struct mlx5dv_dr_flow_meter_attr mtr_init;
35 uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
36 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
37 &fm->profile->srtcm_prm;
38 uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
39 uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
41 enum mlx5_meter_domain domain =
42 fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
43 fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
44 MLX5_MTR_DOMAIN_INGRESS;
45 struct mlx5_flow_meter_def_policy *def_policy =
46 priv->sh->mtrmng->def_policy[domain];
48 memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
49 MLX5_SET(flow_meter_parameters, fmp, valid, 1);
50 MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1);
51 MLX5_SET(flow_meter_parameters, fmp,
52 start_color, MLX5_FLOW_COLOR_GREEN);
53 MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0);
54 val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
55 MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val);
56 val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
57 MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val);
58 val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
59 MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val);
60 val = (cbs_cir & ASO_DSEG_MAN_MASK);
61 MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val);
62 val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
63 MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
64 val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
65 MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
66 mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
67 mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
68 mtr_init.flow_meter_parameter = fmp;
69 mtr_init.flow_meter_parameter_sz =
70 MLX5_ST_SZ_BYTES(flow_meter_parameters);
71 mtr_init.active = fm->active_state;
72 return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
81 * Find meter profile by id.
84 * Pointer to mlx5_priv.
85 * @param meter_profile_id
89 * Pointer to the profile found on success, NULL otherwise.
91 static struct mlx5_flow_meter_profile *
92 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
94 struct mlx5_flow_meter_profile *fmp;
95 union mlx5_l3t_data data;
98 if (mlx5_l3t_get_entry(priv->mtr_profile_tbl,
99 meter_profile_id, &data) || !data.ptr)
102 /* Remove reference taken by the mlx5_l3t_get_entry. */
103 ret = mlx5_l3t_clear_entry(priv->mtr_profile_tbl,
105 if (!ret || ret == -1)
111 * Validate the MTR profile.
114 * Pointer to Ethernet device.
115 * @param[in] meter_profile_id
118 * Pointer to meter profile detail.
120 * Pointer to the error structure.
123 * 0 on success, a negative errno value otherwise and rte_errno is set.
126 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
127 uint32_t meter_profile_id,
128 struct rte_mtr_meter_profile *profile,
129 struct rte_mtr_error *error)
131 struct mlx5_priv *priv = dev->data->dev_private;
132 struct mlx5_flow_meter_profile *fmp;
134 /* Profile must not be NULL. */
136 return -rte_mtr_error_set(error, EINVAL,
137 RTE_MTR_ERROR_TYPE_METER_PROFILE,
138 NULL, "Meter profile is null.");
139 /* Meter profile ID must be valid. */
140 if (meter_profile_id == UINT32_MAX)
141 return -rte_mtr_error_set(error, EINVAL,
142 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
143 NULL, "Meter profile id not valid.");
144 /* Meter profile must not exist. */
145 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
147 return -rte_mtr_error_set(error, EEXIST,
148 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
150 "Meter profile already exists.");
151 if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
152 if (priv->config.hca_attr.qos.flow_meter_old) {
153 /* Verify support for flow meter parameters. */
154 if (priv->sh->meter_aso_en && profile->packet_mode) {
155 if (profile->srtcm_rfc2697.cir > 0 &&
156 (profile->srtcm_rfc2697.cir <<
157 MLX5_MTRS_PPS_MAP_BPS_SHIFT)
158 <= MLX5_SRTCM_CIR_MAX &&
159 profile->srtcm_rfc2697.cbs > 0 &&
160 (profile->srtcm_rfc2697.cbs <<
161 MLX5_MTRS_PPS_MAP_BPS_SHIFT)
162 <= MLX5_SRTCM_CBS_MAX &&
163 (profile->srtcm_rfc2697.ebs <<
164 MLX5_MTRS_PPS_MAP_BPS_SHIFT)
165 <= MLX5_SRTCM_EBS_MAX)
167 return -rte_mtr_error_set
169 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
171 profile->srtcm_rfc2697.ebs ?
172 "Metering value ebs must be 0." :
173 "Invalid metering parameters.");
175 if (profile->srtcm_rfc2697.cir > 0 &&
176 profile->srtcm_rfc2697.cir <=
177 MLX5_SRTCM_CIR_MAX &&
178 profile->srtcm_rfc2697.cbs > 0 &&
179 profile->srtcm_rfc2697.cbs <=
180 MLX5_SRTCM_CBS_MAX &&
181 profile->srtcm_rfc2697.ebs <=
184 return -rte_mtr_error_set(error, ENOTSUP,
185 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
187 profile->srtcm_rfc2697.ebs ?
188 "Metering value ebs must be 0." :
189 "Invalid metering parameters.");
192 return -rte_mtr_error_set(error, ENOTSUP,
193 RTE_MTR_ERROR_TYPE_METER_PROFILE,
194 NULL, "Metering algorithm not supported.");
198 * Calculate mantissa and exponent for cir.
201 * Value to be calculated.
203 * Pointer to the mantissa.
205 * Pointer to the exp.
208 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
211 int64_t delta = INT64_MAX;
216 for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
217 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
218 _cir = (1000000000ULL * m) >> e;
219 if (llabs(cir - _cir) <= delta) {
220 delta = llabs(cir - _cir);
231 * Calculate mantissa and exponent for xbs.
234 * Value to be calculated.
236 * Pointer to the mantissa.
238 * Pointer to the exp.
241 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
246 /* Special case xbs == 0 ? both exp and matissa are 0. */
252 /* xbs = xbs_mantissa * 2^xbs_exponent */
253 _man = frexp(xbs, &_exp);
254 _man = _man * pow(2, MLX5_MAN_WIDTH);
255 _exp = _exp - MLX5_MAN_WIDTH;
256 *man = (uint8_t)ceil(_man);
261 * Fill the prm meter parameter.
264 * Pointer to meter profie to be converted.
266 * Pointer to the error structure.
269 * 0 on success, a negative errno value otherwise and rte_errno is set.
272 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
273 struct mlx5_priv *priv, struct rte_mtr_error *error)
275 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
277 uint32_t cbs_exp, cbs_man, cir_exp, cir_man;
278 uint32_t ebs_exp, ebs_man;
279 uint64_t cir, cbs, ebs;
281 if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
282 return -rte_mtr_error_set(error, ENOTSUP,
283 RTE_MTR_ERROR_TYPE_METER_PROFILE,
284 NULL, "Metering algorithm not supported.");
285 if (!priv->sh->meter_aso_en && fmp->profile.packet_mode)
286 return -rte_mtr_error_set(error, ENOTSUP,
287 RTE_MTR_ERROR_TYPE_METER_PROFILE,
288 NULL, "Metering algorithm packet mode not supported.");
289 if (priv->sh->meter_aso_en && fmp->profile.packet_mode) {
290 cir = fmp->profile.srtcm_rfc2697.cir <<
291 MLX5_MTRS_PPS_MAP_BPS_SHIFT;
292 cbs = fmp->profile.srtcm_rfc2697.cbs <<
293 MLX5_MTRS_PPS_MAP_BPS_SHIFT;
294 ebs = fmp->profile.srtcm_rfc2697.ebs <<
295 MLX5_MTRS_PPS_MAP_BPS_SHIFT;
297 cir = fmp->profile.srtcm_rfc2697.cir;
298 cbs = fmp->profile.srtcm_rfc2697.cbs;
299 ebs = fmp->profile.srtcm_rfc2697.ebs;
301 /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
302 mlx5_flow_meter_cir_man_exp_calc(cir, &man, &exp);
303 /* Check if cir mantissa is too large. */
304 if (exp > ASO_DSEG_CIR_EXP_MASK)
305 return -rte_mtr_error_set(error, ENOTSUP,
306 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
307 "meter profile parameter cir is"
311 /* cbs = cbs_mantissa * 2^cbs_exponent */
312 mlx5_flow_meter_xbs_man_exp_calc(cbs, &man, &exp);
313 /* Check if cbs mantissa is too large. */
314 if (exp > ASO_DSEG_EXP_MASK)
315 return -rte_mtr_error_set(error, ENOTSUP,
316 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
317 "meter profile parameter cbs is"
321 srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET |
322 cbs_man << ASO_DSEG_CBS_MAN_OFFSET |
323 cir_exp << ASO_DSEG_CIR_EXP_OFFSET |
325 mlx5_flow_meter_xbs_man_exp_calc(ebs, &man, &exp);
326 /* Check if ebs mantissa is too large. */
327 if (exp > ASO_DSEG_EXP_MASK)
328 return -rte_mtr_error_set(error, ENOTSUP,
329 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
330 "meter profile parameter ebs is"
334 srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET |
335 ebs_man << ASO_DSEG_EBS_MAN_OFFSET);
340 * Callback to get MTR capabilities.
343 * Pointer to Ethernet device.
345 * Pointer to save MTR capabilities.
347 * Pointer to the error structure.
350 * 0 on success, a negative errno value otherwise and rte_errno is set.
353 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
354 struct rte_mtr_capabilities *cap,
355 struct rte_mtr_error *error __rte_unused)
357 struct mlx5_priv *priv = dev->data->dev_private;
358 struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
361 return -rte_mtr_error_set(error, ENOTSUP,
362 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
363 "Meter is not supported");
364 memset(cap, 0, sizeof(*cap));
365 if (priv->sh->meter_aso_en) {
366 /* 2 meters per one ASO cache line. */
367 cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
368 cap->srtcm_rfc2697_packet_mode_supported = 1;
370 cap->n_max = 1 << qattr->log_max_flow_meter;
371 cap->srtcm_rfc2697_packet_mode_supported = 0;
373 cap->srtcm_rfc2697_byte_mode_supported = 1;
374 cap->n_shared_max = cap->n_max;
376 cap->shared_identical = 1;
377 cap->shared_n_flows_per_mtr_max = 4 << 20;
378 /* 2M flows can share the same meter. */
379 cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
380 cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
381 cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
382 cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
383 RTE_MTR_STATS_N_PKTS_DROPPED;
388 * Callback to add MTR profile.
391 * Pointer to Ethernet device.
392 * @param[in] meter_profile_id
395 * Pointer to meter profile detail.
397 * Pointer to the error structure.
400 * 0 on success, a negative errno value otherwise and rte_errno is set.
403 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
404 uint32_t meter_profile_id,
405 struct rte_mtr_meter_profile *profile,
406 struct rte_mtr_error *error)
408 struct mlx5_priv *priv = dev->data->dev_private;
409 struct mlx5_flow_meter_profile *fmp;
410 union mlx5_l3t_data data;
414 return -rte_mtr_error_set(error, ENOTSUP,
415 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
416 "Meter is not supported");
417 /* Check input params. */
418 ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
422 /* Meter profile memory allocation. */
423 fmp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flow_meter_profile),
424 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
426 return -rte_mtr_error_set(error, ENOMEM,
427 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
428 NULL, "Meter profile memory "
430 /* Fill profile info. */
431 fmp->id = meter_profile_id;
432 fmp->profile = *profile;
433 /* Fill the flow meter parameters for the PRM. */
434 ret = mlx5_flow_meter_param_fill(fmp, priv, error);
438 ret = mlx5_l3t_set_entry(priv->mtr_profile_tbl,
439 meter_profile_id, &data);
441 return -rte_mtr_error_set(error, ENOTSUP,
442 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
443 NULL, "Meter profile insert fail.");
451 * Callback to delete MTR profile.
454 * Pointer to Ethernet device.
455 * @param[in] meter_profile_id
458 * Pointer to the error structure.
461 * 0 on success, a negative errno value otherwise and rte_errno is set.
464 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
465 uint32_t meter_profile_id,
466 struct rte_mtr_error *error)
468 struct mlx5_priv *priv = dev->data->dev_private;
469 struct mlx5_flow_meter_profile *fmp;
472 return -rte_mtr_error_set(error, ENOTSUP,
473 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
474 "Meter is not supported");
475 /* Meter profile must exist. */
476 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
478 return -rte_mtr_error_set(error, ENOENT,
479 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
481 "Meter profile id is invalid.");
482 /* Check profile is unused. */
484 return -rte_mtr_error_set(error, EBUSY,
485 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
486 NULL, "Meter profile is in use.");
487 if (mlx5_l3t_clear_entry(priv->mtr_profile_tbl, meter_profile_id))
488 return -rte_mtr_error_set(error, EBUSY,
489 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
490 NULL, "Meter profile remove fail.");
499 * Pointer to Ethernet device.
504 * Pointer to the policy found on success, NULL otherwise.
506 struct mlx5_flow_meter_policy *
507 mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
509 uint32_t *policy_idx)
511 struct mlx5_priv *priv = dev->data->dev_private;
512 struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
513 union mlx5_l3t_data data;
515 if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM || !priv->policy_idx_tbl)
517 if (mlx5_l3t_get_entry(priv->policy_idx_tbl, policy_id, &data) ||
521 *policy_idx = data.dword;
522 sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
524 /* Remove reference taken by the mlx5_l3t_get_entry. */
525 mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id);
527 if (sub_policy->main_policy_id)
528 return sub_policy->main_policy;
533 * Get the last meter's policy from one meter's policy in hierarchy.
536 * Pointer to Ethernet device.
538 * Pointer to flow meter policy.
541 * Pointer to the final meter's policy, or NULL when fail.
543 struct mlx5_flow_meter_policy *
544 mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
545 struct mlx5_flow_meter_policy *policy)
547 struct mlx5_priv *priv = dev->data->dev_private;
548 struct mlx5_flow_meter_info *next_fm;
549 struct mlx5_flow_meter_policy *next_policy = policy;
551 while (next_policy->is_hierarchy) {
552 next_fm = mlx5_flow_meter_find(priv,
553 next_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
554 if (!next_fm || next_fm->def_policy)
556 next_policy = mlx5_flow_meter_policy_find(dev,
557 next_fm->policy_id, NULL);
558 MLX5_ASSERT(next_policy);
564 * Callback to check MTR policy action validate
567 * Pointer to Ethernet device.
569 * Pointer to meter policy action detail.
571 * Pointer to the error structure.
574 * 0 on success, a negative errno value otherwise and rte_errno is set.
577 mlx5_flow_meter_policy_validate(struct rte_eth_dev *dev,
578 struct rte_mtr_meter_policy_params *policy,
579 struct rte_mtr_error *error)
581 struct mlx5_priv *priv = dev->data->dev_private;
582 struct rte_flow_attr attr = { .transfer =
583 priv->config.dv_esw_en ? 1 : 0};
585 bool is_def_policy = false;
586 uint8_t domain_bitmap;
589 if (!priv->mtr_en || !priv->sh->meter_aso_en)
590 return -rte_mtr_error_set(error, ENOTSUP,
591 RTE_MTR_ERROR_TYPE_METER_POLICY,
592 NULL, "meter policy unsupported.");
593 ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
594 &is_rss, &domain_bitmap, &is_def_policy, error);
601 __mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
603 struct mlx5_flow_meter_policy *mtr_policy,
604 struct rte_mtr_error *error,
607 struct mlx5_priv *priv = dev->data->dev_private;
608 struct mlx5_flow_meter_sub_policy *sub_policy;
610 uint16_t sub_policy_num;
612 rte_spinlock_lock(&mtr_policy->sl);
613 if (mtr_policy->ref_cnt) {
614 rte_spinlock_unlock(&mtr_policy->sl);
615 return -rte_mtr_error_set(error, EBUSY,
616 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
618 "Meter policy object is being used.");
620 mlx5_flow_destroy_policy_rules(dev, mtr_policy);
621 mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
622 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
623 sub_policy_num = (mtr_policy->sub_policy_num >>
624 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
625 MLX5_MTR_SUB_POLICY_NUM_MASK;
626 if (sub_policy_num) {
627 for (j = 0; j < sub_policy_num; j++) {
628 sub_policy = mtr_policy->sub_policys[i][j];
631 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
636 if (priv->policy_idx_tbl && clear_l3t) {
637 if (mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id)) {
638 rte_spinlock_unlock(&mtr_policy->sl);
639 return -rte_mtr_error_set(error, ENOTSUP,
640 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
641 "Fail to delete policy in index table.");
644 rte_spinlock_unlock(&mtr_policy->sl);
649 * Callback to add MTR policy.
652 * Pointer to Ethernet device.
653 * @param[out] policy_id
654 * Pointer to policy id
656 * Pointer to meter policy action detail.
658 * Pointer to the error structure.
661 * 0 on success, a negative errno value otherwise and rte_errno is set.
664 mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
666 struct rte_mtr_meter_policy_params *policy,
667 struct rte_mtr_error *error)
669 struct mlx5_priv *priv = dev->data->dev_private;
670 struct rte_flow_attr attr = { .transfer =
671 priv->config.dv_esw_en ? 1 : 0};
672 uint32_t sub_policy_idx = 0;
673 uint32_t policy_idx = 0;
674 struct mlx5_flow_meter_policy *mtr_policy = NULL;
675 struct mlx5_flow_meter_sub_policy *sub_policy;
677 bool is_def_policy = false;
680 uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
681 uint16_t sub_policy_num;
682 uint8_t domain_bitmap = 0;
683 union mlx5_l3t_data data;
684 bool skip_rule = false;
687 return -rte_mtr_error_set(error, ENOTSUP,
688 RTE_MTR_ERROR_TYPE_METER_POLICY,
689 NULL, "meter policy unsupported. ");
690 if (policy_id == MLX5_INVALID_POLICY_ID)
691 return -rte_mtr_error_set(error, ENOTSUP,
692 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
693 NULL, "policy ID is invalid. ");
694 if (policy_id == priv->sh->mtrmng->def_policy_id)
695 return -rte_mtr_error_set(error, EEXIST,
696 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
697 NULL, "default policy ID exists. ");
698 mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
700 return -rte_mtr_error_set(error, EEXIST,
701 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
702 NULL, "policy ID exists. ");
703 ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
704 &is_rss, &domain_bitmap, &is_def_policy, error);
708 return -rte_mtr_error_set(error, ENOTSUP,
709 RTE_MTR_ERROR_TYPE_METER_POLICY,
710 NULL, "fail to find policy domain.");
712 if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID)
713 return -rte_mtr_error_set(error, EEXIST,
714 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
715 NULL, "a policy with similar actions "
716 "is already configured");
717 if (mlx5_flow_create_def_policy(dev))
718 return -rte_mtr_error_set(error, ENOTSUP,
719 RTE_MTR_ERROR_TYPE_METER_POLICY,
721 "fail to create non-terminated policy.");
722 priv->sh->mtrmng->def_policy_id = policy_id;
725 if (!priv->sh->meter_aso_en)
726 return -rte_mtr_error_set(error, ENOTSUP,
727 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
728 "no ASO capability to support the policy ");
729 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
730 if (!(domain_bitmap & (1 << i)))
733 * If RSS is found, it means that only the ingress domain can
734 * be supported. It is invalid to support RSS for one color
735 * and egress / transfer domain actions for another. Drop and
736 * jump action should have no impact.
740 sizeof(struct mlx5_flow_meter_sub_policy *) *
741 MLX5_MTR_RSS_MAX_SUB_POLICY;
744 policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
746 mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
747 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
749 return -rte_mtr_error_set(error, ENOMEM,
750 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
751 "Memory alloc failed for meter policy.");
752 policy_size = sizeof(struct mlx5_flow_meter_policy);
753 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
754 if (!(domain_bitmap & (1 << i)))
756 if (i == MLX5_MTR_DOMAIN_INGRESS)
757 mtr_policy->ingress = 1;
758 if (i == MLX5_MTR_DOMAIN_EGRESS)
759 mtr_policy->egress = 1;
760 if (i == MLX5_MTR_DOMAIN_TRANSFER)
761 mtr_policy->transfer = 1;
762 sub_policy = mlx5_ipool_zmalloc
763 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
766 sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
768 sub_policy->idx = sub_policy_idx;
769 sub_policy->main_policy = mtr_policy;
771 policy_idx = sub_policy_idx;
772 sub_policy->main_policy_id = 1;
774 mtr_policy->sub_policys[i] =
775 (struct mlx5_flow_meter_sub_policy **)
776 ((uint8_t *)mtr_policy + policy_size);
777 mtr_policy->sub_policys[i][0] = sub_policy;
778 sub_policy_num = (mtr_policy->sub_policy_num >>
779 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
780 MLX5_MTR_SUB_POLICY_NUM_MASK;
782 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
783 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
784 mtr_policy->sub_policy_num |=
785 (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
786 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
788 * If RSS is found, it means that only the ingress domain can
789 * be supported. It is invalid to support RSS for one color
790 * and egress / transfer domain actions for another. Drop and
791 * jump action should have no impact.
794 mtr_policy->is_rss = 1;
797 policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
799 rte_spinlock_init(&mtr_policy->sl);
800 ret = mlx5_flow_create_mtr_acts(dev, mtr_policy,
801 policy->actions, error);
804 if (mtr_policy->is_hierarchy) {
805 struct mlx5_flow_meter_policy *final_policy;
808 mlx5_flow_meter_hierarchy_get_final_policy(dev, mtr_policy);
811 skip_rule = (final_policy->is_rss || final_policy->is_queue);
814 * If either Green or Yellow has queue / RSS action, all the policy
815 * rules will be created later in the flow splitting stage.
817 if (!is_rss && !mtr_policy->is_queue && !skip_rule) {
818 /* Create policy rules in HW. */
819 ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
823 data.dword = policy_idx;
824 if (!priv->policy_idx_tbl) {
825 priv->policy_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
826 if (!priv->policy_idx_tbl)
829 if (mlx5_l3t_set_entry(priv->policy_idx_tbl, policy_id, &data))
834 ret = __mlx5_flow_meter_policy_delete(dev, policy_id,
835 mtr_policy, error, false);
836 mlx5_free(mtr_policy);
840 return -rte_mtr_error_set(error, ENOTSUP,
841 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
842 NULL, "Failed to create devx policy.");
846 * Callback to delete MTR policy.
849 * Pointer to Ethernet device.
850 * @param[in] policy_id
853 * Pointer to the error structure.
856 * 0 on success, a negative errno value otherwise and rte_errno is set.
859 mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
861 struct rte_mtr_error *error)
863 struct mlx5_priv *priv = dev->data->dev_private;
864 struct mlx5_flow_meter_policy *mtr_policy;
868 if (policy_id == priv->sh->mtrmng->def_policy_id) {
869 if (priv->sh->mtrmng->def_policy_ref_cnt > 0)
870 return -rte_mtr_error_set(error, ENOTSUP,
871 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
872 "Meter policy object is being used.");
873 priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
876 mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
878 return -rte_mtr_error_set(error, ENOTSUP,
879 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
880 "Meter policy id is invalid. ");
881 ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
885 mlx5_free(mtr_policy);
890 * Check meter validation.
893 * Pointer to mlx5 private data structure.
894 * @param[in] meter_id
897 * Pointer to rte meter parameters.
899 * Pointer to rte meter error structure.
902 * 0 on success, a negative errno value otherwise and rte_errno is set.
905 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
906 struct rte_mtr_params *params,
907 struct rte_mtr_error *error)
909 /* Meter must use global drop action. */
910 if (!priv->sh->dr_drop_action)
911 return -rte_mtr_error_set(error, ENOTSUP,
912 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
914 "No drop action ready for meter.");
915 /* Meter params must not be NULL. */
917 return -rte_mtr_error_set(error, EINVAL,
918 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
919 NULL, "Meter object params null.");
920 /* Previous meter color is not supported. */
921 if (params->use_prev_mtr_color)
922 return -rte_mtr_error_set(error, ENOTSUP,
923 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
925 "Previous meter color "
927 if (params->meter_policy_id == MLX5_INVALID_POLICY_ID)
928 return -rte_mtr_error_set(error, ENOENT,
929 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
930 NULL, "Meter policy id not valid.");
931 /* Validate meter id. */
932 if (mlx5_flow_meter_find(priv, meter_id, NULL))
933 return -rte_mtr_error_set(error, EEXIST,
934 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
935 "Meter object already exists.");
940 * Modify the flow meter action.
943 * Pointer to mlx5 private data structure.
945 * Pointer to flow meter to be modified.
947 * Pointer to meter srtcm description parameter.
948 * @param[in] modify_bits
949 * The bit in srtcm to be updated.
950 * @param[in] active_state
951 * The state to be updated.
953 * 0 on success, o negative value otherwise.
956 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
957 struct mlx5_flow_meter_info *fm,
958 const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
959 uint64_t modify_bits, uint32_t active_state, uint32_t is_enable)
961 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
962 uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
964 struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
966 struct mlx5_aso_mtr *aso_mtr = NULL;
967 uint32_t cbs_cir, ebs_eir, val;
969 if (priv->sh->meter_aso_en) {
970 fm->is_enable = !!is_enable;
971 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
972 ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
975 ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr);
979 /* Fill command parameters. */
980 mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
981 mod_attr.flow_meter_parameter = in;
982 mod_attr.flow_meter_parameter_sz =
983 MLX5_ST_SZ_BYTES(flow_meter_parameters);
984 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
985 mod_attr.active = !!active_state;
989 cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
990 ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
991 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
992 val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) &
994 MLX5_SET(flow_meter_parameters, attr,
996 val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) &
998 MLX5_SET(flow_meter_parameters, attr,
1001 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
1002 val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) &
1004 MLX5_SET(flow_meter_parameters, attr,
1006 val = cbs_cir & ASO_DSEG_MAN_MASK;
1007 MLX5_SET(flow_meter_parameters, attr,
1010 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
1011 val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) &
1013 MLX5_SET(flow_meter_parameters, attr,
1015 val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) &
1017 MLX5_SET(flow_meter_parameters, attr,
1020 /* Apply modifications to meter only if it was created. */
1021 if (fm->meter_action) {
1022 ret = mlx5_glue->dv_modify_flow_action_meter
1023 (fm->meter_action, &mod_attr,
1024 rte_cpu_to_be_64(modify_bits));
1028 /* Update succeedded modify meter parameters. */
1029 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
1030 fm->active_state = !!active_state;
1045 mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
1046 struct mlx5_flow_meter_info *fm,
1047 uint64_t stats_mask)
1050 (stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
1051 fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
1052 if (fm->bytes_dropped || fm->pkts_dropped) {
1053 if (!fm->drop_cnt) {
1054 /* Alloc policer counters. */
1055 fm->drop_cnt = mlx5_counter_alloc(dev);
1061 mlx5_counter_free(dev, fm->drop_cnt);
1069 * Create meter rules.
1072 * Pointer to Ethernet device.
1073 * @param[in] meter_id
1076 * Pointer to rte meter parameters.
1078 * Meter shared with other flow or not.
1080 * Pointer to rte meter error structure.
1083 * 0 on success, a negative errno value otherwise and rte_errno is set.
1086 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
1087 struct rte_mtr_params *params, int shared,
1088 struct rte_mtr_error *error)
1090 struct mlx5_priv *priv = dev->data->dev_private;
1091 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1092 struct mlx5_flow_meter_profile *fmp;
1093 struct mlx5_flow_meter_info *fm;
1094 struct mlx5_legacy_flow_meter *legacy_fm;
1095 struct mlx5_flow_meter_policy *mtr_policy = NULL;
1096 struct mlx5_indexed_pool_config flow_ipool_cfg = {
1100 .type = "mlx5_flow_mtr_flow_id_pool",
1102 struct mlx5_aso_mtr *aso_mtr;
1103 uint32_t mtr_idx, policy_idx;
1104 union mlx5_l3t_data data;
1106 uint8_t domain_bitmap;
1107 uint8_t mtr_id_bits;
1108 uint8_t mtr_reg_bits = priv->mtr_reg_share ?
1109 MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
1112 return -rte_mtr_error_set(error, ENOTSUP,
1113 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1114 "Meter is not supported");
1115 /* Validate the parameters. */
1116 ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
1119 /* Meter profile must exist. */
1120 fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
1122 return -rte_mtr_error_set(error, ENOENT,
1123 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1124 NULL, "Meter profile id not valid.");
1125 /* Meter policy must exist. */
1126 if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
1128 (&priv->sh->mtrmng->def_policy_ref_cnt,
1129 1, __ATOMIC_RELAXED);
1130 domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
1131 if (!priv->config.dv_esw_en)
1132 domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
1134 mtr_policy = mlx5_flow_meter_policy_find(dev,
1135 params->meter_policy_id, &policy_idx);
1136 if (!priv->sh->meter_aso_en)
1137 return -rte_mtr_error_set(error, ENOTSUP,
1138 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1139 "Part of the policies cannot be "
1140 "supported without ASO ");
1142 return -rte_mtr_error_set(error, ENOENT,
1143 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1144 NULL, "Meter policy id not valid.");
1145 domain_bitmap = (mtr_policy->ingress ?
1146 MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
1147 (mtr_policy->egress ?
1148 MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
1149 (mtr_policy->transfer ?
1150 MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
1152 /* Allocate the flow meter memory. */
1153 if (priv->sh->meter_aso_en) {
1154 mtr_idx = mlx5_flow_mtr_alloc(dev);
1156 return -rte_mtr_error_set(error, ENOMEM,
1157 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1158 "Memory alloc failed for meter.");
1159 aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
1162 legacy_fm = mlx5_ipool_zmalloc
1163 (priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
1164 if (legacy_fm == NULL)
1165 return -rte_mtr_error_set(error, ENOMEM,
1166 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1167 "Memory alloc failed for meter.");
1168 legacy_fm->idx = mtr_idx;
1169 fm = &legacy_fm->fm;
1171 mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
1172 if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
1174 DRV_LOG(ERR, "Meter number exceeds max limit.");
1177 if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
1178 priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
1179 /* Fill the flow meter parameters. */
1180 fm->meter_id = meter_id;
1181 fm->policy_id = params->meter_policy_id;
1183 if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
1185 if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
1187 /* Add to the flow meter list. */
1188 if (!priv->sh->meter_aso_en)
1189 TAILQ_INSERT_TAIL(fms, legacy_fm, next);
1190 /* Add to the flow meter list. */
1191 fm->active_state = 1; /* Config meter starts as active. */
1193 fm->shared = !!shared;
1194 __atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
1195 if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
1197 fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
1198 if (!fm->flow_ipool)
1201 rte_spinlock_init(&fm->sl);
1202 /* If ASO meter supported, update ASO flow meter by wqe. */
1203 if (priv->sh->meter_aso_en) {
1204 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1205 ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
1208 if (!priv->mtr_idx_tbl) {
1210 mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
1211 if (!priv->mtr_idx_tbl)
1214 data.dword = mtr_idx;
1215 if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
1219 __atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
1222 mlx5_flow_destroy_mtr_tbls(dev, fm);
1223 /* Free policer counters. */
1225 mlx5_counter_free(dev, fm->drop_cnt);
1226 if (priv->sh->meter_aso_en)
1227 mlx5_flow_mtr_free(dev, mtr_idx);
1229 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
1230 return -rte_mtr_error_set(error, ENOTSUP,
1231 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1232 NULL, "Failed to create devx meter.");
1236 mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
1237 struct mlx5_flow_meter_info *fm,
1240 struct mlx5_priv *priv = dev->data->dev_private;
1241 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1242 struct mlx5_flow_meter_profile *fmp;
1243 struct mlx5_legacy_flow_meter *legacy_fm = NULL;
1244 struct mlx5_flow_meter_policy *mtr_policy;
1246 /* Meter object must not have any owner. */
1247 MLX5_ASSERT(!fm->ref_cnt);
1248 /* Get meter profile. */
1252 /* Update dependencies. */
1253 __atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
1255 /* Remove from list. */
1256 if (!priv->sh->meter_aso_en) {
1257 legacy_fm = container_of(fm,
1258 struct mlx5_legacy_flow_meter, fm);
1259 TAILQ_REMOVE(fms, legacy_fm, next);
1261 /* Free drop counters. */
1263 mlx5_counter_free(dev, fm->drop_cnt);
1264 /* Free meter flow table. */
1265 if (fm->flow_ipool) {
1266 mlx5_ipool_destroy(fm->flow_ipool);
1269 mlx5_flow_destroy_mtr_tbls(dev, fm);
1271 __atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
1272 1, __ATOMIC_RELAXED);
1273 if (priv->sh->meter_aso_en) {
1274 if (!fm->def_policy) {
1275 mtr_policy = mlx5_flow_meter_policy_find(dev,
1276 fm->policy_id, NULL);
1278 __atomic_sub_fetch(&mtr_policy->ref_cnt,
1279 1, __ATOMIC_RELAXED);
1283 if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
1285 mlx5_flow_mtr_free(dev, mtr_idx);
1287 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
1294 * Destroy meter rules.
1297 * Pointer to Ethernet device.
1298 * @param[in] meter_id
1301 * Pointer to rte meter error structure.
1304 * 0 on success, a negative errno value otherwise and rte_errno is set.
1307 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
1308 struct rte_mtr_error *error)
1310 struct mlx5_priv *priv = dev->data->dev_private;
1311 struct mlx5_flow_meter_info *fm;
1312 uint32_t mtr_idx = 0;
1315 return -rte_mtr_error_set(error, ENOTSUP,
1316 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1318 "Meter is not supported");
1319 /* Meter object must exist. */
1320 fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
1322 return -rte_mtr_error_set(error, ENOENT,
1323 RTE_MTR_ERROR_TYPE_MTR_ID,
1325 "Meter object id not valid.");
1326 /* Meter object must not have any owner. */
1327 if (fm->ref_cnt > 0)
1328 return -rte_mtr_error_set(error, EBUSY,
1329 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1331 "Meter object is being used.");
1332 /* Destroy the meter profile. */
1333 if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
1334 return -rte_mtr_error_set(error, EINVAL,
1335 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1337 "MTR object meter profile invalid.");
1342 * Modify meter state.
1345 * Pointer to mlx5 private data structure.
1347 * Pointer to flow meter.
1348 * @param[in] new_state
1349 * New state to update.
1351 * Pointer to rte meter error structure.
1354 * 0 on success, a negative errno value otherwise and rte_errno is set.
1357 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
1358 struct mlx5_flow_meter_info *fm,
1360 struct rte_mtr_error *error)
1362 static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
1363 .cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL),
1366 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
1367 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
1370 if (new_state == MLX5_FLOW_METER_DISABLE)
1371 ret = mlx5_flow_meter_action_modify(priv, fm,
1372 &srtcm, modify_bits, 0, 0);
1374 ret = mlx5_flow_meter_action_modify(priv, fm,
1375 &fm->profile->srtcm_prm,
1378 return -rte_mtr_error_set(error, -ret,
1379 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
1382 "Failed to enable meter." :
1383 "Failed to disable meter.");
1388 * Callback to enable flow meter.
1391 * Pointer to Ethernet device.
1392 * @param[in] meter_id
1395 * Pointer to rte meter error structure.
1398 * 0 on success, a negative errno value otherwise and rte_errno is set.
1401 mlx5_flow_meter_enable(struct rte_eth_dev *dev,
1403 struct rte_mtr_error *error)
1405 struct mlx5_priv *priv = dev->data->dev_private;
1406 struct mlx5_flow_meter_info *fm;
1410 return -rte_mtr_error_set(error, ENOTSUP,
1411 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1412 "Meter is not supported");
1413 /* Meter object must exist. */
1414 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1416 return -rte_mtr_error_set(error, ENOENT,
1417 RTE_MTR_ERROR_TYPE_MTR_ID,
1418 NULL, "Meter not found.");
1419 if (fm->active_state == MLX5_FLOW_METER_ENABLE)
1421 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
1424 fm->active_state = MLX5_FLOW_METER_ENABLE;
1429 * Callback to disable flow meter.
1432 * Pointer to Ethernet device.
1433 * @param[in] meter_id
1436 * Pointer to rte meter error structure.
1439 * 0 on success, a negative errno value otherwise and rte_errno is set.
1442 mlx5_flow_meter_disable(struct rte_eth_dev *dev,
1444 struct rte_mtr_error *error)
1446 struct mlx5_priv *priv = dev->data->dev_private;
1447 struct mlx5_flow_meter_info *fm;
1451 return -rte_mtr_error_set(error, ENOTSUP,
1452 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1453 "Meter is not supported");
1454 /* Meter object must exist. */
1455 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1457 return -rte_mtr_error_set(error, ENOENT,
1458 RTE_MTR_ERROR_TYPE_MTR_ID,
1459 NULL, "Meter not found.");
1460 if (fm->active_state == MLX5_FLOW_METER_DISABLE)
1462 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
1465 fm->active_state = MLX5_FLOW_METER_DISABLE;
1470 * Callback to update meter profile.
1473 * Pointer to Ethernet device.
1474 * @param[in] meter_id
1476 * @param[in] meter_profile_id
1477 * To be updated meter profile id.
1479 * Pointer to rte meter error structure.
1482 * 0 on success, a negative errno value otherwise and rte_errno is set.
1485 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
1487 uint32_t meter_profile_id,
1488 struct rte_mtr_error *error)
1490 struct mlx5_priv *priv = dev->data->dev_private;
1491 struct mlx5_flow_meter_profile *fmp;
1492 struct mlx5_flow_meter_profile *old_fmp;
1493 struct mlx5_flow_meter_info *fm;
1494 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
1495 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
1499 return -rte_mtr_error_set(error, ENOTSUP,
1500 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1501 "Meter is not supported");
1502 /* Meter profile must exist. */
1503 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
1505 return -rte_mtr_error_set(error, ENOENT,
1506 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1507 NULL, "Meter profile not found.");
1508 /* Meter object must exist. */
1509 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1511 return -rte_mtr_error_set(error, ENOENT,
1512 RTE_MTR_ERROR_TYPE_MTR_ID,
1513 NULL, "Meter not found.");
1514 /* MTR object already set to meter profile id. */
1515 old_fmp = fm->profile;
1518 /* Update the profile. */
1520 /* Update meter params in HW (if not disabled). */
1521 if (fm->active_state == MLX5_FLOW_METER_DISABLE)
1523 ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
1524 modify_bits, fm->active_state, 1);
1526 fm->profile = old_fmp;
1527 return -rte_mtr_error_set(error, -ret,
1528 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
1529 NULL, "Failed to update meter"
1530 " parmeters in hardware.");
1538 * Callback to update meter stats mask.
1541 * Pointer to Ethernet device.
1542 * @param[in] meter_id
1544 * @param[in] stats_mask
1545 * To be updated stats_mask.
1547 * Pointer to rte meter error structure.
1550 * 0 on success, a negative errno value otherwise and rte_errno is set.
1553 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
1555 uint64_t stats_mask,
1556 struct rte_mtr_error *error)
1558 struct mlx5_priv *priv = dev->data->dev_private;
1559 struct mlx5_flow_meter_info *fm;
1562 return -rte_mtr_error_set(error, ENOTSUP,
1563 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1564 "Meter is not supported");
1565 /* Meter object must exist. */
1566 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1568 return -rte_mtr_error_set(error, ENOENT,
1569 RTE_MTR_ERROR_TYPE_MTR_ID,
1570 NULL, "Meter object id not valid.");
1571 if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
1572 return -rte_mtr_error_set(error, ENOENT,
1573 RTE_MTR_ERROR_TYPE_MTR_ID,
1574 NULL, "Fail to allocate "
1575 "counter for meter.");
1580 * Callback to read meter statistics.
1583 * Pointer to Ethernet device.
1584 * @param[in] meter_id
1587 * Pointer to store the statistics.
1588 * @param[out] stats_mask
1589 * Pointer to store the stats_mask.
1591 * Statistic to be cleared after read or not.
1593 * Pointer to rte meter error structure.
1596 * 0 on success, a negative errno value otherwise and rte_errno is set.
1599 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
1601 struct rte_mtr_stats *stats,
1602 uint64_t *stats_mask,
1604 struct rte_mtr_error *error)
1606 struct mlx5_priv *priv = dev->data->dev_private;
1607 struct mlx5_flow_meter_info *fm;
1613 return -rte_mtr_error_set(error, ENOTSUP,
1614 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1615 "Meter is not supported");
1616 /* Meter object must exist. */
1617 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1619 return -rte_mtr_error_set(error, ENOENT,
1620 RTE_MTR_ERROR_TYPE_MTR_ID,
1621 NULL, "Meter object id not valid.");
1623 if (fm->bytes_dropped)
1624 *stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
1625 if (fm->pkts_dropped)
1626 *stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
1627 memset(stats, 0, sizeof(*stats));
1629 ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
1633 /* If need to read the packets, set it. */
1634 if (fm->pkts_dropped)
1635 stats->n_pkts_dropped = pkts;
1636 /* If need to read the bytes, set it. */
1637 if (fm->bytes_dropped)
1638 stats->n_bytes_dropped = bytes;
1642 return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
1643 "Failed to read meter drop counters.");
1646 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
1647 .capabilities_get = mlx5_flow_mtr_cap_get,
1648 .meter_profile_add = mlx5_flow_meter_profile_add,
1649 .meter_profile_delete = mlx5_flow_meter_profile_delete,
1650 .meter_policy_validate = mlx5_flow_meter_policy_validate,
1651 .meter_policy_add = mlx5_flow_meter_policy_add,
1652 .meter_policy_delete = mlx5_flow_meter_policy_delete,
1653 .create = mlx5_flow_meter_create,
1654 .destroy = mlx5_flow_meter_destroy,
1655 .meter_enable = mlx5_flow_meter_enable,
1656 .meter_disable = mlx5_flow_meter_disable,
1657 .meter_profile_update = mlx5_flow_meter_profile_update,
1658 .meter_dscp_table_update = NULL,
1659 .stats_update = mlx5_flow_meter_stats_update,
1660 .stats_read = mlx5_flow_meter_stats_read,
1664 * Get meter operations.
1667 * Pointer to Ethernet device structure.
1669 * Pointer to set the mtr operations.
1675 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
1677 *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
1685 * Pointer to mlx5_priv.
1689 * Pointer to Meter index.
1692 * Pointer to the meter info found on success, NULL otherwise.
1694 struct mlx5_flow_meter_info *
1695 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
1698 struct mlx5_legacy_flow_meter *legacy_fm;
1699 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1700 struct mlx5_aso_mtr *aso_mtr;
1701 struct mlx5_aso_mtr_pools_mng *pools_mng =
1702 &priv->sh->mtrmng->pools_mng;
1703 union mlx5_l3t_data data;
1705 if (priv->sh->meter_aso_en) {
1706 rte_spinlock_lock(&pools_mng->mtrsl);
1707 if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
1708 rte_spinlock_unlock(&pools_mng->mtrsl);
1711 if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
1713 rte_spinlock_unlock(&pools_mng->mtrsl);
1717 *mtr_idx = data.dword;
1718 aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
1719 /* Remove reference taken by the mlx5_l3t_get_entry. */
1720 mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
1721 rte_spinlock_unlock(&pools_mng->mtrsl);
1722 if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
1724 return &aso_mtr->fm;
1726 TAILQ_FOREACH(legacy_fm, fms, next)
1727 if (meter_id == legacy_fm->fm.meter_id) {
1729 *mtr_idx = legacy_fm->idx;
1730 return &legacy_fm->fm;
1736 * Find meter by index.
1739 * Pointer to mlx5_priv.
1744 * Pointer to the meter info found on success, NULL otherwise.
1746 struct mlx5_flow_meter_info *
1747 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
1749 struct mlx5_aso_mtr *aso_mtr;
1751 if (priv->sh->meter_aso_en) {
1752 aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
1755 return &aso_mtr->fm;
1757 return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
1762 * Attach meter to flow.
1763 * Unidirectional Meter creation can only be done
1764 * when flow direction is known, i.e. when calling meter_attach.
1767 * Pointer to mlx5 private data.
1769 * Pointer to flow meter.
1771 * Pointer to flow attributes.
1772 * @param [out] error
1773 * Pointer to error structure.
1776 * 0 on success, a negative errno value otherwise and rte_errno is set.
1779 mlx5_flow_meter_attach(struct mlx5_priv *priv,
1780 struct mlx5_flow_meter_info *fm,
1781 const struct rte_flow_attr *attr,
1782 struct rte_flow_error *error)
1786 if (priv->sh->meter_aso_en) {
1787 struct mlx5_aso_mtr *aso_mtr;
1789 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1790 if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) {
1791 return rte_flow_error_set(error, ENOENT,
1792 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1794 "Timeout in meter configuration");
1796 rte_spinlock_lock(&fm->sl);
1797 if (fm->shared || !fm->ref_cnt) {
1800 rte_flow_error_set(error, EINVAL,
1801 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1802 "Meter cannot be shared");
1805 rte_spinlock_unlock(&fm->sl);
1807 rte_spinlock_lock(&fm->sl);
1808 if (fm->meter_action) {
1810 attr->transfer == fm->transfer &&
1811 attr->ingress == fm->ingress &&
1812 attr->egress == fm->egress) {
1815 rte_flow_error_set(error, EINVAL,
1816 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1818 "Meter attr not match." :
1819 "Meter cannot be shared.");
1823 fm->ingress = attr->ingress;
1824 fm->egress = attr->egress;
1825 fm->transfer = attr->transfer;
1827 /* This also creates the meter object. */
1828 fm->meter_action = mlx5_flow_meter_action_create(priv,
1830 if (!fm->meter_action) {
1835 rte_flow_error_set(error, EINVAL,
1836 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1837 "Meter action create failed.");
1841 rte_spinlock_unlock(&fm->sl);
1843 return ret ? -rte_errno : 0;
1847 * Detach meter from flow.
1850 * Pointer to mlx5 private data.
1852 * Pointer to flow meter.
1855 mlx5_flow_meter_detach(struct mlx5_priv *priv,
1856 struct mlx5_flow_meter_info *fm)
1858 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
1859 rte_spinlock_lock(&fm->sl);
1860 MLX5_ASSERT(fm->ref_cnt);
1861 if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
1862 mlx5_glue->destroy_flow_action(fm->meter_action);
1863 fm->meter_action = NULL;
1868 rte_spinlock_unlock(&fm->sl);
1876 * Flush meter with Rx queue configuration.
1879 * Pointer to Ethernet device.
1882 mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev)
1884 struct mlx5_priv *priv = dev->data->dev_private;
1885 struct mlx5_flow_meter_sub_policy *sub_policy;
1886 struct mlx5_flow_meter_policy *mtr_policy;
1888 uint32_t i, policy_idx;
1892 if (priv->policy_idx_tbl) {
1893 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
1894 policy_idx = *(uint32_t *)entry;
1895 sub_policy = mlx5_ipool_get
1896 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
1898 if (!sub_policy || !sub_policy->main_policy)
1900 mtr_policy = sub_policy->main_policy;
1901 if (mtr_policy->is_queue || mtr_policy->is_rss)
1902 mlx5_flow_destroy_sub_policy_with_rxq(dev,
1909 * Iterate a meter hierarchy and flush all meters and policies if possible.
1912 * Pointer to Ethernet device.
1914 * Pointer to flow meter.
1915 * @param[in] mtr_idx
1918 * Pointer to rte meter error structure.
1921 * 0 on success, a negative errno value otherwise and rte_errno is set.
1924 mlx5_flow_meter_flush_hierarchy(struct rte_eth_dev *dev,
1925 struct mlx5_flow_meter_info *fm,
1927 struct rte_mtr_error *error)
1929 struct mlx5_priv *priv = dev->data->dev_private;
1930 struct mlx5_flow_meter_policy *policy;
1932 struct mlx5_flow_meter_info *next_fm;
1933 uint32_t next_mtr_idx;
1934 struct mlx5_flow_meter_policy *next_policy = NULL;
1936 policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
1937 MLX5_ASSERT(policy);
1938 while (!fm->ref_cnt && policy->is_hierarchy) {
1939 policy_id = fm->policy_id;
1940 next_fm = mlx5_flow_meter_find(priv,
1941 policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
1944 next_policy = mlx5_flow_meter_policy_find(dev,
1947 MLX5_ASSERT(next_policy);
1949 if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
1950 return -rte_mtr_error_set(error, ENOTSUP,
1951 RTE_MTR_ERROR_TYPE_MTR_ID,
1953 "Failed to flush meter.");
1954 if (policy->ref_cnt)
1956 if (__mlx5_flow_meter_policy_delete(dev, policy_id,
1957 policy, error, true))
1960 if (!next_fm || !next_policy)
1963 mtr_idx = next_mtr_idx;
1964 policy = next_policy;
1970 * Flush all the hierarchy meters and their policies.
1973 * Pointer to Ethernet device.
1975 * Pointer to rte meter error structure.
1978 * 0 on success, a negative errno value otherwise and rte_errno is set.
1981 mlx5_flow_meter_flush_all_hierarchies(struct rte_eth_dev *dev,
1982 struct rte_mtr_error *error)
1984 struct mlx5_priv *priv = dev->data->dev_private;
1985 struct mlx5_flow_meter_info *fm;
1986 struct mlx5_flow_meter_policy *policy;
1987 struct mlx5_flow_meter_sub_policy *sub_policy;
1988 struct mlx5_flow_meter_info *next_fm;
1989 struct mlx5_aso_mtr *aso_mtr;
1990 uint32_t mtr_idx = 0;
1991 uint32_t i, policy_idx;
1994 if (!priv->mtr_idx_tbl || !priv->policy_idx_tbl)
1996 MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
1997 mtr_idx = *(uint32_t *)entry;
2000 aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
2002 if (fm->ref_cnt || fm->def_policy)
2004 if (mlx5_flow_meter_flush_hierarchy(dev, fm, mtr_idx, error))
2007 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
2008 policy_idx = *(uint32_t *)entry;
2009 sub_policy = mlx5_ipool_get
2010 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
2013 return -rte_mtr_error_set(error,
2015 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2016 NULL, "Meter policy invalid.");
2017 policy = sub_policy->main_policy;
2018 if (!policy || !policy->is_hierarchy || policy->ref_cnt)
2020 next_fm = mlx5_flow_meter_find(priv,
2021 policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
2023 if (__mlx5_flow_meter_policy_delete(dev, i, policy,
2025 return -rte_mtr_error_set(error,
2027 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2028 NULL, "Meter policy invalid.");
2030 if (!next_fm || next_fm->ref_cnt || next_fm->def_policy)
2032 if (mlx5_flow_meter_flush_hierarchy(dev, next_fm,
2039 * Flush meter configuration.
2042 * Pointer to Ethernet device.
2044 * Pointer to rte meter error structure.
2047 * 0 on success, a negative errno value otherwise and rte_errno is set.
2050 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
2052 struct mlx5_priv *priv = dev->data->dev_private;
2053 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
2054 struct mlx5_flow_meter_profile *fmp;
2055 struct mlx5_legacy_flow_meter *legacy_fm;
2056 struct mlx5_flow_meter_info *fm;
2057 struct mlx5_flow_meter_sub_policy *sub_policy;
2059 uint32_t i, mtr_idx, policy_idx;
2061 struct mlx5_aso_mtr *aso_mtr;
2065 if (priv->sh->meter_aso_en) {
2066 if (mlx5_flow_meter_flush_all_hierarchies(dev, error))
2068 if (priv->mtr_idx_tbl) {
2069 MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
2070 mtr_idx = *(uint32_t *)entry;
2073 mlx5_aso_meter_by_idx(priv, mtr_idx);
2075 (void)mlx5_flow_meter_params_flush(dev,
2079 mlx5_l3t_destroy(priv->mtr_idx_tbl);
2080 priv->mtr_idx_tbl = NULL;
2083 TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
2084 fm = &legacy_fm->fm;
2085 if (mlx5_flow_meter_params_flush(dev, fm, 0))
2086 return -rte_mtr_error_set(error, EINVAL,
2087 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
2088 NULL, "MTR object meter profile invalid.");
2091 if (priv->policy_idx_tbl) {
2092 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
2093 policy_idx = *(uint32_t *)entry;
2094 sub_policy = mlx5_ipool_get
2095 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
2098 return -rte_mtr_error_set(error,
2100 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2102 "meter policy invalid.");
2103 if (__mlx5_flow_meter_policy_delete(dev, i,
2104 sub_policy->main_policy,
2106 return -rte_mtr_error_set(error,
2108 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2110 "meter policy invalid.");
2111 mlx5_free(sub_policy->main_policy);
2113 mlx5_l3t_destroy(priv->policy_idx_tbl);
2114 priv->policy_idx_tbl = NULL;
2116 if (priv->mtr_profile_tbl) {
2117 MLX5_L3T_FOREACH(priv->mtr_profile_tbl, i, entry) {
2119 if (mlx5_flow_meter_profile_delete(dev, fmp->id,
2121 return -rte_mtr_error_set(error, EINVAL,
2122 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2123 NULL, "Fail to destroy "
2126 mlx5_l3t_destroy(priv->mtr_profile_tbl);
2127 priv->mtr_profile_tbl = NULL;
2129 /* Delete default policy table. */
2130 mlx5_flow_destroy_def_policy(dev);
2131 if (priv->sh->refcnt == 1)
2132 mlx5_flow_destroy_mtr_drop_tbls(dev);