[5/6] net/nfp: add meter stats options

Message ID 20221207021748.40143-6-chaoyong.he@corigine.com (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers
Series add offload support of meter for NFP cards |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Chaoyong He Dec. 7, 2022, 2:17 a.m. UTC
  From: Jin Liu <jin.liu@corigine.com>

Add support for meter stats mask feature, it indicate what type
meter stats that NFP card support.

Add function of update meter stats mask, it will change the stats
mask used by the meter to another.

Add function of read meter stats, get the meter stats that stored
in driver.

Signed-off-by: Jin Liu <jin.liu@corigine.com>
Signed-off-by: Peng Zhang <peng.zhang@corigine.com>
Reviewed-by: Chaoyong He <chaoyong.he@corigine.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@corigine.com>
---
 doc/guides/rel_notes/release_23_03.rst   |   3 +
 drivers/net/nfp/flower/nfp_flower_cmsg.c |  29 ++++
 drivers/net/nfp/flower/nfp_flower_cmsg.h |   2 +
 drivers/net/nfp/flower/nfp_flower_ctrl.c |  57 +++++++-
 drivers/net/nfp/nfp_mtr.c                | 164 ++++++++++++++++++++++-
 drivers/net/nfp/nfp_mtr.h                |  44 ++++++
 6 files changed, 296 insertions(+), 3 deletions(-)
  

Patch

diff --git a/doc/guides/rel_notes/release_23_03.rst b/doc/guides/rel_notes/release_23_03.rst
index b8c5b68d6c..0ce6fbf8ee 100644
--- a/doc/guides/rel_notes/release_23_03.rst
+++ b/doc/guides/rel_notes/release_23_03.rst
@@ -55,6 +55,9 @@  New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Updated Corigine nfp driver.**
+
+  * Added support for meter options.
 
 Removed Items
 -------------
diff --git a/drivers/net/nfp/flower/nfp_flower_cmsg.c b/drivers/net/nfp/flower/nfp_flower_cmsg.c
index eaddd6c52c..430dd9c316 100644
--- a/drivers/net/nfp/flower/nfp_flower_cmsg.c
+++ b/drivers/net/nfp/flower/nfp_flower_cmsg.c
@@ -525,3 +525,32 @@  nfp_flower_cmsg_qos_delete(struct nfp_app_fw_flower *app_fw_flower,
 
 	return 0;
 }
+
+int
+nfp_flower_cmsg_qos_stats(struct nfp_app_fw_flower *app_fw_flower,
+		struct nfp_cfg_head *head)
+{
+	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 stats");
+		return -ENOMEM;
+	}
+
+	len = sizeof(struct nfp_cfg_head);
+	msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_QOS_STATS, len);
+	rte_memcpy(msg, head, 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;
+}
diff --git a/drivers/net/nfp/flower/nfp_flower_cmsg.h b/drivers/net/nfp/flower/nfp_flower_cmsg.h
index 1894c454d3..2f4cd68730 100644
--- a/drivers/net/nfp/flower/nfp_flower_cmsg.h
+++ b/drivers/net/nfp/flower/nfp_flower_cmsg.h
@@ -928,5 +928,7 @@  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);
+int nfp_flower_cmsg_qos_stats(struct nfp_app_fw_flower *app_fw_flower,
+		struct nfp_cfg_head *head);
 
 #endif /* _NFP_CMSG_H_ */
diff --git a/drivers/net/nfp/flower/nfp_flower_ctrl.c b/drivers/net/nfp/flower/nfp_flower_ctrl.c
index c545007d0c..03a2e2e622 100644
--- a/drivers/net/nfp/flower/nfp_flower_ctrl.c
+++ b/drivers/net/nfp/flower/nfp_flower_ctrl.c
@@ -249,7 +249,32 @@  nfp_flower_cmsg_rx_stats(struct nfp_flow_priv *flow_priv,
 }
 
 static void
