Hi Ivan,

> +static int
> +nbl_res_txrx_reset_stats(void *priv)
> +{
> + struct nbl_resource_mgt *res_mgt = (struct nbl_resource_mgt *)priv;
> + struct rte_eth_dev *eth_dev = res_mgt->eth_dev;
> + struct nbl_res_rx_ring *rxq;
> + struct nbl_rxq_stats *rxq_stats;
> + struct nbl_res_tx_ring  *txq;
> + struct nbl_txq_stats *txq_stats;
> + uint32_t i;
> +
> + /* Add software counters. */
> + for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
> +  rxq = eth_dev->data->rx_queues[i];
> +  if (unlikely(rxq == NULL))
> +   continue;
> +
> +  rxq_stats = &rxq->rxq_stats;
> +  memset(rxq_stats, 0, sizeof(struct nbl_rxq_stats));

What if the application has dedicated lcores for datapath Rx/Tx burst calls and
uses another, admin core to query/reset statistics?

First, this issue does not cause any crashes. 
Additionally, I think these statistics are not so important,it is unnecessary to set rte_atomic for them, as it would introduce unnecessary performance overhead.

Thank you.


------------------------------------------------------------------
发件人:Ivan Malov <ivan.malov@arknetworks.am>
发送时间:2025年8月13日(周三) 19:48
收件人:Dimon<dimon.zhao@nebula-matrix.com>
抄 送:dev<dev@dpdk.org>; Kyo Liu<kyo.liu@nebula-matrix.com>; Leon<leon.yu@nebula-matrix.com>; Sam<sam.chen@nebula-matrix.com>
主 题:Re: [PATCH v4 15/16] net/nbl: add nbl device xstats and stats

Hi Dimon,

(please see below)

On Tue, 12 Aug 2025, Dimon Zhao wrote:

> Implement NBL device xstats and stats functions
>
> Signed-off-by: Dimon Zhao <dimon.zhao@nebula-matrix.com>
> ---
> drivers/net/nbl/nbl_dev/nbl_dev.c             | 141 +++++++++++++++++-
> drivers/net/nbl/nbl_dev/nbl_dev.h             |   8 +
> drivers/net/nbl/nbl_dispatch.c                | 111 ++++++++++++++
> drivers/net/nbl/nbl_ethdev.c                  |   4 +
> .../nbl/nbl_hw/nbl_hw_leonis/nbl_res_leonis.c | 113 ++++++++++++++
> drivers/net/nbl/nbl_hw/nbl_txrx.c             | 113 +++++++++++++-
> drivers/net/nbl/nbl_include/nbl_def_channel.h |   5 +
> .../net/nbl/nbl_include/nbl_def_dispatch.h    |   9 ++
> .../net/nbl/nbl_include/nbl_def_resource.h    |  12 +-
> drivers/net/nbl/nbl_include/nbl_include.h     |   4 +
> 10 files changed, 514 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/nbl/nbl_dev/nbl_dev.c b/drivers/net/nbl/nbl_dev/nbl_dev.c
> index b32ab839d5..bab89c707f 100644
> --- a/drivers/net/nbl/nbl_dev/nbl_dev.c
> +++ b/drivers/net/nbl/nbl_dev/nbl_dev.c
> @@ -381,6 +381,126 @@ int nbl_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *rte_stats)
>  return disp_ops->get_stats(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt), rte_stats);
> }
>
> +int nbl_stats_reset(struct rte_eth_dev *eth_dev)
> +{
> + struct nbl_adapter *adapter = ETH_DEV_TO_NBL_DEV_PF_PRIV(eth_dev);
> + struct nbl_dev_mgt *dev_mgt = NBL_ADAPTER_TO_DEV_MGT(adapter);
> + struct nbl_dispatch_ops *disp_ops = NBL_DEV_MGT_TO_DISP_OPS(dev_mgt);
> +
> + return disp_ops->reset_stats(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt));
> +}
> +
> +static int nbl_dev_update_hw_xstats(struct nbl_dev_mgt *dev_mgt, struct rte_eth_xstat *xstats,
> +        u16 hw_xstats_cnt, u16 *xstats_cnt)
> +{
> + struct nbl_common_info *common = NBL_DEV_MGT_TO_COMMON(dev_mgt);
> + struct nbl_dispatch_ops *disp_ops = NBL_DEV_MGT_TO_DISP_OPS(dev_mgt);
> + u64 *hw_stats;
> + int i;
> + u16 count = *xstats_cnt;
> +
> + hw_stats = rte_zmalloc("nbl_xstats_cnt", hw_xstats_cnt * sizeof(u64), 0);

Do you believe it's the best course of action, to allocate and free a bounce
buffer on each invocation? This function is not strictly fast-path, but I'd say
semi-fast. Some applications may want to invoke it pretty often.

> + if (!hw_stats)
> +  return -ENOMEM;
> +
> + disp_ops->get_private_stat_data(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +     common->eth_id, hw_stats, hw_xstats_cnt * sizeof(u64));
> + for (i = 0; i < hw_xstats_cnt; i++) {
> +  xstats[count].value = hw_stats[i] - dev_mgt->net_dev->hw_xstats_offset[i];
> +  xstats[count].id = count;
> +  count++;
> + }
> +
> + *xstats_cnt = count;
> + rte_free(hw_stats);
> + return 0;
> +}
> +
> +int nbl_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats, unsigned int n)
> +{
> + struct nbl_adapter *adapter = ETH_DEV_TO_NBL_DEV_PF_PRIV(eth_dev);
> + struct nbl_dev_mgt *dev_mgt = NBL_ADAPTER_TO_DEV_MGT(adapter);
> + struct nbl_common_info *common = NBL_DEV_MGT_TO_COMMON(dev_mgt);
> + struct nbl_dispatch_ops *disp_ops = NBL_DEV_MGT_TO_DISP_OPS(dev_mgt);
> + int ret = 0;
> + u16 txrx_xstats_cnt = 0, hw_xstats_cnt = 0, xstats_cnt = 0;
> +
> + if (!xstats)
> +  return 0;
> +
> + ret = disp_ops->get_txrx_xstats_cnt(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt), &txrx_xstats_cnt);
> + if (!common->is_vf)
> +  ret |= disp_ops->get_hw_xstats_cnt(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +         &hw_xstats_cnt);
> + if (ret)
> +  return -EIO;
> +
> + if (n < (txrx_xstats_cnt + hw_xstats_cnt))
> +  return txrx_xstats_cnt + hw_xstats_cnt;
> +
> + if (txrx_xstats_cnt)
> +  ret = disp_ops->get_txrx_xstats(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +      xstats, &xstats_cnt);
> + if (hw_xstats_cnt)
> +  ret |= nbl_dev_update_hw_xstats(dev_mgt, xstats, hw_xstats_cnt, &xstats_cnt);
> +
> + if (ret)
> +  return -EIO;
> +
> + return xstats_cnt;
> +}
> +
> +int nbl_xstats_get_names(struct rte_eth_dev *eth_dev,
> +    struct rte_eth_xstat_name *xstats_names,
> +    __rte_unused unsigned int limit)
> +{
> + struct nbl_adapter *adapter = ETH_DEV_TO_NBL_DEV_PF_PRIV(eth_dev);
> + struct nbl_dev_mgt *dev_mgt = NBL_ADAPTER_TO_DEV_MGT(adapter);
> + struct nbl_common_info *common = NBL_DEV_MGT_TO_COMMON(dev_mgt);
> + struct nbl_dispatch_ops *disp_ops = NBL_DEV_MGT_TO_DISP_OPS(dev_mgt);
> + u16 txrx_xstats_cnt = 0, hw_xstats_cnt = 0, xstats_cnt = 0;
> + int ret = 0;
> +
> + ret = disp_ops->get_txrx_xstats_cnt(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt), &txrx_xstats_cnt);

