@@ -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
-------------
@@ -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;
+}
@@ -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_ */
@@ -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;
}
}
}
@@ -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;
}
@@ -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__ */