-nfp_flower_cmsg_rx(struct nfp_flow_priv *flow_priv,
+nfp_flower_cmsg_rx_qos_stats(struct nfp_mtr_priv *mtr_priv,
+		struct rte_mbuf *mbuf)
+{
+	char *msg;
+	uint32_t profile_id;
+	struct nfp_mtr *mtr;
+	struct nfp_mtr_stats_reply *mtr_stats;
+
+	msg = rte_pktmbuf_mtod(mbuf, char *) + NFP_FLOWER_CMSG_HLEN;
+
+	mtr_stats = (struct nfp_mtr_stats_reply *)msg;
+	profile_id = rte_be_to_cpu_32(mtr_stats->head.profile_id);
+	mtr = nfp_mtr_find_by_profile_id(mtr_priv, profile_id);
+	if (mtr == NULL)
+		return;
+
+	rte_spinlock_lock(&mtr_priv->mtr_stats_lock);
+	mtr->mtr_stats.curr.pass_bytes = rte_be_to_cpu_64(mtr_stats->pass_bytes);
+	mtr->mtr_stats.curr.pass_pkts = rte_be_to_cpu_64(mtr_stats->pass_pkts);
+	mtr->mtr_stats.curr.drop_bytes = rte_be_to_cpu_64(mtr_stats->drop_bytes);
+	mtr->mtr_stats.curr.drop_pkts = rte_be_to_cpu_64(mtr_stats->drop_pkts);
+	rte_spinlock_unlock(&mtr_priv->mtr_stats_lock);
+}
+
+static void
+nfp_flower_cmsg_rx(struct nfp_app_fw_flower *app_fw_flower,
 		struct rte_mbuf **pkts_burst,
 		uint16_t count)
 {
@@ -257,8 +282,13 @@  nfp_flower_cmsg_rx(struct nfp_flow_priv *flow_priv,
 	char *meta;
 	uint32_t meta_type;
 	uint32_t meta_info;
+	struct nfp_mtr_priv *mtr_priv;
+	struct nfp_flow_priv *flow_priv;
 	struct nfp_flower_cmsg_hdr *cmsg_hdr;
 
+	mtr_priv = app_fw_flower->mtr_priv;
+	flow_priv = app_fw_flower->flow_priv;
+
 	for (i = 0; i < count; i++) {
 		meta = rte_pktmbuf_mtod(pkts_burst[i], char *);
 
@@ -282,21 +312,38 @@  nfp_flower_cmsg_rx(struct nfp_flow_priv *flow_priv,
 		if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_FLOW_STATS) {
 			/* We need to deal with stats updates from HW asap */
 			nfp_flower_cmsg_rx_stats(flow_priv, pkts_burst[i]);
+		} else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_QOS_STATS) {
+			/* Handle meter stats */
+			nfp_flower_cmsg_rx_qos_stats(mtr_priv, pkts_burst[i]);
 		}
 
 		rte_pktmbuf_free(pkts_burst[i]);
 	}
 }
 
+static void
+nfp_mtr_stats_request(struct nfp_app_fw_flower *app_fw_flower)
+{
+	struct nfp_mtr *mtr;
+
+	LIST_FOREACH(mtr, &app_fw_flower->mtr_priv->mtrs, next)
+		(void)nfp_flower_cmsg_qos_stats(app_fw_flower, &mtr->mtr_profile->conf.head);
+}
+
 void
 nfp_flower_ctrl_vnic_poll(struct nfp_app_fw_flower *app_fw_flower)
 {
 	uint16_t count;
+	uint64_t cur_tsc;
+	uint64_t drain_tsc;
+	uint64_t pre_tsc = 0;
 	struct nfp_net_rxq *rxq;
 	struct nfp_net_hw *ctrl_hw;
 	struct rte_eth_dev *ctrl_eth_dev;
 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
 
+	drain_tsc = app_fw_flower->mtr_priv->drain_tsc;
+
 	ctrl_hw = app_fw_flower->ctrl_hw;
 	ctrl_eth_dev = ctrl_hw->eth_dev;
 
@@ -308,7 +355,13 @@  nfp_flower_ctrl_vnic_poll(struct nfp_app_fw_flower *app_fw_flower)
 		if (count != 0) {
 			app_fw_flower->ctrl_vnic_rx_count += count;
 			/* Process cmsgs here */
-			nfp_flower_cmsg_rx(app_fw_flower->flow_priv, pkts_burst, count);
+			nfp_flower_cmsg_rx(app_fw_flower, pkts_burst, count);
+		}
+
+		cur_tsc = rte_rdtsc();
+		if (unlikely(cur_tsc - pre_tsc > drain_tsc)) {
+			nfp_mtr_stats_request(app_fw_flower);
+			pre_tsc = cur_tsc;
 		}
 	}
 }