Exceeds 80-column limit.

> + if (!common->is_vf)
> +  ret |= disp_ops->get_hw_xstats_cnt(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +       &hw_xstats_cnt);
> + if (ret)
> +  return -EIO;
> +
> + if (!xstats_names)
> +  return txrx_xstats_cnt + hw_xstats_cnt;
> +
> + if (txrx_xstats_cnt)
> +  ret = disp_ops->get_txrx_xstats_names(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +            xstats_names, &xstats_cnt);
> + if (hw_xstats_cnt)
> +  ret |= disp_ops->get_hw_xstats_names(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +           xstats_names, &xstats_cnt);
> + if (ret)
> +  return -EIO;
> +
> + return xstats_cnt;
> +}
> +
> +int nbl_xstats_reset(struct rte_eth_dev *eth_dev)
> +{
> + struct nbl_adapter *adapter = ETH_DEV_TO_NBL_DEV_PF_PRIV(eth_dev);
> + struct nbl_dev_mgt *dev_mgt = NBL_ADAPTER_TO_DEV_MGT(adapter);
> + struct nbl_common_info *common = NBL_DEV_MGT_TO_COMMON(dev_mgt);
> + struct nbl_dispatch_ops *disp_ops = NBL_DEV_MGT_TO_DISP_OPS(dev_mgt);
> + struct nbl_dev_net_mgt *net_dev = dev_mgt->net_dev;
> +
> + if (!common->is_vf) {
> +  disp_ops->get_private_stat_data(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +      dev_mgt->common->eth_id,
> +      net_dev->hw_xstats_offset, net_dev->hw_xstats_size);
> + }
> +
> + nbl_stats_reset(eth_dev);
> + return 0;
> +}
> +
> struct nbl_dev_ops dev_ops = {
> };
>
> @@ -435,6 +555,7 @@ static int nbl_dev_common_start(struct nbl_dev_mgt *dev_mgt)
>  struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
>  u8 *mac;
>  int ret;
> + u16 priv_cnt = 0;
>
>  board_info = &common->board_info;
>  disp_ops->get_board_info(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt), board_info);
> @@ -477,8 +598,25 @@ static int nbl_dev_common_start(struct nbl_dev_mgt *dev_mgt)
>    goto add_multi_rule_failed;
>  }
>
> - return 0;
> + net_dev->hw_xstats_offset = NULL;
> + if (!dev_mgt->common->is_vf)
> +  disp_ops->get_hw_xstats_cnt(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt), &priv_cnt);
> + if (priv_cnt) {
> +  net_dev->hw_xstats_offset = rte_zmalloc("nbl_xstats_cnt",
> +       priv_cnt * sizeof(u64), 0);
> +  net_dev->hw_xstats_size = priv_cnt * sizeof(u64);
> +  if (!net_dev->hw_xstats_offset) {
> +   ret = -ENOMEM;
> +   goto alloc_xstats_offset_failed;
> +  }
> +
> +  disp_ops->get_private_stat_data(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt),
> +      dev_mgt->common->eth_id,
> +      net_dev->hw_xstats_offset, net_dev->hw_xstats_size);
> + }
>
> + return 0;
> +alloc_xstats_offset_failed:
> add_multi_rule_failed:
>  disp_ops->del_macvlan(NBL_DEV_MGT_TO_DISP_PRIV(dev_mgt), mac, 0, net_dev->vsi_id);
> add_macvlan_failed:
> @@ -757,6 +895,7 @@ int nbl_dev_init(void *p, struct rte_eth_dev *eth_dev)
>           eth_dev->data->mac_addrs[0].addr_bytes);
>
>  adapter->state = NBL_ETHDEV_INITIALIZED;
> + eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
>  disp_ops->get_resource_pt_ops(NBL_DEV_MGT_TO_DISP_PRIV(*dev_mgt),
>           &(*dev_mgt)->pt_ops, 0);
>
> diff --git a/drivers/net/nbl/nbl_dev/nbl_dev.h b/drivers/net/nbl/nbl_dev/nbl_dev.h
> index 577a28b32d..1500a782a5 100644
> --- a/drivers/net/nbl/nbl_dev/nbl_dev.h
> +++ b/drivers/net/nbl/nbl_dev/nbl_dev.h
> @@ -41,6 +41,8 @@ struct nbl_dev_net_mgt {
>  struct rte_eth_dev *eth_dev;
>  struct nbl_dev_ring_mgt ring_mgt;
>  struct nbl_eth_link_info eth_link_info;
> + u64 *hw_xstats_offset;
> + u32 hw_xstats_size;
>  u16 vsi_id;
>  u8 eth_mode;
>  u8 eth_id;
> @@ -71,5 +73,11 @@ void nbl_rx_queues_release(struct rte_eth_dev *eth_dev, uint16_t queue_id);
> int nbl_dev_infos_get(struct rte_eth_dev *eth_dev __rte_unused, struct rte_eth_dev_info *dev_info);
> int nbl_link_update(struct rte_eth_dev *eth_dev, int wait_to_complete __rte_unused);
> int nbl_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *rte_stats);
> +int nbl_stats_reset(struct rte_eth_dev *eth_dev);
> +int nbl_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats, unsigned int n);
> +int nbl_xstats_get_names(struct rte_eth_dev *eth_dev,
> +    struct rte_eth_xstat_name *xstats_names,
> +    __rte_unused unsigned int limit);
> +int nbl_xstats_reset(struct rte_eth_dev *eth_dev);
>
> #endif
> diff --git a/drivers/net/nbl/nbl_dispatch.c b/drivers/net/nbl/nbl_dispatch.c
> index 9382b76ce6..15ea61d8e4 100644
> --- a/drivers/net/nbl/nbl_dispatch.c
> +++ b/drivers/net/nbl/nbl_dispatch.c
> @@ -809,9 +809,94 @@ static int nbl_disp_get_stats(void *priv, struct rte_eth_stats *rte_stats)
> {
>  struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
>  struct nbl_resource_ops *res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> +
>  return res_ops->get_stats(NBL_DISP_MGT_TO_RES_PRIV(disp_mgt), rte_stats);
> }
>
> +static int nbl_disp_reset_stats(void *priv)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_resource_ops *res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> +
> + return res_ops->reset_stats(NBL_DISP_MGT_TO_RES_PRIV(disp_mgt));
> +}
> +
> +static int nbl_disp_get_txrx_xstats_cnt(void *priv, u16 *xstats_cnt)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_resource_ops *res_ops;
> +
> + res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> + return res_ops->get_txrx_xstats_cnt(NBL_DISP_MGT_TO_RES_PRIV(disp_mgt), xstats_cnt);
> +}
> +
> +static int nbl_disp_get_txrx_xstats(void *priv, struct rte_eth_xstat *xstats, u16 *xstats_cnt)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_resource_ops *res_ops;
> +
> + res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> + return res_ops->get_txrx_xstats(NBL_DISP_MGT_TO_RES_PRIV(disp_mgt), xstats, xstats_cnt);
> +}
> +
> +static int nbl_disp_get_txrx_xstats_names(void *priv, struct rte_eth_xstat_name *xstats_names,
> +       u16 *xstats_cnt)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_resource_ops *res_ops;
> +
> + res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> + return res_ops->get_txrx_xstats_names(NBL_DISP_MGT_TO_RES_PRIV(disp_mgt),
> +      xstats_names, xstats_cnt);
> +}
> +
> +static int nbl_disp_get_hw_xstats_cnt(void *priv, u16 *xstats_cnt)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_resource_ops *res_ops;
> +
> + res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> + return res_ops->get_hw_xstats_cnt(NBL_DISP_MGT_TO_RES_PRIV(disp_mgt), xstats_cnt);
> +}
> +
> +static int nbl_disp_get_hw_xstats_names(void *priv, struct rte_eth_xstat_name *xstats_names,
> +     u16 *xstats_cnt)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_resource_ops *res_ops;
> +
> + res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> + return res_ops->get_hw_xstats_names(NBL_DISP_MGT_TO_RES_PRIV(disp_mgt),
> +         xstats_names, xstats_cnt);
> +}
> +
> +static void nbl_disp_get_private_stat_data(void *priv, u32 eth_id, u64 *data,
> +        __rte_unused u32 data_len)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_resource_ops *res_ops;
> +
> + res_ops = NBL_DISP_MGT_TO_RES_OPS(disp_mgt);
> + NBL_OPS_CALL(res_ops->get_private_stat_data,
> +       (NBL_DISP_MGT_TO_RES_PRIV(disp_mgt), eth_id, data));
> +}
> +
> +static void nbl_disp_get_private_stat_data_req(void *priv, u32 eth_id, u64 *data, u32 data_len)
> +{
> + struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
> + struct nbl_channel_ops *chan_ops;
> + struct nbl_chan_send_info chan_send = {0};
> + struct nbl_chan_param_get_private_stat_data param = {0};
> +
> + chan_ops = NBL_DISP_MGT_TO_CHAN_OPS(disp_mgt);
> +
> + param.eth_id = eth_id;
> + param.data_len = data_len;
> + NBL_CHAN_SEND(chan_send, 0, NBL_CHAN_MSG_GET_ETH_STATS, &param,
> +        sizeof(param), data, data_len, 1);
> + chan_ops->send_msg(NBL_DISP_MGT_TO_CHAN_PRIV(disp_mgt), &chan_send);
> +}
> +
> #define NBL_DISP_OPS_TBL      \
> do {         \
>  NBL_DISP_SET_OPS(configure_msix_map, nbl_disp_configure_msix_map,   \
> @@ -956,6 +1041,32 @@ do {         \
>  NBL_DISP_SET_OPS(get_stats, nbl_disp_get_stats,   \
>     NBL_DISP_CTRL_LVL_ALWAYS, -1,   \
>     NULL, NULL);     \
> + NBL_DISP_SET_OPS(reset_stats, nbl_disp_reset_stats,  \
> +    NBL_DISP_CTRL_LVL_ALWAYS, -1,   \
> +    NULL, NULL);     \
> + NBL_DISP_SET_OPS(get_txrx_xstats_cnt,    \
> +    nbl_disp_get_txrx_xstats_cnt,   \
> +    NBL_DISP_CTRL_LVL_ALWAYS, -1,   \
> +    NULL, NULL);     \
> + NBL_DISP_SET_OPS(get_txrx_xstats, nbl_disp_get_txrx_xstats, \
> +    NBL_DISP_CTRL_LVL_ALWAYS, -1,   \
> +    NULL, NULL);     \
> + NBL_DISP_SET_OPS(get_txrx_xstats_names,    \
> +    nbl_disp_get_txrx_xstats_names,  \
> +    NBL_DISP_CTRL_LVL_ALWAYS, -1,   \
> +    NULL, NULL);     \
> + NBL_DISP_SET_OPS(get_hw_xstats_cnt, nbl_disp_get_hw_xstats_cnt, \
> +    NBL_DISP_CTRL_LVL_ALWAYS, -1,   \
> +    NULL, NULL);     \
> + NBL_DISP_SET_OPS(get_hw_xstats_names,    \
> +    nbl_disp_get_hw_xstats_names,   \
> +    NBL_DISP_CTRL_LVL_ALWAYS, -1,   \
> +    NULL, NULL);     \
> + NBL_DISP_SET_OPS(get_private_stat_data,    \
> +    nbl_disp_get_private_stat_data,  \
> +    NBL_DISP_CTRL_LVL_MGT,    \
> +    NBL_CHAN_MSG_GET_ETH_STATS,   \
> +    nbl_disp_get_private_stat_data_req, NULL); \
> } while (0)
>
> /* Structure starts here, adding an op should not modify anything below */
> diff --git a/drivers/net/nbl/nbl_ethdev.c b/drivers/net/nbl/nbl_ethdev.c
> index f30aca2b7f..81b8946acc 100644
> --- a/drivers/net/nbl/nbl_ethdev.c
> +++ b/drivers/net/nbl/nbl_ethdev.c
> @@ -41,6 +41,10 @@ const struct eth_dev_ops nbl_eth_dev_ops = {
>  .dev_infos_get = nbl_dev_infos_get,
>  .link_update = nbl_link_update,
>  .stats_get = nbl_stats_get,
> + .stats_reset = nbl_stats_reset,
> + .xstats_get = nbl_xstats_get,
> + .xstats_get_names = nbl_xstats_get_names,
> + .xstats_reset = nbl_xstats_reset,
> };
>
> static int nbl_eth_dev_init(struct rte_eth_dev *eth_dev)
> diff --git a/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_res_leonis.c b/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_res_leonis.c
> index e7036373f1..41ae423ff0 100644
> --- a/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_res_leonis.c
> +++ b/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_res_leonis.c
> @@ -4,7 +4,120 @@
>
> #include "nbl_res_leonis.h"
>
> +/* store statistics names */
> +struct nbl_xstats_name {
> + char name[RTE_ETH_XSTATS_NAME_SIZE];
> +};
> +
> +static const struct nbl_xstats_name nbl_stats_strings[] = {
> + {"eth_frames_tx"},
> + {"eth_frames_tx_ok"},
> + {"eth_frames_tx_badfcs"},
> + {"eth_unicast_frames_tx_ok"},
> + {"eth_multicast_frames_tx_ok"},
> + {"eth_broadcast_frames_tx_ok"},
> + {"eth_macctrl_frames_tx_ok"},
> + {"eth_fragment_frames_tx"},
> + {"eth_fragment_frames_tx_ok"},
> + {"eth_pause_frames_tx"},
> + {"eth_pause_macctrl_frames_tx"},
> + {"eth_pfc_frames_tx"},
> + {"eth_pfc_frames_tx_prio0"},
> + {"eth_pfc_frames_tx_prio1"},
> + {"eth_pfc_frames_tx_prio2"},
> + {"eth_pfc_frames_tx_prio3"},
> + {"eth_pfc_frames_tx_prio4"},
> + {"eth_pfc_frames_tx_prio5"},
> + {"eth_pfc_frames_tx_prio6"},
> + {"eth_pfc_frames_tx_prio7"},
> + {"eth_verify_frames_tx"},
> + {"eth_respond_frames_tx"},
> + {"eth_frames_tx_64B"},
> + {"eth_frames_tx_65_to_127B"},
> + {"eth_frames_tx_128_to_255B"},
> + {"eth_frames_tx_256_to_511B"},
> + {"eth_frames_tx_512_to_1023B"},
> + {"eth_frames_tx_1024_to_1535B"},
> + {"eth_frames_tx_1536_to_2047B"},
> + {"eth_frames_tx_2048_to_MAXB"},
> + {"eth_undersize_frames_tx_goodfcs"},
> + {"eth_oversize_frames_tx_goodfcs"},
> + {"eth_undersize_frames_tx_badfcs"},
> + {"eth_oversize_frames_tx_badfcs"},
> + {"eth_octets_tx"},
> + {"eth_octets_tx_ok"},
> + {"eth_octets_tx_badfcs"},
> + {"eth_frames_rx"},
> + {"eth_frames_rx_ok"},
> + {"eth_frames_rx_badfcs"},
> + {"eth_undersize_frames_rx_goodfcs"},
> + {"eth_undersize_frames_rx_badfcs"},
> + {"eth_oversize_frames_rx_goodfcs"},
> + {"eth_oversize_frames_rx_badfcs"},
> + {"eth_frames_rx_misc_error"},
> + {"eth_frames_rx_misc_dropped"},
> + {"eth_unicast_frames_rx_ok"},
> + {"eth_multicast_frames_rx_ok"},
> + {"eth_broadcast_frames_rx_ok"},
> + {"eth_pause_frames_rx"},
> + {"eth_pfc_frames_rx"},
> + {"eth_pfc_frames_rx_prio0"},
> + {"eth_pfc_frames_rx_prio1"},
> + {"eth_pfc_frames_rx_prio2"},
> + {"eth_pfc_frames_rx_prio3"},
> + {"eth_pfc_frames_rx_prio4"},
> + {"eth_pfc_frames_rx_prio5"},
> + {"eth_pfc_frames_rx_prio6"},
> + {"eth_pfc_frames_rx_prio7"},
> + {"eth_macctrl_frames_rx"},
> + {"eth_verify_frames_rx_ok"},
> + {"eth_respond_frames_rx_ok"},
> + {"eth_fragment_frames_rx_ok"},
> + {"eth_fragment_rx_smdc_nocontext"},
> + {"eth_fragment_rx_smds_seq_error"},
> + {"eth_fragment_rx_smdc_seq_error"},
> + {"eth_fragment_rx_frag_cnt_error"},
> + {"eth_frames_assembled_ok"},
> + {"eth_frames_assembled_error"},
> + {"eth_frames_rx_64B"},
> + {"eth_frames_rx_65_to_127B"},
> + {"eth_frames_rx_128_to_255B"},
> + {"eth_frames_rx_256_to_511B"},
> + {"eth_frames_rx_512_to_1023B"},
> + {"eth_frames_rx_1024_to_1535B"},
> + {"eth_frames_rx_1536_to_2047B"},
> + {"eth_frames_rx_2048_to_MAXB"},
> + {"eth_octets_rx"},
> + {"eth_octets_rx_ok"},
> + {"eth_octets_rx_badfcs"},
> + {"eth_octets_rx_dropped"},
> +};
> +
> +static int nbl_get_xstats_cnt(__rte_unused void *priv, u16 *xstats_cnt)
> +{
> + *xstats_cnt = ARRAY_SIZE(nbl_stats_strings);
> + return 0;
> +}
> +
> +static int nbl_get_xstats_names(__rte_unused void *priv,
> +    struct rte_eth_xstat_name *xstats_names,
> +    u16 *xstats_cnt)
> +{
> + u32 i = 0;
> + u16 count = *xstats_cnt;
> +
> + for (i = 0; i < ARRAY_SIZE(nbl_stats_strings); i++) {
> +  strlcpy(xstats_names[count].name, nbl_stats_strings[i].name,
> +   sizeof(nbl_stats_strings[count].name));
> +  count++;
> + }
> + *xstats_cnt = count;
> + return 0;
> +}
> +
> static struct nbl_resource_ops res_ops = {
> + .get_hw_xstats_cnt = nbl_get_xstats_cnt,
> + .get_hw_xstats_names = nbl_get_xstats_names,
> };
>
> static bool is_ops_inited;
> diff --git a/drivers/net/nbl/nbl_hw/nbl_txrx.c b/drivers/net/nbl/nbl_hw/nbl_txrx.c
> index d0acbe867d..3de4eedbdb 100644
> --- a/drivers/net/nbl/nbl_hw/nbl_txrx.c
> +++ b/drivers/net/nbl/nbl_hw/nbl_txrx.c
> @@ -536,6 +536,7 @@ nbl_res_txrx_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, u16 nb_pkts, u
>    txe->mbuf = tx_pkt;
>
>    data_len = tx_pkt->data_len;
> +   txq->txq_stats.tx_bytes += tx_pkt->data_len;
>    dma_addr = rte_mbuf_data_iova(tx_pkt);
>    tx_desc->addr = NBL_DMA_ADDERSS_FULL_TRANSLATE(txq, dma_addr) + addr_offset;
>    tx_desc->len = data_len - addr_offset;
> @@ -615,6 +616,8 @@ nbl_res_txrx_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, u16 nb_pkts)
>    rx_ext_hdr = (union nbl_rx_extend_head *)((char *)rx_mbuf->buf_addr +
>           RTE_PKTMBUF_HEADROOM);
>    num_sg = rx_ext_hdr->common.num_buffers;
> +   if (num_sg > 1)
> +    rxq->rxq_stats.rx_multi_descs++;
>
>    rx_mbuf->nb_segs = num_sg;
>    rx_mbuf->data_len = rx_desc->len - rxq->exthdr_len;
> @@ -642,15 +645,20 @@ nbl_res_txrx_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, u16 nb_pkts)
>   if (--num_sg)
>    continue;
>   if (drop) {
> +   rxq->rxq_stats.rx_drop_proto++;
>    rte_pktmbuf_free(rx_mbuf);
>    continue;
>   }
>   rx_pkts[nb_recv_pkts++] = rx_mbuf;
> +  rxq->rxq_stats.rx_bytes += rx_mbuf->pkt_len;
>  }
>
>  /* BUG on duplicate pkt free */
> - if (unlikely(num_sg))
> + if (unlikely(num_sg)) {
> +  rxq->rxq_stats.rx_ierror++;
>   rte_pktmbuf_free(rx_mbuf);
> + }
> +
>  /* clean memory */
>  rxq->next_to_clean = desc_index;
>  fill_num = rxq->vq_free_cnt;
> @@ -720,6 +728,105 @@ static int nbl_res_txrx_get_stats(void *priv, struct rte_eth_stats *rte_stats)
>  return 0;
> }
>
> +static int
> +nbl_res_txrx_reset_stats(void *priv)
> +{
> + struct nbl_resource_mgt *res_mgt = (struct nbl_resource_mgt *)priv;
> + struct rte_eth_dev *eth_dev = res_mgt->eth_dev;
> + struct nbl_res_rx_ring *rxq;
> + struct nbl_rxq_stats *rxq_stats;
> + struct nbl_res_tx_ring  *txq;
> + struct nbl_txq_stats *txq_stats;
> + uint32_t i;
> +
> + /* Add software counters. */
> + for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
> +  rxq = eth_dev->data->rx_queues[i];
> +  if (unlikely(rxq == NULL))
> +   continue;
> +
> +  rxq_stats = &rxq->rxq_stats;
> +  memset(rxq_stats, 0, sizeof(struct nbl_rxq_stats));

What if the application has dedicated lcores for datapath Rx/Tx burst calls and
uses another, admin core to query/reset statistics?

Thank you.

> + }
> +
> + for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
> +  txq = eth_dev->data->tx_queues[i];
> +  if (unlikely(txq == NULL))
> +   continue;
> +
> +  txq_stats = &txq->txq_stats;
> +  memset(txq_stats, 0, sizeof(struct nbl_txq_stats));
> + }
> +
> + return 0;
> +}
> +
> +/* store statistics names */
> +struct nbl_txrx_xstats_name {
> + char name[RTE_ETH_XSTATS_NAME_SIZE];
> +};
> +
> +static const struct nbl_txrx_xstats_name nbl_stats_strings[] = {
> + {"rx_multidescs_packets"},
> + {"rx_drop_noport_packets"},
> + {"rx_drop_proto_packets"},
> +};
> +
> +static int nbl_res_txrx_get_xstats_cnt(__rte_unused void *priv, u16 *xstats_cnt)
> +{
> + *xstats_cnt = ARRAY_SIZE(nbl_stats_strings);
> + return 0;
> +}
> +
> +static int nbl_res_txrx_get_xstats(void *priv, struct rte_eth_xstat *xstats, u16 *xstats_cnt)
> +{
> + struct nbl_resource_mgt *res_mgt = (struct nbl_resource_mgt *)priv;
> + struct nbl_txrx_mgt *txrx_mgt = NBL_RES_MGT_TO_TXRX_MGT(res_mgt);
> + struct nbl_res_rx_ring *rxq;
> + uint64_t rx_multi_descs = 0, rx_drop_noport = 0, rx_drop_proto = 0;
> + unsigned int i = 0;
> + u16 count = *xstats_cnt;
> +
> + /* todo: get eth stats from emp */
> + for (i = 0; i < txrx_mgt->rx_ring_num; i++) {
> +  rxq = NBL_RES_MGT_TO_RX_RING(res_mgt, i);
> +
> +  if (unlikely(rxq == NULL))
> +   return -EINVAL;
> +
> +  rx_multi_descs += rxq->rxq_stats.rx_multi_descs;
> +  rx_drop_noport += rxq->rxq_stats.rx_drop_noport;
> +  rx_drop_proto += rxq->rxq_stats.rx_drop_proto;
> + }
> +
> + xstats[count].value = rx_multi_descs;
> + xstats[count].id = count;
> + xstats[count + 1].value = rx_drop_noport;
> + xstats[count + 1].id = count + 1;
> + xstats[count + 2].value = rx_drop_proto;
> + xstats[count + 2].id = count + 2;
> +
> + *xstats_cnt = count + 3;
> +
> + return 0;
> +}
> +
> +static int nbl_res_txrx_get_xstats_names(__rte_unused void *priv,
> +      struct rte_eth_xstat_name *xstats_names,
> +      u16 *xstats_cnt)
> +{
> + unsigned int i = 0;
> + u16 count = *xstats_cnt;
> +
> + for (i = 0; i < ARRAY_SIZE(nbl_stats_strings); i++) {
> +  strlcpy(xstats_names[count].name, nbl_stats_strings[i].name,
> +   sizeof(nbl_stats_strings[count].name));
> +  count++;
> + }
> + *xstats_cnt = count;
> + return 0;
> +}
> +
> /* NBL_TXRX_SET_OPS(ops_name, func)
>  *
>  * Use X Macros to reduce setup and remove codes.
> @@ -738,6 +845,10 @@ do {          \
>  NBL_TXRX_SET_OPS(update_rx_ring, nbl_res_txrx_update_rx_ring);  \
>  NBL_TXRX_SET_OPS(get_resource_pt_ops, nbl_res_get_pt_ops);  \
>  NBL_TXRX_SET_OPS(get_stats, nbl_res_txrx_get_stats);   \
> + NBL_TXRX_SET_OPS(reset_stats, nbl_res_txrx_reset_stats);  \
> + NBL_TXRX_SET_OPS(get_txrx_xstats_cnt, nbl_res_txrx_get_xstats_cnt); \
> + NBL_TXRX_SET_OPS(get_txrx_xstats_names, nbl_res_txrx_get_xstats_names); \
> + NBL_TXRX_SET_OPS(get_txrx_xstats, nbl_res_txrx_get_xstats);  \
> } while (0)
>
> /* Structure starts here, adding an op should not modify anything below */
> diff --git a/drivers/net/nbl/nbl_include/nbl_def_channel.h b/drivers/net/nbl/nbl_include/nbl_def_channel.h
> index 481a725a3d..39050a3999 100644
> --- a/drivers/net/nbl/nbl_include/nbl_def_channel.h
> +++ b/drivers/net/nbl/nbl_include/nbl_def_channel.h
> @@ -385,6 +385,11 @@ struct nbl_chan_param_get_link_state {
>  u8 eth_id;
> };
>
> +struct nbl_chan_param_get_private_stat_data {
> + u32 eth_id;
> + u32 data_len;
> +};
> +
> struct nbl_chan_send_info {
>  uint16_t dstid;
>  uint16_t msg_type;
> diff --git a/drivers/net/nbl/nbl_include/nbl_def_dispatch.h b/drivers/net/nbl/nbl_include/nbl_def_dispatch.h
> index 0139b37ad1..f38a10e5f4 100644
> --- a/drivers/net/nbl/nbl_include/nbl_def_dispatch.h
> +++ b/drivers/net/nbl/nbl_include/nbl_def_dispatch.h
> @@ -74,6 +74,15 @@ struct nbl_dispatch_ops {
>  void (*get_board_info)(void *priv, struct nbl_board_port_info *board_info);
>  void (*get_link_state)(void *priv, u8 eth_id, struct nbl_eth_link_info *eth_link_info);
>  int (*get_stats)(void *priv, struct rte_eth_stats *rte_stats);
> + int (*reset_stats)(void *priv);
> + int (*get_txrx_xstats_cnt)(void *priv, u16 *xstats_cnt);
> + int (*get_txrx_xstats)(void *priv, struct rte_eth_xstat *xstats, u16 *xstats_cnt);
> + int (*get_txrx_xstats_names)(void *priv, struct rte_eth_xstat_name *xstats_names,
> +         u16 *xstats_cnt);
> + int (*get_hw_xstats_cnt)(void *priv, u16 *xstats_cnt);
> + int (*get_hw_xstats_names)(void *priv, struct rte_eth_xstat_name *xstats_names,
> +       u16 *xstats_cnt);
> + void (*get_private_stat_data)(void *priv, u32 eth_id, u64 *data, u32 data_len);
>
>  void (*dummy_func)(void *priv);
> };
> diff --git a/drivers/net/nbl/nbl_include/nbl_def_resource.h b/drivers/net/nbl/nbl_include/nbl_def_resource.h
> index c14fdc773e..5b32506be1 100644
> --- a/drivers/net/nbl/nbl_include/nbl_def_resource.h
> +++ b/drivers/net/nbl/nbl_include/nbl_def_resource.h
> @@ -46,6 +46,14 @@ struct nbl_resource_ops {
>  void (*release_rx_ring)(void *priv, u16 queue_idx);
>  int (*get_stats)(void *priv, struct rte_eth_stats *rte_stats);
>  int (*reset_stats)(void *priv);
> + int (*get_txrx_xstats_cnt)(void *priv, u16 *xstats_cnt);
> + int (*get_txrx_xstats)(void *priv, struct rte_eth_xstat *xstats, u16 *xstats_cnt);
> + int (*get_txrx_xstats_names)(void *priv, struct rte_eth_xstat_name *xstats_names,
> +         u16 *xstats_cnt);
> + int (*get_hw_xstats_cnt)(void *priv, u16 *xstats_cnt);
> + int (*get_hw_xstats_names)(void *priv, struct rte_eth_xstat_name *xstats_names,
> +       u16 *xstats_cnt);
> + void (*get_private_stat_data)(void *priv, u32 eth_id, u64 *data);
>  void (*update_rx_ring)(void *priv, u16 queue_idx);
>  u16 (*get_tx_ehdr_len)(void *priv);
>  int (*alloc_txrx_queues)(void *priv, u16 vsi_id, u16 queue_num);
> @@ -58,10 +66,6 @@ struct nbl_resource_ops {
>  void (*cfg_txrx_vlan)(void *priv, u16 vlan_tci, u16 vlan_proto);
>  int (*txrx_burst_mode_get)(void *priv, struct rte_eth_dev *dev,
>        struct rte_eth_burst_mode *mode, bool is_tx);
> - int (*get_txrx_xstats_cnt)(void *priv, u16 *xstats_cnt);
> - int (*get_txrx_xstats)(void *priv, struct rte_eth_xstat *xstats, u16 *xstats_cnt);
> - int (*get_txrx_xstats_names)(void *priv, struct rte_eth_xstat_name *xstats_names,
> -         u16 *xstats_cnt);
>  int (*add_macvlan)(void *priv, u8 *mac, u16 vlan_id, u16 vsi_id);
>  void (*del_macvlan)(void *priv, u8 *mac, u16 vlan_id, u16 vsi_id);
>  int (*add_multi_rule)(void *priv, u16 vsi_id);
> diff --git a/drivers/net/nbl/nbl_include/nbl_include.h b/drivers/net/nbl/nbl_include/nbl_include.h
> index 14c41a0139..a0e18cec20 100644
> --- a/drivers/net/nbl/nbl_include/nbl_include.h
> +++ b/drivers/net/nbl/nbl_include/nbl_include.h
> @@ -50,6 +50,10 @@ typedef int32_t s32;
> typedef int16_t s16;
> typedef int8_t s8;
>
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(arr) RTE_DIM(arr)
> +#endif
> +
> /* Used for macros to pass checkpatch */
> #define NBL_NAME(x)    x
> #define BIT(a)     (1UL << (a))
> --
> 2.34.1
>
>

本邮件所含信息及其任何附件为保密信息且可能属于专有信息。任何非指定接收人均无权访问本邮件。如果您不是该邮件的指定接收人,那么任何对本邮件内容进行披露,复制或使用的行为均是禁止的。如果您不是该邮件的指定接收人,请您立即通过邮件通知 compliance@nebula-matrix.com并立即删除您错误接受的邮件。
The information in this message and any attachments is confidential and may be privileged.  Access to this email by anyone other than the intended recipient is not authorized.  If you are not the intended recipient, disclosure, copying or use of the contents of this email is prohibited.  If you are not the intended recipient, please notify  compliance@nebula-matrix.com immediately by email, and please destroy the email you received in error.