DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats
@ 2021-06-04 14:42 Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
                   ` (18 more replies)
  0 siblings, 19 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev

Rx/Tx doorbells stats are essential for performance investigation.

On the way fix ethdev documenation to refine requirements on
driver callback. It allows to make these callbacks a bit simpler.

Add testpmd option to show specified xstats periodically or upon
request, for example:

 * --display-xstats rx_good_packets,tx_good_packets --stats-period 1

 Port statistics ====================================
  ######################## NIC statistics for port 0  ########################
  RX-packets: 14102808   RX-missed: 0          RX-bytes:  7164239264
  RX-errors: 0
  RX-nombuf:  0
  TX-packets: 14102789   TX-errors: 0          TX-bytes:  7164226028

  Throughput (since last show)
  Rx-pps:      2349577          Rx-bps:   9548682392
  Tx-pps:      2349576          Tx-bps:   9548682408

                      Value                Rate (since last show)
  rx_good_packets     14103280             2349575
  tx_good_packets     14103626             2349573
  ############################################################################

 * -i --display-xstats tx_good_packets,vadapter_rx_overflow

testpmd> port start 0
...
No xstat 'vadapter_rx_overflow' on port 0 - skip it
...
testpmd> start tx_first
testpmd> show port stats all
                               Value            Rate (since last show)
  tx_good_packets             132545336         1420439

net/sfc part of the patch series should be applied on top of [1].

[1] https://patches.dpdk.org/project/dpdk/list/?series=17238

Ivan Ilchenko (11):
  net/sfc: fix get xstats by ID callback to use MAC stats lock
  net/sfc: fix reading adapter state without locking
  ethdev: fix docs of functions getting xstats by IDs
  ethdev: fix docs of drivers callbacks getting xstats by IDs
  net/sfc: fix xstats by ID callbacks according to ethdev
  net/sfc: fix accessing xstats by an unsorted list of IDs
  net/sfc: fix MAC stats update to work for stopped device
  net/sfc: simplify getting of available xstats case
  net/sfc: prepare to add more xstats
  net/sfc: add xstats for Rx/Tx doorbells
  app/testpmd: add option to display extended statistics

 app/test-pmd/cmdline.c                |  56 +++
 app/test-pmd/config.c                 |  66 +++
 app/test-pmd/parameters.c             |  18 +
 app/test-pmd/testpmd.c                | 122 ++++++
 app/test-pmd/testpmd.h                |  21 +
 doc/guides/testpmd_app_ug/run_app.rst |   5 +
 drivers/net/sfc/meson.build           |   1 +
 drivers/net/sfc/sfc.c                 |  16 +
 drivers/net/sfc/sfc.h                 |  18 +-
 drivers/net/sfc/sfc_dp.h              |  10 +
 drivers/net/sfc/sfc_ef10.h            |   3 +-
 drivers/net/sfc/sfc_ef100_rx.c        |   1 +
 drivers/net/sfc/sfc_ef100_tx.c        |   1 +
 drivers/net/sfc/sfc_ef10_essb_rx.c    |   3 +-
 drivers/net/sfc/sfc_ef10_rx.c         |   3 +-
 drivers/net/sfc/sfc_ef10_tx.c         |   1 +
 drivers/net/sfc/sfc_ethdev.c          | 185 +++++----
 drivers/net/sfc/sfc_port.c            | 127 +++++-
 drivers/net/sfc/sfc_rx.c              |   1 +
 drivers/net/sfc/sfc_sw_stats.c        | 572 ++++++++++++++++++++++++++
 drivers/net/sfc/sfc_sw_stats.h        |  49 +++
 drivers/net/sfc/sfc_tx.c              |   4 +-
 lib/ethdev/ethdev_driver.h            |  43 +-
 lib/ethdev/rte_ethdev.h               |  23 +-
 24 files changed, 1243 insertions(+), 106 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_sw_stats.c
 create mode 100644 drivers/net/sfc/sfc_sw_stats.h

-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 02/11] net/sfc: fix reading adapter state without locking Andrew Rybchenko
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, stable, Andy Moreton, Ivan Malov, Remy Horton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add MAC stats lock in get xstats by id callback before reading
number of supported MAC stats.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 88896db1f8..d4ac61ff76 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -789,12 +789,14 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	if (unlikely(values == NULL) ||
-	    unlikely((ids == NULL) && (n < port->mac_stats_nb_supported)))
-		return port->mac_stats_nb_supported;
-
 	rte_spinlock_lock(&port->mac_stats_lock);
 
+	if (unlikely(values == NULL) ||
+	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
+		ret = port->mac_stats_nb_supported;
+		goto unlock;
+	}
+
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 02/11] net/sfc: fix reading adapter state without locking
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, stable, Andy Moreton, Robert Stonehouse, Andrew Lee

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update MAC stats function reads adapter state with MAC stats locking
but without adapter locking. Add adapter locking before calling this
function and remove MAC stats locking since there's no point to have
it together with adapter locking. The second place MAC stats locking
is used is MAC stats reset function. It's called with adapter being
already locked so there's no point to use MAC stats locking anymore.

Fixes: 1caab2f1e68 ("net/sfc: add basic statistics")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  1 -
 drivers/net/sfc/sfc_ethdev.c | 28 ++++++++++++++++++++--------
 drivers/net/sfc/sfc_port.c   |  9 +++------
 3 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 546739bd4a..c7b0e5a30d 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -130,7 +130,6 @@ struct sfc_port {
 	unsigned int			nb_mcast_addrs;
 	uint8_t				*mcast_addrs;
 
-	rte_spinlock_t			mac_stats_lock;
 	uint64_t			*mac_stats_buf;
 	unsigned int			mac_stats_nb_supported;
 	efsys_mem_t			mac_stats_dma_mem;
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index d4ac61ff76..d5417e5e65 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -613,7 +613,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	uint64_t *mac_stats;
 	int ret;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	ret = sfc_port_update_mac_stats(sa);
 	if (ret != 0)
@@ -686,7 +686,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	}
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 	SFC_ASSERT(ret >= 0);
 	return -ret;
 }
@@ -698,12 +698,15 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	struct sfc_port *port = &sa->port;
 	int rc;
 
+	sfc_adapter_lock(sa);
+
 	if (sa->state != SFC_ADAPTER_STARTED) {
 		/*
 		 * The operation cannot be done if port is not started; it
 		 * will be scheduled to be done during the next port start
 		 */
 		port->mac_stats_reset_pending = B_TRUE;
+		sfc_adapter_unlock(sa);
 		return 0;
 	}
 
@@ -711,6 +714,8 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	if (rc != 0)
 		sfc_err(sa, "failed to reset statistics (rc = %d)", rc);
 
+	sfc_adapter_unlock(sa);
+
 	SFC_ASSERT(rc >= 0);
 	return -rc;
 }
@@ -726,7 +731,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	unsigned int i;
 	int nstats = 0;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
@@ -748,7 +753,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	}
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 
 	return nstats;
 }
@@ -789,7 +794,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	if (unlikely(values == NULL) ||
 	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
@@ -819,7 +824,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	ret = nb_written;
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 
 	return ret;
 }
@@ -835,9 +840,14 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int nb_written = 0;
 	unsigned int i;
 
+	sfc_adapter_lock(sa);
+
 	if (unlikely(xstats_names == NULL) ||
-	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported)))
-		return port->mac_stats_nb_supported;
+	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported))) {
+		nb_supported = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nb_supported;
+	}
 
 	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < size); ++i) {
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
@@ -853,6 +863,8 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		++nb_supported;
 	}
 
+	sfc_adapter_unlock(sa);
+
 	return nb_written;
 }
 
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index ac117f9c48..cdc0f94f19 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -43,7 +43,7 @@ sfc_port_update_mac_stats(struct sfc_adapter *sa)
 	unsigned int nb_attempts = 0;
 	int rc;
 
-	SFC_ASSERT(rte_spinlock_is_locked(&port->mac_stats_lock));
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
 	if (sa->state != SFC_ADAPTER_STARTED)
 		return EINVAL;
@@ -103,14 +103,13 @@ sfc_port_reset_sw_stats(struct sfc_adapter *sa)
 int
 sfc_port_reset_mac_stats(struct sfc_adapter *sa)
 {
-	struct sfc_port *port = &sa->port;
 	int rc;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
 	rc = efx_mac_stats_clear(sa->nic);
 	if (rc == 0)
 		sfc_port_reset_sw_stats(sa);
-	rte_spinlock_unlock(&port->mac_stats_lock);
 
 	return rc;
 }
@@ -416,8 +415,6 @@ sfc_port_attach(struct sfc_adapter *sa)
 		goto fail_mcast_addr_list_buf_alloc;
 	}
 
-	rte_spinlock_init(&port->mac_stats_lock);
-
 	rc = ENOMEM;
 	port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
 						sizeof(uint64_t), 0,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 02/11] net/sfc: fix reading adapter state without locking Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-07-20 16:25   ` Ferruh Yigit
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon,
	Ferruh Yigit, Kuba Kozak

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Document valid combinations of input arguments in accordance with
current implementation in ethdev.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index faf3bd901d..1f63118544 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  *   The port identifier of the Ethernet device.
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. If set to NULL, the function returns the required number
- *   of elements.
+ *   be filled. Must not be NULL if @p ids are specified (not NULL).
  * @param ids
- *   IDs array given by app to retrieve specific statistics
+ *   IDs array given by app to retrieve specific statistics. May be NULL
+ *   to retrieve all available statistics.
  * @param size
- *   The size of the xstats_names array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in @p xstats_names to put names in. If @p ids is
+ *   NULL, number of elements in @p xstats_names to put all available statistics
+ *   names in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int
 rte_eth_xstats_get_names_by_id(uint16_t port_id,
@@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  *   The port identifier of the Ethernet device.
  * @param ids
  *   A pointer to an ids array passed by application. This tells which
- *   statistics values function should retrieve. This parameter
- *   can be set to NULL if size is 0. In this case function will retrieve
+ *   statistics values function should retrieve. May be NULL to retrieve
  *   all available statistics.
  * @param values
  *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL if ids are specified (not NULL).
  * @param size
- *   The size of the ids array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in values to put statistics in. If @p ids is NULL,
+ *   number of elements in values to put all available statistics in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
 			     uint64_t *values, unsigned int size);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (2 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-07-20 16:51   ` Ferruh Yigit
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 05/11] net/sfc: fix xstats by ID callbacks according to ethdev Andrew Rybchenko
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon,
	Ferruh Yigit, Kuba Kozak

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 40e474aa7e..fd5b7ca550 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats of an Ethernet device.
+ * For name count, set @p xstats_names and @p ids to NULL.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Can be NULL together with @p ids to retrieve number of
+ *   available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param size
+ *   Size of ids and xstats_names arrays.
+ *   Element count in @p ids and @p xstats_names
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 05/11] net/sfc: fix xstats by ID callbacks according to ethdev
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (3 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs Andrew Rybchenko
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, stable, Andy Moreton, Remy Horton, Ivan Malov

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Fix xstats by ID callbacks according to ethdev usage.
Handle combinations of input arguments that are required by ethdev
and sanity check and reject other combinations on callback entry.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index d5417e5e65..fca3f524a1 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -794,13 +794,10 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	sfc_adapter_lock(sa);
+	if (unlikely(ids == NULL || values == NULL))
+		return -EINVAL;
 
-	if (unlikely(values == NULL) ||
-	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
-		ret = port->mac_stats_nb_supported;
-		goto unlock;
-	}
+	sfc_adapter_lock(sa);
 
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
@@ -815,7 +812,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
 			continue;
 
-		if ((ids == NULL) || (ids[nb_written] == nb_supported))
+		if (ids[nb_written] == nb_supported)
 			values[nb_written++] = mac_stats[i];
 
 		++nb_supported;
@@ -840,10 +837,13 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int nb_written = 0;
 	unsigned int i;
 
+	if (unlikely(xstats_names == NULL && ids != NULL) ||
+	    unlikely(xstats_names != NULL && ids == NULL))
+		return -EINVAL;
+
 	sfc_adapter_lock(sa);
 
-	if (unlikely(xstats_names == NULL) ||
-	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported))) {
+	if (unlikely(xstats_names == NULL && ids == NULL)) {
 		nb_supported = port->mac_stats_nb_supported;
 		sfc_adapter_unlock(sa);
 		return nb_supported;
@@ -853,7 +853,7 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
 			continue;
 
-		if ((ids == NULL) || (ids[nb_written] == nb_supported)) {
+		if (ids[nb_written] == nb_supported) {
 			char *name = xstats_names[nb_written++].name;
 
 			strlcpy(name, efx_mac_stat_name(sa->nic, i),
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (4 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 05/11] net/sfc: fix xstats by ID callbacks according to ethdev Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 07/11] net/sfc: fix MAC stats update to work for stopped device Andrew Rybchenko
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, stable, Andy Moreton, Remy Horton, Ivan Malov

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Device may support only some MAC stats. Add mapping from ids to subset
of supported MAC stats for each port.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  2 ++
 drivers/net/sfc/sfc_ethdev.c | 44 ++++++++++++++++++------------------
 drivers/net/sfc/sfc_port.c   | 29 ++++++++++++++++++------
 3 files changed, 46 insertions(+), 29 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index c7b0e5a30d..972d32606d 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -141,6 +141,8 @@ struct sfc_port {
 
 	uint32_t		mac_stats_mask[EFX_MAC_STATS_MASK_NPAGES];
 
+	unsigned int			mac_stats_by_id[EFX_MAC_NSTATS];
+
 	uint64_t			ipackets;
 };
 
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index fca3f524a1..ae9304f90f 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -788,8 +788,6 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
 	uint64_t *mac_stats;
-	unsigned int nb_supported = 0;
-	unsigned int nb_written = 0;
 	unsigned int i;
 	int ret;
 	int rc;
@@ -808,17 +806,19 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 	mac_stats = port->mac_stats_buf;
 
-	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < n); ++i) {
-		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			continue;
-
-		if (ids[nb_written] == nb_supported)
-			values[nb_written++] = mac_stats[i];
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
 
-		++nb_supported;
+	for (i = 0; i < n; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
+		} else {
+			ret = i;
+			goto unlock;
+		}
 	}
 
-	ret = nb_written;
+	ret = n;
 
 unlock:
 	sfc_adapter_unlock(sa);
@@ -833,8 +833,7 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
-	unsigned int nb_supported = 0;
-	unsigned int nb_written = 0;
+	unsigned int nb_supported;
 	unsigned int i;
 
 	if (unlikely(xstats_names == NULL && ids != NULL) ||
@@ -849,23 +848,24 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		return nb_supported;
 	}
 
-	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < size); ++i) {
-		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			continue;
-
-		if (ids[nb_written] == nb_supported) {
-			char *name = xstats_names[nb_written++].name;
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
 
-			strlcpy(name, efx_mac_stat_name(sa->nic, i),
+	for (i = 0; i < size; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			strlcpy(xstats_names[i].name,
+				efx_mac_stat_name(sa->nic,
+						 port->mac_stats_by_id[ids[i]]),
 				sizeof(xstats_names[0].name));
+		} else {
+			sfc_adapter_unlock(sa);
+			return i;
 		}
-
-		++nb_supported;
 	}
 
 	sfc_adapter_unlock(sa);
 
-	return nb_written;
+	return size;
 }
 
 static int
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index cdc0f94f19..bb9e01d96b 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -157,6 +157,27 @@ sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
 
 #endif
 
+static void
+sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
+{
+	unsigned int mac_stats_nb_supported = 0;
+	struct sfc_port *port = &sa->port;
+	unsigned int stat_idx;
+
+	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
+			       sizeof(port->mac_stats_mask));
+
+	for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
+		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
+			continue;
+
+		port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
+		mac_stats_nb_supported++;
+	}
+
+	port->mac_stats_nb_supported = mac_stats_nb_supported;
+}
+
 int
 sfc_port_start(struct sfc_adapter *sa)
 {
@@ -165,7 +186,6 @@ sfc_port_start(struct sfc_adapter *sa)
 	uint32_t phy_adv_cap;
 	const uint32_t phy_pause_caps =
 		((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
-	unsigned int i;
 
 	sfc_log_init(sa, "entry");
 
@@ -259,12 +279,7 @@ sfc_port_start(struct sfc_adapter *sa)
 		port->mac_stats_reset_pending = B_FALSE;
 	}
 
-	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
-			       sizeof(port->mac_stats_mask));
-
-	for (i = 0, port->mac_stats_nb_supported = 0; i < EFX_MAC_NSTATS; ++i)
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			port->mac_stats_nb_supported++;
+	sfc_port_fill_mac_stats_info(sa);
 
 	port->mac_stats_update_generation = 0;
 
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 07/11] net/sfc: fix MAC stats update to work for stopped device
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (5 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 08/11] net/sfc: simplify getting of available xstats case Andrew Rybchenko
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, stable, Andy Moreton, Andrew Lee, Robert Stonehouse

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Fixes: 1caab2f1e68 ("net/sfc: add basic statistics")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  2 +-
 drivers/net/sfc/sfc_ethdev.c |  6 +++---
 drivers/net/sfc/sfc_port.c   | 11 +++++++----
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 972d32606d..1594f934ba 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -422,7 +422,7 @@ int sfc_port_start(struct sfc_adapter *sa);
 void sfc_port_stop(struct sfc_adapter *sa);
 void sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 				struct rte_eth_link *link_info);
-int sfc_port_update_mac_stats(struct sfc_adapter *sa);
+int sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t manual_update);
 int sfc_port_reset_mac_stats(struct sfc_adapter *sa);
 int sfc_set_rx_mode(struct sfc_adapter *sa);
 int sfc_set_rx_mode_unchecked(struct sfc_adapter *sa);
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index ae9304f90f..bbc22723f6 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -615,7 +615,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 	sfc_adapter_lock(sa);
 
-	ret = sfc_port_update_mac_stats(sa);
+	ret = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (ret != 0)
 		goto unlock;
 
@@ -733,7 +733,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	sfc_adapter_lock(sa);
 
-	rc = sfc_port_update_mac_stats(sa);
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
 		nstats = -rc;
@@ -797,7 +797,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 	sfc_adapter_lock(sa);
 
-	rc = sfc_port_update_mac_stats(sa);
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
 		ret = -rc;
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index bb9e01d96b..8c432c15f5 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -26,7 +26,8 @@
 /**
  * Update MAC statistics in the buffer.
  *
- * @param	sa	Adapter
+ * @param	sa		Adapter
+ * @param	force_upload	Flag to upload MAC stats in any case
  *
  * @return Status code
  * @retval	0	Success
@@ -34,7 +35,7 @@
  * @retval	ENOMEM	Memory allocation failure
  */
 int
-sfc_port_update_mac_stats(struct sfc_adapter *sa)
+sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
 {
 	struct sfc_port *port = &sa->port;
 	efsys_mem_t *esmp = &port->mac_stats_dma_mem;
@@ -46,14 +47,14 @@ sfc_port_update_mac_stats(struct sfc_adapter *sa)
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
 	if (sa->state != SFC_ADAPTER_STARTED)
-		return EINVAL;
+		return 0;
 
 	/*
 	 * If periodic statistics DMA'ing is off or if not supported,
 	 * make a manual request and keep an eye on timer if need be
 	 */
 	if (!port->mac_stats_periodic_dma_supported ||
-	    (port->mac_stats_update_period_ms == 0)) {
+	    (port->mac_stats_update_period_ms == 0) || force_upload) {
 		if (port->mac_stats_update_period_ms != 0) {
 			uint64_t timestamp = sfc_get_system_msecs();
 
@@ -367,6 +368,8 @@ sfc_port_stop(struct sfc_adapter *sa)
 	(void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
 				     0, B_FALSE);
 
+	sfc_port_update_mac_stats(sa, B_TRUE);
+
 	efx_port_fini(sa->nic);
 	efx_filter_fini(sa->nic);
 
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 08/11] net/sfc: simplify getting of available xstats case
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (6 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 07/11] net/sfc: fix MAC stats update to work for stopped device Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 09/11] net/sfc: prepare to add more xstats Andrew Rybchenko
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

There is no point to recalculate number of available xstats on
each request. The number is calculated once on device start
and may be returned on subsequent calls.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index bbc22723f6..f0567a71d0 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -733,6 +733,11 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	sfc_adapter_lock(sa);
 
+	if (unlikely(xstats == NULL)) {
+		nstats = port->mac_stats_nb_supported;
+		goto unlock;
+	}
+
 	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
@@ -744,7 +749,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (xstats != NULL && nstats < (int)xstats_count) {
+			if (nstats < (int)xstats_count) {
 				xstats[nstats].id = nstats;
 				xstats[nstats].value = mac_stats[i];
 			}
@@ -768,9 +773,16 @@ sfc_xstats_get_names(struct rte_eth_dev *dev,
 	unsigned int i;
 	unsigned int nstats = 0;
 
+	if (unlikely(xstats_names == NULL)) {
+		sfc_adapter_lock(sa);
+		nstats = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nstats;
+	}
+
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (xstats_names != NULL && nstats < xstats_count)
+			if (nstats < xstats_count)
 				strlcpy(xstats_names[nstats].name,
 					efx_mac_stat_name(sa->nic, i),
 					sizeof(xstats_names[0].name));
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 09/11] net/sfc: prepare to add more xstats
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (7 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 08/11] net/sfc: simplify getting of available xstats case Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 10/11] net/sfc: add xstats for Rx/Tx doorbells Andrew Rybchenko
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Move getting MAC stats code that involves locking to separate functions
to simplify addition of new xstats.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  4 ++
 drivers/net/sfc/sfc_ethdev.c | 73 ++++----------------------------
 drivers/net/sfc/sfc_port.c   | 80 ++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 65 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 1594f934ba..58b8c2c2ad 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -423,6 +423,10 @@ void sfc_port_stop(struct sfc_adapter *sa);
 void sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 				struct rte_eth_link *link_info);
 int sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t manual_update);
+int sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
+			   unsigned int xstats_count, unsigned int *nb_written);
+int sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				 uint64_t *values, unsigned int n);
 int sfc_port_reset_mac_stats(struct sfc_adapter *sa);
 int sfc_set_rx_mode(struct sfc_adapter *sa);
 int sfc_set_rx_mode_unchecked(struct sfc_adapter *sa);
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index f0567a71d0..dd7e5c253a 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -726,41 +726,17 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
-	uint64_t *mac_stats;
-	int rc;
-	unsigned int i;
-	int nstats = 0;
-
-	sfc_adapter_lock(sa);
+	unsigned int nb_written = 0;
+	unsigned int nb_supp;
 
 	if (unlikely(xstats == NULL)) {
-		nstats = port->mac_stats_nb_supported;
-		goto unlock;
-	}
-
-	rc = sfc_port_update_mac_stats(sa, B_FALSE);
-	if (rc != 0) {
-		SFC_ASSERT(rc > 0);
-		nstats = -rc;
-		goto unlock;
-	}
-
-	mac_stats = port->mac_stats_buf;
-
-	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < (int)xstats_count) {
-				xstats[nstats].id = nstats;
-				xstats[nstats].value = mac_stats[i];
-			}
-			nstats++;
-		}
+		sfc_adapter_lock(sa);
+		nb_supp = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nb_supp;
 	}
 
-unlock:
-	sfc_adapter_unlock(sa);
-
-	return nstats;
+	return sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
 }
 
 static int
@@ -798,44 +774,11 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
-	uint64_t *mac_stats;
-	unsigned int i;
-	int ret;
-	int rc;
 
 	if (unlikely(ids == NULL || values == NULL))
 		return -EINVAL;
 
-	sfc_adapter_lock(sa);
-
-	rc = sfc_port_update_mac_stats(sa, B_FALSE);
-	if (rc != 0) {
-		SFC_ASSERT(rc > 0);
-		ret = -rc;
-		goto unlock;
-	}
-
-	mac_stats = port->mac_stats_buf;
-
-	SFC_ASSERT(port->mac_stats_nb_supported <=
-		   RTE_DIM(port->mac_stats_by_id));
-
-	for (i = 0; i < n; i++) {
-		if (ids[i] < port->mac_stats_nb_supported) {
-			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
-		} else {
-			ret = i;
-			goto unlock;
-		}
-	}
-
-	ret = n;
-
-unlock:
-	sfc_adapter_unlock(sa);
-
-	return ret;
+	return sfc_port_get_mac_stats_by_id(sa, ids, values, n);
 }
 
 static int
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index 8c432c15f5..f6689a17c0 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -636,3 +636,83 @@ sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 
 	link_info->link_autoneg = ETH_LINK_AUTONEG;
 }
+
+int
+sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
+		       unsigned int xstats_count, unsigned int *nb_written)
+{
+	struct sfc_port *port = &sa->port;
+	uint64_t *mac_stats;
+	unsigned int i;
+	int nstats = 0;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	ret = sfc_port_update_mac_stats(sa, B_FALSE);
+	if (ret != 0) {
+		SFC_ASSERT(ret > 0);
+		ret = -ret;
+		goto unlock;
+	}
+
+	mac_stats = port->mac_stats_buf;
+
+	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
+		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
+			if (nstats < (int)xstats_count) {
+				xstats[nstats].id = nstats;
+				xstats[nstats].value = mac_stats[i];
+				(*nb_written)++;
+			}
+			nstats++;
+		}
+	}
+	ret = nstats;
+
+unlock:
+	sfc_adapter_unlock(sa);
+
+	return ret;
+}
+
+int
+sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+			     uint64_t *values, unsigned int n)
+{
+	struct sfc_port *port = &sa->port;
+	uint64_t *mac_stats;
+	unsigned int i;
+	int ret;
+	int rc;
+
+	sfc_adapter_lock(sa);
+
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
+	if (rc != 0) {
+		SFC_ASSERT(rc > 0);
+		ret = -rc;
+		goto unlock;
+	}
+
+	mac_stats = port->mac_stats_buf;
+
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
+
+	for (i = 0; i < n; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
+		} else {
+			ret = i;
+			goto unlock;
+		}
+	}
+
+	ret = n;
+
+unlock:
+	sfc_adapter_unlock(sa);
+
+	return ret;
+}
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 10/11] net/sfc: add xstats for Rx/Tx doorbells
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (8 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 09/11] net/sfc: prepare to add more xstats Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Rx/Tx doorbells statistics are collected in software and
available per queue. These stats are useful for performance
investigation.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/meson.build        |   1 +
 drivers/net/sfc/sfc.c              |  16 +
 drivers/net/sfc/sfc.h              |   9 +
 drivers/net/sfc/sfc_dp.h           |  10 +
 drivers/net/sfc/sfc_ef10.h         |   3 +-
 drivers/net/sfc/sfc_ef100_rx.c     |   1 +
 drivers/net/sfc/sfc_ef100_tx.c     |   1 +
 drivers/net/sfc/sfc_ef10_essb_rx.c |   3 +-
 drivers/net/sfc/sfc_ef10_rx.c      |   3 +-
 drivers/net/sfc/sfc_ef10_tx.c      |   1 +
 drivers/net/sfc/sfc_ethdev.c       | 124 +++++--
 drivers/net/sfc/sfc_port.c         |  10 +-
 drivers/net/sfc/sfc_rx.c           |   1 +
 drivers/net/sfc/sfc_sw_stats.c     | 572 +++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_sw_stats.h     |  49 +++
 drivers/net/sfc/sfc_tx.c           |   4 +-
 16 files changed, 772 insertions(+), 36 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_sw_stats.c
 create mode 100644 drivers/net/sfc/sfc_sw_stats.h

diff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build
index 32b58e3d76..c40c8e12fe 100644
--- a/drivers/net/sfc/meson.build
+++ b/drivers/net/sfc/meson.build
@@ -56,6 +56,7 @@ sources = files(
         'sfc.c',
         'sfc_mcdi.c',
         'sfc_sriov.c',
+        'sfc_sw_stats.c',
         'sfc_intr.c',
         'sfc_ev.c',
         'sfc_port.c',
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 4097cf39de..274a98e228 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -24,6 +24,7 @@
 #include "sfc_tx.h"
 #include "sfc_kvargs.h"
 #include "sfc_tweak.h"
+#include "sfc_sw_stats.h"
 
 
 int
@@ -636,10 +637,17 @@ sfc_configure(struct sfc_adapter *sa)
 	if (rc != 0)
 		goto fail_tx_configure;
 
+	rc = sfc_sw_xstats_configure(sa);
+	if (rc != 0)
+		goto fail_sw_xstats_configure;
+
 	sa->state = SFC_ADAPTER_CONFIGURED;
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_sw_xstats_configure:
+	sfc_tx_close(sa);
+
 fail_tx_configure:
 	sfc_rx_close(sa);
 
@@ -666,6 +674,7 @@ sfc_close(struct sfc_adapter *sa)
 	SFC_ASSERT(sa->state == SFC_ADAPTER_CONFIGURED);
 	sa->state = SFC_ADAPTER_CLOSING;
 
+	sfc_sw_xstats_close(sa);
 	sfc_tx_close(sa);
 	sfc_rx_close(sa);
 	sfc_port_close(sa);
@@ -891,6 +900,10 @@ sfc_attach(struct sfc_adapter *sa)
 
 	sfc_flow_init(sa);
 
+	rc = sfc_sw_xstats_init(sa);
+	if (rc != 0)
+		goto fail_sw_xstats_init;
+
 	/*
 	 * Create vSwitch to be able to use VFs when PF is not started yet
 	 * as DPDK port. VFs should be able to talk to each other even
@@ -906,6 +919,9 @@ sfc_attach(struct sfc_adapter *sa)
 	return 0;
 
 fail_sriov_vswitch_create:
+	sfc_sw_xstats_close(sa);
+
+fail_sw_xstats_init:
 	sfc_flow_fini(sa);
 	sfc_mae_detach(sa);
 
diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 58b8c2c2ad..331e06bac6 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -217,6 +217,14 @@ struct sfc_counter_rxq {
 	struct rte_mempool		*mp;
 };
 
+struct sfc_sw_xstats {
+	uint64_t			*reset_vals;
+
+	rte_spinlock_t			queues_bitmap_lock;
+	void				*queues_bitmap_mem;
+	struct rte_bitmap		*queues_bitmap;
+};
+
 /* Adapter private data */
 struct sfc_adapter {
 	/*
@@ -249,6 +257,7 @@ struct sfc_adapter {
 	struct sfc_sriov		sriov;
 	struct sfc_intr			intr;
 	struct sfc_port			port;
+	struct sfc_sw_xstats		sw_xstats;
 	struct sfc_filter		filter;
 	struct sfc_mae			mae;
 
diff --git a/drivers/net/sfc/sfc_dp.h b/drivers/net/sfc/sfc_dp.h
index 61c1a3fbac..7fd8f34b0f 100644
--- a/drivers/net/sfc/sfc_dp.h
+++ b/drivers/net/sfc/sfc_dp.h
@@ -42,6 +42,16 @@ enum sfc_dp_type {
 
 /** Datapath queue run-time information */
 struct sfc_dp_queue {
+	/*
+	 * Typically the structure is located at the end of Rx/Tx queue
+	 * data structure and not used on datapath. So, it is not a
+	 * problem to have extra fields even if not used. However,
+	 * put stats at top of the structure to be closer to fields
+	 * used on datapath or reap to have more chances to be cache-hot.
+	 */
+	uint32_t			rx_dbells;
+	uint32_t			tx_dbells;
+
 	uint16_t			port_id;
 	uint16_t			queue_id;
 	struct rte_pci_addr		pci_addr;
diff --git a/drivers/net/sfc/sfc_ef10.h b/drivers/net/sfc/sfc_ef10.h
index ad4c1fdbef..e9bb72e28b 100644
--- a/drivers/net/sfc/sfc_ef10.h
+++ b/drivers/net/sfc/sfc_ef10.h
@@ -99,7 +99,7 @@ sfc_ef10_ev_present(const efx_qword_t ev)
 
 static inline void
 sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,
-		  unsigned int ptr_mask)
+		  unsigned int ptr_mask, uint32_t *dbell_counter)
 {
 	efx_dword_t dword;
 
@@ -118,6 +118,7 @@ sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], doorbell);
+	(*dbell_counter)++;
 }
 
 static inline void
diff --git a/drivers/net/sfc/sfc_ef100_rx.c b/drivers/net/sfc/sfc_ef100_rx.c
index 7447f8b9de..832236a6d0 100644
--- a/drivers/net/sfc/sfc_ef100_rx.c
+++ b/drivers/net/sfc/sfc_ef100_rx.c
@@ -119,6 +119,7 @@ sfc_ef100_rx_qpush(struct sfc_ef100_rxq *rxq, unsigned int added)
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], rxq->doorbell);
+	rxq->dp.dpq.rx_dbells++;
 
 	sfc_ef100_rx_debug(rxq, "RxQ pushed doorbell at pidx %u (added=%u)",
 			   EFX_DWORD_FIELD(dword, ERF_GZ_RX_RING_PIDX),
diff --git a/drivers/net/sfc/sfc_ef100_tx.c b/drivers/net/sfc/sfc_ef100_tx.c
index f9ad6f7b73..522e9a0d34 100644
--- a/drivers/net/sfc/sfc_ef100_tx.c
+++ b/drivers/net/sfc/sfc_ef100_tx.c
@@ -489,6 +489,7 @@ sfc_ef100_tx_qpush(struct sfc_ef100_txq *txq, unsigned int added)
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], txq->doorbell);
+	txq->dp.dpq.tx_dbells++;
 
 	sfc_ef100_tx_debug(txq, "TxQ pushed doorbell at pidx %u (added=%u)",
 			   EFX_DWORD_FIELD(dword, ERF_GZ_TX_RING_PIDX),
diff --git a/drivers/net/sfc/sfc_ef10_essb_rx.c b/drivers/net/sfc/sfc_ef10_essb_rx.c
index 3c246eb149..991329e86f 100644
--- a/drivers/net/sfc/sfc_ef10_essb_rx.c
+++ b/drivers/net/sfc/sfc_ef10_essb_rx.c
@@ -220,7 +220,8 @@ sfc_ef10_essb_rx_qrefill(struct sfc_ef10_essb_rxq *rxq)
 
 	SFC_ASSERT(rxq->added != added);
 	rxq->added = added;
-	sfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask);
+	sfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask,
+			  &rxq->dp.dpq.rx_dbells);
 }
 
 static bool
diff --git a/drivers/net/sfc/sfc_ef10_rx.c b/drivers/net/sfc/sfc_ef10_rx.c
index 2b4393d232..49a7d4fb42 100644
--- a/drivers/net/sfc/sfc_ef10_rx.c
+++ b/drivers/net/sfc/sfc_ef10_rx.c
@@ -171,7 +171,8 @@ sfc_ef10_rx_qrefill(struct sfc_ef10_rxq *rxq)
 
 	SFC_ASSERT(rxq->added != added);
 	rxq->added = added;
-	sfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask);
+	sfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask,
+			  &rxq->dp.dpq.rx_dbells);
 }
 
 static void
diff --git a/drivers/net/sfc/sfc_ef10_tx.c b/drivers/net/sfc/sfc_ef10_tx.c
index a8d34ead33..ed43adb4ca 100644
--- a/drivers/net/sfc/sfc_ef10_tx.c
+++ b/drivers/net/sfc/sfc_ef10_tx.c
@@ -248,6 +248,7 @@ sfc_ef10_tx_qpush(struct sfc_ef10_txq *txq, unsigned int added,
 	rte_io_wmb();
 
 	*(volatile efsys_uint128_t *)txq->doorbell = oword.eo_u128[0];
+	txq->dp.dpq.tx_dbells++;
 }
 
 static unsigned int
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index dd7e5c253a..2db0d000c3 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -28,6 +28,10 @@
 #include "sfc_flow.h"
 #include "sfc_dp.h"
 #include "sfc_dp_rx.h"
+#include "sfc_sw_stats.h"
+
+#define SFC_XSTAT_ID_INVALID_VAL  UINT64_MAX
+#define SFC_XSTAT_ID_INVALID_NAME '\0'
 
 uint32_t sfc_logtype_driver;
 
@@ -714,29 +718,49 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	if (rc != 0)
 		sfc_err(sa, "failed to reset statistics (rc = %d)", rc);
 
+	sfc_sw_xstats_reset(sa);
+
 	sfc_adapter_unlock(sa);
 
 	SFC_ASSERT(rc >= 0);
 	return -rc;
 }
 
+static unsigned int
+sfc_xstats_get_nb_supported(struct sfc_adapter *sa)
+{
+	struct sfc_port *port = &sa->port;
+	unsigned int nb_supported;
+
+	sfc_adapter_lock(sa);
+	nb_supported = port->mac_stats_nb_supported +
+		       sfc_sw_xstats_get_nb_supported(sa);
+	sfc_adapter_unlock(sa);
+
+	return nb_supported;
+}
+
 static int
 sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	       unsigned int xstats_count)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
 	unsigned int nb_written = 0;
-	unsigned int nb_supp;
+	unsigned int nb_supported = 0;
+	int rc;
 
-	if (unlikely(xstats == NULL)) {
-		sfc_adapter_lock(sa);
-		nb_supp = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nb_supp;
-	}
+	if (unlikely(xstats == NULL))
+		return sfc_xstats_get_nb_supported(sa);
+
+	rc = sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
+	if (rc < 0)
+		return rc;
 
-	return sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
+	nb_supported = rc;
+	sfc_sw_xstats_get_vals(sa, xstats, xstats_count, &nb_written,
+			       &nb_supported);
+
+	return nb_supported;
 }
 
 static int
@@ -748,24 +772,31 @@ sfc_xstats_get_names(struct rte_eth_dev *dev,
 	struct sfc_port *port = &sa->port;
 	unsigned int i;
 	unsigned int nstats = 0;
+	unsigned int nb_written = 0;
+	int ret;
 
-	if (unlikely(xstats_names == NULL)) {
-		sfc_adapter_lock(sa);
-		nstats = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nstats;
-	}
+	if (unlikely(xstats_names == NULL))
+		return sfc_xstats_get_nb_supported(sa);
 
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < xstats_count)
+			if (nstats < xstats_count) {
 				strlcpy(xstats_names[nstats].name,
 					efx_mac_stat_name(sa->nic, i),
 					sizeof(xstats_names[0].name));
+				nb_written++;
+			}
 			nstats++;
 		}
 	}
 
+	ret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,
+				      &nb_written, &nstats);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
 	return nstats;
 }
 
@@ -774,11 +805,35 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+	struct sfc_port *port = &sa->port;
+	unsigned int nb_supported;
+	unsigned int i;
+	int rc;
 
 	if (unlikely(ids == NULL || values == NULL))
 		return -EINVAL;
 
-	return sfc_port_get_mac_stats_by_id(sa, ids, values, n);
+	/*
+	 * Values array could be filled in nonsequential order. Fill values with
+	 * constant indicating invalid ID first.
+	 */
+	for (i = 0; i < n; i++)
+		values[i] = SFC_XSTAT_ID_INVALID_VAL;
+
+	rc = sfc_port_get_mac_stats_by_id(sa, ids, values, n);
+	if (rc != 0)
+		return rc;
+
+	nb_supported = port->mac_stats_nb_supported;
+	sfc_sw_xstats_get_vals_by_id(sa, ids, values, n, &nb_supported);
+
+	/* Return number of written stats before invalid ID is encountered. */
+	for (i = 0; i < n; i++) {
+		if (values[i] == SFC_XSTAT_ID_INVALID_VAL)
+			return i;
+	}
+
+	return n;
 }
 
 static int
@@ -790,18 +845,23 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	struct sfc_port *port = &sa->port;
 	unsigned int nb_supported;
 	unsigned int i;
+	int ret;
 
 	if (unlikely(xstats_names == NULL && ids != NULL) ||
 	    unlikely(xstats_names != NULL && ids == NULL))
 		return -EINVAL;
 
-	sfc_adapter_lock(sa);
+	if (unlikely(xstats_names == NULL && ids == NULL))
+		return sfc_xstats_get_nb_supported(sa);
 
-	if (unlikely(xstats_names == NULL && ids == NULL)) {
-		nb_supported = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nb_supported;
-	}
+	/*
+	 * Names array could be filled in nonsequential order. Fill names with
+	 * string indicating invalid ID first.
+	 */
+	for (i = 0; i < size; i++)
+		xstats_names[i].name[0] = SFC_XSTAT_ID_INVALID_NAME;
+
+	sfc_adapter_lock(sa);
 
 	SFC_ASSERT(port->mac_stats_nb_supported <=
 		   RTE_DIM(port->mac_stats_by_id));
@@ -812,14 +872,26 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 				efx_mac_stat_name(sa->nic,
 						 port->mac_stats_by_id[ids[i]]),
 				sizeof(xstats_names[0].name));
-		} else {
-			sfc_adapter_unlock(sa);
-			return i;
 		}
 	}
 
+	nb_supported = port->mac_stats_nb_supported;
+
 	sfc_adapter_unlock(sa);
 
+	ret = sfc_sw_xstats_get_names_by_id(sa, ids, xstats_names, size,
+					    &nb_supported);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
+	/* Return number of written names before invalid ID is encountered. */
+	for (i = 0; i < size; i++) {
+		if (xstats_names[i].name[0] == SFC_XSTAT_ID_INVALID_NAME)
+			return i;
+	}
+
 	return size;
 }
 
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index f6689a17c0..adb2b2cb81 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -7,6 +7,8 @@
  * for Solarflare) and Solarflare Communications, Inc.
  */
 
+#include <rte_bitmap.h>
+
 #include "efx.h"
 
 #include "sfc.h"
@@ -701,15 +703,11 @@ sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
 		   RTE_DIM(port->mac_stats_by_id));
 
 	for (i = 0; i < n; i++) {
-		if (ids[i] < port->mac_stats_nb_supported) {
+		if (ids[i] < port->mac_stats_nb_supported)
 			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
-		} else {
-			ret = i;
-			goto unlock;
-		}
 	}
 
-	ret = n;
+	ret = 0;
 
 unlock:
 	sfc_adapter_unlock(sa);
diff --git a/drivers/net/sfc/sfc_rx.c b/drivers/net/sfc/sfc_rx.c
index f6a8ac68e8..280e8a61f9 100644
--- a/drivers/net/sfc/sfc_rx.c
+++ b/drivers/net/sfc/sfc_rx.c
@@ -138,6 +138,7 @@ sfc_efx_rx_qrefill(struct sfc_efx_rxq *rxq)
 	SFC_ASSERT(added != rxq->added);
 	rxq->added = added;
 	efx_rx_qpush(rxq->common, added, &rxq->pushed);
+	rxq->dp.dpq.rx_dbells++;
 }
 
 static uint64_t
diff --git a/drivers/net/sfc/sfc_sw_stats.c b/drivers/net/sfc/sfc_sw_stats.c
new file mode 100644
index 0000000000..8489b603f5
--- /dev/null
+++ b/drivers/net/sfc/sfc_sw_stats.c
@@ -0,0 +1,572 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2021 Xilinx, Inc.
+ */
+#include <rte_dev.h>
+#include <rte_bitmap.h>
+
+#include "sfc.h"
+#include "sfc_rx.h"
+#include "sfc_tx.h"
+#include "sfc_sw_stats.h"
+
+enum sfc_sw_stats_type {
+	SFC_SW_STATS_RX,
+	SFC_SW_STATS_TX,
+};
+
+typedef uint64_t sfc_get_sw_xstat_val_t(struct sfc_adapter *sa, uint16_t qid);
+
+struct sfc_sw_xstat_descr {
+	const char *name;
+	enum sfc_sw_stats_type type;
+	sfc_get_sw_xstat_val_t *get_val;
+};
+
+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_rx_dbells;
+static uint64_t
+sfc_get_sw_xstat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	struct sfc_rxq_info *rxq_info;
+
+	rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);
+	if (rxq_info->state & SFC_RXQ_INITIALIZED)
+		return rxq_info->dp->dpq.rx_dbells;
+	return 0;
+}
+
+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_tx_dbells;
+static uint64_t
+sfc_get_sw_xstat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	struct sfc_txq_info *txq_info;
+
+	txq_info = sfc_txq_info_by_ethdev_qid(sas, qid);
+	if (txq_info->state & SFC_TXQ_INITIALIZED)
+		return txq_info->dp->dpq.tx_dbells;
+	return 0;
+}
+
+struct sfc_sw_xstat_descr sfc_sw_xstats[] = {
+	{
+		.name = "dbells",
+		.type = SFC_SW_STATS_RX,
+		.get_val  = sfc_get_sw_xstat_val_rx_dbells,
+	},
+	{
+		.name = "dbells",
+		.type = SFC_SW_STATS_TX,
+		.get_val  = sfc_get_sw_xstat_val_tx_dbells,
+	}
+};
+
+static int
+sfc_sw_stat_get_name(struct sfc_adapter *sa,
+		     const struct sfc_sw_xstat_descr *sw_xstat, char *name,
+		     size_t name_size, unsigned int id_off)
+{
+	const char *prefix;
+	int ret;
+
+	switch (sw_xstat->type) {
+	case SFC_SW_STATS_RX:
+		prefix = "rx";
+		break;
+	case SFC_SW_STATS_TX:
+		prefix = "tx";
+		break;
+	default:
+		sfc_err(sa, "%s: unknown software statistics type %d",
+			__func__, sw_xstat->type);
+		return -EINVAL;
+	}
+
+	if (id_off == 0) {
+		ret = snprintf(name, name_size, "%s_%s", prefix,
+							 sw_xstat->name);
+		if (ret < 0 || ret >= (int)name_size) {
+			sfc_err(sa, "%s: failed to fill xstat name %s_%s, err %d",
+				__func__, prefix, sw_xstat->name, ret);
+			return ret > 0 ? -EINVAL : ret;
+		}
+	} else {
+		uint16_t qid = id_off - 1;
+		ret = snprintf(name, name_size, "%s_q%u_%s", prefix, qid,
+							sw_xstat->name);
+		if (ret < 0 || ret >= (int)name_size) {
+			sfc_err(sa, "%s: failed to fill xstat name %s_q%u_%s, err %d",
+				__func__, prefix, qid, sw_xstat->name, ret);
+			return ret > 0 ? -EINVAL : ret;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned int
+sfc_sw_stat_get_queue_count(struct sfc_adapter *sa,
+			    const struct sfc_sw_xstat_descr *sw_xstat)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+
+	switch (sw_xstat->type) {
+	case SFC_SW_STATS_RX:
+		return sas->ethdev_rxq_count;
+	case SFC_SW_STATS_TX:
+		return sas->ethdev_txq_count;
+	default:
+		sfc_err(sa, "%s: unknown software statistics type %d",
+			__func__, sw_xstat->type);
+		return 0;
+	}
+}
+
+static unsigned int
+sfc_sw_xstat_per_queue_get_count(unsigned int nb_queues)
+{
+	/* Take into account the accumulative xstat of all queues */
+	return nb_queues > 0 ? 1 + nb_queues : 0;
+}
+
+static unsigned int
+sfc_sw_xstat_get_nb_supported(struct sfc_adapter *sa,
+			      const struct sfc_sw_xstat_descr *sw_xstat)
+{
+	unsigned int nb_queues;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	return sfc_sw_xstat_per_queue_get_count(nb_queues);
+}
+
+static int
+sfc_sw_stat_get_names(struct sfc_adapter *sa,
+		      const struct sfc_sw_xstat_descr *sw_xstat,
+		      struct rte_eth_xstat_name *xstats_names,
+		      unsigned int xstats_names_sz,
+		      unsigned int *nb_written,
+		      unsigned int *nb_supported)
+{
+	const size_t name_size = sizeof(xstats_names[0].name);
+	unsigned int id_base = *nb_supported;
+	unsigned int nb_queues;
+	unsigned int qid;
+	int rc;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return 0;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	if (*nb_written < xstats_names_sz) {
+		rc = sfc_sw_stat_get_name(sa, sw_xstat,
+					  xstats_names[*nb_written].name,
+					  name_size, *nb_written - id_base);
+		if (rc != 0)
+			return rc;
+		(*nb_written)++;
+	}
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		if (*nb_written < xstats_names_sz) {
+			rc = sfc_sw_stat_get_name(sa, sw_xstat,
+					      xstats_names[*nb_written].name,
+					      name_size, *nb_written - id_base);
+			if (rc != 0)
+				return rc;
+			(*nb_written)++;
+		}
+	}
+
+	return 0;
+}
+
+static int
+sfc_sw_xstat_get_names_by_id(struct sfc_adapter *sa,
+			     const struct sfc_sw_xstat_descr *sw_xstat,
+			     const uint64_t *ids,
+			     struct rte_eth_xstat_name *xstats_names,
+			     unsigned int size,
+			     unsigned int *nb_supported)
+{
+	const size_t name_size = sizeof(xstats_names[0].name);
+	unsigned int id_base = *nb_supported;
+	unsigned int nb_queues;
+	unsigned int i;
+	int rc;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return 0;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	for (i = 0; i < size; i++) {
+		if (id_base <= ids[i] && ids[i] <= id_base + nb_queues) {
+			rc = sfc_sw_stat_get_name(sa, sw_xstat,
+						  xstats_names[i].name,
+						  name_size, ids[i] - id_base);
+			if (rc != 0)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static void
+sfc_sw_xstat_get_values(struct sfc_adapter *sa,
+			const struct sfc_sw_xstat_descr *sw_xstat,
+			struct rte_eth_xstat *xstats,
+			unsigned int xstats_size,
+			unsigned int *nb_written,
+			unsigned int *nb_supported)
+{
+	unsigned int qid;
+	uint64_t value;
+	struct rte_eth_xstat *accum_xstat;
+	bool count_accum_value = false;
+	unsigned int nb_queues;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	if (*nb_written < xstats_size) {
+		count_accum_value = true;
+		accum_xstat = &xstats[*nb_written];
+		xstats[*nb_written].id = *nb_written;
+		xstats[*nb_written].value = 0;
+		(*nb_written)++;
+	}
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		value = sw_xstat->get_val(sa, qid);
+
+		if (*nb_written < xstats_size) {
+			xstats[*nb_written].id = *nb_written;
+			xstats[*nb_written].value = value;
+			(*nb_written)++;
+		}
+
+		if (count_accum_value)
+			accum_xstat->value += value;
+	}
+}
+
+static void
+sfc_sw_xstat_get_values_by_id(struct sfc_adapter *sa,
+			      const struct sfc_sw_xstat_descr *sw_xstat,
+			      const uint64_t *ids,
+			      uint64_t *values,
+			      unsigned int ids_size,
+			      unsigned int *nb_supported)
+{
+	rte_spinlock_t *bmp_lock = &sa->sw_xstats.queues_bitmap_lock;
+	struct rte_bitmap *bmp = sa->sw_xstats.queues_bitmap;
+	unsigned int id_base = *nb_supported;
+	bool count_accum_value = false;
+	unsigned int accum_value_idx;
+	uint64_t accum_value = 0;
+	unsigned int i, qid;
+	unsigned int nb_queues;
+
+
+	rte_spinlock_lock(bmp_lock);
+	rte_bitmap_reset(bmp);
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		goto unlock;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	for (i = 0; i < ids_size; i++) {
+		if (id_base <= ids[i] && ids[i] <= (id_base + nb_queues)) {
+			if (ids[i] == id_base) { /* Accumulative value */
+				count_accum_value = true;
+				accum_value_idx = i;
+				continue;
+			}
+			qid = ids[i] - id_base - 1;
+			values[i] = sw_xstat->get_val(sa, qid);
+			accum_value += values[i];
+
+			rte_bitmap_set(bmp, qid);
+		}
+	}
+
+	if (count_accum_value) {
+		for (qid = 0; qid < nb_queues; ++qid) {
+			if (rte_bitmap_get(bmp, qid) != 0)
+				continue;
+			values[accum_value_idx] += sw_xstat->get_val(sa, qid);
+		}
+		values[accum_value_idx] += accum_value;
+	}
+
+unlock:
+	rte_spinlock_unlock(bmp_lock);
+}
+
+unsigned int
+sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa)
+{
+	unsigned int nb_supported = 0;
+	unsigned int i;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
+							     &sfc_sw_xstats[i]);
+	}
+
+	return nb_supported;
+}
+
+void
+sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
+		       struct rte_eth_xstat *xstats,
+		       unsigned int xstats_count,
+		       unsigned int *nb_written,
+		       unsigned int *nb_supported)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	unsigned int sw_xstats_offset;
+	unsigned int i;
+
+	sfc_adapter_lock(sa);
+
+	sw_xstats_offset = *nb_supported;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sfc_sw_xstat_get_values(sa, &sfc_sw_xstats[i], xstats,
+					xstats_count, nb_written, nb_supported);
+	}
+
+	for (i = sw_xstats_offset; i < *nb_written; i++)
+		xstats[i].value -= reset_vals[i - sw_xstats_offset];
+
+	sfc_adapter_unlock(sa);
+}
+
+int
+sfc_sw_xstats_get_names(struct sfc_adapter *sa,
+			struct rte_eth_xstat_name *xstats_names,
+			unsigned int xstats_count,
+			unsigned int *nb_written,
+			unsigned int *nb_supported)
+{
+	unsigned int i;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		ret = sfc_sw_stat_get_names(sa, &sfc_sw_xstats[i],
+					    xstats_names, xstats_count,
+					    nb_written, nb_supported);
+		if (ret != 0) {
+			sfc_adapter_unlock(sa);
+			return ret;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return 0;
+}
+
+void
+sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,
+			     const uint64_t *ids,
+			     uint64_t *values,
+			     unsigned int n,
+			     unsigned int *nb_supported)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	unsigned int sw_xstats_offset;
+	unsigned int i;
+
+	sfc_adapter_lock(sa);
+
+	sw_xstats_offset = *nb_supported;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sfc_sw_xstat_get_values_by_id(sa, &sfc_sw_xstats[i], ids,
+					      values, n, nb_supported);
+	}
+
+	for (i = 0; i < n; i++) {
+		if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)
+			values[i] -= reset_vals[ids[i] - sw_xstats_offset];
+	}
+
+	sfc_adapter_unlock(sa);
+}
+
+int
+sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,
+			      const uint64_t *ids,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int size,
+			      unsigned int *nb_supported)
+{
+	unsigned int i;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		ret = sfc_sw_xstat_get_names_by_id(sa, &sfc_sw_xstats[i], ids,
+						   xstats_names, size,
+						   nb_supported);
+		if (ret != 0) {
+			sfc_adapter_unlock(sa);
+			SFC_ASSERT(ret < 0);
+			return ret;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return 0;
+}
+
+static void
+sfc_sw_xstat_reset(struct sfc_adapter *sa, struct sfc_sw_xstat_descr *sw_xstat,
+		   uint64_t *reset_vals)
+{
+	unsigned int nb_queues;
+	unsigned int qid;
+	uint64_t *accum_xstat_reset;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return;
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	accum_xstat_reset = reset_vals;
+	*accum_xstat_reset = 0;
+	reset_vals++;
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		reset_vals[qid] = sw_xstat->get_val(sa, qid);
+		*accum_xstat_reset += reset_vals[qid];
+	}
+}
+
+void
+sfc_sw_xstats_reset(struct sfc_adapter *sa)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	struct sfc_sw_xstat_descr *sw_xstat;
+	unsigned int i;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sw_xstat = &sfc_sw_xstats[i];
+		sfc_sw_xstat_reset(sa, sw_xstat, reset_vals);
+		reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_xstat);
+	}
+}
+
+int
+sfc_sw_xstats_configure(struct sfc_adapter *sa)
+{
+	uint64_t **reset_vals = &sa->sw_xstats.reset_vals;
+	size_t nb_supported = 0;
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++)
+		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
+							&sfc_sw_xstats[i]);
+
+	*reset_vals = rte_realloc(*reset_vals,
+				  nb_supported * sizeof(**reset_vals), 0);
+	if (*reset_vals == NULL)
+		return ENOMEM;
+
+	memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));
+
+	return 0;
+}
+
+static void
+sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)
+{
+	rte_bitmap_free(sa->sw_xstats.queues_bitmap);
+	rte_free(sa->sw_xstats.queues_bitmap_mem);
+}
+
+static int
+sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)
+{
+	struct rte_bitmap **queues_bitmap = &sa->sw_xstats.queues_bitmap;
+	void **queues_bitmap_mem = &sa->sw_xstats.queues_bitmap_mem;
+	uint32_t bmp_size;
+	int rc;
+
+	bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);
+	*queues_bitmap_mem = NULL;
+	*queues_bitmap = NULL;
+
+	*queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0,
+					       sa->socket_id);
+	if (*queues_bitmap_mem == NULL)
+		return ENOMEM;
+
+	*queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,
+					 *queues_bitmap_mem, bmp_size);
+	if (*queues_bitmap == NULL) {
+		rc = EINVAL;
+		goto fail;
+	}
+
+	rte_spinlock_init(&sa->sw_xstats.queues_bitmap_lock);
+	return 0;
+
+fail:
+	sfc_sw_xstats_free_queues_bitmap(sa);
+	return rc;
+}
+
+int
+sfc_sw_xstats_init(struct sfc_adapter *sa)
+{
+	sa->sw_xstats.reset_vals = NULL;
+
+	return sfc_sw_xstats_alloc_queues_bitmap(sa);
+}
+
+void
+sfc_sw_xstats_close(struct sfc_adapter *sa)
+{
+	rte_free(sa->sw_xstats.reset_vals);
+	sa->sw_xstats.reset_vals = NULL;
+
+	sfc_sw_xstats_free_queues_bitmap(sa);
+}
diff --git a/drivers/net/sfc/sfc_sw_stats.h b/drivers/net/sfc/sfc_sw_stats.h
new file mode 100644
index 0000000000..1abded8018
--- /dev/null
+++ b/drivers/net/sfc/sfc_sw_stats.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2021 Xilinx, Inc.
+ */
+#ifndef _SFC_SW_STATS_H
+#define _SFC_SW_STATS_H
+
+#include <rte_dev.h>
+
+#include "sfc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
+			    struct rte_eth_xstat *xstats,
+			    unsigned int xstats_count, unsigned int *nb_written,
+			    unsigned int *nb_supported);
+
+int sfc_sw_xstats_get_names(struct sfc_adapter *sa,
+			    struct rte_eth_xstat_name *xstats_names,
+			    unsigned int xstats_count, unsigned int *nb_written,
+			    unsigned int *nb_supported);
+
+void sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				  uint64_t *values, unsigned int n,
+				  unsigned int *nb_supported);
+
+int sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				  struct rte_eth_xstat_name *xstats_names,
+				  unsigned int size,
+				  unsigned int *nb_supported);
+
+unsigned int sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa);
+
+int sfc_sw_xstats_configure(struct sfc_adapter *sa);
+
+void sfc_sw_xstats_reset(struct sfc_adapter *sa);
+
+int sfc_sw_xstats_init(struct sfc_adapter *sa);
+
+void sfc_sw_xstats_close(struct sfc_adapter *sa);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _SFC_SW_STATS_H */
diff --git a/drivers/net/sfc/sfc_tx.c b/drivers/net/sfc/sfc_tx.c
index ce2a9a6a4f..49b239f4d2 100644
--- a/drivers/net/sfc/sfc_tx.c
+++ b/drivers/net/sfc/sfc_tx.c
@@ -980,8 +980,10 @@ sfc_efx_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 				       txq->completed, &txq->added);
 		SFC_ASSERT(rc == 0);
 
-		if (likely(pushed != txq->added))
+		if (likely(pushed != txq->added)) {
 			efx_tx_qpush(txq->common, txq->added, pushed);
+			txq->dp.dpq.tx_dbells++;
+		}
 	}
 
 #if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH 11/11] app/testpmd: add option to display extended statistics
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (9 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 10/11] net/sfc: add xstats for Rx/Tx doorbells Andrew Rybchenko
@ 2021-06-04 14:42 ` Andrew Rybchenko
  2021-07-05  7:10   ` David Marchand
  2021-07-06  8:54   ` Li, Xiaoyun
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (7 subsequent siblings)
  18 siblings, 2 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-06-04 14:42 UTC (permalink / raw)
  To: dev; +Cc: Ivan Ilchenko, Xiaoyun Li

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
(i.e. 'stats-period' option or 'show port stats' interactive command) to
display specified list of extended statistics.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 app/test-pmd/cmdline.c                |  56 ++++++++++++
 app/test-pmd/config.c                 |  66 ++++++++++++++
 app/test-pmd/parameters.c             |  18 ++++
 app/test-pmd/testpmd.c                | 122 ++++++++++++++++++++++++++
 app/test-pmd/testpmd.h                |  21 +++++
 doc/guides/testpmd_app_ug/run_app.rst |   5 ++
 6 files changed, 288 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 0268b18f95..b1fd136982 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -3613,6 +3613,62 @@ cmdline_parse_inst_t cmd_stop = {
 
 /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
 
+int
+parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
+		  unsigned int *xstats_num)
+{
+	int max_names_nb, names_nb;
+	int stringlen;
+	char **names;
+	char *str;
+	int ret;
+	int i;
+
+	names = NULL;
+	str = strdup(in_str);
+	if (str == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+	stringlen = strlen(str);
+
+	for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
+		if (str[i] == ',')
+			max_names_nb++;
+	}
+
+	names = calloc(max_names_nb, sizeof(*names));
+	if (names == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
+	printf("max names is %d\n", max_names_nb);
+	if (names_nb < 0) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	*xstats = calloc(names_nb, sizeof(**xstats));
+	if (*xstats == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < names_nb; i++)
+		rte_strscpy((*xstats)[i].name, names[i],
+			    sizeof((*xstats)[i].name));
+
+	*xstats_num = names_nb;
+	ret = 0;
+
+out:
+	free(names);
+	free(str);
+	return ret;
+}
+
 unsigned int
 parse_item_list(char* str, const char* item_name, unsigned int max_items,
 		unsigned int *parsed_items, int check_unique_values)
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 43c79b5021..8e71b664cd 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -173,6 +173,70 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
 	printf("%s%s", name, buf);
 }
 
+static void
+nic_xstats_display_periodic(portid_t port_id)
+{
+	struct xstat_display_info *xstats_info;
+	uint64_t *prev_values, *curr_values;
+	uint64_t diff_value, value_rate;
+	uint64_t *ids, *ids_supp;
+	struct timespec cur_time;
+	unsigned int i, i_supp;
+	size_t ids_supp_sz;
+	uint64_t diff_ns;
+	int rc;
+
+	xstats_info = &xstats_per_port[port_id];
+
+	ids_supp_sz = xstats_info->ids_supp_sz;
+	if (xstats_display_num == 0 || ids_supp_sz == 0)
+		return;
+
+	printf("\n");
+
+	ids = xstats_info->ids;
+	ids_supp = xstats_info->ids_supp;
+	prev_values = xstats_info->prev_values;
+	curr_values = xstats_info->curr_values;
+
+	rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
+				      ids_supp_sz);
+	if (rc != (int)ids_supp_sz) {
+		fprintf(stderr, "%s: Failed to get values of %zu supported xstats for port %u - return code %d\n",
+			__func__, ids_supp_sz, port_id, rc);
+		return;
+	}
+
+	diff_ns = 0;
+	if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
+		uint64_t ns;
+
+		ns = cur_time.tv_sec * NS_PER_SEC;
+		ns += cur_time.tv_nsec;
+
+		if (xstats_info->prev_ns != 0)
+			diff_ns = ns - xstats_info->prev_ns;
+		xstats_info->prev_ns = ns;
+	}
+
+	printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
+	for (i = i_supp = 0; i < xstats_display_num; i++) {
+		if (ids[i] == XSTAT_ID_INVALID)
+			continue;
+
+		diff_value = (curr_values[i_supp] > prev_values[i]) ?
+			     (curr_values[i_supp] - prev_values[i]) : 0;
+		prev_values[i] = curr_values[i_supp];
+		value_rate = diff_ns > 0 ?
+				(double)diff_value / diff_ns * NS_PER_SEC : 0;
+
+		printf("  %-25s%12"PRIu64" %15"PRIu64"\n",
+		       xstats_display[i].name, curr_values[i_supp], value_rate);
+
+		i_supp++;
+	}
+}
+
 void
 nic_stats_display(portid_t port_id)
 {
@@ -243,6 +307,8 @@ nic_stats_display(portid_t port_id)
 	       PRIu64"          Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
 	       mpps_tx, mbps_tx * 8);
 
+	nic_xstats_display_periodic(port_id);
+
 	printf("  %s############################%s\n",
 	       nic_stats_border, nic_stats_border);
 }
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index f3954c1c63..0fecc5e8f8 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -62,6 +62,9 @@ usage(char* progname)
 	       "(only if interactive is disabled).\n");
 	printf("  --stats-period=PERIOD: statistics will be shown "
 	       "every PERIOD seconds (only if interactive is disabled).\n");
+	printf("  --display-xstats xstat1[,...]: extended statistics to show. "
+	       "Used with --stats-period specified or interactive commands "
+	       "that show Rx/Tx statistics (i.e. 'show port stats').\n");
 	printf("  --nb-cores=N: set the number of forwarding cores "
 	       "(1 <= N <= %d).\n", nb_lcores);
 	printf("  --nb-ports=N: set the number of forwarding ports "
@@ -531,6 +534,7 @@ launch_args_parse(int argc, char** argv)
 #endif
 		{ "tx-first",			0, 0, 0 },
 		{ "stats-period",		1, 0, 0 },
+		{ "display-xstats",		1, 0, 0 },
 		{ "nb-cores",			1, 0, 0 },
 		{ "nb-ports",			1, 0, 0 },
 		{ "coremask",			1, 0, 0 },
@@ -686,6 +690,20 @@ launch_args_parse(int argc, char** argv)
 				stats_period = n;
 				break;
 			}
+			if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
+				char rc;
+
+				rc = parse_xstats_list(optarg, &xstats_display,
+						       &xstats_display_num);
+				if (rc != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to fill xstats to display: %d\n",
+						 rc);
+
+				if (alloc_display_xstats_info() != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to alloc xstats display memory\n");
+			}
 			if (!strcmp(lgopts[opt_idx].name,
 				    "eth-peers-configfile")) {
 				if (init_peer_eth_addrs(optarg) != 0)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 8ed1b97dec..8ce61cb0ff 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -203,6 +203,14 @@ uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
                                       * specified on command-line. */
 uint16_t stats_period; /**< Period to show statistics (disabled by default) */
 
+/** Extended statistics to show. */
+struct rte_eth_xstat_name *xstats_display;
+
+unsigned int xstats_display_num; /**< Size of extended statistics to show */
+
+/** Helper structures for each port to show extended statistics. */
+struct xstat_display_info xstats_per_port[RTE_MAX_ETHPORTS];
+
 /*
  * In container, it cannot terminate the process which running with 'stats-period'
  * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
@@ -537,6 +545,12 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
 /* Holds the registered mbuf dynamic flags names. */
 char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
 
+/** Fill helper structures for specified port to show extended statistics. */
+static void fill_display_xstats_info_for_port(portid_t pi);
+
+/** Fill helper structures for all ports to show extended statistics. */
+static void fill_display_xstats_info(void);
+
 /*
  * Helper function to check if socket is already discovered.
  * If yes, return positive value. If not, return zero.
@@ -2675,6 +2689,8 @@ start_port(portid_t pid)
 		}
 	}
 
+	fill_display_xstats_info_for_port(pid);
+
 	printf("Done\n");
 	return 0;
 }
@@ -3693,6 +3709,110 @@ force_quit(void)
 	prompt_exit();
 }
 
+int
+alloc_display_xstats_info(void)
+{
+	portid_t port;
+	uint64_t *mem;
+	size_t mem_size;
+
+	if (xstats_display_num == 0)
+		return 0;
+
+	memset(xstats_per_port, 0, sizeof(xstats_per_port));
+
+	for (port = 0; port < RTE_MAX_ETHPORTS; port++) {
+		uint64_t **ids = &xstats_per_port[port].ids;
+		uint64_t **ids_supp = &xstats_per_port[port].ids_supp;
+		uint64_t **prev_values = &xstats_per_port[port].prev_values;
+		uint64_t **curr_values = &xstats_per_port[port].curr_values;
+
+		if (port == 0) {
+			mem_size = RTE_MAX_ETHPORTS * xstats_display_num *
+				   (sizeof(**ids) + sizeof(**ids_supp) +
+				    sizeof(**prev_values) +
+				    sizeof(**curr_values));
+
+			mem = malloc(mem_size);
+			if (mem == NULL)
+				return -ENOMEM;
+
+			memset(mem, 0, mem_size);
+		}
+
+		*ids = mem;
+		mem += xstats_display_num * sizeof(**ids);
+
+		*ids_supp = mem;
+		mem += xstats_display_num * sizeof(**ids_supp);
+
+		*prev_values = mem;
+		mem += xstats_display_num * sizeof(**prev_values);
+
+		*curr_values = mem;
+		mem += xstats_display_num * sizeof(**curr_values);
+	}
+
+	return 0;
+}
+
+static void
+fill_display_xstats_info_for_port(portid_t pi)
+{
+	unsigned int stat, stat_supp;
+	uint64_t *ids, *ids_supp;
+	const char *xstat_name;
+	struct rte_port *port;
+	int rc;
+
+	if (xstats_display_num == 0)
+		return;
+
+	if (pi == (portid_t)RTE_PORT_ALL) {
+		fill_display_xstats_info();
+		return;
+	}
+
+	port = &ports[pi];
+	if (port->port_status != RTE_PORT_STARTED)
+		return;
+
+	ids = xstats_per_port[pi].ids;
+	ids_supp = xstats_per_port[pi].ids_supp;
+
+	for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
+		xstat_name = xstats_display[stat].name;
+
+		rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
+						   ids + stat);
+		if (rc != 0) {
+			ids[stat] = XSTAT_ID_INVALID;
+			printf("No xstat '%s' on port %u - skip it\n",
+			       xstat_name, pi);
+			continue;
+		}
+		ids_supp[stat_supp++] = ids[stat];
+	}
+
+	xstats_per_port[pi].ids_supp_sz = stat_supp;
+}
+
+static void
+fill_display_xstats_info(void)
+{
+	portid_t pi;
+
+	if (xstats_display_num == 0)
+		return;
+
+	RTE_ETH_FOREACH_DEV(pi) {
+		if (pi == (portid_t)RTE_PORT_ALL)
+			continue;
+
+		fill_display_xstats_info_for_port(pi);
+	}
+}
+
 static void
 print_stats(void)
 {
@@ -3889,6 +4009,8 @@ main(int argc, char** argv)
 	}
 #endif
 
+	fill_display_xstats_info();
+
 #ifdef RTE_LIB_CMDLINE
 	if (strlen(cmdline_filename) != 0)
 		cmdline_read_from_file(cmdline_filename);
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 283b5e3680..d5a42a9e9c 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -433,6 +433,24 @@ extern uint32_t param_total_num_mbufs;
 
 extern uint16_t stats_period;
 
+extern struct rte_eth_xstat_name *xstats_display;
+extern unsigned int xstats_display_num;
+
+#define XSTAT_ID_INVALID UINT64_MAX
+
+/** Information for an extended statistics to show. */
+struct xstat_display_info {
+	/** IDs of xstats in the order of xstats_display */
+	uint64_t *ids;
+	/** Supported xstats IDs in the order of xstats_display */
+	uint64_t *ids_supp;
+	size_t   ids_supp_sz;
+	uint64_t *prev_values;
+	uint64_t *curr_values;
+	uint64_t prev_ns;
+};
+extern struct xstat_display_info xstats_per_port[];
+
 extern uint16_t hairpin_mode;
 
 #ifdef RTE_LIB_LATENCYSTATS
@@ -765,6 +783,8 @@ inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx)
 unsigned int parse_item_list(char* str, const char* item_name,
 			unsigned int max_items,
 			unsigned int *parsed_items, int check_unique_values);
+int parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
+		      unsigned int *xstats_num);
 void launch_args_parse(int argc, char** argv);
 void cmdline_read_from_file(const char *filename);
 void prompt(void);
@@ -977,6 +997,7 @@ enum print_warning {
 int port_id_is_invalid(portid_t port_id, enum print_warning warning);
 void print_valid_ports(void);
 int new_socket_id(unsigned int socket_id);
+int alloc_display_xstats_info(void);
 
 queueid_t get_allowed_max_nb_rxq(portid_t *pid);
 int check_nb_rxq(queueid_t rxq);
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index eb48318353..3e5ba81f18 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -56,6 +56,11 @@ The command line options are:
     Display statistics every PERIOD seconds, if interactive mode is disabled.
     The default value is 0, which means that the statistics will not be displayed.
 
+*   ``--display-xstats xstat1[,...]``
+
+    Display extended statistics every PERIOD seconds as specified in ``--stats-period``
+    or when used with interactive commands that show Rx/Tx statistics (i.e. 'show port stats').
+
 *   ``--nb-cores=N``
 
     Set the number of forwarding cores,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 11/11] app/testpmd: add option to display extended statistics
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
@ 2021-07-05  7:10   ` David Marchand
  2021-07-06  8:54   ` Li, Xiaoyun
  1 sibling, 0 replies; 113+ messages in thread
From: David Marchand @ 2021-07-05  7:10 UTC (permalink / raw)
  To: Xiaoyun Li; +Cc: dev, Andrew Rybchenko, Ivan Ilchenko

Hello,

On Fri, Jun 4, 2021 at 4:44 PM Andrew Rybchenko
<andrew.rybchenko@oktetlabs.ru> wrote:
>
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>
> Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
> (i.e. 'stats-period' option or 'show port stats' interactive command) to
> display specified list of extended statistics.

Xiaoyun, could you review this patch?
Thanks.


-- 
David Marchand


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 11/11] app/testpmd: add option to display extended statistics
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
  2021-07-05  7:10   ` David Marchand
@ 2021-07-06  8:54   ` Li, Xiaoyun
  1 sibling, 0 replies; 113+ messages in thread
From: Li, Xiaoyun @ 2021-07-06  8:54 UTC (permalink / raw)
  To: Andrew Rybchenko, dev; +Cc: Ivan Ilchenko

Hi

> -----Original Message-----
> From: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Sent: Friday, June 4, 2021 22:42
> To: dev@dpdk.org
> Cc: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>; Li, Xiaoyun
> <xiaoyun.li@intel.com>
> Subject: [PATCH 11/11] app/testpmd: add option to display extended statistics
> 
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Add 'display-xstats' option for using in accompanying with Rx/Tx statistics (i.e.
> 'stats-period' option or 'show port stats' interactive command) to display
> specified list of extended statistics.
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> ---
>  app/test-pmd/cmdline.c                |  56 ++++++++++++
>  app/test-pmd/config.c                 |  66 ++++++++++++++
>  app/test-pmd/parameters.c             |  18 ++++
>  app/test-pmd/testpmd.c                | 122 ++++++++++++++++++++++++++
>  app/test-pmd/testpmd.h                |  21 +++++
>  doc/guides/testpmd_app_ug/run_app.rst |   5 ++
>  6 files changed, 288 insertions(+)
> 

Acked-by: Xiaoyun Li <xiaoyun.li@intel.com>

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-07-20 16:25   ` Ferruh Yigit
  2021-07-22  9:12     ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-07-20 16:25 UTC (permalink / raw)
  To: Andrew Rybchenko, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Document valid combinations of input arguments in accordance with
> current implementation in ethdev.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
> ---
>  lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
>  1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
> index faf3bd901d..1f63118544 100644
> --- a/lib/ethdev/rte_ethdev.h
> +++ b/lib/ethdev/rte_ethdev.h
> @@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>   *   The port identifier of the Ethernet device.
>   * @param xstats_names
>   *   An rte_eth_xstat_name array of at least *size* elements to
> - *   be filled. If set to NULL, the function returns the required number
> - *   of elements.
> + *   be filled. Must not be NULL if @p ids are specified (not NULL).

Removed part is also valid. If both 'ids' & 'xstats_names' are NULL, API returns
number of all elements.

Addition part looks good.

>   * @param ids
> - *   IDs array given by app to retrieve specific statistics
> + *   IDs array given by app to retrieve specific statistics. May be NULL
> + *   to retrieve all available statistics.

ack

>   * @param size
> - *   The size of the xstats_names array (number of elements).
> + *   If @p ids is not NULL, number of elements in the array with requested IDs
> + *   and number of elements in @p xstats_names to put names in. If @p ids is
> + *   NULL, number of elements in @p xstats_names to put all available statistics
> + *   names in.

ack

>   * @return
>   *   - A positive value lower or equal to size: success. The return value
>   *     is the number of entries filled in the stats table.
> @@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>   *     is too small. The return value corresponds to the size that should
>   *     be given to succeed. The entries in the table are not valid and
>   *     shall not be used by the caller.
> - *   - A negative value on error (invalid port id).
> + *   - A negative value on error.

ack


The 'eth_dev_get_xstats_count()' API is flexible but it makes API unnecessarily
complex, not for this patch but for future perhaps we can update the API and it
can return error if either 'ids' or 'xstats_names' is NULL. Remove support to
get all elements or getting number of elements support, these already supported
by non _id version of API.


And as a note for future, if we ever consider updating these _by_id APIs, we can
consider making the parameter order same for both, currently it is:
"rte_eth_xstats_get_names_by_id(port_id, values, size, ids)"
"      rte_eth_xstats_get_by_id(port_id, ids, values, size)"

>   */
>  int
>  rte_eth_xstats_get_names_by_id(uint16_t port_id,
> @@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>   *   The port identifier of the Ethernet device.
>   * @param ids
>   *   A pointer to an ids array passed by application. This tells which
> - *   statistics values function should retrieve. This parameter
> - *   can be set to NULL if size is 0. In this case function will retrieve
> + *   statistics values function should retrieve. May be NULL to retrieve
>   *   all available statistics.

Update is good. But what do you think to make it exact same in the both APIs
('rte_eth_xstats_get_names_by_id()' & 'rte_eth_xstats_get_by_id()')? Since it is
used for same purpose and exact same way in both APIs, no need to have slightly
different description.

>   * @param values
>   *   A pointer to a table to be filled with device statistics values.
> + *   Must not be NULL if ids are specified (not NULL).

Same comment on making description similar in both APIs.

Also both 'ids' & 'values' being NULL returns number of all elements should be
addressed.

>   * @param size
> - *   The size of the ids array (number of elements).
> + *   If @p ids is not NULL, number of elements in the array with requested IDs
> + *   and number of elements in values to put statistics in. If @p ids is NULL,
> + *   number of elements in values to put all available statistics in.

ack

>   * @return
>   *   - A positive value lower or equal to size: success. The return value
>   *     is the number of entries filled in the stats table.
> @@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>   *     is too small. The return value corresponds to the size that should
>   *     be given to succeed. The entries in the table are not valid and
>   *     shall not be used by the caller.
> - *   - A negative value on error (invalid port id).
> + *   - A negative value on error.

ack

>   */
>  int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>  			     uint64_t *values, unsigned int size);
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-07-20 16:51   ` Ferruh Yigit
  2021-07-22  9:33     ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-07-20 16:51 UTC (permalink / raw)
  To: Andrew Rybchenko, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Update xstats by IDs callbacks documentation in accordance with
> ethdev usage of these callbacks. Document valid combinations of
> input arguments to make driver implementation simpler.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
> ---
>  lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 41 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
> index 40e474aa7e..fd5b7ca550 100644
> --- a/lib/ethdev/ethdev_driver.h
> +++ b/lib/ethdev/ethdev_driver.h
> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat *stats, unsigned int n);
>  /**< @internal Get extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get extended stats of an Ethernet device.

Should it mention _by_id detail?

> + *
> + * @param dev
> + *   ethdev handle of port.
> + * @param ids
> + *   IDs array to retrieve specific statistics. Must not be NULL.
> + * @param values
> + *   A pointer to a table to be filled with device statistics values.
> + *   Must not be NULL.
> + * @param n
> + *   Element count in @p ids and @p values
> + *
> + * @return
> + *   - A number of filled in stats.
> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>  				      const uint64_t *ids,
>  				      uint64_t *values,
>  				      unsigned int n);
> -/**< @internal Get extended stats of an Ethernet device. */
>  
>  /**
>   * @internal
> @@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>  /**< @internal Get names of extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get names of extended stats of an Ethernet device.

Should it mention _by_id detail?

> + * For name count, set @p xstats_names and @p ids to NULL.
> + *

isn't the 'count' part handled in the API? I think in the devops both should not
be NULL.

> + * @param dev
> + *   ethdev handle of port.
> + * @param xstats_names
> + *   An rte_eth_xstat_name array of at least *size* elements to
> + *   be filled. Can be NULL together with @p ids to retrieve number of
> + *   available statistics.

As far as I understand both _by_id APIs and devops behave same, so argument
descriptions/behavior should be same.

> + * @param ids
> + *   IDs array to retrieve specific statistics. Can be NULL together
> + *   with @p xstats_names to retrieve number of available statistics.
> + * @param size
> + *   Size of ids and xstats_names arrays.
> + *   Element count in @p ids and @p xstats_names
> + *
> + * @return
> + *   - A number of filled in stats if both xstats_names and ids are not NULL.
> + *   - A number of available stats if both xstats_names and ids are NULL.

Again as far as I can see these covered by API, not devops, am I missing something.

> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
>  	unsigned int size);
> -/**< @internal Get names of extended stats of an Ethernet device. */
>  
>  typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
>  					     uint16_t queue_id,
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-07-20 16:25   ` Ferruh Yigit
@ 2021-07-22  9:12     ` Andrew Rybchenko
  2021-07-23 14:19       ` Ferruh Yigit
  0 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:12 UTC (permalink / raw)
  To: Ferruh Yigit, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 7/20/21 7:25 PM, Ferruh Yigit wrote:
> On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Document valid combinations of input arguments in accordance with
>> current implementation in ethdev.
>>
>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>> Cc: stable@dpdk.org
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>> ---
>>   lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
>>   1 file changed, 14 insertions(+), 9 deletions(-)
>>
>> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
>> index faf3bd901d..1f63118544 100644
>> --- a/lib/ethdev/rte_ethdev.h
>> +++ b/lib/ethdev/rte_ethdev.h
>> @@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>>    *   The port identifier of the Ethernet device.
>>    * @param xstats_names
>>    *   An rte_eth_xstat_name array of at least *size* elements to
>> - *   be filled. If set to NULL, the function returns the required number
>> - *   of elements.
>> + *   be filled. Must not be NULL if @p ids are specified (not NULL).
> 
> Removed part is also valid. If both 'ids' & 'xstats_names' are NULL, API returns
> number of all elements.

Yes, but it is an excessive information. The trigger to return number
of all elements is 'ids == NULL'. Here we are talking about
'xstats_names' parameter. If the parameter is NULL, but ids is not
null, it does not trigger number of all elements return. It is an
invalid input parameters. That's what a new description says.

> 
> Addition part looks good.
> 
>>    * @param ids
>> - *   IDs array given by app to retrieve specific statistics
>> + *   IDs array given by app to retrieve specific statistics. May be NULL
>> + *   to retrieve all available statistics.
> 
> ack
> 
>>    * @param size
>> - *   The size of the xstats_names array (number of elements).
>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>> + *   and number of elements in @p xstats_names to put names in. If @p ids is
>> + *   NULL, number of elements in @p xstats_names to put all available statistics
>> + *   names in.
> 
> ack
> 
>>    * @return
>>    *   - A positive value lower or equal to size: success. The return value
>>    *     is the number of entries filled in the stats table.
>> @@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>>    *     is too small. The return value corresponds to the size that should
>>    *     be given to succeed. The entries in the table are not valid and
>>    *     shall not be used by the caller.
>> - *   - A negative value on error (invalid port id).
>> + *   - A negative value on error.
> 
> ack
> 
> 
> The 'eth_dev_get_xstats_count()' API is flexible but it makes API unnecessarily
> complex, not for this patch but for future perhaps we can update the API and it
> can return error if either 'ids' or 'xstats_names' is NULL. Remove support to
> get all elements or getting number of elements support, these already supported
> by non _id version of API.

I'm not sure that it is a right direction. The support allows
application to use less number of functions and depend on less
number of function prototypes.

> And as a note for future, if we ever consider updating these _by_id APIs, we can
> consider making the parameter order same for both, currently it is:
> "rte_eth_xstats_get_names_by_id(port_id, values, size, ids)"
> "      rte_eth_xstats_get_by_id(port_id, ids, values, size)"

+1, current difference is terribly bad

>>    */
>>   int
>>   rte_eth_xstats_get_names_by_id(uint16_t port_id,
>> @@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>    *   The port identifier of the Ethernet device.
>>    * @param ids
>>    *   A pointer to an ids array passed by application. This tells which
>> - *   statistics values function should retrieve. This parameter
>> - *   can be set to NULL if size is 0. In this case function will retrieve
>> + *   statistics values function should retrieve. May be NULL to retrieve
>>    *   all available statistics.
> 
> Update is good. But what do you think to make it exact same in the both APIs
> ('rte_eth_xstats_get_names_by_id()' & 'rte_eth_xstats_get_by_id()')? Since it is
> used for same purpose and exact same way in both APIs, no need to have slightly
> different description.

I agree. I'll fix in v2.

>>    * @param values
>>    *   A pointer to a table to be filled with device statistics values.
>> + *   Must not be NULL if ids are specified (not NULL).
> 
> Same comment on making description similar in both APIs.

OK

> Also both 'ids' & 'values' being NULL returns number of all elements should be
> addressed.

I think it is excessibe. It is sufficient to say so for ids==NULL which
is a trigger to get all elements.

>>    * @param size
>> - *   The size of the ids array (number of elements).
>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>> + *   and number of elements in values to put statistics in. If @p ids is NULL,
>> + *   number of elements in values to put all available statistics in.
> 
> ack
> 
>>    * @return
>>    *   - A positive value lower or equal to size: success. The return value
>>    *     is the number of entries filled in the stats table.
>> @@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>    *     is too small. The return value corresponds to the size that should
>>    *     be given to succeed. The entries in the table are not valid and
>>    *     shall not be used by the caller.
>> - *   - A negative value on error (invalid port id).
>> + *   - A negative value on error.
> 
> ack
> 
>>    */
>>   int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>>   			     uint64_t *values, unsigned int size);
>>


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-20 16:51   ` Ferruh Yigit
@ 2021-07-22  9:33     ` Andrew Rybchenko
  2021-07-23 14:31       ` Ferruh Yigit
  0 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:33 UTC (permalink / raw)
  To: Ferruh Yigit, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 7/20/21 7:51 PM, Ferruh Yigit wrote:
> On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Update xstats by IDs callbacks documentation in accordance with
>> ethdev usage of these callbacks. Document valid combinations of
>> input arguments to make driver implementation simpler.
>>
>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>> Cc: stable@dpdk.org
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>> ---
>>   lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>> index 40e474aa7e..fd5b7ca550 100644
>> --- a/lib/ethdev/ethdev_driver.h
>> +++ b/lib/ethdev/ethdev_driver.h
>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>   	struct rte_eth_xstat *stats, unsigned int n);
>>   /**< @internal Get extended stats of an Ethernet device. */
>>   
>> +/**
>> + * @internal
>> + * Get extended stats of an Ethernet device.
> 
> Should it mention _by_id detail?

Yes, will fix in v2.

>> + *
>> + * @param dev
>> + *   ethdev handle of port.
>> + * @param ids
>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>> + * @param values
>> + *   A pointer to a table to be filled with device statistics values.
>> + *   Must not be NULL.
>> + * @param n
>> + *   Element count in @p ids and @p values
>> + *
>> + * @return
>> + *   - A number of filled in stats.
>> + *   - A negative value on error.
>> + */
>>   typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>   				      const uint64_t *ids,
>>   				      uint64_t *values,
>>   				      unsigned int n);
>> -/**< @internal Get extended stats of an Ethernet device. */
>>   
>>   /**
>>    * @internal
>> @@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>   	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>   /**< @internal Get names of extended stats of an Ethernet device. */
>>   
>> +/**
>> + * @internal
>> + * Get names of extended stats of an Ethernet device.
> 
> Should it mention _by_id detail?

Yes, will fix in v2.

>> + * For name count, set @p xstats_names and @p ids to NULL.
>> + *
> 
> isn't the 'count' part handled in the API? I think in the devops both should not
> be NULL.

No, eth_dev_get_xstats_count() uses the callback with NULL, NULL, 0.

> 
>> + * @param dev
>> + *   ethdev handle of port.
>> + * @param xstats_names
>> + *   An rte_eth_xstat_name array of at least *size* elements to
>> + *   be filled. Can be NULL together with @p ids to retrieve number of
>> + *   available statistics.
> 
> As far as I understand both _by_id APIs and devops behave same, so argument
> descriptions/behavior should be same.

In fact no, it is slightly different. For example, devops is never
called with NULL ids and not NULL names or non-zero size. It allows to
check less in drivers.

>> + * @param ids
>> + *   IDs array to retrieve specific statistics. Can be NULL together
>> + *   with @p xstats_names to retrieve number of available statistics.
>> + * @param size
>> + *   Size of ids and xstats_names arrays.
>> + *   Element count in @p ids and @p xstats_names
>> + *
>> + * @return
>> + *   - A number of filled in stats if both xstats_names and ids are not NULL.
>> + *   - A number of available stats if both xstats_names and ids are NULL.
> 
> Again as far as I can see these covered by API, not devops, am I missing something.

See eth_dev_get_xstats_count()

> 
>> + *   - A negative value on error.
>> + */
>>   typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
>>   	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
>>   	unsigned int size);
>> -/**< @internal Get names of extended stats of an Ethernet device. */
>>   
>>   typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
>>   					     uint16_t queue_id,
>>


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (10 preceding siblings ...)
  2021-06-04 14:42 ` [dpdk-dev] [PATCH 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
@ 2021-07-22  9:54 ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
                     ` (10 more replies)
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (6 subsequent siblings)
  18 siblings, 11 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev; +Cc: David Marchand

Rx/Tx doorbells stats are essential for performance investigation.

On the way fix ethdev documenation to refine requirements on
driver callback. It allows to make these callbacks a bit simpler.

Add testpmd option to show specified xstats periodically or upon
request, for example:

 * --display-xstats rx_good_packets,tx_good_packets --stats-period 1

 Port statistics ====================================
  ######################## NIC statistics for port 0  ########################
  RX-packets: 14102808   RX-missed: 0          RX-bytes:  7164239264
  RX-errors: 0
  RX-nombuf:  0
  TX-packets: 14102789   TX-errors: 0          TX-bytes:  7164226028

  Throughput (since last show)
  Rx-pps:      2349577          Rx-bps:   9548682392
  Tx-pps:      2349576          Tx-bps:   9548682408

                      Value                Rate (since last show)
  rx_good_packets     14103280             2349575
  tx_good_packets     14103626             2349573
  ############################################################################

 * -i --display-xstats tx_good_packets,vadapter_rx_overflow

testpmd> port start 0
...
No xstat 'vadapter_rx_overflow' on port 0 - skip it
...
testpmd> start tx_first
testpmd> show port stats all
                               Value            Rate (since last show)
  tx_good_packets             132545336         1420439

v2:
 - address Ferruh review notes on ethdev patches

Ivan Ilchenko (11):
  net/sfc: fix get xstats by ID callback to use MAC stats lock
  net/sfc: fix reading adapter state without locking
  ethdev: fix docs of functions getting xstats by IDs
  ethdev: fix docs of drivers callbacks getting xstats by IDs
  net/sfc: fix xstats by ID callbacks according to ethdev
  net/sfc: fix accessing xstats by an unsorted list of IDs
  net/sfc: fix MAC stats update to work for stopped device
  net/sfc: simplify getting of available xstats case
  net/sfc: prepare to add more xstats
  net/sfc: add xstats for Rx/Tx doorbells
  app/testpmd: add option to display extended statistics

 app/test-pmd/cmdline.c                |  56 +++
 app/test-pmd/config.c                 |  66 +++
 app/test-pmd/parameters.c             |  18 +
 app/test-pmd/testpmd.c                | 122 ++++++
 app/test-pmd/testpmd.h                |  21 +
 doc/guides/testpmd_app_ug/run_app.rst |   5 +
 drivers/net/sfc/meson.build           |   1 +
 drivers/net/sfc/sfc.c                 |  16 +
 drivers/net/sfc/sfc.h                 |  18 +-
 drivers/net/sfc/sfc_dp.h              |  10 +
 drivers/net/sfc/sfc_ef10.h            |   3 +-
 drivers/net/sfc/sfc_ef100_rx.c        |   1 +
 drivers/net/sfc/sfc_ef100_tx.c        |   1 +
 drivers/net/sfc/sfc_ef10_essb_rx.c    |   3 +-
 drivers/net/sfc/sfc_ef10_rx.c         |   3 +-
 drivers/net/sfc/sfc_ef10_tx.c         |   1 +
 drivers/net/sfc/sfc_ethdev.c          | 185 +++++----
 drivers/net/sfc/sfc_port.c            | 127 +++++-
 drivers/net/sfc/sfc_rx.c              |   1 +
 drivers/net/sfc/sfc_sw_stats.c        | 572 ++++++++++++++++++++++++++
 drivers/net/sfc/sfc_sw_stats.h        |  49 +++
 drivers/net/sfc/sfc_tx.c              |   4 +-
 lib/ethdev/ethdev_driver.h            |  43 +-
 lib/ethdev/rte_ethdev.h               |  30 +-
 24 files changed, 1246 insertions(+), 110 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_sw_stats.c
 create mode 100644 drivers/net/sfc/sfc_sw_stats.h

-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 02/11] net/sfc: fix reading adapter state without locking Andrew Rybchenko
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Remy Horton, Ivan Malov
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add MAC stats lock in get xstats by id callback before reading
number of supported MAC stats.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 88896db1f8..d4ac61ff76 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -789,12 +789,14 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	if (unlikely(values == NULL) ||
-	    unlikely((ids == NULL) && (n < port->mac_stats_nb_supported)))
-		return port->mac_stats_nb_supported;
-
 	rte_spinlock_lock(&port->mac_stats_lock);
 
+	if (unlikely(values == NULL) ||
+	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
+		ret = port->mac_stats_nb_supported;
+		goto unlock;
+	}
+
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 02/11] net/sfc: fix reading adapter state without locking
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Robert Stonehouse, Andrew Lee
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update MAC stats function reads adapter state with MAC stats locking
but without adapter locking. Add adapter locking before calling this
function and remove MAC stats locking since there's no point to have
it together with adapter locking. The second place MAC stats locking
is used is MAC stats reset function. It's called with adapter being
already locked so there's no point to use MAC stats locking anymore.

Fixes: 1caab2f1e68 ("net/sfc: add basic statistics")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  1 -
 drivers/net/sfc/sfc_ethdev.c | 28 ++++++++++++++++++++--------
 drivers/net/sfc/sfc_port.c   |  9 +++------
 3 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 546739bd4a..c7b0e5a30d 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -130,7 +130,6 @@ struct sfc_port {
 	unsigned int			nb_mcast_addrs;
 	uint8_t				*mcast_addrs;
 
-	rte_spinlock_t			mac_stats_lock;
 	uint64_t			*mac_stats_buf;
 	unsigned int			mac_stats_nb_supported;
 	efsys_mem_t			mac_stats_dma_mem;
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index d4ac61ff76..d5417e5e65 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -613,7 +613,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	uint64_t *mac_stats;
 	int ret;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	ret = sfc_port_update_mac_stats(sa);
 	if (ret != 0)
@@ -686,7 +686,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	}
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 	SFC_ASSERT(ret >= 0);
 	return -ret;
 }
@@ -698,12 +698,15 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	struct sfc_port *port = &sa->port;
 	int rc;
 
+	sfc_adapter_lock(sa);
+
 	if (sa->state != SFC_ADAPTER_STARTED) {
 		/*
 		 * The operation cannot be done if port is not started; it
 		 * will be scheduled to be done during the next port start
 		 */
 		port->mac_stats_reset_pending = B_TRUE;
+		sfc_adapter_unlock(sa);
 		return 0;
 	}
 
@@ -711,6 +714,8 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	if (rc != 0)
 		sfc_err(sa, "failed to reset statistics (rc = %d)", rc);
 
+	sfc_adapter_unlock(sa);
+
 	SFC_ASSERT(rc >= 0);
 	return -rc;
 }
@@ -726,7 +731,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	unsigned int i;
 	int nstats = 0;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
@@ -748,7 +753,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	}
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 
 	return nstats;
 }
@@ -789,7 +794,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	if (unlikely(values == NULL) ||
 	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
@@ -819,7 +824,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	ret = nb_written;
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 
 	return ret;
 }
@@ -835,9 +840,14 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int nb_written = 0;
 	unsigned int i;
 
+	sfc_adapter_lock(sa);
+
 	if (unlikely(xstats_names == NULL) ||
-	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported)))
-		return port->mac_stats_nb_supported;
+	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported))) {
+		nb_supported = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nb_supported;
+	}
 
 	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < size); ++i) {
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
@@ -853,6 +863,8 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		++nb_supported;
 	}
 
+	sfc_adapter_unlock(sa);
+
 	return nb_written;
 }
 
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index ac117f9c48..cdc0f94f19 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -43,7 +43,7 @@ sfc_port_update_mac_stats(struct sfc_adapter *sa)
 	unsigned int nb_attempts = 0;
 	int rc;
 
-	SFC_ASSERT(rte_spinlock_is_locked(&port->mac_stats_lock));
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
 	if (sa->state != SFC_ADAPTER_STARTED)
 		return EINVAL;
@@ -103,14 +103,13 @@ sfc_port_reset_sw_stats(struct sfc_adapter *sa)
 int
 sfc_port_reset_mac_stats(struct sfc_adapter *sa)
 {
-	struct sfc_port *port = &sa->port;
 	int rc;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
 	rc = efx_mac_stats_clear(sa->nic);
 	if (rc == 0)
 		sfc_port_reset_sw_stats(sa);
-	rte_spinlock_unlock(&port->mac_stats_lock);
 
 	return rc;
 }
@@ -416,8 +415,6 @@ sfc_port_attach(struct sfc_adapter *sa)
 		goto fail_mcast_addr_list_buf_alloc;
 	}
 
-	rte_spinlock_init(&port->mac_stats_lock);
-
 	rc = ENOMEM;
 	port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
 						sizeof(uint64_t), 0,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 02/11] net/sfc: fix reading adapter state without locking Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Document valid combinations of input arguments in accordance with
current implementation in ethdev.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/rte_ethdev.h | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index d2b27c351f..80c42d2f08 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2872,13 +2872,16 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param xstats_names
- *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. If set to NULL, the function returns the required number
- *   of elements.
+ *   An array of at least @p size elements to be filled in.
+ *   Must not be NULL if @p ids are specified (not NULL) or @p size is not 0.
  * @param ids
- *   IDs array given by app to retrieve specific statistics
+ *   IDs array given by app to retrieve specific statistics names.
+ *   May be NULL to retrieve all available statistics names.
  * @param size
- *   The size of the xstats_names array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in @p xstats_names to put names in. If @p ids is
+ *   NULL, number of elements in @p xstats_names to put all available statistics
+ *   names in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int
 rte_eth_xstats_get_names_by_id(uint16_t port_id,
@@ -2899,14 +2902,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param ids
- *   A pointer to an ids array passed by application. This tells which
- *   statistics values function should retrieve. This parameter
- *   can be set to NULL if size is 0. In this case function will retrieve
- *   all available statistics.
+ *   IDs array given by app to retrieve specific statistics.
+ *   May be NULL to retrieve all available statistics.
  * @param values
- *   A pointer to a table to be filled with device statistics values.
+ *   An array of at least @p size elements to be filled in.
+ *   Must not be NULL if @p ids are specified (not NULL) or @p size is not 0.
  * @param size
- *   The size of the ids array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in values to put statistics in. If @p ids is NULL,
+ *   number of elements in values to put all available statistics in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2914,7 +2918,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
 			     uint64_t *values, unsigned int size);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (2 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 05/11] net/sfc: fix xstats by ID callbacks according to ethdev Andrew Rybchenko
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 40e474aa7e..e934be9285 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats specified by IDs of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats specified by IDs of an Ethernet device.
+ * For name count, set @p xstats_names and @p ids to NULL.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Can be NULL together with @p ids to retrieve number of
+ *   available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param size
+ *   Size of ids and xstats_names arrays.
+ *   Element count in @p ids and @p xstats_names
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 05/11] net/sfc: fix xstats by ID callbacks according to ethdev
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (3 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs Andrew Rybchenko
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Ivan Malov, Remy Horton
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Fix xstats by ID callbacks according to ethdev usage.
Handle combinations of input arguments that are required by ethdev
and sanity check and reject other combinations on callback entry.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index d5417e5e65..fca3f524a1 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -794,13 +794,10 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	sfc_adapter_lock(sa);
+	if (unlikely(ids == NULL || values == NULL))
+		return -EINVAL;
 
-	if (unlikely(values == NULL) ||
-	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
-		ret = port->mac_stats_nb_supported;
-		goto unlock;
-	}
+	sfc_adapter_lock(sa);
 
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
@@ -815,7 +812,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
 			continue;
 
-		if ((ids == NULL) || (ids[nb_written] == nb_supported))
+		if (ids[nb_written] == nb_supported)
 			values[nb_written++] = mac_stats[i];
 
 		++nb_supported;
@@ -840,10 +837,13 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int nb_written = 0;
 	unsigned int i;
 
+	if (unlikely(xstats_names == NULL && ids != NULL) ||
+	    unlikely(xstats_names != NULL && ids == NULL))
+		return -EINVAL;
+
 	sfc_adapter_lock(sa);
 
-	if (unlikely(xstats_names == NULL) ||
-	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported))) {
+	if (unlikely(xstats_names == NULL && ids == NULL)) {
 		nb_supported = port->mac_stats_nb_supported;
 		sfc_adapter_unlock(sa);
 		return nb_supported;
@@ -853,7 +853,7 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
 			continue;
 
-		if ((ids == NULL) || (ids[nb_written] == nb_supported)) {
+		if (ids[nb_written] == nb_supported) {
 			char *name = xstats_names[nb_written++].name;
 
 			strlcpy(name, efx_mac_stat_name(sa->nic, i),
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (4 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 05/11] net/sfc: fix xstats by ID callbacks according to ethdev Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 07/11] net/sfc: fix MAC stats update to work for stopped device Andrew Rybchenko
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Remy Horton, Ivan Malov
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Device may support only some MAC stats. Add mapping from ids to subset
of supported MAC stats for each port.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  2 ++
 drivers/net/sfc/sfc_ethdev.c | 44 ++++++++++++++++++------------------
 drivers/net/sfc/sfc_port.c   | 29 ++++++++++++++++++------
 3 files changed, 46 insertions(+), 29 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index c7b0e5a30d..972d32606d 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -141,6 +141,8 @@ struct sfc_port {
 
 	uint32_t		mac_stats_mask[EFX_MAC_STATS_MASK_NPAGES];
 
+	unsigned int			mac_stats_by_id[EFX_MAC_NSTATS];
+
 	uint64_t			ipackets;
 };
 
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index fca3f524a1..ae9304f90f 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -788,8 +788,6 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
 	uint64_t *mac_stats;
-	unsigned int nb_supported = 0;
-	unsigned int nb_written = 0;
 	unsigned int i;
 	int ret;
 	int rc;
@@ -808,17 +806,19 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 	mac_stats = port->mac_stats_buf;
 
-	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < n); ++i) {
-		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			continue;
-
-		if (ids[nb_written] == nb_supported)
-			values[nb_written++] = mac_stats[i];
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
 
-		++nb_supported;
+	for (i = 0; i < n; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
+		} else {
+			ret = i;
+			goto unlock;
+		}
 	}
 
-	ret = nb_written;
+	ret = n;
 
 unlock:
 	sfc_adapter_unlock(sa);
@@ -833,8 +833,7 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
-	unsigned int nb_supported = 0;
-	unsigned int nb_written = 0;
+	unsigned int nb_supported;
 	unsigned int i;
 
 	if (unlikely(xstats_names == NULL && ids != NULL) ||
@@ -849,23 +848,24 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		return nb_supported;
 	}
 
-	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < size); ++i) {
-		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			continue;
-
-		if (ids[nb_written] == nb_supported) {
-			char *name = xstats_names[nb_written++].name;
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
 
-			strlcpy(name, efx_mac_stat_name(sa->nic, i),
+	for (i = 0; i < size; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			strlcpy(xstats_names[i].name,
+				efx_mac_stat_name(sa->nic,
+						 port->mac_stats_by_id[ids[i]]),
 				sizeof(xstats_names[0].name));
+		} else {
+			sfc_adapter_unlock(sa);
+			return i;
 		}
-
-		++nb_supported;
 	}
 
 	sfc_adapter_unlock(sa);
 
-	return nb_written;
+	return size;
 }
 
 static int
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index cdc0f94f19..bb9e01d96b 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -157,6 +157,27 @@ sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
 
 #endif
 
+static void
+sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
+{
+	unsigned int mac_stats_nb_supported = 0;
+	struct sfc_port *port = &sa->port;
+	unsigned int stat_idx;
+
+	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
+			       sizeof(port->mac_stats_mask));
+
+	for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
+		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
+			continue;
+
+		port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
+		mac_stats_nb_supported++;
+	}
+
+	port->mac_stats_nb_supported = mac_stats_nb_supported;
+}
+
 int
 sfc_port_start(struct sfc_adapter *sa)
 {
@@ -165,7 +186,6 @@ sfc_port_start(struct sfc_adapter *sa)
 	uint32_t phy_adv_cap;
 	const uint32_t phy_pause_caps =
 		((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
-	unsigned int i;
 
 	sfc_log_init(sa, "entry");
 
@@ -259,12 +279,7 @@ sfc_port_start(struct sfc_adapter *sa)
 		port->mac_stats_reset_pending = B_FALSE;
 	}
 
-	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
-			       sizeof(port->mac_stats_mask));
-
-	for (i = 0, port->mac_stats_nb_supported = 0; i < EFX_MAC_NSTATS; ++i)
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			port->mac_stats_nb_supported++;
+	sfc_port_fill_mac_stats_info(sa);
 
 	port->mac_stats_update_generation = 0;
 
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 07/11] net/sfc: fix MAC stats update to work for stopped device
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (5 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 08/11] net/sfc: simplify getting of available xstats case Andrew Rybchenko
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Robert Stonehouse, Andrew Lee
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Fixes: 1caab2f1e68 ("net/sfc: add basic statistics")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  2 +-
 drivers/net/sfc/sfc_ethdev.c |  6 +++---
 drivers/net/sfc/sfc_port.c   | 11 +++++++----
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 972d32606d..1594f934ba 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -422,7 +422,7 @@ int sfc_port_start(struct sfc_adapter *sa);
 void sfc_port_stop(struct sfc_adapter *sa);
 void sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 				struct rte_eth_link *link_info);
-int sfc_port_update_mac_stats(struct sfc_adapter *sa);
+int sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t manual_update);
 int sfc_port_reset_mac_stats(struct sfc_adapter *sa);
 int sfc_set_rx_mode(struct sfc_adapter *sa);
 int sfc_set_rx_mode_unchecked(struct sfc_adapter *sa);
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index ae9304f90f..bbc22723f6 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -615,7 +615,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 	sfc_adapter_lock(sa);
 
-	ret = sfc_port_update_mac_stats(sa);
+	ret = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (ret != 0)
 		goto unlock;
 
@@ -733,7 +733,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	sfc_adapter_lock(sa);
 
-	rc = sfc_port_update_mac_stats(sa);
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
 		nstats = -rc;
@@ -797,7 +797,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 	sfc_adapter_lock(sa);
 
-	rc = sfc_port_update_mac_stats(sa);
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
 		ret = -rc;
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index bb9e01d96b..8c432c15f5 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -26,7 +26,8 @@
 /**
  * Update MAC statistics in the buffer.
  *
- * @param	sa	Adapter
+ * @param	sa		Adapter
+ * @param	force_upload	Flag to upload MAC stats in any case
  *
  * @return Status code
  * @retval	0	Success
@@ -34,7 +35,7 @@
  * @retval	ENOMEM	Memory allocation failure
  */
 int
-sfc_port_update_mac_stats(struct sfc_adapter *sa)
+sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
 {
 	struct sfc_port *port = &sa->port;
 	efsys_mem_t *esmp = &port->mac_stats_dma_mem;
@@ -46,14 +47,14 @@ sfc_port_update_mac_stats(struct sfc_adapter *sa)
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
 	if (sa->state != SFC_ADAPTER_STARTED)
-		return EINVAL;
+		return 0;
 
 	/*
 	 * If periodic statistics DMA'ing is off or if not supported,
 	 * make a manual request and keep an eye on timer if need be
 	 */
 	if (!port->mac_stats_periodic_dma_supported ||
-	    (port->mac_stats_update_period_ms == 0)) {
+	    (port->mac_stats_update_period_ms == 0) || force_upload) {
 		if (port->mac_stats_update_period_ms != 0) {
 			uint64_t timestamp = sfc_get_system_msecs();
 
@@ -367,6 +368,8 @@ sfc_port_stop(struct sfc_adapter *sa)
 	(void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
 				     0, B_FALSE);
 
+	sfc_port_update_mac_stats(sa, B_TRUE);
+
 	efx_port_fini(sa->nic);
 	efx_filter_fini(sa->nic);
 
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 08/11] net/sfc: simplify getting of available xstats case
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (6 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 07/11] net/sfc: fix MAC stats update to work for stopped device Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 09/11] net/sfc: prepare to add more xstats Andrew Rybchenko
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev; +Cc: David Marchand, Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

There is no point to recalculate number of available xstats on
each request. The number is calculated once on device start
and may be returned on subsequent calls.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index bbc22723f6..f0567a71d0 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -733,6 +733,11 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	sfc_adapter_lock(sa);
 
+	if (unlikely(xstats == NULL)) {
+		nstats = port->mac_stats_nb_supported;
+		goto unlock;
+	}
+
 	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
@@ -744,7 +749,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (xstats != NULL && nstats < (int)xstats_count) {
+			if (nstats < (int)xstats_count) {
 				xstats[nstats].id = nstats;
 				xstats[nstats].value = mac_stats[i];
 			}
@@ -768,9 +773,16 @@ sfc_xstats_get_names(struct rte_eth_dev *dev,
 	unsigned int i;
 	unsigned int nstats = 0;
 
+	if (unlikely(xstats_names == NULL)) {
+		sfc_adapter_lock(sa);
+		nstats = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nstats;
+	}
+
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (xstats_names != NULL && nstats < xstats_count)
+			if (nstats < xstats_count)
 				strlcpy(xstats_names[nstats].name,
 					efx_mac_stat_name(sa->nic, i),
 					sizeof(xstats_names[0].name));
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 09/11] net/sfc: prepare to add more xstats
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (7 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 08/11] net/sfc: simplify getting of available xstats case Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 10/11] net/sfc: add xstats for Rx/Tx doorbells Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev; +Cc: David Marchand, Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Move getting MAC stats code that involves locking to separate functions
to simplify addition of new xstats.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  4 ++
 drivers/net/sfc/sfc_ethdev.c | 73 ++++----------------------------
 drivers/net/sfc/sfc_port.c   | 80 ++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 65 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 1594f934ba..58b8c2c2ad 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -423,6 +423,10 @@ void sfc_port_stop(struct sfc_adapter *sa);
 void sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 				struct rte_eth_link *link_info);
 int sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t manual_update);
+int sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
+			   unsigned int xstats_count, unsigned int *nb_written);
+int sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				 uint64_t *values, unsigned int n);
 int sfc_port_reset_mac_stats(struct sfc_adapter *sa);
 int sfc_set_rx_mode(struct sfc_adapter *sa);
 int sfc_set_rx_mode_unchecked(struct sfc_adapter *sa);
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index f0567a71d0..dd7e5c253a 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -726,41 +726,17 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
-	uint64_t *mac_stats;
-	int rc;
-	unsigned int i;
-	int nstats = 0;
-
-	sfc_adapter_lock(sa);
+	unsigned int nb_written = 0;
+	unsigned int nb_supp;
 
 	if (unlikely(xstats == NULL)) {
-		nstats = port->mac_stats_nb_supported;
-		goto unlock;
-	}
-
-	rc = sfc_port_update_mac_stats(sa, B_FALSE);
-	if (rc != 0) {
-		SFC_ASSERT(rc > 0);
-		nstats = -rc;
-		goto unlock;
-	}
-
-	mac_stats = port->mac_stats_buf;
-
-	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < (int)xstats_count) {
-				xstats[nstats].id = nstats;
-				xstats[nstats].value = mac_stats[i];
-			}
-			nstats++;
-		}
+		sfc_adapter_lock(sa);
+		nb_supp = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nb_supp;
 	}
 
-unlock:
-	sfc_adapter_unlock(sa);
-
-	return nstats;
+	return sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
 }
 
 static int
@@ -798,44 +774,11 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
-	uint64_t *mac_stats;
-	unsigned int i;
-	int ret;
-	int rc;
 
 	if (unlikely(ids == NULL || values == NULL))
 		return -EINVAL;
 
-	sfc_adapter_lock(sa);
-
-	rc = sfc_port_update_mac_stats(sa, B_FALSE);
-	if (rc != 0) {
-		SFC_ASSERT(rc > 0);
-		ret = -rc;
-		goto unlock;
-	}
-
-	mac_stats = port->mac_stats_buf;
-
-	SFC_ASSERT(port->mac_stats_nb_supported <=
-		   RTE_DIM(port->mac_stats_by_id));
-
-	for (i = 0; i < n; i++) {
-		if (ids[i] < port->mac_stats_nb_supported) {
-			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
-		} else {
-			ret = i;
-			goto unlock;
-		}
-	}
-
-	ret = n;
-
-unlock:
-	sfc_adapter_unlock(sa);
-
-	return ret;
+	return sfc_port_get_mac_stats_by_id(sa, ids, values, n);
 }
 
 static int
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index 8c432c15f5..f6689a17c0 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -636,3 +636,83 @@ sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 
 	link_info->link_autoneg = ETH_LINK_AUTONEG;
 }
+
+int
+sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
+		       unsigned int xstats_count, unsigned int *nb_written)
+{
+	struct sfc_port *port = &sa->port;
+	uint64_t *mac_stats;
+	unsigned int i;
+	int nstats = 0;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	ret = sfc_port_update_mac_stats(sa, B_FALSE);
+	if (ret != 0) {
+		SFC_ASSERT(ret > 0);
+		ret = -ret;
+		goto unlock;
+	}
+
+	mac_stats = port->mac_stats_buf;
+
+	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
+		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
+			if (nstats < (int)xstats_count) {
+				xstats[nstats].id = nstats;
+				xstats[nstats].value = mac_stats[i];
+				(*nb_written)++;
+			}
+			nstats++;
+		}
+	}
+	ret = nstats;
+
+unlock:
+	sfc_adapter_unlock(sa);
+
+	return ret;
+}
+
+int
+sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+			     uint64_t *values, unsigned int n)
+{
+	struct sfc_port *port = &sa->port;
+	uint64_t *mac_stats;
+	unsigned int i;
+	int ret;
+	int rc;
+
+	sfc_adapter_lock(sa);
+
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
+	if (rc != 0) {
+		SFC_ASSERT(rc > 0);
+		ret = -rc;
+		goto unlock;
+	}
+
+	mac_stats = port->mac_stats_buf;
+
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
+
+	for (i = 0; i < n; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
+		} else {
+			ret = i;
+			goto unlock;
+		}
+	}
+
+	ret = n;
+
+unlock:
+	sfc_adapter_unlock(sa);
+
+	return ret;
+}
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 10/11] net/sfc: add xstats for Rx/Tx doorbells
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (8 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 09/11] net/sfc: prepare to add more xstats Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
  10 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev; +Cc: David Marchand, Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Rx/Tx doorbells statistics are collected in software and
available per queue. These stats are useful for performance
investigation.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/meson.build        |   1 +
 drivers/net/sfc/sfc.c              |  16 +
 drivers/net/sfc/sfc.h              |   9 +
 drivers/net/sfc/sfc_dp.h           |  10 +
 drivers/net/sfc/sfc_ef10.h         |   3 +-
 drivers/net/sfc/sfc_ef100_rx.c     |   1 +
 drivers/net/sfc/sfc_ef100_tx.c     |   1 +
 drivers/net/sfc/sfc_ef10_essb_rx.c |   3 +-
 drivers/net/sfc/sfc_ef10_rx.c      |   3 +-
 drivers/net/sfc/sfc_ef10_tx.c      |   1 +
 drivers/net/sfc/sfc_ethdev.c       | 124 +++++--
 drivers/net/sfc/sfc_port.c         |  10 +-
 drivers/net/sfc/sfc_rx.c           |   1 +
 drivers/net/sfc/sfc_sw_stats.c     | 572 +++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_sw_stats.h     |  49 +++
 drivers/net/sfc/sfc_tx.c           |   4 +-
 16 files changed, 772 insertions(+), 36 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_sw_stats.c
 create mode 100644 drivers/net/sfc/sfc_sw_stats.h

diff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build
index 4625859077..a912cdccfa 100644
--- a/drivers/net/sfc/meson.build
+++ b/drivers/net/sfc/meson.build
@@ -70,6 +70,7 @@ sources = files(
         'sfc.c',
         'sfc_mcdi.c',
         'sfc_sriov.c',
+        'sfc_sw_stats.c',
         'sfc_intr.c',
         'sfc_ev.c',
         'sfc_port.c',
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 4097cf39de..274a98e228 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -24,6 +24,7 @@
 #include "sfc_tx.h"
 #include "sfc_kvargs.h"
 #include "sfc_tweak.h"
+#include "sfc_sw_stats.h"
 
 
 int
@@ -636,10 +637,17 @@ sfc_configure(struct sfc_adapter *sa)
 	if (rc != 0)
 		goto fail_tx_configure;
 
+	rc = sfc_sw_xstats_configure(sa);
+	if (rc != 0)
+		goto fail_sw_xstats_configure;
+
 	sa->state = SFC_ADAPTER_CONFIGURED;
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_sw_xstats_configure:
+	sfc_tx_close(sa);
+
 fail_tx_configure:
 	sfc_rx_close(sa);
 
@@ -666,6 +674,7 @@ sfc_close(struct sfc_adapter *sa)
 	SFC_ASSERT(sa->state == SFC_ADAPTER_CONFIGURED);
 	sa->state = SFC_ADAPTER_CLOSING;
 
+	sfc_sw_xstats_close(sa);
 	sfc_tx_close(sa);
 	sfc_rx_close(sa);
 	sfc_port_close(sa);
@@ -891,6 +900,10 @@ sfc_attach(struct sfc_adapter *sa)
 
 	sfc_flow_init(sa);
 
+	rc = sfc_sw_xstats_init(sa);
+	if (rc != 0)
+		goto fail_sw_xstats_init;
+
 	/*
 	 * Create vSwitch to be able to use VFs when PF is not started yet
 	 * as DPDK port. VFs should be able to talk to each other even
@@ -906,6 +919,9 @@ sfc_attach(struct sfc_adapter *sa)
 	return 0;
 
 fail_sriov_vswitch_create:
+	sfc_sw_xstats_close(sa);
+
+fail_sw_xstats_init:
 	sfc_flow_fini(sa);
 	sfc_mae_detach(sa);
 
diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 58b8c2c2ad..331e06bac6 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -217,6 +217,14 @@ struct sfc_counter_rxq {
 	struct rte_mempool		*mp;
 };
 
+struct sfc_sw_xstats {
+	uint64_t			*reset_vals;
+
+	rte_spinlock_t			queues_bitmap_lock;
+	void				*queues_bitmap_mem;
+	struct rte_bitmap		*queues_bitmap;
+};
+
 /* Adapter private data */
 struct sfc_adapter {
 	/*
@@ -249,6 +257,7 @@ struct sfc_adapter {
 	struct sfc_sriov		sriov;
 	struct sfc_intr			intr;
 	struct sfc_port			port;
+	struct sfc_sw_xstats		sw_xstats;
 	struct sfc_filter		filter;
 	struct sfc_mae			mae;
 
diff --git a/drivers/net/sfc/sfc_dp.h b/drivers/net/sfc/sfc_dp.h
index 61c1a3fbac..7fd8f34b0f 100644
--- a/drivers/net/sfc/sfc_dp.h
+++ b/drivers/net/sfc/sfc_dp.h
@@ -42,6 +42,16 @@ enum sfc_dp_type {
 
 /** Datapath queue run-time information */
 struct sfc_dp_queue {
+	/*
+	 * Typically the structure is located at the end of Rx/Tx queue
+	 * data structure and not used on datapath. So, it is not a
+	 * problem to have extra fields even if not used. However,
+	 * put stats at top of the structure to be closer to fields
+	 * used on datapath or reap to have more chances to be cache-hot.
+	 */
+	uint32_t			rx_dbells;
+	uint32_t			tx_dbells;
+
 	uint16_t			port_id;
 	uint16_t			queue_id;
 	struct rte_pci_addr		pci_addr;
diff --git a/drivers/net/sfc/sfc_ef10.h b/drivers/net/sfc/sfc_ef10.h
index ad4c1fdbef..e9bb72e28b 100644
--- a/drivers/net/sfc/sfc_ef10.h
+++ b/drivers/net/sfc/sfc_ef10.h
@@ -99,7 +99,7 @@ sfc_ef10_ev_present(const efx_qword_t ev)
 
 static inline void
 sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,
-		  unsigned int ptr_mask)
+		  unsigned int ptr_mask, uint32_t *dbell_counter)
 {
 	efx_dword_t dword;
 
@@ -118,6 +118,7 @@ sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], doorbell);
+	(*dbell_counter)++;
 }
 
 static inline void
diff --git a/drivers/net/sfc/sfc_ef100_rx.c b/drivers/net/sfc/sfc_ef100_rx.c
index 10c74aa118..d4cb96881c 100644
--- a/drivers/net/sfc/sfc_ef100_rx.c
+++ b/drivers/net/sfc/sfc_ef100_rx.c
@@ -119,6 +119,7 @@ sfc_ef100_rx_qpush(struct sfc_ef100_rxq *rxq, unsigned int added)
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], rxq->doorbell);
+	rxq->dp.dpq.rx_dbells++;
 
 	sfc_ef100_rx_debug(rxq, "RxQ pushed doorbell at pidx %u (added=%u)",
 			   EFX_DWORD_FIELD(dword, ERF_GZ_RX_RING_PIDX),
diff --git a/drivers/net/sfc/sfc_ef100_tx.c b/drivers/net/sfc/sfc_ef100_tx.c
index f9ad6f7b73..522e9a0d34 100644
--- a/drivers/net/sfc/sfc_ef100_tx.c
+++ b/drivers/net/sfc/sfc_ef100_tx.c
@@ -489,6 +489,7 @@ sfc_ef100_tx_qpush(struct sfc_ef100_txq *txq, unsigned int added)
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], txq->doorbell);
+	txq->dp.dpq.tx_dbells++;
 
 	sfc_ef100_tx_debug(txq, "TxQ pushed doorbell at pidx %u (added=%u)",
 			   EFX_DWORD_FIELD(dword, ERF_GZ_TX_RING_PIDX),
diff --git a/drivers/net/sfc/sfc_ef10_essb_rx.c b/drivers/net/sfc/sfc_ef10_essb_rx.c
index 3c246eb149..991329e86f 100644
--- a/drivers/net/sfc/sfc_ef10_essb_rx.c
+++ b/drivers/net/sfc/sfc_ef10_essb_rx.c
@@ -220,7 +220,8 @@ sfc_ef10_essb_rx_qrefill(struct sfc_ef10_essb_rxq *rxq)
 
 	SFC_ASSERT(rxq->added != added);
 	rxq->added = added;
-	sfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask);
+	sfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask,
+			  &rxq->dp.dpq.rx_dbells);
 }
 
 static bool
diff --git a/drivers/net/sfc/sfc_ef10_rx.c b/drivers/net/sfc/sfc_ef10_rx.c
index 2b4393d232..49a7d4fb42 100644
--- a/drivers/net/sfc/sfc_ef10_rx.c
+++ b/drivers/net/sfc/sfc_ef10_rx.c
@@ -171,7 +171,8 @@ sfc_ef10_rx_qrefill(struct sfc_ef10_rxq *rxq)
 
 	SFC_ASSERT(rxq->added != added);
 	rxq->added = added;
-	sfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask);
+	sfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask,
+			  &rxq->dp.dpq.rx_dbells);
 }
 
 static void
diff --git a/drivers/net/sfc/sfc_ef10_tx.c b/drivers/net/sfc/sfc_ef10_tx.c
index a8d34ead33..ed43adb4ca 100644
--- a/drivers/net/sfc/sfc_ef10_tx.c
+++ b/drivers/net/sfc/sfc_ef10_tx.c
@@ -248,6 +248,7 @@ sfc_ef10_tx_qpush(struct sfc_ef10_txq *txq, unsigned int added,
 	rte_io_wmb();
 
 	*(volatile efsys_uint128_t *)txq->doorbell = oword.eo_u128[0];
+	txq->dp.dpq.tx_dbells++;
 }
 
 static unsigned int
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index dd7e5c253a..2db0d000c3 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -28,6 +28,10 @@
 #include "sfc_flow.h"
 #include "sfc_dp.h"
 #include "sfc_dp_rx.h"
+#include "sfc_sw_stats.h"
+
+#define SFC_XSTAT_ID_INVALID_VAL  UINT64_MAX
+#define SFC_XSTAT_ID_INVALID_NAME '\0'
 
 uint32_t sfc_logtype_driver;
 
@@ -714,29 +718,49 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	if (rc != 0)
 		sfc_err(sa, "failed to reset statistics (rc = %d)", rc);
 
+	sfc_sw_xstats_reset(sa);
+
 	sfc_adapter_unlock(sa);
 
 	SFC_ASSERT(rc >= 0);
 	return -rc;
 }
 
+static unsigned int
+sfc_xstats_get_nb_supported(struct sfc_adapter *sa)
+{
+	struct sfc_port *port = &sa->port;
+	unsigned int nb_supported;
+
+	sfc_adapter_lock(sa);
+	nb_supported = port->mac_stats_nb_supported +
+		       sfc_sw_xstats_get_nb_supported(sa);
+	sfc_adapter_unlock(sa);
+
+	return nb_supported;
+}
+
 static int
 sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	       unsigned int xstats_count)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
 	unsigned int nb_written = 0;
-	unsigned int nb_supp;
+	unsigned int nb_supported = 0;
+	int rc;
 
-	if (unlikely(xstats == NULL)) {
-		sfc_adapter_lock(sa);
-		nb_supp = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nb_supp;
-	}
+	if (unlikely(xstats == NULL))
+		return sfc_xstats_get_nb_supported(sa);
+
+	rc = sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
+	if (rc < 0)
+		return rc;
 
-	return sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
+	nb_supported = rc;
+	sfc_sw_xstats_get_vals(sa, xstats, xstats_count, &nb_written,
+			       &nb_supported);
+
+	return nb_supported;
 }
 
 static int
@@ -748,24 +772,31 @@ sfc_xstats_get_names(struct rte_eth_dev *dev,
 	struct sfc_port *port = &sa->port;
 	unsigned int i;
 	unsigned int nstats = 0;
+	unsigned int nb_written = 0;
+	int ret;
 
-	if (unlikely(xstats_names == NULL)) {
-		sfc_adapter_lock(sa);
-		nstats = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nstats;
-	}
+	if (unlikely(xstats_names == NULL))
+		return sfc_xstats_get_nb_supported(sa);
 
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < xstats_count)
+			if (nstats < xstats_count) {
 				strlcpy(xstats_names[nstats].name,
 					efx_mac_stat_name(sa->nic, i),
 					sizeof(xstats_names[0].name));
+				nb_written++;
+			}
 			nstats++;
 		}
 	}
 
+	ret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,
+				      &nb_written, &nstats);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
 	return nstats;
 }
 
@@ -774,11 +805,35 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+	struct sfc_port *port = &sa->port;
+	unsigned int nb_supported;
+	unsigned int i;
+	int rc;
 
 	if (unlikely(ids == NULL || values == NULL))
 		return -EINVAL;
 
-	return sfc_port_get_mac_stats_by_id(sa, ids, values, n);
+	/*
+	 * Values array could be filled in nonsequential order. Fill values with
+	 * constant indicating invalid ID first.
+	 */
+	for (i = 0; i < n; i++)
+		values[i] = SFC_XSTAT_ID_INVALID_VAL;
+
+	rc = sfc_port_get_mac_stats_by_id(sa, ids, values, n);
+	if (rc != 0)
+		return rc;
+
+	nb_supported = port->mac_stats_nb_supported;
+	sfc_sw_xstats_get_vals_by_id(sa, ids, values, n, &nb_supported);
+
+	/* Return number of written stats before invalid ID is encountered. */
+	for (i = 0; i < n; i++) {
+		if (values[i] == SFC_XSTAT_ID_INVALID_VAL)
+			return i;
+	}
+
+	return n;
 }
 
 static int
@@ -790,18 +845,23 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	struct sfc_port *port = &sa->port;
 	unsigned int nb_supported;
 	unsigned int i;
+	int ret;
 
 	if (unlikely(xstats_names == NULL && ids != NULL) ||
 	    unlikely(xstats_names != NULL && ids == NULL))
 		return -EINVAL;
 
-	sfc_adapter_lock(sa);
+	if (unlikely(xstats_names == NULL && ids == NULL))
+		return sfc_xstats_get_nb_supported(sa);
 
-	if (unlikely(xstats_names == NULL && ids == NULL)) {
-		nb_supported = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nb_supported;
-	}
+	/*
+	 * Names array could be filled in nonsequential order. Fill names with
+	 * string indicating invalid ID first.
+	 */
+	for (i = 0; i < size; i++)
+		xstats_names[i].name[0] = SFC_XSTAT_ID_INVALID_NAME;
+
+	sfc_adapter_lock(sa);
 
 	SFC_ASSERT(port->mac_stats_nb_supported <=
 		   RTE_DIM(port->mac_stats_by_id));
@@ -812,14 +872,26 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 				efx_mac_stat_name(sa->nic,
 						 port->mac_stats_by_id[ids[i]]),
 				sizeof(xstats_names[0].name));
-		} else {
-			sfc_adapter_unlock(sa);
-			return i;
 		}
 	}
 
+	nb_supported = port->mac_stats_nb_supported;
+
 	sfc_adapter_unlock(sa);
 
+	ret = sfc_sw_xstats_get_names_by_id(sa, ids, xstats_names, size,
+					    &nb_supported);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
+	/* Return number of written names before invalid ID is encountered. */
+	for (i = 0; i < size; i++) {
+		if (xstats_names[i].name[0] == SFC_XSTAT_ID_INVALID_NAME)
+			return i;
+	}
+
 	return size;
 }
 
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index f6689a17c0..adb2b2cb81 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -7,6 +7,8 @@
  * for Solarflare) and Solarflare Communications, Inc.
  */
 
+#include <rte_bitmap.h>
+
 #include "efx.h"
 
 #include "sfc.h"
@@ -701,15 +703,11 @@ sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
 		   RTE_DIM(port->mac_stats_by_id));
 
 	for (i = 0; i < n; i++) {
-		if (ids[i] < port->mac_stats_nb_supported) {
+		if (ids[i] < port->mac_stats_nb_supported)
 			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
-		} else {
-			ret = i;
-			goto unlock;
-		}
 	}
 
-	ret = n;
+	ret = 0;
 
 unlock:
 	sfc_adapter_unlock(sa);
diff --git a/drivers/net/sfc/sfc_rx.c b/drivers/net/sfc/sfc_rx.c
index f6a8ac68e8..280e8a61f9 100644
--- a/drivers/net/sfc/sfc_rx.c
+++ b/drivers/net/sfc/sfc_rx.c
@@ -138,6 +138,7 @@ sfc_efx_rx_qrefill(struct sfc_efx_rxq *rxq)
 	SFC_ASSERT(added != rxq->added);
 	rxq->added = added;
 	efx_rx_qpush(rxq->common, added, &rxq->pushed);
+	rxq->dp.dpq.rx_dbells++;
 }
 
 static uint64_t
diff --git a/drivers/net/sfc/sfc_sw_stats.c b/drivers/net/sfc/sfc_sw_stats.c
new file mode 100644
index 0000000000..8489b603f5
--- /dev/null
+++ b/drivers/net/sfc/sfc_sw_stats.c
@@ -0,0 +1,572 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2021 Xilinx, Inc.
+ */
+#include <rte_dev.h>
+#include <rte_bitmap.h>
+
+#include "sfc.h"
+#include "sfc_rx.h"
+#include "sfc_tx.h"
+#include "sfc_sw_stats.h"
+
+enum sfc_sw_stats_type {
+	SFC_SW_STATS_RX,
+	SFC_SW_STATS_TX,
+};
+
+typedef uint64_t sfc_get_sw_xstat_val_t(struct sfc_adapter *sa, uint16_t qid);
+
+struct sfc_sw_xstat_descr {
+	const char *name;
+	enum sfc_sw_stats_type type;
+	sfc_get_sw_xstat_val_t *get_val;
+};
+
+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_rx_dbells;
+static uint64_t
+sfc_get_sw_xstat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	struct sfc_rxq_info *rxq_info;
+
+	rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);
+	if (rxq_info->state & SFC_RXQ_INITIALIZED)
+		return rxq_info->dp->dpq.rx_dbells;
+	return 0;
+}
+
+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_tx_dbells;
+static uint64_t
+sfc_get_sw_xstat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	struct sfc_txq_info *txq_info;
+
+	txq_info = sfc_txq_info_by_ethdev_qid(sas, qid);
+	if (txq_info->state & SFC_TXQ_INITIALIZED)
+		return txq_info->dp->dpq.tx_dbells;
+	return 0;
+}
+
+struct sfc_sw_xstat_descr sfc_sw_xstats[] = {
+	{
+		.name = "dbells",
+		.type = SFC_SW_STATS_RX,
+		.get_val  = sfc_get_sw_xstat_val_rx_dbells,
+	},
+	{
+		.name = "dbells",
+		.type = SFC_SW_STATS_TX,
+		.get_val  = sfc_get_sw_xstat_val_tx_dbells,
+	}
+};
+
+static int
+sfc_sw_stat_get_name(struct sfc_adapter *sa,
+		     const struct sfc_sw_xstat_descr *sw_xstat, char *name,
+		     size_t name_size, unsigned int id_off)
+{
+	const char *prefix;
+	int ret;
+
+	switch (sw_xstat->type) {
+	case SFC_SW_STATS_RX:
+		prefix = "rx";
+		break;
+	case SFC_SW_STATS_TX:
+		prefix = "tx";
+		break;
+	default:
+		sfc_err(sa, "%s: unknown software statistics type %d",
+			__func__, sw_xstat->type);
+		return -EINVAL;
+	}
+
+	if (id_off == 0) {
+		ret = snprintf(name, name_size, "%s_%s", prefix,
+							 sw_xstat->name);
+		if (ret < 0 || ret >= (int)name_size) {
+			sfc_err(sa, "%s: failed to fill xstat name %s_%s, err %d",
+				__func__, prefix, sw_xstat->name, ret);
+			return ret > 0 ? -EINVAL : ret;
+		}
+	} else {
+		uint16_t qid = id_off - 1;
+		ret = snprintf(name, name_size, "%s_q%u_%s", prefix, qid,
+							sw_xstat->name);
+		if (ret < 0 || ret >= (int)name_size) {
+			sfc_err(sa, "%s: failed to fill xstat name %s_q%u_%s, err %d",
+				__func__, prefix, qid, sw_xstat->name, ret);
+			return ret > 0 ? -EINVAL : ret;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned int
+sfc_sw_stat_get_queue_count(struct sfc_adapter *sa,
+			    const struct sfc_sw_xstat_descr *sw_xstat)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+
+	switch (sw_xstat->type) {
+	case SFC_SW_STATS_RX:
+		return sas->ethdev_rxq_count;
+	case SFC_SW_STATS_TX:
+		return sas->ethdev_txq_count;
+	default:
+		sfc_err(sa, "%s: unknown software statistics type %d",
+			__func__, sw_xstat->type);
+		return 0;
+	}
+}
+
+static unsigned int
+sfc_sw_xstat_per_queue_get_count(unsigned int nb_queues)
+{
+	/* Take into account the accumulative xstat of all queues */
+	return nb_queues > 0 ? 1 + nb_queues : 0;
+}
+
+static unsigned int
+sfc_sw_xstat_get_nb_supported(struct sfc_adapter *sa,
+			      const struct sfc_sw_xstat_descr *sw_xstat)
+{
+	unsigned int nb_queues;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	return sfc_sw_xstat_per_queue_get_count(nb_queues);
+}
+
+static int
+sfc_sw_stat_get_names(struct sfc_adapter *sa,
+		      const struct sfc_sw_xstat_descr *sw_xstat,
+		      struct rte_eth_xstat_name *xstats_names,
+		      unsigned int xstats_names_sz,
+		      unsigned int *nb_written,
+		      unsigned int *nb_supported)
+{
+	const size_t name_size = sizeof(xstats_names[0].name);
+	unsigned int id_base = *nb_supported;
+	unsigned int nb_queues;
+	unsigned int qid;
+	int rc;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return 0;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	if (*nb_written < xstats_names_sz) {
+		rc = sfc_sw_stat_get_name(sa, sw_xstat,
+					  xstats_names[*nb_written].name,
+					  name_size, *nb_written - id_base);
+		if (rc != 0)
+			return rc;
+		(*nb_written)++;
+	}
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		if (*nb_written < xstats_names_sz) {
+			rc = sfc_sw_stat_get_name(sa, sw_xstat,
+					      xstats_names[*nb_written].name,
+					      name_size, *nb_written - id_base);
+			if (rc != 0)
+				return rc;
+			(*nb_written)++;
+		}
+	}
+
+	return 0;
+}
+
+static int
+sfc_sw_xstat_get_names_by_id(struct sfc_adapter *sa,
+			     const struct sfc_sw_xstat_descr *sw_xstat,
+			     const uint64_t *ids,
+			     struct rte_eth_xstat_name *xstats_names,
+			     unsigned int size,
+			     unsigned int *nb_supported)
+{
+	const size_t name_size = sizeof(xstats_names[0].name);
+	unsigned int id_base = *nb_supported;
+	unsigned int nb_queues;
+	unsigned int i;
+	int rc;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return 0;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	for (i = 0; i < size; i++) {
+		if (id_base <= ids[i] && ids[i] <= id_base + nb_queues) {
+			rc = sfc_sw_stat_get_name(sa, sw_xstat,
+						  xstats_names[i].name,
+						  name_size, ids[i] - id_base);
+			if (rc != 0)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static void
+sfc_sw_xstat_get_values(struct sfc_adapter *sa,
+			const struct sfc_sw_xstat_descr *sw_xstat,
+			struct rte_eth_xstat *xstats,
+			unsigned int xstats_size,
+			unsigned int *nb_written,
+			unsigned int *nb_supported)
+{
+	unsigned int qid;
+	uint64_t value;
+	struct rte_eth_xstat *accum_xstat;
+	bool count_accum_value = false;
+	unsigned int nb_queues;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	if (*nb_written < xstats_size) {
+		count_accum_value = true;
+		accum_xstat = &xstats[*nb_written];
+		xstats[*nb_written].id = *nb_written;
+		xstats[*nb_written].value = 0;
+		(*nb_written)++;
+	}
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		value = sw_xstat->get_val(sa, qid);
+
+		if (*nb_written < xstats_size) {
+			xstats[*nb_written].id = *nb_written;
+			xstats[*nb_written].value = value;
+			(*nb_written)++;
+		}
+
+		if (count_accum_value)
+			accum_xstat->value += value;
+	}
+}
+
+static void
+sfc_sw_xstat_get_values_by_id(struct sfc_adapter *sa,
+			      const struct sfc_sw_xstat_descr *sw_xstat,
+			      const uint64_t *ids,
+			      uint64_t *values,
+			      unsigned int ids_size,
+			      unsigned int *nb_supported)
+{
+	rte_spinlock_t *bmp_lock = &sa->sw_xstats.queues_bitmap_lock;
+	struct rte_bitmap *bmp = sa->sw_xstats.queues_bitmap;
+	unsigned int id_base = *nb_supported;
+	bool count_accum_value = false;
+	unsigned int accum_value_idx;
+	uint64_t accum_value = 0;
+	unsigned int i, qid;
+	unsigned int nb_queues;
+
+
+	rte_spinlock_lock(bmp_lock);
+	rte_bitmap_reset(bmp);
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		goto unlock;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	for (i = 0; i < ids_size; i++) {
+		if (id_base <= ids[i] && ids[i] <= (id_base + nb_queues)) {
+			if (ids[i] == id_base) { /* Accumulative value */
+				count_accum_value = true;
+				accum_value_idx = i;
+				continue;
+			}
+			qid = ids[i] - id_base - 1;
+			values[i] = sw_xstat->get_val(sa, qid);
+			accum_value += values[i];
+
+			rte_bitmap_set(bmp, qid);
+		}
+	}
+
+	if (count_accum_value) {
+		for (qid = 0; qid < nb_queues; ++qid) {
+			if (rte_bitmap_get(bmp, qid) != 0)
+				continue;
+			values[accum_value_idx] += sw_xstat->get_val(sa, qid);
+		}
+		values[accum_value_idx] += accum_value;
+	}
+
+unlock:
+	rte_spinlock_unlock(bmp_lock);
+}
+
+unsigned int
+sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa)
+{
+	unsigned int nb_supported = 0;
+	unsigned int i;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
+							     &sfc_sw_xstats[i]);
+	}
+
+	return nb_supported;
+}
+
+void
+sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
+		       struct rte_eth_xstat *xstats,
+		       unsigned int xstats_count,
+		       unsigned int *nb_written,
+		       unsigned int *nb_supported)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	unsigned int sw_xstats_offset;
+	unsigned int i;
+
+	sfc_adapter_lock(sa);
+
+	sw_xstats_offset = *nb_supported;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sfc_sw_xstat_get_values(sa, &sfc_sw_xstats[i], xstats,
+					xstats_count, nb_written, nb_supported);
+	}
+
+	for (i = sw_xstats_offset; i < *nb_written; i++)
+		xstats[i].value -= reset_vals[i - sw_xstats_offset];
+
+	sfc_adapter_unlock(sa);
+}
+
+int
+sfc_sw_xstats_get_names(struct sfc_adapter *sa,
+			struct rte_eth_xstat_name *xstats_names,
+			unsigned int xstats_count,
+			unsigned int *nb_written,
+			unsigned int *nb_supported)
+{
+	unsigned int i;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		ret = sfc_sw_stat_get_names(sa, &sfc_sw_xstats[i],
+					    xstats_names, xstats_count,
+					    nb_written, nb_supported);
+		if (ret != 0) {
+			sfc_adapter_unlock(sa);
+			return ret;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return 0;
+}
+
+void
+sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,
+			     const uint64_t *ids,
+			     uint64_t *values,
+			     unsigned int n,
+			     unsigned int *nb_supported)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	unsigned int sw_xstats_offset;
+	unsigned int i;
+
+	sfc_adapter_lock(sa);
+
+	sw_xstats_offset = *nb_supported;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sfc_sw_xstat_get_values_by_id(sa, &sfc_sw_xstats[i], ids,
+					      values, n, nb_supported);
+	}
+
+	for (i = 0; i < n; i++) {
+		if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)
+			values[i] -= reset_vals[ids[i] - sw_xstats_offset];
+	}
+
+	sfc_adapter_unlock(sa);
+}
+
+int
+sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,
+			      const uint64_t *ids,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int size,
+			      unsigned int *nb_supported)
+{
+	unsigned int i;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		ret = sfc_sw_xstat_get_names_by_id(sa, &sfc_sw_xstats[i], ids,
+						   xstats_names, size,
+						   nb_supported);
+		if (ret != 0) {
+			sfc_adapter_unlock(sa);
+			SFC_ASSERT(ret < 0);
+			return ret;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return 0;
+}
+
+static void
+sfc_sw_xstat_reset(struct sfc_adapter *sa, struct sfc_sw_xstat_descr *sw_xstat,
+		   uint64_t *reset_vals)
+{
+	unsigned int nb_queues;
+	unsigned int qid;
+	uint64_t *accum_xstat_reset;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return;
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	accum_xstat_reset = reset_vals;
+	*accum_xstat_reset = 0;
+	reset_vals++;
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		reset_vals[qid] = sw_xstat->get_val(sa, qid);
+		*accum_xstat_reset += reset_vals[qid];
+	}
+}
+
+void
+sfc_sw_xstats_reset(struct sfc_adapter *sa)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	struct sfc_sw_xstat_descr *sw_xstat;
+	unsigned int i;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sw_xstat = &sfc_sw_xstats[i];
+		sfc_sw_xstat_reset(sa, sw_xstat, reset_vals);
+		reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_xstat);
+	}
+}
+
+int
+sfc_sw_xstats_configure(struct sfc_adapter *sa)
+{
+	uint64_t **reset_vals = &sa->sw_xstats.reset_vals;
+	size_t nb_supported = 0;
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++)
+		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
+							&sfc_sw_xstats[i]);
+
+	*reset_vals = rte_realloc(*reset_vals,
+				  nb_supported * sizeof(**reset_vals), 0);
+	if (*reset_vals == NULL)
+		return ENOMEM;
+
+	memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));
+
+	return 0;
+}
+
+static void
+sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)
+{
+	rte_bitmap_free(sa->sw_xstats.queues_bitmap);
+	rte_free(sa->sw_xstats.queues_bitmap_mem);
+}
+
+static int
+sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)
+{
+	struct rte_bitmap **queues_bitmap = &sa->sw_xstats.queues_bitmap;
+	void **queues_bitmap_mem = &sa->sw_xstats.queues_bitmap_mem;
+	uint32_t bmp_size;
+	int rc;
+
+	bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);
+	*queues_bitmap_mem = NULL;
+	*queues_bitmap = NULL;
+
+	*queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0,
+					       sa->socket_id);
+	if (*queues_bitmap_mem == NULL)
+		return ENOMEM;
+
+	*queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,
+					 *queues_bitmap_mem, bmp_size);
+	if (*queues_bitmap == NULL) {
+		rc = EINVAL;
+		goto fail;
+	}
+
+	rte_spinlock_init(&sa->sw_xstats.queues_bitmap_lock);
+	return 0;
+
+fail:
+	sfc_sw_xstats_free_queues_bitmap(sa);
+	return rc;
+}
+
+int
+sfc_sw_xstats_init(struct sfc_adapter *sa)
+{
+	sa->sw_xstats.reset_vals = NULL;
+
+	return sfc_sw_xstats_alloc_queues_bitmap(sa);
+}
+
+void
+sfc_sw_xstats_close(struct sfc_adapter *sa)
+{
+	rte_free(sa->sw_xstats.reset_vals);
+	sa->sw_xstats.reset_vals = NULL;
+
+	sfc_sw_xstats_free_queues_bitmap(sa);
+}
diff --git a/drivers/net/sfc/sfc_sw_stats.h b/drivers/net/sfc/sfc_sw_stats.h
new file mode 100644
index 0000000000..1abded8018
--- /dev/null
+++ b/drivers/net/sfc/sfc_sw_stats.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2021 Xilinx, Inc.
+ */
+#ifndef _SFC_SW_STATS_H
+#define _SFC_SW_STATS_H
+
+#include <rte_dev.h>
+
+#include "sfc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
+			    struct rte_eth_xstat *xstats,
+			    unsigned int xstats_count, unsigned int *nb_written,
+			    unsigned int *nb_supported);
+
+int sfc_sw_xstats_get_names(struct sfc_adapter *sa,
+			    struct rte_eth_xstat_name *xstats_names,
+			    unsigned int xstats_count, unsigned int *nb_written,
+			    unsigned int *nb_supported);
+
+void sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				  uint64_t *values, unsigned int n,
+				  unsigned int *nb_supported);
+
+int sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				  struct rte_eth_xstat_name *xstats_names,
+				  unsigned int size,
+				  unsigned int *nb_supported);
+
+unsigned int sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa);
+
+int sfc_sw_xstats_configure(struct sfc_adapter *sa);
+
+void sfc_sw_xstats_reset(struct sfc_adapter *sa);
+
+int sfc_sw_xstats_init(struct sfc_adapter *sa);
+
+void sfc_sw_xstats_close(struct sfc_adapter *sa);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _SFC_SW_STATS_H */
diff --git a/drivers/net/sfc/sfc_tx.c b/drivers/net/sfc/sfc_tx.c
index ce2a9a6a4f..49b239f4d2 100644
--- a/drivers/net/sfc/sfc_tx.c
+++ b/drivers/net/sfc/sfc_tx.c
@@ -980,8 +980,10 @@ sfc_efx_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 				       txq->completed, &txq->added);
 		SFC_ASSERT(rc == 0);
 
-		if (likely(pushed != txq->added))
+		if (likely(pushed != txq->added)) {
 			efx_tx_qpush(txq->common, txq->added, pushed);
+			txq->dp.dpq.tx_dbells++;
+		}
 	}
 
 #if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (9 preceding siblings ...)
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 10/11] net/sfc: add xstats for Rx/Tx doorbells Andrew Rybchenko
@ 2021-07-22  9:54   ` Andrew Rybchenko
  2021-07-22 19:43     ` David Marchand
  2021-07-22 20:15     ` David Marchand
  10 siblings, 2 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-22  9:54 UTC (permalink / raw)
  To: dev, Xiaoyun Li; +Cc: David Marchand, Ivan Ilchenko

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
(i.e. 'stats-period' option or 'show port stats' interactive command) to
display specified list of extended statistics.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 app/test-pmd/cmdline.c                |  56 ++++++++++++
 app/test-pmd/config.c                 |  66 ++++++++++++++
 app/test-pmd/parameters.c             |  18 ++++
 app/test-pmd/testpmd.c                | 122 ++++++++++++++++++++++++++
 app/test-pmd/testpmd.h                |  21 +++++
 doc/guides/testpmd_app_ug/run_app.rst |   5 ++
 6 files changed, 288 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 8468018cf3..baffef1642 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -3609,6 +3609,62 @@ cmdline_parse_inst_t cmd_stop = {
 
 /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
 
+int
+parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
+		  unsigned int *xstats_num)
+{
+	int max_names_nb, names_nb;
+	int stringlen;
+	char **names;
+	char *str;
+	int ret;
+	int i;
+
+	names = NULL;
+	str = strdup(in_str);
+	if (str == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+	stringlen = strlen(str);
+
+	for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
+		if (str[i] == ',')
+			max_names_nb++;
+	}
+
+	names = calloc(max_names_nb, sizeof(*names));
+	if (names == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
+	printf("max names is %d\n", max_names_nb);
+	if (names_nb < 0) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	*xstats = calloc(names_nb, sizeof(**xstats));
+	if (*xstats == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < names_nb; i++)
+		rte_strscpy((*xstats)[i].name, names[i],
+			    sizeof((*xstats)[i].name));
+
+	*xstats_num = names_nb;
+	ret = 0;
+
+out:
+	free(names);
+	free(str);
+	return ret;
+}
+
 unsigned int
 parse_item_list(const char *str, const char *item_name, unsigned int max_items,
 		unsigned int *parsed_items, int check_unique_values)
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 04ae0feb58..6d604145bd 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -173,6 +173,70 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
 	printf("%s%s", name, buf);
 }
 
+static void
+nic_xstats_display_periodic(portid_t port_id)
+{
+	struct xstat_display_info *xstats_info;
+	uint64_t *prev_values, *curr_values;
+	uint64_t diff_value, value_rate;
+	uint64_t *ids, *ids_supp;
+	struct timespec cur_time;
+	unsigned int i, i_supp;
+	size_t ids_supp_sz;
+	uint64_t diff_ns;
+	int rc;
+
+	xstats_info = &xstats_per_port[port_id];
+
+	ids_supp_sz = xstats_info->ids_supp_sz;
+	if (xstats_display_num == 0 || ids_supp_sz == 0)
+		return;
+
+	printf("\n");
+
+	ids = xstats_info->ids;
+	ids_supp = xstats_info->ids_supp;
+	prev_values = xstats_info->prev_values;
+	curr_values = xstats_info->curr_values;
+
+	rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
+				      ids_supp_sz);
+	if (rc != (int)ids_supp_sz) {
+		fprintf(stderr, "%s: Failed to get values of %zu supported xstats for port %u - return code %d\n",
+			__func__, ids_supp_sz, port_id, rc);
+		return;
+	}
+
+	diff_ns = 0;
+	if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
+		uint64_t ns;
+
+		ns = cur_time.tv_sec * NS_PER_SEC;
+		ns += cur_time.tv_nsec;
+
+		if (xstats_info->prev_ns != 0)
+			diff_ns = ns - xstats_info->prev_ns;
+		xstats_info->prev_ns = ns;
+	}
+
+	printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
+	for (i = i_supp = 0; i < xstats_display_num; i++) {
+		if (ids[i] == XSTAT_ID_INVALID)
+			continue;
+
+		diff_value = (curr_values[i_supp] > prev_values[i]) ?
+			     (curr_values[i_supp] - prev_values[i]) : 0;
+		prev_values[i] = curr_values[i_supp];
+		value_rate = diff_ns > 0 ?
+				(double)diff_value / diff_ns * NS_PER_SEC : 0;
+
+		printf("  %-25s%12"PRIu64" %15"PRIu64"\n",
+		       xstats_display[i].name, curr_values[i_supp], value_rate);
+
+		i_supp++;
+	}
+}
+
 void
 nic_stats_display(portid_t port_id)
 {
@@ -243,6 +307,8 @@ nic_stats_display(portid_t port_id)
 	       PRIu64"          Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
 	       mpps_tx, mbps_tx * 8);
 
+	nic_xstats_display_periodic(port_id);
+
 	printf("  %s############################%s\n",
 	       nic_stats_border, nic_stats_border);
 }
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 5e69d2aa8c..d4c032cb56 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -61,6 +61,9 @@ usage(char* progname)
 	       "(only if interactive is disabled).\n");
 	printf("  --stats-period=PERIOD: statistics will be shown "
 	       "every PERIOD seconds (only if interactive is disabled).\n");
+	printf("  --display-xstats xstat1[,...]: extended statistics to show. "
+	       "Used with --stats-period specified or interactive commands "
+	       "that show Rx/Tx statistics (i.e. 'show port stats').\n");
 	printf("  --nb-cores=N: set the number of forwarding cores "
 	       "(1 <= N <= %d).\n", nb_lcores);
 	printf("  --nb-ports=N: set the number of forwarding ports "
@@ -532,6 +535,7 @@ launch_args_parse(int argc, char** argv)
 #endif
 		{ "tx-first",			0, 0, 0 },
 		{ "stats-period",		1, 0, 0 },
+		{ "display-xstats",		1, 0, 0 },
 		{ "nb-cores",			1, 0, 0 },
 		{ "nb-ports",			1, 0, 0 },
 		{ "coremask",			1, 0, 0 },
@@ -689,6 +693,20 @@ launch_args_parse(int argc, char** argv)
 				stats_period = n;
 				break;
 			}
+			if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
+				char rc;
+
+				rc = parse_xstats_list(optarg, &xstats_display,
+						       &xstats_display_num);
+				if (rc != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to fill xstats to display: %d\n",
+						 rc);
+
+				if (alloc_display_xstats_info() != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to alloc xstats display memory\n");
+			}
 			if (!strcmp(lgopts[opt_idx].name,
 				    "eth-peers-configfile")) {
 				if (init_peer_eth_addrs(optarg) != 0)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index a48f70962f..aebb1d6135 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -208,6 +208,14 @@ uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
                                       * specified on command-line. */
 uint16_t stats_period; /**< Period to show statistics (disabled by default) */
 
+/** Extended statistics to show. */
+struct rte_eth_xstat_name *xstats_display;
+
+unsigned int xstats_display_num; /**< Size of extended statistics to show */
+
+/** Helper structures for each port to show extended statistics. */
+struct xstat_display_info xstats_per_port[RTE_MAX_ETHPORTS];
+
 /*
  * In container, it cannot terminate the process which running with 'stats-period'
  * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
@@ -542,6 +550,12 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
 /* Holds the registered mbuf dynamic flags names. */
 char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
 
+/** Fill helper structures for specified port to show extended statistics. */
+static void fill_display_xstats_info_for_port(portid_t pi);
+
+/** Fill helper structures for all ports to show extended statistics. */
+static void fill_display_xstats_info(void);
+
 /*
  * Helper function to check if socket is already discovered.
  * If yes, return positive value. If not, return zero.
@@ -2673,6 +2687,8 @@ start_port(portid_t pid)
 		}
 	}
 
+	fill_display_xstats_info_for_port(pid);
+
 	printf("Done\n");
 	return 0;
 }
@@ -3693,6 +3709,110 @@ force_quit(void)
 	prompt_exit();
 }
 
+int
+alloc_display_xstats_info(void)
+{
+	portid_t port;
+	uint64_t *mem;
+	size_t mem_size;
+
+	if (xstats_display_num == 0)
+		return 0;
+
+	memset(xstats_per_port, 0, sizeof(xstats_per_port));
+
+	for (port = 0; port < RTE_MAX_ETHPORTS; port++) {
+		uint64_t **ids = &xstats_per_port[port].ids;
+		uint64_t **ids_supp = &xstats_per_port[port].ids_supp;
+		uint64_t **prev_values = &xstats_per_port[port].prev_values;
+		uint64_t **curr_values = &xstats_per_port[port].curr_values;
+
+		if (port == 0) {
+			mem_size = RTE_MAX_ETHPORTS * xstats_display_num *
+				   (sizeof(**ids) + sizeof(**ids_supp) +
+				    sizeof(**prev_values) +
+				    sizeof(**curr_values));
+
+			mem = malloc(mem_size);
+			if (mem == NULL)
+				return -ENOMEM;
+
+			memset(mem, 0, mem_size);
+		}
+
+		*ids = mem;
+		mem += xstats_display_num * sizeof(**ids);
+
+		*ids_supp = mem;
+		mem += xstats_display_num * sizeof(**ids_supp);
+
+		*prev_values = mem;
+		mem += xstats_display_num * sizeof(**prev_values);
+
+		*curr_values = mem;
+		mem += xstats_display_num * sizeof(**curr_values);
+	}
+
+	return 0;
+}
+
+static void
+fill_display_xstats_info_for_port(portid_t pi)
+{
+	unsigned int stat, stat_supp;
+	uint64_t *ids, *ids_supp;
+	const char *xstat_name;
+	struct rte_port *port;
+	int rc;
+
+	if (xstats_display_num == 0)
+		return;
+
+	if (pi == (portid_t)RTE_PORT_ALL) {
+		fill_display_xstats_info();
+		return;
+	}
+
+	port = &ports[pi];
+	if (port->port_status != RTE_PORT_STARTED)
+		return;
+
+	ids = xstats_per_port[pi].ids;
+	ids_supp = xstats_per_port[pi].ids_supp;
+
+	for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
+		xstat_name = xstats_display[stat].name;
+
+		rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
+						   ids + stat);
+		if (rc != 0) {
+			ids[stat] = XSTAT_ID_INVALID;
+			printf("No xstat '%s' on port %u - skip it\n",
+			       xstat_name, pi);
+			continue;
+		}
+		ids_supp[stat_supp++] = ids[stat];
+	}
+
+	xstats_per_port[pi].ids_supp_sz = stat_supp;
+}
+
+static void
+fill_display_xstats_info(void)
+{
+	portid_t pi;
+
+	if (xstats_display_num == 0)
+		return;
+
+	RTE_ETH_FOREACH_DEV(pi) {
+		if (pi == (portid_t)RTE_PORT_ALL)
+			continue;
+
+		fill_display_xstats_info_for_port(pi);
+	}
+}
+
 static void
 print_stats(void)
 {
@@ -3893,6 +4013,8 @@ main(int argc, char** argv)
 	}
 #endif
 
+	fill_display_xstats_info();
+
 #ifdef RTE_LIB_CMDLINE
 	if (strlen(cmdline_filename) != 0)
 		cmdline_read_from_file(cmdline_filename);
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index d61a055bdd..d66232dfa4 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -434,6 +434,24 @@ extern uint32_t param_total_num_mbufs;
 
 extern uint16_t stats_period;
 
+extern struct rte_eth_xstat_name *xstats_display;
+extern unsigned int xstats_display_num;
+
+#define XSTAT_ID_INVALID UINT64_MAX
+
+/** Information for an extended statistics to show. */
+struct xstat_display_info {
+	/** IDs of xstats in the order of xstats_display */
+	uint64_t *ids;
+	/** Supported xstats IDs in the order of xstats_display */
+	uint64_t *ids_supp;
+	size_t   ids_supp_sz;
+	uint64_t *prev_values;
+	uint64_t *curr_values;
+	uint64_t prev_ns;
+};
+extern struct xstat_display_info xstats_per_port[];
+
 extern uint16_t hairpin_mode;
 
 #ifdef RTE_LIB_LATENCYSTATS
@@ -766,6 +784,8 @@ inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx)
 unsigned int parse_item_list(const char *str, const char *item_name,
 			unsigned int max_items,
 			unsigned int *parsed_items, int check_unique_values);
+int parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
+		      unsigned int *xstats_num);
 void launch_args_parse(int argc, char** argv);
 void cmdline_read_from_file(const char *filename);
 void prompt(void);
@@ -978,6 +998,7 @@ enum print_warning {
 int port_id_is_invalid(portid_t port_id, enum print_warning warning);
 void print_valid_ports(void);
 int new_socket_id(unsigned int socket_id);
+int alloc_display_xstats_info(void);
 
 queueid_t get_allowed_max_nb_rxq(portid_t *pid);
 int check_nb_rxq(queueid_t rxq);
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index eb48318353..3e5ba81f18 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -56,6 +56,11 @@ The command line options are:
     Display statistics every PERIOD seconds, if interactive mode is disabled.
     The default value is 0, which means that the statistics will not be displayed.
 
+*   ``--display-xstats xstat1[,...]``
+
+    Display extended statistics every PERIOD seconds as specified in ``--stats-period``
+    or when used with interactive commands that show Rx/Tx statistics (i.e. 'show port stats').
+
 *   ``--nb-cores=N``
 
     Set the number of forwarding cores,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
@ 2021-07-22 19:43     ` David Marchand
  2021-07-22 20:15     ` David Marchand
  1 sibling, 0 replies; 113+ messages in thread
From: David Marchand @ 2021-07-22 19:43 UTC (permalink / raw)
  To: Andrew Rybchenko; +Cc: dev, Xiaoyun Li, Ivan Ilchenko

On Thu, Jul 22, 2021 at 11:55 AM Andrew Rybchenko
<andrew.rybchenko@oktetlabs.ru> wrote:
>
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>
> Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
> (i.e. 'stats-period' option or 'show port stats' interactive command) to
> display specified list of extended statistics.
>
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>

$ build/app/dpdk-testpmd -c 3 --no-huge -m 20 -a 0:0.0 --vdev
net_null1 --vdev net_null2 -- --no-mlockall --total-num-mbufs=2048
--stats-period 1 --display-xstats a,
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Detected static linkage of DPDK
EAL: Multi-process socket /run/user/114840/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'VA'
max names is 2
^^^^^^^^^^^^^^

Useless printf debug.
I can remove it when applying.


testpmd: create a new mbuf pool <mb_pool_0>: n=2048, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
Configuring Port 0 (socket 0)
Port 0: 26:45:E7:40:23:6E
Configuring Port 1 (socket 0)
Port 1: BA:5B:47:48:E6:AC
Checking link statuses...
No xstat 'a' on port 0 - skip it
No xstat 'a' on port 1 - skip it
Done
No xstat 'a' on port 0 - skip it
No xstat 'a' on port 1 - skip it
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

xstats are resolved twice (at least?) per port.
This is harmless afaics.
Can you double check?


No commandline core given, start packet forwarding
io packet forwarding - ports=2 - cores=1 - streams=2 - NUMA support
enabled, MP allocation mode: native



-- 
David Marchand


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics
  2021-07-22  9:54   ` [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
  2021-07-22 19:43     ` David Marchand
@ 2021-07-22 20:15     ` David Marchand
  2021-07-23 13:08       ` Andrew Rybchenko
  1 sibling, 1 reply; 113+ messages in thread
From: David Marchand @ 2021-07-22 20:15 UTC (permalink / raw)
  To: Andrew Rybchenko; +Cc: dev, Xiaoyun Li, Ivan Ilchenko

On Thu, Jul 22, 2021 at 11:55 AM Andrew Rybchenko
<andrew.rybchenko@oktetlabs.ru> wrote:
>
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index 8468018cf3..baffef1642 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -3609,6 +3609,62 @@ cmdline_parse_inst_t cmd_stop = {
>
>  /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
>
> +int
> +parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
> +                 unsigned int *xstats_num)

I had saved this comment as it seemed harmless, but in_str can be constified.
And well, mingw build seems picky about it:

[5/20] Compiling C object app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj
FAILED: app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj
x86_64-w64-mingw32-gcc -Iapp/dpdk-testpmd.exe.p -Iapp -I../../dpdk/app
-Ilib/ethdev -I../../dpdk/lib/ethdev -I. -I../../dpdk -Iconfig
-I../../dpdk/config -Ilib/eal/include -I../../dpdk/lib/eal/include
-Ilib/eal/windows/include -I../../dpdk/lib/eal/windows/include
-Ilib/eal/x86/include -I../../dpdk/lib/eal/x86/include
-Ilib/eal/common -I../../dpdk/lib/eal/common -Ilib/eal
-I../../dpdk/lib/eal -Ilib/kvargs -I../../dpdk/lib/kvargs -Ilib/net
-I../../dpdk/lib/net -Ilib/mbuf -I../../dpdk/lib/mbuf -Ilib/mempool
-I../../dpdk/lib/mempool -Ilib/ring -I../../dpdk/lib/ring -Ilib/meter
-I../../dpdk/lib/meter -Ilib/metrics -I../../dpdk/lib/metrics
-Ilib/telemetry -I../../dpdk/lib/telemetry -Ilib/gro
-I../../dpdk/lib/gro -Ilib/gso -I../../dpdk/lib/gso -Ilib/cmdline
-I../../dpdk/lib/cmdline -Idrivers/bus/pci
-I../../dpdk/drivers/bus/pci -I../../dpdk/drivers/bus/pci/windows
-Ilib/pci -I../../dpdk/lib/pci -Ilib/bitratestats
-I../../dpdk/lib/bitratestats -Ilib/pdump -I../../dpdk/lib/pdump
-Ilib/latencystats -I../../dpdk/lib/latencystats -Idrivers/net/i40e
-I../../dpdk/drivers/net/i40e -Idrivers/net/i40e/base
-I../../dpdk/drivers/net/i40e/base -Idrivers/bus/vdev
-I../../dpdk/drivers/bus/vdev -Ilib/hash -I../../dpdk/lib/hash
-Ilib/rcu -I../../dpdk/lib/rcu -fdiagnostics-color=always -pipe
-D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Werror -O2 -g -include
rte_config.h -Wextra -Wcast-qual -Wdeprecated -Wformat
-Wformat-nonliteral -Wformat-security -Wmissing-declarations
-Wmissing-prototypes -Wnested-externs -Wold-style-definition
-Wpointer-arith -Wsign-compare -Wstrict-prototypes -Wundef
-Wwrite-strings -Wno-address-of-packed-member -Wno-packed-not-aligned
-Wno-missing-field-initializers -D_GNU_SOURCE -D_WIN32_WINNT=0x0A00
-D__USE_MINGW_ANSI_STDIO -mno-avx512f -march=native
-DALLOW_EXPERIMENTAL_API -Wno-deprecated-declarations -MD -MQ
app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj -MF
app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj.d -o
app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj -c
../../dpdk/app/test-pmd/parameters.c
In file included from ../../dpdk/app/test-pmd/parameters.c:6:
../../dpdk/app/test-pmd/parameters.c: In function 'launch_args_parse':
../../dpdk/lib/eal/windows/include/getopt.h:38:16: error: passing
argument 1 of 'parse_xstats_list' discards 'const' qualifier from
pointer target type [-Werror=discarded-qualifiers]
   38 | #define optarg usual_optarg
      |                ^~~~~~~~~~~~
../../dpdk/app/test-pmd/parameters.c:699:28: note: in expansion of
macro 'optarg'
  699 |     rc = parse_xstats_list(optarg, &xstats_display,
      |                            ^~~~~~
In file included from ../../dpdk/app/test-pmd/parameters.c:46:
../../dpdk/app/test-pmd/testpmd.h:787:29: note: expected 'char *' but
argument is of type 'const char *'
  787 | int parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
      |                       ~~~~~~^~~~~~
cc1: all warnings being treated as errors
[19/20] Compiling C object app/dpdk-testpmd.exe.p/test-pmd_cmdline.c.obj



-- 
David Marchand


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v2 11/11] app/testpmd: add option to display extended statistics
  2021-07-22 20:15     ` David Marchand
@ 2021-07-23 13:08       ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:08 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, Xiaoyun Li, Ivan Ilchenko

Hi David,

On 7/22/21 11:15 PM, David Marchand wrote:
> On Thu, Jul 22, 2021 at 11:55 AM Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru> wrote:
>>
>> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
>> index 8468018cf3..baffef1642 100644
>> --- a/app/test-pmd/cmdline.c
>> +++ b/app/test-pmd/cmdline.c
>> @@ -3609,6 +3609,62 @@ cmdline_parse_inst_t cmd_stop = {
>>
>>   /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
>>
>> +int
>> +parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
>> +                 unsigned int *xstats_num)
> 
> I had saved this comment as it seemed harmless, but in_str can be constified.
> And well, mingw build seems picky about it:
> 
> [5/20] Compiling C object app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj
> FAILED: app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj
> x86_64-w64-mingw32-gcc -Iapp/dpdk-testpmd.exe.p -Iapp -I../../dpdk/app
> -Ilib/ethdev -I../../dpdk/lib/ethdev -I. -I../../dpdk -Iconfig
> -I../../dpdk/config -Ilib/eal/include -I../../dpdk/lib/eal/include
> -Ilib/eal/windows/include -I../../dpdk/lib/eal/windows/include
> -Ilib/eal/x86/include -I../../dpdk/lib/eal/x86/include
> -Ilib/eal/common -I../../dpdk/lib/eal/common -Ilib/eal
> -I../../dpdk/lib/eal -Ilib/kvargs -I../../dpdk/lib/kvargs -Ilib/net
> -I../../dpdk/lib/net -Ilib/mbuf -I../../dpdk/lib/mbuf -Ilib/mempool
> -I../../dpdk/lib/mempool -Ilib/ring -I../../dpdk/lib/ring -Ilib/meter
> -I../../dpdk/lib/meter -Ilib/metrics -I../../dpdk/lib/metrics
> -Ilib/telemetry -I../../dpdk/lib/telemetry -Ilib/gro
> -I../../dpdk/lib/gro -Ilib/gso -I../../dpdk/lib/gso -Ilib/cmdline
> -I../../dpdk/lib/cmdline -Idrivers/bus/pci
> -I../../dpdk/drivers/bus/pci -I../../dpdk/drivers/bus/pci/windows
> -Ilib/pci -I../../dpdk/lib/pci -Ilib/bitratestats
> -I../../dpdk/lib/bitratestats -Ilib/pdump -I../../dpdk/lib/pdump
> -Ilib/latencystats -I../../dpdk/lib/latencystats -Idrivers/net/i40e
> -I../../dpdk/drivers/net/i40e -Idrivers/net/i40e/base
> -I../../dpdk/drivers/net/i40e/base -Idrivers/bus/vdev
> -I../../dpdk/drivers/bus/vdev -Ilib/hash -I../../dpdk/lib/hash
> -Ilib/rcu -I../../dpdk/lib/rcu -fdiagnostics-color=always -pipe
> -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Werror -O2 -g -include
> rte_config.h -Wextra -Wcast-qual -Wdeprecated -Wformat
> -Wformat-nonliteral -Wformat-security -Wmissing-declarations
> -Wmissing-prototypes -Wnested-externs -Wold-style-definition
> -Wpointer-arith -Wsign-compare -Wstrict-prototypes -Wundef
> -Wwrite-strings -Wno-address-of-packed-member -Wno-packed-not-aligned
> -Wno-missing-field-initializers -D_GNU_SOURCE -D_WIN32_WINNT=0x0A00
> -D__USE_MINGW_ANSI_STDIO -mno-avx512f -march=native
> -DALLOW_EXPERIMENTAL_API -Wno-deprecated-declarations -MD -MQ
> app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj -MF
> app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj.d -o
> app/dpdk-testpmd.exe.p/test-pmd_parameters.c.obj -c
> ../../dpdk/app/test-pmd/parameters.c
> In file included from ../../dpdk/app/test-pmd/parameters.c:6:
> ../../dpdk/app/test-pmd/parameters.c: In function 'launch_args_parse':
> ../../dpdk/lib/eal/windows/include/getopt.h:38:16: error: passing
> argument 1 of 'parse_xstats_list' discards 'const' qualifier from
> pointer target type [-Werror=discarded-qualifiers]
>     38 | #define optarg usual_optarg
>        |                ^~~~~~~~~~~~
> ../../dpdk/app/test-pmd/parameters.c:699:28: note: in expansion of
> macro 'optarg'
>    699 |     rc = parse_xstats_list(optarg, &xstats_display,
>        |                            ^~~~~~
> In file included from ../../dpdk/app/test-pmd/parameters.c:46:
> ../../dpdk/app/test-pmd/testpmd.h:787:29: note: expected 'char *' but
> argument is of type 'const char *'
>    787 | int parse_xstats_list(char *in_str, struct rte_eth_xstat_name **xstats,
>        |                       ~~~~~~^~~~~~
> cc1: all warnings being treated as errors
> [19/20] Compiling C object app/dpdk-testpmd.exe.p/test-pmd_cmdline.c.obj


Many thanks, I'll send v3 shortly with fixes applied to avoid
dup resolution, remove debug printout and make mingw build happy.

Andrew.


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (11 preceding siblings ...)
  2021-07-22  9:54 ` [dpdk-dev] [PATCH v2 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
@ 2021-07-23 13:15 ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
                     ` (11 more replies)
  2021-07-24 12:33 ` [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
                   ` (5 subsequent siblings)
  18 siblings, 12 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev; +Cc: David Marchand

Rx/Tx doorbells stats are essential for performance investigation.

On the way fix ethdev documenation to refine requirements on
driver callback. It allows to make these callbacks a bit simpler.

Add testpmd option to show specified xstats periodically or upon
request, for example:

 * --display-xstats rx_good_packets,tx_good_packets --stats-period 1

 Port statistics ====================================
  ######################## NIC statistics for port 0  ########################
  RX-packets: 14102808   RX-missed: 0          RX-bytes:  7164239264
  RX-errors: 0
  RX-nombuf:  0
  TX-packets: 14102789   TX-errors: 0          TX-bytes:  7164226028

  Throughput (since last show)
  Rx-pps:      2349577          Rx-bps:   9548682392
  Tx-pps:      2349576          Tx-bps:   9548682408

                      Value                Rate (since last show)
  rx_good_packets     14103280             2349575
  tx_good_packets     14103626             2349573
  ############################################################################

 * -i --display-xstats tx_good_packets,vadapter_rx_overflow

testpmd> port start 0
...
No xstat 'vadapter_rx_overflow' on port 0 - skip it
...
testpmd> start tx_first
testpmd> show port stats all
                               Value            Rate (since last show)
  tx_good_packets             132545336         1420439

v3:
 - testpmd: avoid duplicatin xstats resolution
 - testpmd: remove debug printout
 - testpmd: add missing const qualifier

v2:
 - address Ferruh review notes on ethdev patches


Ivan Ilchenko (11):
  net/sfc: fix get xstats by ID callback to use MAC stats lock
  net/sfc: fix reading adapter state without locking
  ethdev: fix docs of functions getting xstats by IDs
  ethdev: fix docs of drivers callbacks getting xstats by IDs
  net/sfc: fix xstats by ID callbacks according to ethdev
  net/sfc: fix accessing xstats by an unsorted list of IDs
  net/sfc: fix MAC stats update to work for stopped device
  net/sfc: simplify getting of available xstats case
  net/sfc: prepare to add more xstats
  net/sfc: add xstats for Rx/Tx doorbells
  app/testpmd: add option to display extended statistics

 app/test-pmd/cmdline.c                |  55 +++
 app/test-pmd/config.c                 |  66 +++
 app/test-pmd/parameters.c             |  18 +
 app/test-pmd/testpmd.c                | 120 ++++++
 app/test-pmd/testpmd.h                |  21 +
 doc/guides/testpmd_app_ug/run_app.rst |   5 +
 drivers/net/sfc/meson.build           |   1 +
 drivers/net/sfc/sfc.c                 |  16 +
 drivers/net/sfc/sfc.h                 |  18 +-
 drivers/net/sfc/sfc_dp.h              |  10 +
 drivers/net/sfc/sfc_ef10.h            |   3 +-
 drivers/net/sfc/sfc_ef100_rx.c        |   1 +
 drivers/net/sfc/sfc_ef100_tx.c        |   1 +
 drivers/net/sfc/sfc_ef10_essb_rx.c    |   3 +-
 drivers/net/sfc/sfc_ef10_rx.c         |   3 +-
 drivers/net/sfc/sfc_ef10_tx.c         |   1 +
 drivers/net/sfc/sfc_ethdev.c          | 185 +++++----
 drivers/net/sfc/sfc_port.c            | 127 +++++-
 drivers/net/sfc/sfc_rx.c              |   1 +
 drivers/net/sfc/sfc_sw_stats.c        | 572 ++++++++++++++++++++++++++
 drivers/net/sfc/sfc_sw_stats.h        |  49 +++
 drivers/net/sfc/sfc_tx.c              |   4 +-
 lib/ethdev/ethdev_driver.h            |  43 +-
 lib/ethdev/rte_ethdev.h               |  23 +-
 24 files changed, 1240 insertions(+), 106 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_sw_stats.c
 create mode 100644 drivers/net/sfc/sfc_sw_stats.h

-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 02/11] net/sfc: fix reading adapter state without locking Andrew Rybchenko
                     ` (10 subsequent siblings)
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Ivan Malov, Remy Horton
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add MAC stats lock in get xstats by id callback before reading
number of supported MAC stats.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 88896db1f8..d4ac61ff76 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -789,12 +789,14 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	if (unlikely(values == NULL) ||
-	    unlikely((ids == NULL) && (n < port->mac_stats_nb_supported)))
-		return port->mac_stats_nb_supported;
-
 	rte_spinlock_lock(&port->mac_stats_lock);
 
+	if (unlikely(values == NULL) ||
+	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
+		ret = port->mac_stats_nb_supported;
+		goto unlock;
+	}
+
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 02/11] net/sfc: fix reading adapter state without locking
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Robert Stonehouse, Andrew Lee
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update MAC stats function reads adapter state with MAC stats locking
but without adapter locking. Add adapter locking before calling this
function and remove MAC stats locking since there's no point to have
it together with adapter locking. The second place MAC stats locking
is used is MAC stats reset function. It's called with adapter being
already locked so there's no point to use MAC stats locking anymore.

Fixes: 1caab2f1e68 ("net/sfc: add basic statistics")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  1 -
 drivers/net/sfc/sfc_ethdev.c | 28 ++++++++++++++++++++--------
 drivers/net/sfc/sfc_port.c   |  9 +++------
 3 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 546739bd4a..c7b0e5a30d 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -130,7 +130,6 @@ struct sfc_port {
 	unsigned int			nb_mcast_addrs;
 	uint8_t				*mcast_addrs;
 
-	rte_spinlock_t			mac_stats_lock;
 	uint64_t			*mac_stats_buf;
 	unsigned int			mac_stats_nb_supported;
 	efsys_mem_t			mac_stats_dma_mem;
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index d4ac61ff76..d5417e5e65 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -613,7 +613,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	uint64_t *mac_stats;
 	int ret;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	ret = sfc_port_update_mac_stats(sa);
 	if (ret != 0)
@@ -686,7 +686,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	}
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 	SFC_ASSERT(ret >= 0);
 	return -ret;
 }
@@ -698,12 +698,15 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	struct sfc_port *port = &sa->port;
 	int rc;
 
+	sfc_adapter_lock(sa);
+
 	if (sa->state != SFC_ADAPTER_STARTED) {
 		/*
 		 * The operation cannot be done if port is not started; it
 		 * will be scheduled to be done during the next port start
 		 */
 		port->mac_stats_reset_pending = B_TRUE;
+		sfc_adapter_unlock(sa);
 		return 0;
 	}
 
@@ -711,6 +714,8 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	if (rc != 0)
 		sfc_err(sa, "failed to reset statistics (rc = %d)", rc);
 
+	sfc_adapter_unlock(sa);
+
 	SFC_ASSERT(rc >= 0);
 	return -rc;
 }
@@ -726,7 +731,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	unsigned int i;
 	int nstats = 0;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
@@ -748,7 +753,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	}
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 
 	return nstats;
 }
@@ -789,7 +794,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	sfc_adapter_lock(sa);
 
 	if (unlikely(values == NULL) ||
 	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
@@ -819,7 +824,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	ret = nb_written;
 
 unlock:
-	rte_spinlock_unlock(&port->mac_stats_lock);
+	sfc_adapter_unlock(sa);
 
 	return ret;
 }
@@ -835,9 +840,14 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int nb_written = 0;
 	unsigned int i;
 
+	sfc_adapter_lock(sa);
+
 	if (unlikely(xstats_names == NULL) ||
-	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported)))
-		return port->mac_stats_nb_supported;
+	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported))) {
+		nb_supported = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nb_supported;
+	}
 
 	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < size); ++i) {
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
@@ -853,6 +863,8 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		++nb_supported;
 	}
 
+	sfc_adapter_unlock(sa);
+
 	return nb_written;
 }
 
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index ac117f9c48..cdc0f94f19 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -43,7 +43,7 @@ sfc_port_update_mac_stats(struct sfc_adapter *sa)
 	unsigned int nb_attempts = 0;
 	int rc;
 
-	SFC_ASSERT(rte_spinlock_is_locked(&port->mac_stats_lock));
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
 	if (sa->state != SFC_ADAPTER_STARTED)
 		return EINVAL;
@@ -103,14 +103,13 @@ sfc_port_reset_sw_stats(struct sfc_adapter *sa)
 int
 sfc_port_reset_mac_stats(struct sfc_adapter *sa)
 {
-	struct sfc_port *port = &sa->port;
 	int rc;
 
-	rte_spinlock_lock(&port->mac_stats_lock);
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
 	rc = efx_mac_stats_clear(sa->nic);
 	if (rc == 0)
 		sfc_port_reset_sw_stats(sa);
-	rte_spinlock_unlock(&port->mac_stats_lock);
 
 	return rc;
 }
@@ -416,8 +415,6 @@ sfc_port_attach(struct sfc_adapter *sa)
 		goto fail_mcast_addr_list_buf_alloc;
 	}
 
-	rte_spinlock_init(&port->mac_stats_lock);
-
 	rc = ENOMEM;
 	port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
 						sizeof(uint64_t), 0,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 01/11] net/sfc: fix get xstats by ID callback to use MAC stats lock Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 02/11] net/sfc: fix reading adapter state without locking Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 14:42     ` Ferruh Yigit
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
                     ` (8 subsequent siblings)
  11 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Document valid combinations of input arguments in accordance with
current implementation in ethdev.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index d2b27c351f..28440c46d3 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  *   The port identifier of the Ethernet device.
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. If set to NULL, the function returns the required number
- *   of elements.
+ *   be filled. Must not be NULL if @p ids are specified (not NULL).
  * @param ids
- *   IDs array given by app to retrieve specific statistics
+ *   IDs array given by app to retrieve specific statistics. May be NULL
+ *   to retrieve all available statistics.
  * @param size
- *   The size of the xstats_names array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in @p xstats_names to put names in. If @p ids is
+ *   NULL, number of elements in @p xstats_names to put all available statistics
+ *   names in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int
 rte_eth_xstats_get_names_by_id(uint16_t port_id,
@@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  *   The port identifier of the Ethernet device.
  * @param ids
  *   A pointer to an ids array passed by application. This tells which
- *   statistics values function should retrieve. This parameter
- *   can be set to NULL if size is 0. In this case function will retrieve
+ *   statistics values function should retrieve. May be NULL to retrieve
  *   all available statistics.
  * @param values
  *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL if ids are specified (not NULL).
  * @param size
- *   The size of the ids array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in values to put statistics in. If @p ids is NULL,
+ *   number of elements in values to put all available statistics in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
 			     uint64_t *values, unsigned int size);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (2 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 14:46     ` Ferruh Yigit
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 05/11] net/sfc: fix xstats by ID callbacks according to ethdev Andrew Rybchenko
                     ` (7 subsequent siblings)
  11 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 40e474aa7e..fd5b7ca550 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats of an Ethernet device.
+ * For name count, set @p xstats_names and @p ids to NULL.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Can be NULL together with @p ids to retrieve number of
+ *   available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param size
+ *   Size of ids and xstats_names arrays.
+ *   Element count in @p ids and @p xstats_names
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 05/11] net/sfc: fix xstats by ID callbacks according to ethdev
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (3 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs Andrew Rybchenko
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Ivan Malov, Remy Horton
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Fix xstats by ID callbacks according to ethdev usage.
Handle combinations of input arguments that are required by ethdev
and sanity check and reject other combinations on callback entry.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index d5417e5e65..fca3f524a1 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -794,13 +794,10 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	int ret;
 	int rc;
 
-	sfc_adapter_lock(sa);
+	if (unlikely(ids == NULL || values == NULL))
+		return -EINVAL;
 
-	if (unlikely(values == NULL) ||
-	    unlikely(ids == NULL && n < port->mac_stats_nb_supported)) {
-		ret = port->mac_stats_nb_supported;
-		goto unlock;
-	}
+	sfc_adapter_lock(sa);
 
 	rc = sfc_port_update_mac_stats(sa);
 	if (rc != 0) {
@@ -815,7 +812,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
 			continue;
 
-		if ((ids == NULL) || (ids[nb_written] == nb_supported))
+		if (ids[nb_written] == nb_supported)
 			values[nb_written++] = mac_stats[i];
 
 		++nb_supported;
@@ -840,10 +837,13 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int nb_written = 0;
 	unsigned int i;
 
+	if (unlikely(xstats_names == NULL && ids != NULL) ||
+	    unlikely(xstats_names != NULL && ids == NULL))
+		return -EINVAL;
+
 	sfc_adapter_lock(sa);
 
-	if (unlikely(xstats_names == NULL) ||
-	    unlikely((ids == NULL) && (size < port->mac_stats_nb_supported))) {
+	if (unlikely(xstats_names == NULL && ids == NULL)) {
 		nb_supported = port->mac_stats_nb_supported;
 		sfc_adapter_unlock(sa);
 		return nb_supported;
@@ -853,7 +853,7 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
 			continue;
 
-		if ((ids == NULL) || (ids[nb_written] == nb_supported)) {
+		if (ids[nb_written] == nb_supported) {
 			char *name = xstats_names[nb_written++].name;
 
 			strlcpy(name, efx_mac_stat_name(sa->nic, i),
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (4 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 05/11] net/sfc: fix xstats by ID callbacks according to ethdev Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 07/11] net/sfc: fix MAC stats update to work for stopped device Andrew Rybchenko
                     ` (5 subsequent siblings)
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Ivan Malov, Remy Horton
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Device may support only some MAC stats. Add mapping from ids to subset
of supported MAC stats for each port.

Fixes: 73280c1e4ff ("net/sfc: support xstats retrieval by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  2 ++
 drivers/net/sfc/sfc_ethdev.c | 44 ++++++++++++++++++------------------
 drivers/net/sfc/sfc_port.c   | 29 ++++++++++++++++++------
 3 files changed, 46 insertions(+), 29 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index c7b0e5a30d..972d32606d 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -141,6 +141,8 @@ struct sfc_port {
 
 	uint32_t		mac_stats_mask[EFX_MAC_STATS_MASK_NPAGES];
 
+	unsigned int			mac_stats_by_id[EFX_MAC_NSTATS];
+
 	uint64_t			ipackets;
 };
 
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index fca3f524a1..ae9304f90f 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -788,8 +788,6 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
 	uint64_t *mac_stats;
-	unsigned int nb_supported = 0;
-	unsigned int nb_written = 0;
 	unsigned int i;
 	int ret;
 	int rc;
@@ -808,17 +806,19 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 	mac_stats = port->mac_stats_buf;
 
-	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < n); ++i) {
-		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			continue;
-
-		if (ids[nb_written] == nb_supported)
-			values[nb_written++] = mac_stats[i];
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
 
-		++nb_supported;
+	for (i = 0; i < n; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
+		} else {
+			ret = i;
+			goto unlock;
+		}
 	}
 
-	ret = nb_written;
+	ret = n;
 
 unlock:
 	sfc_adapter_unlock(sa);
@@ -833,8 +833,7 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
-	unsigned int nb_supported = 0;
-	unsigned int nb_written = 0;
+	unsigned int nb_supported;
 	unsigned int i;
 
 	if (unlikely(xstats_names == NULL && ids != NULL) ||
@@ -849,23 +848,24 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		return nb_supported;
 	}
 
-	for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < size); ++i) {
-		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			continue;
-
-		if (ids[nb_written] == nb_supported) {
-			char *name = xstats_names[nb_written++].name;
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
 
-			strlcpy(name, efx_mac_stat_name(sa->nic, i),
+	for (i = 0; i < size; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			strlcpy(xstats_names[i].name,
+				efx_mac_stat_name(sa->nic,
+						 port->mac_stats_by_id[ids[i]]),
 				sizeof(xstats_names[0].name));
+		} else {
+			sfc_adapter_unlock(sa);
+			return i;
 		}
-
-		++nb_supported;
 	}
 
 	sfc_adapter_unlock(sa);
 
-	return nb_written;
+	return size;
 }
 
 static int
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index cdc0f94f19..bb9e01d96b 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -157,6 +157,27 @@ sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
 
 #endif
 
+static void
+sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
+{
+	unsigned int mac_stats_nb_supported = 0;
+	struct sfc_port *port = &sa->port;
+	unsigned int stat_idx;
+
+	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
+			       sizeof(port->mac_stats_mask));
+
+	for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
+		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
+			continue;
+
+		port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
+		mac_stats_nb_supported++;
+	}
+
+	port->mac_stats_nb_supported = mac_stats_nb_supported;
+}
+
 int
 sfc_port_start(struct sfc_adapter *sa)
 {
@@ -165,7 +186,6 @@ sfc_port_start(struct sfc_adapter *sa)
 	uint32_t phy_adv_cap;
 	const uint32_t phy_pause_caps =
 		((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
-	unsigned int i;
 
 	sfc_log_init(sa, "entry");
 
@@ -259,12 +279,7 @@ sfc_port_start(struct sfc_adapter *sa)
 		port->mac_stats_reset_pending = B_FALSE;
 	}
 
-	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
-			       sizeof(port->mac_stats_mask));
-
-	for (i = 0, port->mac_stats_nb_supported = 0; i < EFX_MAC_NSTATS; ++i)
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
-			port->mac_stats_nb_supported++;
+	sfc_port_fill_mac_stats_info(sa);
 
 	port->mac_stats_update_generation = 0;
 
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 07/11] net/sfc: fix MAC stats update to work for stopped device
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (5 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 06/11] net/sfc: fix accessing xstats by an unsorted list of IDs Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 08/11] net/sfc: simplify getting of available xstats case Andrew Rybchenko
                     ` (4 subsequent siblings)
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Robert Stonehouse, Andrew Lee
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Fixes: 1caab2f1e68 ("net/sfc: add basic statistics")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  2 +-
 drivers/net/sfc/sfc_ethdev.c |  6 +++---
 drivers/net/sfc/sfc_port.c   | 11 +++++++----
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 972d32606d..1594f934ba 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -422,7 +422,7 @@ int sfc_port_start(struct sfc_adapter *sa);
 void sfc_port_stop(struct sfc_adapter *sa);
 void sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 				struct rte_eth_link *link_info);
-int sfc_port_update_mac_stats(struct sfc_adapter *sa);
+int sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t manual_update);
 int sfc_port_reset_mac_stats(struct sfc_adapter *sa);
 int sfc_set_rx_mode(struct sfc_adapter *sa);
 int sfc_set_rx_mode_unchecked(struct sfc_adapter *sa);
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index ae9304f90f..bbc22723f6 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -615,7 +615,7 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 	sfc_adapter_lock(sa);
 
-	ret = sfc_port_update_mac_stats(sa);
+	ret = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (ret != 0)
 		goto unlock;
 
@@ -733,7 +733,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	sfc_adapter_lock(sa);
 
-	rc = sfc_port_update_mac_stats(sa);
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
 		nstats = -rc;
@@ -797,7 +797,7 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 	sfc_adapter_lock(sa);
 
-	rc = sfc_port_update_mac_stats(sa);
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
 		ret = -rc;
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index bb9e01d96b..8c432c15f5 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -26,7 +26,8 @@
 /**
  * Update MAC statistics in the buffer.
  *
- * @param	sa	Adapter
+ * @param	sa		Adapter
+ * @param	force_upload	Flag to upload MAC stats in any case
  *
  * @return Status code
  * @retval	0	Success
@@ -34,7 +35,7 @@
  * @retval	ENOMEM	Memory allocation failure
  */
 int
-sfc_port_update_mac_stats(struct sfc_adapter *sa)
+sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
 {
 	struct sfc_port *port = &sa->port;
 	efsys_mem_t *esmp = &port->mac_stats_dma_mem;
@@ -46,14 +47,14 @@ sfc_port_update_mac_stats(struct sfc_adapter *sa)
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
 	if (sa->state != SFC_ADAPTER_STARTED)
-		return EINVAL;
+		return 0;
 
 	/*
 	 * If periodic statistics DMA'ing is off or if not supported,
 	 * make a manual request and keep an eye on timer if need be
 	 */
 	if (!port->mac_stats_periodic_dma_supported ||
-	    (port->mac_stats_update_period_ms == 0)) {
+	    (port->mac_stats_update_period_ms == 0) || force_upload) {
 		if (port->mac_stats_update_period_ms != 0) {
 			uint64_t timestamp = sfc_get_system_msecs();
 
@@ -367,6 +368,8 @@ sfc_port_stop(struct sfc_adapter *sa)
 	(void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
 				     0, B_FALSE);
 
+	sfc_port_update_mac_stats(sa, B_TRUE);
+
 	efx_port_fini(sa->nic);
 	efx_filter_fini(sa->nic);
 
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 08/11] net/sfc: simplify getting of available xstats case
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (6 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 07/11] net/sfc: fix MAC stats update to work for stopped device Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 09/11] net/sfc: prepare to add more xstats Andrew Rybchenko
                     ` (3 subsequent siblings)
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev; +Cc: David Marchand, Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

There is no point to recalculate number of available xstats on
each request. The number is calculated once on device start
and may be returned on subsequent calls.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_ethdev.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index bbc22723f6..f0567a71d0 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -733,6 +733,11 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	sfc_adapter_lock(sa);
 
+	if (unlikely(xstats == NULL)) {
+		nstats = port->mac_stats_nb_supported;
+		goto unlock;
+	}
+
 	rc = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (rc != 0) {
 		SFC_ASSERT(rc > 0);
@@ -744,7 +749,7 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (xstats != NULL && nstats < (int)xstats_count) {
+			if (nstats < (int)xstats_count) {
 				xstats[nstats].id = nstats;
 				xstats[nstats].value = mac_stats[i];
 			}
@@ -768,9 +773,16 @@ sfc_xstats_get_names(struct rte_eth_dev *dev,
 	unsigned int i;
 	unsigned int nstats = 0;
 
+	if (unlikely(xstats_names == NULL)) {
+		sfc_adapter_lock(sa);
+		nstats = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nstats;
+	}
+
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (xstats_names != NULL && nstats < xstats_count)
+			if (nstats < xstats_count)
 				strlcpy(xstats_names[nstats].name,
 					efx_mac_stat_name(sa->nic, i),
 					sizeof(xstats_names[0].name));
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 09/11] net/sfc: prepare to add more xstats
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (7 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 08/11] net/sfc: simplify getting of available xstats case Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 10/11] net/sfc: add xstats for Rx/Tx doorbells Andrew Rybchenko
                     ` (2 subsequent siblings)
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev; +Cc: David Marchand, Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Move getting MAC stats code that involves locking to separate functions
to simplify addition of new xstats.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc.h        |  4 ++
 drivers/net/sfc/sfc_ethdev.c | 73 ++++----------------------------
 drivers/net/sfc/sfc_port.c   | 80 ++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 65 deletions(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 1594f934ba..58b8c2c2ad 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -423,6 +423,10 @@ void sfc_port_stop(struct sfc_adapter *sa);
 void sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 				struct rte_eth_link *link_info);
 int sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t manual_update);
+int sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
+			   unsigned int xstats_count, unsigned int *nb_written);
+int sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				 uint64_t *values, unsigned int n);
 int sfc_port_reset_mac_stats(struct sfc_adapter *sa);
 int sfc_set_rx_mode(struct sfc_adapter *sa);
 int sfc_set_rx_mode_unchecked(struct sfc_adapter *sa);
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index f0567a71d0..dd7e5c253a 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -726,41 +726,17 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
-	uint64_t *mac_stats;
-	int rc;
-	unsigned int i;
-	int nstats = 0;
-
-	sfc_adapter_lock(sa);
+	unsigned int nb_written = 0;
+	unsigned int nb_supp;
 
 	if (unlikely(xstats == NULL)) {
-		nstats = port->mac_stats_nb_supported;
-		goto unlock;
-	}
-
-	rc = sfc_port_update_mac_stats(sa, B_FALSE);
-	if (rc != 0) {
-		SFC_ASSERT(rc > 0);
-		nstats = -rc;
-		goto unlock;
-	}
-
-	mac_stats = port->mac_stats_buf;
-
-	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < (int)xstats_count) {
-				xstats[nstats].id = nstats;
-				xstats[nstats].value = mac_stats[i];
-			}
-			nstats++;
-		}
+		sfc_adapter_lock(sa);
+		nb_supp = port->mac_stats_nb_supported;
+		sfc_adapter_unlock(sa);
+		return nb_supp;
 	}
 
-unlock:
-	sfc_adapter_unlock(sa);
-
-	return nstats;
+	return sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
 }
 
 static int
@@ -798,44 +774,11 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
-	uint64_t *mac_stats;
-	unsigned int i;
-	int ret;
-	int rc;
 
 	if (unlikely(ids == NULL || values == NULL))
 		return -EINVAL;
 
-	sfc_adapter_lock(sa);
-
-	rc = sfc_port_update_mac_stats(sa, B_FALSE);
-	if (rc != 0) {
-		SFC_ASSERT(rc > 0);
-		ret = -rc;
-		goto unlock;
-	}
-
-	mac_stats = port->mac_stats_buf;
-
-	SFC_ASSERT(port->mac_stats_nb_supported <=
-		   RTE_DIM(port->mac_stats_by_id));
-
-	for (i = 0; i < n; i++) {
-		if (ids[i] < port->mac_stats_nb_supported) {
-			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
-		} else {
-			ret = i;
-			goto unlock;
-		}
-	}
-
-	ret = n;
-
-unlock:
-	sfc_adapter_unlock(sa);
-
-	return ret;
+	return sfc_port_get_mac_stats_by_id(sa, ids, values, n);
 }
 
 static int
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index 8c432c15f5..f6689a17c0 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -636,3 +636,83 @@ sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
 
 	link_info->link_autoneg = ETH_LINK_AUTONEG;
 }
+
+int
+sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
+		       unsigned int xstats_count, unsigned int *nb_written)
+{
+	struct sfc_port *port = &sa->port;
+	uint64_t *mac_stats;
+	unsigned int i;
+	int nstats = 0;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	ret = sfc_port_update_mac_stats(sa, B_FALSE);
+	if (ret != 0) {
+		SFC_ASSERT(ret > 0);
+		ret = -ret;
+		goto unlock;
+	}
+
+	mac_stats = port->mac_stats_buf;
+
+	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
+		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
+			if (nstats < (int)xstats_count) {
+				xstats[nstats].id = nstats;
+				xstats[nstats].value = mac_stats[i];
+				(*nb_written)++;
+			}
+			nstats++;
+		}
+	}
+	ret = nstats;
+
+unlock:
+	sfc_adapter_unlock(sa);
+
+	return ret;
+}
+
+int
+sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+			     uint64_t *values, unsigned int n)
+{
+	struct sfc_port *port = &sa->port;
+	uint64_t *mac_stats;
+	unsigned int i;
+	int ret;
+	int rc;
+
+	sfc_adapter_lock(sa);
+
+	rc = sfc_port_update_mac_stats(sa, B_FALSE);
+	if (rc != 0) {
+		SFC_ASSERT(rc > 0);
+		ret = -rc;
+		goto unlock;
+	}
+
+	mac_stats = port->mac_stats_buf;
+
+	SFC_ASSERT(port->mac_stats_nb_supported <=
+		   RTE_DIM(port->mac_stats_by_id));
+
+	for (i = 0; i < n; i++) {
+		if (ids[i] < port->mac_stats_nb_supported) {
+			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
+		} else {
+			ret = i;
+			goto unlock;
+		}
+	}
+
+	ret = n;
+
+unlock:
+	sfc_adapter_unlock(sa);
+
+	return ret;
+}
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 10/11] net/sfc: add xstats for Rx/Tx doorbells
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (8 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 09/11] net/sfc: prepare to add more xstats Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
  2021-07-23 21:34   ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Thomas Monjalon
  11 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev; +Cc: David Marchand, Ivan Ilchenko, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Rx/Tx doorbells statistics are collected in software and
available per queue. These stats are useful for performance
investigation.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/meson.build        |   1 +
 drivers/net/sfc/sfc.c              |  16 +
 drivers/net/sfc/sfc.h              |   9 +
 drivers/net/sfc/sfc_dp.h           |  10 +
 drivers/net/sfc/sfc_ef10.h         |   3 +-
 drivers/net/sfc/sfc_ef100_rx.c     |   1 +
 drivers/net/sfc/sfc_ef100_tx.c     |   1 +
 drivers/net/sfc/sfc_ef10_essb_rx.c |   3 +-
 drivers/net/sfc/sfc_ef10_rx.c      |   3 +-
 drivers/net/sfc/sfc_ef10_tx.c      |   1 +
 drivers/net/sfc/sfc_ethdev.c       | 124 +++++--
 drivers/net/sfc/sfc_port.c         |  10 +-
 drivers/net/sfc/sfc_rx.c           |   1 +
 drivers/net/sfc/sfc_sw_stats.c     | 572 +++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_sw_stats.h     |  49 +++
 drivers/net/sfc/sfc_tx.c           |   4 +-
 16 files changed, 772 insertions(+), 36 deletions(-)
 create mode 100644 drivers/net/sfc/sfc_sw_stats.c
 create mode 100644 drivers/net/sfc/sfc_sw_stats.h

diff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build
index 4625859077..a912cdccfa 100644
--- a/drivers/net/sfc/meson.build
+++ b/drivers/net/sfc/meson.build
@@ -70,6 +70,7 @@ sources = files(
         'sfc.c',
         'sfc_mcdi.c',
         'sfc_sriov.c',
+        'sfc_sw_stats.c',
         'sfc_intr.c',
         'sfc_ev.c',
         'sfc_port.c',
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 4097cf39de..274a98e228 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -24,6 +24,7 @@
 #include "sfc_tx.h"
 #include "sfc_kvargs.h"
 #include "sfc_tweak.h"
+#include "sfc_sw_stats.h"
 
 
 int
@@ -636,10 +637,17 @@ sfc_configure(struct sfc_adapter *sa)
 	if (rc != 0)
 		goto fail_tx_configure;
 
+	rc = sfc_sw_xstats_configure(sa);
+	if (rc != 0)
+		goto fail_sw_xstats_configure;
+
 	sa->state = SFC_ADAPTER_CONFIGURED;
 	sfc_log_init(sa, "done");
 	return 0;
 
+fail_sw_xstats_configure:
+	sfc_tx_close(sa);
+
 fail_tx_configure:
 	sfc_rx_close(sa);
 
@@ -666,6 +674,7 @@ sfc_close(struct sfc_adapter *sa)
 	SFC_ASSERT(sa->state == SFC_ADAPTER_CONFIGURED);
 	sa->state = SFC_ADAPTER_CLOSING;
 
+	sfc_sw_xstats_close(sa);
 	sfc_tx_close(sa);
 	sfc_rx_close(sa);
 	sfc_port_close(sa);
@@ -891,6 +900,10 @@ sfc_attach(struct sfc_adapter *sa)
 
 	sfc_flow_init(sa);
 
+	rc = sfc_sw_xstats_init(sa);
+	if (rc != 0)
+		goto fail_sw_xstats_init;
+
 	/*
 	 * Create vSwitch to be able to use VFs when PF is not started yet
 	 * as DPDK port. VFs should be able to talk to each other even
@@ -906,6 +919,9 @@ sfc_attach(struct sfc_adapter *sa)
 	return 0;
 
 fail_sriov_vswitch_create:
+	sfc_sw_xstats_close(sa);
+
+fail_sw_xstats_init:
 	sfc_flow_fini(sa);
 	sfc_mae_detach(sa);
 
diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 58b8c2c2ad..331e06bac6 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -217,6 +217,14 @@ struct sfc_counter_rxq {
 	struct rte_mempool		*mp;
 };
 
+struct sfc_sw_xstats {
+	uint64_t			*reset_vals;
+
+	rte_spinlock_t			queues_bitmap_lock;
+	void				*queues_bitmap_mem;
+	struct rte_bitmap		*queues_bitmap;
+};
+
 /* Adapter private data */
 struct sfc_adapter {
 	/*
@@ -249,6 +257,7 @@ struct sfc_adapter {
 	struct sfc_sriov		sriov;
 	struct sfc_intr			intr;
 	struct sfc_port			port;
+	struct sfc_sw_xstats		sw_xstats;
 	struct sfc_filter		filter;
 	struct sfc_mae			mae;
 
diff --git a/drivers/net/sfc/sfc_dp.h b/drivers/net/sfc/sfc_dp.h
index 61c1a3fbac..7fd8f34b0f 100644
--- a/drivers/net/sfc/sfc_dp.h
+++ b/drivers/net/sfc/sfc_dp.h
@@ -42,6 +42,16 @@ enum sfc_dp_type {
 
 /** Datapath queue run-time information */
 struct sfc_dp_queue {
+	/*
+	 * Typically the structure is located at the end of Rx/Tx queue
+	 * data structure and not used on datapath. So, it is not a
+	 * problem to have extra fields even if not used. However,
+	 * put stats at top of the structure to be closer to fields
+	 * used on datapath or reap to have more chances to be cache-hot.
+	 */
+	uint32_t			rx_dbells;
+	uint32_t			tx_dbells;
+
 	uint16_t			port_id;
 	uint16_t			queue_id;
 	struct rte_pci_addr		pci_addr;
diff --git a/drivers/net/sfc/sfc_ef10.h b/drivers/net/sfc/sfc_ef10.h
index ad4c1fdbef..e9bb72e28b 100644
--- a/drivers/net/sfc/sfc_ef10.h
+++ b/drivers/net/sfc/sfc_ef10.h
@@ -99,7 +99,7 @@ sfc_ef10_ev_present(const efx_qword_t ev)
 
 static inline void
 sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,
-		  unsigned int ptr_mask)
+		  unsigned int ptr_mask, uint32_t *dbell_counter)
 {
 	efx_dword_t dword;
 
@@ -118,6 +118,7 @@ sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], doorbell);
+	(*dbell_counter)++;
 }
 
 static inline void
diff --git a/drivers/net/sfc/sfc_ef100_rx.c b/drivers/net/sfc/sfc_ef100_rx.c
index 10c74aa118..d4cb96881c 100644
--- a/drivers/net/sfc/sfc_ef100_rx.c
+++ b/drivers/net/sfc/sfc_ef100_rx.c
@@ -119,6 +119,7 @@ sfc_ef100_rx_qpush(struct sfc_ef100_rxq *rxq, unsigned int added)
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], rxq->doorbell);
+	rxq->dp.dpq.rx_dbells++;
 
 	sfc_ef100_rx_debug(rxq, "RxQ pushed doorbell at pidx %u (added=%u)",
 			   EFX_DWORD_FIELD(dword, ERF_GZ_RX_RING_PIDX),
diff --git a/drivers/net/sfc/sfc_ef100_tx.c b/drivers/net/sfc/sfc_ef100_tx.c
index f9ad6f7b73..522e9a0d34 100644
--- a/drivers/net/sfc/sfc_ef100_tx.c
+++ b/drivers/net/sfc/sfc_ef100_tx.c
@@ -489,6 +489,7 @@ sfc_ef100_tx_qpush(struct sfc_ef100_txq *txq, unsigned int added)
 	 * operations that follow it (i.e. doorbell write).
 	 */
 	rte_write32(dword.ed_u32[0], txq->doorbell);
+	txq->dp.dpq.tx_dbells++;
 
 	sfc_ef100_tx_debug(txq, "TxQ pushed doorbell at pidx %u (added=%u)",
 			   EFX_DWORD_FIELD(dword, ERF_GZ_TX_RING_PIDX),
diff --git a/drivers/net/sfc/sfc_ef10_essb_rx.c b/drivers/net/sfc/sfc_ef10_essb_rx.c
index 3c246eb149..991329e86f 100644
--- a/drivers/net/sfc/sfc_ef10_essb_rx.c
+++ b/drivers/net/sfc/sfc_ef10_essb_rx.c
@@ -220,7 +220,8 @@ sfc_ef10_essb_rx_qrefill(struct sfc_ef10_essb_rxq *rxq)
 
 	SFC_ASSERT(rxq->added != added);
 	rxq->added = added;
-	sfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask);
+	sfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask,
+			  &rxq->dp.dpq.rx_dbells);
 }
 
 static bool
diff --git a/drivers/net/sfc/sfc_ef10_rx.c b/drivers/net/sfc/sfc_ef10_rx.c
index 2b4393d232..49a7d4fb42 100644
--- a/drivers/net/sfc/sfc_ef10_rx.c
+++ b/drivers/net/sfc/sfc_ef10_rx.c
@@ -171,7 +171,8 @@ sfc_ef10_rx_qrefill(struct sfc_ef10_rxq *rxq)
 
 	SFC_ASSERT(rxq->added != added);
 	rxq->added = added;
-	sfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask);
+	sfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask,
+			  &rxq->dp.dpq.rx_dbells);
 }
 
 static void
diff --git a/drivers/net/sfc/sfc_ef10_tx.c b/drivers/net/sfc/sfc_ef10_tx.c
index a8d34ead33..ed43adb4ca 100644
--- a/drivers/net/sfc/sfc_ef10_tx.c
+++ b/drivers/net/sfc/sfc_ef10_tx.c
@@ -248,6 +248,7 @@ sfc_ef10_tx_qpush(struct sfc_ef10_txq *txq, unsigned int added,
 	rte_io_wmb();
 
 	*(volatile efsys_uint128_t *)txq->doorbell = oword.eo_u128[0];
+	txq->dp.dpq.tx_dbells++;
 }
 
 static unsigned int
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index dd7e5c253a..2db0d000c3 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -28,6 +28,10 @@
 #include "sfc_flow.h"
 #include "sfc_dp.h"
 #include "sfc_dp_rx.h"
+#include "sfc_sw_stats.h"
+
+#define SFC_XSTAT_ID_INVALID_VAL  UINT64_MAX
+#define SFC_XSTAT_ID_INVALID_NAME '\0'
 
 uint32_t sfc_logtype_driver;
 
@@ -714,29 +718,49 @@ sfc_stats_reset(struct rte_eth_dev *dev)
 	if (rc != 0)
 		sfc_err(sa, "failed to reset statistics (rc = %d)", rc);
 
+	sfc_sw_xstats_reset(sa);
+
 	sfc_adapter_unlock(sa);
 
 	SFC_ASSERT(rc >= 0);
 	return -rc;
 }
 
+static unsigned int
+sfc_xstats_get_nb_supported(struct sfc_adapter *sa)
+{
+	struct sfc_port *port = &sa->port;
+	unsigned int nb_supported;
+
+	sfc_adapter_lock(sa);
+	nb_supported = port->mac_stats_nb_supported +
+		       sfc_sw_xstats_get_nb_supported(sa);
+	sfc_adapter_unlock(sa);
+
+	return nb_supported;
+}
+
 static int
 sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	       unsigned int xstats_count)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
 	unsigned int nb_written = 0;
-	unsigned int nb_supp;
+	unsigned int nb_supported = 0;
+	int rc;
 
-	if (unlikely(xstats == NULL)) {
-		sfc_adapter_lock(sa);
-		nb_supp = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nb_supp;
-	}
+	if (unlikely(xstats == NULL))
+		return sfc_xstats_get_nb_supported(sa);
+
+	rc = sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
+	if (rc < 0)
+		return rc;
 
-	return sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);
+	nb_supported = rc;
+	sfc_sw_xstats_get_vals(sa, xstats, xstats_count, &nb_written,
+			       &nb_supported);
+
+	return nb_supported;
 }
 
 static int
@@ -748,24 +772,31 @@ sfc_xstats_get_names(struct rte_eth_dev *dev,
 	struct sfc_port *port = &sa->port;
 	unsigned int i;
 	unsigned int nstats = 0;
+	unsigned int nb_written = 0;
+	int ret;
 
-	if (unlikely(xstats_names == NULL)) {
-		sfc_adapter_lock(sa);
-		nstats = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nstats;
-	}
+	if (unlikely(xstats_names == NULL))
+		return sfc_xstats_get_nb_supported(sa);
 
 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < xstats_count)
+			if (nstats < xstats_count) {
 				strlcpy(xstats_names[nstats].name,
 					efx_mac_stat_name(sa->nic, i),
 					sizeof(xstats_names[0].name));
+				nb_written++;
+			}
 			nstats++;
 		}
 	}
 
+	ret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,
+				      &nb_written, &nstats);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
 	return nstats;
 }
 
@@ -774,11 +805,35 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+	struct sfc_port *port = &sa->port;
+	unsigned int nb_supported;
+	unsigned int i;
+	int rc;
 
 	if (unlikely(ids == NULL || values == NULL))
 		return -EINVAL;
 
-	return sfc_port_get_mac_stats_by_id(sa, ids, values, n);
+	/*
+	 * Values array could be filled in nonsequential order. Fill values with
+	 * constant indicating invalid ID first.
+	 */
+	for (i = 0; i < n; i++)
+		values[i] = SFC_XSTAT_ID_INVALID_VAL;
+
+	rc = sfc_port_get_mac_stats_by_id(sa, ids, values, n);
+	if (rc != 0)
+		return rc;
+
+	nb_supported = port->mac_stats_nb_supported;
+	sfc_sw_xstats_get_vals_by_id(sa, ids, values, n, &nb_supported);
+
+	/* Return number of written stats before invalid ID is encountered. */
+	for (i = 0; i < n; i++) {
+		if (values[i] == SFC_XSTAT_ID_INVALID_VAL)
+			return i;
+	}
+
+	return n;
 }
 
 static int
@@ -790,18 +845,23 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	struct sfc_port *port = &sa->port;
 	unsigned int nb_supported;
 	unsigned int i;
+	int ret;
 
 	if (unlikely(xstats_names == NULL && ids != NULL) ||
 	    unlikely(xstats_names != NULL && ids == NULL))
 		return -EINVAL;
 
-	sfc_adapter_lock(sa);
+	if (unlikely(xstats_names == NULL && ids == NULL))
+		return sfc_xstats_get_nb_supported(sa);
 
-	if (unlikely(xstats_names == NULL && ids == NULL)) {
-		nb_supported = port->mac_stats_nb_supported;
-		sfc_adapter_unlock(sa);
-		return nb_supported;
-	}
+	/*
+	 * Names array could be filled in nonsequential order. Fill names with
+	 * string indicating invalid ID first.
+	 */
+	for (i = 0; i < size; i++)
+		xstats_names[i].name[0] = SFC_XSTAT_ID_INVALID_NAME;
+
+	sfc_adapter_lock(sa);
 
 	SFC_ASSERT(port->mac_stats_nb_supported <=
 		   RTE_DIM(port->mac_stats_by_id));
@@ -812,14 +872,26 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 				efx_mac_stat_name(sa->nic,
 						 port->mac_stats_by_id[ids[i]]),
 				sizeof(xstats_names[0].name));
-		} else {
-			sfc_adapter_unlock(sa);
-			return i;
 		}
 	}
 
+	nb_supported = port->mac_stats_nb_supported;
+
 	sfc_adapter_unlock(sa);
 
+	ret = sfc_sw_xstats_get_names_by_id(sa, ids, xstats_names, size,
+					    &nb_supported);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
+	/* Return number of written names before invalid ID is encountered. */
+	for (i = 0; i < size; i++) {
+		if (xstats_names[i].name[0] == SFC_XSTAT_ID_INVALID_NAME)
+			return i;
+	}
+
 	return size;
 }
 
diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c
index f6689a17c0..adb2b2cb81 100644
--- a/drivers/net/sfc/sfc_port.c
+++ b/drivers/net/sfc/sfc_port.c
@@ -7,6 +7,8 @@
  * for Solarflare) and Solarflare Communications, Inc.
  */
 
+#include <rte_bitmap.h>
+
 #include "efx.h"
 
 #include "sfc.h"
@@ -701,15 +703,11 @@ sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
 		   RTE_DIM(port->mac_stats_by_id));
 
 	for (i = 0; i < n; i++) {
-		if (ids[i] < port->mac_stats_nb_supported) {
+		if (ids[i] < port->mac_stats_nb_supported)
 			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
-		} else {
-			ret = i;
-			goto unlock;
-		}
 	}
 
-	ret = n;
+	ret = 0;
 
 unlock:
 	sfc_adapter_unlock(sa);
diff --git a/drivers/net/sfc/sfc_rx.c b/drivers/net/sfc/sfc_rx.c
index f6a8ac68e8..280e8a61f9 100644
--- a/drivers/net/sfc/sfc_rx.c
+++ b/drivers/net/sfc/sfc_rx.c
@@ -138,6 +138,7 @@ sfc_efx_rx_qrefill(struct sfc_efx_rxq *rxq)
 	SFC_ASSERT(added != rxq->added);
 	rxq->added = added;
 	efx_rx_qpush(rxq->common, added, &rxq->pushed);
+	rxq->dp.dpq.rx_dbells++;
 }
 
 static uint64_t
diff --git a/drivers/net/sfc/sfc_sw_stats.c b/drivers/net/sfc/sfc_sw_stats.c
new file mode 100644
index 0000000000..8489b603f5
--- /dev/null
+++ b/drivers/net/sfc/sfc_sw_stats.c
@@ -0,0 +1,572 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2021 Xilinx, Inc.
+ */
+#include <rte_dev.h>
+#include <rte_bitmap.h>
+
+#include "sfc.h"
+#include "sfc_rx.h"
+#include "sfc_tx.h"
+#include "sfc_sw_stats.h"
+
+enum sfc_sw_stats_type {
+	SFC_SW_STATS_RX,
+	SFC_SW_STATS_TX,
+};
+
+typedef uint64_t sfc_get_sw_xstat_val_t(struct sfc_adapter *sa, uint16_t qid);
+
+struct sfc_sw_xstat_descr {
+	const char *name;
+	enum sfc_sw_stats_type type;
+	sfc_get_sw_xstat_val_t *get_val;
+};
+
+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_rx_dbells;
+static uint64_t
+sfc_get_sw_xstat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	struct sfc_rxq_info *rxq_info;
+
+	rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);
+	if (rxq_info->state & SFC_RXQ_INITIALIZED)
+		return rxq_info->dp->dpq.rx_dbells;
+	return 0;
+}
+
+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_tx_dbells;
+static uint64_t
+sfc_get_sw_xstat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	struct sfc_txq_info *txq_info;
+
+	txq_info = sfc_txq_info_by_ethdev_qid(sas, qid);
+	if (txq_info->state & SFC_TXQ_INITIALIZED)
+		return txq_info->dp->dpq.tx_dbells;
+	return 0;
+}
+
+struct sfc_sw_xstat_descr sfc_sw_xstats[] = {
+	{
+		.name = "dbells",
+		.type = SFC_SW_STATS_RX,
+		.get_val  = sfc_get_sw_xstat_val_rx_dbells,
+	},
+	{
+		.name = "dbells",
+		.type = SFC_SW_STATS_TX,
+		.get_val  = sfc_get_sw_xstat_val_tx_dbells,
+	}
+};
+
+static int
+sfc_sw_stat_get_name(struct sfc_adapter *sa,
+		     const struct sfc_sw_xstat_descr *sw_xstat, char *name,
+		     size_t name_size, unsigned int id_off)
+{
+	const char *prefix;
+	int ret;
+
+	switch (sw_xstat->type) {
+	case SFC_SW_STATS_RX:
+		prefix = "rx";
+		break;
+	case SFC_SW_STATS_TX:
+		prefix = "tx";
+		break;
+	default:
+		sfc_err(sa, "%s: unknown software statistics type %d",
+			__func__, sw_xstat->type);
+		return -EINVAL;
+	}
+
+	if (id_off == 0) {
+		ret = snprintf(name, name_size, "%s_%s", prefix,
+							 sw_xstat->name);
+		if (ret < 0 || ret >= (int)name_size) {
+			sfc_err(sa, "%s: failed to fill xstat name %s_%s, err %d",
+				__func__, prefix, sw_xstat->name, ret);
+			return ret > 0 ? -EINVAL : ret;
+		}
+	} else {
+		uint16_t qid = id_off - 1;
+		ret = snprintf(name, name_size, "%s_q%u_%s", prefix, qid,
+							sw_xstat->name);
+		if (ret < 0 || ret >= (int)name_size) {
+			sfc_err(sa, "%s: failed to fill xstat name %s_q%u_%s, err %d",
+				__func__, prefix, qid, sw_xstat->name, ret);
+			return ret > 0 ? -EINVAL : ret;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned int
+sfc_sw_stat_get_queue_count(struct sfc_adapter *sa,
+			    const struct sfc_sw_xstat_descr *sw_xstat)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+
+	switch (sw_xstat->type) {
+	case SFC_SW_STATS_RX:
+		return sas->ethdev_rxq_count;
+	case SFC_SW_STATS_TX:
+		return sas->ethdev_txq_count;
+	default:
+		sfc_err(sa, "%s: unknown software statistics type %d",
+			__func__, sw_xstat->type);
+		return 0;
+	}
+}
+
+static unsigned int
+sfc_sw_xstat_per_queue_get_count(unsigned int nb_queues)
+{
+	/* Take into account the accumulative xstat of all queues */
+	return nb_queues > 0 ? 1 + nb_queues : 0;
+}
+
+static unsigned int
+sfc_sw_xstat_get_nb_supported(struct sfc_adapter *sa,
+			      const struct sfc_sw_xstat_descr *sw_xstat)
+{
+	unsigned int nb_queues;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	return sfc_sw_xstat_per_queue_get_count(nb_queues);
+}
+
+static int
+sfc_sw_stat_get_names(struct sfc_adapter *sa,
+		      const struct sfc_sw_xstat_descr *sw_xstat,
+		      struct rte_eth_xstat_name *xstats_names,
+		      unsigned int xstats_names_sz,
+		      unsigned int *nb_written,
+		      unsigned int *nb_supported)
+{
+	const size_t name_size = sizeof(xstats_names[0].name);
+	unsigned int id_base = *nb_supported;
+	unsigned int nb_queues;
+	unsigned int qid;
+	int rc;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return 0;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	if (*nb_written < xstats_names_sz) {
+		rc = sfc_sw_stat_get_name(sa, sw_xstat,
+					  xstats_names[*nb_written].name,
+					  name_size, *nb_written - id_base);
+		if (rc != 0)
+			return rc;
+		(*nb_written)++;
+	}
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		if (*nb_written < xstats_names_sz) {
+			rc = sfc_sw_stat_get_name(sa, sw_xstat,
+					      xstats_names[*nb_written].name,
+					      name_size, *nb_written - id_base);
+			if (rc != 0)
+				return rc;
+			(*nb_written)++;
+		}
+	}
+
+	return 0;
+}
+
+static int
+sfc_sw_xstat_get_names_by_id(struct sfc_adapter *sa,
+			     const struct sfc_sw_xstat_descr *sw_xstat,
+			     const uint64_t *ids,
+			     struct rte_eth_xstat_name *xstats_names,
+			     unsigned int size,
+			     unsigned int *nb_supported)
+{
+	const size_t name_size = sizeof(xstats_names[0].name);
+	unsigned int id_base = *nb_supported;
+	unsigned int nb_queues;
+	unsigned int i;
+	int rc;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return 0;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	for (i = 0; i < size; i++) {
+		if (id_base <= ids[i] && ids[i] <= id_base + nb_queues) {
+			rc = sfc_sw_stat_get_name(sa, sw_xstat,
+						  xstats_names[i].name,
+						  name_size, ids[i] - id_base);
+			if (rc != 0)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static void
+sfc_sw_xstat_get_values(struct sfc_adapter *sa,
+			const struct sfc_sw_xstat_descr *sw_xstat,
+			struct rte_eth_xstat *xstats,
+			unsigned int xstats_size,
+			unsigned int *nb_written,
+			unsigned int *nb_supported)
+{
+	unsigned int qid;
+	uint64_t value;
+	struct rte_eth_xstat *accum_xstat;
+	bool count_accum_value = false;
+	unsigned int nb_queues;
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	if (*nb_written < xstats_size) {
+		count_accum_value = true;
+		accum_xstat = &xstats[*nb_written];
+		xstats[*nb_written].id = *nb_written;
+		xstats[*nb_written].value = 0;
+		(*nb_written)++;
+	}
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		value = sw_xstat->get_val(sa, qid);
+
+		if (*nb_written < xstats_size) {
+			xstats[*nb_written].id = *nb_written;
+			xstats[*nb_written].value = value;
+			(*nb_written)++;
+		}
+
+		if (count_accum_value)
+			accum_xstat->value += value;
+	}
+}
+
+static void
+sfc_sw_xstat_get_values_by_id(struct sfc_adapter *sa,
+			      const struct sfc_sw_xstat_descr *sw_xstat,
+			      const uint64_t *ids,
+			      uint64_t *values,
+			      unsigned int ids_size,
+			      unsigned int *nb_supported)
+{
+	rte_spinlock_t *bmp_lock = &sa->sw_xstats.queues_bitmap_lock;
+	struct rte_bitmap *bmp = sa->sw_xstats.queues_bitmap;
+	unsigned int id_base = *nb_supported;
+	bool count_accum_value = false;
+	unsigned int accum_value_idx;
+	uint64_t accum_value = 0;
+	unsigned int i, qid;
+	unsigned int nb_queues;
+
+
+	rte_spinlock_lock(bmp_lock);
+	rte_bitmap_reset(bmp);
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		goto unlock;
+	*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	for (i = 0; i < ids_size; i++) {
+		if (id_base <= ids[i] && ids[i] <= (id_base + nb_queues)) {
+			if (ids[i] == id_base) { /* Accumulative value */
+				count_accum_value = true;
+				accum_value_idx = i;
+				continue;
+			}
+			qid = ids[i] - id_base - 1;
+			values[i] = sw_xstat->get_val(sa, qid);
+			accum_value += values[i];
+
+			rte_bitmap_set(bmp, qid);
+		}
+	}
+
+	if (count_accum_value) {
+		for (qid = 0; qid < nb_queues; ++qid) {
+			if (rte_bitmap_get(bmp, qid) != 0)
+				continue;
+			values[accum_value_idx] += sw_xstat->get_val(sa, qid);
+		}
+		values[accum_value_idx] += accum_value;
+	}
+
+unlock:
+	rte_spinlock_unlock(bmp_lock);
+}
+
+unsigned int
+sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa)
+{
+	unsigned int nb_supported = 0;
+	unsigned int i;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
+							     &sfc_sw_xstats[i]);
+	}
+
+	return nb_supported;
+}
+
+void
+sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
+		       struct rte_eth_xstat *xstats,
+		       unsigned int xstats_count,
+		       unsigned int *nb_written,
+		       unsigned int *nb_supported)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	unsigned int sw_xstats_offset;
+	unsigned int i;
+
+	sfc_adapter_lock(sa);
+
+	sw_xstats_offset = *nb_supported;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sfc_sw_xstat_get_values(sa, &sfc_sw_xstats[i], xstats,
+					xstats_count, nb_written, nb_supported);
+	}
+
+	for (i = sw_xstats_offset; i < *nb_written; i++)
+		xstats[i].value -= reset_vals[i - sw_xstats_offset];
+
+	sfc_adapter_unlock(sa);
+}
+
+int
+sfc_sw_xstats_get_names(struct sfc_adapter *sa,
+			struct rte_eth_xstat_name *xstats_names,
+			unsigned int xstats_count,
+			unsigned int *nb_written,
+			unsigned int *nb_supported)
+{
+	unsigned int i;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		ret = sfc_sw_stat_get_names(sa, &sfc_sw_xstats[i],
+					    xstats_names, xstats_count,
+					    nb_written, nb_supported);
+		if (ret != 0) {
+			sfc_adapter_unlock(sa);
+			return ret;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return 0;
+}
+
+void
+sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,
+			     const uint64_t *ids,
+			     uint64_t *values,
+			     unsigned int n,
+			     unsigned int *nb_supported)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	unsigned int sw_xstats_offset;
+	unsigned int i;
+
+	sfc_adapter_lock(sa);
+
+	sw_xstats_offset = *nb_supported;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sfc_sw_xstat_get_values_by_id(sa, &sfc_sw_xstats[i], ids,
+					      values, n, nb_supported);
+	}
+
+	for (i = 0; i < n; i++) {
+		if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)
+			values[i] -= reset_vals[ids[i] - sw_xstats_offset];
+	}
+
+	sfc_adapter_unlock(sa);
+}
+
+int
+sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,
+			      const uint64_t *ids,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int size,
+			      unsigned int *nb_supported)
+{
+	unsigned int i;
+	int ret;
+
+	sfc_adapter_lock(sa);
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		ret = sfc_sw_xstat_get_names_by_id(sa, &sfc_sw_xstats[i], ids,
+						   xstats_names, size,
+						   nb_supported);
+		if (ret != 0) {
+			sfc_adapter_unlock(sa);
+			SFC_ASSERT(ret < 0);
+			return ret;
+		}
+	}
+
+	sfc_adapter_unlock(sa);
+
+	return 0;
+}
+
+static void
+sfc_sw_xstat_reset(struct sfc_adapter *sa, struct sfc_sw_xstat_descr *sw_xstat,
+		   uint64_t *reset_vals)
+{
+	unsigned int nb_queues;
+	unsigned int qid;
+	uint64_t *accum_xstat_reset;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
+	if (nb_queues == 0)
+		return;
+
+	/*
+	 * The order of each software xstat type is the accumulative xstat
+	 * followed by per-queue xstats.
+	 */
+	accum_xstat_reset = reset_vals;
+	*accum_xstat_reset = 0;
+	reset_vals++;
+
+	for (qid = 0; qid < nb_queues; ++qid) {
+		reset_vals[qid] = sw_xstat->get_val(sa, qid);
+		*accum_xstat_reset += reset_vals[qid];
+	}
+}
+
+void
+sfc_sw_xstats_reset(struct sfc_adapter *sa)
+{
+	uint64_t *reset_vals = sa->sw_xstats.reset_vals;
+	struct sfc_sw_xstat_descr *sw_xstat;
+	unsigned int i;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {
+		sw_xstat = &sfc_sw_xstats[i];
+		sfc_sw_xstat_reset(sa, sw_xstat, reset_vals);
+		reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_xstat);
+	}
+}
+
+int
+sfc_sw_xstats_configure(struct sfc_adapter *sa)
+{
+	uint64_t **reset_vals = &sa->sw_xstats.reset_vals;
+	size_t nb_supported = 0;
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(sfc_sw_xstats); i++)
+		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
+							&sfc_sw_xstats[i]);
+
+	*reset_vals = rte_realloc(*reset_vals,
+				  nb_supported * sizeof(**reset_vals), 0);
+	if (*reset_vals == NULL)
+		return ENOMEM;
+
+	memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));
+
+	return 0;
+}
+
+static void
+sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)
+{
+	rte_bitmap_free(sa->sw_xstats.queues_bitmap);
+	rte_free(sa->sw_xstats.queues_bitmap_mem);
+}
+
+static int
+sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)
+{
+	struct rte_bitmap **queues_bitmap = &sa->sw_xstats.queues_bitmap;
+	void **queues_bitmap_mem = &sa->sw_xstats.queues_bitmap_mem;
+	uint32_t bmp_size;
+	int rc;
+
+	bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);
+	*queues_bitmap_mem = NULL;
+	*queues_bitmap = NULL;
+
+	*queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0,
+					       sa->socket_id);
+	if (*queues_bitmap_mem == NULL)
+		return ENOMEM;
+
+	*queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,
+					 *queues_bitmap_mem, bmp_size);
+	if (*queues_bitmap == NULL) {
+		rc = EINVAL;
+		goto fail;
+	}
+
+	rte_spinlock_init(&sa->sw_xstats.queues_bitmap_lock);
+	return 0;
+
+fail:
+	sfc_sw_xstats_free_queues_bitmap(sa);
+	return rc;
+}
+
+int
+sfc_sw_xstats_init(struct sfc_adapter *sa)
+{
+	sa->sw_xstats.reset_vals = NULL;
+
+	return sfc_sw_xstats_alloc_queues_bitmap(sa);
+}
+
+void
+sfc_sw_xstats_close(struct sfc_adapter *sa)
+{
+	rte_free(sa->sw_xstats.reset_vals);
+	sa->sw_xstats.reset_vals = NULL;
+
+	sfc_sw_xstats_free_queues_bitmap(sa);
+}
diff --git a/drivers/net/sfc/sfc_sw_stats.h b/drivers/net/sfc/sfc_sw_stats.h
new file mode 100644
index 0000000000..1abded8018
--- /dev/null
+++ b/drivers/net/sfc/sfc_sw_stats.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2021 Xilinx, Inc.
+ */
+#ifndef _SFC_SW_STATS_H
+#define _SFC_SW_STATS_H
+
+#include <rte_dev.h>
+
+#include "sfc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
+			    struct rte_eth_xstat *xstats,
+			    unsigned int xstats_count, unsigned int *nb_written,
+			    unsigned int *nb_supported);
+
+int sfc_sw_xstats_get_names(struct sfc_adapter *sa,
+			    struct rte_eth_xstat_name *xstats_names,
+			    unsigned int xstats_count, unsigned int *nb_written,
+			    unsigned int *nb_supported);
+
+void sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				  uint64_t *values, unsigned int n,
+				  unsigned int *nb_supported);
+
+int sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+				  struct rte_eth_xstat_name *xstats_names,
+				  unsigned int size,
+				  unsigned int *nb_supported);
+
+unsigned int sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa);
+
+int sfc_sw_xstats_configure(struct sfc_adapter *sa);
+
+void sfc_sw_xstats_reset(struct sfc_adapter *sa);
+
+int sfc_sw_xstats_init(struct sfc_adapter *sa);
+
+void sfc_sw_xstats_close(struct sfc_adapter *sa);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _SFC_SW_STATS_H */
diff --git a/drivers/net/sfc/sfc_tx.c b/drivers/net/sfc/sfc_tx.c
index ce2a9a6a4f..49b239f4d2 100644
--- a/drivers/net/sfc/sfc_tx.c
+++ b/drivers/net/sfc/sfc_tx.c
@@ -980,8 +980,10 @@ sfc_efx_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 				       txq->completed, &txq->added);
 		SFC_ASSERT(rc == 0);
 
-		if (likely(pushed != txq->added))
+		if (likely(pushed != txq->added)) {
 			efx_tx_qpush(txq->common, txq->added, pushed);
+			txq->dp.dpq.tx_dbells++;
+		}
 	}
 
 #if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v3 11/11] app/testpmd: add option to display extended statistics
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (9 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 10/11] net/sfc: add xstats for Rx/Tx doorbells Andrew Rybchenko
@ 2021-07-23 13:15   ` Andrew Rybchenko
  2021-08-20 13:55     ` [dpdk-dev] [PATCH v4] " Andrew Rybchenko
                       ` (2 more replies)
  2021-07-23 21:34   ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Thomas Monjalon
  11 siblings, 3 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 13:15 UTC (permalink / raw)
  To: dev, Xiaoyun Li; +Cc: David Marchand, Ivan Ilchenko

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
(i.e. 'stats-period' option or 'show port stats' interactive command) to
display specified list of extended statistics.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 app/test-pmd/cmdline.c                |  55 ++++++++++++
 app/test-pmd/config.c                 |  66 ++++++++++++++
 app/test-pmd/parameters.c             |  18 ++++
 app/test-pmd/testpmd.c                | 120 ++++++++++++++++++++++++++
 app/test-pmd/testpmd.h                |  21 +++++
 doc/guides/testpmd_app_ug/run_app.rst |   5 ++
 6 files changed, 285 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 8468018cf3..97cfc5dc2a 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -3609,6 +3609,61 @@ cmdline_parse_inst_t cmd_stop = {
 
 /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
 
+int
+parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
+		  unsigned int *xstats_num)
+{
+	int max_names_nb, names_nb;
+	int stringlen;
+	char **names;
+	char *str;
+	int ret;
+	int i;
+
+	names = NULL;
+	str = strdup(in_str);
+	if (str == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+	stringlen = strlen(str);
+
+	for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
+		if (str[i] == ',')
+			max_names_nb++;
+	}
+
+	names = calloc(max_names_nb, sizeof(*names));
+	if (names == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
+	if (names_nb < 0) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	*xstats = calloc(names_nb, sizeof(**xstats));
+	if (*xstats == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < names_nb; i++)
+		rte_strscpy((*xstats)[i].name, names[i],
+			    sizeof((*xstats)[i].name));
+
+	*xstats_num = names_nb;
+	ret = 0;
+
+out:
+	free(names);
+	free(str);
+	return ret;
+}
+
 unsigned int
 parse_item_list(const char *str, const char *item_name, unsigned int max_items,
 		unsigned int *parsed_items, int check_unique_values)
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 04ae0feb58..6d604145bd 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -173,6 +173,70 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
 	printf("%s%s", name, buf);
 }
 
+static void
+nic_xstats_display_periodic(portid_t port_id)
+{
+	struct xstat_display_info *xstats_info;
+	uint64_t *prev_values, *curr_values;
+	uint64_t diff_value, value_rate;
+	uint64_t *ids, *ids_supp;
+	struct timespec cur_time;
+	unsigned int i, i_supp;
+	size_t ids_supp_sz;
+	uint64_t diff_ns;
+	int rc;
+
+	xstats_info = &xstats_per_port[port_id];
+
+	ids_supp_sz = xstats_info->ids_supp_sz;
+	if (xstats_display_num == 0 || ids_supp_sz == 0)
+		return;
+
+	printf("\n");
+
+	ids = xstats_info->ids;
+	ids_supp = xstats_info->ids_supp;
+	prev_values = xstats_info->prev_values;
+	curr_values = xstats_info->curr_values;
+
+	rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
+				      ids_supp_sz);
+	if (rc != (int)ids_supp_sz) {
+		fprintf(stderr, "%s: Failed to get values of %zu supported xstats for port %u - return code %d\n",
+			__func__, ids_supp_sz, port_id, rc);
+		return;
+	}
+
+	diff_ns = 0;
+	if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
+		uint64_t ns;
+
+		ns = cur_time.tv_sec * NS_PER_SEC;
+		ns += cur_time.tv_nsec;
+
+		if (xstats_info->prev_ns != 0)
+			diff_ns = ns - xstats_info->prev_ns;
+		xstats_info->prev_ns = ns;
+	}
+
+	printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
+	for (i = i_supp = 0; i < xstats_display_num; i++) {
+		if (ids[i] == XSTAT_ID_INVALID)
+			continue;
+
+		diff_value = (curr_values[i_supp] > prev_values[i]) ?
+			     (curr_values[i_supp] - prev_values[i]) : 0;
+		prev_values[i] = curr_values[i_supp];
+		value_rate = diff_ns > 0 ?
+				(double)diff_value / diff_ns * NS_PER_SEC : 0;
+
+		printf("  %-25s%12"PRIu64" %15"PRIu64"\n",
+		       xstats_display[i].name, curr_values[i_supp], value_rate);
+
+		i_supp++;
+	}
+}
+
 void
 nic_stats_display(portid_t port_id)
 {
@@ -243,6 +307,8 @@ nic_stats_display(portid_t port_id)
 	       PRIu64"          Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
 	       mpps_tx, mbps_tx * 8);
 
+	nic_xstats_display_periodic(port_id);
+
 	printf("  %s############################%s\n",
 	       nic_stats_border, nic_stats_border);
 }
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 5e69d2aa8c..d4c032cb56 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -61,6 +61,9 @@ usage(char* progname)
 	       "(only if interactive is disabled).\n");
 	printf("  --stats-period=PERIOD: statistics will be shown "
 	       "every PERIOD seconds (only if interactive is disabled).\n");
+	printf("  --display-xstats xstat1[,...]: extended statistics to show. "
+	       "Used with --stats-period specified or interactive commands "
+	       "that show Rx/Tx statistics (i.e. 'show port stats').\n");
 	printf("  --nb-cores=N: set the number of forwarding cores "
 	       "(1 <= N <= %d).\n", nb_lcores);
 	printf("  --nb-ports=N: set the number of forwarding ports "
@@ -532,6 +535,7 @@ launch_args_parse(int argc, char** argv)
 #endif
 		{ "tx-first",			0, 0, 0 },
 		{ "stats-period",		1, 0, 0 },
+		{ "display-xstats",		1, 0, 0 },
 		{ "nb-cores",			1, 0, 0 },
 		{ "nb-ports",			1, 0, 0 },
 		{ "coremask",			1, 0, 0 },
@@ -689,6 +693,20 @@ launch_args_parse(int argc, char** argv)
 				stats_period = n;
 				break;
 			}
+			if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
+				char rc;
+
+				rc = parse_xstats_list(optarg, &xstats_display,
+						       &xstats_display_num);
+				if (rc != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to fill xstats to display: %d\n",
+						 rc);
+
+				if (alloc_display_xstats_info() != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to alloc xstats display memory\n");
+			}
 			if (!strcmp(lgopts[opt_idx].name,
 				    "eth-peers-configfile")) {
 				if (init_peer_eth_addrs(optarg) != 0)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index a48f70962f..1703d7d30f 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -208,6 +208,14 @@ uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
                                       * specified on command-line. */
 uint16_t stats_period; /**< Period to show statistics (disabled by default) */
 
+/** Extended statistics to show. */
+struct rte_eth_xstat_name *xstats_display;
+
+unsigned int xstats_display_num; /**< Size of extended statistics to show */
+
+/** Helper structures for each port to show extended statistics. */
+struct xstat_display_info xstats_per_port[RTE_MAX_ETHPORTS];
+
 /*
  * In container, it cannot terminate the process which running with 'stats-period'
  * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
@@ -542,6 +550,12 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
 /* Holds the registered mbuf dynamic flags names. */
 char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
 
+/** Fill helper structures for specified port to show extended statistics. */
+static void fill_display_xstats_info_for_port(portid_t pi);
+
+/** Fill helper structures for all ports to show extended statistics. */
+static void fill_display_xstats_info(void);
+
 /*
  * Helper function to check if socket is already discovered.
  * If yes, return positive value. If not, return zero.
@@ -2673,6 +2687,8 @@ start_port(portid_t pid)
 		}
 	}
 
+	fill_display_xstats_info_for_port(pid);
+
 	printf("Done\n");
 	return 0;
 }
@@ -3693,6 +3709,110 @@ force_quit(void)
 	prompt_exit();
 }
 
+int
+alloc_display_xstats_info(void)
+{
+	portid_t port;
+	uint64_t *mem;
+	size_t mem_size;
+
+	if (xstats_display_num == 0)
+		return 0;
+
+	memset(xstats_per_port, 0, sizeof(xstats_per_port));
+
+	for (port = 0; port < RTE_MAX_ETHPORTS; port++) {
+		uint64_t **ids = &xstats_per_port[port].ids;
+		uint64_t **ids_supp = &xstats_per_port[port].ids_supp;
+		uint64_t **prev_values = &xstats_per_port[port].prev_values;
+		uint64_t **curr_values = &xstats_per_port[port].curr_values;
+
+		if (port == 0) {
+			mem_size = RTE_MAX_ETHPORTS * xstats_display_num *
+				   (sizeof(**ids) + sizeof(**ids_supp) +
+				    sizeof(**prev_values) +
+				    sizeof(**curr_values));
+
+			mem = malloc(mem_size);
+			if (mem == NULL)
+				return -ENOMEM;
+
+			memset(mem, 0, mem_size);
+		}
+
+		*ids = mem;
+		mem += xstats_display_num * sizeof(**ids);
+
+		*ids_supp = mem;
+		mem += xstats_display_num * sizeof(**ids_supp);
+
+		*prev_values = mem;
+		mem += xstats_display_num * sizeof(**prev_values);
+
+		*curr_values = mem;
+		mem += xstats_display_num * sizeof(**curr_values);
+	}
+
+	return 0;
+}
+
+static void
+fill_display_xstats_info_for_port(portid_t pi)
+{
+	unsigned int stat, stat_supp;
+	uint64_t *ids, *ids_supp;
+	const char *xstat_name;
+	struct rte_port *port;
+	int rc;
+
+	if (xstats_display_num == 0)
+		return;
+
+	if (pi == (portid_t)RTE_PORT_ALL) {
+		fill_display_xstats_info();
+		return;
+	}
+
+	port = &ports[pi];
+	if (port->port_status != RTE_PORT_STARTED)
+		return;
+
+	ids = xstats_per_port[pi].ids;
+	ids_supp = xstats_per_port[pi].ids_supp;
+
+	for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
+		xstat_name = xstats_display[stat].name;
+
+		rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
+						   ids + stat);
+		if (rc != 0) {
+			ids[stat] = XSTAT_ID_INVALID;
+			printf("No xstat '%s' on port %u - skip it\n",
+			       xstat_name, pi);
+			continue;
+		}
+		ids_supp[stat_supp++] = ids[stat];
+	}
+
+	xstats_per_port[pi].ids_supp_sz = stat_supp;
+}
+
+static void
+fill_display_xstats_info(void)
+{
+	portid_t pi;
+
+	if (xstats_display_num == 0)
+		return;
+
+	RTE_ETH_FOREACH_DEV(pi) {
+		if (pi == (portid_t)RTE_PORT_ALL)
+			continue;
+
+		fill_display_xstats_info_for_port(pi);
+	}
+}
+
 static void
 print_stats(void)
 {
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index d61a055bdd..22d11a57f6 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -434,6 +434,24 @@ extern uint32_t param_total_num_mbufs;
 
 extern uint16_t stats_period;
 
+extern struct rte_eth_xstat_name *xstats_display;
+extern unsigned int xstats_display_num;
+
+#define XSTAT_ID_INVALID UINT64_MAX
+
+/** Information for an extended statistics to show. */
+struct xstat_display_info {
+	/** IDs of xstats in the order of xstats_display */
+	uint64_t *ids;
+	/** Supported xstats IDs in the order of xstats_display */
+	uint64_t *ids_supp;
+	size_t   ids_supp_sz;
+	uint64_t *prev_values;
+	uint64_t *curr_values;
+	uint64_t prev_ns;
+};
+extern struct xstat_display_info xstats_per_port[];
+
 extern uint16_t hairpin_mode;
 
 #ifdef RTE_LIB_LATENCYSTATS
@@ -766,6 +784,8 @@ inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx)
 unsigned int parse_item_list(const char *str, const char *item_name,
 			unsigned int max_items,
 			unsigned int *parsed_items, int check_unique_values);
+int parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
+		      unsigned int *xstats_num);
 void launch_args_parse(int argc, char** argv);
 void cmdline_read_from_file(const char *filename);
 void prompt(void);
@@ -978,6 +998,7 @@ enum print_warning {
 int port_id_is_invalid(portid_t port_id, enum print_warning warning);
 void print_valid_ports(void);
 int new_socket_id(unsigned int socket_id);
+int alloc_display_xstats_info(void);
 
 queueid_t get_allowed_max_nb_rxq(portid_t *pid);
 int check_nb_rxq(queueid_t rxq);
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index eb48318353..3e5ba81f18 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -56,6 +56,11 @@ The command line options are:
     Display statistics every PERIOD seconds, if interactive mode is disabled.
     The default value is 0, which means that the statistics will not be displayed.
 
+*   ``--display-xstats xstat1[,...]``
+
+    Display extended statistics every PERIOD seconds as specified in ``--stats-period``
+    or when used with interactive commands that show Rx/Tx statistics (i.e. 'show port stats').
+
 *   ``--nb-cores=N``
 
     Set the number of forwarding cores,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-07-22  9:12     ` Andrew Rybchenko
@ 2021-07-23 14:19       ` Ferruh Yigit
  2021-07-24 12:06         ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-07-23 14:19 UTC (permalink / raw)
  To: Andrew Rybchenko, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 7/22/2021 10:12 AM, Andrew Rybchenko wrote:
> On 7/20/21 7:25 PM, Ferruh Yigit wrote:
>> On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>
>>> Document valid combinations of input arguments in accordance with
>>> current implementation in ethdev.
>>>
>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>> Cc: stable@dpdk.org
>>>
>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>> ---
>>>   lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
>>>   1 file changed, 14 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
>>> index faf3bd901d..1f63118544 100644
>>> --- a/lib/ethdev/rte_ethdev.h
>>> +++ b/lib/ethdev/rte_ethdev.h
>>> @@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct
>>> rte_eth_xstat *xstats,
>>>    *   The port identifier of the Ethernet device.
>>>    * @param xstats_names
>>>    *   An rte_eth_xstat_name array of at least *size* elements to
>>> - *   be filled. If set to NULL, the function returns the required number
>>> - *   of elements.
>>> + *   be filled. Must not be NULL if @p ids are specified (not NULL).
>>
>> Removed part is also valid. If both 'ids' & 'xstats_names' are NULL, API returns
>> number of all elements.
> 
> Yes, but it is an excessive information. The trigger to return number
> of all elements is 'ids == NULL'. Here we are talking about
> 'xstats_names' parameter. If the parameter is NULL, but ids is not
> null, it does not trigger number of all elements return. It is an
> invalid input parameters. That's what a new description says.
> 

   ids		xstats_names
a) NULL		NULL		valid, return _number_ of all elements
b) NULL		!NULL		valid, return all elements (if size big enough)
c) !NULL	NULL		invalid

Above a) is a valid option, the previous comment tries to describe it via "If
set to NULL, the function returns the required number of elements." and that
part is removed.
Since it is valid option I think we should keep it documented, location or
wording is up to you.

>>
>> Addition part looks good.
>>
>>>    * @param ids
>>> - *   IDs array given by app to retrieve specific statistics
>>> + *   IDs array given by app to retrieve specific statistics. May be NULL
>>> + *   to retrieve all available statistics.
>>
>> ack
>>
>>>    * @param size
>>> - *   The size of the xstats_names array (number of elements).
>>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>>> + *   and number of elements in @p xstats_names to put names in. If @p ids is
>>> + *   NULL, number of elements in @p xstats_names to put all available
>>> statistics
>>> + *   names in.
>>
>> ack
>>
>>>    * @return
>>>    *   - A positive value lower or equal to size: success. The return value
>>>    *     is the number of entries filled in the stats table.
>>> @@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct
>>> rte_eth_xstat *xstats,
>>>    *     is too small. The return value corresponds to the size that should
>>>    *     be given to succeed. The entries in the table are not valid and
>>>    *     shall not be used by the caller.
>>> - *   - A negative value on error (invalid port id).
>>> + *   - A negative value on error.
>>
>> ack
>>
>>
>> The 'eth_dev_get_xstats_count()' API is flexible but it makes API unnecessarily
>> complex, not for this patch but for future perhaps we can update the API and it
>> can return error if either 'ids' or 'xstats_names' is NULL. Remove support to
>> get all elements or getting number of elements support, these already supported
>> by non _id version of API.
> 
> I'm not sure that it is a right direction. The support allows
> application to use less number of functions and depend on less
> number of function prototypes.
> 

True, but makes API more complex, and creates multiple way to do same thing (get
number of all entries), trade off.

>> And as a note for future, if we ever consider updating these _by_id APIs, we can
>> consider making the parameter order same for both, currently it is:
>> "rte_eth_xstats_get_names_by_id(port_id, values, size, ids)"
>> "      rte_eth_xstats_get_by_id(port_id, ids, values, size)"
> 
> +1, current difference is terribly bad
> 
>>>    */
>>>   int
>>>   rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>> @@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>>    *   The port identifier of the Ethernet device.
>>>    * @param ids
>>>    *   A pointer to an ids array passed by application. This tells which
>>> - *   statistics values function should retrieve. This parameter
>>> - *   can be set to NULL if size is 0. In this case function will retrieve
>>> + *   statistics values function should retrieve. May be NULL to retrieve
>>>    *   all available statistics.
>>
>> Update is good. But what do you think to make it exact same in the both APIs
>> ('rte_eth_xstats_get_names_by_id()' & 'rte_eth_xstats_get_by_id()')? Since it is
>> used for same purpose and exact same way in both APIs, no need to have slightly
>> different description.
> 
> I agree. I'll fix in v2.
> 
>>>    * @param values
>>>    *   A pointer to a table to be filled with device statistics values.
>>> + *   Must not be NULL if ids are specified (not NULL).
>>
>> Same comment on making description similar in both APIs.
> 
> OK
> 
>> Also both 'ids' & 'values' being NULL returns number of all elements should be
>> addressed.
> 
> I think it is excessibe. It is sufficient to say so for ids==NULL which
> is a trigger to get all elements.
> 

But these two are different things,
one fills values with stats and return number of filled elements
other doesn't fill any value, but only return number of all elements

>>>    * @param size
>>> - *   The size of the ids array (number of elements).
>>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>>> + *   and number of elements in values to put statistics in. If @p ids is NULL,
>>> + *   number of elements in values to put all available statistics in.
>>
>> ack
>>
>>>    * @return
>>>    *   - A positive value lower or equal to size: success. The return value
>>>    *     is the number of entries filled in the stats table.
>>> @@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>>    *     is too small. The return value corresponds to the size that should
>>>    *     be given to succeed. The entries in the table are not valid and
>>>    *     shall not be used by the caller.
>>> - *   - A negative value on error (invalid port id).
>>> + *   - A negative value on error.
>>
>> ack
>>
>>>    */
>>>   int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>>>                    uint64_t *values, unsigned int size);
>>>
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-22  9:33     ` Andrew Rybchenko
@ 2021-07-23 14:31       ` Ferruh Yigit
  2021-07-23 18:47         ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-07-23 14:31 UTC (permalink / raw)
  To: Andrew Rybchenko, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 7/22/2021 10:33 AM, Andrew Rybchenko wrote:
> On 7/20/21 7:51 PM, Ferruh Yigit wrote:
>> On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>
>>> Update xstats by IDs callbacks documentation in accordance with
>>> ethdev usage of these callbacks. Document valid combinations of
>>> input arguments to make driver implementation simpler.
>>>
>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>> Cc: stable@dpdk.org
>>>
>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>> ---
>>>   lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
>>>   1 file changed, 41 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>>> index 40e474aa7e..fd5b7ca550 100644
>>> --- a/lib/ethdev/ethdev_driver.h
>>> +++ b/lib/ethdev/ethdev_driver.h
>>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>>       struct rte_eth_xstat *stats, unsigned int n);
>>>   /**< @internal Get extended stats of an Ethernet device. */
>>>   +/**
>>> + * @internal
>>> + * Get extended stats of an Ethernet device.
>>
>> Should it mention _by_id detail?
> 
> Yes, will fix in v2.
> 
>>> + *
>>> + * @param dev
>>> + *   ethdev handle of port.
>>> + * @param ids
>>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>>> + * @param values
>>> + *   A pointer to a table to be filled with device statistics values.
>>> + *   Must not be NULL.
>>> + * @param n
>>> + *   Element count in @p ids and @p values
>>> + *
>>> + * @return
>>> + *   - A number of filled in stats.
>>> + *   - A negative value on error.
>>> + */
>>>   typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>>                         const uint64_t *ids,
>>>                         uint64_t *values,
>>>                         unsigned int n);
>>> -/**< @internal Get extended stats of an Ethernet device. */
>>>     /**
>>>    * @internal
>>> @@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct
>>> rte_eth_dev *dev,
>>>       struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>>   /**< @internal Get names of extended stats of an Ethernet device. */
>>>   +/**
>>> + * @internal
>>> + * Get names of extended stats of an Ethernet device.
>>
>> Should it mention _by_id detail?
> 
> Yes, will fix in v2.
> 
>>> + * For name count, set @p xstats_names and @p ids to NULL.
>>> + *
>>
>> isn't the 'count' part handled in the API? I think in the devops both should not
>> be NULL.
> 
> No, eth_dev_get_xstats_count() uses the callback with NULL, NULL, 0.
> 

Right, I missed it, xstats_get_names_by_id() seems used outside of the ethdev
_by_id() APIs.

>>
>>> + * @param dev
>>> + *   ethdev handle of port.
>>> + * @param xstats_names
>>> + *   An rte_eth_xstat_name array of at least *size* elements to
>>> + *   be filled. Can be NULL together with @p ids to retrieve number of
>>> + *   available statistics.
>>
>> As far as I understand both _by_id APIs and devops behave same, so argument
>> descriptions/behavior should be same.
> 
> In fact no, it is slightly different. For example, devops is never
> called with NULL ids and not NULL names or non-zero size. It allows to
> check less in drivers.
> 

I am not sure if this difference is intentional.

'eth_dev_get_xstats_count()' is ethdev internal function, what do you think
removing 'xstats_get_names_by_id()' call from it. And make both _by_id() dev_ops
doesn't accept NULL ids and NULL values/names, so simplifies PMD implementations.

>>> + * @param ids
>>> + *   IDs array to retrieve specific statistics. Can be NULL together
>>> + *   with @p xstats_names to retrieve number of available statistics.
>>> + * @param size
>>> + *   Size of ids and xstats_names arrays.
>>> + *   Element count in @p ids and @p xstats_names
>>> + *
>>> + * @return
>>> + *   - A number of filled in stats if both xstats_names and ids are not NULL.
>>> + *   - A number of available stats if both xstats_names and ids are NULL.
>>
>> Again as far as I can see these covered by API, not devops, am I missing
>> something.
> 
> See eth_dev_get_xstats_count()
> 
>>
>>> + *   - A negative value on error.
>>> + */
>>>   typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
>>>       struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
>>>       unsigned int size);
>>> -/**< @internal Get names of extended stats of an Ethernet device. */
>>>     typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
>>>                            uint16_t queue_id,
>>>
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v3 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 03/11] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-07-23 14:42     ` Ferruh Yigit
  2021-07-24 12:07       ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-07-23 14:42 UTC (permalink / raw)
  To: Andrew Rybchenko, dev, Thomas Monjalon, Kuba Kozak
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

On 7/23/2021 2:15 PM, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Document valid combinations of input arguments in accordance with
> current implementation in ethdev.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
> ---
>  lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
>  1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
> index d2b27c351f..28440c46d3 100644
> --- a/lib/ethdev/rte_ethdev.h
> +++ b/lib/ethdev/rte_ethdev.h
> @@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>   *   The port identifier of the Ethernet device.
>   * @param xstats_names
>   *   An rte_eth_xstat_name array of at least *size* elements to
> - *   be filled. If set to NULL, the function returns the required number
> - *   of elements.
> + *   be filled. Must not be NULL if @p ids are specified (not NULL).
>   * @param ids
> - *   IDs array given by app to retrieve specific statistics
> + *   IDs array given by app to retrieve specific statistics. May be NULL
> + *   to retrieve all available statistics.
>   * @param size
> - *   The size of the xstats_names array (number of elements).
> + *   If @p ids is not NULL, number of elements in the array with requested IDs
> + *   and number of elements in @p xstats_names to put names in. If @p ids is
> + *   NULL, number of elements in @p xstats_names to put all available statistics
> + *   names in.
>   * @return
>   *   - A positive value lower or equal to size: success. The return value
>   *     is the number of entries filled in the stats table.
> @@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>   *     is too small. The return value corresponds to the size that should
>   *     be given to succeed. The entries in the table are not valid and
>   *     shall not be used by the caller.
> - *   - A negative value on error (invalid port id).
> + *   - A negative value on error.
>   */
>  int
>  rte_eth_xstats_get_names_by_id(uint16_t port_id,
> @@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>   *   The port identifier of the Ethernet device.
>   * @param ids
>   *   A pointer to an ids array passed by application. This tells which
> - *   statistics values function should retrieve. This parameter
> - *   can be set to NULL if size is 0. In this case function will retrieve
> + *   statistics values function should retrieve. May be NULL to retrieve
>   *   all available statistics.

'ids' parameter in 'rte_eth_xstats_get_names_by_id()' &
'rte_eth_xstats_get_by_id()' are exactly same thing, and description is same but
wording is different.

Do you think does it make sense to use exact same wording, to clarify that there
is no difference in this parameter within APIs?

>   * @param values
>   *   A pointer to a table to be filled with device statistics values.
> + *   Must not be NULL if ids are specified (not NULL).

Similar comment on this one, two different API get 'name' and 'value' part of
key-value pair. The description between APIs can be almost same.

>   * @param size
> - *   The size of the ids array (number of elements).
> + *   If @p ids is not NULL, number of elements in the array with requested IDs
> + *   and number of elements in values to put statistics in. If @p ids is NULL,
> + *   number of elements in values to put all available statistics in.

And same comment again on using exact same comment on two APIs.

>   * @return
>   *   - A positive value lower or equal to size: success. The return value
>   *     is the number of entries filled in the stats table.
> @@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>   *     is too small. The return value corresponds to the size that should
>   *     be given to succeed. The entries in the table are not valid and
>   *     shall not be used by the caller.
> - *   - A negative value on error (invalid port id).
> + *   - A negative value on error.
>   */
>  int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>  			     uint64_t *values, unsigned int size);
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v3 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 04/11] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-07-23 14:46     ` Ferruh Yigit
  0 siblings, 0 replies; 113+ messages in thread
From: Ferruh Yigit @ 2021-07-23 14:46 UTC (permalink / raw)
  To: Andrew Rybchenko, dev, Thomas Monjalon, Kuba Kozak
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

On 7/23/2021 2:15 PM, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Update xstats by IDs callbacks documentation in accordance with
> ethdev usage of these callbacks. Document valid combinations of
> input arguments to make driver implementation simpler.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
> ---
>  lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 41 insertions(+), 2 deletions(-)
> 

Some discussion on the v1 is still valid here, so I am not putting same comments
here until v1 ones clarified.

> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
> index 40e474aa7e..fd5b7ca550 100644
> --- a/lib/ethdev/ethdev_driver.h
> +++ b/lib/ethdev/ethdev_driver.h
> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat *stats, unsigned int n);
>  /**< @internal Get extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get extended stats of an Ethernet device.
> + *
> + * @param dev
> + *   ethdev handle of port.
> + * @param ids
> + *   IDs array to retrieve specific statistics. Must not be NULL.
> + * @param values
> + *   A pointer to a table to be filled with device statistics values.
> + *   Must not be NULL.
> + * @param n
> + *   Element count in @p ids and @p values
> + *
> + * @return
> + *   - A number of filled in stats.
> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>  				      const uint64_t *ids,
>  				      uint64_t *values,
>  				      unsigned int n);
> -/**< @internal Get extended stats of an Ethernet device. */
>  
>  /**
>   * @internal
> @@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>  /**< @internal Get names of extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get names of extended stats of an Ethernet device.
> + * For name count, set @p xstats_names and @p ids to NULL.
> + *
> + * @param dev
> + *   ethdev handle of port.
> + * @param xstats_names
> + *   An rte_eth_xstat_name array of at least *size* elements to
> + *   be filled. Can be NULL together with @p ids to retrieve number of
> + *   available statistics.
> + * @param ids
> + *   IDs array to retrieve specific statistics. Can be NULL together
> + *   with @p xstats_names to retrieve number of available statistics.
> + * @param size
> + *   Size of ids and xstats_names arrays.
> + *   Element count in @p ids and @p xstats_names
> + *
> + * @return
> + *   - A number of filled in stats if both xstats_names and ids are not NULL.
> + *   - A number of available stats if both xstats_names and ids are NULL.
> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
>  	unsigned int size);
> -/**< @internal Get names of extended stats of an Ethernet device. */
>  
>  typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
>  					     uint16_t queue_id,
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 04/11] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-23 14:31       ` Ferruh Yigit
@ 2021-07-23 18:47         ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-23 18:47 UTC (permalink / raw)
  To: Ferruh Yigit, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 7/23/21 5:31 PM, Ferruh Yigit wrote:
> On 7/22/2021 10:33 AM, Andrew Rybchenko wrote:
>> On 7/20/21 7:51 PM, Ferruh Yigit wrote:
>>> On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
>>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>
>>>> Update xstats by IDs callbacks documentation in accordance with
>>>> ethdev usage of these callbacks. Document valid combinations of
>>>> input arguments to make driver implementation simpler.
>>>>
>>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>>> Cc: stable@dpdk.org
>>>>
>>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>

[snip]

>>>> + * @param dev
>>>> + *   ethdev handle of port.
>>>> + * @param xstats_names
>>>> + *   An rte_eth_xstat_name array of at least *size* elements to
>>>> + *   be filled. Can be NULL together with @p ids to retrieve number of
>>>> + *   available statistics.
>>>
>>> As far as I understand both _by_id APIs and devops behave same, so argument
>>> descriptions/behavior should be same.
>>
>> In fact no, it is slightly different. For example, devops is never
>> called with NULL ids and not NULL names or non-zero size. It allows to
>> check less in drivers.
>>
> 
> I am not sure if this difference is intentional.

What we're trying to do here is to document existing usage of these
callbacks to more strictly define valid input parameters to allow
drivers to support less combinations (to make implementation simpler).

So, intentional.

If you're trying to say that API functions could handle less variants,
the answer is simple - it could be discussed, but out of scope of the
patch series since it will be API change.
> 'eth_dev_get_xstats_count()' is ethdev internal function, what do you think
> removing 'xstats_get_names_by_id()' call from it. And make both _by_id() dev_ops
> doesn't accept NULL ids and NULL values/names, so simplifies PMD implementations.
>
In fact the function eth_dev_get_xstats_count() looks buggy since it
does not use  xstats_get_names_by_id positive result if
xstats_get_names is not NULL. Really confusing.

Again, it will be slight change on PMD requirements. May be it is OK
to do, but I'd conduct it separately since it is logically a separate
thing. Current patches just clarify documentation.


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                     ` (10 preceding siblings ...)
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
@ 2021-07-23 21:34   ` Thomas Monjalon
  11 siblings, 0 replies; 113+ messages in thread
From: Thomas Monjalon @ 2021-07-23 21:34 UTC (permalink / raw)
  To: Andrew Rybchenko; +Cc: dev, David Marchand, ferruh.yigit, beilei.xing

23/07/2021 15:15, Andrew Rybchenko:
> Ivan Ilchenko (11):
>   net/sfc: fix get xstats by ID callback to use MAC stats lock
>   net/sfc: fix reading adapter state without locking
>   ethdev: fix docs of functions getting xstats by IDs
>   ethdev: fix docs of drivers callbacks getting xstats by IDs
>   net/sfc: fix xstats by ID callbacks according to ethdev
>   net/sfc: fix accessing xstats by an unsorted list of IDs
>   net/sfc: fix MAC stats update to work for stopped device
>   net/sfc: simplify getting of available xstats case
>   net/sfc: prepare to add more xstats
>   net/sfc: add xstats for Rx/Tx doorbells
>   app/testpmd: add option to display extended statistics

Applied the sfc patches.
The ethdev doc and testpmd patches may be part of -rc3 after more reviews.




^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-07-23 14:19       ` Ferruh Yigit
@ 2021-07-24 12:06         ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-24 12:06 UTC (permalink / raw)
  To: Ferruh Yigit, dev
  Cc: Ivan Ilchenko, stable, Andy Moreton, Thomas Monjalon, Kuba Kozak

On 7/23/21 5:19 PM, Ferruh Yigit wrote:
> On 7/22/2021 10:12 AM, Andrew Rybchenko wrote:
>> On 7/20/21 7:25 PM, Ferruh Yigit wrote:
>>> On 6/4/2021 3:42 PM, Andrew Rybchenko wrote:
>>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>
>>>> Document valid combinations of input arguments in accordance with
>>>> current implementation in ethdev.
>>>>
>>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>>> Cc: stable@dpdk.org
>>>>
>>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>>> ---
>>>>    lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
>>>>    1 file changed, 14 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
>>>> index faf3bd901d..1f63118544 100644
>>>> --- a/lib/ethdev/rte_ethdev.h
>>>> +++ b/lib/ethdev/rte_ethdev.h
>>>> @@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct
>>>> rte_eth_xstat *xstats,
>>>>     *   The port identifier of the Ethernet device.
>>>>     * @param xstats_names
>>>>     *   An rte_eth_xstat_name array of at least *size* elements to
>>>> - *   be filled. If set to NULL, the function returns the required number
>>>> - *   of elements.
>>>> + *   be filled. Must not be NULL if @p ids are specified (not NULL).
>>>
>>> Removed part is also valid. If both 'ids' & 'xstats_names' are NULL, API returns
>>> number of all elements.
>>
>> Yes, but it is an excessive information. The trigger to return number
>> of all elements is 'ids == NULL'. Here we are talking about
>> 'xstats_names' parameter. If the parameter is NULL, but ids is not
>> null, it does not trigger number of all elements return. It is an
>> invalid input parameters. That's what a new description says.
>>
> 
>     ids		xstats_names
> a) NULL		NULL		valid, return _number_ of all elements
> b) NULL		!NULL		valid, return all elements (if size big enough)
> c) !NULL	NULL		invalid
> 
> Above a) is a valid option, the previous comment tries to describe it via "If
> set to NULL, the function returns the required number of elements." and that
> part is removed.
> Since it is valid option I think we should keep it documented, location or
> wording is up to you.

OK, I see. IMHO, it looks better if it is mentioned in ids parameter
description.  See v4.

>>>
>>> Addition part looks good.
>>>
>>>>     * @param ids
>>>> - *   IDs array given by app to retrieve specific statistics
>>>> + *   IDs array given by app to retrieve specific statistics. May be NULL
>>>> + *   to retrieve all available statistics.
>>>
>>> ack
>>>
>>>>     * @param size
>>>> - *   The size of the xstats_names array (number of elements).
>>>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>>>> + *   and number of elements in @p xstats_names to put names in. If @p ids is
>>>> + *   NULL, number of elements in @p xstats_names to put all available
>>>> statistics
>>>> + *   names in.
>>>
>>> ack
>>>
>>>>     * @return
>>>>     *   - A positive value lower or equal to size: success. The return value
>>>>     *     is the number of entries filled in the stats table.
>>>> @@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct
>>>> rte_eth_xstat *xstats,
>>>>     *     is too small. The return value corresponds to the size that should
>>>>     *     be given to succeed. The entries in the table are not valid and
>>>>     *     shall not be used by the caller.
>>>> - *   - A negative value on error (invalid port id).
>>>> + *   - A negative value on error.
>>>
>>> ack
>>>
>>>
>>> The 'eth_dev_get_xstats_count()' API is flexible but it makes API unnecessarily
>>> complex, not for this patch but for future perhaps we can update the API and it
>>> can return error if either 'ids' or 'xstats_names' is NULL. Remove support to
>>> get all elements or getting number of elements support, these already supported
>>> by non _id version of API.
>>
>> I'm not sure that it is a right direction. The support allows
>> application to use less number of functions and depend on less
>> number of function prototypes.
>>
> 
> True, but makes API more complex, and creates multiple way to do same thing (get
> number of all entries), trade off.

Yes.

>>> And as a note for future, if we ever consider updating these _by_id APIs, we can
>>> consider making the parameter order same for both, currently it is:
>>> "rte_eth_xstats_get_names_by_id(port_id, values, size, ids)"
>>> "      rte_eth_xstats_get_by_id(port_id, ids, values, size)"
>>
>> +1, current difference is terribly bad
>>
>>>>     */
>>>>    int
>>>>    rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>>> @@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>>>     *   The port identifier of the Ethernet device.
>>>>     * @param ids
>>>>     *   A pointer to an ids array passed by application. This tells which
>>>> - *   statistics values function should retrieve. This parameter
>>>> - *   can be set to NULL if size is 0. In this case function will retrieve
>>>> + *   statistics values function should retrieve. May be NULL to retrieve
>>>>     *   all available statistics.
>>>
>>> Update is good. But what do you think to make it exact same in the both APIs
>>> ('rte_eth_xstats_get_names_by_id()' & 'rte_eth_xstats_get_by_id()')? Since it is
>>> used for same purpose and exact same way in both APIs, no need to have slightly
>>> different description.
>>
>> I agree. I'll fix in v2.
>>
>>>>     * @param values
>>>>     *   A pointer to a table to be filled with device statistics values.
>>>> + *   Must not be NULL if ids are specified (not NULL).
>>>
>>> Same comment on making description similar in both APIs.
>>
>> OK
>>
>>> Also both 'ids' & 'values' being NULL returns number of all elements should be
>>> addressed.
>>
>> I think it is excessibe. It is sufficient to say so for ids==NULL which
>> is a trigger to get all elements.
>>
> 
> But these two are different things,
> one fills values with stats and return number of filled elements
> other doesn't fill any value, but only return number of all elements

I get it. See v4. Hopefully I'll address it in ids parameter
description.

>>>>     * @param size
>>>> - *   The size of the ids array (number of elements).
>>>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>>>> + *   and number of elements in values to put statistics in. If @p ids is NULL,
>>>> + *   number of elements in values to put all available statistics in.
>>>
>>> ack
>>>
>>>>     * @return
>>>>     *   - A positive value lower or equal to size: success. The return value
>>>>     *     is the number of entries filled in the stats table.
>>>> @@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>>>     *     is too small. The return value corresponds to the size that should
>>>>     *     be given to succeed. The entries in the table are not valid and
>>>>     *     shall not be used by the caller.
>>>> - *   - A negative value on error (invalid port id).
>>>> + *   - A negative value on error.
>>>
>>> ack
>>>
>>>>     */
>>>>    int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>>>>                     uint64_t *values, unsigned int size);
>>>>
>>


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v3 03/11] ethdev: fix docs of functions getting xstats by IDs
  2021-07-23 14:42     ` Ferruh Yigit
@ 2021-07-24 12:07       ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-24 12:07 UTC (permalink / raw)
  To: Ferruh Yigit, dev, Thomas Monjalon, Kuba Kozak
  Cc: David Marchand, Ivan Ilchenko, stable, Andy Moreton

On 7/23/21 5:42 PM, Ferruh Yigit wrote:
> On 7/23/2021 2:15 PM, Andrew Rybchenko wrote:
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Document valid combinations of input arguments in accordance with
>> current implementation in ethdev.
>>
>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>> Cc: stable@dpdk.org
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>> ---
>>   lib/ethdev/rte_ethdev.h | 23 ++++++++++++++---------
>>   1 file changed, 14 insertions(+), 9 deletions(-)
>>
>> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
>> index d2b27c351f..28440c46d3 100644
>> --- a/lib/ethdev/rte_ethdev.h
>> +++ b/lib/ethdev/rte_ethdev.h
>> @@ -2873,12 +2873,15 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>>    *   The port identifier of the Ethernet device.
>>    * @param xstats_names
>>    *   An rte_eth_xstat_name array of at least *size* elements to
>> - *   be filled. If set to NULL, the function returns the required number
>> - *   of elements.
>> + *   be filled. Must not be NULL if @p ids are specified (not NULL).
>>    * @param ids
>> - *   IDs array given by app to retrieve specific statistics
>> + *   IDs array given by app to retrieve specific statistics. May be NULL
>> + *   to retrieve all available statistics.
>>    * @param size
>> - *   The size of the xstats_names array (number of elements).
>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>> + *   and number of elements in @p xstats_names to put names in. If @p ids is
>> + *   NULL, number of elements in @p xstats_names to put all available statistics
>> + *   names in.
>>    * @return
>>    *   - A positive value lower or equal to size: success. The return value
>>    *     is the number of entries filled in the stats table.
>> @@ -2886,7 +2889,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>>    *     is too small. The return value corresponds to the size that should
>>    *     be given to succeed. The entries in the table are not valid and
>>    *     shall not be used by the caller.
>> - *   - A negative value on error (invalid port id).
>> + *   - A negative value on error.
>>    */
>>   int
>>   rte_eth_xstats_get_names_by_id(uint16_t port_id,
>> @@ -2900,13 +2903,15 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>    *   The port identifier of the Ethernet device.
>>    * @param ids
>>    *   A pointer to an ids array passed by application. This tells which
>> - *   statistics values function should retrieve. This parameter
>> - *   can be set to NULL if size is 0. In this case function will retrieve
>> + *   statistics values function should retrieve. May be NULL to retrieve
>>    *   all available statistics.
> 
> 'ids' parameter in 'rte_eth_xstats_get_names_by_id()' &
> 'rte_eth_xstats_get_by_id()' are exactly same thing, and description is same but
> wording is different.
> 
> Do you think does it make sense to use exact same wording, to clarify that there
> is no difference in this parameter within APIs?

I thought that I've fixed it, but it looks like I've lost it on the way.
Will fix in v4. IMHO, it looks awkward if description is absolutely the
same, but description structure should be definitely the same.

>>    * @param values
>>    *   A pointer to a table to be filled with device statistics values.
>> + *   Must not be NULL if ids are specified (not NULL).
> 
> Similar comment on this one, two different API get 'name' and 'value' part of
> key-value pair. The description between APIs can be almost same.

Will fix in v4 similar to above.

>>    * @param size
>> - *   The size of the ids array (number of elements).
>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>> + *   and number of elements in values to put statistics in. If @p ids is NULL,
>> + *   number of elements in values to put all available statistics in.
> 
> And same comment again on using exact same comment on two APIs.

It is almost the same since it refers to other parameters which differ.
Other than that the description is equal.

>>    * @return
>>    *   - A positive value lower or equal to size: success. The return value
>>    *     is the number of entries filled in the stats table.
>> @@ -2914,7 +2919,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>    *     is too small. The return value corresponds to the size that should
>>    *     be given to succeed. The entries in the table are not valid and
>>    *     shall not be used by the caller.
>> - *   - A negative value on error (invalid port id).
>> + *   - A negative value on error.
>>    */
>>   int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>>   			     uint64_t *values, unsigned int size);
>>


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions getting xstats by IDs
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (12 preceding siblings ...)
  2021-07-23 13:15 ` [dpdk-dev] [PATCH v3 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
@ 2021-07-24 12:33 ` Andrew Rybchenko
  2021-07-24 12:33   ` [dpdk-dev] [PATCH v4 2/2] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
  2021-07-26 10:13   ` [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions " Olivier Matz
  2021-09-28 12:05 ` [dpdk-dev] [PATCH v5 " Andrew Rybchenko
                   ` (4 subsequent siblings)
  18 siblings, 2 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-24 12:33 UTC (permalink / raw)
  To: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Document valid combinations of input arguments in accordance with
current implementation in ethdev.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/rte_ethdev.h | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index d2b27c351f..b14067fe7e 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2872,13 +2872,17 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param xstats_names
- *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. If set to NULL, the function returns the required number
- *   of elements.
+ *   Array to be filled in with names of requested device statistics.
+ *   Must not be NULL if @p ids are specified (not NULL).
  * @param ids
- *   IDs array given by app to retrieve specific statistics
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve names of all available statistics or, if @p xstats_names is
+ *   NULL as well,  just a number of available statistics.
  * @param size
- *   The size of the xstats_names array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in @p xstats_names to put names in. If @p ids is
+ *   NULL, number of elements in @p xstats_names to put all available statistics
+ *   names in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2886,7 +2890,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int
 rte_eth_xstats_get_names_by_id(uint16_t port_id,
@@ -2899,14 +2903,16 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param ids
- *   A pointer to an ids array passed by application. This tells which
- *   statistics values function should retrieve. This parameter
- *   can be set to NULL if size is 0. In this case function will retrieve
- *   all available statistics.
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve all available statistics or, if @p values is NULL as well,
+ *   just a number of available statistics.
  * @param values
- *   A pointer to a table to be filled with device statistics values.
+ *   Array to be filled in with requested device statistics.
+ *   Must not be NULL if ids are specified (not NULL).
  * @param size
- *   The size of the ids array (number of elements).
+ *   If @p ids is not NULL, number of elements in the array with requested IDs
+ *   and number of elements in @p values to put statistics in. If @p ids is NULL,
+ *   number of elements in @p values to put all available statistics in.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
@@ -2914,7 +2920,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
 			     uint64_t *values, unsigned int size);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v4 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-24 12:33 ` [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-07-24 12:33   ` Andrew Rybchenko
  2021-07-26 10:13     ` Olivier Matz
  2021-07-26 10:13   ` [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions " Olivier Matz
  1 sibling, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-07-24 12:33 UTC (permalink / raw)
  To: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 40e474aa7e..fd5b7ca550 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats of an Ethernet device.
+ * For name count, set @p xstats_names and @p ids to NULL.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Can be NULL together with @p ids to retrieve number of
+ *   available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param size
+ *   Size of ids and xstats_names arrays.
+ *   Element count in @p ids and @p xstats_names
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions getting xstats by IDs
  2021-07-24 12:33 ` [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
  2021-07-24 12:33   ` [dpdk-dev] [PATCH v4 2/2] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-07-26 10:13   ` Olivier Matz
  2021-09-28 12:01     ` Andrew Rybchenko
  1 sibling, 1 reply; 113+ messages in thread
From: Olivier Matz @ 2021-07-26 10:13 UTC (permalink / raw)
  To: Andrew Rybchenko
  Cc: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak, Ivan Ilchenko,
	stable, Andy Moreton

Hi Andrew,

Some comments below.

On Sat, Jul 24, 2021 at 03:33:13PM +0300, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Document valid combinations of input arguments in accordance with
> current implementation in ethdev.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
> ---
>  lib/ethdev/rte_ethdev.h | 32 +++++++++++++++++++-------------
>  1 file changed, 19 insertions(+), 13 deletions(-)
> 
> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
> index d2b27c351f..b14067fe7e 100644
> --- a/lib/ethdev/rte_ethdev.h
> +++ b/lib/ethdev/rte_ethdev.h
> @@ -2872,13 +2872,17 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>   * @param port_id
>   *   The port identifier of the Ethernet device.
>   * @param xstats_names
> - *   An rte_eth_xstat_name array of at least *size* elements to
> - *   be filled. If set to NULL, the function returns the required number
> - *   of elements.
> + *   Array to be filled in with names of requested device statistics.
> + *   Must not be NULL if @p ids are specified (not NULL).
>   * @param ids
> - *   IDs array given by app to retrieve specific statistics
> + *   IDs array given by app to retrieve specific statistics. May be NULL to
> + *   retrieve names of all available statistics or, if @p xstats_names is
> + *   NULL as well,  just a number of available statistics.

double spaces before "just"

"a number" -> "the number"?

>   * @param size
> - *   The size of the xstats_names array (number of elements).
> + *   If @p ids is not NULL, number of elements in the array with requested IDs
> + *   and number of elements in @p xstats_names to put names in. If @p ids is
> + *   NULL, number of elements in @p xstats_names to put all available statistics
> + *   names in.

Just a suggestion here, I feel the following description would be clearer:

  Number of elements in @p xstats_names array (if not NULL) and
  in @p ids array (if not NULL).

Shouldn't we say that it has to be 0 if both arrays are NULL?


Also, the order of arguments is not the same in comment and in
the function. I think it can make sense to align the comment
to the prototype.


>   * @return
>   *   - A positive value lower or equal to size: success. The return value
>   *     is the number of entries filled in the stats table.

Not seen in the patch, but right after this line, there is:

 *   - A positive value higher than size: error, the given statistics table
 *     is too small. The return value corresponds to the size that should
 *     be given to succeed. The entries in the table are not valid and
 *     shall not be used by the caller.

I wonder if it shouldn't be slighly reworded to remove 'error'. After
all, passing NULL arrays (and size == 0) is a valid, so the return is
not an error.


> @@ -2886,7 +2890,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>   *     is too small. The return value corresponds to the size that should
>   *     be given to succeed. The entries in the table are not valid and
>   *     shall not be used by the caller.
> - *   - A negative value on error (invalid port id).
> + *   - A negative value on error.
>   */
>  int
>  rte_eth_xstats_get_names_by_id(uint16_t port_id,
> @@ -2899,14 +2903,16 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>   * @param port_id
>   *   The port identifier of the Ethernet device.
>   * @param ids
> - *   A pointer to an ids array passed by application. This tells which
> - *   statistics values function should retrieve. This parameter
> - *   can be set to NULL if size is 0. In this case function will retrieve
> - *   all available statistics.
> + *   IDs array given by app to retrieve specific statistics. May be NULL to
> + *   retrieve all available statistics or, if @p values is NULL as well,
> + *   just a number of available statistics.
>   * @param values
> - *   A pointer to a table to be filled with device statistics values.
> + *   Array to be filled in with requested device statistics.
> + *   Must not be NULL if ids are specified (not NULL).
>   * @param size
> - *   The size of the ids array (number of elements).
> + *   If @p ids is not NULL, number of elements in the array with requested IDs
> + *   and number of elements in @p values to put statistics in. If @p ids is NULL,
> + *   number of elements in @p values to put all available statistics in.
>   * @return
>   *   - A positive value lower or equal to size: success. The return value
>   *     is the number of entries filled in the stats table.
> @@ -2914,7 +2920,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>   *     is too small. The return value corresponds to the size that should
>   *     be given to succeed. The entries in the table are not valid and
>   *     shall not be used by the caller.
> - *   - A negative value on error (invalid port id).
> + *   - A negative value on error.
>   */

Some of the comments above also apply here.

>  int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>  			     uint64_t *values, unsigned int size);
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-24 12:33   ` [dpdk-dev] [PATCH v4 2/2] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-07-26 10:13     ` Olivier Matz
  2021-09-28 12:04       ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Olivier Matz @ 2021-07-26 10:13 UTC (permalink / raw)
  To: Andrew Rybchenko
  Cc: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak, Ivan Ilchenko,
	stable, Andy Moreton

On Sat, Jul 24, 2021 at 03:33:14PM +0300, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Update xstats by IDs callbacks documentation in accordance with
> ethdev usage of these callbacks. Document valid combinations of
> input arguments to make driver implementation simpler.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
> ---
>  lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 41 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
> index 40e474aa7e..fd5b7ca550 100644
> --- a/lib/ethdev/ethdev_driver.h
> +++ b/lib/ethdev/ethdev_driver.h
> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat *stats, unsigned int n);
>  /**< @internal Get extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get extended stats of an Ethernet device.
> + *
> + * @param dev
> + *   ethdev handle of port.
> + * @param ids
> + *   IDs array to retrieve specific statistics. Must not be NULL.
> + * @param values
> + *   A pointer to a table to be filled with device statistics values.
> + *   Must not be NULL.
> + * @param n
> + *   Element count in @p ids and @p values
> + *
> + * @return
> + *   - A number of filled in stats.
> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>  				      const uint64_t *ids,
>  				      uint64_t *values,
>  				      unsigned int n);
> -/**< @internal Get extended stats of an Ethernet device. */
>  
>  /**
>   * @internal
> @@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>  /**< @internal Get names of extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get names of extended stats of an Ethernet device.
> + * For name count, set @p xstats_names and @p ids to NULL.
> + *
> + * @param dev
> + *   ethdev handle of port.
> + * @param xstats_names
> + *   An rte_eth_xstat_name array of at least *size* elements to
> + *   be filled. Can be NULL together with @p ids to retrieve number of
> + *   available statistics.
> + * @param ids
> + *   IDs array to retrieve specific statistics. Can be NULL together
> + *   with @p xstats_names to retrieve number of available statistics.
> + * @param size
> + *   Size of ids and xstats_names arrays.
> + *   Element count in @p ids and @p xstats_names

I think only the second line should be kept.

Shouldn't we also say here that size should be 0 if arrays are NULL?

> + *
> + * @return
> + *   - A number of filled in stats if both xstats_names and ids are not NULL.
> + *   - A number of available stats if both xstats_names and ids are NULL.
> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
>  	unsigned int size);
> -/**< @internal Get names of extended stats of an Ethernet device. */
>  
>  typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
>  					     uint16_t queue_id,
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v4] app/testpmd: add option to display extended statistics
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
@ 2021-08-20 13:55     ` Andrew Rybchenko
  2021-08-21  1:09       ` Ajit Khaparde
  2021-09-02 16:08       ` Ferruh Yigit
  2021-09-15 11:27     ` [dpdk-dev] [PATCH v5] " Andrew Rybchenko
  2021-10-14  9:00     ` [dpdk-dev] [PATCH v6] " Andrew Rybchenko
  2 siblings, 2 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-08-20 13:55 UTC (permalink / raw)
  To: Xiaoyun Li; +Cc: dev, David Marchand, Ivan Ilchenko

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
(i.e. 'stats-period' option or 'show port stats' interactive command) to
display specified list of extended statistics.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
v4:
    - split from patch series
    - move xstats information to rte_port structure to avoid
      extra global structure

 app/test-pmd/cmdline.c                |  55 +++++++++++++
 app/test-pmd/config.c                 |  66 ++++++++++++++++
 app/test-pmd/parameters.c             |  14 ++++
 app/test-pmd/testpmd.c                | 110 ++++++++++++++++++++++++++
 app/test-pmd/testpmd.h                |  23 ++++++
 doc/guides/testpmd_app_ug/run_app.rst |   5 ++
 6 files changed, 273 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 82253bc751..cd538ace30 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -3621,6 +3621,61 @@ cmdline_parse_inst_t cmd_stop = {
 
 /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
 
+int
+parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
+		  unsigned int *xstats_num)
+{
+	int max_names_nb, names_nb;
+	int stringlen;
+	char **names;
+	char *str;
+	int ret;
+	int i;
+
+	names = NULL;
+	str = strdup(in_str);
+	if (str == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+	stringlen = strlen(str);
+
+	for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
+		if (str[i] == ',')
+			max_names_nb++;
+	}
+
+	names = calloc(max_names_nb, sizeof(*names));
+	if (names == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
+	if (names_nb < 0) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	*xstats = calloc(names_nb, sizeof(**xstats));
+	if (*xstats == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < names_nb; i++)
+		rte_strscpy((*xstats)[i].name, names[i],
+			    sizeof((*xstats)[i].name));
+
+	*xstats_num = names_nb;
+	ret = 0;
+
+out:
+	free(names);
+	free(str);
+	return ret;
+}
+
 unsigned int
 parse_item_list(const char *str, const char *item_name, unsigned int max_items,
 		unsigned int *parsed_items, int check_unique_values)
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 31d8ba1b91..ea5b59f54f 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -173,6 +173,70 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
 	printf("%s%s", name, buf);
 }
 
+static void
+nic_xstats_display_periodic(portid_t port_id)
+{
+	struct xstat_display_info *xstats_info;
+	uint64_t *prev_values, *curr_values;
+	uint64_t diff_value, value_rate;
+	uint64_t *ids, *ids_supp;
+	struct timespec cur_time;
+	unsigned int i, i_supp;
+	size_t ids_supp_sz;
+	uint64_t diff_ns;
+	int rc;
+
+	xstats_info = &ports[port_id].xstats_info;
+
+	ids_supp_sz = xstats_info->ids_supp_sz;
+	if (xstats_display_num == 0 || ids_supp_sz == 0)
+		return;
+
+	printf("\n");
+
+	ids = xstats_info->ids;
+	ids_supp = xstats_info->ids_supp;
+	prev_values = xstats_info->prev_values;
+	curr_values = xstats_info->curr_values;
+
+	rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
+				      ids_supp_sz);
+	if (rc != (int)ids_supp_sz) {
+		fprintf(stderr, "%s: Failed to get values of %zu supported xstats for port %u - return code %d\n",
+			__func__, ids_supp_sz, port_id, rc);
+		return;
+	}
+
+	diff_ns = 0;
+	if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
+		uint64_t ns;
+
+		ns = cur_time.tv_sec * NS_PER_SEC;
+		ns += cur_time.tv_nsec;
+
+		if (xstats_info->prev_ns != 0)
+			diff_ns = ns - xstats_info->prev_ns;
+		xstats_info->prev_ns = ns;
+	}
+
+	printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
+	for (i = i_supp = 0; i < xstats_display_num; i++) {
+		if (ids[i] == XSTAT_ID_INVALID)
+			continue;
+
+		diff_value = (curr_values[i_supp] > prev_values[i]) ?
+			     (curr_values[i_supp] - prev_values[i]) : 0;
+		prev_values[i] = curr_values[i_supp];
+		value_rate = diff_ns > 0 ?
+				(double)diff_value / diff_ns * NS_PER_SEC : 0;
+
+		printf("  %-25s%12"PRIu64" %15"PRIu64"\n",
+		       xstats_display[i].name, curr_values[i_supp], value_rate);
+
+		i_supp++;
+	}
+}
+
 void
 nic_stats_display(portid_t port_id)
 {
@@ -243,6 +307,8 @@ nic_stats_display(portid_t port_id)
 	       PRIu64"          Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
 	       mpps_tx, mbps_tx * 8);
 
+	nic_xstats_display_periodic(port_id);
+
 	printf("  %s############################%s\n",
 	       nic_stats_border, nic_stats_border);
 }
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 7c13210f04..e78929795c 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -61,6 +61,9 @@ usage(char* progname)
 	       "(only if interactive is disabled).\n");
 	printf("  --stats-period=PERIOD: statistics will be shown "
 	       "every PERIOD seconds (only if interactive is disabled).\n");
+	printf("  --display-xstats xstat1[,...]: extended statistics to show. "
+	       "Used with --stats-period specified or interactive commands "
+	       "that show Rx/Tx statistics (i.e. 'show port stats').\n");
 	printf("  --nb-cores=N: set the number of forwarding cores "
 	       "(1 <= N <= %d).\n", nb_lcores);
 	printf("  --nb-ports=N: set the number of forwarding ports "
@@ -535,6 +538,7 @@ launch_args_parse(int argc, char** argv)
 #endif
 		{ "tx-first",			0, 0, 0 },
 		{ "stats-period",		1, 0, 0 },
+		{ "display-xstats",		1, 0, 0 },
 		{ "nb-cores",			1, 0, 0 },
 		{ "nb-ports",			1, 0, 0 },
 		{ "coremask",			1, 0, 0 },
@@ -692,6 +696,16 @@ launch_args_parse(int argc, char** argv)
 				stats_period = n;
 				break;
 			}
+			if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
+				char rc;
+
+				rc = parse_xstats_list(optarg, &xstats_display,
+						       &xstats_display_num);
+				if (rc != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to fill xstats to display: %d\n",
+						 rc);
+			}
 			if (!strcmp(lgopts[opt_idx].name,
 				    "eth-peers-configfile")) {
 				if (init_peer_eth_addrs(optarg) != 0)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 6cbe9ba3c8..69a6a6913c 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -208,6 +208,11 @@ uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
                                       * specified on command-line. */
 uint16_t stats_period; /**< Period to show statistics (disabled by default) */
 
+/** Extended statistics to show. */
+struct rte_eth_xstat_name *xstats_display;
+
+unsigned int xstats_display_num; /**< Size of extended statistics to show */
+
 /*
  * In container, it cannot terminate the process which running with 'stats-period'
  * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
@@ -542,6 +547,12 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
 /* Holds the registered mbuf dynamic flags names. */
 char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
 
+/** Fill helper structures for specified port to show extended statistics. */
+static void fill_display_xstats_info_for_port(portid_t pi);
+
+/** Fill helper structures for all ports to show extended statistics. */
+static void fill_display_xstats_info(void);
+
 /*
  * Helper function to check if socket is already discovered.
  * If yes, return positive value. If not, return zero.
@@ -2685,6 +2696,8 @@ start_port(portid_t pid)
 		}
 	}
 
+	fill_display_xstats_info_for_port(pid);
+
 	printf("Done\n");
 	return 0;
 }
@@ -3719,6 +3732,40 @@ init_port_dcb_config(portid_t pid,
 	return 0;
 }
 
+static int
+alloc_display_xstats_info(portid_t pi)
+{
+	uint64_t **ids = &ports[pi].xstats_info.ids;
+	uint64_t **ids_supp = &ports[pi].xstats_info.ids_supp;
+	uint64_t **prev_values = &ports[pi].xstats_info.prev_values;
+	uint64_t **curr_values = &ports[pi].xstats_info.curr_values;
+
+	if (xstats_display_num == 0)
+		return 0;
+
+	*ids = calloc(xstats_display_num, sizeof(**ids));
+	if (*ids == NULL)
+		return -ENOMEM;
+
+	*ids_supp = calloc(xstats_display_num, sizeof(**ids_supp));
+	if (*ids_supp == NULL)
+		return -ENOMEM;
+
+	*prev_values = calloc(xstats_display_num,
+			      sizeof(**prev_values));
+	if (*prev_values == NULL)
+		return -ENOMEM;
+
+	*curr_values = calloc(xstats_display_num,
+			      sizeof(**curr_values));
+	if (*curr_values == NULL)
+		return -ENOMEM;
+
+	ports[pi].xstats_info.allocated = true;
+
+	return 0;
+}
+
 static void
 init_port(void)
 {
@@ -3733,6 +3780,8 @@ init_port(void)
 				"rte_zmalloc(%d struct rte_port) failed\n",
 				RTE_MAX_ETHPORTS);
 	}
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		ports[i].xstats_info.allocated = false;
 	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
 		LIST_INIT(&ports[i].flow_tunnel_list);
 	/* Initialize ports NUMA structures */
@@ -3748,6 +3797,67 @@ force_quit(void)
 	prompt_exit();
 }
 
+static void
+fill_display_xstats_info_for_port(portid_t pi)
+{
+	unsigned int stat, stat_supp;
+	uint64_t *ids, *ids_supp;
+	const char *xstat_name;
+	struct rte_port *port;
+	int rc;
+
+	if (xstats_display_num == 0)
+		return;
+
+	if (pi == (portid_t)RTE_PORT_ALL) {
+		fill_display_xstats_info();
+		return;
+	}
+
+	port = &ports[pi];
+	if (port->port_status != RTE_PORT_STARTED)
+		return;
+
+	if (!port->xstats_info.allocated && alloc_display_xstats_info(pi) != 0)
+		rte_exit(EXIT_FAILURE,
+			 "Failed to allocate xstats display memory\n");
+
+	ids = port->xstats_info.ids;
+	ids_supp = port->xstats_info.ids_supp;
+
+	for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
+		xstat_name = xstats_display[stat].name;
+
+		rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
+						   ids + stat);
+		if (rc != 0) {
+			ids[stat] = XSTAT_ID_INVALID;
+			fprintf(stderr, "No xstat '%s' on port %u - skip it\n",
+				xstat_name, pi);
+			continue;
+		}
+		ids_supp[stat_supp++] = ids[stat];
+	}
+
+	port->xstats_info.ids_supp_sz = stat_supp;
+}
+
+static void
+fill_display_xstats_info(void)
+{
+	portid_t pi;
+
+	if (xstats_display_num == 0)
+		return;
+
+	RTE_ETH_FOREACH_DEV(pi) {
+		if (pi == (portid_t)RTE_PORT_ALL)
+			continue;
+
+		fill_display_xstats_info_for_port(pi);
+	}
+}
+
 static void
 print_stats(void)
 {
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 16a3598e48..68f182944b 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -195,6 +195,19 @@ struct tunnel_ops {
 	uint32_t items:1;
 };
 
+/** Information for an extended statistics to show. */
+struct xstat_display_info {
+	/** IDs of xstats in the order of xstats_display */
+	uint64_t *ids;
+	/** Supported xstats IDs in the order of xstats_display */
+	uint64_t *ids_supp;
+	size_t   ids_supp_sz;
+	uint64_t *prev_values;
+	uint64_t *curr_values;
+	uint64_t prev_ns;
+	bool	 allocated;
+};
+
 /**
  * The data structure associated with each port.
  */
@@ -234,6 +247,7 @@ struct rte_port {
 	/**< dynamic flags. */
 	uint64_t		mbuf_dynf;
 	const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1];
+	struct xstat_display_info xstats_info;
 };
 
 /**
@@ -434,6 +448,13 @@ extern uint32_t param_total_num_mbufs;
 
 extern uint16_t stats_period;
 
+extern struct rte_eth_xstat_name *xstats_display;
+extern unsigned int xstats_display_num;
+
+#define XSTAT_ID_INVALID UINT64_MAX
+
+extern struct xstat_display_info xstats_per_port[];
+
 extern uint16_t hairpin_mode;
 
 #ifdef RTE_LIB_LATENCYSTATS
@@ -766,6 +787,8 @@ inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx)
 unsigned int parse_item_list(const char *str, const char *item_name,
 			unsigned int max_items,
 			unsigned int *parsed_items, int check_unique_values);
+int parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
+		      unsigned int *xstats_num);
 void launch_args_parse(int argc, char** argv);
 void cmdline_read_from_file(const char *filename);
 void prompt(void);
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index 6061674239..d77afeb633 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -56,6 +56,11 @@ The command line options are:
     Display statistics every PERIOD seconds, if interactive mode is disabled.
     The default value is 0, which means that the statistics will not be displayed.
 
+*   ``--display-xstats xstat1[,...]``
+
+    Display extended statistics every PERIOD seconds as specified in ``--stats-period``
+    or when used with interactive commands that show Rx/Tx statistics (i.e. 'show port stats').
+
 *   ``--nb-cores=N``
 
     Set the number of forwarding cores,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4] app/testpmd: add option to display extended statistics
  2021-08-20 13:55     ` [dpdk-dev] [PATCH v4] " Andrew Rybchenko
@ 2021-08-21  1:09       ` Ajit Khaparde
  2021-08-23  9:59         ` Andrew Rybchenko
  2021-09-02 16:08       ` Ferruh Yigit
  1 sibling, 1 reply; 113+ messages in thread
From: Ajit Khaparde @ 2021-08-21  1:09 UTC (permalink / raw)
  To: Andrew Rybchenko; +Cc: Xiaoyun Li, dpdk-dev, David Marchand, Ivan Ilchenko

[-- Attachment #1: Type: text/plain, Size: 604 bytes --]

On Fri, Aug 20, 2021 at 6:55 AM Andrew Rybchenko
<andrew.rybchenko@oktetlabs.ru> wrote:
>
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>
> Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
> (i.e. 'stats-period' option or 'show port stats' interactive command) to
> display specified list of extended statistics.
>
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>

Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
A pretty good enhancement. And for what it's worth, I tested it as well.
>
>

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4] app/testpmd: add option to display extended statistics
  2021-08-21  1:09       ` Ajit Khaparde
@ 2021-08-23  9:59         ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-08-23  9:59 UTC (permalink / raw)
  To: Ajit Khaparde; +Cc: Xiaoyun Li, dpdk-dev, David Marchand, Ivan Ilchenko

On 8/21/21 4:09 AM, Ajit Khaparde wrote:
> On Fri, Aug 20, 2021 at 6:55 AM Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru> wrote:
>>
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
>> (i.e. 'stats-period' option or 'show port stats' interactive command) to
>> display specified list of extended statistics.
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> 
> Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
> A pretty good enhancement. And for what it's worth, I tested it as well.

Ajit, many thanks for feedback.



^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4] app/testpmd: add option to display extended statistics
  2021-08-20 13:55     ` [dpdk-dev] [PATCH v4] " Andrew Rybchenko
  2021-08-21  1:09       ` Ajit Khaparde
@ 2021-09-02 16:08       ` Ferruh Yigit
  2021-09-15 10:25         ` Ivan Ilchenko
  1 sibling, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-09-02 16:08 UTC (permalink / raw)
  To: Andrew Rybchenko, Xiaoyun Li
  Cc: dev, David Marchand, Ivan Ilchenko, Ciara Power

On 8/20/2021 2:55 PM, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
> (i.e. 'stats-period' option or 'show port stats' interactive command) to
> display specified list of extended statistics.
> 

Overall +1 to the feature.

Just a reminder that same thing can be done via telemetry, custom xstat values
can be retrieved from any dpdk application (including testpmd) by a telemetry
client. cc'ed Ciara if more detail is required.

> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> ---
> v4:
>     - split from patch series
>     - move xstats information to rte_port structure to avoid
>       extra global structure
> 
>  app/test-pmd/cmdline.c                |  55 +++++++++++++
>  app/test-pmd/config.c                 |  66 ++++++++++++++++
>  app/test-pmd/parameters.c             |  14 ++++
>  app/test-pmd/testpmd.c                | 110 ++++++++++++++++++++++++++
>  app/test-pmd/testpmd.h                |  23 ++++++
>  doc/guides/testpmd_app_ug/run_app.rst |   5 ++
>  6 files changed, 273 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index 82253bc751..cd538ace30 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -3621,6 +3621,61 @@ cmdline_parse_inst_t cmd_stop = {
>  
>  /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
>  

Inserting the below function between the above comment and its function makes
the comment wrong.
This is in file 'cmdline.c', which has command line functions and static
functions that are needed for the command.
Below function is to parse the application parameter, and called by a function
in 'parameters.c'. Since that is the only consumer of this function, why not
move this function to 'parameters.c' file and make it static?

> +int
> +parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
> +		  unsigned int *xstats_num)
> +{
> +	int max_names_nb, names_nb;
> +	int stringlen;
> +	char **names;
> +	char *str;
> +	int ret;
> +	int i;
> +
> +	names = NULL;
> +	str = strdup(in_str);

'in_str' is an user input, it is coming from 'lgopts()', can you please double
check if it is guaranteed that it will be null terminated?

> +	if (str == NULL) {
> +		ret = ENOMEM;

Please return negative error values.
Only net/sfc has positive error values, since that is the syntax in its base
code and we let to keep the syntax, but for rest of the DPDK please use negative
error values.

> +		goto out;
> +	}
> +	stringlen = strlen(str);
> +> +	for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
> +		if (str[i] == ',')
> +			max_names_nb++;
> +	}
> +
> +	names = calloc(max_names_nb, sizeof(*names));
> +	if (names == NULL) {
> +		ret = ENOMEM;
> +		goto out;
> +	}
> +
> +	names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
> +	if (names_nb < 0) {
> +		ret = EINVAL;
> +		goto out;
> +	}

Should we check the length of each 'names' to prevent unnecessary allocation for
the cause user provided something like --display-xstats ',,,,,'?
I think this check can be done during copy below.

> +
> +	*xstats = calloc(names_nb, sizeof(**xstats));
> +	if (*xstats == NULL) {
> +		ret = ENOMEM;
> +		goto out;
> +	}
> +

When and how 'xstats' ('xstats_display') is freed?

> +	for (i = 0; i < names_nb; i++)
> +		rte_strscpy((*xstats)[i].name, names[i],
> +			    sizeof((*xstats)[i].name));
> +
> +	*xstats_num = names_nb;
> +	ret = 0;
> +
> +out:
> +	free(names);
> +	free(str);
> +	return ret;
> +}
> +
>  unsigned int
>  parse_item_list(const char *str, const char *item_name, unsigned int max_items,
>  		unsigned int *parsed_items, int check_unique_values)
> diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
> index 31d8ba1b91..ea5b59f54f 100644
> --- a/app/test-pmd/config.c
> +++ b/app/test-pmd/config.c
> @@ -173,6 +173,70 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
>  	printf("%s%s", name, buf);
>  }
>  
> +static void
> +nic_xstats_display_periodic(portid_t port_id)
> +{
> +	struct xstat_display_info *xstats_info;
> +	uint64_t *prev_values, *curr_values;
> +	uint64_t diff_value, value_rate;
> +	uint64_t *ids, *ids_supp;
> +	struct timespec cur_time;
> +	unsigned int i, i_supp;
> +	size_t ids_supp_sz;
> +	uint64_t diff_ns;
> +	int rc;
> +
> +	xstats_info = &ports[port_id].xstats_info;
> +
> +	ids_supp_sz = xstats_info->ids_supp_sz;
> +	if (xstats_display_num == 0 || ids_supp_sz == 0)
> +		return;
> +
> +	printf("\n");
> +
> +	ids = xstats_info->ids;
> +	ids_supp = xstats_info->ids_supp;
> +	prev_values = xstats_info->prev_values;
> +	curr_values = xstats_info->curr_values;
> +
> +	rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
> +				      ids_supp_sz);
> +	if (rc != (int)ids_supp_sz) {
> +		fprintf(stderr, "%s: Failed to get values of %zu supported xstats for port %u - return code %d\n",

Can you break the line after 'stderr, ' to reduce the line length?

Also I think you can drop 'supported' word in this context, because you already
know all requested xstat is supported and retrieving it is failing, so for this
log it is failing to get values of xstat.

> +			__func__, ids_supp_sz, port_id, rc);

Not sure if __func__is required here?

> +		return;
> +	}
> +
> +	diff_ns = 0;
> +	if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
> +		uint64_t ns;
> +
> +		ns = cur_time.tv_sec * NS_PER_SEC;
> +		ns += cur_time.tv_nsec;
> +
> +		if (xstats_info->prev_ns != 0)
> +			diff_ns = ns - xstats_info->prev_ns;
> +		xstats_info->prev_ns = ns;
> +	}
> +
> +	printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
> +	for (i = i_supp = 0; i < xstats_display_num; i++) {
> +		if (ids[i] == XSTAT_ID_INVALID)
> +			continue;
> +
> +		diff_value = (curr_values[i_supp] > prev_values[i]) ?
> +			     (curr_values[i_supp] - prev_values[i]) : 0;
> +		prev_values[i] = curr_values[i_supp];
> +		value_rate = diff_ns > 0 ?
> +				(double)diff_value / diff_ns * NS_PER_SEC : 0;
> +
> +		printf("  %-25s%12"PRIu64" %15"PRIu64"\n",
> +		       xstats_display[i].name, curr_values[i_supp], value_rate);
> +
> +		i_supp++;
> +	}
> +}
> +
>  void
>  nic_stats_display(portid_t port_id)
>  {
> @@ -243,6 +307,8 @@ nic_stats_display(portid_t port_id)
>  	       PRIu64"          Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
>  	       mpps_tx, mbps_tx * 8);
>  
> +	nic_xstats_display_periodic(port_id);
> +

What do you think to call the function if 'xstats_display_num > 0'? I can see
there is already check in the function but I assume '--display-xstats' won't be
set for majority of use cases, and checking it in advance can prevent
unnecessary function call.

>  	printf("  %s############################%s\n",
>  	       nic_stats_border, nic_stats_border);
>  }
> diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
> index 7c13210f04..e78929795c 100644
> --- a/app/test-pmd/parameters.c
> +++ b/app/test-pmd/parameters.c
> @@ -61,6 +61,9 @@ usage(char* progname)
>  	       "(only if interactive is disabled).\n");
>  	printf("  --stats-period=PERIOD: statistics will be shown "
>  	       "every PERIOD seconds (only if interactive is disabled).\n");
> +	printf("  --display-xstats xstat1[,...]: extended statistics to show. "
> +	       "Used with --stats-period specified or interactive commands "
> +	       "that show Rx/Tx statistics (i.e. 'show port stats').\n");
>  	printf("  --nb-cores=N: set the number of forwarding cores "
>  	       "(1 <= N <= %d).\n", nb_lcores);
>  	printf("  --nb-ports=N: set the number of forwarding ports "
> @@ -535,6 +538,7 @@ launch_args_parse(int argc, char** argv)
>  #endif
>  		{ "tx-first",			0, 0, 0 },
>  		{ "stats-period",		1, 0, 0 },
> +		{ "display-xstats",		1, 0, 0 },
>  		{ "nb-cores",			1, 0, 0 },
>  		{ "nb-ports",			1, 0, 0 },
>  		{ "coremask",			1, 0, 0 },
> @@ -692,6 +696,16 @@ launch_args_parse(int argc, char** argv)
>  				stats_period = n;
>  				break;
>  			}
> +			if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
> +				char rc;
> +
> +				rc = parse_xstats_list(optarg, &xstats_display,
> +						       &xstats_display_num);
> +				if (rc != 0)
> +					rte_exit(EXIT_FAILURE,
> +						 "Failed to fill xstats to display: %d\n",

What about updating the error message something like: 'failed to parse
display-xstats argument'

> +						 rc);
> +			}
>  			if (!strcmp(lgopts[opt_idx].name,
>  				    "eth-peers-configfile")) {
>  				if (init_peer_eth_addrs(optarg) != 0)
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> index 6cbe9ba3c8..69a6a6913c 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -208,6 +208,11 @@ uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
>                                        * specified on command-line. */
>  uint16_t stats_period; /**< Period to show statistics (disabled by default) */
>  
> +/** Extended statistics to show. */
> +struct rte_eth_xstat_name *xstats_display;
> +
> +unsigned int xstats_display_num; /**< Size of extended statistics to show */
> +

what about renaming 'num' as 'size'? no strong opinion.

>  /*
>   * In container, it cannot terminate the process which running with 'stats-period'
>   * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
> @@ -542,6 +547,12 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
>  /* Holds the registered mbuf dynamic flags names. */
>  char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
>  
> +/** Fill helper structures for specified port to show extended statistics. */
> +static void fill_display_xstats_info_for_port(portid_t pi);
> +

Can you please eliminate need of function declaration by rearranging the
placement of static function?

> +/** Fill helper structures for all ports to show extended statistics. */
> +static void fill_display_xstats_info(void);
> +

This declaration seems can't be eliminated because of cross call (cyclic
dependency) between functions.

>  /*
>   * Helper function to check if socket is already discovered.
>   * If yes, return positive value. If not, return zero.
> @@ -2685,6 +2696,8 @@ start_port(portid_t pid)
>  		}
>  	}
>  
> +	fill_display_xstats_info_for_port(pid);
> +

Why do we need to do the 'fill' in each start?

Let's assume we are in the interactive mode and on each stop/start, the
'xstat_display_info' will filled again with exact same values, because names get
via application parameter and they won't change.

Will it work to call this function in port init?

>  	printf("Done\n");
>  	return 0;
>  }
> @@ -3719,6 +3732,40 @@ init_port_dcb_config(portid_t pid,
>  	return 0;
>  }
>  
> +static int
> +alloc_display_xstats_info(portid_t pi)

both 'xstats_display' and 'display_xstats' wording seems used for this feature,
I suggest picking one and stick to it.

And I am not sure about 'xstats_display', there are other commands in testpmd
that displays the 'xstats', but not sure how to rename it.

> +{
> +	uint64_t **ids = &ports[pi].xstats_info.ids;
> +	uint64_t **ids_supp = &ports[pi].xstats_info.ids_supp;
> +	uint64_t **prev_values = &ports[pi].xstats_info.prev_values;
> +	uint64_t **curr_values = &ports[pi].xstats_info.curr_values;
> +
> +	if (xstats_display_num == 0)
> +		return 0;
> +
> +	*ids = calloc(xstats_display_num, sizeof(**ids));
> +	if (*ids == NULL)
> +		return -ENOMEM;
> +
> +	*ids_supp = calloc(xstats_display_num, sizeof(**ids_supp));
> +	if (*ids_supp == NULL)
> +		return -ENOMEM;
> +
> +	*prev_values = calloc(xstats_display_num,
> +			      sizeof(**prev_values));
> +	if (*prev_values == NULL)
> +		return -ENOMEM;
> +
> +	*curr_values = calloc(xstats_display_num,
> +			      sizeof(**curr_values));
> +	if (*curr_values == NULL)
> +		return -ENOMEM;
> +
> +	ports[pi].xstats_info.allocated = true;
> +

We should free these memory at some point ...

> +	return 0;
> +}
> +
>  static void
>  init_port(void)
>  {
> @@ -3733,6 +3780,8 @@ init_port(void)
>  				"rte_zmalloc(%d struct rte_port) failed\n",
>  				RTE_MAX_ETHPORTS);
>  	}
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
> +		ports[i].xstats_info.allocated = false;
>  	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
>  		LIST_INIT(&ports[i].flow_tunnel_list);
>  	/* Initialize ports NUMA structures */
> @@ -3748,6 +3797,67 @@ force_quit(void)
>  	prompt_exit();
>  }
>  
> +static void
> +fill_display_xstats_info_for_port(portid_t pi)
> +{
> +	unsigned int stat, stat_supp;
> +	uint64_t *ids, *ids_supp;
> +	const char *xstat_name;
> +	struct rte_port *port;
> +	int rc;
> +
> +	if (xstats_display_num == 0)
> +		return;
> +
> +	if (pi == (portid_t)RTE_PORT_ALL) {
> +		fill_display_xstats_info();
> +		return;
> +	}
> +
> +	port = &ports[pi];
> +	if (port->port_status != RTE_PORT_STARTED)

Why this requirement? Why port has to be started to get the ids of xstat names?

> +		return;
> +
> +	if (!port->xstats_info.allocated && alloc_display_xstats_info(pi) != 0)
> +		rte_exit(EXIT_FAILURE,
> +			 "Failed to allocate xstats display memory\n");
> +
> +	ids = port->xstats_info.ids;
> +	ids_supp = port->xstats_info.ids_supp;
> +
> +	for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
> +		xstat_name = xstats_display[stat].name;
> +
> +		rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
> +						   ids + stat);
> +		if (rc != 0) {
> +			ids[stat] = XSTAT_ID_INVALID;
> +			fprintf(stderr, "No xstat '%s' on port %u - skip it\n",
> +				xstat_name, pi);
> +			continue;
> +		}
> +		ids_supp[stat_supp++] = ids[stat];
> +	}
> +
> +	port->xstats_info.ids_supp_sz = stat_supp;
> +}
> +
> +static void
> +fill_display_xstats_info(void)
> +{
> +	portid_t pi;
> +
> +	if (xstats_display_num == 0)
> +		return;
> +
> +	RTE_ETH_FOREACH_DEV(pi) {
> +		if (pi == (portid_t)RTE_PORT_ALL)
> +			continue;

Do we really need this check? Can testpmd created more than 'RTE_PORT_ALL' port?

> +
> +		fill_display_xstats_info_for_port(pi);
> +	}
> +}
> +
>  static void
>  print_stats(void)
>  {
> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
> index 16a3598e48..68f182944b 100644
> --- a/app/test-pmd/testpmd.h
> +++ b/app/test-pmd/testpmd.h
> @@ -195,6 +195,19 @@ struct tunnel_ops {
>  	uint32_t items:1;
>  };
>  
> +/** Information for an extended statistics to show. */
> +struct xstat_display_info {
> +	/** IDs of xstats in the order of xstats_display */
> +	uint64_t *ids;

I think we can drop 'ids' and just keep 'ids_supp', please see below comment on
'XSTAT_ID_INVALID'.

> +	/** Supported xstats IDs in the order of xstats_display */
> +	uint64_t *ids_supp;
> +	size_t   ids_supp_sz;
> +	uint64_t *prev_values;
> +	uint64_t *curr_values;
> +	uint64_t prev_ns;
> +	bool	 allocated;
> +};
> +
>  /**
>   * The data structure associated with each port.
>   */
> @@ -234,6 +247,7 @@ struct rte_port {
>  	/**< dynamic flags. */
>  	uint64_t		mbuf_dynf;
>  	const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1];
> +	struct xstat_display_info xstats_info;
>  };
>  
>  /**
> @@ -434,6 +448,13 @@ extern uint32_t param_total_num_mbufs;
>  
>  extern uint16_t stats_period;
>  
> +extern struct rte_eth_xstat_name *xstats_display;
> +extern unsigned int xstats_display_num;
> +
> +#define XSTAT_ID_INVALID UINT64_MAX

Why you need this flag? Instead marking invalid xstats, why not just save the
valid one and ignore invalid ones?
Briefly, in 'xstat_display_info', drop the 'ids' and just keep 'ids_supp'.

> +
> +extern struct xstat_display_info xstats_per_port[];
> +

Is 'xstats_per_port' residue of previous implementations? It seems it is not needed.

>  extern uint16_t hairpin_mode;
>  
>  #ifdef RTE_LIB_LATENCYSTATS
> @@ -766,6 +787,8 @@ inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx)
>  unsigned int parse_item_list(const char *str, const char *item_name,
>  			unsigned int max_items,
>  			unsigned int *parsed_items, int check_unique_values);
> +int parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
> +		      unsigned int *xstats_num);
>  void launch_args_parse(int argc, char** argv);
>  void cmdline_read_from_file(const char *filename);
>  void prompt(void);
> diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
> index 6061674239..d77afeb633 100644
> --- a/doc/guides/testpmd_app_ug/run_app.rst
> +++ b/doc/guides/testpmd_app_ug/run_app.rst
> @@ -56,6 +56,11 @@ The command line options are:
>      Display statistics every PERIOD seconds, if interactive mode is disabled.
>      The default value is 0, which means that the statistics will not be displayed.
>  
> +*   ``--display-xstats xstat1[,...]``
> +
> +    Display extended statistics every PERIOD seconds as specified in ``--stats-period``
> +    or when used with interactive commands that show Rx/Tx statistics (i.e. 'show port stats').
> +

Can you please highlight 'xstat1' is the xstat name, to prevent it to be
confused with xstat id?
Also can you please highlight that list should be comma separated, the short
'xstat1[,...]' usage implies this already but better to say it explicitly in the
document.

>  *   ``--nb-cores=N``
>  
>      Set the number of forwarding cores,
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4] app/testpmd: add option to display extended statistics
  2021-09-02 16:08       ` Ferruh Yigit
@ 2021-09-15 10:25         ` Ivan Ilchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Ivan Ilchenko @ 2021-09-15 10:25 UTC (permalink / raw)
  To: Ferruh Yigit, Andrew Rybchenko, Xiaoyun Li
  Cc: dev, David Marchand, Ciara Power


On 9/2/21 7:08 PM, Ferruh Yigit wrote:
> On 8/20/2021 2:55 PM, Andrew Rybchenko wrote:
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
>> (i.e. 'stats-period' option or 'show port stats' interactive command) to
>> display specified list of extended statistics.
>>
> Overall +1 to the feature.
>
> Just a reminder that same thing can be done via telemetry, custom xstat values
> can be retrieved from any dpdk application (including testpmd) by a telemetry
> client. cc'ed Ciara if more detail is required.
>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>> ---
>> v4:
>>      - split from patch series
>>      - move xstats information to rte_port structure to avoid
>>        extra global structure
>>
>>   app/test-pmd/cmdline.c                |  55 +++++++++++++
>>   app/test-pmd/config.c                 |  66 ++++++++++++++++
>>   app/test-pmd/parameters.c             |  14 ++++
>>   app/test-pmd/testpmd.c                | 110 ++++++++++++++++++++++++++
>>   app/test-pmd/testpmd.h                |  23 ++++++
>>   doc/guides/testpmd_app_ug/run_app.rst |   5 ++
>>   6 files changed, 273 insertions(+)
>>
>> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
>> index 82253bc751..cd538ace30 100644
>> --- a/app/test-pmd/cmdline.c
>> +++ b/app/test-pmd/cmdline.c
>> @@ -3621,6 +3621,61 @@ cmdline_parse_inst_t cmd_stop = {
>>   
>>   /* *** SET CORELIST and PORTLIST CONFIGURATION *** */
>>   
> Inserting the below function between the above comment and its function makes
> the comment wrong.
> This is in file 'cmdline.c', which has command line functions and static
> functions that are needed for the command.
> Below function is to parse the application parameter, and called by a function
> in 'parameters.c'. Since that is the only consumer of this function, why not
> move this function to 'parameters.c' file and make it static?
It will be done in the next version.
>> +int
>> +parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
>> +		  unsigned int *xstats_num)
>> +{
>> +	int max_names_nb, names_nb;
>> +	int stringlen;
>> +	char **names;
>> +	char *str;
>> +	int ret;
>> +	int i;
>> +
>> +	names = NULL;
>> +	str = strdup(in_str);
> 'in_str' is an user input, it is coming from 'lgopts()', can you please double
> check if it is guaranteed that it will be null terminated?
optarg points to argv that's guaranteed to be null terminated.
>
>> +	if (str == NULL) {
>> +		ret = ENOMEM;
> Please return negative error values.
> Only net/sfc has positive error values, since that is the syntax in its base
> code and we let to keep the syntax, but for rest of the DPDK please use negative
> error values.
>
>> +		goto out;
>> +	}
>> +	stringlen = strlen(str);
>> +> +	for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
>> +		if (str[i] == ',')
>> +			max_names_nb++;
>> +	}
>> +
>> +	names = calloc(max_names_nb, sizeof(*names));
>> +	if (names == NULL) {
>> +		ret = ENOMEM;
>> +		goto out;
>> +	}
>> +
>> +	names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
>> +	if (names_nb < 0) {
>> +		ret = EINVAL;
>> +		goto out;
>> +	}
> Should we check the length of each 'names' to prevent unnecessary allocation for
> the cause user provided something like --display-xstats ',,,,,'?
> I think this check can be done during copy below.
It's good to have, will be done in the next version.
>
>> +
>> +	*xstats = calloc(names_nb, sizeof(**xstats));
>> +	if (*xstats == NULL) {
>> +		ret = ENOMEM;
>> +		goto out;
>> +	}
>> +
> When and how 'xstats' ('xstats_display') is freed?
I'll add free in the next version.
>
>> +	for (i = 0; i < names_nb; i++)
>> +		rte_strscpy((*xstats)[i].name, names[i],
>> +			    sizeof((*xstats)[i].name));
>> +
>> +	*xstats_num = names_nb;
>> +	ret = 0;
>> +
>> +out:
>> +	free(names);
>> +	free(str);
>> +	return ret;
>> +}
>> +
>>   unsigned int
>>   parse_item_list(const char *str, const char *item_name, unsigned int max_items,
>>   		unsigned int *parsed_items, int check_unique_values)
>> diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
>> index 31d8ba1b91..ea5b59f54f 100644
>> --- a/app/test-pmd/config.c
>> +++ b/app/test-pmd/config.c
>> @@ -173,6 +173,70 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
>>   	printf("%s%s", name, buf);
>>   }
>>   
>> +static void
>> +nic_xstats_display_periodic(portid_t port_id)
>> +{
>> +	struct xstat_display_info *xstats_info;
>> +	uint64_t *prev_values, *curr_values;
>> +	uint64_t diff_value, value_rate;
>> +	uint64_t *ids, *ids_supp;
>> +	struct timespec cur_time;
>> +	unsigned int i, i_supp;
>> +	size_t ids_supp_sz;
>> +	uint64_t diff_ns;
>> +	int rc;
>> +
>> +	xstats_info = &ports[port_id].xstats_info;
>> +
>> +	ids_supp_sz = xstats_info->ids_supp_sz;
>> +	if (xstats_display_num == 0 || ids_supp_sz == 0)
>> +		return;
>> +
>> +	printf("\n");
>> +
>> +	ids = xstats_info->ids;
>> +	ids_supp = xstats_info->ids_supp;
>> +	prev_values = xstats_info->prev_values;
>> +	curr_values = xstats_info->curr_values;
>> +
>> +	rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
>> +				      ids_supp_sz);
>> +	if (rc != (int)ids_supp_sz) {
>> +		fprintf(stderr, "%s: Failed to get values of %zu supported xstats for port %u - return code %d\n",
> Can you break the line after 'stderr, ' to reduce the line length?
>
> Also I think you can drop 'supported' word in this context, because you already
> know all requested xstat is supported and retrieving it is failing, so for this
> log it is failing to get values of xstat.
>
>> +			__func__, ids_supp_sz, port_id, rc);
> Not sure if __func__is required here?
>
>> +		return;
>> +	}
>> +
>> +	diff_ns = 0;
>> +	if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
>> +		uint64_t ns;
>> +
>> +		ns = cur_time.tv_sec * NS_PER_SEC;
>> +		ns += cur_time.tv_nsec;
>> +
>> +		if (xstats_info->prev_ns != 0)
>> +			diff_ns = ns - xstats_info->prev_ns;
>> +		xstats_info->prev_ns = ns;
>> +	}
>> +
>> +	printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
>> +	for (i = i_supp = 0; i < xstats_display_num; i++) {
>> +		if (ids[i] == XSTAT_ID_INVALID)
>> +			continue;
>> +
>> +		diff_value = (curr_values[i_supp] > prev_values[i]) ?
>> +			     (curr_values[i_supp] - prev_values[i]) : 0;
>> +		prev_values[i] = curr_values[i_supp];
>> +		value_rate = diff_ns > 0 ?
>> +				(double)diff_value / diff_ns * NS_PER_SEC : 0;
>> +
>> +		printf("  %-25s%12"PRIu64" %15"PRIu64"\n",
>> +		       xstats_display[i].name, curr_values[i_supp], value_rate);
>> +
>> +		i_supp++;
>> +	}
>> +}
>> +
>>   void
>>   nic_stats_display(portid_t port_id)
>>   {
>> @@ -243,6 +307,8 @@ nic_stats_display(portid_t port_id)
>>   	       PRIu64"          Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
>>   	       mpps_tx, mbps_tx * 8);
>>   
>> +	nic_xstats_display_periodic(port_id);
>> +
> What do you think to call the function if 'xstats_display_num > 0'? I can see
> there is already check in the function but I assume '--display-xstats' won't be
> set for majority of use cases, and checking it in advance can prevent
> unnecessary function call.
Yes, it would be better.
>
>>   	printf("  %s############################%s\n",
>>   	       nic_stats_border, nic_stats_border);
>>   }
>> diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
>> index 7c13210f04..e78929795c 100644
>> --- a/app/test-pmd/parameters.c
>> +++ b/app/test-pmd/parameters.c
>> @@ -61,6 +61,9 @@ usage(char* progname)
>>   	       "(only if interactive is disabled).\n");
>>   	printf("  --stats-period=PERIOD: statistics will be shown "
>>   	       "every PERIOD seconds (only if interactive is disabled).\n");
>> +	printf("  --display-xstats xstat1[,...]: extended statistics to show. "
>> +	       "Used with --stats-period specified or interactive commands "
>> +	       "that show Rx/Tx statistics (i.e. 'show port stats').\n");
>>   	printf("  --nb-cores=N: set the number of forwarding cores "
>>   	       "(1 <= N <= %d).\n", nb_lcores);
>>   	printf("  --nb-ports=N: set the number of forwarding ports "
>> @@ -535,6 +538,7 @@ launch_args_parse(int argc, char** argv)
>>   #endif
>>   		{ "tx-first",			0, 0, 0 },
>>   		{ "stats-period",		1, 0, 0 },
>> +		{ "display-xstats",		1, 0, 0 },
>>   		{ "nb-cores",			1, 0, 0 },
>>   		{ "nb-ports",			1, 0, 0 },
>>   		{ "coremask",			1, 0, 0 },
>> @@ -692,6 +696,16 @@ launch_args_parse(int argc, char** argv)
>>   				stats_period = n;
>>   				break;
>>   			}
>> +			if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
>> +				char rc;
>> +
>> +				rc = parse_xstats_list(optarg, &xstats_display,
>> +						       &xstats_display_num);
>> +				if (rc != 0)
>> +					rte_exit(EXIT_FAILURE,
>> +						 "Failed to fill xstats to display: %d\n",
> What about updating the error message something like: 'failed to parse
> display-xstats argument'
>
>> +						 rc);
>> +			}
>>   			if (!strcmp(lgopts[opt_idx].name,
>>   				    "eth-peers-configfile")) {
>>   				if (init_peer_eth_addrs(optarg) != 0)
>> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
>> index 6cbe9ba3c8..69a6a6913c 100644
>> --- a/app/test-pmd/testpmd.c
>> +++ b/app/test-pmd/testpmd.c
>> @@ -208,6 +208,11 @@ uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
>>                                         * specified on command-line. */
>>   uint16_t stats_period; /**< Period to show statistics (disabled by default) */
>>   
>> +/** Extended statistics to show. */
>> +struct rte_eth_xstat_name *xstats_display;
>> +
>> +unsigned int xstats_display_num; /**< Size of extended statistics to show */
>> +
> what about renaming 'num' as 'size'? no strong opinion.
>
>>   /*
>>    * In container, it cannot terminate the process which running with 'stats-period'
>>    * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
>> @@ -542,6 +547,12 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
>>   /* Holds the registered mbuf dynamic flags names. */
>>   char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
>>   
>> +/** Fill helper structures for specified port to show extended statistics. */
>> +static void fill_display_xstats_info_for_port(portid_t pi);
>> +
> Can you please eliminate need of function declaration by rearranging the
> placement of static function?
>
>> +/** Fill helper structures for all ports to show extended statistics. */
>> +static void fill_display_xstats_info(void);
>> +
> This declaration seems can't be eliminated because of cross call (cyclic
> dependency) between functions.
I'll do it in the next version.
>
>>   /*
>>    * Helper function to check if socket is already discovered.
>>    * If yes, return positive value. If not, return zero.
>> @@ -2685,6 +2696,8 @@ start_port(portid_t pid)
>>   		}
>>   	}
>>   
>> +	fill_display_xstats_info_for_port(pid);
>> +
> Why do we need to do the 'fill' in each start?
>
> Let's assume we are in the interactive mode and on each stop/start, the
> 'xstat_display_info' will filled again with exact same values, because names get
> via application parameter and they won't change.
>
> Will it work to call this function in port init?
Device configuration may change in stopped state. So, it is just safer 
to resync on start.
>
>>   	printf("Done\n");
>>   	return 0;
>>   }
>> @@ -3719,6 +3732,40 @@ init_port_dcb_config(portid_t pid,
>>   	return 0;
>>   }
>>   
>> +static int
>> +alloc_display_xstats_info(portid_t pi)
> both 'xstats_display' and 'display_xstats' wording seems used for this feature,
> I suggest picking one and stick to it.
>
> And I am not sure about 'xstats_display', there are other commands in testpmd
> that displays the 'xstats', but not sure how to rename it.
Let's stick to 'xstats_display' then.
>> +{
>> +	uint64_t **ids = &ports[pi].xstats_info.ids;
>> +	uint64_t **ids_supp = &ports[pi].xstats_info.ids_supp;
>> +	uint64_t **prev_values = &ports[pi].xstats_info.prev_values;
>> +	uint64_t **curr_values = &ports[pi].xstats_info.curr_values;
>> +
>> +	if (xstats_display_num == 0)
>> +		return 0;
>> +
>> +	*ids = calloc(xstats_display_num, sizeof(**ids));
>> +	if (*ids == NULL)
>> +		return -ENOMEM;
>> +
>> +	*ids_supp = calloc(xstats_display_num, sizeof(**ids_supp));
>> +	if (*ids_supp == NULL)
>> +		return -ENOMEM;
>> +
>> +	*prev_values = calloc(xstats_display_num,
>> +			      sizeof(**prev_values));
>> +	if (*prev_values == NULL)
>> +		return -ENOMEM;
>> +
>> +	*curr_values = calloc(xstats_display_num,
>> +			      sizeof(**curr_values));
>> +	if (*curr_values == NULL)
>> +		return -ENOMEM;
>> +
>> +	ports[pi].xstats_info.allocated = true;
>> +
> We should free these memory at some point ...
I'll add free in the next version.
>
>> +	return 0;
>> +}
>> +
>>   static void
>>   init_port(void)
>>   {
>> @@ -3733,6 +3780,8 @@ init_port(void)
>>   				"rte_zmalloc(%d struct rte_port) failed\n",
>>   				RTE_MAX_ETHPORTS);
>>   	}
>> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
>> +		ports[i].xstats_info.allocated = false;
>>   	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
>>   		LIST_INIT(&ports[i].flow_tunnel_list);
>>   	/* Initialize ports NUMA structures */
>> @@ -3748,6 +3797,67 @@ force_quit(void)
>>   	prompt_exit();
>>   }
>>   
>> +static void
>> +fill_display_xstats_info_for_port(portid_t pi)
>> +{
>> +	unsigned int stat, stat_supp;
>> +	uint64_t *ids, *ids_supp;
>> +	const char *xstat_name;
>> +	struct rte_port *port;
>> +	int rc;
>> +
>> +	if (xstats_display_num == 0)
>> +		return;
>> +
>> +	if (pi == (portid_t)RTE_PORT_ALL) {
>> +		fill_display_xstats_info();
>> +		return;
>> +	}
>> +
>> +	port = &ports[pi];
>> +	if (port->port_status != RTE_PORT_STARTED)
> Why this requirement? Why port has to be started to get the ids of xstat names?

xstats could be extracted from HW and could be available in started 
state only.

It's more robust to require started state.

>
>> +		return;
>> +
>> +	if (!port->xstats_info.allocated && alloc_display_xstats_info(pi) != 0)
>> +		rte_exit(EXIT_FAILURE,
>> +			 "Failed to allocate xstats display memory\n");
>> +
>> +	ids = port->xstats_info.ids;
>> +	ids_supp = port->xstats_info.ids_supp;
>> +
>> +	for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
>> +		xstat_name = xstats_display[stat].name;
>> +
>> +		rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
>> +						   ids + stat);
>> +		if (rc != 0) {
>> +			ids[stat] = XSTAT_ID_INVALID;
>> +			fprintf(stderr, "No xstat '%s' on port %u - skip it\n",
>> +				xstat_name, pi);
>> +			continue;
>> +		}
>> +		ids_supp[stat_supp++] = ids[stat];
>> +	}
>> +
>> +	port->xstats_info.ids_supp_sz = stat_supp;
>> +}
>> +
>> +static void
>> +fill_display_xstats_info(void)
>> +{
>> +	portid_t pi;
>> +
>> +	if (xstats_display_num == 0)
>> +		return;
>> +
>> +	RTE_ETH_FOREACH_DEV(pi) {
>> +		if (pi == (portid_t)RTE_PORT_ALL)
>> +			continue;
> Do we really need this check? Can testpmd created more than 'RTE_PORT_ALL' port?
As I see in other places it's not required. I'll fix it.
>
>> +
>> +		fill_display_xstats_info_for_port(pi);
>> +	}
>> +}
>> +
>>   static void
>>   print_stats(void)
>>   {
>> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
>> index 16a3598e48..68f182944b 100644
>> --- a/app/test-pmd/testpmd.h
>> +++ b/app/test-pmd/testpmd.h
>> @@ -195,6 +195,19 @@ struct tunnel_ops {
>>   	uint32_t items:1;
>>   };
>>   
>> +/** Information for an extended statistics to show. */
>> +struct xstat_display_info {
>> +	/** IDs of xstats in the order of xstats_display */
>> +	uint64_t *ids;
> I think we can drop 'ids' and just keep 'ids_supp', please see below comment on
> 'XSTAT_ID_INVALID'.
>
>> +	/** Supported xstats IDs in the order of xstats_display */
>> +	uint64_t *ids_supp;
>> +	size_t   ids_supp_sz;
>> +	uint64_t *prev_values;
>> +	uint64_t *curr_values;
>> +	uint64_t prev_ns;
>> +	bool	 allocated;
>> +};
>> +
>>   /**
>>    * The data structure associated with each port.
>>    */
>> @@ -234,6 +247,7 @@ struct rte_port {
>>   	/**< dynamic flags. */
>>   	uint64_t		mbuf_dynf;
>>   	const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1];
>> +	struct xstat_display_info xstats_info;
>>   };
>>   
>>   /**
>> @@ -434,6 +448,13 @@ extern uint32_t param_total_num_mbufs;
>>   
>>   extern uint16_t stats_period;
>>   
>> +extern struct rte_eth_xstat_name *xstats_display;
>> +extern unsigned int xstats_display_num;
>> +
>> +#define XSTAT_ID_INVALID UINT64_MAX
> Why you need this flag? Instead marking invalid xstats, why not just save the
> valid one and ignore invalid ones?
> Briefly, in 'xstat_display_info', drop the 'ids' and just keep 'ids_supp'.
You're right. I'll fix it.
>
>> +
>> +extern struct xstat_display_info xstats_per_port[];
>> +
> Is 'xstats_per_port' residue of previous implementations? It seems it is not needed.
Thanks, I'll remove it in the next version.
>>   extern uint16_t hairpin_mode;
>>   
>>   #ifdef RTE_LIB_LATENCYSTATS
>> @@ -766,6 +787,8 @@ inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx)
>>   unsigned int parse_item_list(const char *str, const char *item_name,
>>   			unsigned int max_items,
>>   			unsigned int *parsed_items, int check_unique_values);
>> +int parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
>> +		      unsigned int *xstats_num);
>>   void launch_args_parse(int argc, char** argv);
>>   void cmdline_read_from_file(const char *filename);
>>   void prompt(void);
>> diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
>> index 6061674239..d77afeb633 100644
>> --- a/doc/guides/testpmd_app_ug/run_app.rst
>> +++ b/doc/guides/testpmd_app_ug/run_app.rst
>> @@ -56,6 +56,11 @@ The command line options are:
>>       Display statistics every PERIOD seconds, if interactive mode is disabled.
>>       The default value is 0, which means that the statistics will not be displayed.
>>   
>> +*   ``--display-xstats xstat1[,...]``
>> +
>> +    Display extended statistics every PERIOD seconds as specified in ``--stats-period``
>> +    or when used with interactive commands that show Rx/Tx statistics (i.e. 'show port stats').
>> +
> Can you please highlight 'xstat1' is the xstat name, to prevent it to be
> confused with xstat id?
> Also can you please highlight that list should be comma separated, the short
> 'xstat1[,...]' usage implies this already but better to say it explicitly in the
> document.
>
I'll do it in the next version.
>>   *   ``--nb-cores=N``
>>   
>>       Set the number of forwarding cores,
>>

^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v5] app/testpmd: add option to display extended statistics
  2021-07-23 13:15   ` [dpdk-dev] [PATCH v3 11/11] app/testpmd: add option to display extended statistics Andrew Rybchenko
  2021-08-20 13:55     ` [dpdk-dev] [PATCH v4] " Andrew Rybchenko
@ 2021-09-15 11:27     ` Andrew Rybchenko
  2021-10-14  7:43       ` Ferruh Yigit
  2021-10-14  9:00     ` [dpdk-dev] [PATCH v6] " Andrew Rybchenko
  2 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-15 11:27 UTC (permalink / raw)
  To: Xiaoyun Li; +Cc: dev, Ferruh Yigit, Ivan Ilchenko, Ajit Khaparde

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Add 'display-xstats' option for using in accompanying with Rx/Tx statistics
(i.e. 'stats-period' option or 'show port stats' interactive command) to
display specified list of extended statistics.

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
v5:
    - process review notes from Ferruh

v4:
    - split from patch series
    - move xstats information to rte_port structure to avoid
      extra global structure

 app/test-pmd/config.c                 |  62 +++++++++++++++
 app/test-pmd/parameters.c             |  81 +++++++++++++++++++
 app/test-pmd/testpmd.c                | 108 ++++++++++++++++++++++++++
 app/test-pmd/testpmd.h                |  17 ++++
 doc/guides/testpmd_app_ug/run_app.rst |   6 ++
 5 files changed, 274 insertions(+)

diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index f5765b34f7..d9f0b5caba 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -173,6 +173,65 @@ print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
 	printf("%s%s", name, buf);
 }
 
+static void
+nic_xstats_display_periodic(portid_t port_id)
+{
+	struct xstat_display_info *xstats_info;
+	uint64_t *prev_values, *curr_values;
+	uint64_t diff_value, value_rate;
+	struct timespec cur_time;
+	uint64_t *ids_supp;
+	size_t ids_supp_sz;
+	uint64_t diff_ns;
+	unsigned int i;
+	int rc;
+
+	xstats_info = &ports[port_id].xstats_info;
+
+	ids_supp_sz = xstats_info->ids_supp_sz;
+	if (ids_supp_sz == 0)
+		return;
+
+	printf("\n");
+
+	ids_supp = xstats_info->ids_supp;
+	prev_values = xstats_info->prev_values;
+	curr_values = xstats_info->curr_values;
+
+	rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
+				      ids_supp_sz);
+	if (rc != (int)ids_supp_sz) {
+		fprintf(stderr,
+			"Failed to get values of %zu xstats for port %u - return code %d\n",
+			ids_supp_sz, port_id, rc);
+		return;
+	}
+
+	diff_ns = 0;
+	if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
+		uint64_t ns;
+
+		ns = cur_time.tv_sec * NS_PER_SEC;
+		ns += cur_time.tv_nsec;
+
+		if (xstats_info->prev_ns != 0)
+			diff_ns = ns - xstats_info->prev_ns;
+		xstats_info->prev_ns = ns;
+	}
+
+	printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
+	for (i = 0; i < ids_supp_sz; i++) {
+		diff_value = (curr_values[i] > prev_values[i]) ?
+			     (curr_values[i] - prev_values[i]) : 0;
+		prev_values[i] = curr_values[i];
+		value_rate = diff_ns > 0 ?
+				(double)diff_value / diff_ns * NS_PER_SEC : 0;
+
+		printf("  %-25s%12"PRIu64" %15"PRIu64"\n",
+		       xstats_display[i].name, curr_values[i], value_rate);
+	}
+}
+
 void
 nic_stats_display(portid_t port_id)
 {
@@ -243,6 +302,9 @@ nic_stats_display(portid_t port_id)
 	       PRIu64"          Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
 	       mpps_tx, mbps_tx * 8);
 
+	if (xstats_display_num > 0)
+		nic_xstats_display_periodic(port_id);
+
 	printf("  %s############################%s\n",
 	       nic_stats_border, nic_stats_border);
 }
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 3f94a82e32..b3217d6e5c 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -61,6 +61,10 @@ usage(char* progname)
 	       "(only if interactive is disabled).\n");
 	printf("  --stats-period=PERIOD: statistics will be shown "
 	       "every PERIOD seconds (only if interactive is disabled).\n");
+	printf("  --display-xstats xstat_name1[,...]: comma-separated list of "
+	       "extended statistics to show. Used with --stats-period "
+	       "specified or interactive commands that show Rx/Tx statistics "
+	       "(i.e. 'show port stats').\n");
 	printf("  --nb-cores=N: set the number of forwarding cores "
 	       "(1 <= N <= %d).\n", nb_lcores);
 	printf("  --nb-ports=N: set the number of forwarding ports "
@@ -473,6 +477,72 @@ parse_event_printing_config(const char *optarg, int enable)
 	return 0;
 }
 
+static int
+parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
+		  unsigned int *xstats_num)
+{
+	int max_names_nb, names_nb, nonempty_names_nb;
+	int name, nonempty_name;
+	int stringlen;
+	char **names;
+	char *str;
+	int ret;
+	int i;
+
+	names = NULL;
+	str = strdup(in_str);
+	if (str == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	stringlen = strlen(str);
+
+	for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
+		if (str[i] == ',')
+			max_names_nb++;
+	}
+
+	names = calloc(max_names_nb, sizeof(*names));
+	if (names == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
+	if (names_nb < 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nonempty_names_nb = 0;
+	for (i = 0; i < names_nb; i++) {
+		if (names[i][0] == '\0')
+			continue;
+		nonempty_names_nb++;
+	}
+	*xstats = calloc(nonempty_names_nb, sizeof(**xstats));
+	if (*xstats == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	for (name = nonempty_name = 0; name < names_nb; name++) {
+		if (names[name][0] == '\0')
+			continue;
+		rte_strscpy((*xstats)[nonempty_name].name, names[name],
+			    sizeof((*xstats)[nonempty_name].name));
+		nonempty_name++;
+	}
+
+	*xstats_num = nonempty_names_nb;
+	ret = 0;
+
+out:
+	free(names);
+	free(str);
+	return ret;
+}
+
 static int
 parse_link_speed(int n)
 {
@@ -539,6 +609,7 @@ launch_args_parse(int argc, char** argv)
 #endif
 		{ "tx-first",			0, 0, 0 },
 		{ "stats-period",		1, 0, 0 },
+		{ "display-xstats",		1, 0, 0 },
 		{ "nb-cores",			1, 0, 0 },
 		{ "nb-ports",			1, 0, 0 },
 		{ "coremask",			1, 0, 0 },
@@ -699,6 +770,16 @@ launch_args_parse(int argc, char** argv)
 				stats_period = n;
 				break;
 			}
+			if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
+				char rc;
+
+				rc = parse_xstats_list(optarg, &xstats_display,
+						       &xstats_display_num);
+				if (rc != 0)
+					rte_exit(EXIT_FAILURE,
+						 "Failed to parse display-xstats argument: %d\n",
+						 rc);
+			}
 			if (!strcmp(lgopts[opt_idx].name,
 				    "eth-peers-configfile")) {
 				if (init_peer_eth_addrs(optarg) != 0)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 97ae52e17e..f343d7079c 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -208,6 +208,11 @@ uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
                                       * specified on command-line. */
 uint16_t stats_period; /**< Period to show statistics (disabled by default) */
 
+/** Extended statistics to show. */
+struct rte_eth_xstat_name *xstats_display;
+
+unsigned int xstats_display_num; /**< Size of extended statistics to show */
+
 /*
  * In container, it cannot terminate the process which running with 'stats-period'
  * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
@@ -586,6 +591,7 @@ static int eth_event_callback(portid_t port_id,
 static void dev_event_callback(const char *device_name,
 				enum rte_dev_event_type type,
 				void *param);
+static void fill_xstats_display_info(void);
 
 /*
  * Check if all the ports are started.
@@ -599,6 +605,7 @@ uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
 /* Holds the registered mbuf dynamic flags names. */
 char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
 
+
 /*
  * Helper function to check if socket is already discovered.
  * If yes, return positive value. If not, return zero.
@@ -2500,6 +2507,101 @@ rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
 	return ret;
 }
 
+static int
+alloc_xstats_display_info(portid_t pi)
+{
+	uint64_t **ids_supp = &ports[pi].xstats_info.ids_supp;
+	uint64_t **prev_values = &ports[pi].xstats_info.prev_values;
+	uint64_t **curr_values = &ports[pi].xstats_info.curr_values;
+
+	if (xstats_display_num == 0)
+		return 0;
+
+	*ids_supp = calloc(xstats_display_num, sizeof(**ids_supp));
+	if (*ids_supp == NULL)
+		return -ENOMEM;
+
+	*prev_values = calloc(xstats_display_num,
+			      sizeof(**prev_values));
+	if (*prev_values == NULL)
+		return -ENOMEM;
+
+	*curr_values = calloc(xstats_display_num,
+			      sizeof(**curr_values));
+	if (*curr_values == NULL)
+		return -ENOMEM;
+
+	ports[pi].xstats_info.allocated = true;
+
+	return 0;
+}
+
+static void
+free_xstats_display_info(portid_t pi)
+{
+	if (!ports[pi].xstats_info.allocated)
+		return;
+	free(ports[pi].xstats_info.ids_supp);
+	free(ports[pi].xstats_info.prev_values);
+	free(ports[pi].xstats_info.curr_values);
+	ports[pi].xstats_info.allocated = false;
+}
+
+/** Fill helper structures for specified port to show extended statistics. */
+static void
+fill_xstats_display_info_for_port(portid_t pi)
+{
+	unsigned int stat, stat_supp;
+	const char *xstat_name;
+	struct rte_port *port;
+	uint64_t *ids_supp;
+	int rc;
+
+	if (xstats_display_num == 0)
+		return;
+
+	if (pi == (portid_t)RTE_PORT_ALL) {
+		fill_xstats_display_info();
+		return;
+	}
+
+	port = &ports[pi];
+	if (port->port_status != RTE_PORT_STARTED)
+		return;
+
+	if (!port->xstats_info.allocated && alloc_xstats_display_info(pi) != 0)
+		rte_exit(EXIT_FAILURE,
+			 "Failed to allocate xstats display memory\n");
+
+	ids_supp = port->xstats_info.ids_supp;
+	for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
+		xstat_name = xstats_display[stat].name;
+		rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
+						   ids_supp + stat_supp);
+		if (rc != 0) {
+			fprintf(stderr, "No xstat '%s' on port %u - skip it %u\n",
+				xstat_name, pi, stat);
+			continue;
+		}
+		stat_supp++;
+	}
+
+	port->xstats_info.ids_supp_sz = stat_supp;
+}
+
+/** Fill helper structures for all ports to show extended statistics. */
+static void
+fill_xstats_display_info(void)
+{
+	portid_t pi;
+
+	if (xstats_display_num == 0)
+		return;
+
+	RTE_ETH_FOREACH_DEV(pi)
+		fill_xstats_display_info_for_port(pi);
+}
+
 int
 start_port(portid_t pid)
 {
@@ -2750,6 +2852,8 @@ start_port(portid_t pid)
 		}
 	}
 
+	fill_xstats_display_info_for_port(pid);
+
 	printf("Done\n");
 	return 0;
 }
@@ -2886,6 +2990,7 @@ close_port(portid_t pid)
 
 		if (is_proc_primary()) {
 			port_flow_flush(pi);
+			free_xstats_display_info(pi);
 			rte_eth_dev_close(pi);
 		}
 	}
@@ -3174,6 +3279,7 @@ pmd_test_exit(void)
 		if (mempools[i])
 			mempool_free_mp(mempools[i]);
 	}
+	free(xstats_display);
 
 	printf("\nBye...\n");
 }
@@ -3804,6 +3910,8 @@ init_port(void)
 				"rte_zmalloc(%d struct rte_port) failed\n",
 				RTE_MAX_ETHPORTS);
 	}
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		ports[i].xstats_info.allocated = false;
 	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
 		LIST_INIT(&ports[i].flow_tunnel_list);
 	/* Initialize ports NUMA structures */
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 5863b2f43f..10af4970b3 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -195,6 +195,17 @@ struct tunnel_ops {
 	uint32_t items:1;
 };
 
+/** Information for an extended statistics to show. */
+struct xstat_display_info {
+	/** Supported xstats IDs in the order of xstats_display */
+	uint64_t *ids_supp;
+	size_t   ids_supp_sz;
+	uint64_t *prev_values;
+	uint64_t *curr_values;
+	uint64_t prev_ns;
+	bool	 allocated;
+};
+
 /**
  * The data structure associated with each port.
  */
@@ -234,6 +245,7 @@ struct rte_port {
 	/**< dynamic flags. */
 	uint64_t		mbuf_dynf;
 	const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1];
+	struct xstat_display_info xstats_info;
 };
 
 /**
@@ -434,6 +446,11 @@ extern uint32_t param_total_num_mbufs;
 
 extern uint16_t stats_period;
 
+extern struct rte_eth_xstat_name *xstats_display;
+extern unsigned int xstats_display_num;
+
+#define XSTAT_ID_INVALID UINT64_MAX
+
 extern uint16_t hairpin_mode;
 
 #ifdef RTE_LIB_LATENCYSTATS
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index 640eadeff7..8ff7ab8536 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -56,6 +56,12 @@ The command line options are:
     Display statistics every PERIOD seconds, if interactive mode is disabled.
     The default value is 0, which means that the statistics will not be displayed.
 
+*   ``--display-xstats xstat_name1[,...]``
+
+    Display comma-separated list of extended statistics every PERIOD seconds
+    as specified in ``--stats-period`` or when used with interactive commands
+    that show Rx/Tx statistics (i.e. 'show port stats').
+
 *   ``--nb-cores=N``
 
     Set the number of forwarding cores,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions getting xstats by IDs
  2021-07-26 10:13   ` [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions " Olivier Matz
@ 2021-09-28 12:01     ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-28 12:01 UTC (permalink / raw)
  To: Olivier Matz
  Cc: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak, Ivan Ilchenko,
	stable, Andy Moreton

Hi Olivier,

I apologize for so long delay with reply. I simply lost it from
my view.

Many thanks for review notes. See below.

On 7/26/21 1:13 PM, Olivier Matz wrote:
> Hi Andrew,
> 
> Some comments below.
> 
> On Sat, Jul 24, 2021 at 03:33:13PM +0300, Andrew Rybchenko wrote:
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Document valid combinations of input arguments in accordance with
>> current implementation in ethdev.
>>
>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>> Cc: stable@dpdk.org
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>> ---
>>  lib/ethdev/rte_ethdev.h | 32 +++++++++++++++++++-------------
>>  1 file changed, 19 insertions(+), 13 deletions(-)
>>
>> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
>> index d2b27c351f..b14067fe7e 100644
>> --- a/lib/ethdev/rte_ethdev.h
>> +++ b/lib/ethdev/rte_ethdev.h
>> @@ -2872,13 +2872,17 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>>   * @param port_id
>>   *   The port identifier of the Ethernet device.
>>   * @param xstats_names
>> - *   An rte_eth_xstat_name array of at least *size* elements to
>> - *   be filled. If set to NULL, the function returns the required number
>> - *   of elements.
>> + *   Array to be filled in with names of requested device statistics.
>> + *   Must not be NULL if @p ids are specified (not NULL).
>>   * @param ids
>> - *   IDs array given by app to retrieve specific statistics
>> + *   IDs array given by app to retrieve specific statistics. May be NULL to
>> + *   retrieve names of all available statistics or, if @p xstats_names is
>> + *   NULL as well,  just a number of available statistics.
> 
> double spaces before "just"
> 
> "a number" -> "the number"?

Fixed in v5

>>   * @param size
>> - *   The size of the xstats_names array (number of elements).
>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>> + *   and number of elements in @p xstats_names to put names in. If @p ids is
>> + *   NULL, number of elements in @p xstats_names to put all available statistics
>> + *   names in.
> 
> Just a suggestion here, I feel the following description would be clearer:
> 
>   Number of elements in @p xstats_names array (if not NULL) and
>   in @p ids array (if not NULL).

I agree that it is better to avoid here details about
behaviour of one or another array pointer is NULL.
Descriptions of corresponding parameters cover it.

Fixed in v5.

>
> Shouldn't we say that it has to be 0 if both arrays are NULL?

Yes, I think it is useful. Will add in v5.

> 
> Also, the order of arguments is not the same in comment and in
> the function. I think it can make sense to align the comment
> to the prototype.

Fixed in v5.

> 
> 
>>   * @return
>>   *   - A positive value lower or equal to size: success. The return value
>>   *     is the number of entries filled in the stats table.
> 
> Not seen in the patch, but right after this line, there is:
> 
>  *   - A positive value higher than size: error, the given statistics table
>  *     is too small. The return value corresponds to the size that should
>  *     be given to succeed. The entries in the table are not valid and
>  *     shall not be used by the caller.
> 
> I wonder if it shouldn't be slighly reworded to remove 'error'. After
> all, passing NULL arrays (and size == 0) is a valid, so the return is
> not an error.

I agree that it should not be treated as an error. It is just a
special case of success when return is partially provided (just
a number of stats).

Fixed in v5.

> 
>> @@ -2886,7 +2890,7 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
>>   *     is too small. The return value corresponds to the size that should
>>   *     be given to succeed. The entries in the table are not valid and
>>   *     shall not be used by the caller.
>> - *   - A negative value on error (invalid port id).
>> + *   - A negative value on error.
>>   */
>>  int
>>  rte_eth_xstats_get_names_by_id(uint16_t port_id,
>> @@ -2899,14 +2903,16 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>   * @param port_id
>>   *   The port identifier of the Ethernet device.
>>   * @param ids
>> - *   A pointer to an ids array passed by application. This tells which
>> - *   statistics values function should retrieve. This parameter
>> - *   can be set to NULL if size is 0. In this case function will retrieve
>> - *   all available statistics.
>> + *   IDs array given by app to retrieve specific statistics. May be NULL to
>> + *   retrieve all available statistics or, if @p values is NULL as well,
>> + *   just a number of available statistics.
>>   * @param values
>> - *   A pointer to a table to be filled with device statistics values.
>> + *   Array to be filled in with requested device statistics.
>> + *   Must not be NULL if ids are specified (not NULL).
>>   * @param size
>> - *   The size of the ids array (number of elements).
>> + *   If @p ids is not NULL, number of elements in the array with requested IDs
>> + *   and number of elements in @p values to put statistics in. If @p ids is NULL,
>> + *   number of elements in @p values to put all available statistics in.
>>   * @return
>>   *   - A positive value lower or equal to size: success. The return value
>>   *     is the number of entries filled in the stats table.
>> @@ -2914,7 +2920,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>>   *     is too small. The return value corresponds to the size that should
>>   *     be given to succeed. The entries in the table are not valid and
>>   *     shall not be used by the caller.
>> - *   - A negative value on error (invalid port id).
>> + *   - A negative value on error.
>>   */
> 
> Some of the comments above also apply here.

Done.

> 
>>  int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
>>  			     uint64_t *values, unsigned int size);
>> -- 
>> 2.30.2
>>


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v4 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-07-26 10:13     ` Olivier Matz
@ 2021-09-28 12:04       ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-28 12:04 UTC (permalink / raw)
  To: Olivier Matz
  Cc: dev, Thomas Monjalon, Ferruh Yigit, Kuba Kozak, Ivan Ilchenko,
	stable, Andy Moreton

On 7/26/21 1:13 PM, Olivier Matz wrote:
> On Sat, Jul 24, 2021 at 03:33:14PM +0300, Andrew Rybchenko wrote:
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Update xstats by IDs callbacks documentation in accordance with
>> ethdev usage of these callbacks. Document valid combinations of
>> input arguments to make driver implementation simpler.
>>
>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>> Cc: stable@dpdk.org
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>> ---
>>  lib/ethdev/ethdev_driver.h | 43 ++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>> index 40e474aa7e..fd5b7ca550 100644
>> --- a/lib/ethdev/ethdev_driver.h
>> +++ b/lib/ethdev/ethdev_driver.h
>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>  	struct rte_eth_xstat *stats, unsigned int n);
>>  /**< @internal Get extended stats of an Ethernet device. */
>>  
>> +/**
>> + * @internal
>> + * Get extended stats of an Ethernet device.
>> + *
>> + * @param dev
>> + *   ethdev handle of port.
>> + * @param ids
>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>> + * @param values
>> + *   A pointer to a table to be filled with device statistics values.
>> + *   Must not be NULL.
>> + * @param n
>> + *   Element count in @p ids and @p values
>> + *
>> + * @return
>> + *   - A number of filled in stats.
>> + *   - A negative value on error.
>> + */
>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>  				      const uint64_t *ids,
>>  				      uint64_t *values,
>>  				      unsigned int n);
>> -/**< @internal Get extended stats of an Ethernet device. */
>>  
>>  /**
>>   * @internal
>> @@ -218,10 +235,32 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>  
>> +/**
>> + * @internal
>> + * Get names of extended stats of an Ethernet device.
>> + * For name count, set @p xstats_names and @p ids to NULL.
>> + *
>> + * @param dev
>> + *   ethdev handle of port.
>> + * @param xstats_names
>> + *   An rte_eth_xstat_name array of at least *size* elements to
>> + *   be filled. Can be NULL together with @p ids to retrieve number of
>> + *   available statistics.
>> + * @param ids
>> + *   IDs array to retrieve specific statistics. Can be NULL together
>> + *   with @p xstats_names to retrieve number of available statistics.
>> + * @param size
>> + *   Size of ids and xstats_names arrays.
>> + *   Element count in @p ids and @p xstats_names
> 
> I think only the second line should be kept.

Thanks, fixed in v5.

> 
> Shouldn't we also say here that size should be 0 if arrays are NULL?

In this particular case I don't think so. ethdev layer
guarantees that the parameter is 0 if both array pointers
are NULL. PMD should not care about it.

> 
>> + *
>> + * @return
>> + *   - A number of filled in stats if both xstats_names and ids are not NULL.
>> + *   - A number of available stats if both xstats_names and ids are NULL.
>> + *   - A negative value on error.
>> + */
>>  typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
>>  	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
>>  	unsigned int size);
>> -/**< @internal Get names of extended stats of an Ethernet device. */
>>  
>>  typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
>>  					     uint16_t queue_id,
>> -- 
>> 2.30.2
>>


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v5 1/2] ethdev: fix docs of functions getting xstats by IDs
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (13 preceding siblings ...)
  2021-07-24 12:33 ` [dpdk-dev] [PATCH v4 1/2] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-09-28 12:05 ` Andrew Rybchenko
  2021-09-28 12:05   ` [dpdk-dev] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
  2021-09-28 16:46   ` [dpdk-dev] [PATCH v5 1/2] ethdev: fix docs of functions " Ferruh Yigit
  2021-09-30 14:04 ` [dpdk-dev] [PATCH v6 1/4] " Andrew Rybchenko
                   ` (3 subsequent siblings)
  18 siblings, 2 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-28 12:05 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Document valid combinations of input arguments in accordance with
current implementation in ethdev.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/rte_ethdev.h | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index 224c6c980a..f597171c97 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2899,21 +2899,23 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param xstats_names
- *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. If set to NULL, the function returns the required number
- *   of elements.
- * @param ids
- *   IDs array given by app to retrieve specific statistics
+ *   Array to be filled in with names of requested device statistics.
+ *   Must not be NULL if @p ids are specified (not NULL).
  * @param size
- *   The size of the xstats_names array (number of elements).
+ *   Number of elements in @p xstats_names array (if not NULL) and in
+ *   @p ids array (if not NULL). Must be 0 if both array pointers are NULL.
+ * @param ids
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve names of all available statistics or, if @p xstats_names is
+ *   NULL as well, just the number of available statistics.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
- *   - A positive value higher than size: error, the given statistics table
+ *   - A positive value higher than size: success. The given statistics table
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int
 rte_eth_xstats_get_names_by_id(uint16_t port_id,
@@ -2926,22 +2928,23 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param ids
- *   A pointer to an ids array passed by application. This tells which
- *   statistics values function should retrieve. This parameter
- *   can be set to NULL if size is 0. In this case function will retrieve
- *   all available statistics.
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve all available statistics or, if @p values is NULL as well,
+ *   just the number of available statistics.
  * @param values
- *   A pointer to a table to be filled with device statistics values.
+ *   Array to be filled in with requested device statistics.
+ *   Must not be NULL if ids are specified (not NULL).
  * @param size
- *   The size of the ids array (number of elements).
+ *   Number of elements in @p values array (if not NULL) and in @p ids
+ *   array (if not NULL). Must be 0 if both array pointers are NULL.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
- *   - A positive value higher than size: error, the given statistics table
+ *   - A positive value higher than size: success: The given statistics table
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
 			     uint64_t *values, unsigned int size);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-28 12:05 ` [dpdk-dev] [PATCH v5 " Andrew Rybchenko
@ 2021-09-28 12:05   ` Andrew Rybchenko
  2021-09-28 16:50     ` Ferruh Yigit
  2021-09-28 16:46   ` [dpdk-dev] [PATCH v5 1/2] ethdev: fix docs of functions " Ferruh Yigit
  1 sibling, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-28 12:05 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 40e474aa7e..c89eefcc42 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values.
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats of an Ethernet device.
+ * For name count, set @p xstats_names and @p ids to NULL.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Can be NULL together with @p ids to retrieve number of
+ *   available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param size
+ *   Element count in @p ids and @p xstats_names.
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/2] ethdev: fix docs of functions getting xstats by IDs
  2021-09-28 12:05 ` [dpdk-dev] [PATCH v5 " Andrew Rybchenko
  2021-09-28 12:05   ` [dpdk-dev] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-09-28 16:46   ` Ferruh Yigit
  1 sibling, 0 replies; 113+ messages in thread
From: Ferruh Yigit @ 2021-09-28 16:46 UTC (permalink / raw)
  To: Andrew Rybchenko, Thomas Monjalon, Kuba Kozak
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton

On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Document valid combinations of input arguments in accordance with
> current implementation in ethdev.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>

Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>

Only minor issue below.

> @@ -2926,22 +2928,23 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
>   * @param port_id
>   *   The port identifier of the Ethernet device.
>   * @param ids
> - *   A pointer to an ids array passed by application. This tells which
> - *   statistics values function should retrieve. This parameter
> - *   can be set to NULL if size is 0. In this case function will retrieve
> - *   all available statistics.
> + *   IDs array given by app to retrieve specific statistics. May be NULL to
> + *   retrieve all available statistics or, if @p values is NULL as well,
> + *   just the number of available statistics.
>   * @param values
> - *   A pointer to a table to be filled with device statistics values.
> + *   Array to be filled in with requested device statistics.
> + *   Must not be NULL if ids are specified (not NULL).

Minor issue, @p marker is missed before 'ids', comparing the
'rte_eth_xstats_get_names_by_id()' comment.



^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-28 12:05   ` [dpdk-dev] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-09-28 16:50     ` Ferruh Yigit
  2021-09-28 16:53       ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-09-28 16:50 UTC (permalink / raw)
  To: Andrew Rybchenko, Thomas Monjalon, Kuba Kozak
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton

On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> 
> Update xstats by IDs callbacks documentation in accordance with
> ethdev usage of these callbacks. Document valid combinations of
> input arguments to make driver implementation simpler.
> 
> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
> ---
>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 40 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
> index 40e474aa7e..c89eefcc42 100644
> --- a/lib/ethdev/ethdev_driver.h
> +++ b/lib/ethdev/ethdev_driver.h
> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat *stats, unsigned int n);
>  /**< @internal Get extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get extended stats of an Ethernet device.
> + *
> + * @param dev
> + *   ethdev handle of port.
> + * @param ids
> + *   IDs array to retrieve specific statistics. Must not be NULL.
> + * @param values
> + *   A pointer to a table to be filled with device statistics values.
> + *   Must not be NULL.
> + * @param n
> + *   Element count in @p ids and @p values.
> + *
> + * @return
> + *   - A number of filled in stats.
> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>  				      const uint64_t *ids,
>  				      uint64_t *values,
>  				      unsigned int n);
> -/**< @internal Get extended stats of an Ethernet device. */
>  
>  /**
>   * @internal
> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>  /**< @internal Get names of extended stats of an Ethernet device. */
>  
> +/**
> + * @internal
> + * Get names of extended stats of an Ethernet device.
> + * For name count, set @p xstats_names and @p ids to NULL.

Why limiting this behavior to 'xstats_get_names_by_id'?

Internally 'xstats_get_names_by_id' is used to get the count, but I think this
is not intentionally selected, just one of the xstats_*_by_id dev_ops used.

I think it is confusing to have this support for one of the '_by_id' dev_ops but
not for other. Why not require both to support returning 'count'?

> + *
> + * @param dev
> + *   ethdev handle of port.
> + * @param xstats_names
> + *   An rte_eth_xstat_name array of at least *size* elements to
> + *   be filled. Can be NULL together with @p ids to retrieve number of
> + *   available statistics.
> + * @param ids
> + *   IDs array to retrieve specific statistics. Can be NULL together
> + *   with @p xstats_names to retrieve number of available statistics.
> + * @param size
> + *   Element count in @p ids and @p xstats_names.
> + *
> + * @return
> + *   - A number of filled in stats if both xstats_names and ids are not NULL.
> + *   - A number of available stats if both xstats_names and ids are NULL.
> + *   - A negative value on error.
> + */
>  typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
>  	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
>  	unsigned int size);
> -/**< @internal Get names of extended stats of an Ethernet device. */
>  
>  typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
>  					     uint16_t queue_id,
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-28 16:50     ` Ferruh Yigit
@ 2021-09-28 16:53       ` Andrew Rybchenko
  2021-09-29  8:44         ` [dpdk-dev] [dpdk-stable] " Ferruh Yigit
  0 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-28 16:53 UTC (permalink / raw)
  To: Ferruh Yigit, Thomas Monjalon, Kuba Kozak
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton

On 9/28/21 7:50 PM, Ferruh Yigit wrote:
> On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>
>> Update xstats by IDs callbacks documentation in accordance with
>> ethdev usage of these callbacks. Document valid combinations of
>> input arguments to make driver implementation simpler.
>>
>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>> Cc: stable@dpdk.org
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>> ---
>>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>
>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>> index 40e474aa7e..c89eefcc42 100644
>> --- a/lib/ethdev/ethdev_driver.h
>> +++ b/lib/ethdev/ethdev_driver.h
>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>  	struct rte_eth_xstat *stats, unsigned int n);
>>  /**< @internal Get extended stats of an Ethernet device. */
>>  
>> +/**
>> + * @internal
>> + * Get extended stats of an Ethernet device.
>> + *
>> + * @param dev
>> + *   ethdev handle of port.
>> + * @param ids
>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>> + * @param values
>> + *   A pointer to a table to be filled with device statistics values.
>> + *   Must not be NULL.
>> + * @param n
>> + *   Element count in @p ids and @p values.
>> + *
>> + * @return
>> + *   - A number of filled in stats.
>> + *   - A negative value on error.
>> + */
>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>  				      const uint64_t *ids,
>>  				      uint64_t *values,
>>  				      unsigned int n);
>> -/**< @internal Get extended stats of an Ethernet device. */
>>  
>>  /**
>>   * @internal
>> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>  
>> +/**
>> + * @internal
>> + * Get names of extended stats of an Ethernet device.
>> + * For name count, set @p xstats_names and @p ids to NULL.
> 
> Why limiting this behavior to 'xstats_get_names_by_id'?
> 
> Internally 'xstats_get_names_by_id' is used to get the count, but I think this
> is not intentionally selected, just one of the xstats_*_by_id dev_ops used.
> 
> I think it is confusing to have this support for one of the '_by_id' dev_ops but
> not for other. Why not require both to support returning 'count'?

Simply because it is dead code. There is no point to require
from driver to have dead code.

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [dpdk-stable] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-28 16:53       ` Andrew Rybchenko
@ 2021-09-29  8:44         ` Ferruh Yigit
  2021-09-29 11:54           ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-09-29  8:44 UTC (permalink / raw)
  To: Andrew Rybchenko, Thomas Monjalon, Kuba Kozak
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton

On 9/28/2021 5:53 PM, Andrew Rybchenko wrote:
> On 9/28/21 7:50 PM, Ferruh Yigit wrote:
>> On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>
>>> Update xstats by IDs callbacks documentation in accordance with
>>> ethdev usage of these callbacks. Document valid combinations of
>>> input arguments to make driver implementation simpler.
>>>
>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>> Cc: stable@dpdk.org
>>>
>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>> ---
>>>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>>> index 40e474aa7e..c89eefcc42 100644
>>> --- a/lib/ethdev/ethdev_driver.h
>>> +++ b/lib/ethdev/ethdev_driver.h
>>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>>  	struct rte_eth_xstat *stats, unsigned int n);
>>>  /**< @internal Get extended stats of an Ethernet device. */
>>>  
>>> +/**
>>> + * @internal
>>> + * Get extended stats of an Ethernet device.
>>> + *
>>> + * @param dev
>>> + *   ethdev handle of port.
>>> + * @param ids
>>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>>> + * @param values
>>> + *   A pointer to a table to be filled with device statistics values.
>>> + *   Must not be NULL.
>>> + * @param n
>>> + *   Element count in @p ids and @p values.
>>> + *
>>> + * @return
>>> + *   - A number of filled in stats.
>>> + *   - A negative value on error.
>>> + */
>>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>>  				      const uint64_t *ids,
>>>  				      uint64_t *values,
>>>  				      unsigned int n);
>>> -/**< @internal Get extended stats of an Ethernet device. */
>>>  
>>>  /**
>>>   * @internal
>>> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>>  
>>> +/**
>>> + * @internal
>>> + * Get names of extended stats of an Ethernet device.
>>> + * For name count, set @p xstats_names and @p ids to NULL.
>>
>> Why limiting this behavior to 'xstats_get_names_by_id'?
>>
>> Internally 'xstats_get_names_by_id' is used to get the count, but I think this
>> is not intentionally selected, just one of the xstats_*_by_id dev_ops used.
>>
>> I think it is confusing to have this support for one of the '_by_id' dev_ops but
>> not for other. Why not require both to support returning 'count'?
> 
> Simply because it is dead code. There is no point to require
> from driver to have dead code.
> 

Let me step back a little, both ethdev APIs can be used to return xstats count
by providing 'values/names' & 'ids' pointers as NULL and 'size' as 0:
'rte_eth_xstats_get_names_by_id()'
'rte_eth_xstats_get_by_id()'

But internally both APIs use 'xstats_get_names_by_id' dev_ops to get the count,
as said above I believe this selection is done unintentionally.


I am for below two options:

a) Internally use 'xstats_get_names' || 'xstats_get' dev_ops to get the xstats
count, and doesn't support getting xstats count for both '_by_id' dev_ops, this
simplifies driver code. As far as I remember I suggested this before, still I
prefer this one.

b) If we will support getting xstats count from '_by_id' dev_ops, I think both
should support it, to not make it more complex to figure out which one support
what. As sample both 'xstats_get_names' and 'xstats_get' supports getting xstats
count, not just one.

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [dpdk-stable] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-29  8:44         ` [dpdk-dev] [dpdk-stable] " Ferruh Yigit
@ 2021-09-29 11:54           ` Andrew Rybchenko
  2021-09-30 12:08             ` Ferruh Yigit
  0 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-29 11:54 UTC (permalink / raw)
  To: Ferruh Yigit, Thomas Monjalon
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton, Kuba Kozak

On 9/29/21 11:44 AM, Ferruh Yigit wrote:
> On 9/28/2021 5:53 PM, Andrew Rybchenko wrote:
>> On 9/28/21 7:50 PM, Ferruh Yigit wrote:
>>> On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
>>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>
>>>> Update xstats by IDs callbacks documentation in accordance with
>>>> ethdev usage of these callbacks. Document valid combinations of
>>>> input arguments to make driver implementation simpler.
>>>>
>>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>>> Cc: stable@dpdk.org
>>>>
>>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>>> ---
>>>>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>>>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>>>> index 40e474aa7e..c89eefcc42 100644
>>>> --- a/lib/ethdev/ethdev_driver.h
>>>> +++ b/lib/ethdev/ethdev_driver.h
>>>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>>>  	struct rte_eth_xstat *stats, unsigned int n);
>>>>  /**< @internal Get extended stats of an Ethernet device. */
>>>>  
>>>> +/**
>>>> + * @internal
>>>> + * Get extended stats of an Ethernet device.
>>>> + *
>>>> + * @param dev
>>>> + *   ethdev handle of port.
>>>> + * @param ids
>>>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>>>> + * @param values
>>>> + *   A pointer to a table to be filled with device statistics values.
>>>> + *   Must not be NULL.
>>>> + * @param n
>>>> + *   Element count in @p ids and @p values.
>>>> + *
>>>> + * @return
>>>> + *   - A number of filled in stats.
>>>> + *   - A negative value on error.
>>>> + */
>>>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>>>  				      const uint64_t *ids,
>>>>  				      uint64_t *values,
>>>>  				      unsigned int n);
>>>> -/**< @internal Get extended stats of an Ethernet device. */
>>>>  
>>>>  /**
>>>>   * @internal
>>>> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>>>  
>>>> +/**
>>>> + * @internal
>>>> + * Get names of extended stats of an Ethernet device.
>>>> + * For name count, set @p xstats_names and @p ids to NULL.
>>>
>>> Why limiting this behavior to 'xstats_get_names_by_id'?
>>>
>>> Internally 'xstats_get_names_by_id' is used to get the count, but I think this
>>> is not intentionally selected, just one of the xstats_*_by_id dev_ops used.
>>>
>>> I think it is confusing to have this support for one of the '_by_id' dev_ops but
>>> not for other. Why not require both to support returning 'count'?
>>
>> Simply because it is dead code. There is no point to require
>> from driver to have dead code.
>>
> 
> Let me step back a little, both ethdev APIs can be used to return xstats count
> by providing 'values/names' & 'ids' pointers as NULL and 'size' as 0:
> 'rte_eth_xstats_get_names_by_id()'
> 'rte_eth_xstats_get_by_id()'
> 
> But internally both APIs use 'xstats_get_names_by_id' dev_ops to get the count,
> as said above I believe this selection is done unintentionally.
> 
> 
> I am for below two options:
> 
> a) Internally use 'xstats_get_names' || 'xstats_get' dev_ops to get the xstats
> count, and doesn't support getting xstats count for both '_by_id' dev_ops, this
> simplifies driver code. As far as I remember I suggested this before, still I
> prefer this one.
> 
> b) If we will support getting xstats count from '_by_id' dev_ops, I think both
> should support it, to not make it more complex to figure out which one support
> what. As sample both 'xstats_get_names' and 'xstats_get' supports getting xstats
> count, not just one.
> 

In (b) do you suggest to change ethdev to use xstats_get_by_id
driver op if users asks for a number of xstats using
rte_eth_xstats_get_by_id()? It will complicate ethdev and
will complicate drivers. Just for the symmetry?

The patch does not change external API, does not change etcdev
bahaviour. It just clarify requirements on driver ops to
allow to check less in all drivers and support less cases
in all drivers.

If we make a one more step back, frankly speaking I think we
have too many functions to retrieve statistics. I can
understand from ethdev API point of view taking API stability
into account etc. But why do we have so many complicated
driver callbacks?

First of all I'd like to do one more cleanup:
change eth_xstats_get_names_by_id_t prototype to
have ids before xstats_names.
I.e. eth_xstats_get_by_id_t(dev, ids, values, size)
eth_xstats_get_names_by_id_t(dev, ids, names, size)

Second, merge eth_xstats_get_names_t and eth_xstats_get_names_by_id_t
callbacks to keep
name of the first, but prototype from the second.
The reason is equal functionality if ids==NULL,
shorter name of the first and optional ids (i.e. no
reason to mention optional parameter in name).
Drivers which do not implement by_id_t,
but implement eth_xstats_get_names_t, will simply
return ENOTSUP if ids!=NULL.

The case of values ops is more complicated,
however since:

2834  * There is an assumption that 'xstat_names' and 'xstats' arrays
are matched
2835  * by array index:
2836  *  xstats_names[i].name => xstats[i].value
2837  *
2838  * And the array index is same with id field of 'struct rte_eth_xstat':
2839  *  xstats[i].id == i
2840  *
2841  * This assumption makes key-value pair matching less flexible but
simpler.

we can switch to eth_xstats_get_by_id_t only callback as
well and fill in stats->id equal to index on ethdev layer.
However, it will require extra buffer for
uint64_t *values and copying in the rte_eth_xstats_get()
implementation. So, I doubt in this case.

In fact, it is sad that we still do not move forward
in accordance with Thomas presentation made 2 years ago.

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [dpdk-stable] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-29 11:54           ` Andrew Rybchenko
@ 2021-09-30 12:08             ` Ferruh Yigit
  2021-09-30 14:01               ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-09-30 12:08 UTC (permalink / raw)
  To: Andrew Rybchenko, Thomas Monjalon
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton, Kuba Kozak

On 9/29/2021 12:54 PM, Andrew Rybchenko wrote:
> On 9/29/21 11:44 AM, Ferruh Yigit wrote:
>> On 9/28/2021 5:53 PM, Andrew Rybchenko wrote:
>>> On 9/28/21 7:50 PM, Ferruh Yigit wrote:
>>>> On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
>>>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>>
>>>>> Update xstats by IDs callbacks documentation in accordance with
>>>>> ethdev usage of these callbacks. Document valid combinations of
>>>>> input arguments to make driver implementation simpler.
>>>>>
>>>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>>>> Cc: stable@dpdk.org
>>>>>
>>>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>>>> ---
>>>>>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>>>>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>>>>> index 40e474aa7e..c89eefcc42 100644
>>>>> --- a/lib/ethdev/ethdev_driver.h
>>>>> +++ b/lib/ethdev/ethdev_driver.h
>>>>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>>>>  	struct rte_eth_xstat *stats, unsigned int n);
>>>>>  /**< @internal Get extended stats of an Ethernet device. */
>>>>>  
>>>>> +/**
>>>>> + * @internal
>>>>> + * Get extended stats of an Ethernet device.
>>>>> + *
>>>>> + * @param dev
>>>>> + *   ethdev handle of port.
>>>>> + * @param ids
>>>>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>>>>> + * @param values
>>>>> + *   A pointer to a table to be filled with device statistics values.
>>>>> + *   Must not be NULL.
>>>>> + * @param n
>>>>> + *   Element count in @p ids and @p values.
>>>>> + *
>>>>> + * @return
>>>>> + *   - A number of filled in stats.
>>>>> + *   - A negative value on error.
>>>>> + */
>>>>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>>>>  				      const uint64_t *ids,
>>>>>  				      uint64_t *values,
>>>>>  				      unsigned int n);
>>>>> -/**< @internal Get extended stats of an Ethernet device. */
>>>>>  
>>>>>  /**
>>>>>   * @internal
>>>>> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>>>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>>>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>>>>  
>>>>> +/**
>>>>> + * @internal
>>>>> + * Get names of extended stats of an Ethernet device.
>>>>> + * For name count, set @p xstats_names and @p ids to NULL.
>>>>
>>>> Why limiting this behavior to 'xstats_get_names_by_id'?
>>>>
>>>> Internally 'xstats_get_names_by_id' is used to get the count, but I think this
>>>> is not intentionally selected, just one of the xstats_*_by_id dev_ops used.
>>>>
>>>> I think it is confusing to have this support for one of the '_by_id' dev_ops but
>>>> not for other. Why not require both to support returning 'count'?
>>>
>>> Simply because it is dead code. There is no point to require
>>> from driver to have dead code.
>>>
>>
>> Let me step back a little, both ethdev APIs can be used to return xstats count
>> by providing 'values/names' & 'ids' pointers as NULL and 'size' as 0:
>> 'rte_eth_xstats_get_names_by_id()'
>> 'rte_eth_xstats_get_by_id()'
>>
>> But internally both APIs use 'xstats_get_names_by_id' dev_ops to get the count,
>> as said above I believe this selection is done unintentionally.
>>
>>
>> I am for below two options:
>>
>> a) Internally use 'xstats_get_names' || 'xstats_get' dev_ops to get the xstats
>> count, and doesn't support getting xstats count for both '_by_id' dev_ops, this
>> simplifies driver code. As far as I remember I suggested this before, still I
>> prefer this one.
>>
>> b) If we will support getting xstats count from '_by_id' dev_ops, I think both
>> should support it, to not make it more complex to figure out which one support
>> what. As sample both 'xstats_get_names' and 'xstats_get' supports getting xstats
>> count, not just one.
>>
> 
> In (b) do you suggest to change ethdev to use xstats_get_by_id
> driver op if users asks for a number of xstats using
> rte_eth_xstats_get_by_id()? It will complicate ethdev and
> will complicate drivers. Just for the symmetry?
> 

Not just for symmetry, but simplify the logic. Both dev_ops are very similar and
they are having different behavior with same parameters is confusing.
If you want to simplify the drivers why not go with option (a)? Option (a) also
doesn't change external API, and has only minor change in the ethdev layer.

> The patch does not change external API, does not change etcdev
> bahaviour. It just clarify requirements on driver ops to
> allow to check less in all drivers and support less cases
> in all drivers.
> 

It is not clarifying the requirements of dev_ops, but changing it. Previously
there was nothing saying only one of the '_by_id' dev_ops should support
returning element count.

> If we make a one more step back, frankly speaking I think we
> have too many functions to retrieve statistics. I can
> understand from ethdev API point of view taking API stability
> into account etc. But why do we have so many complicated
> driver callbacks?
> > First of all I'd like to do one more cleanup:
> change eth_xstats_get_names_by_id_t prototype to
> have ids before xstats_names.
> I.e. eth_xstats_get_by_id_t(dev, ids, values, size)
> eth_xstats_get_names_by_id_t(dev, ids, names, size)
> 

+1

> Second, merge eth_xstats_get_names_t and eth_xstats_get_names_by_id_t
> callbacks to keep
> name of the first, but prototype from the second.
> The reason is equal functionality if ids==NULL,
> shorter name of the first and optional ids (i.e. no
> reason to mention optional parameter in name).
> Drivers which do not implement by_id_t,
> but implement eth_xstats_get_names_t, will simply
> return ENOTSUP if ids!=NULL.
> 

No objection, _by_id() version is already superset of the other.

> The case of values ops is more complicated,
> however since:
> 
> 2834  * There is an assumption that 'xstat_names' and 'xstats' arrays
> are matched
> 2835  * by array index:
> 2836  *  xstats_names[i].name => xstats[i].value
> 2837  *
> 2838  * And the array index is same with id field of 'struct rte_eth_xstat':
> 2839  *  xstats[i].id == i
> 2840  *
> 2841  * This assumption makes key-value pair matching less flexible but
> simpler.
> 
> we can switch to eth_xstats_get_by_id_t only callback as
> well and fill in stats->id equal to index on ethdev layer.

When ids != NULL, the index from 'ids' can be used, isn't it.

> However, it will require extra buffer for
> uint64_t *values and copying in the rte_eth_xstats_get()
> implementation. So, I doubt in this case.
> 

Overall merging xstats _by_id APIs doesn't look bad idea, but since it will
require change in applications, I am not really sure if benefit worth the
trouble it brings to users.

> In fact, it is sad that we still do not move forward
> in accordance with Thomas presentation made 2 years ago.
> 

In my experience things don't move forward without proper plan (who, what, when).

^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [dpdk-stable] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-30 12:08             ` Ferruh Yigit
@ 2021-09-30 14:01               ` Andrew Rybchenko
  2021-09-30 15:30                 ` Ferruh Yigit
  0 siblings, 1 reply; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 14:01 UTC (permalink / raw)
  To: Ferruh Yigit, Thomas Monjalon
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton, Kuba Kozak

On 9/30/21 3:08 PM, Ferruh Yigit wrote:
> On 9/29/2021 12:54 PM, Andrew Rybchenko wrote:
>> On 9/29/21 11:44 AM, Ferruh Yigit wrote:
>>> On 9/28/2021 5:53 PM, Andrew Rybchenko wrote:
>>>> On 9/28/21 7:50 PM, Ferruh Yigit wrote:
>>>>> On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
>>>>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>>>
>>>>>> Update xstats by IDs callbacks documentation in accordance with
>>>>>> ethdev usage of these callbacks. Document valid combinations of
>>>>>> input arguments to make driver implementation simpler.
>>>>>>
>>>>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>>>>> Cc: stable@dpdk.org
>>>>>>
>>>>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>>>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>>>>> ---
>>>>>>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>>>>>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>>>>>> index 40e474aa7e..c89eefcc42 100644
>>>>>> --- a/lib/ethdev/ethdev_driver.h
>>>>>> +++ b/lib/ethdev/ethdev_driver.h
>>>>>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>>>>>  	struct rte_eth_xstat *stats, unsigned int n);
>>>>>>  /**< @internal Get extended stats of an Ethernet device. */
>>>>>>  
>>>>>> +/**
>>>>>> + * @internal
>>>>>> + * Get extended stats of an Ethernet device.
>>>>>> + *
>>>>>> + * @param dev
>>>>>> + *   ethdev handle of port.
>>>>>> + * @param ids
>>>>>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>>>>>> + * @param values
>>>>>> + *   A pointer to a table to be filled with device statistics values.
>>>>>> + *   Must not be NULL.
>>>>>> + * @param n
>>>>>> + *   Element count in @p ids and @p values.
>>>>>> + *
>>>>>> + * @return
>>>>>> + *   - A number of filled in stats.
>>>>>> + *   - A negative value on error.
>>>>>> + */
>>>>>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>>>>>  				      const uint64_t *ids,
>>>>>>  				      uint64_t *values,
>>>>>>  				      unsigned int n);
>>>>>> -/**< @internal Get extended stats of an Ethernet device. */
>>>>>>  
>>>>>>  /**
>>>>>>   * @internal
>>>>>> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>>>>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>>>>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>>>>>  
>>>>>> +/**
>>>>>> + * @internal
>>>>>> + * Get names of extended stats of an Ethernet device.
>>>>>> + * For name count, set @p xstats_names and @p ids to NULL.
>>>>>
>>>>> Why limiting this behavior to 'xstats_get_names_by_id'?
>>>>>
>>>>> Internally 'xstats_get_names_by_id' is used to get the count, but I think this
>>>>> is not intentionally selected, just one of the xstats_*_by_id dev_ops used.
>>>>>
>>>>> I think it is confusing to have this support for one of the '_by_id' dev_ops but
>>>>> not for other. Why not require both to support returning 'count'?
>>>>
>>>> Simply because it is dead code. There is no point to require
>>>> from driver to have dead code.
>>>>
>>>
>>> Let me step back a little, both ethdev APIs can be used to return xstats count
>>> by providing 'values/names' & 'ids' pointers as NULL and 'size' as 0:
>>> 'rte_eth_xstats_get_names_by_id()'
>>> 'rte_eth_xstats_get_by_id()'
>>>
>>> But internally both APIs use 'xstats_get_names_by_id' dev_ops to get the count,
>>> as said above I believe this selection is done unintentionally.
>>>
>>>
>>> I am for below two options:
>>>
>>> a) Internally use 'xstats_get_names' || 'xstats_get' dev_ops to get the xstats
>>> count, and doesn't support getting xstats count for both '_by_id' dev_ops, this
>>> simplifies driver code. As far as I remember I suggested this before, still I
>>> prefer this one.
>>>
>>> b) If we will support getting xstats count from '_by_id' dev_ops, I think both
>>> should support it, to not make it more complex to figure out which one support
>>> what. As sample both 'xstats_get_names' and 'xstats_get' supports getting xstats
>>> count, not just one.
>>>
>>
>> In (b) do you suggest to change ethdev to use xstats_get_by_id
>> driver op if users asks for a number of xstats using
>> rte_eth_xstats_get_by_id()? It will complicate ethdev and
>> will complicate drivers. Just for the symmetry?
>>
> 
> Not just for symmetry, but simplify the logic. Both dev_ops are very similar and

I'm sorry, but could you point of which logic you'd
like to simply. Less requirements on driver ops
means less code required inside.

> they are having different behavior with same parameters is confusing.

Ah, logic from PMD maintainer point of view. Does it
really worse to require extra code inside because of it?

> If you want to simplify the drivers why not go with option (a)? Option (a) also
> doesn't change external API, and has only minor change in the ethdev layer.

Is two extra patches in v6 (discussed below) a step
towards (a)?

>> The patch does not change external API, does not change etcdev
>> bahaviour. It just clarify requirements on driver ops to
>> allow to check less in all drivers and support less cases
>> in all drivers.
>>
> 
> It is not clarifying the requirements of dev_ops, but changing it. Previously
> there was nothing saying only one of the '_by_id' dev_ops should support
> returning element count.

I say "clarifying" since I adjust it a real source of
truth for internals - implementation, usage of these
callback by ethdev layer.

Yes, I agree that it changes documentation.

> 
>> If we make a one more step back, frankly speaking I think we
>> have too many functions to retrieve statistics. I can
>> understand from ethdev API point of view taking API stability
>> into account etc. But why do we have so many complicated
>> driver callbacks?
>>> First of all I'd like to do one more cleanup:
>> change eth_xstats_get_names_by_id_t prototype to
>> have ids before xstats_names.
>> I.e. eth_xstats_get_by_id_t(dev, ids, values, size)
>> eth_xstats_get_names_by_id_t(dev, ids, names, size)
>>
> 
> +1

See patch 3/4 in v6

> 
>> Second, merge eth_xstats_get_names_t and eth_xstats_get_names_by_id_t
>> callbacks to keep
>> name of the first, but prototype from the second.
>> The reason is equal functionality if ids==NULL,
>> shorter name of the first and optional ids (i.e. no
>> reason to mention optional parameter in name).
>> Drivers which do not implement by_id_t,
>> but implement eth_xstats_get_names_t, will simply
>> return ENOTSUP if ids!=NULL.
>>
> 
> No objection, _by_id() version is already superset of the other.

See patch 4/4 in v6

> 
>> The case of values ops is more complicated,
>> however since:
>>
>> 2834  * There is an assumption that 'xstat_names' and 'xstats' arrays
>> are matched
>> 2835  * by array index:
>> 2836  *  xstats_names[i].name => xstats[i].value
>> 2837  *
>> 2838  * And the array index is same with id field of 'struct rte_eth_xstat':
>> 2839  *  xstats[i].id == i
>> 2840  *
>> 2841  * This assumption makes key-value pair matching less flexible but
>> simpler.
>>
>> we can switch to eth_xstats_get_by_id_t only callback as
>> well and fill in stats->id equal to index on ethdev layer.
> 
> When ids != NULL, the index from 'ids' can be used, isn't it.

Yes, of course, but above documentation is for API without IDs.

> 
>> However, it will require extra buffer for
>> uint64_t *values and copying in the rte_eth_xstats_get()
>> implementation. So, I doubt in this case.
>>
> 
> Overall merging xstats _by_id APIs doesn't look bad idea, but since it will
> require change in applications, I am not really sure if benefit worth the
> trouble it brings to users.

Yes, I agree. I'm not going to change external API.

>> In fact, it is sad that we still do not move forward
>> in accordance with Thomas presentation made 2 years ago.
>>
> 
> In my experience things don't move forward without proper plan (who, what, when).
> 

+1

^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v6 1/4] ethdev: fix docs of functions getting xstats by IDs
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (14 preceding siblings ...)
  2021-09-28 12:05 ` [dpdk-dev] [PATCH v5 " Andrew Rybchenko
@ 2021-09-30 14:04 ` Andrew Rybchenko
  2021-09-30 14:04   ` [dpdk-dev] [PATCH v6 2/4] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
                     ` (2 more replies)
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
                   ` (2 subsequent siblings)
  18 siblings, 3 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 14:04 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: dev, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Document valid combinations of input arguments in accordance with
current implementation in ethdev.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/rte_ethdev.h | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index afdc53b674..2ad2bf2019 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2896,21 +2896,23 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param xstats_names
- *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. If set to NULL, the function returns the required number
- *   of elements.
- * @param ids
- *   IDs array given by app to retrieve specific statistics
+ *   Array to be filled in with names of requested device statistics.
+ *   Must not be NULL if @p ids are specified (not NULL).
  * @param size
- *   The size of the xstats_names array (number of elements).
+ *   Number of elements in @p xstats_names array (if not NULL) and in
+ *   @p ids array (if not NULL). Must be 0 if both array pointers are NULL.
+ * @param ids
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve names of all available statistics or, if @p xstats_names is
+ *   NULL as well, just the number of available statistics.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
- *   - A positive value higher than size: error, the given statistics table
+ *   - A positive value higher than size: success. The given statistics table
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int
 rte_eth_xstats_get_names_by_id(uint16_t port_id,
@@ -2923,22 +2925,23 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param ids
- *   A pointer to an ids array passed by application. This tells which
- *   statistics values function should retrieve. This parameter
- *   can be set to NULL if size is 0. In this case function will retrieve
- *   all available statistics.
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve all available statistics or, if @p values is NULL as well,
+ *   just the number of available statistics.
  * @param values
- *   A pointer to a table to be filled with device statistics values.
+ *   Array to be filled in with requested device statistics.
+ *   Must not be NULL if ids are specified (not NULL).
  * @param size
- *   The size of the ids array (number of elements).
+ *   Number of elements in @p values array (if not NULL) and in @p ids
+ *   array (if not NULL). Must be 0 if both array pointers are NULL.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
- *   - A positive value higher than size: error, the given statistics table
+ *   - A positive value higher than size: success: The given statistics table
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
 			     uint64_t *values, unsigned int size);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v6 2/4] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-30 14:04 ` [dpdk-dev] [PATCH v6 1/4] " Andrew Rybchenko
@ 2021-09-30 14:04   ` Andrew Rybchenko
  2021-09-30 14:04   ` [dpdk-dev] [PATCH v6 3/4] ethdev: improve xstats names by IDs get prototype Andrew Rybchenko
  2021-09-30 14:04   ` [dpdk-dev] [PATCH v6 4/4] ethdev: merge driver ops to get all xstats names and by ID Andrew Rybchenko
  2 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 14:04 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: dev, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index cc2c75261c..c05fdbf6fe 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -183,11 +183,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values.
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -214,10 +231,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats of an Ethernet device.
+ * For name count, set @p xstats_names and @p ids to NULL.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Can be NULL together with @p ids to retrieve number of
+ *   available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param size
+ *   Element count in @p ids and @p xstats_names.
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v6 3/4] ethdev: improve xstats names by IDs get prototype
  2021-09-30 14:04 ` [dpdk-dev] [PATCH v6 1/4] " Andrew Rybchenko
  2021-09-30 14:04   ` [dpdk-dev] [PATCH v6 2/4] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
@ 2021-09-30 14:04   ` Andrew Rybchenko
  2021-09-30 14:04   ` [dpdk-dev] [PATCH v6 4/4] ethdev: merge driver ops to get all xstats names and by ID Andrew Rybchenko
  2 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 14:04 UTC (permalink / raw)
  To: Somalapuram Amaranath, Nithin Dabilpuram, Kiran Kumar K,
	Sunil Kumar Kori, Satha Rao, Rahul Lakkireddy, Hemant Agrawal,
	Sachin Saxena, Haiyue Wang, Min Hu (Connor),
	Yisen Zhuang, Lijun Ou, Andrew Boyer, Jerin Jacob, Jiawen Wu,
	Jian Wang, Thomas Monjalon, Ferruh Yigit
  Cc: dev

Adjust parameters order to eth_xstats_get_by_id_t prototype.
Make ids the second parameter similar to eth_xstats_get_by_id_t.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 drivers/net/axgbe/axgbe_ethdev.c    | 4 ++--
 drivers/net/cnxk/cnxk_ethdev.h      | 3 ++-
 drivers/net/cnxk/cnxk_stats.c       | 3 ++-
 drivers/net/cxgbe/cxgbe_ethdev.c    | 3 ++-
 drivers/net/dpaa/dpaa_ethdev.c      | 2 +-
 drivers/net/dpaa2/dpaa2_ethdev.c    | 2 +-
 drivers/net/e1000/igb_ethdev.c      | 6 +++---
 drivers/net/hns3/hns3_stats.c       | 7 ++++---
 drivers/net/hns3/hns3_stats.h       | 2 +-
 drivers/net/igc/igc_ethdev.c        | 4 ++--
 drivers/net/ionic/ionic_ethdev.c    | 6 +++---
 drivers/net/ixgbe/ixgbe_ethdev.c    | 6 +++---
 drivers/net/octeontx2/otx2_ethdev.h | 3 ++-
 drivers/net/octeontx2/otx2_stats.c  | 3 ++-
 drivers/net/sfc/sfc_ethdev.c        | 3 ++-
 drivers/net/txgbe/txgbe_ethdev.c    | 2 +-
 lib/ethdev/ethdev_driver.h          | 8 ++++----
 lib/ethdev/rte_ethdev.c             | 2 +-
 18 files changed, 38 insertions(+), 31 deletions(-)

diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
index 9cb4818af1..ebd5411fdd 100644
--- a/drivers/net/axgbe/axgbe_ethdev.c
+++ b/drivers/net/axgbe/axgbe_ethdev.c
@@ -57,8 +57,8 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			   unsigned int n);
 static int
 axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 struct rte_eth_xstat_name *xstats_names,
 				 const uint64_t *ids,
+				 struct rte_eth_xstat_name *xstats_names,
 				 unsigned int size);
 static int axgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int axgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
@@ -1076,8 +1076,8 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 static int
 axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 struct rte_eth_xstat_name *xstats_names,
 				 const uint64_t *ids,
+				 struct rte_eth_xstat_name *xstats_names,
 				 unsigned int size)
 {
 	struct rte_eth_xstat_name xstats_names_copy[AXGBE_XSTATS_COUNT];
diff --git a/drivers/net/cnxk/cnxk_ethdev.h b/drivers/net/cnxk/cnxk_ethdev.h
index 10e05e6b5e..946629f72e 100644
--- a/drivers/net/cnxk/cnxk_ethdev.h
+++ b/drivers/net/cnxk/cnxk_ethdev.h
@@ -365,8 +365,9 @@ int cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
 int cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
-				    const uint64_t *ids, unsigned int limit);
+				    unsigned int limit);
 int cnxk_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev, const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int cnxk_nix_xstats_reset(struct rte_eth_dev *eth_dev);
diff --git a/drivers/net/cnxk/cnxk_stats.c b/drivers/net/cnxk/cnxk_stats.c
index 19bab2170c..4b0deac05e 100644
--- a/drivers/net/cnxk/cnxk_stats.c
+++ b/drivers/net/cnxk/cnxk_stats.c
@@ -227,8 +227,9 @@ cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 
 int
 cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, unsigned int limit)
+				unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	uint32_t nix_cnt = roc_nix_num_xstats_get(&dev->nix);
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 177eca3976..4929766d9a 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -1006,8 +1006,9 @@ static int cxgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 
 /* Get names of port extended statistics by ID. */
 static int cxgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+					    const uint64_t *ids,
 					    struct rte_eth_xstat_name *xnames,
-					    const uint64_t *ids, unsigned int n)
+					    unsigned int n)
 {
 	struct port_info *pi = dev->data->dev_private;
 	struct rte_eth_xstat_name *xnames_copy;
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index 36d8f9249d..1f80e8d744 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -815,8 +815,8 @@ dpaa_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int
 dpaa_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa_xstats_strings);
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index c12169578e..ea191564fc 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -1795,8 +1795,8 @@ dpaa2_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int
 dpaa2_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa2_xstats_strings);
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index d80fad01e3..6510cd7ceb 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -96,7 +96,7 @@ static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
 				    struct rte_eth_xstat_name *xstats_names,
 				    unsigned int size);
 static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igb_stats_reset(struct rte_eth_dev *dev);
 static int eth_igb_xstats_reset(struct rte_eth_dev *dev);
@@ -1883,7 +1883,7 @@ static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 }
 
 static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
@@ -1902,7 +1902,7 @@ static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	} else {
 		struct rte_eth_xstat_name xstats_names_copy[IGB_NB_XSTATS];
 
-		eth_igb_xstats_get_names_by_id(dev, xstats_names_copy, NULL,
+		eth_igb_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
 				IGB_NB_XSTATS);
 
 		for (i = 0; i < limit; i++) {
diff --git a/drivers/net/hns3/hns3_stats.c b/drivers/net/hns3/hns3_stats.c
index e09dc0da80..0fe853d626 100644
--- a/drivers/net/hns3/hns3_stats.c
+++ b/drivers/net/hns3/hns3_stats.c
@@ -1365,12 +1365,12 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  *
  * @param dev
  *   Pointer to Ethernet device.
+ * @param ids
+ *   IDs array given by app to retrieve specific statistics
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. If set to NULL, the function returns the required number
  *   of elements.
- * @param ids
- *   IDs array given by app to retrieve specific statistics
  * @param size
  *   The size of the xstats_names array (number of elements).
  * @return
@@ -1383,8 +1383,9 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  */
 int
 hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, uint32_t size)
+				uint32_t size)
 {
 	const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
 	struct hns3_adapter *hns = dev->data->dev_private;
diff --git a/drivers/net/hns3/hns3_stats.h b/drivers/net/hns3/hns3_stats.h
index de5c40d6b5..d1230f94cb 100644
--- a/drivers/net/hns3/hns3_stats.h
+++ b/drivers/net/hns3/hns3_stats.h
@@ -161,8 +161,8 @@ int hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			      uint64_t *values,
 			      uint32_t size);
 int hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				    struct rte_eth_xstat_name *xstats_names,
 				    const uint64_t *ids,
+				    struct rte_eth_xstat_name *xstats_names,
 				    uint32_t size);
 int hns3_stats_reset(struct rte_eth_dev *dev);
 int hns3_tqp_stats_init(struct hns3_hw *hw);
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index 224a095483..be2c066111 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -216,7 +216,7 @@ static int eth_igc_xstats_get_names(struct rte_eth_dev *dev,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int size);
 static int eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igc_xstats_reset(struct rte_eth_dev *dev);
 static int
@@ -2013,7 +2013,7 @@ eth_igc_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 static int
 eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index e620793966..344c076f30 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -52,7 +52,7 @@ static int  ionic_dev_xstats_reset(struct rte_eth_dev *dev);
 static int  ionic_dev_xstats_get_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 static int  ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int  ionic_dev_fw_version_get(struct rte_eth_dev *eth_dev,
 	char *fw_version, size_t fw_size);
@@ -733,7 +733,7 @@ ionic_dev_xstats_get_names(__rte_unused struct rte_eth_dev *eth_dev,
 
 static int
 ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[IONIC_NB_HW_STATS];
@@ -751,7 +751,7 @@ ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 		return IONIC_NB_HW_STATS;
 	}
 
-	ionic_dev_xstats_get_names_by_id(eth_dev, xstats_names_copy, NULL,
+	ionic_dev_xstats_get_names_by_id(eth_dev, NULL, xstats_names_copy,
 		IONIC_NB_HW_STATS);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 47693c0c47..aae8b55d83 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -173,8 +173,8 @@ static int ixgbevf_dev_xstats_get_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned limit);
 static int ixgbe_dev_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
 					     uint16_t queue_id,
@@ -3437,8 +3437,8 @@ static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 static int ixgbe_dev_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	if (!ids) {
@@ -3497,7 +3497,7 @@ static int ixgbe_dev_xstats_get_names_by_id(
 	uint16_t size = ixgbe_xstats_calc_num();
 	struct rte_eth_xstat_name xstats_names_copy[size];
 
-	ixgbe_dev_xstats_get_names_by_id(dev, xstats_names_copy, NULL,
+	ixgbe_dev_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
 			size);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h
index 7871e3d30b..b1575f59a2 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -514,8 +514,9 @@ int otx2_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev,
 			      const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
-				    const uint64_t *ids, unsigned int limit);
+				    unsigned int limit);
 
 /* RSS */
 void otx2_nix_rss_set_key(struct otx2_eth_dev *dev,
diff --git a/drivers/net/octeontx2/otx2_stats.c b/drivers/net/octeontx2/otx2_stats.c
index 8aaf270a7c..3adf21608c 100644
--- a/drivers/net/octeontx2/otx2_stats.c
+++ b/drivers/net/octeontx2/otx2_stats.c
@@ -240,8 +240,9 @@ otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 
 int
 otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, unsigned int limit)
+				unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[OTX2_NIX_NUM_XSTATS_REG];
 	uint16_t i;
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 2db0d000c3..f212ca8ad6 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -838,8 +838,9 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 static int
 sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
+			   const uint64_t *ids,
 			   struct rte_eth_xstat_name *xstats_names,
-			   const uint64_t *ids, unsigned int size)
+			   unsigned int size)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0063994688..b267da462b 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2451,8 +2451,8 @@ static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
 }
 
 static int txgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i;
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index c05fdbf6fe..b1b3c9bc59 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -238,13 +238,13 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *
  * @param dev
  *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. Can be NULL together with @p ids to retrieve number of
  *   available statistics.
- * @param ids
- *   IDs array to retrieve specific statistics. Can be NULL together
- *   with @p xstats_names to retrieve number of available statistics.
  * @param size
  *   Element count in @p ids and @p xstats_names.
  *
@@ -254,7 +254,7 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *   - A negative value on error.
  */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int size);
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index daf5ca9242..15e1213820 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -3029,7 +3029,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
 
 		if (no_basic_stat_requested)
 			return (*dev->dev_ops->xstats_get_names_by_id)(dev,
-					xstats_names, ids_copy, size);
+					ids_copy, xstats_names, size);
 	}
 
 	/* Retrieve all stats */
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v6 4/4] ethdev: merge driver ops to get all xstats names and by ID
  2021-09-30 14:04 ` [dpdk-dev] [PATCH v6 1/4] " Andrew Rybchenko
  2021-09-30 14:04   ` [dpdk-dev] [PATCH v6 2/4] ethdev: fix docs of drivers callbacks " Andrew Rybchenko
  2021-09-30 14:04   ` [dpdk-dev] [PATCH v6 3/4] ethdev: improve xstats names by IDs get prototype Andrew Rybchenko
@ 2021-09-30 14:04   ` Andrew Rybchenko
  2 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 14:04 UTC (permalink / raw)
  To: Igor Russkikh, Somalapuram Amaranath, Rasesh Mody, Shahed Shaikh,
	Ajit Khaparde, Somnath Kotur, Nithin Dabilpuram, Kiran Kumar K,
	Sunil Kumar Kori, Satha Rao, Rahul Lakkireddy, Hemant Agrawal,
	Sachin Saxena, Haiyue Wang, Marcin Wojtas, Michal Krawczyk,
	Shai Brandes, Evgeny Schemeilin, Igor Chauskin, Gaetan Rivet,
	Qi Zhang, Xiao Wang, Ziyang Xuan, Xiaoyun Wang, Guoyang Zhou,
	Min Hu (Connor),
	Yisen Zhuang, Lijun Ou, Beilei Xing, Jingjing Wu, Qiming Yang,
	Andrew Boyer, Rosen Xu, Shijith Thotton,
	Srisivasubramanian Srinivasan, Matan Azrad, Viacheslav Ovsiienko,
	Liron Himi, Stephen Hemminger, Long Li, Jerin Jacob,
	Devendra Singh Rawat, Jiawen Wu, Jian Wang, Maxime Coquelin,
	Chenbo Xia, Yong Wang, Thomas Monjalon, Ferruh Yigit
  Cc: dev

All xstats names may be retrieved passing NULL ids.

If a driver does not support getting names by IDs, it returns
-ENOTSUP on attempt to use it.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 doc/guides/nics/features.rst            |  2 +-
 drivers/net/atlantic/atl_ethdev.c       |  5 ++
 drivers/net/axgbe/axgbe_ethdev.c        | 30 ++++-----
 drivers/net/bnx2x/bnx2x_ethdev.c        |  4 ++
 drivers/net/bnxt/bnxt_stats.c           |  4 ++
 drivers/net/bnxt/bnxt_stats.h           |  1 +
 drivers/net/cnxk/cnxk_ethdev.c          |  1 -
 drivers/net/cnxk/cnxk_ethdev.h          |  5 +-
 drivers/net/cnxk/cnxk_stats.c           | 18 +++---
 drivers/net/cxgbe/cxgbe_ethdev.c        | 17 ++---
 drivers/net/dpaa/dpaa_ethdev.c          | 13 ++--
 drivers/net/dpaa2/dpaa2_ethdev.c        | 13 ++--
 drivers/net/e1000/igb_ethdev.c          | 36 +++--------
 drivers/net/ena/ena_ethdev.c            |  6 +-
 drivers/net/failsafe/failsafe_ops.c     |  5 +-
 drivers/net/fm10k/fm10k_ethdev.c        |  4 ++
 drivers/net/hinic/hinic_pmd_ethdev.c    |  4 ++
 drivers/net/hns3/hns3_ethdev.c          |  1 -
 drivers/net/hns3/hns3_ethdev_vf.c       |  1 -
 drivers/net/hns3/hns3_stats.c           | 22 +++----
 drivers/net/hns3/hns3_stats.h           | 10 +--
 drivers/net/i40e/i40e_ethdev.c          |  5 ++
 drivers/net/iavf/iavf_ethdev.c          | 13 ++--
 drivers/net/ice/ice_ethdev.c            |  5 ++
 drivers/net/igc/igc_ethdev.c            | 10 +--
 drivers/net/ionic/ionic_ethdev.c        | 25 +-------
 drivers/net/ipn3ke/ipn3ke_representor.c |  5 +-
 drivers/net/ixgbe/ixgbe_ethdev.c        | 71 +++------------------
 drivers/net/liquidio/lio_ethdev.c       |  4 ++
 drivers/net/mlx5/mlx5.h                 |  1 +
 drivers/net/mlx5/mlx5_stats.c           |  7 ++-
 drivers/net/mvpp2/mrvl_ethdev.c         |  4 ++
 drivers/net/netvsc/hn_ethdev.c          |  5 +-
 drivers/net/octeontx2/otx2_ethdev.c     |  1 -
 drivers/net/octeontx2/otx2_ethdev.h     |  5 +-
 drivers/net/octeontx2/otx2_stats.c      | 14 ++---
 drivers/net/qede/qede_ethdev.c          |  4 ++
 drivers/net/sfc/sfc_ethdev.c            | 84 ++++++++++++-------------
 drivers/net/txgbe/txgbe_ethdev.c        |  7 +--
 drivers/net/txgbe/txgbe_ethdev_vf.c     |  4 ++
 drivers/net/vhost/rte_eth_vhost.c       |  4 ++
 drivers/net/virtio/virtio_ethdev.c      |  5 ++
 drivers/net/vmxnet3/vmxnet3_ethdev.c    |  5 ++
 lib/ethdev/ethdev_driver.h              | 12 +---
 lib/ethdev/rte_ethdev.c                 | 14 ++---
 45 files changed, 228 insertions(+), 288 deletions(-)

diff --git a/doc/guides/nics/features.rst b/doc/guides/nics/features.rst
index 4fce8cd1c9..8fef2939fb 100644
--- a/doc/guides/nics/features.rst
+++ b/doc/guides/nics/features.rst
@@ -708,7 +708,7 @@ Extended stats
 Supports Extended Statistics, changes from driver to driver.
 
 * **[implements] eth_dev_ops**: ``xstats_get``, ``xstats_reset``, ``xstats_get_names``.
-* **[implements] eth_dev_ops**: ``xstats_get_by_id``, ``xstats_get_names_by_id``.
+* **[implements] eth_dev_ops**: ``xstats_get_by_id``.
 * **[related]    API**: ``rte_eth_xstats_get()``, ``rte_eth_xstats_reset()``,
   ``rte_eth_xstats_get_names``, ``rte_eth_xstats_get_by_id()``,
   ``rte_eth_xstats_get_names_by_id()``, ``rte_eth_xstats_get_id_by_name()``.
diff --git a/drivers/net/atlantic/atl_ethdev.c b/drivers/net/atlantic/atl_ethdev.c
index 0ce35eb519..f55d18ae9a 100644
--- a/drivers/net/atlantic/atl_ethdev.c
+++ b/drivers/net/atlantic/atl_ethdev.c
@@ -29,6 +29,7 @@ static int atl_dev_allmulticast_disable(struct rte_eth_dev *dev);
 static int  atl_dev_link_update(struct rte_eth_dev *dev, int wait);
 
 static int atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
 				    unsigned int size);
 
@@ -1003,12 +1004,16 @@ atl_dev_xstats_get_count(struct rte_eth_dev *dev)
 
 static int
 atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+			 const uint64_t *ids,
 			 struct rte_eth_xstat_name *xstats_names,
 			 unsigned int size)
 {
 	unsigned int i;
 	unsigned int count = atl_dev_xstats_get_count(dev);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names) {
 		for (i = 0; i < size && i < count; i++) {
 			snprintf(xstats_names[i].name,
diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
index ebd5411fdd..6a55a211df 100644
--- a/drivers/net/axgbe/axgbe_ethdev.c
+++ b/drivers/net/axgbe/axgbe_ethdev.c
@@ -47,19 +47,14 @@ static int axgbe_dev_xstats_get(struct rte_eth_dev *dev,
 				struct rte_eth_xstat *stats,
 				unsigned int n);
 static int
-axgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int size);
-static int
 axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			   const uint64_t *ids,
 			   uint64_t *values,
 			   unsigned int n);
 static int
-axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 const uint64_t *ids,
-				 struct rte_eth_xstat_name *xstats_names,
-				 unsigned int size);
+axgbe_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int size);
 static int axgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int axgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
 			  struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -239,7 +234,6 @@ static const struct eth_dev_ops axgbe_eth_dev_ops = {
 	.xstats_get	      = axgbe_dev_xstats_get,
 	.xstats_reset	      = axgbe_dev_xstats_reset,
 	.xstats_get_names     = axgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = axgbe_dev_xstats_get_names_by_id,
 	.xstats_get_by_id     = axgbe_dev_xstats_get_by_id,
 	.reta_update          = axgbe_dev_rss_reta_update,
 	.reta_query           = axgbe_dev_rss_reta_query,
@@ -1022,9 +1016,9 @@ axgbe_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
 }
 
 static int
-axgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int n)
+axgbe_dev_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			       struct rte_eth_xstat_name *xstats_names,
+			       unsigned int n)
 {
 	unsigned int i;
 
@@ -1075,18 +1069,18 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 const uint64_t *ids,
-				 struct rte_eth_xstat_name *xstats_names,
-				 unsigned int size)
+axgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+			   const uint64_t *ids,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int size)
 {
 	struct rte_eth_xstat_name xstats_names_copy[AXGBE_XSTATS_COUNT];
 	unsigned int i;
 
 	if (!ids)
-		return axgbe_dev_xstats_get_names(dev, xstats_names, size);
+		return axgbe_dev_xstats_get_all_names(dev, xstats_names, size);
 
-	axgbe_dev_xstats_get_names(dev, xstats_names_copy, size);
+	axgbe_dev_xstats_get_all_names(dev, xstats_names_copy, size);
 
 	for (i = 0; i < size; i++) {
 		if (ids[i] >= AXGBE_XSTATS_COUNT) {
diff --git a/drivers/net/bnx2x/bnx2x_ethdev.c b/drivers/net/bnx2x/bnx2x_ethdev.c
index 463886f17a..b18d14d735 100644
--- a/drivers/net/bnx2x/bnx2x_ethdev.c
+++ b/drivers/net/bnx2x/bnx2x_ethdev.c
@@ -484,11 +484,15 @@ bnx2x_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 static int
 bnx2x_get_xstats_names(__rte_unused struct rte_eth_dev *dev,
+		       const uint64_t *ids,
 		       struct rte_eth_xstat_name *xstats_names,
 		       __rte_unused unsigned limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(bnx2x_xstats_strings);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < stat_cnt; i++)
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index 991eafc644..aca350402b 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -845,6 +845,7 @@ int bnxt_flow_stats_cnt(struct bnxt *bp)
 }
 
 int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
+		const uint64_t *ids,
 		struct rte_eth_xstat_name *xstats_names,
 		__rte_unused unsigned int limit)
 {
@@ -862,6 +863,9 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
 	if (rc)
 		return rc;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		count = 0;
 
diff --git a/drivers/net/bnxt/bnxt_stats.h b/drivers/net/bnxt/bnxt_stats.h
index 1ca9b9c594..497380ae2d 100644
--- a/drivers/net/bnxt/bnxt_stats.h
+++ b/drivers/net/bnxt/bnxt_stats.h
@@ -13,6 +13,7 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
 			   struct rte_eth_stats *bnxt_stats);
 int bnxt_stats_reset_op(struct rte_eth_dev *eth_dev);
 int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
 	__rte_unused unsigned int limit);
 int bnxt_dev_xstats_get_op(struct rte_eth_dev *eth_dev,
diff --git a/drivers/net/cnxk/cnxk_ethdev.c b/drivers/net/cnxk/cnxk_ethdev.c
index 8629193d50..c208611e88 100644
--- a/drivers/net/cnxk/cnxk_ethdev.c
+++ b/drivers/net/cnxk/cnxk_ethdev.c
@@ -1258,7 +1258,6 @@ struct eth_dev_ops cnxk_eth_dev_ops = {
 	.xstats_get_names = cnxk_nix_xstats_get_names,
 	.xstats_reset = cnxk_nix_xstats_reset,
 	.xstats_get_by_id = cnxk_nix_xstats_get_by_id,
-	.xstats_get_names_by_id = cnxk_nix_xstats_get_names_by_id,
 	.fw_version_get = cnxk_nix_fw_version_get,
 	.rxq_info_get = cnxk_nix_rxq_info_get,
 	.txq_info_get = cnxk_nix_txq_info_get,
diff --git a/drivers/net/cnxk/cnxk_ethdev.h b/drivers/net/cnxk/cnxk_ethdev.h
index 946629f72e..1165482baf 100644
--- a/drivers/net/cnxk/cnxk_ethdev.h
+++ b/drivers/net/cnxk/cnxk_ethdev.h
@@ -362,12 +362,9 @@ int cnxk_nix_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
 int cnxk_nix_xstats_get(struct rte_eth_dev *eth_dev,
 			struct rte_eth_xstat *xstats, unsigned int n);
 int cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			      const uint64_t *ids,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
-int cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				    const uint64_t *ids,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int limit);
 int cnxk_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev, const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int cnxk_nix_xstats_reset(struct rte_eth_dev *eth_dev);
diff --git a/drivers/net/cnxk/cnxk_stats.c b/drivers/net/cnxk/cnxk_stats.c
index 4b0deac05e..ae3eef3628 100644
--- a/drivers/net/cnxk/cnxk_stats.c
+++ b/drivers/net/cnxk/cnxk_stats.c
@@ -162,10 +162,10 @@ cnxk_nix_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats,
 	return size;
 }
 
-int
-cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
-			  struct rte_eth_xstat_name *xstats_names,
-			  unsigned int limit)
+static int
+cnxk_nix_xstats_get_all_names(struct rte_eth_dev *eth_dev,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	struct roc_nix_xstat_name roc_xstats_name[limit];
@@ -226,10 +226,10 @@ cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 }
 
 int
-cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				const uint64_t *ids,
-				struct rte_eth_xstat_name *xstats_names,
-				unsigned int limit)
+cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			  const uint64_t *ids,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	uint32_t nix_cnt = roc_nix_num_xstats_get(&dev->nix);
@@ -247,7 +247,7 @@ cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 	if (xstats_names == NULL)
 		return -ENOMEM;
 
-	cnxk_nix_xstats_get_names(eth_dev, xnames, stat_cnt);
+	cnxk_nix_xstats_get_all_names(eth_dev, xnames, stat_cnt);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt)
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 4929766d9a..371550069e 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -1005,10 +1005,10 @@ static int cxgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 }
 
 /* Get names of port extended statistics by ID. */
-static int cxgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-					    const uint64_t *ids,
-					    struct rte_eth_xstat_name *xnames,
-					    unsigned int n)
+static int cxgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+				      const uint64_t *ids,
+				      struct rte_eth_xstat_name *xnames,
+				      unsigned int n)
 {
 	struct port_info *pi = dev->data->dev_private;
 	struct rte_eth_xstat_name *xnames_copy;
@@ -1048,14 +1048,6 @@ static int cxgbe_dev_xstats_get(struct rte_eth_dev *dev,
 	return cxgbe_dev_xstats(dev, NULL, xstats, n);
 }
 
-/* Get names of port extended statistics. */
-static int cxgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
-				      struct rte_eth_xstat_name *xstats_names,
-				      unsigned int n)
-{
-	return cxgbe_dev_xstats(dev, xstats_names, NULL, n);
-}
-
 /* Reset port extended statistics. */
 static int cxgbe_dev_xstats_reset(struct rte_eth_dev *dev)
 {
@@ -1620,7 +1612,6 @@ static const struct eth_dev_ops cxgbe_eth_dev_ops = {
 	.xstats_get             = cxgbe_dev_xstats_get,
 	.xstats_get_by_id       = cxgbe_dev_xstats_get_by_id,
 	.xstats_get_names       = cxgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = cxgbe_dev_xstats_get_names_by_id,
 	.xstats_reset           = cxgbe_dev_xstats_reset,
 	.flow_ctrl_get		= cxgbe_flow_ctrl_get,
 	.flow_ctrl_set		= cxgbe_flow_ctrl_set,
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index 1f80e8d744..06e293b17f 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -758,9 +758,9 @@ dpaa_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int
-dpaa_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-		      struct rte_eth_xstat_name *xstats_names,
-		      unsigned int limit)
+dpaa_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa_xstats_strings);
 
@@ -813,7 +813,7 @@ dpaa_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-dpaa_xstats_get_names_by_id(
+dpaa_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -823,9 +823,9 @@ dpaa_xstats_get_names_by_id(
 	struct rte_eth_xstat_name xstats_names_copy[stat_cnt];
 
 	if (!ids)
-		return dpaa_xstats_get_names(dev, xstats_names, limit);
+		return dpaa_xstats_get_all_names(dev, xstats_names, limit);
 
-	dpaa_xstats_get_names(dev, xstats_names_copy, limit);
+	dpaa_xstats_get_all_names(dev, xstats_names_copy, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt) {
@@ -1585,7 +1585,6 @@ static struct eth_dev_ops dpaa_devops = {
 	.stats_get		  = dpaa_eth_stats_get,
 	.xstats_get		  = dpaa_dev_xstats_get,
 	.xstats_get_by_id	  = dpaa_xstats_get_by_id,
-	.xstats_get_names_by_id	  = dpaa_xstats_get_names_by_id,
 	.xstats_get_names	  = dpaa_xstats_get_names,
 	.xstats_reset		  = dpaa_eth_stats_reset,
 	.stats_reset		  = dpaa_eth_stats_reset,
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index ea191564fc..9aaeb0bc17 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -1711,9 +1711,9 @@ dpaa2_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int
-dpaa2_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-		       struct rte_eth_xstat_name *xstats_names,
-		       unsigned int limit)
+dpaa2_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa2_xstats_strings);
 
@@ -1793,7 +1793,7 @@ dpaa2_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-dpaa2_xstats_get_names_by_id(
+dpaa2_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -1803,9 +1803,9 @@ dpaa2_xstats_get_names_by_id(
 	struct rte_eth_xstat_name xstats_names_copy[stat_cnt];
 
 	if (!ids)
-		return dpaa2_xstats_get_names(dev, xstats_names, limit);
+		return dpaa2_xstats_get_all_names(dev, xstats_names, limit);
 
-	dpaa2_xstats_get_names(dev, xstats_names_copy, limit);
+	dpaa2_xstats_get_all_names(dev, xstats_names_copy, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt) {
@@ -2413,7 +2413,6 @@ static struct eth_dev_ops dpaa2_ethdev_ops = {
 	.stats_get	       = dpaa2_dev_stats_get,
 	.xstats_get	       = dpaa2_dev_xstats_get,
 	.xstats_get_by_id     = dpaa2_xstats_get_by_id,
-	.xstats_get_names_by_id = dpaa2_xstats_get_names_by_id,
 	.xstats_get_names      = dpaa2_xstats_get_names,
 	.stats_reset	   = dpaa2_dev_stats_reset,
 	.xstats_reset	      = dpaa2_dev_stats_reset,
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 6510cd7ceb..8bf254a802 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -93,9 +93,6 @@ static int eth_igb_xstats_get_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids,
 		uint64_t *values, unsigned int n);
 static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int size);
-static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igb_stats_reset(struct rte_eth_dev *dev);
@@ -166,6 +163,7 @@ static int eth_igbvf_stats_get(struct rte_eth_dev *dev,
 static int eth_igbvf_xstats_get(struct rte_eth_dev *dev,
 				struct rte_eth_xstat *xstats, unsigned n);
 static int eth_igbvf_xstats_get_names(struct rte_eth_dev *dev,
+				      const uint64_t *ids,
 				      struct rte_eth_xstat_name *xstats_names,
 				      unsigned limit);
 static int eth_igbvf_stats_reset(struct rte_eth_dev *dev);
@@ -343,7 +341,6 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.stats_get            = eth_igb_stats_get,
 	.xstats_get           = eth_igb_xstats_get,
 	.xstats_get_by_id     = eth_igb_xstats_get_by_id,
-	.xstats_get_names_by_id = eth_igb_xstats_get_names_by_id,
 	.xstats_get_names     = eth_igb_xstats_get_names,
 	.stats_reset          = eth_igb_stats_reset,
 	.xstats_reset         = eth_igb_xstats_reset,
@@ -1863,26 +1860,7 @@ eth_igb_xstats_reset(struct rte_eth_dev *dev)
 	return 0;
 }
 
-static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
-	__rte_unused unsigned int size)
-{
-	unsigned i;
-
-	if (xstats_names == NULL)
-		return IGB_NB_XSTATS;
-
-	/* Note: limit checked in rte_eth_xstats_names() */
-
-	for (i = 0; i < IGB_NB_XSTATS; i++) {
-		strlcpy(xstats_names[i].name, rte_igb_stats_strings[i].name,
-			sizeof(xstats_names[i].name));
-	}
-
-	return IGB_NB_XSTATS;
-}
-
-static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
+static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
@@ -1902,7 +1880,7 @@ static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	} else {
 		struct rte_eth_xstat_name xstats_names_copy[IGB_NB_XSTATS];
 
-		eth_igb_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
+		eth_igb_xstats_get_names(dev, NULL, xstats_names_copy,
 				IGB_NB_XSTATS);
 
 		for (i = 0; i < limit; i++) {
@@ -2035,11 +2013,15 @@ igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats)
 }
 
 static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-				     struct rte_eth_xstat_name *xstats_names,
-				     __rte_unused unsigned limit)
+				      const uint64_t *ids,
+				      struct rte_eth_xstat_name *xstats_names,
+				      __rte_unused unsigned limit)
 {
 	unsigned i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < IGBVF_NB_XSTATS; i++) {
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index 4cebf60a68..a807e50dba 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -212,7 +212,7 @@ static void ena_interrupt_handler_rte(void *cb_arg);
 static void ena_timer_wd_callback(struct rte_timer *timer, void *arg);
 static void ena_destroy_device(struct rte_eth_dev *eth_dev);
 static int eth_ena_dev_init(struct rte_eth_dev *eth_dev);
-static int ena_xstats_get_names(struct rte_eth_dev *dev,
+static int ena_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n);
 static int ena_xstats_get(struct rte_eth_dev *dev,
@@ -2585,12 +2585,16 @@ int ena_copy_eni_stats(struct ena_adapter *adapter)
  *   Number of xstats names.
  */
 static int ena_xstats_get_names(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n)
 {
 	unsigned int xstats_count = ena_xstats_calc_num(dev->data);
 	unsigned int stat, i, count = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (n < xstats_count || !xstats_names)
 		return xstats_count;
 
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 5ff33e03e0..dae85b7677 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -990,12 +990,15 @@ __fs_xstats_get_names(struct rte_eth_dev *dev,
 }
 
 static int
-fs_xstats_get_names(struct rte_eth_dev *dev,
+fs_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 		    struct rte_eth_xstat_name *xstats_names,
 		    unsigned int limit)
 {
 	int ret;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	fs_lock(dev, 0);
 	ret = __fs_xstats_get_names(dev, xstats_names, limit);
 	fs_unlock(dev, 0);
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index 3236290e40..16af1751f9 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1232,11 +1232,15 @@ fm10k_link_update(struct rte_eth_dev *dev,
 }
 
 static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned limit)
 {
 	unsigned i, q;
 	unsigned count = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		/* Note: limit checked in rte_eth_xstats_names() */
 
diff --git a/drivers/net/hinic/hinic_pmd_ethdev.c b/drivers/net/hinic/hinic_pmd_ethdev.c
index c01e2ec1d4..bc6f07d070 100644
--- a/drivers/net/hinic/hinic_pmd_ethdev.c
+++ b/drivers/net/hinic/hinic_pmd_ethdev.c
@@ -2280,6 +2280,7 @@ static void hinic_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
  *   Number of xstats names.
  */
 static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
+			       const uint64_t *ids,
 			       struct rte_eth_xstat_name *xstats_names,
 			       __rte_unused unsigned int limit)
 {
@@ -2287,6 +2288,9 @@ static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
 	int count = 0;
 	u16 i = 0, q_num;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return hinic_xstats_calc_num(nic_dev);
 
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 7d37004972..87ae92080f 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -7413,7 +7413,6 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
 	.xstats_get_names   = hns3_dev_xstats_get_names,
 	.xstats_reset       = hns3_dev_xstats_reset,
 	.xstats_get_by_id   = hns3_dev_xstats_get_by_id,
-	.xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
 	.dev_infos_get          = hns3_dev_infos_get,
 	.fw_version_get         = hns3_fw_version_get,
 	.rx_queue_setup         = hns3_rx_queue_setup,
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 8d9b7979c8..d65236e003 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -2905,7 +2905,6 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
 	.xstats_get_names   = hns3_dev_xstats_get_names,
 	.xstats_reset       = hns3_dev_xstats_reset,
 	.xstats_get_by_id   = hns3_dev_xstats_get_by_id,
-	.xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
 	.dev_infos_get      = hns3vf_dev_infos_get,
 	.fw_version_get     = hns3vf_fw_version_get,
 	.rx_queue_setup     = hns3_rx_queue_setup,
diff --git a/drivers/net/hns3/hns3_stats.c b/drivers/net/hns3/hns3_stats.c
index 0fe853d626..abb2d42144 100644
--- a/drivers/net/hns3/hns3_stats.c
+++ b/drivers/net/hns3/hns3_stats.c
@@ -1189,7 +1189,7 @@ hns3_imissed_stats_name_get(struct rte_eth_dev *dev,
 }
 
 /*
- * Retrieve names of extended statistics of an Ethernet device.
+ * Retrieve all names of extended statistics of an Ethernet device.
  *
  * There is an assumption that 'xstat_names' and 'xstats' arrays are matched
  * by array index:
@@ -1212,10 +1212,10 @@ hns3_imissed_stats_name_get(struct rte_eth_dev *dev,
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
  */
-int
-hns3_dev_xstats_get_names(struct rte_eth_dev *dev,
-			  struct rte_eth_xstat_name *xstats_names,
-			  __rte_unused unsigned int size)
+static int
+hns3_dev_xstats_get_all_names(struct rte_eth_dev *dev,
+			      struct rte_eth_xstat_name *xstats_names,
+			      __rte_unused unsigned int size)
 {
 	struct hns3_adapter *hns = dev->data->dev_private;
 	int cnt_stats = hns3_xstats_calc_num(dev);
@@ -1382,10 +1382,9 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  *     shall not be used by the caller.
  */
 int
-hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				const uint64_t *ids,
-				struct rte_eth_xstat_name *xstats_names,
-				uint32_t size)
+hns3_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+			  struct rte_eth_xstat_name *xstats_names,
+			  uint32_t size)
 {
 	const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
 	struct hns3_adapter *hns = dev->data->dev_private;
@@ -1401,7 +1400,8 @@ hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		if (size < cnt_stats)
 			return cnt_stats;
 
-		return hns3_dev_xstats_get_names(dev, xstats_names, cnt_stats);
+		return hns3_dev_xstats_get_all_names(dev, xstats_names,
+						     cnt_stats);
 	}
 
 	len = cnt_stats * sizeof(struct rte_eth_xstat_name);
@@ -1412,7 +1412,7 @@ hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		return -ENOMEM;
 	}
 
-	(void)hns3_dev_xstats_get_names(dev, names_copy, cnt_stats);
+	(void)hns3_dev_xstats_get_all_names(dev, names_copy, cnt_stats);
 
 	for (i = 0; i < size; i++) {
 		if (ids[i] >= cnt_stats) {
diff --git a/drivers/net/hns3/hns3_stats.h b/drivers/net/hns3/hns3_stats.h
index d1230f94cb..53fd1572f0 100644
--- a/drivers/net/hns3/hns3_stats.h
+++ b/drivers/net/hns3/hns3_stats.h
@@ -153,17 +153,13 @@ int hns3_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats);
 int hns3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 			unsigned int n);
 int hns3_dev_xstats_reset(struct rte_eth_dev *dev);
-int hns3_dev_xstats_get_names(struct rte_eth_dev *dev,
-			      struct rte_eth_xstat_name *xstats_names,
-			      __rte_unused unsigned int size);
 int hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			      const uint64_t *ids,
 			      uint64_t *values,
 			      uint32_t size);
-int hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				    const uint64_t *ids,
-				    struct rte_eth_xstat_name *xstats_names,
-				    uint32_t size);
+int hns3_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int size);
 int hns3_stats_reset(struct rte_eth_dev *dev);
 int hns3_tqp_stats_init(struct hns3_hw *hw);
 void hns3_tqp_stats_uninit(struct hns3_hw *hw);
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 7a2a8281d2..832c9bff01 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -258,6 +258,7 @@ static int i40e_dev_stats_get(struct rte_eth_dev *dev,
 static int i40e_dev_xstats_get(struct rte_eth_dev *dev,
 			       struct rte_eth_xstat *xstats, unsigned n);
 static int i40e_dev_xstats_get_names(struct rte_eth_dev *dev,
+				     const uint64_t *ids,
 				     struct rte_eth_xstat_name *xstats_names,
 				     unsigned limit);
 static int i40e_dev_stats_reset(struct rte_eth_dev *dev);
@@ -3567,12 +3568,16 @@ i40e_xstats_calc_num(void)
 }
 
 static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+				     const uint64_t *ids,
 				     struct rte_eth_xstat_name *xstats_names,
 				     __rte_unused unsigned limit)
 {
 	unsigned count = 0;
 	unsigned i, prio;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return i40e_xstats_calc_num();
 
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 5a5a7f59e1..a7be7abf1a 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -87,8 +87,9 @@ static int iavf_dev_stats_reset(struct rte_eth_dev *dev);
 static int iavf_dev_xstats_get(struct rte_eth_dev *dev,
 				 struct rte_eth_xstat *xstats, unsigned int n);
 static int iavf_dev_xstats_get_names(struct rte_eth_dev *dev,
-				       struct rte_eth_xstat_name *xstats_names,
-				       unsigned int limit);
+				     const uint64_t *ids,
+				     struct rte_eth_xstat_name *xstats_names,
+				     unsigned int limit);
 static int iavf_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static int iavf_dev_promiscuous_disable(struct rte_eth_dev *dev);
 static int iavf_dev_allmulticast_enable(struct rte_eth_dev *dev);
@@ -1611,11 +1612,15 @@ iavf_dev_stats_reset(struct rte_eth_dev *dev)
 }
 
 static int iavf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-				      struct rte_eth_xstat_name *xstats_names,
-				      __rte_unused unsigned int limit)
+				     const uint64_t *ids,
+				     struct rte_eth_xstat_name *xstats_names,
+				     __rte_unused unsigned int limit)
 {
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < IAVF_NB_XSTATS; i++) {
 			snprintf(xstats_names[i].name,
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index ea3b5c02aa..adeb5a00f3 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -145,6 +145,7 @@ static int ice_stats_reset(struct rte_eth_dev *dev);
 static int ice_xstats_get(struct rte_eth_dev *dev,
 			  struct rte_eth_xstat *xstats, unsigned int n);
 static int ice_xstats_get_names(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int limit);
 static int ice_dev_flow_ops_get(struct rte_eth_dev *dev,
@@ -5420,12 +5421,16 @@ ice_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int ice_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				__rte_unused unsigned int limit)
 {
 	unsigned int count = 0;
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return ice_xstats_calc_num();
 
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index be2c066111..969e515a5f 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -213,9 +213,6 @@ static int eth_igc_xstats_get_by_id(struct rte_eth_dev *dev,
 				const uint64_t *ids,
 				uint64_t *values, unsigned int n);
 static int eth_igc_xstats_get_names(struct rte_eth_dev *dev,
-				struct rte_eth_xstat_name *xstats_names,
-				unsigned int size);
-static int eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igc_xstats_reset(struct rte_eth_dev *dev);
@@ -280,7 +277,6 @@ static const struct eth_dev_ops eth_igc_ops = {
 	.stats_get		= eth_igc_stats_get,
 	.xstats_get		= eth_igc_xstats_get,
 	.xstats_get_by_id	= eth_igc_xstats_get_by_id,
-	.xstats_get_names_by_id	= eth_igc_xstats_get_names_by_id,
 	.xstats_get_names	= eth_igc_xstats_get_names,
 	.stats_reset		= eth_igc_xstats_reset,
 	.xstats_reset		= eth_igc_xstats_reset,
@@ -1991,7 +1987,7 @@ eth_igc_xstats_reset(struct rte_eth_dev *dev)
 }
 
 static int
-eth_igc_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+eth_igc_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size)
 {
 	unsigned int i;
@@ -2012,14 +2008,14 @@ eth_igc_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 }
 
 static int
-eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
+eth_igc_xstats_get_names(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
 
 	if (!ids)
-		return eth_igc_xstats_get_names(dev, xstats_names, limit);
+		return eth_igc_xstats_get_all_names(dev, xstats_names, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= IGC_NB_XSTATS) {
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 344c076f30..d813e9f909 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -50,8 +50,6 @@ static int  ionic_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 	const uint64_t *ids, uint64_t *values, unsigned int n);
 static int  ionic_dev_xstats_reset(struct rte_eth_dev *dev);
 static int  ionic_dev_xstats_get_names(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, unsigned int size);
-static int  ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int  ionic_dev_fw_version_get(struct rte_eth_dev *eth_dev,
@@ -119,7 +117,6 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.xstats_get_by_id       = ionic_dev_xstats_get_by_id,
 	.xstats_reset           = ionic_dev_xstats_reset,
 	.xstats_get_names       = ionic_dev_xstats_get_names,
-	.xstats_get_names_by_id = ionic_dev_xstats_get_names_by_id,
 	.fw_version_get         = ionic_dev_fw_version_get,
 };
 
@@ -714,25 +711,7 @@ ionic_dev_stats_reset(struct rte_eth_dev *eth_dev)
 }
 
 static int
-ionic_dev_xstats_get_names(__rte_unused struct rte_eth_dev *eth_dev,
-		struct rte_eth_xstat_name *xstats_names,
-		__rte_unused unsigned int size)
-{
-	unsigned int i;
-
-	if (xstats_names != NULL) {
-		for (i = 0; i < IONIC_NB_HW_STATS; i++) {
-			snprintf(xstats_names[i].name,
-					sizeof(xstats_names[i].name),
-					"%s", rte_ionic_xstats_strings[i].name);
-		}
-	}
-
-	return IONIC_NB_HW_STATS;
-}
-
-static int
-ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+ionic_dev_xstats_get_names(struct rte_eth_dev *eth_dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
@@ -751,7 +730,7 @@ ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 		return IONIC_NB_HW_STATS;
 	}
 
-	ionic_dev_xstats_get_names_by_id(eth_dev, NULL, xstats_names_copy,
+	ionic_dev_xstats_get_names(eth_dev, NULL, xstats_names_copy,
 		IONIC_NB_HW_STATS);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c
index 589d9fa587..5312b955d6 100644
--- a/drivers/net/ipn3ke/ipn3ke_representor.c
+++ b/drivers/net/ipn3ke/ipn3ke_representor.c
@@ -2329,13 +2329,16 @@ ipn3ke_rpst_xstats_get
 
 static int
 ipn3ke_rpst_xstats_get_names
-(__rte_unused struct rte_eth_dev *dev,
+(__rte_unused struct rte_eth_dev *dev, const uint64_t *ids,
 struct rte_eth_xstat_name *xstats_names,
 __rte_unused unsigned int limit)
 {
 	unsigned int count = 0;
 	unsigned int i, prio;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return ipn3ke_rpst_xstats_calc_num();
 
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index aae8b55d83..51b86ea5ce 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -167,15 +167,12 @@ ixgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int ixgbe_dev_stats_reset(struct rte_eth_dev *dev);
 static int ixgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int ixgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
 	unsigned int size);
 static int ixgbevf_dev_xstats_get_names(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, unsigned limit);
-static int ixgbe_dev_xstats_get_names_by_id(
-	struct rte_eth_dev *dev,
 	const uint64_t *ids,
-	struct rte_eth_xstat_name *xstats_names,
-	unsigned int limit);
+	struct rte_eth_xstat_name *xstats_names, unsigned limit);
 static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
 					     uint16_t queue_id,
 					     uint8_t stat_idx,
@@ -499,7 +496,6 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.stats_reset          = ixgbe_dev_stats_reset,
 	.xstats_reset         = ixgbe_dev_xstats_reset,
 	.xstats_get_names     = ixgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = ixgbe_dev_xstats_get_names_by_id,
 	.queue_stats_mapping_set = ixgbe_dev_queue_stats_mapping_set,
 	.fw_version_get       = ixgbe_fw_version_get,
 	.dev_infos_get        = ixgbe_dev_info_get,
@@ -3381,61 +3377,7 @@ ixgbe_xstats_calc_num(void) {
 		(IXGBE_NB_TXQ_PRIO_STATS * IXGBE_NB_TXQ_PRIO_VALUES);
 }
 
-static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned int size)
-{
-	const unsigned cnt_stats = ixgbe_xstats_calc_num();
-	unsigned stat, i, count;
-
-	if (xstats_names != NULL) {
-		count = 0;
-
-		/* Note: limit >= cnt_stats checked upstream
-		 * in rte_eth_xstats_names()
-		 */
-
-		/* Extended stats from ixgbe_hw_stats */
-		for (i = 0; i < IXGBE_NB_HW_STATS; i++) {
-			strlcpy(xstats_names[count].name,
-				rte_ixgbe_stats_strings[i].name,
-				sizeof(xstats_names[count].name));
-			count++;
-		}
-
-		/* MACsec Stats */
-		for (i = 0; i < IXGBE_NB_MACSEC_STATS; i++) {
-			strlcpy(xstats_names[count].name,
-				rte_ixgbe_macsec_strings[i].name,
-				sizeof(xstats_names[count].name));
-			count++;
-		}
-
-		/* RX Priority Stats */
-		for (stat = 0; stat < IXGBE_NB_RXQ_PRIO_STATS; stat++) {
-			for (i = 0; i < IXGBE_NB_RXQ_PRIO_VALUES; i++) {
-				snprintf(xstats_names[count].name,
-					sizeof(xstats_names[count].name),
-					"rx_priority%u_%s", i,
-					rte_ixgbe_rxq_strings[stat].name);
-				count++;
-			}
-		}
-
-		/* TX Priority Stats */
-		for (stat = 0; stat < IXGBE_NB_TXQ_PRIO_STATS; stat++) {
-			for (i = 0; i < IXGBE_NB_TXQ_PRIO_VALUES; i++) {
-				snprintf(xstats_names[count].name,
-					sizeof(xstats_names[count].name),
-					"tx_priority%u_%s", i,
-					rte_ixgbe_txq_strings[stat].name);
-				count++;
-			}
-		}
-	}
-	return cnt_stats;
-}
-
-static int ixgbe_dev_xstats_get_names_by_id(
+static int ixgbe_dev_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -3497,8 +3439,7 @@ static int ixgbe_dev_xstats_get_names_by_id(
 	uint16_t size = ixgbe_xstats_calc_num();
 	struct rte_eth_xstat_name xstats_names_copy[size];
 
-	ixgbe_dev_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
-			size);
+	ixgbe_dev_xstats_get_names(dev, NULL, xstats_names_copy, size);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= size) {
@@ -3512,6 +3453,7 @@ static int ixgbe_dev_xstats_get_names_by_id(
 }
 
 static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names, unsigned limit)
 {
 	unsigned i;
@@ -3519,6 +3461,9 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	if (limit < IXGBEVF_NB_XSTATS && xstats_names != NULL)
 		return -ENOMEM;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < IXGBEVF_NB_XSTATS; i++)
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/liquidio/lio_ethdev.c b/drivers/net/liquidio/lio_ethdev.c
index b72060a449..68b674c2a6 100644
--- a/drivers/net/liquidio/lio_ethdev.c
+++ b/drivers/net/liquidio/lio_ethdev.c
@@ -214,6 +214,7 @@ lio_dev_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats,
 
 static int
 lio_dev_xstats_get_names(struct rte_eth_dev *eth_dev,
+			 const uint64_t *ids,
 			 struct rte_eth_xstat_name *xstats_names,
 			 unsigned limit __rte_unused)
 {
@@ -226,6 +227,9 @@ lio_dev_xstats_get_names(struct rte_eth_dev *eth_dev,
 		return -EINVAL;
 	}
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return LIO_NB_XSTATS;
 
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 3581414b78..4eab2554bc 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1620,6 +1620,7 @@ int mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
 		    unsigned int n);
 int mlx5_xstats_reset(struct rte_eth_dev *dev);
 int mlx5_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+			  const uint64_t *ids,
 			  struct rte_eth_xstat_name *xstats_names,
 			  unsigned int n);
 
diff --git a/drivers/net/mlx5/mlx5_stats.c b/drivers/net/mlx5/mlx5_stats.c
index ae2f5668a7..d67afd6bc1 100644
--- a/drivers/net/mlx5/mlx5_stats.c
+++ b/drivers/net/mlx5/mlx5_stats.c
@@ -260,6 +260,8 @@ mlx5_xstats_reset(struct rte_eth_dev *dev)
  *
  * @param dev
  *   Pointer to Ethernet device structure.
+ * @param ids
+ *   Array of xstats IDs to get names
  * @param[out] xstats_names
  *   Buffer to insert names into.
  * @param n
@@ -269,7 +271,7 @@ mlx5_xstats_reset(struct rte_eth_dev *dev)
  *   Number of xstats names.
  */
 int
-mlx5_xstats_get_names(struct rte_eth_dev *dev,
+mlx5_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 		      struct rte_eth_xstat_name *xstats_names, unsigned int n)
 {
 	unsigned int i;
@@ -277,6 +279,9 @@ mlx5_xstats_get_names(struct rte_eth_dev *dev,
 	struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
 	unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (n >= mlx5_xstats_n && xstats_names) {
 		for (i = 0; i != mlx5_xstats_n; ++i) {
 			strncpy(xstats_names[i].name,
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 078aefbb8d..554aba1be9 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -1689,11 +1689,15 @@ mrvl_xstats_reset(struct rte_eth_dev *dev)
  */
 static int
 mrvl_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+		      const uint64_t *ids,
 		      struct rte_eth_xstat_name *xstats_names,
 		      unsigned int size)
 {
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return RTE_DIM(mrvl_xstats_tbl);
 
diff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c
index 9e2a405973..4260f0b4ab 100644
--- a/drivers/net/netvsc/hn_ethdev.c
+++ b/drivers/net/netvsc/hn_ethdev.c
@@ -851,13 +851,16 @@ hn_dev_xstats_count(struct rte_eth_dev *dev)
 }
 
 static int
-hn_dev_xstats_get_names(struct rte_eth_dev *dev,
+hn_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 			struct rte_eth_xstat_name *xstats_names,
 			unsigned int limit)
 {
 	unsigned int i, t, count = 0;
 	int ret;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return hn_dev_xstats_count(dev);
 
diff --git a/drivers/net/octeontx2/otx2_ethdev.c b/drivers/net/octeontx2/otx2_ethdev.c
index 75d4cabf2e..c1fd2ad7d5 100644
--- a/drivers/net/octeontx2/otx2_ethdev.c
+++ b/drivers/net/octeontx2/otx2_ethdev.c
@@ -2338,7 +2338,6 @@ static const struct eth_dev_ops otx2_eth_dev_ops = {
 	.xstats_get_names         = otx2_nix_xstats_get_names,
 	.xstats_reset             = otx2_nix_xstats_reset,
 	.xstats_get_by_id         = otx2_nix_xstats_get_by_id,
-	.xstats_get_names_by_id   = otx2_nix_xstats_get_names_by_id,
 	.rxq_info_get             = otx2_nix_rxq_info_get,
 	.txq_info_get             = otx2_nix_txq_info_get,
 	.rx_burst_mode_get        = otx2_rx_burst_mode_get,
diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h
index b1575f59a2..1eeb77c9dd 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -506,6 +506,7 @@ int otx2_nix_queue_stats_mapping(struct rte_eth_dev *dev,
 int otx2_nix_xstats_get(struct rte_eth_dev *eth_dev,
 			struct rte_eth_xstat *xstats, unsigned int n);
 int otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			      const uint64_t *ids,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
 int otx2_nix_xstats_reset(struct rte_eth_dev *eth_dev);
@@ -513,10 +514,6 @@ int otx2_nix_xstats_reset(struct rte_eth_dev *eth_dev);
 int otx2_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev,
 			      const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
-int otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				    const uint64_t *ids,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int limit);
 
 /* RSS */
 void otx2_nix_rss_set_key(struct otx2_eth_dev *dev,
diff --git a/drivers/net/octeontx2/otx2_stats.c b/drivers/net/octeontx2/otx2_stats.c
index 3adf21608c..70bfaa3d77 100644
--- a/drivers/net/octeontx2/otx2_stats.c
+++ b/drivers/net/octeontx2/otx2_stats.c
@@ -200,8 +200,8 @@ otx2_nix_xstats_get(struct rte_eth_dev *eth_dev,
 	return count;
 }
 
-int
-otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+static int
+otx2_nix_xstats_get_all_names(struct rte_eth_dev *eth_dev,
 			  struct rte_eth_xstat_name *xstats_names,
 			  unsigned int limit)
 {
@@ -239,10 +239,10 @@ otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 }
 
 int
-otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				const uint64_t *ids,
-				struct rte_eth_xstat_name *xstats_names,
-				unsigned int limit)
+otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			  const uint64_t *ids,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[OTX2_NIX_NUM_XSTATS_REG];
 	uint16_t i;
@@ -256,7 +256,7 @@ otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 	if (xstats_names == NULL)
 		return -ENOMEM;
 
-	otx2_nix_xstats_get_names(eth_dev, xstats_names_copy, limit);
+	otx2_nix_xstats_get_all_names(eth_dev, xstats_names_copy, limit);
 
 	for (i = 0; i < OTX2_NIX_NUM_XSTATS_REG; i++) {
 		if (ids[i] >= OTX2_NIX_NUM_XSTATS_REG) {
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index a4304e0eff..40443b30bf 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -1718,6 +1718,7 @@ qede_get_xstats_count(struct qede_dev *qdev) {
 
 static int
 qede_get_xstats_names(struct rte_eth_dev *dev,
+		      const uint64_t *ids,
 		      struct rte_eth_xstat_name *xstats_names,
 		      __rte_unused unsigned int limit)
 {
@@ -1726,6 +1727,9 @@ qede_get_xstats_names(struct rte_eth_dev *dev,
 	const unsigned int stat_cnt = qede_get_xstats_count(qdev);
 	unsigned int i, qid, hw_fn, stat_idx = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return stat_cnt;
 
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index f212ca8ad6..d05a1fb5ca 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -763,43 +763,6 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	return nb_supported;
 }
 
-static int
-sfc_xstats_get_names(struct rte_eth_dev *dev,
-		     struct rte_eth_xstat_name *xstats_names,
-		     unsigned int xstats_count)
-{
-	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
-	unsigned int i;
-	unsigned int nstats = 0;
-	unsigned int nb_written = 0;
-	int ret;
-
-	if (unlikely(xstats_names == NULL))
-		return sfc_xstats_get_nb_supported(sa);
-
-	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < xstats_count) {
-				strlcpy(xstats_names[nstats].name,
-					efx_mac_stat_name(sa->nic, i),
-					sizeof(xstats_names[0].name));
-				nb_written++;
-			}
-			nstats++;
-		}
-	}
-
-	ret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,
-				      &nb_written, &nstats);
-	if (ret != 0) {
-		SFC_ASSERT(ret < 0);
-		return ret;
-	}
-
-	return nstats;
-}
-
 static int
 sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
@@ -837,10 +800,42 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-			   const uint64_t *ids,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int size)
+sfc_xstats_get_all_names(struct sfc_adapter *sa,
+			 struct rte_eth_xstat_name *xstats_names,
+			 unsigned int xstats_count)
+{
+	struct sfc_port *port = &sa->port;
+	unsigned int i;
+	unsigned int nstats = 0;
+	unsigned int nb_written = 0;
+	int ret;
+
+	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
+		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
+			if (nstats < xstats_count) {
+				strlcpy(xstats_names[nstats].name,
+					efx_mac_stat_name(sa->nic, i),
+					sizeof(xstats_names[0].name));
+				nb_written++;
+			}
+			nstats++;
+		}
+	}
+
+	ret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,
+				      &nb_written, &nstats);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
+	return nstats;
+}
+
+static int
+sfc_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+		     struct rte_eth_xstat_name *xstats_names,
+		     unsigned int size)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
@@ -848,13 +843,15 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int i;
 	int ret;
 
-	if (unlikely(xstats_names == NULL && ids != NULL) ||
-	    unlikely(xstats_names != NULL && ids == NULL))
+	if (unlikely(xstats_names == NULL && ids != NULL))
 		return -EINVAL;
 
 	if (unlikely(xstats_names == NULL && ids == NULL))
 		return sfc_xstats_get_nb_supported(sa);
 
+	if (ids == NULL)
+		return sfc_xstats_get_all_names(sa, xstats_names, size);
+
 	/*
 	 * Names array could be filled in nonsequential order. Fill names with
 	 * string indicating invalid ID first.
@@ -1905,7 +1902,6 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {
 	.txq_info_get			= sfc_tx_queue_info_get,
 	.fw_version_get			= sfc_fw_version_get,
 	.xstats_get_by_id		= sfc_xstats_get_by_id,
-	.xstats_get_names_by_id		= sfc_xstats_get_names_by_id,
 	.pool_ops_supported		= sfc_pool_ops_supported,
 };
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index b267da462b..be6e073141 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2424,7 +2424,7 @@ txgbe_get_offset_by_id(uint32_t id, uint32_t *offset)
 	return -1;
 }
 
-static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+static int txgbe_dev_xstats_get_all_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int limit)
 {
 	unsigned int i, count;
@@ -2450,7 +2450,7 @@ static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
 	return i;
 }
 
-static int txgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
@@ -2458,7 +2458,7 @@ static int txgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int i;
 
 	if (ids == NULL)
-		return txgbe_dev_xstats_get_names(dev, xstats_names, limit);
+		return txgbe_dev_xstats_get_all_names(dev, xstats_names, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (txgbe_get_name_by_id(ids[i], xstats_names[i].name,
@@ -5292,7 +5292,6 @@ static const struct eth_dev_ops txgbe_eth_dev_ops = {
 	.stats_reset                = txgbe_dev_stats_reset,
 	.xstats_reset               = txgbe_dev_xstats_reset,
 	.xstats_get_names           = txgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id     = txgbe_dev_xstats_get_names_by_id,
 	.queue_stats_mapping_set    = txgbe_dev_queue_stats_mapping_set,
 	.fw_version_get             = txgbe_fw_version_get,
 	.dev_supported_ptypes_get   = txgbe_dev_supported_ptypes_get,
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index 896da8a887..cbe2f46f34 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -348,10 +348,14 @@ static struct rte_pci_driver rte_txgbevf_pmd = {
 };
 
 static int txgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names, unsigned int limit)
 {
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (limit < TXGBEVF_NB_XSTATS && xstats_names != NULL)
 		return -ENOMEM;
 
diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index a202931e9a..e5d723bfd7 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -251,6 +251,7 @@ vhost_dev_xstats_reset(struct rte_eth_dev *dev)
 
 static int
 vhost_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+			   const uint64_t *ids,
 			   struct rte_eth_xstat_name *xstats_names,
 			   unsigned int limit __rte_unused)
 {
@@ -258,6 +259,9 @@ vhost_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
 	int count = 0;
 	int nstats = VHOST_NB_XSTATS_RXPORT + VHOST_NB_XSTATS_TXPORT;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return nstats;
 	for (t = 0; t < VHOST_NB_XSTATS_RXPORT; t++) {
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b08109c61c..0a75e9396f 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -60,6 +60,7 @@ static int virtio_dev_stats_get(struct rte_eth_dev *dev,
 static int virtio_dev_xstats_get(struct rte_eth_dev *dev,
 				 struct rte_eth_xstat *xstats, unsigned n);
 static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
+				       const uint64_t *ids,
 				       struct rte_eth_xstat_name *xstats_names,
 				       unsigned limit);
 static int virtio_dev_stats_reset(struct rte_eth_dev *dev);
@@ -1032,6 +1033,7 @@ virtio_update_stats(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 }
 
 static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
+				       const uint64_t *ids,
 				       struct rte_eth_xstat_name *xstats_names,
 				       __rte_unused unsigned limit)
 {
@@ -1042,6 +1044,9 @@ static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
 	unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_TXQ_XSTATS +
 		dev->data->nb_rx_queues * VIRTIO_NB_RXQ_XSTATS;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		/* Note: limit checked in rte_eth_xstats_names() */
 
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 2f40ae907d..48767e6db1 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -80,6 +80,7 @@ static int vmxnet3_dev_stats_get(struct rte_eth_dev *dev,
 				  struct rte_eth_stats *stats);
 static int vmxnet3_dev_stats_reset(struct rte_eth_dev *dev);
 static int vmxnet3_dev_xstats_get_names(struct rte_eth_dev *dev,
+					const uint64_t *ids,
 					struct rte_eth_xstat_name *xstats,
 					unsigned int n);
 static int vmxnet3_dev_xstats_get(struct rte_eth_dev *dev,
@@ -1201,6 +1202,7 @@ vmxnet3_hw_stats_save(struct vmxnet3_hw *hw)
 
 static int
 vmxnet3_dev_xstats_get_names(struct rte_eth_dev *dev,
+			     const uint64_t *ids,
 			     struct rte_eth_xstat_name *xstats_names,
 			     unsigned int n)
 {
@@ -1209,6 +1211,9 @@ vmxnet3_dev_xstats_get_names(struct rte_eth_dev *dev,
 		dev->data->nb_tx_queues * RTE_DIM(vmxnet3_txq_stat_strings) +
 		dev->data->nb_rx_queues * RTE_DIM(vmxnet3_rxq_stat_strings);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names || n < nstats)
 		return nstats;
 
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index b1b3c9bc59..a10a7ed297 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -227,10 +227,6 @@ typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
  */
 typedef int (*eth_xstats_reset_t)(struct rte_eth_dev *dev);
 
-typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
-
 /**
  * @internal
  * Get names of extended stats of an Ethernet device.
@@ -239,8 +235,8 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  * @param dev
  *   ethdev handle of port.
  * @param ids
- *   IDs array to retrieve specific statistics. Can be NULL together
- *   with @p xstats_names to retrieve number of available statistics.
+ *   IDs array to retrieve specific statistics. Can be NULL to get names
+ *   of all available statistics.
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. Can be NULL together with @p ids to retrieve number of
@@ -253,7 +249,7 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *   - A number of available stats if both xstats_names and ids are NULL.
  *   - A negative value on error.
  */
-typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
+typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int size);
 
@@ -940,8 +936,6 @@ struct eth_dev_ops {
 
 	eth_xstats_get_by_id_t     xstats_get_by_id;
 	/**< Get extended device statistic values by ID. */
-	eth_xstats_get_names_by_id_t xstats_get_names_by_id;
-	/**< Get name of extended device statistics by ID. */
 
 	eth_tm_ops_get_t tm_ops_get;
 	/**< Get Traffic Management (TM) operations. */
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index 15e1213820..02ddf2424c 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -2866,14 +2866,8 @@ eth_dev_get_xstats_count(uint16_t port_id)
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
-	if (dev->dev_ops->xstats_get_names_by_id != NULL) {
-		count = (*dev->dev_ops->xstats_get_names_by_id)(dev, NULL,
-				NULL, 0);
-		if (count < 0)
-			return eth_err(port_id, count);
-	}
 	if (dev->dev_ops->xstats_get_names != NULL) {
-		count = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0);
+		count = (*dev->dev_ops->xstats_get_names)(dev, NULL, NULL, 0);
 		if (count < 0)
 			return eth_err(port_id, count);
 	} else
@@ -3011,7 +3005,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
 	if (ids && !xstats_names)
 		return -EINVAL;
 
-	if (ids && dev->dev_ops->xstats_get_names_by_id != NULL && size > 0) {
+	if (ids && dev->dev_ops->xstats_get_names != NULL && size > 0) {
 		uint64_t ids_copy[size];
 
 		for (i = 0; i < size; i++) {
@@ -3028,7 +3022,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
 		}
 
 		if (no_basic_stat_requested)
-			return (*dev->dev_ops->xstats_get_names_by_id)(dev,
+			return (*dev->dev_ops->xstats_get_names)(dev,
 					ids_copy, xstats_names, size);
 	}
 
@@ -3110,7 +3104,7 @@ rte_eth_xstats_get_names(uint16_t port_id,
 		 * to end of list.
 		 */
 		cnt_driver_entries = (*dev->dev_ops->xstats_get_names)(
-			dev,
+			dev, NULL,
 			xstats_names + cnt_used_entries,
 			size - cnt_used_entries);
 		if (cnt_driver_entries < 0)
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [dpdk-stable] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-30 14:01               ` Andrew Rybchenko
@ 2021-09-30 15:30                 ` Ferruh Yigit
  2021-09-30 16:01                   ` Andrew Rybchenko
  0 siblings, 1 reply; 113+ messages in thread
From: Ferruh Yigit @ 2021-09-30 15:30 UTC (permalink / raw)
  To: Andrew Rybchenko, Thomas Monjalon
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton, Kuba Kozak

On 9/30/2021 3:01 PM, Andrew Rybchenko wrote:
> On 9/30/21 3:08 PM, Ferruh Yigit wrote:
>> On 9/29/2021 12:54 PM, Andrew Rybchenko wrote:
>>> On 9/29/21 11:44 AM, Ferruh Yigit wrote:
>>>> On 9/28/2021 5:53 PM, Andrew Rybchenko wrote:
>>>>> On 9/28/21 7:50 PM, Ferruh Yigit wrote:
>>>>>> On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
>>>>>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>>>>
>>>>>>> Update xstats by IDs callbacks documentation in accordance with
>>>>>>> ethdev usage of these callbacks. Document valid combinations of
>>>>>>> input arguments to make driver implementation simpler.
>>>>>>>
>>>>>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>>>>>> Cc: stable@dpdk.org
>>>>>>>
>>>>>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>>>>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>>>>>> ---
>>>>>>>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>>>>>>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>>>>>>
>>>>>>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>>>>>>> index 40e474aa7e..c89eefcc42 100644
>>>>>>> --- a/lib/ethdev/ethdev_driver.h
>>>>>>> +++ b/lib/ethdev/ethdev_driver.h
>>>>>>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>>>>>>  	struct rte_eth_xstat *stats, unsigned int n);
>>>>>>>  /**< @internal Get extended stats of an Ethernet device. */
>>>>>>>  
>>>>>>> +/**
>>>>>>> + * @internal
>>>>>>> + * Get extended stats of an Ethernet device.
>>>>>>> + *
>>>>>>> + * @param dev
>>>>>>> + *   ethdev handle of port.
>>>>>>> + * @param ids
>>>>>>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>>>>>>> + * @param values
>>>>>>> + *   A pointer to a table to be filled with device statistics values.
>>>>>>> + *   Must not be NULL.
>>>>>>> + * @param n
>>>>>>> + *   Element count in @p ids and @p values.
>>>>>>> + *
>>>>>>> + * @return
>>>>>>> + *   - A number of filled in stats.
>>>>>>> + *   - A negative value on error.
>>>>>>> + */
>>>>>>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>>>>>>  				      const uint64_t *ids,
>>>>>>>  				      uint64_t *values,
>>>>>>>  				      unsigned int n);
>>>>>>> -/**< @internal Get extended stats of an Ethernet device. */
>>>>>>>  
>>>>>>>  /**
>>>>>>>   * @internal
>>>>>>> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>>>>>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>>>>>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>>>>>>  
>>>>>>> +/**
>>>>>>> + * @internal
>>>>>>> + * Get names of extended stats of an Ethernet device.
>>>>>>> + * For name count, set @p xstats_names and @p ids to NULL.
>>>>>>
>>>>>> Why limiting this behavior to 'xstats_get_names_by_id'?
>>>>>>
>>>>>> Internally 'xstats_get_names_by_id' is used to get the count, but I think this
>>>>>> is not intentionally selected, just one of the xstats_*_by_id dev_ops used.
>>>>>>
>>>>>> I think it is confusing to have this support for one of the '_by_id' dev_ops but
>>>>>> not for other. Why not require both to support returning 'count'?
>>>>>
>>>>> Simply because it is dead code. There is no point to require
>>>>> from driver to have dead code.
>>>>>
>>>>
>>>> Let me step back a little, both ethdev APIs can be used to return xstats count
>>>> by providing 'values/names' & 'ids' pointers as NULL and 'size' as 0:
>>>> 'rte_eth_xstats_get_names_by_id()'
>>>> 'rte_eth_xstats_get_by_id()'
>>>>
>>>> But internally both APIs use 'xstats_get_names_by_id' dev_ops to get the count,
>>>> as said above I believe this selection is done unintentionally.
>>>>
>>>>
>>>> I am for below two options:
>>>>
>>>> a) Internally use 'xstats_get_names' || 'xstats_get' dev_ops to get the xstats
>>>> count, and doesn't support getting xstats count for both '_by_id' dev_ops, this
>>>> simplifies driver code. As far as I remember I suggested this before, still I
>>>> prefer this one.
>>>>
>>>> b) If we will support getting xstats count from '_by_id' dev_ops, I think both
>>>> should support it, to not make it more complex to figure out which one support
>>>> what. As sample both 'xstats_get_names' and 'xstats_get' supports getting xstats
>>>> count, not just one.
>>>>
>>>
>>> In (b) do you suggest to change ethdev to use xstats_get_by_id
>>> driver op if users asks for a number of xstats using
>>> rte_eth_xstats_get_by_id()? It will complicate ethdev and
>>> will complicate drivers. Just for the symmetry?
>>>
>>
>> Not just for symmetry, but simplify the logic. Both dev_ops are very similar and
> 
> I'm sorry, but could you point of which logic you'd
> like to simply. Less requirements on driver ops
> means less code required inside.
> 
>> they are having different behavior with same parameters is confusing.
> 
> Ah, logic from PMD maintainer point of view. Does it
> really worse to require extra code inside because of it?
> 
>> If you want to simplify the drivers why not go with option (a)? Option (a) also
>> doesn't change external API, and has only minor change in the ethdev layer.
> 
> Is two extra patches in v6 (discussed below) a step
> towards (a)?
> 

I am not sure of it, for (a) ethdev layer will handle getting all stats or
getting count using 'xstats_get_names' || 'xstats_get', and '*_by_id()' dev_ops
will become simpler since they won't accept NULL 'ids' & 'values'.

Also when dev_ops merged, it forces PMDs to implement the getting by ids, but
now it is covered by ethdev layer for the PMDs that doesn't implement '_by_id()'.

>>> The patch does not change external API, does not change etcdev
>>> bahaviour. It just clarify requirements on driver ops to
>>> allow to check less in all drivers and support less cases
>>> in all drivers.
>>>
>>
>> It is not clarifying the requirements of dev_ops, but changing it. Previously
>> there was nothing saying only one of the '_by_id' dev_ops should support
>> returning element count.
> 
> I say "clarifying" since I adjust it a real source of
> truth for internals - implementation, usage of these
> callback by ethdev layer.
> 
> Yes, I agree that it changes documentation.
> 
>>
>>> If we make a one more step back, frankly speaking I think we
>>> have too many functions to retrieve statistics. I can
>>> understand from ethdev API point of view taking API stability
>>> into account etc. But why do we have so many complicated
>>> driver callbacks?
>>>> First of all I'd like to do one more cleanup:
>>> change eth_xstats_get_names_by_id_t prototype to
>>> have ids before xstats_names.
>>> I.e. eth_xstats_get_by_id_t(dev, ids, values, size)
>>> eth_xstats_get_names_by_id_t(dev, ids, names, size)
>>>
>>
>> +1
> 
> See patch 3/4 in v6
> 
>>
>>> Second, merge eth_xstats_get_names_t and eth_xstats_get_names_by_id_t
>>> callbacks to keep
>>> name of the first, but prototype from the second.
>>> The reason is equal functionality if ids==NULL,
>>> shorter name of the first and optional ids (i.e. no
>>> reason to mention optional parameter in name).
>>> Drivers which do not implement by_id_t,
>>> but implement eth_xstats_get_names_t, will simply
>>> return ENOTSUP if ids!=NULL.
>>>
>>
>> No objection, _by_id() version is already superset of the other.
> 
> See patch 4/4 in v6
> 
>>
>>> The case of values ops is more complicated,
>>> however since:
>>>
>>> 2834  * There is an assumption that 'xstat_names' and 'xstats' arrays
>>> are matched
>>> 2835  * by array index:
>>> 2836  *  xstats_names[i].name => xstats[i].value
>>> 2837  *
>>> 2838  * And the array index is same with id field of 'struct rte_eth_xstat':
>>> 2839  *  xstats[i].id == i
>>> 2840  *
>>> 2841  * This assumption makes key-value pair matching less flexible but
>>> simpler.
>>>
>>> we can switch to eth_xstats_get_by_id_t only callback as
>>> well and fill in stats->id equal to index on ethdev layer.
>>
>> When ids != NULL, the index from 'ids' can be used, isn't it.
> 
> Yes, of course, but above documentation is for API without IDs.
> 
>>
>>> However, it will require extra buffer for
>>> uint64_t *values and copying in the rte_eth_xstats_get()
>>> implementation. So, I doubt in this case.
>>>
>>
>> Overall merging xstats _by_id APIs doesn't look bad idea, but since it will
>> require change in applications, I am not really sure if benefit worth the
>> trouble it brings to users.
> 
> Yes, I agree. I'm not going to change external API.
> 
>>> In fact, it is sad that we still do not move forward
>>> in accordance with Thomas presentation made 2 years ago.
>>>
>>
>> In my experience things don't move forward without proper plan (who, what, when).
>>
> 
> +1
> 


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count
  2021-06-04 14:42 [dpdk-dev] [PATCH 00/11] net/sfc: provide Rx/Tx doorbells stats Andrew Rybchenko
                   ` (15 preceding siblings ...)
  2021-09-30 14:04 ` [dpdk-dev] [PATCH v6 1/4] " Andrew Rybchenko
@ 2021-09-30 16:01 ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 1/5] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
                     ` (7 more replies)
  2021-09-30 16:05 ` [dpdk-dev] [PATCH v8 1/5] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
  2021-10-01  9:07 ` [dpdk-dev] [PATCH v9 1/5] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
  18 siblings, 8 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit; +Cc: dev

Relax requirements on get xstats names by IDs. After the patch
corresponding the driver operation is called with non-NULL ids
and xstats_names parameters only.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 lib/ethdev/rte_ethdev.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index daf5ca9242..e5ddc1b81f 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -2866,12 +2866,6 @@ eth_dev_get_xstats_count(uint16_t port_id)
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
-	if (dev->dev_ops->xstats_get_names_by_id != NULL) {
-		count = (*dev->dev_ops->xstats_get_names_by_id)(dev, NULL,
-				NULL, 0);
-		if (count < 0)
-			return eth_err(port_id, count);
-	}
 	if (dev->dev_ops->xstats_get_names != NULL) {
 		count = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0);
 		if (count < 0)
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 1/5] ethdev: fix docs of functions getting xstats by IDs
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 2/5] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: dev, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Document valid combinations of input arguments in accordance with
current implementation in ethdev.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 lib/ethdev/rte_ethdev.h | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index afdc53b674..2ad2bf2019 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2896,21 +2896,23 @@ int rte_eth_xstats_get(uint16_t port_id, struct rte_eth_xstat *xstats,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param xstats_names
- *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. If set to NULL, the function returns the required number
- *   of elements.
- * @param ids
- *   IDs array given by app to retrieve specific statistics
+ *   Array to be filled in with names of requested device statistics.
+ *   Must not be NULL if @p ids are specified (not NULL).
  * @param size
- *   The size of the xstats_names array (number of elements).
+ *   Number of elements in @p xstats_names array (if not NULL) and in
+ *   @p ids array (if not NULL). Must be 0 if both array pointers are NULL.
+ * @param ids
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve names of all available statistics or, if @p xstats_names is
+ *   NULL as well, just the number of available statistics.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
- *   - A positive value higher than size: error, the given statistics table
+ *   - A positive value higher than size: success. The given statistics table
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int
 rte_eth_xstats_get_names_by_id(uint16_t port_id,
@@ -2923,22 +2925,23 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
  * @param port_id
  *   The port identifier of the Ethernet device.
  * @param ids
- *   A pointer to an ids array passed by application. This tells which
- *   statistics values function should retrieve. This parameter
- *   can be set to NULL if size is 0. In this case function will retrieve
- *   all available statistics.
+ *   IDs array given by app to retrieve specific statistics. May be NULL to
+ *   retrieve all available statistics or, if @p values is NULL as well,
+ *   just the number of available statistics.
  * @param values
- *   A pointer to a table to be filled with device statistics values.
+ *   Array to be filled in with requested device statistics.
+ *   Must not be NULL if ids are specified (not NULL).
  * @param size
- *   The size of the ids array (number of elements).
+ *   Number of elements in @p values array (if not NULL) and in @p ids
+ *   array (if not NULL). Must be 0 if both array pointers are NULL.
  * @return
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
- *   - A positive value higher than size: error, the given statistics table
+ *   - A positive value higher than size: success: The given statistics table
  *     is too small. The return value corresponds to the size that should
  *     be given to succeed. The entries in the table are not valid and
  *     shall not be used by the caller.
- *   - A negative value on error (invalid port id).
+ *   - A negative value on error.
  */
 int rte_eth_xstats_get_by_id(uint16_t port_id, const uint64_t *ids,
 			     uint64_t *values, unsigned int size);
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 2/5] ethdev: do not use get xstats names by IDs to obtain count
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 1/5] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 2/4] ethdev: fix docs of drivers callbacks getting xstats by IDs Andrew Rybchenko
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit; +Cc: dev

Relax requirements on get xstats names by IDs. After the patch
corresponding the driver operation is called with non-NULL ids
and xstats_names parameters only.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 lib/ethdev/rte_ethdev.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index daf5ca9242..e5ddc1b81f 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -2866,12 +2866,6 @@ eth_dev_get_xstats_count(uint16_t port_id)
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
-	if (dev->dev_ops->xstats_get_names_by_id != NULL) {
-		count = (*dev->dev_ops->xstats_get_names_by_id)(dev, NULL,
-				NULL, 0);
-		if (count < 0)
-			return eth_err(port_id, count);
-	}
 	if (dev->dev_ops->xstats_get_names != NULL) {
 		count = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0);
 		if (count < 0)
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 2/4] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 1/5] ethdev: fix docs of functions getting xstats by IDs Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 2/5] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 3/5] " Andrew Rybchenko
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: dev, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 39 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index cc2c75261c..74af878bb8 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -183,11 +183,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values.
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -214,10 +231,28 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Must not be NULL.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param size
+ *   Element count in @p ids and @p xstats_names.
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* Re: [dpdk-dev] [dpdk-stable] [PATCH v5 2/2] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-30 15:30                 ` Ferruh Yigit
@ 2021-09-30 16:01                   ` Andrew Rybchenko
  0 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Ferruh Yigit, Thomas Monjalon
  Cc: dev, Olivier Matz, Ivan Ilchenko, stable, Andy Moreton, Kuba Kozak

On 9/30/21 6:30 PM, Ferruh Yigit wrote:
> On 9/30/2021 3:01 PM, Andrew Rybchenko wrote:
>> On 9/30/21 3:08 PM, Ferruh Yigit wrote:
>>> On 9/29/2021 12:54 PM, Andrew Rybchenko wrote:
>>>> On 9/29/21 11:44 AM, Ferruh Yigit wrote:
>>>>> On 9/28/2021 5:53 PM, Andrew Rybchenko wrote:
>>>>>> On 9/28/21 7:50 PM, Ferruh Yigit wrote:
>>>>>>> On 9/28/2021 1:05 PM, Andrew Rybchenko wrote:
>>>>>>>> From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>>>>>
>>>>>>>> Update xstats by IDs callbacks documentation in accordance with
>>>>>>>> ethdev usage of these callbacks. Document valid combinations of
>>>>>>>> input arguments to make driver implementation simpler.
>>>>>>>>
>>>>>>>> Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
>>>>>>>> Cc: stable@dpdk.org
>>>>>>>>
>>>>>>>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
>>>>>>>> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
>>>>>>>> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
>>>>>>>> ---
>>>>>>>>  lib/ethdev/ethdev_driver.h | 42 ++++++++++++++++++++++++++++++++++++--
>>>>>>>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
>>>>>>>> index 40e474aa7e..c89eefcc42 100644
>>>>>>>> --- a/lib/ethdev/ethdev_driver.h
>>>>>>>> +++ b/lib/ethdev/ethdev_driver.h
>>>>>>>> @@ -187,11 +187,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
>>>>>>>>  	struct rte_eth_xstat *stats, unsigned int n);
>>>>>>>>  /**< @internal Get extended stats of an Ethernet device. */
>>>>>>>>  
>>>>>>>> +/**
>>>>>>>> + * @internal
>>>>>>>> + * Get extended stats of an Ethernet device.
>>>>>>>> + *
>>>>>>>> + * @param dev
>>>>>>>> + *   ethdev handle of port.
>>>>>>>> + * @param ids
>>>>>>>> + *   IDs array to retrieve specific statistics. Must not be NULL.
>>>>>>>> + * @param values
>>>>>>>> + *   A pointer to a table to be filled with device statistics values.
>>>>>>>> + *   Must not be NULL.
>>>>>>>> + * @param n
>>>>>>>> + *   Element count in @p ids and @p values.
>>>>>>>> + *
>>>>>>>> + * @return
>>>>>>>> + *   - A number of filled in stats.
>>>>>>>> + *   - A negative value on error.
>>>>>>>> + */
>>>>>>>>  typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
>>>>>>>>  				      const uint64_t *ids,
>>>>>>>>  				      uint64_t *values,
>>>>>>>>  				      unsigned int n);
>>>>>>>> -/**< @internal Get extended stats of an Ethernet device. */
>>>>>>>>  
>>>>>>>>  /**
>>>>>>>>   * @internal
>>>>>>>> @@ -218,10 +235,31 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
>>>>>>>>  	struct rte_eth_xstat_name *xstats_names, unsigned int size);
>>>>>>>>  /**< @internal Get names of extended stats of an Ethernet device. */
>>>>>>>>  
>>>>>>>> +/**
>>>>>>>> + * @internal
>>>>>>>> + * Get names of extended stats of an Ethernet device.
>>>>>>>> + * For name count, set @p xstats_names and @p ids to NULL.
>>>>>>>
>>>>>>> Why limiting this behavior to 'xstats_get_names_by_id'?
>>>>>>>
>>>>>>> Internally 'xstats_get_names_by_id' is used to get the count, but I think this
>>>>>>> is not intentionally selected, just one of the xstats_*_by_id dev_ops used.
>>>>>>>
>>>>>>> I think it is confusing to have this support for one of the '_by_id' dev_ops but
>>>>>>> not for other. Why not require both to support returning 'count'?
>>>>>>
>>>>>> Simply because it is dead code. There is no point to require
>>>>>> from driver to have dead code.
>>>>>>
>>>>>
>>>>> Let me step back a little, both ethdev APIs can be used to return xstats count
>>>>> by providing 'values/names' & 'ids' pointers as NULL and 'size' as 0:
>>>>> 'rte_eth_xstats_get_names_by_id()'
>>>>> 'rte_eth_xstats_get_by_id()'
>>>>>
>>>>> But internally both APIs use 'xstats_get_names_by_id' dev_ops to get the count,
>>>>> as said above I believe this selection is done unintentionally.
>>>>>
>>>>>
>>>>> I am for below two options:
>>>>>
>>>>> a) Internally use 'xstats_get_names' || 'xstats_get' dev_ops to get the xstats
>>>>> count, and doesn't support getting xstats count for both '_by_id' dev_ops, this
>>>>> simplifies driver code. As far as I remember I suggested this before, still I
>>>>> prefer this one.
>>>>>
>>>>> b) If we will support getting xstats count from '_by_id' dev_ops, I think both
>>>>> should support it, to not make it more complex to figure out which one support
>>>>> what. As sample both 'xstats_get_names' and 'xstats_get' supports getting xstats
>>>>> count, not just one.
>>>>>
>>>>
>>>> In (b) do you suggest to change ethdev to use xstats_get_by_id
>>>> driver op if users asks for a number of xstats using
>>>> rte_eth_xstats_get_by_id()? It will complicate ethdev and
>>>> will complicate drivers. Just for the symmetry?
>>>>
>>>
>>> Not just for symmetry, but simplify the logic. Both dev_ops are very similar and
>>
>> I'm sorry, but could you point of which logic you'd
>> like to simply. Less requirements on driver ops
>> means less code required inside.
>>
>>> they are having different behavior with same parameters is confusing.
>>
>> Ah, logic from PMD maintainer point of view. Does it
>> really worse to require extra code inside because of it?
>>
>>> If you want to simplify the drivers why not go with option (a)? Option (a) also
>>> doesn't change external API, and has only minor change in the ethdev layer.
>>
>> Is two extra patches in v6 (discussed below) a step
>> towards (a)?
>>
> 
> I am not sure of it, for (a) ethdev layer will handle getting all stats or
> getting count using 'xstats_get_names' || 'xstats_get', and '*_by_id()' dev_ops
> will become simpler since they won't accept NULL 'ids' & 'values'.

Got it. Will fix it in v7. I'll remove requirement in a
dedicated patch, but may be it should be squashed with
this one on apply.

> Also when dev_ops merged, it forces PMDs to implement the getting by ids, but
> now it is covered by ethdev layer for the PMDs that doesn't implement '_by_id()'.

Thanks, good catch. I'll handle it v7 as well.

^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 3/5] ethdev: fix docs of drivers callbacks getting xstats by IDs
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
                     ` (2 preceding siblings ...)
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 2/4] ethdev: fix docs of drivers callbacks getting xstats by IDs Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 3/4] ethdev: improve xstats names by IDs get prototype Andrew Rybchenko
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Kuba Kozak
  Cc: dev, Ivan Ilchenko, stable, Andy Moreton

From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>

Update xstats by IDs callbacks documentation in accordance with
ethdev usage of these callbacks. Document valid combinations of
input arguments to make driver implementation simpler.

Fixes: 79c913a42f0 ("ethdev: retrieve xstats by ID")
Cc: stable@dpdk.org

Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 lib/ethdev/ethdev_driver.h | 39 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index cc2c75261c..74af878bb8 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -183,11 +183,28 @@ typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat *stats, unsigned int n);
 /**< @internal Get extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param values
+ *   A pointer to a table to be filled with device statistics values.
+ *   Must not be NULL.
+ * @param n
+ *   Element count in @p ids and @p values.
+ *
+ * @return
+ *   - A number of filled in stats.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
 				      const uint64_t *ids,
 				      uint64_t *values,
 				      unsigned int n);
-/**< @internal Get extended stats of an Ethernet device. */
 
 /**
  * @internal
@@ -214,10 +231,28 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 /**< @internal Get names of extended stats of an Ethernet device. */
 
+/**
+ * @internal
+ * Get names of extended stats of an Ethernet device.
+ *
+ * @param dev
+ *   ethdev handle of port.
+ * @param xstats_names
+ *   An rte_eth_xstat_name array of at least *size* elements to
+ *   be filled. Must not be NULL.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
+ * @param size
+ *   Element count in @p ids and @p xstats_names.
+ *
+ * @return
+ *   - A number of filled in stats if both xstats_names and ids are not NULL.
+ *   - A number of available stats if both xstats_names and ids are NULL.
+ *   - A negative value on error.
+ */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 	unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
 					     uint16_t queue_id,
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 3/4] ethdev: improve xstats names by IDs get prototype
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
                     ` (3 preceding siblings ...)
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 3/5] " Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 4/5] " Andrew Rybchenko
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Somalapuram Amaranath, Nithin Dabilpuram, Kiran Kumar K,
	Sunil Kumar Kori, Satha Rao, Rahul Lakkireddy, Hemant Agrawal,
	Sachin Saxena, Haiyue Wang, Min Hu (Connor),
	Yisen Zhuang, Lijun Ou, Andrew Boyer, Jerin Jacob, Jiawen Wu,
	Jian Wang, Thomas Monjalon, Ferruh Yigit
  Cc: dev

Adjust parameters order to eth_xstats_get_by_id_t prototype.
Make ids the second parameter similar to eth_xstats_get_by_id_t.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 drivers/net/axgbe/axgbe_ethdev.c    | 4 ++--
 drivers/net/cnxk/cnxk_ethdev.h      | 3 ++-
 drivers/net/cnxk/cnxk_stats.c       | 3 ++-
 drivers/net/cxgbe/cxgbe_ethdev.c    | 3 ++-
 drivers/net/dpaa/dpaa_ethdev.c      | 2 +-
 drivers/net/dpaa2/dpaa2_ethdev.c    | 2 +-
 drivers/net/e1000/igb_ethdev.c      | 6 +++---
 drivers/net/hns3/hns3_stats.c       | 7 ++++---
 drivers/net/hns3/hns3_stats.h       | 2 +-
 drivers/net/igc/igc_ethdev.c        | 4 ++--
 drivers/net/ionic/ionic_ethdev.c    | 6 +++---
 drivers/net/ixgbe/ixgbe_ethdev.c    | 6 +++---
 drivers/net/octeontx2/otx2_ethdev.h | 3 ++-
 drivers/net/octeontx2/otx2_stats.c  | 3 ++-
 drivers/net/sfc/sfc_ethdev.c        | 3 ++-
 drivers/net/txgbe/txgbe_ethdev.c    | 2 +-
 lib/ethdev/ethdev_driver.h          | 9 ++++++---
 lib/ethdev/rte_ethdev.c             | 2 +-
 18 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
index 9cb4818af1..ebd5411fdd 100644
--- a/drivers/net/axgbe/axgbe_ethdev.c
+++ b/drivers/net/axgbe/axgbe_ethdev.c
@@ -57,8 +57,8 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			   unsigned int n);
 static int
 axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 struct rte_eth_xstat_name *xstats_names,
 				 const uint64_t *ids,
+				 struct rte_eth_xstat_name *xstats_names,
 				 unsigned int size);
 static int axgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int axgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
@@ -1076,8 +1076,8 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 static int
 axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 struct rte_eth_xstat_name *xstats_names,
 				 const uint64_t *ids,
+				 struct rte_eth_xstat_name *xstats_names,
 				 unsigned int size)
 {
 	struct rte_eth_xstat_name xstats_names_copy[AXGBE_XSTATS_COUNT];
diff --git a/drivers/net/cnxk/cnxk_ethdev.h b/drivers/net/cnxk/cnxk_ethdev.h
index 10e05e6b5e..946629f72e 100644
--- a/drivers/net/cnxk/cnxk_ethdev.h
+++ b/drivers/net/cnxk/cnxk_ethdev.h
@@ -365,8 +365,9 @@ int cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
 int cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
-				    const uint64_t *ids, unsigned int limit);
+				    unsigned int limit);
 int cnxk_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev, const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int cnxk_nix_xstats_reset(struct rte_eth_dev *eth_dev);
diff --git a/drivers/net/cnxk/cnxk_stats.c b/drivers/net/cnxk/cnxk_stats.c
index 19bab2170c..4b0deac05e 100644
--- a/drivers/net/cnxk/cnxk_stats.c
+++ b/drivers/net/cnxk/cnxk_stats.c
@@ -227,8 +227,9 @@ cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 
 int
 cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, unsigned int limit)
+				unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	uint32_t nix_cnt = roc_nix_num_xstats_get(&dev->nix);
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 177eca3976..4929766d9a 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -1006,8 +1006,9 @@ static int cxgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 
 /* Get names of port extended statistics by ID. */
 static int cxgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+					    const uint64_t *ids,
 					    struct rte_eth_xstat_name *xnames,
-					    const uint64_t *ids, unsigned int n)
+					    unsigned int n)
 {
 	struct port_info *pi = dev->data->dev_private;
 	struct rte_eth_xstat_name *xnames_copy;
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index 36d8f9249d..1f80e8d744 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -815,8 +815,8 @@ dpaa_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int
 dpaa_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa_xstats_strings);
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index c12169578e..ea191564fc 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -1795,8 +1795,8 @@ dpaa2_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int
 dpaa2_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa2_xstats_strings);
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index d80fad01e3..6510cd7ceb 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -96,7 +96,7 @@ static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
 				    struct rte_eth_xstat_name *xstats_names,
 				    unsigned int size);
 static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igb_stats_reset(struct rte_eth_dev *dev);
 static int eth_igb_xstats_reset(struct rte_eth_dev *dev);
@@ -1883,7 +1883,7 @@ static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 }
 
 static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
@@ -1902,7 +1902,7 @@ static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	} else {
 		struct rte_eth_xstat_name xstats_names_copy[IGB_NB_XSTATS];
 
-		eth_igb_xstats_get_names_by_id(dev, xstats_names_copy, NULL,
+		eth_igb_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
 				IGB_NB_XSTATS);
 
 		for (i = 0; i < limit; i++) {
diff --git a/drivers/net/hns3/hns3_stats.c b/drivers/net/hns3/hns3_stats.c
index e09dc0da80..0fe853d626 100644
--- a/drivers/net/hns3/hns3_stats.c
+++ b/drivers/net/hns3/hns3_stats.c
@@ -1365,12 +1365,12 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  *
  * @param dev
  *   Pointer to Ethernet device.
+ * @param ids
+ *   IDs array given by app to retrieve specific statistics
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. If set to NULL, the function returns the required number
  *   of elements.
- * @param ids
- *   IDs array given by app to retrieve specific statistics
  * @param size
  *   The size of the xstats_names array (number of elements).
  * @return
@@ -1383,8 +1383,9 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  */
 int
 hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, uint32_t size)
+				uint32_t size)
 {
 	const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
 	struct hns3_adapter *hns = dev->data->dev_private;
diff --git a/drivers/net/hns3/hns3_stats.h b/drivers/net/hns3/hns3_stats.h
index de5c40d6b5..d1230f94cb 100644
--- a/drivers/net/hns3/hns3_stats.h
+++ b/drivers/net/hns3/hns3_stats.h
@@ -161,8 +161,8 @@ int hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			      uint64_t *values,
 			      uint32_t size);
 int hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				    struct rte_eth_xstat_name *xstats_names,
 				    const uint64_t *ids,
+				    struct rte_eth_xstat_name *xstats_names,
 				    uint32_t size);
 int hns3_stats_reset(struct rte_eth_dev *dev);
 int hns3_tqp_stats_init(struct hns3_hw *hw);
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index 224a095483..be2c066111 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -216,7 +216,7 @@ static int eth_igc_xstats_get_names(struct rte_eth_dev *dev,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int size);
 static int eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igc_xstats_reset(struct rte_eth_dev *dev);
 static int
@@ -2013,7 +2013,7 @@ eth_igc_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 static int
 eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index e620793966..344c076f30 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -52,7 +52,7 @@ static int  ionic_dev_xstats_reset(struct rte_eth_dev *dev);
 static int  ionic_dev_xstats_get_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 static int  ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int  ionic_dev_fw_version_get(struct rte_eth_dev *eth_dev,
 	char *fw_version, size_t fw_size);
@@ -733,7 +733,7 @@ ionic_dev_xstats_get_names(__rte_unused struct rte_eth_dev *eth_dev,
 
 static int
 ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[IONIC_NB_HW_STATS];
@@ -751,7 +751,7 @@ ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 		return IONIC_NB_HW_STATS;
 	}
 
-	ionic_dev_xstats_get_names_by_id(eth_dev, xstats_names_copy, NULL,
+	ionic_dev_xstats_get_names_by_id(eth_dev, NULL, xstats_names_copy,
 		IONIC_NB_HW_STATS);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 47693c0c47..aae8b55d83 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -173,8 +173,8 @@ static int ixgbevf_dev_xstats_get_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned limit);
 static int ixgbe_dev_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
 					     uint16_t queue_id,
@@ -3437,8 +3437,8 @@ static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 static int ixgbe_dev_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	if (!ids) {
@@ -3497,7 +3497,7 @@ static int ixgbe_dev_xstats_get_names_by_id(
 	uint16_t size = ixgbe_xstats_calc_num();
 	struct rte_eth_xstat_name xstats_names_copy[size];
 
-	ixgbe_dev_xstats_get_names_by_id(dev, xstats_names_copy, NULL,
+	ixgbe_dev_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
 			size);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h
index 7871e3d30b..b1575f59a2 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -514,8 +514,9 @@ int otx2_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev,
 			      const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
-				    const uint64_t *ids, unsigned int limit);
+				    unsigned int limit);
 
 /* RSS */
 void otx2_nix_rss_set_key(struct otx2_eth_dev *dev,
diff --git a/drivers/net/octeontx2/otx2_stats.c b/drivers/net/octeontx2/otx2_stats.c
index 8aaf270a7c..3adf21608c 100644
--- a/drivers/net/octeontx2/otx2_stats.c
+++ b/drivers/net/octeontx2/otx2_stats.c
@@ -240,8 +240,9 @@ otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 
 int
 otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, unsigned int limit)
+				unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[OTX2_NIX_NUM_XSTATS_REG];
 	uint16_t i;
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 2db0d000c3..f212ca8ad6 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -838,8 +838,9 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 static int
 sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
+			   const uint64_t *ids,
 			   struct rte_eth_xstat_name *xstats_names,
-			   const uint64_t *ids, unsigned int size)
+			   unsigned int size)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0063994688..b267da462b 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2451,8 +2451,8 @@ static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
 }
 
 static int txgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i;
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 74af878bb8..6a2be98c1f 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -237,11 +237,14 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *
  * @param dev
  *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. Must not be NULL.
- * @param ids
- *   IDs array to retrieve specific statistics. Must not be NULL.
  * @param size
  *   Element count in @p ids and @p xstats_names.
  *
@@ -251,7 +254,7 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *   - A negative value on error.
  */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int size);
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index e5ddc1b81f..655d7be3b5 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -3023,7 +3023,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
 
 		if (no_basic_stat_requested)
 			return (*dev->dev_ops->xstats_get_names_by_id)(dev,
-					xstats_names, ids_copy, size);
+					ids_copy, xstats_names, size);
 	}
 
 	/* Retrieve all stats */
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 4/5] ethdev: improve xstats names by IDs get prototype
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
                     ` (4 preceding siblings ...)
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 3/4] ethdev: improve xstats names by IDs get prototype Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 4/4] ethdev: merge driver ops to get all xstats names and by ID Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 5/5] " Andrew Rybchenko
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Somalapuram Amaranath, Nithin Dabilpuram, Kiran Kumar K,
	Sunil Kumar Kori, Satha Rao, Rahul Lakkireddy, Hemant Agrawal,
	Sachin Saxena, Haiyue Wang, Min Hu (Connor),
	Yisen Zhuang, Lijun Ou, Andrew Boyer, Jerin Jacob, Jiawen Wu,
	Jian Wang, Thomas Monjalon, Ferruh Yigit
  Cc: dev

Adjust parameters order to eth_xstats_get_by_id_t prototype.
Make ids the second parameter similar to eth_xstats_get_by_id_t.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 drivers/net/axgbe/axgbe_ethdev.c    | 4 ++--
 drivers/net/cnxk/cnxk_ethdev.h      | 3 ++-
 drivers/net/cnxk/cnxk_stats.c       | 3 ++-
 drivers/net/cxgbe/cxgbe_ethdev.c    | 3 ++-
 drivers/net/dpaa/dpaa_ethdev.c      | 2 +-
 drivers/net/dpaa2/dpaa2_ethdev.c    | 2 +-
 drivers/net/e1000/igb_ethdev.c      | 6 +++---
 drivers/net/hns3/hns3_stats.c       | 7 ++++---
 drivers/net/hns3/hns3_stats.h       | 2 +-
 drivers/net/igc/igc_ethdev.c        | 4 ++--
 drivers/net/ionic/ionic_ethdev.c    | 6 +++---
 drivers/net/ixgbe/ixgbe_ethdev.c    | 6 +++---
 drivers/net/octeontx2/otx2_ethdev.h | 3 ++-
 drivers/net/octeontx2/otx2_stats.c  | 3 ++-
 drivers/net/sfc/sfc_ethdev.c        | 3 ++-
 drivers/net/txgbe/txgbe_ethdev.c    | 2 +-
 lib/ethdev/ethdev_driver.h          | 9 ++++++---
 lib/ethdev/rte_ethdev.c             | 2 +-
 18 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
index 9cb4818af1..ebd5411fdd 100644
--- a/drivers/net/axgbe/axgbe_ethdev.c
+++ b/drivers/net/axgbe/axgbe_ethdev.c
@@ -57,8 +57,8 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			   unsigned int n);
 static int
 axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 struct rte_eth_xstat_name *xstats_names,
 				 const uint64_t *ids,
+				 struct rte_eth_xstat_name *xstats_names,
 				 unsigned int size);
 static int axgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int axgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
@@ -1076,8 +1076,8 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 static int
 axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 struct rte_eth_xstat_name *xstats_names,
 				 const uint64_t *ids,
+				 struct rte_eth_xstat_name *xstats_names,
 				 unsigned int size)
 {
 	struct rte_eth_xstat_name xstats_names_copy[AXGBE_XSTATS_COUNT];
diff --git a/drivers/net/cnxk/cnxk_ethdev.h b/drivers/net/cnxk/cnxk_ethdev.h
index 10e05e6b5e..946629f72e 100644
--- a/drivers/net/cnxk/cnxk_ethdev.h
+++ b/drivers/net/cnxk/cnxk_ethdev.h
@@ -365,8 +365,9 @@ int cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
 int cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
-				    const uint64_t *ids, unsigned int limit);
+				    unsigned int limit);
 int cnxk_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev, const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int cnxk_nix_xstats_reset(struct rte_eth_dev *eth_dev);
diff --git a/drivers/net/cnxk/cnxk_stats.c b/drivers/net/cnxk/cnxk_stats.c
index 19bab2170c..4b0deac05e 100644
--- a/drivers/net/cnxk/cnxk_stats.c
+++ b/drivers/net/cnxk/cnxk_stats.c
@@ -227,8 +227,9 @@ cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 
 int
 cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, unsigned int limit)
+				unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	uint32_t nix_cnt = roc_nix_num_xstats_get(&dev->nix);
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 177eca3976..4929766d9a 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -1006,8 +1006,9 @@ static int cxgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 
 /* Get names of port extended statistics by ID. */
 static int cxgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+					    const uint64_t *ids,
 					    struct rte_eth_xstat_name *xnames,
-					    const uint64_t *ids, unsigned int n)
+					    unsigned int n)
 {
 	struct port_info *pi = dev->data->dev_private;
 	struct rte_eth_xstat_name *xnames_copy;
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index 36d8f9249d..1f80e8d744 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -815,8 +815,8 @@ dpaa_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int
 dpaa_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa_xstats_strings);
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index c12169578e..ea191564fc 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -1795,8 +1795,8 @@ dpaa2_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int
 dpaa2_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa2_xstats_strings);
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index d80fad01e3..6510cd7ceb 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -96,7 +96,7 @@ static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
 				    struct rte_eth_xstat_name *xstats_names,
 				    unsigned int size);
 static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igb_stats_reset(struct rte_eth_dev *dev);
 static int eth_igb_xstats_reset(struct rte_eth_dev *dev);
@@ -1883,7 +1883,7 @@ static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 }
 
 static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
@@ -1902,7 +1902,7 @@ static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	} else {
 		struct rte_eth_xstat_name xstats_names_copy[IGB_NB_XSTATS];
 
-		eth_igb_xstats_get_names_by_id(dev, xstats_names_copy, NULL,
+		eth_igb_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
 				IGB_NB_XSTATS);
 
 		for (i = 0; i < limit; i++) {
diff --git a/drivers/net/hns3/hns3_stats.c b/drivers/net/hns3/hns3_stats.c
index e09dc0da80..0fe853d626 100644
--- a/drivers/net/hns3/hns3_stats.c
+++ b/drivers/net/hns3/hns3_stats.c
@@ -1365,12 +1365,12 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  *
  * @param dev
  *   Pointer to Ethernet device.
+ * @param ids
+ *   IDs array given by app to retrieve specific statistics
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. If set to NULL, the function returns the required number
  *   of elements.
- * @param ids
- *   IDs array given by app to retrieve specific statistics
  * @param size
  *   The size of the xstats_names array (number of elements).
  * @return
@@ -1383,8 +1383,9 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  */
 int
 hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, uint32_t size)
+				uint32_t size)
 {
 	const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
 	struct hns3_adapter *hns = dev->data->dev_private;
diff --git a/drivers/net/hns3/hns3_stats.h b/drivers/net/hns3/hns3_stats.h
index de5c40d6b5..d1230f94cb 100644
--- a/drivers/net/hns3/hns3_stats.h
+++ b/drivers/net/hns3/hns3_stats.h
@@ -161,8 +161,8 @@ int hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			      uint64_t *values,
 			      uint32_t size);
 int hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				    struct rte_eth_xstat_name *xstats_names,
 				    const uint64_t *ids,
+				    struct rte_eth_xstat_name *xstats_names,
 				    uint32_t size);
 int hns3_stats_reset(struct rte_eth_dev *dev);
 int hns3_tqp_stats_init(struct hns3_hw *hw);
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index 224a095483..be2c066111 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -216,7 +216,7 @@ static int eth_igc_xstats_get_names(struct rte_eth_dev *dev,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int size);
 static int eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igc_xstats_reset(struct rte_eth_dev *dev);
 static int
@@ -2013,7 +2013,7 @@ eth_igc_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 static int
 eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index e620793966..344c076f30 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -52,7 +52,7 @@ static int  ionic_dev_xstats_reset(struct rte_eth_dev *dev);
 static int  ionic_dev_xstats_get_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size);
 static int  ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int  ionic_dev_fw_version_get(struct rte_eth_dev *eth_dev,
 	char *fw_version, size_t fw_size);
@@ -733,7 +733,7 @@ ionic_dev_xstats_get_names(__rte_unused struct rte_eth_dev *eth_dev,
 
 static int
 ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[IONIC_NB_HW_STATS];
@@ -751,7 +751,7 @@ ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 		return IONIC_NB_HW_STATS;
 	}
 
-	ionic_dev_xstats_get_names_by_id(eth_dev, xstats_names_copy, NULL,
+	ionic_dev_xstats_get_names_by_id(eth_dev, NULL, xstats_names_copy,
 		IONIC_NB_HW_STATS);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 47693c0c47..aae8b55d83 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -173,8 +173,8 @@ static int ixgbevf_dev_xstats_get_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned limit);
 static int ixgbe_dev_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
 					     uint16_t queue_id,
@@ -3437,8 +3437,8 @@ static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 static int ixgbe_dev_xstats_get_names_by_id(
 	struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	if (!ids) {
@@ -3497,7 +3497,7 @@ static int ixgbe_dev_xstats_get_names_by_id(
 	uint16_t size = ixgbe_xstats_calc_num();
 	struct rte_eth_xstat_name xstats_names_copy[size];
 
-	ixgbe_dev_xstats_get_names_by_id(dev, xstats_names_copy, NULL,
+	ixgbe_dev_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
 			size);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h
index 7871e3d30b..b1575f59a2 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -514,8 +514,9 @@ int otx2_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev,
 			      const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
-				    const uint64_t *ids, unsigned int limit);
+				    unsigned int limit);
 
 /* RSS */
 void otx2_nix_rss_set_key(struct otx2_eth_dev *dev,
diff --git a/drivers/net/octeontx2/otx2_stats.c b/drivers/net/octeontx2/otx2_stats.c
index 8aaf270a7c..3adf21608c 100644
--- a/drivers/net/octeontx2/otx2_stats.c
+++ b/drivers/net/octeontx2/otx2_stats.c
@@ -240,8 +240,9 @@ otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 
 int
 otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
-				const uint64_t *ids, unsigned int limit)
+				unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[OTX2_NIX_NUM_XSTATS_REG];
 	uint16_t i;
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 2db0d000c3..f212ca8ad6 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -838,8 +838,9 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 
 static int
 sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
+			   const uint64_t *ids,
 			   struct rte_eth_xstat_name *xstats_names,
-			   const uint64_t *ids, unsigned int size)
+			   unsigned int size)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0063994688..b267da462b 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2451,8 +2451,8 @@ static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
 }
 
 static int txgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
 	const uint64_t *ids,
+	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
 {
 	unsigned int i;
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 74af878bb8..6a2be98c1f 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -237,11 +237,14 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *
  * @param dev
  *   ethdev handle of port.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Can be NULL together
+ *   with @p xstats_names to retrieve number of available statistics.
+ * @param ids
+ *   IDs array to retrieve specific statistics. Must not be NULL.
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
  *   be filled. Must not be NULL.
- * @param ids
- *   IDs array to retrieve specific statistics. Must not be NULL.
  * @param size
  *   Element count in @p ids and @p xstats_names.
  *
@@ -251,7 +254,7 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *   - A negative value on error.
  */
 typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int size);
 
 typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index e5ddc1b81f..655d7be3b5 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -3023,7 +3023,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
 
 		if (no_basic_stat_requested)
 			return (*dev->dev_ops->xstats_get_names_by_id)(dev,
-					xstats_names, ids_copy, size);
+					ids_copy, xstats_names, size);
 	}
 
 	/* Retrieve all stats */
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 4/4] ethdev: merge driver ops to get all xstats names and by ID
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
                     ` (5 preceding siblings ...)
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 4/5] " Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 5/5] " Andrew Rybchenko
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Igor Russkikh, Somalapuram Amaranath, Rasesh Mody, Shahed Shaikh,
	Ajit Khaparde, Somnath Kotur, Nithin Dabilpuram, Kiran Kumar K,
	Sunil Kumar Kori, Satha Rao, Rahul Lakkireddy, Hemant Agrawal,
	Sachin Saxena, Haiyue Wang, Marcin Wojtas, Michal Krawczyk,
	Shai Brandes, Evgeny Schemeilin, Igor Chauskin, Gaetan Rivet,
	Qi Zhang, Xiao Wang, Ziyang Xuan, Xiaoyun Wang, Guoyang Zhou,
	Min Hu (Connor),
	Yisen Zhuang, Lijun Ou, Beilei Xing, Jingjing Wu, Qiming Yang,
	Andrew Boyer, Rosen Xu, Shijith Thotton,
	Srisivasubramanian Srinivasan, Matan Azrad, Viacheslav Ovsiienko,
	Liron Himi, Stephen Hemminger, Long Li, Jerin Jacob,
	Devendra Singh Rawat, Jiawen Wu, Jian Wang, Maxime Coquelin,
	Chenbo Xia, Yong Wang, Thomas Monjalon, Ferruh Yigit
  Cc: dev

All xstats names may be retrieved passing NULL ids.

If a driver does not support getting names by IDs, the callback should
return -ENOTSUP on attempt to use it. If so, the request is handled
on ethdev layer by getting all names and filtering out requested only.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 doc/guides/nics/features.rst            |  2 +-
 drivers/net/atlantic/atl_ethdev.c       |  5 ++
 drivers/net/axgbe/axgbe_ethdev.c        | 30 ++++-----
 drivers/net/bnx2x/bnx2x_ethdev.c        |  4 ++
 drivers/net/bnxt/bnxt_stats.c           |  4 ++
 drivers/net/bnxt/bnxt_stats.h           |  1 +
 drivers/net/cnxk/cnxk_ethdev.c          |  1 -
 drivers/net/cnxk/cnxk_ethdev.h          |  5 +-
 drivers/net/cnxk/cnxk_stats.c           | 18 +++---
 drivers/net/cxgbe/cxgbe_ethdev.c        | 17 ++---
 drivers/net/dpaa/dpaa_ethdev.c          | 13 ++--
 drivers/net/dpaa2/dpaa2_ethdev.c        | 13 ++--
 drivers/net/e1000/igb_ethdev.c          | 36 +++--------
 drivers/net/ena/ena_ethdev.c            |  6 +-
 drivers/net/failsafe/failsafe_ops.c     |  5 +-
 drivers/net/fm10k/fm10k_ethdev.c        |  4 ++
 drivers/net/hinic/hinic_pmd_ethdev.c    |  4 ++
 drivers/net/hns3/hns3_ethdev.c          |  1 -
 drivers/net/hns3/hns3_ethdev_vf.c       |  1 -
 drivers/net/hns3/hns3_stats.c           | 22 +++----
 drivers/net/hns3/hns3_stats.h           | 10 +--
 drivers/net/i40e/i40e_ethdev.c          |  5 ++
 drivers/net/iavf/iavf_ethdev.c          | 13 ++--
 drivers/net/ice/ice_ethdev.c            |  5 ++
 drivers/net/igc/igc_ethdev.c            | 10 +--
 drivers/net/ionic/ionic_ethdev.c        | 25 +-------
 drivers/net/ipn3ke/ipn3ke_representor.c |  5 +-
 drivers/net/ixgbe/ixgbe_ethdev.c        | 71 +++------------------
 drivers/net/liquidio/lio_ethdev.c       |  4 ++
 drivers/net/mlx5/mlx5.h                 |  1 +
 drivers/net/mlx5/mlx5_stats.c           |  7 ++-
 drivers/net/mvpp2/mrvl_ethdev.c         |  4 ++
 drivers/net/netvsc/hn_ethdev.c          |  5 +-
 drivers/net/octeontx2/otx2_ethdev.c     |  1 -
 drivers/net/octeontx2/otx2_ethdev.h     |  5 +-
 drivers/net/octeontx2/otx2_stats.c      | 14 ++---
 drivers/net/qede/qede_ethdev.c          |  4 ++
 drivers/net/sfc/sfc_ethdev.c            | 84 ++++++++++++-------------
 drivers/net/txgbe/txgbe_ethdev.c        |  7 +--
 drivers/net/txgbe/txgbe_ethdev_vf.c     |  4 ++
 drivers/net/vhost/rte_eth_vhost.c       |  4 ++
 drivers/net/virtio/virtio_ethdev.c      |  5 ++
 drivers/net/vmxnet3/vmxnet3_ethdev.c    |  5 ++
 lib/ethdev/ethdev_driver.h              | 17 ++---
 lib/ethdev/rte_ethdev.c                 | 17 +++--
 45 files changed, 238 insertions(+), 286 deletions(-)

diff --git a/doc/guides/nics/features.rst b/doc/guides/nics/features.rst
index 4fce8cd1c9..8fef2939fb 100644
--- a/doc/guides/nics/features.rst
+++ b/doc/guides/nics/features.rst
@@ -708,7 +708,7 @@ Extended stats
 Supports Extended Statistics, changes from driver to driver.
 
 * **[implements] eth_dev_ops**: ``xstats_get``, ``xstats_reset``, ``xstats_get_names``.
-* **[implements] eth_dev_ops**: ``xstats_get_by_id``, ``xstats_get_names_by_id``.
+* **[implements] eth_dev_ops**: ``xstats_get_by_id``.
 * **[related]    API**: ``rte_eth_xstats_get()``, ``rte_eth_xstats_reset()``,
   ``rte_eth_xstats_get_names``, ``rte_eth_xstats_get_by_id()``,
   ``rte_eth_xstats_get_names_by_id()``, ``rte_eth_xstats_get_id_by_name()``.
diff --git a/drivers/net/atlantic/atl_ethdev.c b/drivers/net/atlantic/atl_ethdev.c
index 0ce35eb519..f55d18ae9a 100644
--- a/drivers/net/atlantic/atl_ethdev.c
+++ b/drivers/net/atlantic/atl_ethdev.c
@@ -29,6 +29,7 @@ static int atl_dev_allmulticast_disable(struct rte_eth_dev *dev);
 static int  atl_dev_link_update(struct rte_eth_dev *dev, int wait);
 
 static int atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
 				    unsigned int size);
 
@@ -1003,12 +1004,16 @@ atl_dev_xstats_get_count(struct rte_eth_dev *dev)
 
 static int
 atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+			 const uint64_t *ids,
 			 struct rte_eth_xstat_name *xstats_names,
 			 unsigned int size)
 {
 	unsigned int i;
 	unsigned int count = atl_dev_xstats_get_count(dev);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names) {
 		for (i = 0; i < size && i < count; i++) {
 			snprintf(xstats_names[i].name,
diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
index ebd5411fdd..6a55a211df 100644
--- a/drivers/net/axgbe/axgbe_ethdev.c
+++ b/drivers/net/axgbe/axgbe_ethdev.c
@@ -47,19 +47,14 @@ static int axgbe_dev_xstats_get(struct rte_eth_dev *dev,
 				struct rte_eth_xstat *stats,
 				unsigned int n);
 static int
-axgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int size);
-static int
 axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			   const uint64_t *ids,
 			   uint64_t *values,
 			   unsigned int n);
 static int
-axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 const uint64_t *ids,
-				 struct rte_eth_xstat_name *xstats_names,
-				 unsigned int size);
+axgbe_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int size);
 static int axgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int axgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
 			  struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -239,7 +234,6 @@ static const struct eth_dev_ops axgbe_eth_dev_ops = {
 	.xstats_get	      = axgbe_dev_xstats_get,
 	.xstats_reset	      = axgbe_dev_xstats_reset,
 	.xstats_get_names     = axgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = axgbe_dev_xstats_get_names_by_id,
 	.xstats_get_by_id     = axgbe_dev_xstats_get_by_id,
 	.reta_update          = axgbe_dev_rss_reta_update,
 	.reta_query           = axgbe_dev_rss_reta_query,
@@ -1022,9 +1016,9 @@ axgbe_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
 }
 
 static int
-axgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int n)
+axgbe_dev_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			       struct rte_eth_xstat_name *xstats_names,
+			       unsigned int n)
 {
 	unsigned int i;
 
@@ -1075,18 +1069,18 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 const uint64_t *ids,
-				 struct rte_eth_xstat_name *xstats_names,
-				 unsigned int size)
+axgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+			   const uint64_t *ids,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int size)
 {
 	struct rte_eth_xstat_name xstats_names_copy[AXGBE_XSTATS_COUNT];
 	unsigned int i;
 
 	if (!ids)
-		return axgbe_dev_xstats_get_names(dev, xstats_names, size);
+		return axgbe_dev_xstats_get_all_names(dev, xstats_names, size);
 
-	axgbe_dev_xstats_get_names(dev, xstats_names_copy, size);
+	axgbe_dev_xstats_get_all_names(dev, xstats_names_copy, size);
 
 	for (i = 0; i < size; i++) {
 		if (ids[i] >= AXGBE_XSTATS_COUNT) {
diff --git a/drivers/net/bnx2x/bnx2x_ethdev.c b/drivers/net/bnx2x/bnx2x_ethdev.c
index 463886f17a..b18d14d735 100644
--- a/drivers/net/bnx2x/bnx2x_ethdev.c
+++ b/drivers/net/bnx2x/bnx2x_ethdev.c
@@ -484,11 +484,15 @@ bnx2x_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 static int
 bnx2x_get_xstats_names(__rte_unused struct rte_eth_dev *dev,
+		       const uint64_t *ids,
 		       struct rte_eth_xstat_name *xstats_names,
 		       __rte_unused unsigned limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(bnx2x_xstats_strings);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < stat_cnt; i++)
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index 991eafc644..aca350402b 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -845,6 +845,7 @@ int bnxt_flow_stats_cnt(struct bnxt *bp)
 }
 
 int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
+		const uint64_t *ids,
 		struct rte_eth_xstat_name *xstats_names,
 		__rte_unused unsigned int limit)
 {
@@ -862,6 +863,9 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
 	if (rc)
 		return rc;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		count = 0;
 
diff --git a/drivers/net/bnxt/bnxt_stats.h b/drivers/net/bnxt/bnxt_stats.h
index 1ca9b9c594..497380ae2d 100644
--- a/drivers/net/bnxt/bnxt_stats.h
+++ b/drivers/net/bnxt/bnxt_stats.h
@@ -13,6 +13,7 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
 			   struct rte_eth_stats *bnxt_stats);
 int bnxt_stats_reset_op(struct rte_eth_dev *eth_dev);
 int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
 	__rte_unused unsigned int limit);
 int bnxt_dev_xstats_get_op(struct rte_eth_dev *eth_dev,
diff --git a/drivers/net/cnxk/cnxk_ethdev.c b/drivers/net/cnxk/cnxk_ethdev.c
index 8629193d50..c208611e88 100644
--- a/drivers/net/cnxk/cnxk_ethdev.c
+++ b/drivers/net/cnxk/cnxk_ethdev.c
@@ -1258,7 +1258,6 @@ struct eth_dev_ops cnxk_eth_dev_ops = {
 	.xstats_get_names = cnxk_nix_xstats_get_names,
 	.xstats_reset = cnxk_nix_xstats_reset,
 	.xstats_get_by_id = cnxk_nix_xstats_get_by_id,
-	.xstats_get_names_by_id = cnxk_nix_xstats_get_names_by_id,
 	.fw_version_get = cnxk_nix_fw_version_get,
 	.rxq_info_get = cnxk_nix_rxq_info_get,
 	.txq_info_get = cnxk_nix_txq_info_get,
diff --git a/drivers/net/cnxk/cnxk_ethdev.h b/drivers/net/cnxk/cnxk_ethdev.h
index 946629f72e..1165482baf 100644
--- a/drivers/net/cnxk/cnxk_ethdev.h
+++ b/drivers/net/cnxk/cnxk_ethdev.h
@@ -362,12 +362,9 @@ int cnxk_nix_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
 int cnxk_nix_xstats_get(struct rte_eth_dev *eth_dev,
 			struct rte_eth_xstat *xstats, unsigned int n);
 int cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			      const uint64_t *ids,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
-int cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				    const uint64_t *ids,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int limit);
 int cnxk_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev, const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int cnxk_nix_xstats_reset(struct rte_eth_dev *eth_dev);
diff --git a/drivers/net/cnxk/cnxk_stats.c b/drivers/net/cnxk/cnxk_stats.c
index 4b0deac05e..ae3eef3628 100644
--- a/drivers/net/cnxk/cnxk_stats.c
+++ b/drivers/net/cnxk/cnxk_stats.c
@@ -162,10 +162,10 @@ cnxk_nix_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats,
 	return size;
 }
 
-int
-cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
-			  struct rte_eth_xstat_name *xstats_names,
-			  unsigned int limit)
+static int
+cnxk_nix_xstats_get_all_names(struct rte_eth_dev *eth_dev,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	struct roc_nix_xstat_name roc_xstats_name[limit];
@@ -226,10 +226,10 @@ cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 }
 
 int
-cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				const uint64_t *ids,
-				struct rte_eth_xstat_name *xstats_names,
-				unsigned int limit)
+cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			  const uint64_t *ids,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	uint32_t nix_cnt = roc_nix_num_xstats_get(&dev->nix);
@@ -247,7 +247,7 @@ cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 	if (xstats_names == NULL)
 		return -ENOMEM;
 
-	cnxk_nix_xstats_get_names(eth_dev, xnames, stat_cnt);
+	cnxk_nix_xstats_get_all_names(eth_dev, xnames, stat_cnt);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt)
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 4929766d9a..371550069e 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -1005,10 +1005,10 @@ static int cxgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 }
 
 /* Get names of port extended statistics by ID. */
-static int cxgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-					    const uint64_t *ids,
-					    struct rte_eth_xstat_name *xnames,
-					    unsigned int n)
+static int cxgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+				      const uint64_t *ids,
+				      struct rte_eth_xstat_name *xnames,
+				      unsigned int n)
 {
 	struct port_info *pi = dev->data->dev_private;
 	struct rte_eth_xstat_name *xnames_copy;
@@ -1048,14 +1048,6 @@ static int cxgbe_dev_xstats_get(struct rte_eth_dev *dev,
 	return cxgbe_dev_xstats(dev, NULL, xstats, n);
 }
 
-/* Get names of port extended statistics. */
-static int cxgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
-				      struct rte_eth_xstat_name *xstats_names,
-				      unsigned int n)
-{
-	return cxgbe_dev_xstats(dev, xstats_names, NULL, n);
-}
-
 /* Reset port extended statistics. */
 static int cxgbe_dev_xstats_reset(struct rte_eth_dev *dev)
 {
@@ -1620,7 +1612,6 @@ static const struct eth_dev_ops cxgbe_eth_dev_ops = {
 	.xstats_get             = cxgbe_dev_xstats_get,
 	.xstats_get_by_id       = cxgbe_dev_xstats_get_by_id,
 	.xstats_get_names       = cxgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = cxgbe_dev_xstats_get_names_by_id,
 	.xstats_reset           = cxgbe_dev_xstats_reset,
 	.flow_ctrl_get		= cxgbe_flow_ctrl_get,
 	.flow_ctrl_set		= cxgbe_flow_ctrl_set,
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index 1f80e8d744..06e293b17f 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -758,9 +758,9 @@ dpaa_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int
-dpaa_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-		      struct rte_eth_xstat_name *xstats_names,
-		      unsigned int limit)
+dpaa_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa_xstats_strings);
 
@@ -813,7 +813,7 @@ dpaa_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-dpaa_xstats_get_names_by_id(
+dpaa_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -823,9 +823,9 @@ dpaa_xstats_get_names_by_id(
 	struct rte_eth_xstat_name xstats_names_copy[stat_cnt];
 
 	if (!ids)
-		return dpaa_xstats_get_names(dev, xstats_names, limit);
+		return dpaa_xstats_get_all_names(dev, xstats_names, limit);
 
-	dpaa_xstats_get_names(dev, xstats_names_copy, limit);
+	dpaa_xstats_get_all_names(dev, xstats_names_copy, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt) {
@@ -1585,7 +1585,6 @@ static struct eth_dev_ops dpaa_devops = {
 	.stats_get		  = dpaa_eth_stats_get,
 	.xstats_get		  = dpaa_dev_xstats_get,
 	.xstats_get_by_id	  = dpaa_xstats_get_by_id,
-	.xstats_get_names_by_id	  = dpaa_xstats_get_names_by_id,
 	.xstats_get_names	  = dpaa_xstats_get_names,
 	.xstats_reset		  = dpaa_eth_stats_reset,
 	.stats_reset		  = dpaa_eth_stats_reset,
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index ea191564fc..9aaeb0bc17 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -1711,9 +1711,9 @@ dpaa2_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int
-dpaa2_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-		       struct rte_eth_xstat_name *xstats_names,
-		       unsigned int limit)
+dpaa2_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa2_xstats_strings);
 
@@ -1793,7 +1793,7 @@ dpaa2_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-dpaa2_xstats_get_names_by_id(
+dpaa2_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -1803,9 +1803,9 @@ dpaa2_xstats_get_names_by_id(
 	struct rte_eth_xstat_name xstats_names_copy[stat_cnt];
 
 	if (!ids)
-		return dpaa2_xstats_get_names(dev, xstats_names, limit);
+		return dpaa2_xstats_get_all_names(dev, xstats_names, limit);
 
-	dpaa2_xstats_get_names(dev, xstats_names_copy, limit);
+	dpaa2_xstats_get_all_names(dev, xstats_names_copy, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt) {
@@ -2413,7 +2413,6 @@ static struct eth_dev_ops dpaa2_ethdev_ops = {
 	.stats_get	       = dpaa2_dev_stats_get,
 	.xstats_get	       = dpaa2_dev_xstats_get,
 	.xstats_get_by_id     = dpaa2_xstats_get_by_id,
-	.xstats_get_names_by_id = dpaa2_xstats_get_names_by_id,
 	.xstats_get_names      = dpaa2_xstats_get_names,
 	.stats_reset	   = dpaa2_dev_stats_reset,
 	.xstats_reset	      = dpaa2_dev_stats_reset,
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 6510cd7ceb..8bf254a802 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -93,9 +93,6 @@ static int eth_igb_xstats_get_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids,
 		uint64_t *values, unsigned int n);
 static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int size);
-static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igb_stats_reset(struct rte_eth_dev *dev);
@@ -166,6 +163,7 @@ static int eth_igbvf_stats_get(struct rte_eth_dev *dev,
 static int eth_igbvf_xstats_get(struct rte_eth_dev *dev,
 				struct rte_eth_xstat *xstats, unsigned n);
 static int eth_igbvf_xstats_get_names(struct rte_eth_dev *dev,
+				      const uint64_t *ids,
 				      struct rte_eth_xstat_name *xstats_names,
 				      unsigned limit);
 static int eth_igbvf_stats_reset(struct rte_eth_dev *dev);
@@ -343,7 +341,6 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.stats_get            = eth_igb_stats_get,
 	.xstats_get           = eth_igb_xstats_get,
 	.xstats_get_by_id     = eth_igb_xstats_get_by_id,
-	.xstats_get_names_by_id = eth_igb_xstats_get_names_by_id,
 	.xstats_get_names     = eth_igb_xstats_get_names,
 	.stats_reset          = eth_igb_stats_reset,
 	.xstats_reset         = eth_igb_xstats_reset,
@@ -1863,26 +1860,7 @@ eth_igb_xstats_reset(struct rte_eth_dev *dev)
 	return 0;
 }
 
-static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
-	__rte_unused unsigned int size)
-{
-	unsigned i;
-
-	if (xstats_names == NULL)
-		return IGB_NB_XSTATS;
-
-	/* Note: limit checked in rte_eth_xstats_names() */
-
-	for (i = 0; i < IGB_NB_XSTATS; i++) {
-		strlcpy(xstats_names[i].name, rte_igb_stats_strings[i].name,
-			sizeof(xstats_names[i].name));
-	}
-
-	return IGB_NB_XSTATS;
-}
-
-static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
+static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
@@ -1902,7 +1880,7 @@ static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	} else {
 		struct rte_eth_xstat_name xstats_names_copy[IGB_NB_XSTATS];
 
-		eth_igb_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
+		eth_igb_xstats_get_names(dev, NULL, xstats_names_copy,
 				IGB_NB_XSTATS);
 
 		for (i = 0; i < limit; i++) {
@@ -2035,11 +2013,15 @@ igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats)
 }
 
 static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-				     struct rte_eth_xstat_name *xstats_names,
-				     __rte_unused unsigned limit)
+				      const uint64_t *ids,
+				      struct rte_eth_xstat_name *xstats_names,
+				      __rte_unused unsigned limit)
 {
 	unsigned i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < IGBVF_NB_XSTATS; i++) {
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index 4cebf60a68..a807e50dba 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -212,7 +212,7 @@ static void ena_interrupt_handler_rte(void *cb_arg);
 static void ena_timer_wd_callback(struct rte_timer *timer, void *arg);
 static void ena_destroy_device(struct rte_eth_dev *eth_dev);
 static int eth_ena_dev_init(struct rte_eth_dev *eth_dev);
-static int ena_xstats_get_names(struct rte_eth_dev *dev,
+static int ena_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n);
 static int ena_xstats_get(struct rte_eth_dev *dev,
@@ -2585,12 +2585,16 @@ int ena_copy_eni_stats(struct ena_adapter *adapter)
  *   Number of xstats names.
  */
 static int ena_xstats_get_names(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n)
 {
 	unsigned int xstats_count = ena_xstats_calc_num(dev->data);
 	unsigned int stat, i, count = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (n < xstats_count || !xstats_names)
 		return xstats_count;
 
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 5ff33e03e0..dae85b7677 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -990,12 +990,15 @@ __fs_xstats_get_names(struct rte_eth_dev *dev,
 }
 
 static int
-fs_xstats_get_names(struct rte_eth_dev *dev,
+fs_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 		    struct rte_eth_xstat_name *xstats_names,
 		    unsigned int limit)
 {
 	int ret;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	fs_lock(dev, 0);
 	ret = __fs_xstats_get_names(dev, xstats_names, limit);
 	fs_unlock(dev, 0);
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index 3236290e40..16af1751f9 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1232,11 +1232,15 @@ fm10k_link_update(struct rte_eth_dev *dev,
 }
 
 static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned limit)
 {
 	unsigned i, q;
 	unsigned count = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		/* Note: limit checked in rte_eth_xstats_names() */
 
diff --git a/drivers/net/hinic/hinic_pmd_ethdev.c b/drivers/net/hinic/hinic_pmd_ethdev.c
index c01e2ec1d4..bc6f07d070 100644
--- a/drivers/net/hinic/hinic_pmd_ethdev.c
+++ b/drivers/net/hinic/hinic_pmd_ethdev.c
@@ -2280,6 +2280,7 @@ static void hinic_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
  *   Number of xstats names.
  */
 static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
+			       const uint64_t *ids,
 			       struct rte_eth_xstat_name *xstats_names,
 			       __rte_unused unsigned int limit)
 {
@@ -2287,6 +2288,9 @@ static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
 	int count = 0;
 	u16 i = 0, q_num;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return hinic_xstats_calc_num(nic_dev);
 
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 7d37004972..87ae92080f 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -7413,7 +7413,6 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
 	.xstats_get_names   = hns3_dev_xstats_get_names,
 	.xstats_reset       = hns3_dev_xstats_reset,
 	.xstats_get_by_id   = hns3_dev_xstats_get_by_id,
-	.xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
 	.dev_infos_get          = hns3_dev_infos_get,
 	.fw_version_get         = hns3_fw_version_get,
 	.rx_queue_setup         = hns3_rx_queue_setup,
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 8d9b7979c8..d65236e003 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -2905,7 +2905,6 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
 	.xstats_get_names   = hns3_dev_xstats_get_names,
 	.xstats_reset       = hns3_dev_xstats_reset,
 	.xstats_get_by_id   = hns3_dev_xstats_get_by_id,
-	.xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
 	.dev_infos_get      = hns3vf_dev_infos_get,
 	.fw_version_get     = hns3vf_fw_version_get,
 	.rx_queue_setup     = hns3_rx_queue_setup,
diff --git a/drivers/net/hns3/hns3_stats.c b/drivers/net/hns3/hns3_stats.c
index 0fe853d626..abb2d42144 100644
--- a/drivers/net/hns3/hns3_stats.c
+++ b/drivers/net/hns3/hns3_stats.c
@@ -1189,7 +1189,7 @@ hns3_imissed_stats_name_get(struct rte_eth_dev *dev,
 }
 
 /*
- * Retrieve names of extended statistics of an Ethernet device.
+ * Retrieve all names of extended statistics of an Ethernet device.
  *
  * There is an assumption that 'xstat_names' and 'xstats' arrays are matched
  * by array index:
@@ -1212,10 +1212,10 @@ hns3_imissed_stats_name_get(struct rte_eth_dev *dev,
  *   - A positive value lower or equal to size: success. The return value
  *     is the number of entries filled in the stats table.
  */
-int
-hns3_dev_xstats_get_names(struct rte_eth_dev *dev,
-			  struct rte_eth_xstat_name *xstats_names,
-			  __rte_unused unsigned int size)
+static int
+hns3_dev_xstats_get_all_names(struct rte_eth_dev *dev,
+			      struct rte_eth_xstat_name *xstats_names,
+			      __rte_unused unsigned int size)
 {
 	struct hns3_adapter *hns = dev->data->dev_private;
 	int cnt_stats = hns3_xstats_calc_num(dev);
@@ -1382,10 +1382,9 @@ hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
  *     shall not be used by the caller.
  */
 int
-hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				const uint64_t *ids,
-				struct rte_eth_xstat_name *xstats_names,
-				uint32_t size)
+hns3_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+			  struct rte_eth_xstat_name *xstats_names,
+			  uint32_t size)
 {
 	const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
 	struct hns3_adapter *hns = dev->data->dev_private;
@@ -1401,7 +1400,8 @@ hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		if (size < cnt_stats)
 			return cnt_stats;
 
-		return hns3_dev_xstats_get_names(dev, xstats_names, cnt_stats);
+		return hns3_dev_xstats_get_all_names(dev, xstats_names,
+						     cnt_stats);
 	}
 
 	len = cnt_stats * sizeof(struct rte_eth_xstat_name);
@@ -1412,7 +1412,7 @@ hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		return -ENOMEM;
 	}
 
-	(void)hns3_dev_xstats_get_names(dev, names_copy, cnt_stats);
+	(void)hns3_dev_xstats_get_all_names(dev, names_copy, cnt_stats);
 
 	for (i = 0; i < size; i++) {
 		if (ids[i] >= cnt_stats) {
diff --git a/drivers/net/hns3/hns3_stats.h b/drivers/net/hns3/hns3_stats.h
index d1230f94cb..53fd1572f0 100644
--- a/drivers/net/hns3/hns3_stats.h
+++ b/drivers/net/hns3/hns3_stats.h
@@ -153,17 +153,13 @@ int hns3_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats);
 int hns3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 			unsigned int n);
 int hns3_dev_xstats_reset(struct rte_eth_dev *dev);
-int hns3_dev_xstats_get_names(struct rte_eth_dev *dev,
-			      struct rte_eth_xstat_name *xstats_names,
-			      __rte_unused unsigned int size);
 int hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			      const uint64_t *ids,
 			      uint64_t *values,
 			      uint32_t size);
-int hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				    const uint64_t *ids,
-				    struct rte_eth_xstat_name *xstats_names,
-				    uint32_t size);
+int hns3_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int size);
 int hns3_stats_reset(struct rte_eth_dev *dev);
 int hns3_tqp_stats_init(struct hns3_hw *hw);
 void hns3_tqp_stats_uninit(struct hns3_hw *hw);
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 7a2a8281d2..832c9bff01 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -258,6 +258,7 @@ static int i40e_dev_stats_get(struct rte_eth_dev *dev,
 static int i40e_dev_xstats_get(struct rte_eth_dev *dev,
 			       struct rte_eth_xstat *xstats, unsigned n);
 static int i40e_dev_xstats_get_names(struct rte_eth_dev *dev,
+				     const uint64_t *ids,
 				     struct rte_eth_xstat_name *xstats_names,
 				     unsigned limit);
 static int i40e_dev_stats_reset(struct rte_eth_dev *dev);
@@ -3567,12 +3568,16 @@ i40e_xstats_calc_num(void)
 }
 
 static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+				     const uint64_t *ids,
 				     struct rte_eth_xstat_name *xstats_names,
 				     __rte_unused unsigned limit)
 {
 	unsigned count = 0;
 	unsigned i, prio;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return i40e_xstats_calc_num();
 
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 5a5a7f59e1..a7be7abf1a 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -87,8 +87,9 @@ static int iavf_dev_stats_reset(struct rte_eth_dev *dev);
 static int iavf_dev_xstats_get(struct rte_eth_dev *dev,
 				 struct rte_eth_xstat *xstats, unsigned int n);
 static int iavf_dev_xstats_get_names(struct rte_eth_dev *dev,
-				       struct rte_eth_xstat_name *xstats_names,
-				       unsigned int limit);
+				     const uint64_t *ids,
+				     struct rte_eth_xstat_name *xstats_names,
+				     unsigned int limit);
 static int iavf_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static int iavf_dev_promiscuous_disable(struct rte_eth_dev *dev);
 static int iavf_dev_allmulticast_enable(struct rte_eth_dev *dev);
@@ -1611,11 +1612,15 @@ iavf_dev_stats_reset(struct rte_eth_dev *dev)
 }
 
 static int iavf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-				      struct rte_eth_xstat_name *xstats_names,
-				      __rte_unused unsigned int limit)
+				     const uint64_t *ids,
+				     struct rte_eth_xstat_name *xstats_names,
+				     __rte_unused unsigned int limit)
 {
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < IAVF_NB_XSTATS; i++) {
 			snprintf(xstats_names[i].name,
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index ea3b5c02aa..adeb5a00f3 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -145,6 +145,7 @@ static int ice_stats_reset(struct rte_eth_dev *dev);
 static int ice_xstats_get(struct rte_eth_dev *dev,
 			  struct rte_eth_xstat *xstats, unsigned int n);
 static int ice_xstats_get_names(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int limit);
 static int ice_dev_flow_ops_get(struct rte_eth_dev *dev,
@@ -5420,12 +5421,16 @@ ice_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int ice_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				__rte_unused unsigned int limit)
 {
 	unsigned int count = 0;
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return ice_xstats_calc_num();
 
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index be2c066111..969e515a5f 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -213,9 +213,6 @@ static int eth_igc_xstats_get_by_id(struct rte_eth_dev *dev,
 				const uint64_t *ids,
 				uint64_t *values, unsigned int n);
 static int eth_igc_xstats_get_names(struct rte_eth_dev *dev,
-				struct rte_eth_xstat_name *xstats_names,
-				unsigned int size);
-static int eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igc_xstats_reset(struct rte_eth_dev *dev);
@@ -280,7 +277,6 @@ static const struct eth_dev_ops eth_igc_ops = {
 	.stats_get		= eth_igc_stats_get,
 	.xstats_get		= eth_igc_xstats_get,
 	.xstats_get_by_id	= eth_igc_xstats_get_by_id,
-	.xstats_get_names_by_id	= eth_igc_xstats_get_names_by_id,
 	.xstats_get_names	= eth_igc_xstats_get_names,
 	.stats_reset		= eth_igc_xstats_reset,
 	.xstats_reset		= eth_igc_xstats_reset,
@@ -1991,7 +1987,7 @@ eth_igc_xstats_reset(struct rte_eth_dev *dev)
 }
 
 static int
-eth_igc_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+eth_igc_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int size)
 {
 	unsigned int i;
@@ -2012,14 +2008,14 @@ eth_igc_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 }
 
 static int
-eth_igc_xstats_get_names_by_id(struct rte_eth_dev *dev,
+eth_igc_xstats_get_names(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
 	unsigned int i;
 
 	if (!ids)
-		return eth_igc_xstats_get_names(dev, xstats_names, limit);
+		return eth_igc_xstats_get_all_names(dev, xstats_names, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= IGC_NB_XSTATS) {
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 344c076f30..d813e9f909 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -50,8 +50,6 @@ static int  ionic_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 	const uint64_t *ids, uint64_t *values, unsigned int n);
 static int  ionic_dev_xstats_reset(struct rte_eth_dev *dev);
 static int  ionic_dev_xstats_get_names(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, unsigned int size);
-static int  ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit);
 static int  ionic_dev_fw_version_get(struct rte_eth_dev *eth_dev,
@@ -119,7 +117,6 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.xstats_get_by_id       = ionic_dev_xstats_get_by_id,
 	.xstats_reset           = ionic_dev_xstats_reset,
 	.xstats_get_names       = ionic_dev_xstats_get_names,
-	.xstats_get_names_by_id = ionic_dev_xstats_get_names_by_id,
 	.fw_version_get         = ionic_dev_fw_version_get,
 };
 
@@ -714,25 +711,7 @@ ionic_dev_stats_reset(struct rte_eth_dev *eth_dev)
 }
 
 static int
-ionic_dev_xstats_get_names(__rte_unused struct rte_eth_dev *eth_dev,
-		struct rte_eth_xstat_name *xstats_names,
-		__rte_unused unsigned int size)
-{
-	unsigned int i;
-
-	if (xstats_names != NULL) {
-		for (i = 0; i < IONIC_NB_HW_STATS; i++) {
-			snprintf(xstats_names[i].name,
-					sizeof(xstats_names[i].name),
-					"%s", rte_ionic_xstats_strings[i].name);
-		}
-	}
-
-	return IONIC_NB_HW_STATS;
-}
-
-static int
-ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+ionic_dev_xstats_get_names(struct rte_eth_dev *eth_dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
@@ -751,7 +730,7 @@ ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 		return IONIC_NB_HW_STATS;
 	}
 
-	ionic_dev_xstats_get_names_by_id(eth_dev, NULL, xstats_names_copy,
+	ionic_dev_xstats_get_names(eth_dev, NULL, xstats_names_copy,
 		IONIC_NB_HW_STATS);
 
 	for (i = 0; i < limit; i++) {
diff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c
index 589d9fa587..5312b955d6 100644
--- a/drivers/net/ipn3ke/ipn3ke_representor.c
+++ b/drivers/net/ipn3ke/ipn3ke_representor.c
@@ -2329,13 +2329,16 @@ ipn3ke_rpst_xstats_get
 
 static int
 ipn3ke_rpst_xstats_get_names
-(__rte_unused struct rte_eth_dev *dev,
+(__rte_unused struct rte_eth_dev *dev, const uint64_t *ids,
 struct rte_eth_xstat_name *xstats_names,
 __rte_unused unsigned int limit)
 {
 	unsigned int count = 0;
 	unsigned int i, prio;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return ipn3ke_rpst_xstats_calc_num();
 
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index aae8b55d83..51b86ea5ce 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -167,15 +167,12 @@ ixgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 static int ixgbe_dev_stats_reset(struct rte_eth_dev *dev);
 static int ixgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int ixgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
 	unsigned int size);
 static int ixgbevf_dev_xstats_get_names(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, unsigned limit);
-static int ixgbe_dev_xstats_get_names_by_id(
-	struct rte_eth_dev *dev,
 	const uint64_t *ids,
-	struct rte_eth_xstat_name *xstats_names,
-	unsigned int limit);
+	struct rte_eth_xstat_name *xstats_names, unsigned limit);
 static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
 					     uint16_t queue_id,
 					     uint8_t stat_idx,
@@ -499,7 +496,6 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.stats_reset          = ixgbe_dev_stats_reset,
 	.xstats_reset         = ixgbe_dev_xstats_reset,
 	.xstats_get_names     = ixgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = ixgbe_dev_xstats_get_names_by_id,
 	.queue_stats_mapping_set = ixgbe_dev_queue_stats_mapping_set,
 	.fw_version_get       = ixgbe_fw_version_get,
 	.dev_infos_get        = ixgbe_dev_info_get,
@@ -3381,61 +3377,7 @@ ixgbe_xstats_calc_num(void) {
 		(IXGBE_NB_TXQ_PRIO_STATS * IXGBE_NB_TXQ_PRIO_VALUES);
 }
 
-static int ixgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned int size)
-{
-	const unsigned cnt_stats = ixgbe_xstats_calc_num();
-	unsigned stat, i, count;
-
-	if (xstats_names != NULL) {
-		count = 0;
-
-		/* Note: limit >= cnt_stats checked upstream
-		 * in rte_eth_xstats_names()
-		 */
-
-		/* Extended stats from ixgbe_hw_stats */
-		for (i = 0; i < IXGBE_NB_HW_STATS; i++) {
-			strlcpy(xstats_names[count].name,
-				rte_ixgbe_stats_strings[i].name,
-				sizeof(xstats_names[count].name));
-			count++;
-		}
-
-		/* MACsec Stats */
-		for (i = 0; i < IXGBE_NB_MACSEC_STATS; i++) {
-			strlcpy(xstats_names[count].name,
-				rte_ixgbe_macsec_strings[i].name,
-				sizeof(xstats_names[count].name));
-			count++;
-		}
-
-		/* RX Priority Stats */
-		for (stat = 0; stat < IXGBE_NB_RXQ_PRIO_STATS; stat++) {
-			for (i = 0; i < IXGBE_NB_RXQ_PRIO_VALUES; i++) {
-				snprintf(xstats_names[count].name,
-					sizeof(xstats_names[count].name),
-					"rx_priority%u_%s", i,
-					rte_ixgbe_rxq_strings[stat].name);
-				count++;
-			}
-		}
-
-		/* TX Priority Stats */
-		for (stat = 0; stat < IXGBE_NB_TXQ_PRIO_STATS; stat++) {
-			for (i = 0; i < IXGBE_NB_TXQ_PRIO_VALUES; i++) {
-				snprintf(xstats_names[count].name,
-					sizeof(xstats_names[count].name),
-					"tx_priority%u_%s", i,
-					rte_ixgbe_txq_strings[stat].name);
-				count++;
-			}
-		}
-	}
-	return cnt_stats;
-}
-
-static int ixgbe_dev_xstats_get_names_by_id(
+static int ixgbe_dev_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -3497,8 +3439,7 @@ static int ixgbe_dev_xstats_get_names_by_id(
 	uint16_t size = ixgbe_xstats_calc_num();
 	struct rte_eth_xstat_name xstats_names_copy[size];
 
-	ixgbe_dev_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
-			size);
+	ixgbe_dev_xstats_get_names(dev, NULL, xstats_names_copy, size);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= size) {
@@ -3512,6 +3453,7 @@ static int ixgbe_dev_xstats_get_names_by_id(
 }
 
 static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names, unsigned limit)
 {
 	unsigned i;
@@ -3519,6 +3461,9 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	if (limit < IXGBEVF_NB_XSTATS && xstats_names != NULL)
 		return -ENOMEM;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < IXGBEVF_NB_XSTATS; i++)
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/liquidio/lio_ethdev.c b/drivers/net/liquidio/lio_ethdev.c
index b72060a449..68b674c2a6 100644
--- a/drivers/net/liquidio/lio_ethdev.c
+++ b/drivers/net/liquidio/lio_ethdev.c
@@ -214,6 +214,7 @@ lio_dev_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats,
 
 static int
 lio_dev_xstats_get_names(struct rte_eth_dev *eth_dev,
+			 const uint64_t *ids,
 			 struct rte_eth_xstat_name *xstats_names,
 			 unsigned limit __rte_unused)
 {
@@ -226,6 +227,9 @@ lio_dev_xstats_get_names(struct rte_eth_dev *eth_dev,
 		return -EINVAL;
 	}
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return LIO_NB_XSTATS;
 
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 3581414b78..4eab2554bc 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1620,6 +1620,7 @@ int mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
 		    unsigned int n);
 int mlx5_xstats_reset(struct rte_eth_dev *dev);
 int mlx5_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+			  const uint64_t *ids,
 			  struct rte_eth_xstat_name *xstats_names,
 			  unsigned int n);
 
diff --git a/drivers/net/mlx5/mlx5_stats.c b/drivers/net/mlx5/mlx5_stats.c
index ae2f5668a7..d67afd6bc1 100644
--- a/drivers/net/mlx5/mlx5_stats.c
+++ b/drivers/net/mlx5/mlx5_stats.c
@@ -260,6 +260,8 @@ mlx5_xstats_reset(struct rte_eth_dev *dev)
  *
  * @param dev
  *   Pointer to Ethernet device structure.
+ * @param ids
+ *   Array of xstats IDs to get names
  * @param[out] xstats_names
  *   Buffer to insert names into.
  * @param n
@@ -269,7 +271,7 @@ mlx5_xstats_reset(struct rte_eth_dev *dev)
  *   Number of xstats names.
  */
 int
-mlx5_xstats_get_names(struct rte_eth_dev *dev,
+mlx5_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 		      struct rte_eth_xstat_name *xstats_names, unsigned int n)
 {
 	unsigned int i;
@@ -277,6 +279,9 @@ mlx5_xstats_get_names(struct rte_eth_dev *dev,
 	struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
 	unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (n >= mlx5_xstats_n && xstats_names) {
 		for (i = 0; i != mlx5_xstats_n; ++i) {
 			strncpy(xstats_names[i].name,
diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c
index 078aefbb8d..554aba1be9 100644
--- a/drivers/net/mvpp2/mrvl_ethdev.c
+++ b/drivers/net/mvpp2/mrvl_ethdev.c
@@ -1689,11 +1689,15 @@ mrvl_xstats_reset(struct rte_eth_dev *dev)
  */
 static int
 mrvl_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+		      const uint64_t *ids,
 		      struct rte_eth_xstat_name *xstats_names,
 		      unsigned int size)
 {
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return RTE_DIM(mrvl_xstats_tbl);
 
diff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c
index 9e2a405973..4260f0b4ab 100644
--- a/drivers/net/netvsc/hn_ethdev.c
+++ b/drivers/net/netvsc/hn_ethdev.c
@@ -851,13 +851,16 @@ hn_dev_xstats_count(struct rte_eth_dev *dev)
 }
 
 static int
-hn_dev_xstats_get_names(struct rte_eth_dev *dev,
+hn_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 			struct rte_eth_xstat_name *xstats_names,
 			unsigned int limit)
 {
 	unsigned int i, t, count = 0;
 	int ret;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return hn_dev_xstats_count(dev);
 
diff --git a/drivers/net/octeontx2/otx2_ethdev.c b/drivers/net/octeontx2/otx2_ethdev.c
index 75d4cabf2e..c1fd2ad7d5 100644
--- a/drivers/net/octeontx2/otx2_ethdev.c
+++ b/drivers/net/octeontx2/otx2_ethdev.c
@@ -2338,7 +2338,6 @@ static const struct eth_dev_ops otx2_eth_dev_ops = {
 	.xstats_get_names         = otx2_nix_xstats_get_names,
 	.xstats_reset             = otx2_nix_xstats_reset,
 	.xstats_get_by_id         = otx2_nix_xstats_get_by_id,
-	.xstats_get_names_by_id   = otx2_nix_xstats_get_names_by_id,
 	.rxq_info_get             = otx2_nix_rxq_info_get,
 	.txq_info_get             = otx2_nix_txq_info_get,
 	.rx_burst_mode_get        = otx2_rx_burst_mode_get,
diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h
index b1575f59a2..1eeb77c9dd 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -506,6 +506,7 @@ int otx2_nix_queue_stats_mapping(struct rte_eth_dev *dev,
 int otx2_nix_xstats_get(struct rte_eth_dev *eth_dev,
 			struct rte_eth_xstat *xstats, unsigned int n);
 int otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			      const uint64_t *ids,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
 int otx2_nix_xstats_reset(struct rte_eth_dev *eth_dev);
@@ -513,10 +514,6 @@ int otx2_nix_xstats_reset(struct rte_eth_dev *eth_dev);
 int otx2_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev,
 			      const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
-int otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				    const uint64_t *ids,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int limit);
 
 /* RSS */
 void otx2_nix_rss_set_key(struct otx2_eth_dev *dev,
diff --git a/drivers/net/octeontx2/otx2_stats.c b/drivers/net/octeontx2/otx2_stats.c
index 3adf21608c..70bfaa3d77 100644
--- a/drivers/net/octeontx2/otx2_stats.c
+++ b/drivers/net/octeontx2/otx2_stats.c
@@ -200,8 +200,8 @@ otx2_nix_xstats_get(struct rte_eth_dev *eth_dev,
 	return count;
 }
 
-int
-otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+static int
+otx2_nix_xstats_get_all_names(struct rte_eth_dev *eth_dev,
 			  struct rte_eth_xstat_name *xstats_names,
 			  unsigned int limit)
 {
@@ -239,10 +239,10 @@ otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 }
 
 int
-otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				const uint64_t *ids,
-				struct rte_eth_xstat_name *xstats_names,
-				unsigned int limit)
+otx2_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			  const uint64_t *ids,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	struct rte_eth_xstat_name xstats_names_copy[OTX2_NIX_NUM_XSTATS_REG];
 	uint16_t i;
@@ -256,7 +256,7 @@ otx2_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 	if (xstats_names == NULL)
 		return -ENOMEM;
 
-	otx2_nix_xstats_get_names(eth_dev, xstats_names_copy, limit);
+	otx2_nix_xstats_get_all_names(eth_dev, xstats_names_copy, limit);
 
 	for (i = 0; i < OTX2_NIX_NUM_XSTATS_REG; i++) {
 		if (ids[i] >= OTX2_NIX_NUM_XSTATS_REG) {
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index a4304e0eff..40443b30bf 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -1718,6 +1718,7 @@ qede_get_xstats_count(struct qede_dev *qdev) {
 
 static int
 qede_get_xstats_names(struct rte_eth_dev *dev,
+		      const uint64_t *ids,
 		      struct rte_eth_xstat_name *xstats_names,
 		      __rte_unused unsigned int limit)
 {
@@ -1726,6 +1727,9 @@ qede_get_xstats_names(struct rte_eth_dev *dev,
 	const unsigned int stat_cnt = qede_get_xstats_count(qdev);
 	unsigned int i, qid, hw_fn, stat_idx = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return stat_cnt;
 
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index f212ca8ad6..d05a1fb5ca 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -763,43 +763,6 @@ sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	return nb_supported;
 }
 
-static int
-sfc_xstats_get_names(struct rte_eth_dev *dev,
-		     struct rte_eth_xstat_name *xstats_names,
-		     unsigned int xstats_count)
-{
-	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
-	struct sfc_port *port = &sa->port;
-	unsigned int i;
-	unsigned int nstats = 0;
-	unsigned int nb_written = 0;
-	int ret;
-
-	if (unlikely(xstats_names == NULL))
-		return sfc_xstats_get_nb_supported(sa);
-
-	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
-		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
-			if (nstats < xstats_count) {
-				strlcpy(xstats_names[nstats].name,
-					efx_mac_stat_name(sa->nic, i),
-					sizeof(xstats_names[0].name));
-				nb_written++;
-			}
-			nstats++;
-		}
-	}
-
-	ret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,
-				      &nb_written, &nstats);
-	if (ret != 0) {
-		SFC_ASSERT(ret < 0);
-		return ret;
-	}
-
-	return nstats;
-}
-
 static int
 sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 		     uint64_t *values, unsigned int n)
@@ -837,10 +800,42 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
-			   const uint64_t *ids,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int size)
+sfc_xstats_get_all_names(struct sfc_adapter *sa,
+			 struct rte_eth_xstat_name *xstats_names,
+			 unsigned int xstats_count)
+{
+	struct sfc_port *port = &sa->port;
+	unsigned int i;
+	unsigned int nstats = 0;
+	unsigned int nb_written = 0;
+	int ret;
+
+	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
+		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
+			if (nstats < xstats_count) {
+				strlcpy(xstats_names[nstats].name,
+					efx_mac_stat_name(sa->nic, i),
+					sizeof(xstats_names[0].name));
+				nb_written++;
+			}
+			nstats++;
+		}
+	}
+
+	ret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,
+				      &nb_written, &nstats);
+	if (ret != 0) {
+		SFC_ASSERT(ret < 0);
+		return ret;
+	}
+
+	return nstats;
+}
+
+static int
+sfc_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+		     struct rte_eth_xstat_name *xstats_names,
+		     unsigned int size)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
@@ -848,13 +843,15 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int i;
 	int ret;
 
-	if (unlikely(xstats_names == NULL && ids != NULL) ||
-	    unlikely(xstats_names != NULL && ids == NULL))
+	if (unlikely(xstats_names == NULL && ids != NULL))
 		return -EINVAL;
 
 	if (unlikely(xstats_names == NULL && ids == NULL))
 		return sfc_xstats_get_nb_supported(sa);
 
+	if (ids == NULL)
+		return sfc_xstats_get_all_names(sa, xstats_names, size);
+
 	/*
 	 * Names array could be filled in nonsequential order. Fill names with
 	 * string indicating invalid ID first.
@@ -1905,7 +1902,6 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {
 	.txq_info_get			= sfc_tx_queue_info_get,
 	.fw_version_get			= sfc_fw_version_get,
 	.xstats_get_by_id		= sfc_xstats_get_by_id,
-	.xstats_get_names_by_id		= sfc_xstats_get_names_by_id,
 	.pool_ops_supported		= sfc_pool_ops_supported,
 };
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index b267da462b..be6e073141 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2424,7 +2424,7 @@ txgbe_get_offset_by_id(uint32_t id, uint32_t *offset)
 	return -1;
 }
 
-static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+static int txgbe_dev_xstats_get_all_names(struct rte_eth_dev *dev,
 	struct rte_eth_xstat_name *xstats_names, unsigned int limit)
 {
 	unsigned int i, count;
@@ -2450,7 +2450,7 @@ static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
 	return i;
 }
 
-static int txgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+static int txgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
 	unsigned int limit)
@@ -2458,7 +2458,7 @@ static int txgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	unsigned int i;
 
 	if (ids == NULL)
-		return txgbe_dev_xstats_get_names(dev, xstats_names, limit);
+		return txgbe_dev_xstats_get_all_names(dev, xstats_names, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (txgbe_get_name_by_id(ids[i], xstats_names[i].name,
@@ -5292,7 +5292,6 @@ static const struct eth_dev_ops txgbe_eth_dev_ops = {
 	.stats_reset                = txgbe_dev_stats_reset,
 	.xstats_reset               = txgbe_dev_xstats_reset,
 	.xstats_get_names           = txgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id     = txgbe_dev_xstats_get_names_by_id,
 	.queue_stats_mapping_set    = txgbe_dev_queue_stats_mapping_set,
 	.fw_version_get             = txgbe_fw_version_get,
 	.dev_supported_ptypes_get   = txgbe_dev_supported_ptypes_get,
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index 896da8a887..cbe2f46f34 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -348,10 +348,14 @@ static struct rte_pci_driver rte_txgbevf_pmd = {
 };
 
 static int txgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names, unsigned int limit)
 {
 	unsigned int i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (limit < TXGBEVF_NB_XSTATS && xstats_names != NULL)
 		return -ENOMEM;
 
diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index a202931e9a..e5d723bfd7 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -251,6 +251,7 @@ vhost_dev_xstats_reset(struct rte_eth_dev *dev)
 
 static int
 vhost_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+			   const uint64_t *ids,
 			   struct rte_eth_xstat_name *xstats_names,
 			   unsigned int limit __rte_unused)
 {
@@ -258,6 +259,9 @@ vhost_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
 	int count = 0;
 	int nstats = VHOST_NB_XSTATS_RXPORT + VHOST_NB_XSTATS_TXPORT;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names)
 		return nstats;
 	for (t = 0; t < VHOST_NB_XSTATS_RXPORT; t++) {
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b60eeb24ab..da405e0896 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -60,6 +60,7 @@ static int virtio_dev_stats_get(struct rte_eth_dev *dev,
 static int virtio_dev_xstats_get(struct rte_eth_dev *dev,
 				 struct rte_eth_xstat *xstats, unsigned n);
 static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
+				       const uint64_t *ids,
 				       struct rte_eth_xstat_name *xstats_names,
 				       unsigned limit);
 static int virtio_dev_stats_reset(struct rte_eth_dev *dev);
@@ -1045,6 +1046,7 @@ virtio_update_stats(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 }
 
 static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
+				       const uint64_t *ids,
 				       struct rte_eth_xstat_name *xstats_names,
 				       __rte_unused unsigned limit)
 {
@@ -1055,6 +1057,9 @@ static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
 	unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_TXQ_XSTATS +
 		dev->data->nb_rx_queues * VIRTIO_NB_RXQ_XSTATS;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		/* Note: limit checked in rte_eth_xstats_names() */
 
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 2f40ae907d..48767e6db1 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -80,6 +80,7 @@ static int vmxnet3_dev_stats_get(struct rte_eth_dev *dev,
 				  struct rte_eth_stats *stats);
 static int vmxnet3_dev_stats_reset(struct rte_eth_dev *dev);
 static int vmxnet3_dev_xstats_get_names(struct rte_eth_dev *dev,
+					const uint64_t *ids,
 					struct rte_eth_xstat_name *xstats,
 					unsigned int n);
 static int vmxnet3_dev_xstats_get(struct rte_eth_dev *dev,
@@ -1201,6 +1202,7 @@ vmxnet3_hw_stats_save(struct vmxnet3_hw *hw)
 
 static int
 vmxnet3_dev_xstats_get_names(struct rte_eth_dev *dev,
+			     const uint64_t *ids,
 			     struct rte_eth_xstat_name *xstats_names,
 			     unsigned int n)
 {
@@ -1209,6 +1211,9 @@ vmxnet3_dev_xstats_get_names(struct rte_eth_dev *dev,
 		dev->data->nb_tx_queues * RTE_DIM(vmxnet3_txq_stat_strings) +
 		dev->data->nb_rx_queues * RTE_DIM(vmxnet3_rxq_stat_strings);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (!xstats_names || n < nstats)
 		return nstats;
 
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 6a2be98c1f..9423200d9f 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -227,10 +227,6 @@ typedef int (*eth_xstats_get_by_id_t)(struct rte_eth_dev *dev,
  */
 typedef int (*eth_xstats_reset_t)(struct rte_eth_dev *dev);
 
-typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names, unsigned int size);
-/**< @internal Get names of extended stats of an Ethernet device. */
-
 /**
  * @internal
  * Get names of extended stats of an Ethernet device.
@@ -238,13 +234,12 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  * @param dev
  *   ethdev handle of port.
  * @param ids
- *   IDs array to retrieve specific statistics. Can be NULL together
- *   with @p xstats_names to retrieve number of available statistics.
- * @param ids
- *   IDs array to retrieve specific statistics. Must not be NULL.
+ *   IDs array to retrieve specific statistics. Can be NULL to get names
+ *   of all available statistics.
  * @param xstats_names
  *   An rte_eth_xstat_name array of at least *size* elements to
- *   be filled. Must not be NULL.
+ *   be filled. Can be NULL together with @p ids to get number of
+ *   extended statistics.
  * @param size
  *   Element count in @p ids and @p xstats_names.
  *
@@ -253,7 +248,7 @@ typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
  *   - A number of available stats if both xstats_names and ids are NULL.
  *   - A negative value on error.
  */
-typedef int (*eth_xstats_get_names_by_id_t)(struct rte_eth_dev *dev,
+typedef int (*eth_xstats_get_names_t)(struct rte_eth_dev *dev,
 	const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 	unsigned int size);
 
@@ -940,8 +935,6 @@ struct eth_dev_ops {
 
 	eth_xstats_get_by_id_t     xstats_get_by_id;
 	/**< Get extended device statistic values by ID. */
-	eth_xstats_get_names_by_id_t xstats_get_names_by_id;
-	/**< Get name of extended device statistics by ID. */
 
 	eth_tm_ops_get_t tm_ops_get;
 	/**< Get Traffic Management (TM) operations. */
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index 655d7be3b5..c951c0ba35 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -2867,7 +2867,7 @@ eth_dev_get_xstats_count(uint16_t port_id)
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
 	if (dev->dev_ops->xstats_get_names != NULL) {
-		count = (*dev->dev_ops->xstats_get_names)(dev, NULL, 0);
+		count = (*dev->dev_ops->xstats_get_names)(dev, NULL, NULL, 0);
 		if (count < 0)
 			return eth_err(port_id, count);
 	} else
@@ -3005,7 +3005,7 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
 	if (ids && !xstats_names)
 		return -EINVAL;
 
-	if (ids && dev->dev_ops->xstats_get_names_by_id != NULL && size > 0) {
+	if (ids && dev->dev_ops->xstats_get_names != NULL && size > 0) {
 		uint64_t ids_copy[size];
 
 		for (i = 0; i < size; i++) {
@@ -3021,9 +3021,16 @@ rte_eth_xstats_get_names_by_id(uint16_t port_id,
 			ids_copy[i] = ids[i] - basic_count;
 		}
 
-		if (no_basic_stat_requested)
-			return (*dev->dev_ops->xstats_get_names_by_id)(dev,
+		if (no_basic_stat_requested) {
+			ret = (*dev->dev_ops->xstats_get_names)(dev,
 					ids_copy, xstats_names, size);
+			if (ret == 0 || ret != -ENOTSUP)
+				return ret;
+			/*
+			 * Driver does not support getting names by IDs.
+			 * Fallback to support on ethdev layer.
+			 */
+		}
 	}
 
 	/* Retrieve all stats */
@@ -3104,7 +3111,7 @@ rte_eth_xstats_get_names(uint16_t port_id,
 		 * to end of list.
 		 */
 		cnt_driver_entries = (*dev->dev_ops->xstats_get_names)(
-			dev,
+			dev, NULL,
 			xstats_names + cnt_used_entries,
 			size - cnt_used_entries);
 		if (cnt_driver_entries < 0)
-- 
2.30.2


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [dpdk-dev] [PATCH v7 5/5] ethdev: merge driver ops to get all xstats names and by ID
  2021-09-30 16:01 ` [dpdk-dev] [PATCH v7 1/4] ethdev: do not use get xstats names by IDs to obtain count Andrew Rybchenko
                     ` (6 preceding siblings ...)
  2021-09-30 16:01   ` [dpdk-dev] [PATCH v7 4/4] ethdev: merge driver ops to get all xstats names and by ID Andrew Rybchenko
@ 2021-09-30 16:01   ` Andrew Rybchenko
  7 siblings, 0 replies; 113+ messages in thread
From: Andrew Rybchenko @ 2021-09-30 16:01 UTC (permalink / raw)
  To: Igor Russkikh, Somalapuram Amaranath, Rasesh Mody, Shahed Shaikh,
	Ajit Khaparde, Somnath Kotur, Nithin Dabilpuram, Kiran Kumar K,
	Sunil Kumar Kori, Satha Rao, Rahul Lakkireddy, Hemant Agrawal,
	Sachin Saxena, Haiyue Wang, Marcin Wojtas, Michal Krawczyk,
	Shai Brandes, Evgeny Schemeilin, Igor Chauskin, Gaetan Rivet,
	Qi Zhang, Xiao Wang, Ziyang Xuan, Xiaoyun Wang, Guoyang Zhou,
	Min Hu (Connor),
	Yisen Zhuang, Lijun Ou, Beilei Xing, Jingjing Wu, Qiming Yang,
	Andrew Boyer, Rosen Xu, Shijith Thotton,
	Srisivasubramanian Srinivasan, Matan Azrad, Viacheslav Ovsiienko,
	Liron Himi, Stephen Hemminger, Long Li, Jerin Jacob,
	Devendra Singh Rawat, Jiawen Wu, Jian Wang, Maxime Coquelin,
	Chenbo Xia, Yong Wang, Thomas Monjalon, Ferruh Yigit
  Cc: dev

All xstats names may be retrieved passing NULL ids.

If a driver does not support getting names by IDs, the callback should
return -ENOTSUP on attempt to use it. If so, the request is handled
on ethdev layer by getting all names and filtering out requested only.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
---
 doc/guides/nics/features.rst            |  2 +-
 drivers/net/atlantic/atl_ethdev.c       |  5 ++
 drivers/net/axgbe/axgbe_ethdev.c        | 30 ++++-----
 drivers/net/bnx2x/bnx2x_ethdev.c        |  4 ++
 drivers/net/bnxt/bnxt_stats.c           |  4 ++
 drivers/net/bnxt/bnxt_stats.h           |  1 +
 drivers/net/cnxk/cnxk_ethdev.c          |  1 -
 drivers/net/cnxk/cnxk_ethdev.h          |  5 +-
 drivers/net/cnxk/cnxk_stats.c           | 18 +++---
 drivers/net/cxgbe/cxgbe_ethdev.c        | 17 ++---
 drivers/net/dpaa/dpaa_ethdev.c          | 13 ++--
 drivers/net/dpaa2/dpaa2_ethdev.c        | 13 ++--
 drivers/net/e1000/igb_ethdev.c          | 36 +++--------
 drivers/net/ena/ena_ethdev.c            |  6 +-
 drivers/net/failsafe/failsafe_ops.c     |  5 +-
 drivers/net/fm10k/fm10k_ethdev.c        |  4 ++
 drivers/net/hinic/hinic_pmd_ethdev.c    |  4 ++
 drivers/net/hns3/hns3_ethdev.c          |  1 -
 drivers/net/hns3/hns3_ethdev_vf.c       |  1 -
 drivers/net/hns3/hns3_stats.c           | 22 +++----
 drivers/net/hns3/hns3_stats.h           | 10 +--
 drivers/net/i40e/i40e_ethdev.c          |  5 ++
 drivers/net/iavf/iavf_ethdev.c          | 13 ++--
 drivers/net/ice/ice_ethdev.c            |  5 ++
 drivers/net/igc/igc_ethdev.c            | 10 +--
 drivers/net/ionic/ionic_ethdev.c        | 25 +-------
 drivers/net/ipn3ke/ipn3ke_representor.c |  5 +-
 drivers/net/ixgbe/ixgbe_ethdev.c        | 71 +++------------------
 drivers/net/liquidio/lio_ethdev.c       |  4 ++
 drivers/net/mlx5/mlx5.h                 |  1 +
 drivers/net/mlx5/mlx5_stats.c           |  7 ++-
 drivers/net/mvpp2/mrvl_ethdev.c         |  4 ++
 drivers/net/netvsc/hn_ethdev.c          |  5 +-
 drivers/net/octeontx2/otx2_ethdev.c     |  1 -
 drivers/net/octeontx2/otx2_ethdev.h     |  5 +-
 drivers/net/octeontx2/otx2_stats.c      | 14 ++---
 drivers/net/qede/qede_ethdev.c          |  4 ++
 drivers/net/sfc/sfc_ethdev.c            | 84 ++++++++++++-------------
 drivers/net/txgbe/txgbe_ethdev.c        |  7 +--
 drivers/net/txgbe/txgbe_ethdev_vf.c     |  4 ++
 drivers/net/vhost/rte_eth_vhost.c       |  4 ++
 drivers/net/virtio/virtio_ethdev.c      |  5 ++
 drivers/net/vmxnet3/vmxnet3_ethdev.c    |  5 ++
 lib/ethdev/ethdev_driver.h              | 17 ++---
 lib/ethdev/rte_ethdev.c                 | 17 +++--
 45 files changed, 238 insertions(+), 286 deletions(-)

diff --git a/doc/guides/nics/features.rst b/doc/guides/nics/features.rst
index 4fce8cd1c9..8fef2939fb 100644
--- a/doc/guides/nics/features.rst
+++ b/doc/guides/nics/features.rst
@@ -708,7 +708,7 @@ Extended stats
 Supports Extended Statistics, changes from driver to driver.
 
 * **[implements] eth_dev_ops**: ``xstats_get``, ``xstats_reset``, ``xstats_get_names``.
-* **[implements] eth_dev_ops**: ``xstats_get_by_id``, ``xstats_get_names_by_id``.
+* **[implements] eth_dev_ops**: ``xstats_get_by_id``.
 * **[related]    API**: ``rte_eth_xstats_get()``, ``rte_eth_xstats_reset()``,
   ``rte_eth_xstats_get_names``, ``rte_eth_xstats_get_by_id()``,
   ``rte_eth_xstats_get_names_by_id()``, ``rte_eth_xstats_get_id_by_name()``.
diff --git a/drivers/net/atlantic/atl_ethdev.c b/drivers/net/atlantic/atl_ethdev.c
index 0ce35eb519..f55d18ae9a 100644
--- a/drivers/net/atlantic/atl_ethdev.c
+++ b/drivers/net/atlantic/atl_ethdev.c
@@ -29,6 +29,7 @@ static int atl_dev_allmulticast_disable(struct rte_eth_dev *dev);
 static int  atl_dev_link_update(struct rte_eth_dev *dev, int wait);
 
 static int atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+				    const uint64_t *ids,
 				    struct rte_eth_xstat_name *xstats_names,
 				    unsigned int size);
 
@@ -1003,12 +1004,16 @@ atl_dev_xstats_get_count(struct rte_eth_dev *dev)
 
 static int
 atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
+			 const uint64_t *ids,
 			 struct rte_eth_xstat_name *xstats_names,
 			 unsigned int size)
 {
 	unsigned int i;
 	unsigned int count = atl_dev_xstats_get_count(dev);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names) {
 		for (i = 0; i < size && i < count; i++) {
 			snprintf(xstats_names[i].name,
diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
index ebd5411fdd..6a55a211df 100644
--- a/drivers/net/axgbe/axgbe_ethdev.c
+++ b/drivers/net/axgbe/axgbe_ethdev.c
@@ -47,19 +47,14 @@ static int axgbe_dev_xstats_get(struct rte_eth_dev *dev,
 				struct rte_eth_xstat *stats,
 				unsigned int n);
 static int
-axgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int size);
-static int
 axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 			   const uint64_t *ids,
 			   uint64_t *values,
 			   unsigned int n);
 static int
-axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 const uint64_t *ids,
-				 struct rte_eth_xstat_name *xstats_names,
-				 unsigned int size);
+axgbe_dev_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int size);
 static int axgbe_dev_xstats_reset(struct rte_eth_dev *dev);
 static int axgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
 			  struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -239,7 +234,6 @@ static const struct eth_dev_ops axgbe_eth_dev_ops = {
 	.xstats_get	      = axgbe_dev_xstats_get,
 	.xstats_reset	      = axgbe_dev_xstats_reset,
 	.xstats_get_names     = axgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = axgbe_dev_xstats_get_names_by_id,
 	.xstats_get_by_id     = axgbe_dev_xstats_get_by_id,
 	.reta_update          = axgbe_dev_rss_reta_update,
 	.reta_query           = axgbe_dev_rss_reta_query,
@@ -1022,9 +1016,9 @@ axgbe_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
 }
 
 static int
-axgbe_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-			   struct rte_eth_xstat_name *xstats_names,
-			   unsigned int n)
+axgbe_dev_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			       struct rte_eth_xstat_name *xstats_names,
+			       unsigned int n)
 {
 	unsigned int i;
 
@@ -1075,18 +1069,18 @@ axgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-axgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-				 const uint64_t *ids,
-				 struct rte_eth_xstat_name *xstats_names,
-				 unsigned int size)
+axgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+			   const uint64_t *ids,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int size)
 {
 	struct rte_eth_xstat_name xstats_names_copy[AXGBE_XSTATS_COUNT];
 	unsigned int i;
 
 	if (!ids)
-		return axgbe_dev_xstats_get_names(dev, xstats_names, size);
+		return axgbe_dev_xstats_get_all_names(dev, xstats_names, size);
 
-	axgbe_dev_xstats_get_names(dev, xstats_names_copy, size);
+	axgbe_dev_xstats_get_all_names(dev, xstats_names_copy, size);
 
 	for (i = 0; i < size; i++) {
 		if (ids[i] >= AXGBE_XSTATS_COUNT) {
diff --git a/drivers/net/bnx2x/bnx2x_ethdev.c b/drivers/net/bnx2x/bnx2x_ethdev.c
index 463886f17a..b18d14d735 100644
--- a/drivers/net/bnx2x/bnx2x_ethdev.c
+++ b/drivers/net/bnx2x/bnx2x_ethdev.c
@@ -484,11 +484,15 @@ bnx2x_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 static int
 bnx2x_get_xstats_names(__rte_unused struct rte_eth_dev *dev,
+		       const uint64_t *ids,
 		       struct rte_eth_xstat_name *xstats_names,
 		       __rte_unused unsigned limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(bnx2x_xstats_strings);
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < stat_cnt; i++)
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index 991eafc644..aca350402b 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -845,6 +845,7 @@ int bnxt_flow_stats_cnt(struct bnxt *bp)
 }
 
 int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
+		const uint64_t *ids,
 		struct rte_eth_xstat_name *xstats_names,
 		__rte_unused unsigned int limit)
 {
@@ -862,6 +863,9 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
 	if (rc)
 		return rc;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		count = 0;
 
diff --git a/drivers/net/bnxt/bnxt_stats.h b/drivers/net/bnxt/bnxt_stats.h
index 1ca9b9c594..497380ae2d 100644
--- a/drivers/net/bnxt/bnxt_stats.h
+++ b/drivers/net/bnxt/bnxt_stats.h
@@ -13,6 +13,7 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
 			   struct rte_eth_stats *bnxt_stats);
 int bnxt_stats_reset_op(struct rte_eth_dev *eth_dev);
 int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
 	__rte_unused unsigned int limit);
 int bnxt_dev_xstats_get_op(struct rte_eth_dev *eth_dev,
diff --git a/drivers/net/cnxk/cnxk_ethdev.c b/drivers/net/cnxk/cnxk_ethdev.c
index 8629193d50..c208611e88 100644
--- a/drivers/net/cnxk/cnxk_ethdev.c
+++ b/drivers/net/cnxk/cnxk_ethdev.c
@@ -1258,7 +1258,6 @@ struct eth_dev_ops cnxk_eth_dev_ops = {
 	.xstats_get_names = cnxk_nix_xstats_get_names,
 	.xstats_reset = cnxk_nix_xstats_reset,
 	.xstats_get_by_id = cnxk_nix_xstats_get_by_id,
-	.xstats_get_names_by_id = cnxk_nix_xstats_get_names_by_id,
 	.fw_version_get = cnxk_nix_fw_version_get,
 	.rxq_info_get = cnxk_nix_rxq_info_get,
 	.txq_info_get = cnxk_nix_txq_info_get,
diff --git a/drivers/net/cnxk/cnxk_ethdev.h b/drivers/net/cnxk/cnxk_ethdev.h
index 946629f72e..1165482baf 100644
--- a/drivers/net/cnxk/cnxk_ethdev.h
+++ b/drivers/net/cnxk/cnxk_ethdev.h
@@ -362,12 +362,9 @@ int cnxk_nix_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
 int cnxk_nix_xstats_get(struct rte_eth_dev *eth_dev,
 			struct rte_eth_xstat *xstats, unsigned int n);
 int cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			      const uint64_t *ids,
 			      struct rte_eth_xstat_name *xstats_names,
 			      unsigned int limit);
-int cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				    const uint64_t *ids,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int limit);
 int cnxk_nix_xstats_get_by_id(struct rte_eth_dev *eth_dev, const uint64_t *ids,
 			      uint64_t *values, unsigned int n);
 int cnxk_nix_xstats_reset(struct rte_eth_dev *eth_dev);
diff --git a/drivers/net/cnxk/cnxk_stats.c b/drivers/net/cnxk/cnxk_stats.c
index 4b0deac05e..ae3eef3628 100644
--- a/drivers/net/cnxk/cnxk_stats.c
+++ b/drivers/net/cnxk/cnxk_stats.c
@@ -162,10 +162,10 @@ cnxk_nix_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats,
 	return size;
 }
 
-int
-cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
-			  struct rte_eth_xstat_name *xstats_names,
-			  unsigned int limit)
+static int
+cnxk_nix_xstats_get_all_names(struct rte_eth_dev *eth_dev,
+			      struct rte_eth_xstat_name *xstats_names,
+			      unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	struct roc_nix_xstat_name roc_xstats_name[limit];
@@ -226,10 +226,10 @@ cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
 }
 
 int
-cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
-				const uint64_t *ids,
-				struct rte_eth_xstat_name *xstats_names,
-				unsigned int limit)
+cnxk_nix_xstats_get_names(struct rte_eth_dev *eth_dev,
+			  const uint64_t *ids,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
 	uint32_t nix_cnt = roc_nix_num_xstats_get(&dev->nix);
@@ -247,7 +247,7 @@ cnxk_nix_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
 	if (xstats_names == NULL)
 		return -ENOMEM;
 
-	cnxk_nix_xstats_get_names(eth_dev, xnames, stat_cnt);
+	cnxk_nix_xstats_get_all_names(eth_dev, xnames, stat_cnt);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt)
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 4929766d9a..371550069e 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -1005,10 +1005,10 @@ static int cxgbe_dev_xstats_get_by_id(struct rte_eth_dev *dev,
 }
 
 /* Get names of port extended statistics by ID. */
-static int cxgbe_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
-					    const uint64_t *ids,
-					    struct rte_eth_xstat_name *xnames,
-					    unsigned int n)
+static int cxgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
+				      const uint64_t *ids,
+				      struct rte_eth_xstat_name *xnames,
+				      unsigned int n)
 {
 	struct port_info *pi = dev->data->dev_private;
 	struct rte_eth_xstat_name *xnames_copy;
@@ -1048,14 +1048,6 @@ static int cxgbe_dev_xstats_get(struct rte_eth_dev *dev,
 	return cxgbe_dev_xstats(dev, NULL, xstats, n);
 }
 
-/* Get names of port extended statistics. */
-static int cxgbe_dev_xstats_get_names(struct rte_eth_dev *dev,
-				      struct rte_eth_xstat_name *xstats_names,
-				      unsigned int n)
-{
-	return cxgbe_dev_xstats(dev, xstats_names, NULL, n);
-}
-
 /* Reset port extended statistics. */
 static int cxgbe_dev_xstats_reset(struct rte_eth_dev *dev)
 {
@@ -1620,7 +1612,6 @@ static const struct eth_dev_ops cxgbe_eth_dev_ops = {
 	.xstats_get             = cxgbe_dev_xstats_get,
 	.xstats_get_by_id       = cxgbe_dev_xstats_get_by_id,
 	.xstats_get_names       = cxgbe_dev_xstats_get_names,
-	.xstats_get_names_by_id = cxgbe_dev_xstats_get_names_by_id,
 	.xstats_reset           = cxgbe_dev_xstats_reset,
 	.flow_ctrl_get		= cxgbe_flow_ctrl_get,
 	.flow_ctrl_set		= cxgbe_flow_ctrl_set,
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index 1f80e8d744..06e293b17f 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -758,9 +758,9 @@ dpaa_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int
-dpaa_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-		      struct rte_eth_xstat_name *xstats_names,
-		      unsigned int limit)
+dpaa_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			  struct rte_eth_xstat_name *xstats_names,
+			  unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa_xstats_strings);
 
@@ -813,7 +813,7 @@ dpaa_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-dpaa_xstats_get_names_by_id(
+dpaa_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -823,9 +823,9 @@ dpaa_xstats_get_names_by_id(
 	struct rte_eth_xstat_name xstats_names_copy[stat_cnt];
 
 	if (!ids)
-		return dpaa_xstats_get_names(dev, xstats_names, limit);
+		return dpaa_xstats_get_all_names(dev, xstats_names, limit);
 
-	dpaa_xstats_get_names(dev, xstats_names_copy, limit);
+	dpaa_xstats_get_all_names(dev, xstats_names_copy, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt) {
@@ -1585,7 +1585,6 @@ static struct eth_dev_ops dpaa_devops = {
 	.stats_get		  = dpaa_eth_stats_get,
 	.xstats_get		  = dpaa_dev_xstats_get,
 	.xstats_get_by_id	  = dpaa_xstats_get_by_id,
-	.xstats_get_names_by_id	  = dpaa_xstats_get_names_by_id,
 	.xstats_get_names	  = dpaa_xstats_get_names,
 	.xstats_reset		  = dpaa_eth_stats_reset,
 	.stats_reset		  = dpaa_eth_stats_reset,
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index ea191564fc..9aaeb0bc17 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -1711,9 +1711,9 @@ dpaa2_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 }
 
 static int
-dpaa2_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-		       struct rte_eth_xstat_name *xstats_names,
-		       unsigned int limit)
+dpaa2_xstats_get_all_names(__rte_unused struct rte_eth_dev *dev,
+			   struct rte_eth_xstat_name *xstats_names,
+			   unsigned int limit)
 {
 	unsigned int i, stat_cnt = RTE_DIM(dpaa2_xstats_strings);
 
@@ -1793,7 +1793,7 @@ dpaa2_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
 }
 
 static int
-dpaa2_xstats_get_names_by_id(
+dpaa2_xstats_get_names(
 	struct rte_eth_dev *dev,
 	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names,
@@ -1803,9 +1803,9 @@ dpaa2_xstats_get_names_by_id(
 	struct rte_eth_xstat_name xstats_names_copy[stat_cnt];
 
 	if (!ids)
-		return dpaa2_xstats_get_names(dev, xstats_names, limit);
+		return dpaa2_xstats_get_all_names(dev, xstats_names, limit);
 
-	dpaa2_xstats_get_names(dev, xstats_names_copy, limit);
+	dpaa2_xstats_get_all_names(dev, xstats_names_copy, limit);
 
 	for (i = 0; i < limit; i++) {
 		if (ids[i] >= stat_cnt) {
@@ -2413,7 +2413,6 @@ static struct eth_dev_ops dpaa2_ethdev_ops = {
 	.stats_get	       = dpaa2_dev_stats_get,
 	.xstats_get	       = dpaa2_dev_xstats_get,
 	.xstats_get_by_id     = dpaa2_xstats_get_by_id,
-	.xstats_get_names_by_id = dpaa2_xstats_get_names_by_id,
 	.xstats_get_names      = dpaa2_xstats_get_names,
 	.stats_reset	   = dpaa2_dev_stats_reset,
 	.xstats_reset	      = dpaa2_dev_stats_reset,
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 6510cd7ceb..8bf254a802 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -93,9 +93,6 @@ static int eth_igb_xstats_get_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids,
 		uint64_t *values, unsigned int n);
 static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
-				    struct rte_eth_xstat_name *xstats_names,
-				    unsigned int size);
-static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit);
 static int eth_igb_stats_reset(struct rte_eth_dev *dev);
@@ -166,6 +163,7 @@ static int eth_igbvf_stats_get(struct rte_eth_dev *dev,
 static int eth_igbvf_xstats_get(struct rte_eth_dev *dev,
 				struct rte_eth_xstat *xstats, unsigned n);
 static int eth_igbvf_xstats_get_names(struct rte_eth_dev *dev,
+				      const uint64_t *ids,
 				      struct rte_eth_xstat_name *xstats_names,
 				      unsigned limit);
 static int eth_igbvf_stats_reset(struct rte_eth_dev *dev);
@@ -343,7 +341,6 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.stats_get            = eth_igb_stats_get,
 	.xstats_get           = eth_igb_xstats_get,
 	.xstats_get_by_id     = eth_igb_xstats_get_by_id,
-	.xstats_get_names_by_id = eth_igb_xstats_get_names_by_id,
 	.xstats_get_names     = eth_igb_xstats_get_names,
 	.stats_reset          = eth_igb_stats_reset,
 	.xstats_reset         = eth_igb_xstats_reset,
@@ -1863,26 +1860,7 @@ eth_igb_xstats_reset(struct rte_eth_dev *dev)
 	return 0;
 }
 
-static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-	struct rte_eth_xstat_name *xstats_names,
-	__rte_unused unsigned int size)
-{
-	unsigned i;
-
-	if (xstats_names == NULL)
-		return IGB_NB_XSTATS;
-
-	/* Note: limit checked in rte_eth_xstats_names() */
-
-	for (i = 0; i < IGB_NB_XSTATS; i++) {
-		strlcpy(xstats_names[i].name, rte_igb_stats_strings[i].name,
-			sizeof(xstats_names[i].name));
-	}
-
-	return IGB_NB_XSTATS;
-}
-
-static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
+static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
 		const uint64_t *ids, struct rte_eth_xstat_name *xstats_names,
 		unsigned int limit)
 {
@@ -1902,7 +1880,7 @@ static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
 	} else {
 		struct rte_eth_xstat_name xstats_names_copy[IGB_NB_XSTATS];
 
-		eth_igb_xstats_get_names_by_id(dev, NULL, xstats_names_copy,
+		eth_igb_xstats_get_names(dev, NULL, xstats_names_copy,
 				IGB_NB_XSTATS);
 
 		for (i = 0; i < limit; i++) {
@@ -2035,11 +2013,15 @@ igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats)
 }
 
 static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
-				     struct rte_eth_xstat_name *xstats_names,
-				     __rte_unused unsigned limit)
+				      const uint64_t *ids,
+				      struct rte_eth_xstat_name *xstats_names,
+				      __rte_unused unsigned limit)
 {
 	unsigned i;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL)
 		for (i = 0; i < IGBVF_NB_XSTATS; i++) {
 			strlcpy(xstats_names[i].name,
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index 4cebf60a68..a807e50dba 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -212,7 +212,7 @@ static void ena_interrupt_handler_rte(void *cb_arg);
 static void ena_timer_wd_callback(struct rte_timer *timer, void *arg);
 static void ena_destroy_device(struct rte_eth_dev *eth_dev);
 static int eth_ena_dev_init(struct rte_eth_dev *eth_dev);
-static int ena_xstats_get_names(struct rte_eth_dev *dev,
+static int ena_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n);
 static int ena_xstats_get(struct rte_eth_dev *dev,
@@ -2585,12 +2585,16 @@ int ena_copy_eni_stats(struct ena_adapter *adapter)
  *   Number of xstats names.
  */
 static int ena_xstats_get_names(struct rte_eth_dev *dev,
+				const uint64_t *ids,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n)
 {
 	unsigned int xstats_count = ena_xstats_calc_num(dev->data);
 	unsigned int stat, i, count = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (n < xstats_count || !xstats_names)
 		return xstats_count;
 
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 5ff33e03e0..dae85b7677 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -990,12 +990,15 @@ __fs_xstats_get_names(struct rte_eth_dev *dev,
 }
 
 static int
-fs_xstats_get_names(struct rte_eth_dev *dev,
+fs_xstats_get_names(struct rte_eth_dev *dev, const uint64_t *ids,
 		    struct rte_eth_xstat_name *xstats_names,
 		    unsigned int limit)
 {
 	int ret;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	fs_lock(dev, 0);
 	ret = __fs_xstats_get_names(dev, xstats_names, limit);
 	fs_unlock(dev, 0);
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index 3236290e40..16af1751f9 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1232,11 +1232,15 @@ fm10k_link_update(struct rte_eth_dev *dev,
 }
 
 static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+	const uint64_t *ids,
 	struct rte_eth_xstat_name *xstats_names, __rte_unused unsigned limit)
 {
 	unsigned i, q;
 	unsigned count = 0;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names != NULL) {
 		/* Note: limit checked in rte_eth_xstats_names() */
 
diff --git a/drivers/net/hinic/hinic_pmd_ethdev.c b/drivers/net/hinic/hinic_pmd_ethdev.c
index c01e2ec1d4..bc6f07d070 100644
--- a/drivers/net/hinic/hinic_pmd_ethdev.c
+++ b/drivers/net/hinic/hinic_pmd_ethdev.c
@@ -2280,6 +2280,7 @@ static void hinic_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
  *   Number of xstats names.
  */
 static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
+			       const uint64_t *ids,
 			       struct rte_eth_xstat_name *xstats_names,
 			       __rte_unused unsigned int limit)
 {
@@ -2287,6 +2288,9 @@ static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
 	int count = 0;
 	u16 i = 0, q_num;
 
+	if (ids != NULL)
+		return -ENOTSUP;
+
 	if (xstats_names == NULL)
 		return hinic_xstats_calc_num(nic_dev);