diff --git a/drivers/net/nfp/nfp_mtr.c b/drivers/net/nfp/nfp_mtr.c
index 1df7103417..f77381dcb3 100644
--- a/drivers/net/nfp/nfp_mtr.c
+++ b/drivers/net/nfp/nfp_mtr.c
@@ -553,6 +553,48 @@  nfp_mtr_find_by_mtr_id(struct nfp_mtr_priv *priv, uint32_t mtr_id)
 	return mtr;
 }
 
+struct nfp_mtr *
+nfp_mtr_find_by_profile_id(struct nfp_mtr_priv *priv, uint32_t profile_id)
+{
+	struct nfp_mtr *mtr;
+
+	LIST_FOREACH(mtr, &priv->mtrs, next)
+		if (mtr->mtr_profile->profile_id == profile_id)
+			break;
+
+	return mtr;
+}
+
+static int
+nfp_mtr_stats_mask_validate(uint64_t stats_mask, struct rte_mtr_error *error)
+{
+	if ((stats_mask & RTE_MTR_STATS_N_PKTS_YELLOW) != 0) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+				NULL, "RTE_MTR_STATS_N_PKTS_YELLOW not support");
+	}
+
+	if ((stats_mask & RTE_MTR_STATS_N_PKTS_RED) != 0) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+				NULL, "RTE_MTR_STATS_N_PKTS_RED not support");
+	}
+
+	if ((stats_mask & RTE_MTR_STATS_N_BYTES_YELLOW) != 0) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+				NULL, "RTE_MTR_STATS_N_BYTES_YELLOW not support");
+	}
+
+	if ((stats_mask & RTE_MTR_STATS_N_BYTES_RED) != 0) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+				NULL, "RTE_MTR_STATS_N_BYTES_RED not support");
+	}
+
+	return 0;
+}
+
 static int
 nfp_mtr_validate(uint32_t meter_id,
 		struct rte_mtr_params *params,
@@ -578,7 +620,7 @@  nfp_mtr_validate(uint32_t meter_id,
 				NULL, "Feature use_prev_mtr_color not support");
 	}
 
-	return 0;
+	return nfp_mtr_stats_mask_validate(params->stats_mask, error);
 }
 
 static void
