From: Gagandeep Singh <[email protected]>

Add support for the traffic metering and policing (rte_mtr) API to
the dpaa2 PMD. The implementation registers the rte_mtr operations
through the ".mtr_ops_get" dev_ops hook and maintains software
bookkeeping of meter profiles, policies and meter objects under a
per-device spinlock.

Supported algorithms are trTCM RFC 2698 and trTCM RFC 4115 in both
byte and packet modes. Meter policies support drop and pass-through
actions on the red color.

Signed-off-by: Gagandeep Singh <[email protected]>
---
 drivers/net/dpaa2/dpaa2_ethdev.c |   1 +
 drivers/net/dpaa2/dpaa2_ethdev.h |  29 ++
 drivers/net/dpaa2/dpaa2_meter.c  | 588 +++++++++++++++++++++++++++++++
 drivers/net/dpaa2/mc/fsl_dpni.h  |  23 +-
 drivers/net/dpaa2/meson.build    |   1 +
 5 files changed, 638 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/dpaa2/dpaa2_meter.c

diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index d79dfa7114..c8abab830f 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -3322,6 +3322,7 @@ static struct eth_dev_ops dpaa2_ethdev_ops = {
        .rxq_info_get         = dpaa2_rxq_info_get,
        .txq_info_get         = dpaa2_txq_info_get,
        .tm_ops_get           = dpaa2_tm_ops_get,
+       .mtr_ops_get          = dpaa2_mtr_ops_get,
 #if defined(RTE_LIBRTE_IEEE1588)
        .timesync_enable      = dpaa2_timesync_enable,
        .timesync_disable     = dpaa2_timesync_disable,
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.h b/drivers/net/dpaa2/dpaa2_ethdev.h
index 0366315ec7..c5aac65c28 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.h
+++ b/drivers/net/dpaa2/dpaa2_ethdev.h
@@ -385,6 +385,30 @@ struct extract_s {
        uint8_t *tc_extract_param[MAX_TCS];
 };
 
+struct dpaa2_dev_meter_profile {
+       LIST_ENTRY(dpaa2_dev_meter_profile) next;
+       uint32_t profile_id;
+       uint64_t cir;
+       uint64_t cbs;
+       uint64_t pir;
+       uint64_t pbs;
+       enum dpni_policer_mode mode;
+       enum dpni_policer_unit policer_unit;
+};
+
+struct dpaa2_dev_meter_policy {
+       LIST_ENTRY(dpaa2_dev_meter_policy) next;
+       uint32_t policy_id;
+       int red_drop;
+};
+
+struct dpaa2_dev_meter {
+       LIST_ENTRY(dpaa2_dev_meter) next;
+       uint32_t meter_id;
+       uint32_t profile_id;
+       uint32_t policy_id;
+};
+
 struct dpaa2_dev_priv {
        void *hw;
        int32_t hw_id;
@@ -412,6 +436,7 @@ struct dpaa2_dev_priv {
        uint8_t en_loose_ordered;
        uint8_t max_cgs;
        uint8_t cgid_in_use[MAX_RX_QUEUES];
+       rte_spinlock_t meter_lock;
 
        /* Current hash distribution size per RX TC, written by
         * dpaa2_setup_flow_dist_size() and read by reta_query / reta_update.
@@ -457,6 +482,9 @@ struct dpaa2_dev_priv {
 
        struct dpaa2_dev_flow *curr;
        LIST_HEAD(, dpaa2_dev_flow) flows;
+       LIST_HEAD(, dpaa2_dev_meter_profile) profiles;
+       LIST_HEAD(, dpaa2_dev_meter_policy) policies;
+       LIST_HEAD(, dpaa2_dev_meter) meters;
        LIST_HEAD(nodes, dpaa2_tm_node) nodes;
        LIST_HEAD(shaper_profiles, dpaa2_tm_shaper_profile) shaper_profiles;
 };
@@ -549,6 +577,7 @@ int dpaa2_timesync_read_tx_timestamp(struct rte_eth_dev 
*dev,
 
 int dpaa2_dev_recycle_config(struct rte_eth_dev *eth_dev);
 int dpaa2_dev_recycle_deconfig(struct rte_eth_dev *eth_dev);
+int dpaa2_mtr_ops_get(struct rte_eth_dev *dev, void *ops);
 int dpaa2_soft_parser_loaded(void);
 
 void
diff --git a/drivers/net/dpaa2/dpaa2_meter.c b/drivers/net/dpaa2/dpaa2_meter.c
new file mode 100644
index 0000000000..aae88a4d4b
--- /dev/null
+++ b/drivers/net/dpaa2/dpaa2_meter.c
@@ -0,0 +1,588 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2025-2026 NXP
+ */
+
+#include <sys/queue.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_flow_driver.h>
+#include <rte_tailq.h>
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
+
+#include <fsl_dpni.h>
+#include <fsl_dpkg.h>
+
+#include <dpaa2_ethdev.h>
+#include <dpaa2_pmd_logs.h>
+
+static char s_err_msg[128];
+
+static struct rte_mtr_capabilities s_dpaa2_mtr_capa = {
+       .color_aware_trtcm_rfc2698_supported = true,
+       .color_aware_trtcm_rfc4115_supported = true,
+       .trtcm_rfc2698_byte_mode_supported = true,
+       .trtcm_rfc2698_packet_mode_supported = true,
+       .trtcm_rfc4115_byte_mode_supported = true,
+       .trtcm_rfc4115_packet_mode_supported = true
+};
+
+static int
+dpaa2_mtr_capabilities_get(struct rte_eth_dev *dev,
+       struct rte_mtr_capabilities *capa,
+       struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+
+       if (capa == NULL) {
+               return -rte_mtr_error_set(error, EINVAL,
+                               RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+                               "NULL input parameter");
+       }
+
+       rte_spinlock_lock(&priv->meter_lock);
+       s_dpaa2_mtr_capa.n_max = priv->num_rx_tc;
+       s_dpaa2_mtr_capa.n_shared_max = priv->num_rx_tc;
+       s_dpaa2_mtr_capa.meter_trtcm_rfc2698_n_max = priv->num_rx_tc;
+       s_dpaa2_mtr_capa.meter_trtcm_rfc4115_n_max = priv->num_rx_tc;
+       s_dpaa2_mtr_capa.meter_policy_n_max = priv->num_rx_tc;
+       s_dpaa2_mtr_capa.shared_n_flows_per_mtr_max = priv->fs_entries;
+       rte_spinlock_unlock(&priv->meter_lock);
+
+       *capa = s_dpaa2_mtr_capa;
+
+       return 0;
+}
+
+static int
+dpaa2_mtr_profile_add(struct rte_eth_dev *dev,
+       uint32_t profile_id, struct rte_mtr_meter_profile *profile,
+       struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_profile *dpaa2_profile;
+       struct dpaa2_dev_meter_profile *curr;
+       int ret = 0;
+
+       dpaa2_profile = rte_zmalloc(NULL,
+               sizeof(struct dpaa2_dev_meter_profile), 0);
+       if (dpaa2_profile == NULL) {
+               return -rte_mtr_error_set(error, ENOMEM,
+                               RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+                               "Meter profile memory alloc failed!");
+       }
+       if (profile->alg == RTE_MTR_NONE) {
+               dpaa2_profile->mode = DPNI_POLICER_MODE_PASS_THROUGH;
+       } else if (profile->alg == RTE_MTR_TRTCM_RFC2698) {
+               dpaa2_profile->mode = DPNI_POLICER_MODE_RFC_2698;
+       } else if (profile->alg == RTE_MTR_TRTCM_RFC4115) {
+               dpaa2_profile->mode = DPNI_POLICER_MODE_RFC_4115;
+       } else {
+               DPAA2_PMD_ERR("Policer profile alg(%d) not supported!",
+                       profile->alg);
+               ret = -ENOTSUP;
+               goto err;
+       }
+
+       if (profile->alg == RTE_MTR_TRTCM_RFC2698) {
+               dpaa2_profile->cir = profile->trtcm_rfc2698.cir;
+               dpaa2_profile->cbs = profile->trtcm_rfc2698.cbs;
+               dpaa2_profile->pir = profile->trtcm_rfc2698.pir;
+               dpaa2_profile->pbs = profile->trtcm_rfc2698.pbs;
+       } else if (profile->alg == RTE_MTR_TRTCM_RFC4115) {
+               dpaa2_profile->cir = profile->trtcm_rfc4115.cir;
+               dpaa2_profile->cbs = profile->trtcm_rfc4115.cbs;
+               dpaa2_profile->pir = profile->trtcm_rfc4115.eir;
+               dpaa2_profile->pbs = profile->trtcm_rfc4115.ebs;
+       }
+
+       /** Align with DPNI policy.*/
+       if (!profile->packet_mode) {
+               dpaa2_profile->policer_unit = DPNI_POLICER_UNIT_BYTES_L3;
+       } else if (profile->packet_mode > DPNI_POLICER_UNIT_FRAMES) {
+               dpaa2_profile->policer_unit =
+                       DPNI_POLICER_UNIT_BYTES_L2_WITHOUT_FCS;
+       } else {
+               dpaa2_profile->policer_unit = DPNI_POLICER_UNIT_FRAMES;
+       }
+
+       dpaa2_profile->profile_id = profile_id;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       curr = LIST_FIRST(&priv->profiles);
+       if (curr == NULL) {
+               LIST_INSERT_HEAD(&priv->profiles, dpaa2_profile, next);
+       } else {
+               while (LIST_NEXT(curr, next) != NULL)
+                       curr = LIST_NEXT(curr, next);
+               LIST_INSERT_AFTER(curr, dpaa2_profile, next);
+       }
+       rte_spinlock_unlock(&priv->meter_lock);
+
+err:
+       if (ret != 0)
+               rte_free(dpaa2_profile);
+
+       return ret;
+}
+
+static int
+dpaa2_mtr_policy_add(struct rte_eth_dev *dev,
+       uint32_t policy_id, struct rte_mtr_meter_policy_params *policy,
+       struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_policy *dpaa2_policy;
+       struct dpaa2_dev_meter_policy *curr;
+       const struct rte_flow_action *red_action;
+       bool red_drop = false;
+
+       if (policy->actions[RTE_COLOR_GREEN] != NULL) {
+               return -rte_mtr_error_set(error, ENOMEM,
+                               RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN, NULL,
+                               "Meter green policy action not supported!");
+       }
+       if (policy->actions[RTE_COLOR_YELLOW] != NULL) {
+               return -rte_mtr_error_set(error, ENOMEM,
+                               RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW, NULL,
+                               "Meter yellow policy action not supported!");
+       }
+
+       red_action = policy->actions[RTE_COLOR_RED];
+
+       if (red_action != NULL) {
+               if (red_action->type == RTE_FLOW_ACTION_TYPE_DROP) {
+                       red_drop = true;
+               } else if (red_action->type != RTE_FLOW_ACTION_TYPE_PASSTHRU) {
+                       snprintf(s_err_msg, sizeof(s_err_msg),
+                               "Meter red policy action(%d) NOT supported!",
+                               red_action->type);
+                       return -rte_mtr_error_set(error, ENOMEM,
+                               RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED, NULL,
+                               s_err_msg);
+               }
+       }
+
+       dpaa2_policy = rte_zmalloc(NULL,
+               sizeof(struct dpaa2_dev_meter_policy), 0);
+       if (dpaa2_policy == NULL) {
+               return -rte_mtr_error_set(error, ENOMEM,
+                               RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+                               "Meter policy memory alloc failed!");
+       }
+
+       dpaa2_policy->policy_id = policy_id;
+       dpaa2_policy->red_drop = red_drop;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       curr = LIST_FIRST(&priv->policies);
+       if (curr == NULL) {
+               LIST_INSERT_HEAD(&priv->policies, dpaa2_policy, next);
+       } else {
+               while (LIST_NEXT(curr, next) != NULL)
+                       curr = LIST_NEXT(curr, next);
+               LIST_INSERT_AFTER(curr, dpaa2_policy, next);
+       }
+       rte_spinlock_unlock(&priv->meter_lock);
+
+       return 0;
+}
+
+static struct rte_flow_meter_profile *
+dpaa2_mtr_profile_get(struct rte_eth_dev *dev,
+       uint32_t meter_profile_id, struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_profile *dpaa2_profile;
+
+       RTE_SET_USED(error);
+
+       rte_spinlock_lock(&priv->meter_lock);
+       dpaa2_profile = LIST_FIRST(&priv->profiles);
+       while (dpaa2_profile != NULL) {
+               if (dpaa2_profile->profile_id == meter_profile_id) {
+                       rte_spinlock_unlock(&priv->meter_lock);
+                       return (struct rte_flow_meter_profile *)dpaa2_profile;
+               }
+               dpaa2_profile = LIST_NEXT(dpaa2_profile, next);
+       }
+       rte_spinlock_unlock(&priv->meter_lock);
+
+       return NULL;
+}
+
+static struct rte_flow_meter_policy *
+dpaa2_mtr_policy_get(struct rte_eth_dev *dev,
+       uint32_t policy_id, struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_policy *dpaa2_policy;
+
+       RTE_SET_USED(error);
+
+       rte_spinlock_lock(&priv->meter_lock);
+       dpaa2_policy = LIST_FIRST(&priv->policies);
+       while (dpaa2_policy != NULL) {
+               if (dpaa2_policy->policy_id == policy_id) {
+                       rte_spinlock_unlock(&priv->meter_lock);
+                       return (struct rte_flow_meter_policy *)dpaa2_policy;
+               }
+               dpaa2_policy = LIST_NEXT(dpaa2_policy, next);
+       }
+       rte_spinlock_unlock(&priv->meter_lock);
+
+       return NULL;
+}
+
+static int
+dpaa2_mtr_profile_delete(struct rte_eth_dev *dev,
+       uint32_t profile_id, struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_profile *dpaa2_profile = NULL, *curr;
+       struct dpaa2_dev_meter *meter, *tmp;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       curr = LIST_FIRST(&priv->profiles);
+       while (curr != NULL) {
+               if (curr->profile_id == profile_id) {
+                       dpaa2_profile = curr;
+                       break;
+               }
+               curr = LIST_NEXT(curr, next);
+       }
+       if (dpaa2_profile == NULL) {
+               rte_spinlock_unlock(&priv->meter_lock);
+               return -rte_mtr_error_set(error, ENOENT,
+                       RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+                       &profile_id, "Meter profile is invalid.");
+       }
+
+       meter = LIST_FIRST(&priv->meters);
+       while (meter != NULL) {
+               if (meter->profile_id == profile_id) {
+                       DPAA2_PMD_INFO("Meter(id=%d) with profile(%d) is 
removed!",
+                               meter->meter_id, profile_id);
+                       tmp = meter;
+                       meter = LIST_NEXT(meter, next);
+                       LIST_REMOVE(tmp, next);
+                       rte_free(tmp);
+               } else {
+                       meter = LIST_NEXT(meter, next);
+               }
+       }
+
+       LIST_REMOVE(dpaa2_profile, next);
+       rte_free(dpaa2_profile);
+       rte_spinlock_unlock(&priv->meter_lock);
+
+       return 0;
+}
+
+static int
+dpaa2_mtr_policy_delete(struct rte_eth_dev *dev,
+       uint32_t policy_id, struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_policy *dpaa2_policy = NULL, *curr;
+       struct dpaa2_dev_meter *meter, *tmp;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       curr = LIST_FIRST(&priv->policies);
+       while (curr != NULL) {
+               if (curr->policy_id == policy_id) {
+                       dpaa2_policy = curr;
+                       break;
+               }
+               curr = LIST_NEXT(curr, next);
+       }
+       if (dpaa2_policy == NULL) {
+               rte_spinlock_unlock(&priv->meter_lock);
+               return -rte_mtr_error_set(error, ENOENT,
+                       RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+                       NULL, "Meter policy is invalid.");
+       }
+
+       meter = LIST_FIRST(&priv->meters);
+       while (meter != NULL) {
+               if (meter->policy_id == policy_id) {
+                       DPAA2_PMD_INFO("Meter(id=%d) with policy(%d) is 
removed!",
+                               meter->meter_id, policy_id);
+                       tmp = meter;
+                       meter = LIST_NEXT(meter, next);
+                       LIST_REMOVE(tmp, next);
+                       rte_free(tmp);
+               } else {
+                       meter = LIST_NEXT(meter, next);
+               }
+       }
+
+       LIST_REMOVE(dpaa2_policy, next);
+       rte_free(dpaa2_policy);
+       rte_spinlock_unlock(&priv->meter_lock);
+
+       return 0;
+}
+
+static int
+dpaa2_mtr_meter_create(struct rte_eth_dev *dev,
+       uint32_t mtr_id, struct rte_mtr_params *params,
+       int shared, struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_profile *profile;
+       struct dpaa2_dev_meter_policy *policy;
+       struct dpaa2_dev_meter *meter, *curr;
+       uint32_t profile_id, policy_id;
+       enum rte_mtr_error_type err_type = RTE_MTR_ERROR_TYPE_NONE;
+       bool found = false;
+       int ret = 0;
+
+       RTE_SET_USED(shared);
+       profile_id = params->meter_profile_id;
+       policy_id = params->meter_policy_id;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       profile = LIST_FIRST(&priv->profiles);
+       while (profile != NULL) {
+               if (profile->profile_id == profile_id) {
+                       found = true;
+                       break;
+               }
+               profile = LIST_NEXT(profile, next);
+       }
+       if (!found) {
+               snprintf(s_err_msg, sizeof(s_err_msg),
+                       "Meter profile ID(%d) not exist!", profile_id);
+               ret = ENOENT;
+               err_type = RTE_MTR_ERROR_TYPE_METER_PROFILE_ID;
+               goto quit;
+       }
+
+       found = false;
+       policy = LIST_FIRST(&priv->policies);
+       while (policy != NULL) {
+               if (policy->policy_id == policy_id) {
+                       found = true;
+                       break;
+               }
+               policy = LIST_NEXT(policy, next);
+       }
+       if (!found) {
+               snprintf(s_err_msg, sizeof(s_err_msg),
+                       "Meter policy ID(%d) not exist!", policy_id);
+               ret = ENOENT;
+               err_type = RTE_MTR_ERROR_TYPE_METER_POLICY_ID;
+               goto quit;
+       }
+
+       meter = LIST_FIRST(&priv->meters);
+       while (meter != NULL) {
+               if (meter->meter_id == mtr_id) {
+                       snprintf(s_err_msg, sizeof(s_err_msg),
+                               "Meter ID(%d) exist!", mtr_id);
+                       ret = EEXIST;
+                       err_type = RTE_MTR_ERROR_TYPE_MTR_ID;
+                       goto quit;
+               }
+               meter = LIST_NEXT(meter, next);
+       }
+       meter = rte_zmalloc(NULL, sizeof(struct dpaa2_dev_meter), 0);
+       if (meter == NULL) {
+               snprintf(s_err_msg, sizeof(s_err_msg),
+                       "Meter memory alloc failed!");
+               ret = ENOMEM;
+               err_type = RTE_MTR_ERROR_TYPE_UNSPECIFIED;
+               goto quit;
+       }
+       meter->meter_id = mtr_id;
+       meter->profile_id = profile_id;
+       meter->policy_id = policy_id;
+
+       curr = LIST_FIRST(&priv->meters);
+       if (curr == NULL) {
+               LIST_INSERT_HEAD(&priv->meters, meter, next);
+       } else {
+               while (LIST_NEXT(curr, next) != NULL)
+                       curr = LIST_NEXT(curr, next);
+               LIST_INSERT_AFTER(curr, meter, next);
+       }
+
+quit:
+       rte_spinlock_unlock(&priv->meter_lock);
+       if (ret != 0)
+               return -rte_mtr_error_set(error, ret, err_type, NULL, 
s_err_msg);
+
+       return 0;
+}
+
+static int
+dpaa2_mtr_meter_destroy(struct rte_eth_dev *dev,
+       uint32_t mtr_id, struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter *meter;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       meter = LIST_FIRST(&priv->meters);
+       while (meter != NULL) {
+               if (meter->meter_id == mtr_id) {
+                       LIST_REMOVE(meter, next);
+                       rte_free(meter);
+                       rte_spinlock_unlock(&priv->meter_lock);
+
+                       return 0;
+               }
+               meter = LIST_NEXT(meter, next);
+       }
+       snprintf(s_err_msg, sizeof(s_err_msg),
+               "Meter ID(%d) does not exist!", mtr_id);
+       rte_spinlock_unlock(&priv->meter_lock);
+       return -rte_mtr_error_set(error, ENOENT,
+               RTE_MTR_ERROR_TYPE_MTR_ID, NULL, s_err_msg);
+}
+
+static int
+dpaa2_mtr_meter_profile_update(struct rte_eth_dev *dev,
+       uint32_t mtr_id, uint32_t profile_id,
+       struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_profile *profile;
+       struct dpaa2_dev_meter *meter;
+       enum rte_mtr_error_type err_type = RTE_MTR_ERROR_TYPE_NONE;
+       bool found = false;
+       int ret = 0;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       meter = LIST_FIRST(&priv->meters);
+       while (meter != NULL) {
+               if (meter->meter_id == mtr_id) {
+                       found = true;
+                       break;
+               }
+               meter = LIST_NEXT(meter, next);
+       }
+       if (!found) {
+               snprintf(s_err_msg, sizeof(s_err_msg),
+                       "Meter ID(%d) not found!", mtr_id);
+               ret = ENOENT;
+               err_type = RTE_MTR_ERROR_TYPE_MTR_ID;
+               goto quit;
+       }
+
+       found = false;
+       profile = LIST_FIRST(&priv->profiles);
+       while (profile != NULL) {
+               if (profile->profile_id == profile_id) {
+                       found = true;
+                       break;
+               }
+               profile = LIST_NEXT(profile, next);
+       }
+       if (!found) {
+               snprintf(s_err_msg, sizeof(s_err_msg),
+                       "Profile ID(%d) not found!", profile_id);
+               ret = ENOENT;
+               err_type = RTE_MTR_ERROR_TYPE_METER_PROFILE_ID;
+               goto quit;
+       }
+       meter->profile_id = profile_id;
+
+quit:
+       rte_spinlock_unlock(&priv->meter_lock);
+       if (ret != 0)
+               return -rte_mtr_error_set(error, ret, err_type, NULL, 
s_err_msg);
+
+       return 0;
+}
+
+static int
+dpaa2_mtr_meter_policy_update(struct rte_eth_dev *dev,
+       uint32_t mtr_id, uint32_t policy_id,
+       struct rte_mtr_error *error)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct dpaa2_dev_meter_policy *policy;
+       struct dpaa2_dev_meter *meter;
+       enum rte_mtr_error_type err_type = RTE_MTR_ERROR_TYPE_NONE;
+       bool found = false;
+       int ret = 0;
+
+       rte_spinlock_lock(&priv->meter_lock);
+       meter = LIST_FIRST(&priv->meters);
+       while (meter != NULL) {
+               if (meter->meter_id == mtr_id) {
+                       found = true;
+                       break;
+               }
+               meter = LIST_NEXT(meter, next);
+       }
+       if (!found) {
+               snprintf(s_err_msg, sizeof(s_err_msg),
+                       "Meter ID(%d) not found!", mtr_id);
+               ret = ENOENT;
+               err_type = RTE_MTR_ERROR_TYPE_MTR_ID;
+               goto quit;
+       }
+
+       found = false;
+       policy = LIST_FIRST(&priv->policies);
+       while (policy != NULL) {
+               if (policy->policy_id == policy_id) {
+                       found = true;
+                       break;
+               }
+               policy = LIST_NEXT(policy, next);
+       }
+       if (!found) {
+               snprintf(s_err_msg, sizeof(s_err_msg),
+                       "Profile ID(%d) not found!", policy_id);
+               ret = ENOENT;
+               err_type = RTE_MTR_ERROR_TYPE_METER_POLICY_ID;
+               goto quit;
+       }
+       meter->policy_id = policy_id;
+
+quit:
+       rte_spinlock_unlock(&priv->meter_lock);
+       if (ret != 0)
+               return -rte_mtr_error_set(error, ret, err_type, NULL, 
s_err_msg);
+
+       return 0;
+}
+
+static const struct rte_mtr_ops dpaa2_meter_ops = {
+       .capabilities_get = dpaa2_mtr_capabilities_get,
+       .meter_profile_add = dpaa2_mtr_profile_add,
+       .meter_profile_delete = dpaa2_mtr_profile_delete,
+       .meter_policy_add = dpaa2_mtr_policy_add,
+       .meter_policy_delete = dpaa2_mtr_policy_delete,
+       .meter_profile_get = dpaa2_mtr_profile_get,
+       .meter_policy_get = dpaa2_mtr_policy_get,
+       .create = dpaa2_mtr_meter_create,
+       .destroy = dpaa2_mtr_meter_destroy,
+       .meter_profile_update = dpaa2_mtr_meter_profile_update,
+       .meter_policy_update = dpaa2_mtr_meter_policy_update,
+};
+
+int
+dpaa2_mtr_ops_get(struct rte_eth_dev *dev, void *ops)
+{
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+
+       rte_spinlock_init(&priv->meter_lock);
+
+       *(const void **)ops = &dpaa2_meter_ops;
+       return 0;
+}
diff --git a/drivers/net/dpaa2/mc/fsl_dpni.h b/drivers/net/dpaa2/mc/fsl_dpni.h
index 8913b408e7..d227025e01 100644
--- a/drivers/net/dpaa2/mc/fsl_dpni.h
+++ b/drivers/net/dpaa2/mc/fsl_dpni.h
@@ -1111,6 +1111,11 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io,
  */
 #define DPNI_POLICER_OPT_DISCARD_RED   0x00000002
 
+/**
+ * Do NOT reset counters generally for policer update
+ */
+#define DPNI_POLICER_OPT_DO_NOT_RESET_COUNTERS 0x00000004
+
 /**
  * enum dpni_policer_mode - selecting the policer mode
  * @DPNI_POLICER_MODE_NONE: Policer is disabled
@@ -1127,12 +1132,17 @@ enum dpni_policer_mode {
 
 /**
  * enum dpni_policer_unit - DPNI policer units
- * @DPNI_POLICER_UNIT_BYTES: bytes units
+ * @DPNI_POLICER_UNIT_BYTES_L3: bytes units (for each frame takes into account
+ * FD length - L3 offset)
  * @DPNI_POLICER_UNIT_FRAMES: frames units
+ * @DPNI_POLICER_UNIT_BYTES_L2_WITHOUT_FCS: bytes units (for each frame takes
+ * into account FD length - L2 offset, which means L2 size without the 4 bytes
+ * for the FCS)
  */
 enum dpni_policer_unit {
-       DPNI_POLICER_UNIT_BYTES = 0,
-       DPNI_POLICER_UNIT_FRAMES
+       DPNI_POLICER_UNIT_BYTES_L3 = 0,
+       DPNI_POLICER_UNIT_FRAMES,
+       DPNI_POLICER_UNIT_BYTES_L2_WITHOUT_FCS,
 };
 
 /**
@@ -1173,13 +1183,18 @@ struct dpni_rx_tc_policing_cfg {
        uint32_t ebs;
 };
 
-
 int dpni_set_rx_tc_policing(struct fsl_mc_io *mc_io,
                            uint32_t cmd_flags,
                            uint16_t token,
                            uint8_t tc_id,
                            const struct dpni_rx_tc_policing_cfg *cfg);
 
+int dpni_set_rx_tc_policing_v1(struct fsl_mc_io *mc_io,
+                           uint32_t cmd_flags,
+                           uint16_t token,
+                           uint8_t tc_id,
+                           const struct dpni_rx_tc_policing_cfg *cfg);
+
 int dpni_get_rx_tc_policing(struct fsl_mc_io *mc_io,
                            uint32_t cmd_flags,
                            uint16_t token,
diff --git a/drivers/net/dpaa2/meson.build b/drivers/net/dpaa2/meson.build
index 4094ea02ba..808dad8112 100644
--- a/drivers/net/dpaa2/meson.build
+++ b/drivers/net/dpaa2/meson.build
@@ -11,6 +11,7 @@ sources = files(
         'base/dpaa2_hw_dpni.c',
         'base/dpaa2_tlu_hash.c',
         'dpaa2_tm.c',
+        'dpaa2_meter.c',
         'dpaa2_mux.c',
         'dpaa2_ethdev.c',
         'dpaa2_flow.c',
-- 
2.43.0

Reply via email to