@@ -194,6 +194,8 @@ nfp_flower_pf_close(struct rte_eth_dev *dev)
pf_dev = hw->pf_dev;
app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv);
+ nfp_mtr_priv_uninit(pf_dev);
+
/*
* We assume that the DPDK application is stopping all the
* threads/queues before calling the device close function.
@@ -1097,13 +1099,19 @@ nfp_init_app_fw_flower(struct nfp_pf_dev *pf_dev)
goto app_cleanup;
}
+ ret = nfp_mtr_priv_init(pf_dev);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Error initializing metering private data");
+ goto flow_priv_cleanup;
+ }
+
/* Allocate memory for the PF AND ctrl vNIC here (hence the * 2) */
pf_hw = rte_zmalloc_socket("nfp_pf_vnic", 2 * sizeof(struct nfp_net_adapter),
RTE_CACHE_LINE_SIZE, numa_node);
if (pf_hw == NULL) {
PMD_INIT_LOG(ERR, "Could not malloc nfp pf vnic");
ret = -ENOMEM;
- goto flow_priv_cleanup;
+ goto mtr_priv_cleanup;
}
/* Map the PF ctrl bar */
@@ -1193,6 +1201,8 @@ nfp_init_app_fw_flower(struct nfp_pf_dev *pf_dev)
nfp_cpp_area_free(pf_dev->ctrl_area);
vnic_cleanup:
rte_free(pf_hw);
+mtr_priv_cleanup:
+ nfp_mtr_priv_uninit(pf_dev);
flow_priv_cleanup:
nfp_flow_priv_uninit(pf_dev);
app_cleanup:
@@ -76,6 +76,7 @@ struct nfp_app_fw_flower {
uint64_t ext_features;
struct nfp_flow_priv *flow_priv;
+ struct nfp_mtr_priv *mtr_priv;
};
static inline bool
@@ -467,3 +467,61 @@ nfp_flower_cmsg_tun_mac_rule(struct nfp_app_fw_flower *app_fw_flower,
return 0;
}
+
+int
+nfp_flower_cmsg_qos_add(struct nfp_app_fw_flower *app_fw_flower,
+ struct nfp_profile_conf *conf)
+{
+ char *msg;
+ uint16_t cnt;
+ uint32_t len;
+ struct rte_mbuf *mbuf;
+
+ mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool);
+ if (mbuf == NULL) {
+ PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for qos add");
+ return -ENOMEM;
+ }
+
+ len = sizeof(struct nfp_profile_conf);
+ msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_QOS_MOD, len);
+ rte_memcpy(msg, conf, len);
+
+ cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf);
+ if (cnt == 0) {
+ PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed.");
+ rte_pktmbuf_free(mbuf);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int
+nfp_flower_cmsg_qos_delete(struct nfp_app_fw_flower *app_fw_flower,
+ struct nfp_profile_conf *conf)
+{
+ char *msg;
+ uint16_t cnt;
+ uint32_t len;
+ struct rte_mbuf *mbuf;
+
+ mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool);
+ if (mbuf == NULL) {
+ PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for qos delete");
+ return -ENOMEM;
+ }
+
+ len = sizeof(struct nfp_profile_conf);
+ msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_QOS_DEL, len);
+ rte_memcpy(msg, conf, len);
+
+ cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf);
+ if (cnt == 0) {
+ PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed.");
+ rte_pktmbuf_free(mbuf);
+ return -EIO;
+ }
+
+ return 0;
+}
@@ -9,6 +9,7 @@
#include <rte_byteorder.h>
#include <rte_ether.h>
+#include "../nfp_mtr.h"
#include "../nfp_flow.h"
struct nfp_flower_cmsg_hdr {
@@ -923,5 +924,9 @@ int nfp_flower_cmsg_tun_mac_rule(struct nfp_app_fw_flower *app_fw_flower,
struct rte_ether_addr *mac,
uint16_t mac_idx,
bool is_del);
+int nfp_flower_cmsg_qos_add(struct nfp_app_fw_flower *app_fw_flower,
+ struct nfp_profile_conf *conf);
+int nfp_flower_cmsg_qos_delete(struct nfp_app_fw_flower *app_fw_flower,
+ struct nfp_profile_conf *conf);
#endif /* _NFP_CMSG_H_ */
@@ -553,6 +553,7 @@ static const struct eth_dev_ops nfp_flower_repr_dev_ops = {
.mac_addr_set = nfp_flower_repr_mac_addr_set,
.flow_ops_get = nfp_net_flow_ops_get,
+ .mtr_ops_get = nfp_net_mtr_ops_get,
};
static uint32_t
@@ -28,6 +28,7 @@ sources = files(
'nfp_ethdev_vf.c',
'nfp_ethdev.c',
'nfp_flow.c',
+ 'nfp_mtr.c',
)
deps += ['hash']
new file mode 100644
@@ -0,0 +1,429 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Corigine, Inc.
+ * All rights reserved.
+ */
+
+#include <rte_mtr_driver.h>
+#include <bus_pci_driver.h>
+#include <rte_malloc.h>
+
+#include "nfp_common.h"
+#include "nfp_mtr.h"
+#include "nfp_logs.h"
+#include "flower/nfp_flower.h"
+#include "flower/nfp_flower_cmsg.h"
+#include "flower/nfp_flower_representor.h"
+
+#define NFP_FL_QOS_PPS RTE_BIT32(15)
+#define NFP_FL_QOS_METER RTE_BIT32(10)
+#define NFP_FL_QOS_RFC2697 RTE_BIT32(0)
+
+/**
+ * Callback to get MTR capabilities.
+ *
+ * @param[in] dev
+ * Pointer to the device (unused).
+ * @param[out] cap
+ * Pointer to the meter object capabilities.
+ * @param[out] error
+ * Pointer to the error (unused).
+ *
+ * @returns
+ * 0 on success, a negative value otherwise and rte_errno is set.
+ */
+static int
+nfp_mtr_cap_get(struct rte_eth_dev *dev __rte_unused,
+ struct rte_mtr_capabilities *cap,
+ struct rte_mtr_error *error)
+{
+ if (cap == NULL) {
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL, "NULL pointer for capabilitie argument");
+ }
+
+ memset(cap, 0, sizeof(struct rte_mtr_capabilities));
+
+ cap->n_max = NFP_MAX_MTR_CNT;
+ cap->n_shared_max = NFP_MAX_MTR_CNT;
+ cap->identical = 1;
+ cap->shared_identical = 1;
+ cap->chaining_n_mtrs_per_flow_max = 1;
+ cap->meter_srtcm_rfc2697_n_max = NFP_MAX_MTR_CNT;
+ cap->meter_trtcm_rfc2698_n_max = NFP_MAX_MTR_CNT;
+ cap->meter_rate_max = UINT64_MAX;
+ cap->meter_policy_n_max = NFP_MAX_POLICY_CNT;
+ cap->srtcm_rfc2697_byte_mode_supported = 1;
+ cap->srtcm_rfc2697_packet_mode_supported = 1;
+ cap->trtcm_rfc2698_byte_mode_supported = 1;
+ cap->trtcm_rfc2698_packet_mode_supported = 1;
+ cap->stats_mask = RTE_MTR_STATS_N_PKTS_GREEN |
+ RTE_MTR_STATS_N_PKTS_DROPPED |
+ RTE_MTR_STATS_N_BYTES_GREEN |
+ RTE_MTR_STATS_N_BYTES_DROPPED;
+
+ return 0;
+}
+
+static int
+nfp_mtr_profile_validate(uint32_t mtr_profile_id,
+ struct rte_mtr_meter_profile *profile,
+ struct rte_mtr_error *error)
+{
+ /* Profile must not be NULL. */
+ if (profile == NULL) {
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE,
+ NULL, "Meter profile is null");
+ }
+
+ /* Meter profile ID must be valid. */
+ if (mtr_profile_id >= NFP_MAX_PROFILE_CNT) {
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+ NULL, "Meter profile id not valid");
+ }
+
+ switch (profile->alg) {
+ case RTE_MTR_SRTCM_RFC2697:
+ case RTE_MTR_TRTCM_RFC2698:
+ return 0;
+ case RTE_MTR_TRTCM_RFC4115:
+ return -rte_mtr_error_set(error, ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE,
+ NULL, "Unsupported metering algorithm");
+ default:
+ return -rte_mtr_error_set(error, ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE,
+ NULL, "Unknown metering algorithm");
+ }
+}
+
+static void
+nfp_mtr_profile_config_2698(uint32_t mtr_profile_id,
+ struct rte_mtr_meter_profile *profile,
+ struct nfp_profile_conf *conf)
+{
+ if (profile->packet_mode != 0)
+ conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_PPS);
+
+ conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_METER);
+ conf->head.profile_id = rte_cpu_to_be_32(mtr_profile_id);
+
+ conf->bkt_tkn_c = rte_cpu_to_be_32(profile->trtcm_rfc2698.cbs);
+ conf->bkt_tkn_p = rte_cpu_to_be_32(profile->trtcm_rfc2698.pbs);
+ conf->cbs = rte_cpu_to_be_32(profile->trtcm_rfc2698.cbs);
+ conf->pbs = rte_cpu_to_be_32(profile->trtcm_rfc2698.pbs);
+ conf->cir = rte_cpu_to_be_32(profile->trtcm_rfc2698.cir);
+ conf->pir = rte_cpu_to_be_32(profile->trtcm_rfc2698.pir);
+}
+
+static void
+nfp_mtr_profile_config_2697(uint32_t mtr_profile_id,
+ struct rte_mtr_meter_profile *profile,
+ struct nfp_profile_conf *conf)
+{
+ if (profile->packet_mode != 0)
+ conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_PPS);
+
+ conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_RFC2697);
+ conf->head.flags_opts |= rte_cpu_to_be_32(NFP_FL_QOS_METER);
+ conf->head.profile_id = rte_cpu_to_be_32(mtr_profile_id);
+
+ conf->bkt_tkn_c = rte_cpu_to_be_32(profile->srtcm_rfc2697.cbs);
+ conf->bkt_tkn_p = rte_cpu_to_be_32(profile->srtcm_rfc2697.ebs);
+ conf->cbs = rte_cpu_to_be_32(profile->srtcm_rfc2697.cbs);
+ conf->pbs = rte_cpu_to_be_32(profile->srtcm_rfc2697.ebs);
+ conf->cir = rte_cpu_to_be_32(profile->srtcm_rfc2697.cir);
+ conf->pir = rte_cpu_to_be_32(profile->srtcm_rfc2697.cir);
+}
+
+static int
+nfp_mtr_profile_conf_mod(uint32_t mtr_profile_id,
+ struct rte_mtr_meter_profile *profile,
+ struct nfp_profile_conf *conf)
+{
+ switch (profile->alg) {
+ case RTE_MTR_SRTCM_RFC2697:
+ nfp_mtr_profile_config_2697(mtr_profile_id, profile, conf);
+ return 0;
+ case RTE_MTR_TRTCM_RFC2698:
+ nfp_mtr_profile_config_2698(mtr_profile_id, profile, conf);
+ return 0;
+ case RTE_MTR_TRTCM_RFC4115:
+ return -ENOTSUP;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+nfp_mtr_profile_conf_insert(uint32_t mtr_profile_id,
+ struct rte_mtr_meter_profile *profile,
+ struct nfp_mtr_profile *mtr_profile)
+{
+ mtr_profile->profile_id = mtr_profile_id;
+ mtr_profile->in_use = false;
+
+ return nfp_mtr_profile_conf_mod(mtr_profile_id, profile,
+ &mtr_profile->conf);
+}
+
+static struct nfp_mtr_profile *
+nfp_mtr_profile_search(struct nfp_mtr_priv *priv, uint32_t mtr_profile_id)
+{
+ struct nfp_mtr_profile *mtr_profile;
+
+ LIST_FOREACH(mtr_profile, &priv->profiles, next)
+ if (mtr_profile->profile_id == mtr_profile_id)
+ break;
+
+ return mtr_profile;
+}
+
+static int
+nfp_mtr_profile_insert(struct nfp_app_fw_flower *app_fw_flower,
+ struct rte_mtr_meter_profile *profile,
+ uint32_t mtr_profile_id,
+ struct rte_mtr_error *error)
+{
+ int ret;
+ struct nfp_mtr_priv *priv;
+ struct nfp_mtr_profile *mtr_profile;
+
+ priv = app_fw_flower->mtr_priv;
+
+ /* Meter profile memory allocation. */
+ mtr_profile = rte_zmalloc(NULL, sizeof(struct nfp_mtr_profile), 0);
+ if (mtr_profile == NULL) {
+ return -rte_mtr_error_set(error, ENOMEM,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Meter profile alloc failed");
+ }
+
+ ret = nfp_mtr_profile_conf_insert(mtr_profile_id,
+ profile, mtr_profile);
+ if (ret != 0) {
+ rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Insert profile config failed");
+ goto free_profile;
+ }
+
+ ret = nfp_flower_cmsg_qos_add(app_fw_flower, &mtr_profile->conf);
+ if (ret != 0) {
+ rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Add meter to firmware failed");
+ goto free_profile;
+ }
+
+ /* Insert profile into profile list */
+ LIST_INSERT_HEAD(&priv->profiles, mtr_profile, next);
+
+ return 0;
+
+free_profile:
+ rte_free(mtr_profile);
+
+ return ret;
+}
+
+static int
+nfp_mtr_profile_mod(struct nfp_app_fw_flower *app_fw_flower,
+ struct rte_mtr_meter_profile *profile,
+ struct nfp_mtr_profile *mtr_profile,
+ struct rte_mtr_error *error)
+{
+ int ret;
+ struct nfp_profile_conf old_conf;
+
+ /* Get the old profile config */
+ rte_memcpy(&old_conf, &mtr_profile->conf, sizeof(old_conf));
+
+ ret = nfp_mtr_profile_conf_mod(mtr_profile->profile_id,
+ profile, &mtr_profile->conf);
+ if (ret != 0) {
+ rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Mod profile config failed");
+ goto rollback;
+ }
+
+ ret = nfp_flower_cmsg_qos_add(app_fw_flower, &mtr_profile->conf);
+ if (ret != 0) {
+ rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Mod meter to firmware failed");
+ goto rollback;
+ }
+
+ return 0;
+
+rollback:
+ rte_memcpy(&mtr_profile->conf, &old_conf, sizeof(old_conf));
+
+ return ret;
+}
+
+/**
+ * Callback to add MTR profile.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] mtr_profile_id
+ * Meter profile id.
+ * @param[in] profile
+ * Pointer to meter profile detail.
+ * @param[out] error
+ * Pointer to the error structure.
+ *
+ * @return
+ * 0 on success, a negative value otherwise and rte_errno is set.
+ */
+static int
+nfp_mtr_profile_add(struct rte_eth_dev *dev,
+ uint32_t mtr_profile_id,
+ struct rte_mtr_meter_profile *profile,
+ struct rte_mtr_error *error)
+{
+ int ret;
+ struct nfp_mtr_priv *priv;
+ struct nfp_mtr_profile *mtr_profile;
+ struct nfp_app_fw_flower *app_fw_flower;
+ struct nfp_flower_representor *representor;
+
+ representor = dev->data->dev_private;
+ app_fw_flower = representor->app_fw_flower;
+ priv = app_fw_flower->mtr_priv;
+
+ /* Check input params */
+ ret = nfp_mtr_profile_validate(mtr_profile_id, profile, error);
+ if (ret != 0)
+ return ret;
+
+ /* Check if mtr profile id exist */
+ mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id);
+ if (mtr_profile == NULL) {
+ ret = nfp_mtr_profile_insert(app_fw_flower,
+ profile, mtr_profile_id, error);
+ } else {
+ ret = nfp_mtr_profile_mod(app_fw_flower,
+ profile, mtr_profile, error);
+ }
+
+ return ret;
+}
+
+/**
+ * Callback to delete MTR profile.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] mtr_profile_id
+ * Meter profile id.
+ * @param[out] error
+ * Pointer to the error structure.
+ *
+ * @return
+ * 0 on success, a negative value otherwise and rte_errno is set.
+ */
+static int
+nfp_mtr_profile_delete(struct rte_eth_dev *dev,
+ uint32_t mtr_profile_id,
+ struct rte_mtr_error *error)
+{
+ int ret;
+ struct nfp_mtr_priv *priv;
+ struct nfp_mtr_profile *mtr_profile;
+ struct nfp_app_fw_flower *app_fw_flower;
+ struct nfp_flower_representor *representor;
+
+ representor = dev->data->dev_private;
+ app_fw_flower = representor->app_fw_flower;
+ priv = app_fw_flower->mtr_priv;
+
+ /* Check if mtr profile id exist */
+ mtr_profile = nfp_mtr_profile_search(priv, mtr_profile_id);
+ if (mtr_profile == NULL) {
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+ NULL, "Request meter profile not exist");
+ }
+
+ if (mtr_profile->in_use) {
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE,
+ NULL, "Request meter profile is been used");
+ }
+
+ ret = nfp_flower_cmsg_qos_delete(app_fw_flower, &mtr_profile->conf);
+ if (ret != 0) {
+ return -rte_mtr_error_set(error, EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Delete meter from firmware failed");
+ }
+
+ /* Remove profile from profile list */
+ LIST_REMOVE(mtr_profile, next);
+ rte_free(mtr_profile);
+
+ return 0;
+}
+
+static const struct rte_mtr_ops nfp_mtr_ops = {
+ .capabilities_get = nfp_mtr_cap_get,
+ .meter_profile_add = nfp_mtr_profile_add,
+ .meter_profile_delete = nfp_mtr_profile_delete,
+};
+
+int
+nfp_net_mtr_ops_get(struct rte_eth_dev *dev, void *arg)
+{
+ if ((dev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR) == 0) {
+ PMD_DRV_LOG(ERR, "Port is not a representor");
+ return -EINVAL;
+ }
+
+ *(const struct rte_mtr_ops **)arg = &nfp_mtr_ops;
+
+ return 0;
+}
+
+int
+nfp_mtr_priv_init(struct nfp_pf_dev *pf_dev)
+{
+ struct nfp_mtr_priv *priv;
+ struct nfp_app_fw_flower *app_fw_flower;
+
+ priv = rte_zmalloc("nfp_app_mtr_priv", sizeof(struct nfp_mtr_priv), 0);
+ if (priv == NULL) {
+ PMD_INIT_LOG(ERR, "nfp app mtr priv creation failed");
+ return -ENOMEM;
+ }
+
+ app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv);
+ app_fw_flower->mtr_priv = priv;
+
+ LIST_INIT(&priv->profiles);
+
+ return 0;
+}
+
+void
+nfp_mtr_priv_uninit(struct nfp_pf_dev *pf_dev)
+{
+ struct nfp_mtr_priv *priv;
+ struct nfp_mtr_profile *mtr_profile;
+ struct nfp_app_fw_flower *app_fw_flower;
+
+ app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv);
+ priv = app_fw_flower->mtr_priv;
+
+ LIST_FOREACH(mtr_profile, &priv->profiles, next) {
+ LIST_REMOVE(mtr_profile, next);
+ rte_free(mtr_profile);
+ }
+
+ rte_free(priv);
+}
new file mode 100644
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Corigine, Inc.
+ * All rights reserved.
+ */
+
+#ifndef __NFP_MTR_H__
+#define __NFP_MTR_H__
+
+/**
+ * The max meter count is determined by firmware.
+ * The max count is 65536 defined by OF_METER_COUNT.
+ */
+#define NFP_MAX_MTR_CNT 65536
+#define NFP_MAX_POLICY_CNT NFP_MAX_MTR_CNT
+#define NFP_MAX_PROFILE_CNT NFP_MAX_MTR_CNT
+
+/**
+ * See RFC 2698 for more details.
+ * Word[0](Flag options):
+ * [15] p(pps) 1 for pps, 0 for bps
+ *
+ * Meter control message
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------------------------------+-+---+-----+-+---------+-+---+-+
+ * | Reserved |p| Y |TYPE |E| TSHFV |P| PC|R|
+ * +-------------------------------+-+---+-----+-+---------+-+---+-+
+ * | Profile ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Token Bucket Peak |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Token Bucket Committed |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Peak Burst Size |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Committed Burst Size |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Peak Information Rate |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Committed Information Rate |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_cfg_head {
+ rte_be32_t flags_opts;
+ rte_be32_t profile_id;
+};
+
+/**
+ * Struct nfp_profile_conf - profile config, offload to NIC
+ * @head: config head information
+ * @bkt_tkn_p: token bucket peak
+ * @bkt_tkn_c: token bucket committed
+ * @pbs: peak burst size
+ * @cbs: committed burst size
+ * @pir: peak information rate
+ * @cir: committed information rate
+ */
+struct nfp_profile_conf {
+ struct nfp_cfg_head head;
+ rte_be32_t bkt_tkn_p;
+ rte_be32_t bkt_tkn_c;
+ rte_be32_t pbs;
+ rte_be32_t cbs;
+ rte_be32_t pir;
+ rte_be32_t cir;
+};
+
+/**
+ * Struct nfp_mtr_profile - meter profile, stored in driver
+ * Can only be used by one meter
+ * @next: next meter profile object
+ * @profile_id: meter profile id
+ * @conf: meter profile config
+ * @in_use: if profile is been used by meter
+ */
+struct nfp_mtr_profile {
+ LIST_ENTRY(nfp_mtr_profile) next;
+ uint32_t profile_id;
+ struct nfp_profile_conf conf;
+ bool in_use;
+};
+
+/**
+ * Struct nfp_mtr_priv - meter private data
+ * @profiles: the head node of profile list
+ */
+struct nfp_mtr_priv {
+ LIST_HEAD(, nfp_mtr_profile) profiles;
+};
+
+int nfp_net_mtr_ops_get(struct rte_eth_dev *dev, void *arg);
+int nfp_mtr_priv_init(struct nfp_pf_dev *pf_dev);
+void nfp_mtr_priv_uninit(struct nfp_pf_dev *pf_dev);
+
+#endif /* __NFP_MTR_H__ */