@@ -599,6 +641,7 @@  nfp_mtr_config(uint32_t mtr_id,
 
 	mtr->mtr_profile = mtr_profile;
 	mtr->mtr_policy = mtr_policy;
+	mtr->stats_mask = params->stats_mask;
 }
 
 /**
@@ -886,6 +929,119 @@  nfp_mtr_profile_update(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * Callback to update meter stats mask.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_id
+ *   Meter id.
+ * @param[in] stats_mask
+ *   To be updated stats_mask.
+ * @param[out] error
+ *   Pointer to rte meter error structure.
+ *
+ * @return
+ *   0 on success, a negative value otherwise and rte_errno is set.
+ */
+static int
+nfp_mtr_stats_update(struct rte_eth_dev *dev,
+		uint32_t mtr_id,
+		uint64_t stats_mask,
+		struct rte_mtr_error *error)
+{
+	int ret;
+	struct nfp_mtr *mtr;
+	struct nfp_mtr_priv *priv;
+	struct nfp_flower_representor *representor;
+
+	representor = dev->data->dev_private;
+	priv = representor->app_fw_flower->mtr_priv;
+
+	/* Check if meter id exist */
+	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
+	if (mtr == NULL) {
+		return -rte_mtr_error_set(error, EEXIST,
+				RTE_MTR_ERROR_TYPE_MTR_ID,
+				NULL, "Request meter id not exist");
+	}
+
+	ret = nfp_mtr_stats_mask_validate(stats_mask, error);
+	if (ret != 0)
+		return ret;
+
+	mtr->stats_mask = stats_mask;
+
+	return 0;
+}
+
+/**
+ * Callback to read meter statistics.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_id
+ *   Meter id.
+ * @param[out] stats
+ *   Pointer to store the statistics.
+ * @param[out] stats_mask
+ *   Pointer to store the stats_mask.
+ * @param[in] clear
+ *   Statistic to be cleared after read or not.
+ * @param[out] error
+ *   Pointer to rte meter error structure.
+ *
+ * @return
+ *   0 on success, a negative value otherwise and rte_errno is set.
+ */
+static int
+nfp_mtr_stats_read(struct rte_eth_dev *dev,
+		uint32_t mtr_id,
+		struct rte_mtr_stats *stats,
+		uint64_t *stats_mask,
+		int clear,
+		struct rte_mtr_error *error)
+{
+	struct nfp_mtr *mtr;
+	struct nfp_mtr_priv *priv;
+	struct nfp_mtr_stats curr;
+	struct nfp_mtr_stats *prev;
+	struct nfp_flower_representor *representor;
+
+	representor = dev->data->dev_private;
+	priv = representor->app_fw_flower->mtr_priv;
+
+	/* Check if meter id exist */
+	mtr = nfp_mtr_find_by_mtr_id(priv, mtr_id);
+	if (mtr == NULL) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_MTR_ID,
+				NULL, "Request meter not exist");
+	}
+
+	*stats_mask = mtr->stats_mask;
+
+	rte_spinlock_lock(&priv->mtr_stats_lock);
+	rte_memcpy(&curr, &mtr->mtr_stats.curr, sizeof(curr));
+	rte_spinlock_unlock(&priv->mtr_stats_lock);
+
+	prev = &mtr->mtr_stats.prev;
+
+	stats->n_pkts[RTE_COLOR_GREEN] = curr.pass_pkts - prev->pass_pkts;
+	stats->n_bytes[RTE_COLOR_GREEN] = curr.pass_bytes - prev->pass_bytes;
+	stats->n_pkts_dropped = curr.drop_pkts - prev->drop_pkts;
+	stats->n_bytes_dropped = curr.drop_bytes - prev->drop_bytes;
+
+	if (clear != 0) {
+		prev->pass_pkts = curr.pass_pkts;
+		prev->pass_bytes = curr.pass_bytes;
+		prev->drop_pkts = curr.drop_pkts;
+		prev->drop_bytes = curr.drop_bytes;
+	}
+
+	return 0;
+}
+
 static const struct rte_mtr_ops nfp_mtr_ops = {
 	.capabilities_get      = nfp_mtr_cap_get,
 	.meter_profile_add     = nfp_mtr_profile_add,
@@ -897,6 +1053,8 @@  static const struct rte_mtr_ops nfp_mtr_ops = {
 	.meter_enable          = nfp_mtr_enable,
 	.meter_disable         = nfp_mtr_disable,
 	.meter_profile_update  = nfp_mtr_profile_update,
+	.stats_update          = nfp_mtr_stats_update,
+	.stats_read            = nfp_mtr_stats_read,
 };
 
 int
@@ -927,10 +1085,14 @@  nfp_mtr_priv_init(struct nfp_pf_dev *pf_dev)
 	app_fw_flower = NFP_PRIV_TO_APP_FW_FLOWER(pf_dev->app_fw_priv);
 	app_fw_flower->mtr_priv = priv;
 
+	priv->drain_tsc = rte_get_tsc_hz();
+
 	LIST_INIT(&priv->mtrs);
 	LIST_INIT(&priv->profiles);
 	LIST_INIT(&priv->policies);
 
+	rte_spinlock_init(&priv->mtr_stats_lock);
+
 	return 0;
 }
 
diff --git a/drivers/net/nfp/nfp_mtr.h b/drivers/net/nfp/nfp_mtr.h
index 1f74e39e17..7bfc935e7d 100644
--- a/drivers/net/nfp/nfp_mtr.h
+++ b/drivers/net/nfp/nfp_mtr.h
@@ -66,6 +66,22 @@  struct nfp_profile_conf {
 	rte_be32_t cir;
 };
 
+/**
+ * Struct nfp_mtr_stats_reply - meter stats, read from firmware
+ * @head:          config head information
+ * @pass_bytes:    count of passed bytes
+ * @pass_pkts:     count of passed packets
+ * @drop_bytes:    count of dropped bytes
+ * @drop_pkts:     count of dropped packets
+ */
+struct nfp_mtr_stats_reply {
+	struct nfp_cfg_head head;
+	rte_be64_t pass_bytes;
+	rte_be64_t pass_pkts;
+	rte_be64_t drop_bytes;
+	rte_be64_t drop_pkts;
+};
+
 /**
  * Struct nfp_mtr_profile - meter profile, stored in driver
  * Can only be used by one meter
@@ -95,6 +111,20 @@  struct nfp_mtr_policy {
 	struct rte_mtr_meter_policy_params policy;
 };
 
+/**
+ * Struct nfp_mtr_stats - meter stats information
+ * @pass_bytes:        count of passed bytes for meter
+ * @pass_pkts:         count of passed packets for meter
+ * @drop_bytes:        count of dropped bytes for meter
+ * @drop_pkts:         count of dropped packets for meter
+ */
+struct nfp_mtr_stats {
+	uint64_t pass_bytes;
+	uint64_t pass_pkts;
+	uint64_t drop_bytes;
+	uint64_t drop_pkts;
+};
+
 /**
  * Struct nfp_mtr - meter object information
  * @next:        next meter object
@@ -104,6 +134,9 @@  struct nfp_mtr_policy {
  * @enable:      if meter is enable to use
  * @mtr_profile: the pointer of profile
  * @mtr_policy:  the pointer of policy
+ * @stats_mask:  supported meter stats mask
+ * @curr:        current meter stats
+ * @prev:        previous meter stats
  */
 struct nfp_mtr {
 	LIST_ENTRY(nfp_mtr) next;
@@ -113,6 +146,11 @@  struct nfp_mtr {
 	bool enable;
 	struct nfp_mtr_profile *mtr_profile;
 	struct nfp_mtr_policy *mtr_policy;
+	uint64_t stats_mask;
+	struct {
+		struct nfp_mtr_stats curr;
+		struct nfp_mtr_stats prev;
+	} mtr_stats;
 };
 
 /**
@@ -120,11 +158,15 @@  struct nfp_mtr {
  * @profiles:        the head node of profile list
  * @policies:        the head node of policy list
  * @mtrs:            the head node of mtrs list
+ * @mtr_stats_lock:  spinlock for meter stats
+ * @drain_tsc:       clock period
  */
 struct nfp_mtr_priv {
 	LIST_HEAD(, nfp_mtr_profile) profiles;
 	LIST_HEAD(, nfp_mtr_policy) policies;
 	LIST_HEAD(, nfp_mtr) mtrs;
+	rte_spinlock_t mtr_stats_lock;
+	uint64_t drain_tsc;
 };
 
 int nfp_net_mtr_ops_get(struct rte_eth_dev *dev, void *arg);
@@ -132,5 +174,7 @@  int nfp_mtr_priv_init(struct nfp_pf_dev *pf_dev);
 void nfp_mtr_priv_uninit(struct nfp_pf_dev *pf_dev);
 struct nfp_mtr *nfp_mtr_find_by_mtr_id(struct nfp_mtr_priv *priv,
 		uint32_t mtr_id);
+struct nfp_mtr *nfp_mtr_find_by_profile_id(struct nfp_mtr_priv *priv,
+		uint32_t profile_id);
 
 #endif /* __NFP_MTR_H__ */