> Queue stats were passed back from drivers in arrays of
> RTE_ETHDEV_QUEUE_STAT_CNTRS entries, limiting reporting to the first 16
> queues unless DPDK was rebuilt with a larger value.
> 
> Replace the arrays with one counter structure per queue, allocated by
> ethdev and sized to the number of queues configured on the port.
> Queue counts are already validated by rte_eth_dev_configure(), so no
> additional limit is needed.
> 
> Drop the per-queue error counter. Only a few drivers filled it, and
> errors are still counted by the port level ierrors and oerrors.
> 
> RTE_ETHDEV_QUEUE_STAT_CNTRS is unused now and removed. It was
> defined in
> ethdev_driver.h, only installed with the driver SDK, so the ABI is
> unaffected.
> 
> Signed-off-by: Stephen Hemminger <[email protected]>

For mana and netvsc:
Reviewed-by: Long Li <[email protected]>

> ---
>  doc/guides/howto/debug_troubleshoot.rst       |  5 +-
>  doc/guides/nics/bnxt.rst                      |  4 +-
>  doc/guides/nics/features.rst                  |  5 +-
>  doc/guides/rel_notes/release_26_11.rst        |  4 ++
>  drivers/net/af_packet/rte_eth_af_packet.c     | 15 +++--
>  drivers/net/af_xdp/rte_eth_af_xdp.c           | 13 ++--
>  drivers/net/ark/ark_ethdev_rx.c               |  7 +-
>  drivers/net/ark/ark_ethdev_tx.c               |  6 +-
>  drivers/net/atlantic/atl_ethdev.c             | 13 ++--
>  drivers/net/atlantic/atl_rxtx.c               |  8 +--
>  drivers/net/atlantic/atl_types.h              | 15 +++--
>  drivers/net/avp/avp_ethdev.c                  | 13 ++--
>  drivers/net/axgbe/axgbe_ethdev.c              | 13 ++--
>  drivers/net/bnxt/bnxt_ethdev.c                |  5 --
>  drivers/net/bnxt/bnxt_reps.c                  |  9 ++-
>  drivers/net/bnxt/bnxt_stats.c                 | 40 ++++-------
>  drivers/net/cnxk/cnxk_rep_ops.c               |  8 +--
>  drivers/net/cnxk/cnxk_stats.c                 | 15 ++---
>  drivers/net/dpaa2/dpaa2_ethdev.c              | 17 ++---
>  drivers/net/ena/ena_ethdev.c                  | 21 ++----
>  drivers/net/hinic/hinic_pmd_ethdev.c          | 17 +++--
>  drivers/net/hinic3/hinic3_ethdev.c            | 13 ++--
>  drivers/net/intel/e1000/igc_ethdev.c          | 13 ++--
>  drivers/net/intel/fm10k/fm10k_ethdev.c        | 16 +++--
>  drivers/net/intel/ixgbe/ixgbe_ethdev.c        | 14 ++--
>  drivers/net/ionic/ionic_lif.c                 | 24 +++----
>  drivers/net/mana/mana.c                       | 12 ++--
>  drivers/net/memif/rte_eth_memif.c             | 16 ++---
>  drivers/net/mlx4/mlx4_ethdev.c                | 14 ++--
>  drivers/net/mlx5/mlx5_rx.h                    |  3 +-
>  drivers/net/mlx5/mlx5_stats.c                 | 22 +++----
>  drivers/net/mvpp2/mrvl_ethdev.c               | 20 +++---
>  drivers/net/nbl/nbl_dev/nbl_dev.c             |  2 -
>  drivers/net/nbl/nbl_hw/nbl_txrx.c             | 12 ++--
>  drivers/net/netvsc/hn_ethdev.c                | 12 ++--
>  drivers/net/netvsc/hn_vf.c                    |  3 +-
>  drivers/net/nfb/nfb_stats.c                   | 12 ++--
>  drivers/net/nfp/flower/nfp_flower.c           |  8 +--
>  .../net/nfp/flower/nfp_flower_representor.c   | 32 ++++++---
>  .../net/nfp/flower/nfp_flower_representor.h   |  4 +-
>  drivers/net/nfp/nfp_ethdev.c                  | 13 ++++
>  drivers/net/nfp/nfp_ethdev_vf.c               | 13 ++++
>  drivers/net/nfp/nfp_net_common.c              | 36 ++++------
>  drivers/net/nfp/nfp_net_common.h              |  3 +-
>  drivers/net/ngbe/ngbe_ethdev.c                | 34 +++-------
>  drivers/net/ngbe/ngbe_ethdev.h                | 12 ----
>  drivers/net/ntnic/ntnic_ethdev.c              | 12 ++--
>  drivers/net/null/rte_eth_null.c               | 12 ++--
>  drivers/net/octeon_ep/otx_ep_ethdev.c         | 13 ++--
>  drivers/net/pcap/pcap_ethdev.c                | 14 ++--
>  drivers/net/qede/qede_ethdev.c                | 36 ++--------
>  drivers/net/ring/rte_eth_ring.c               | 10 ++-
>  drivers/net/rnp/rnp_ethdev.c                  | 12 ++--
>  drivers/net/sxe2/sxe2_cmd_chnl.c              | 20 +++---
>  drivers/net/tap/rte_eth_tap.c                 | 12 ++--
>  drivers/net/thunderx/nicvf_ethdev.c           | 24 +++----
>  drivers/net/txgbe/txgbe_ethdev.c              | 14 ++--
>  drivers/net/vhost/rte_eth_vhost.c             | 14 ++--
>  drivers/net/virtio/virtio_ethdev.c            | 12 ++--
>  drivers/net/vmxnet3/vmxnet3_ethdev.c          | 13 ++--
>  drivers/net/xsc/xsc_ethdev.c                  | 14 ++--
>  drivers/net/zxdh/zxdh_ethdev_ops.c            | 24 +++----
>  lib/ethdev/ethdev_driver.h                    | 27 ++++----
>  lib/ethdev/ethdev_private.c                   |  2 -
>  lib/ethdev/rte_ethdev.c                       | 66 ++++++++++---------
>  65 files changed, 445 insertions(+), 522 deletions(-)
> 
> diff --git a/doc/guides/howto/debug_troubleshoot.rst
> b/doc/guides/howto/debug_troubleshoot.rst
> index c19aada6f8..969118fcfc 100644
> --- a/doc/guides/howto/debug_troubleshoot.rst
> +++ b/doc/guides/howto/debug_troubleshoot.rst
> @@ -120,8 +120,9 @@ RX-TX port and associated
> cores :numref:`dtg_rx_tx_drop`.
>     * Identify if there are multiple RX queue configured for port by
>       ``nb_rx_queues`` using ``rte_eth_dev_info_get``.
> 
> -   * Using ``rte_eth_dev_stats`` fetch drops in q_errors, check if RX thread
> -     is configured to fetch packets from the port queue pair.
> +   * Using ``rte_eth_dev_stats`` fetch drops in ``ierrors`` and ``imissed``,
> +     check if RX thread is configured to fetch packets from the port queue
> +     pair.
> 
>     * Using ``rte_eth_dev_stats`` shows drops in ``rx_nombuf``, check if RX
>       thread has enough cycles to consume the packets from the queue.
> diff --git a/doc/guides/nics/bnxt.rst b/doc/guides/nics/bnxt.rst
> index 45529a89ee..48b950876c 100644
> --- a/doc/guides/nics/bnxt.rst
> +++ b/doc/guides/nics/bnxt.rst
> @@ -588,9 +588,7 @@ Basic stats include:
>  * ierrors
>  * oerrors
> 
> -By default, per-queue stats for 16 queues are supported. For more than 16
> -queues, BNXT PMD should be compiled with
> ``RTE_ETHDEV_QUEUE_STAT_CNTRS``
> -set to the desired number of queues.
> +Per-queue stats are supported for all configured queues.
> 
>  Extended Stats
>  ^^^^^^^^^^^^^^
> diff --git a/doc/guides/nics/features.rst b/doc/guides/nics/features.rst
> index d6852b063c..43eda7867d 100644
> --- a/doc/guides/nics/features.rst
> +++ b/doc/guides/nics/features.rst
> @@ -757,8 +757,9 @@ These apply to all drivers.
>  Stats per queue
>  ---------------
> 
> -Supports per queue stats: q_ipackets, q_opackets, q_ibytes, q_obytes,
> q_errors.
> -Statistics only supplied for first ``RTE_ETHDEV_QUEUE_STAT_CNTRS`` (16)
> queues.
> +Supports per queue stats: q_ipackets, q_opackets, q_ibytes, q_obytes.
> +Statistics are supplied for all configured queues,
> +subject to any hardware counter limit of the device.
>  If driver does not support this feature the per queue stats will be zero.
> 
>  * **[implements] eth_dev_ops**: ``stats_get``, ``stats_reset``.
> diff --git a/doc/guides/rel_notes/release_26_11.rst
> b/doc/guides/rel_notes/release_26_11.rst
> index d29d7591e9..ed271a81f6 100644
> --- a/doc/guides/rel_notes/release_26_11.rst
> +++ b/doc/guides/rel_notes/release_26_11.rst
> @@ -82,6 +82,10 @@ Removed Items
>    ``rte_eth_dev_set_tx_queue_stats_mapping`` and
> ``rte_eth_dev_set_rx_queue_stats_mapping``
>    were deprecated and are now removed.
> 
> +* ethdev: Removed the ``RTE_ETHDEV_QUEUE_STAT_CNTRS`` build time
> limit.
> +  Per-queue xstats are now reported for all queues, not just the first 16.
> +  The ``rx_qN_errors`` xstat is removed, drops are still counted in 
> ``ierrors``.
> +
> 
>  API Changes
>  -----------
> diff --git a/drivers/net/af_packet/rte_eth_af_packet.c
> b/drivers/net/af_packet/rte_eth_af_packet.c
> index b0ff22ea55..a97b826305 100644
> --- a/drivers/net/af_packet/rte_eth_af_packet.c
> +++ b/drivers/net/af_packet/rte_eth_af_packet.c
> @@ -515,12 +515,15 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats, struct eth_q
>               tx_err_total += internal->tx_queue[i].err_pkts;
>               tx_bytes_total += internal->tx_queue[i].tx_bytes;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = internal->rx_queue[i].rx_pkts;
> -                     qstats->q_ibytes[i] = internal->rx_queue[i].rx_bytes;
> -                     qstats->q_opackets[i] = internal->tx_queue[i].tx_pkts;
> -                     qstats->q_obytes[i] = internal->tx_queue[i].tx_bytes;
> -                     qstats->q_errors[i] = internal->rx_queue[i].rx_nombuf;
> +             if (qstats != NULL) {
> +                     if (i < dev->data->nb_rx_queues) {
> +                             qstats[i].q_ipackets = internal-
> >rx_queue[i].rx_pkts;
> +                             qstats[i].q_ibytes = internal-
> >rx_queue[i].rx_bytes;
> +                     }
> +                     if (i < dev->data->nb_tx_queues) {
> +                             qstats[i].q_opackets = internal-
> >tx_queue[i].tx_pkts;
> +                             qstats[i].q_obytes = internal-
> >tx_queue[i].tx_bytes;
> +                     }
>               }
>       }
> 
> diff --git a/drivers/net/af_xdp/rte_eth_af_xdp.c
> b/drivers/net/af_xdp/rte_eth_af_xdp.c
> index 2cdb533276..be2f5760ae 100644
> --- a/drivers/net/af_xdp/rte_eth_af_xdp.c
> +++ b/drivers/net/af_xdp/rte_eth_af_xdp.c
> @@ -910,12 +910,13 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               rxq = &internals->rx_queues[i];
>               txq = rxq->pair;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = rxq->stats.rx_pkts;
> -                     qstats->q_ibytes[i] = rxq->stats.rx_bytes;
> -                     qstats->q_opackets[i] = txq->stats.tx_pkts;
> -                     qstats->q_obytes[i] = txq->stats.tx_bytes;
> -                     qstats->q_errors[i] = 0; /* Not used */
> +             if (qstats != NULL) {
> +                     qstats[i].q_ipackets = rxq->stats.rx_pkts;
> +                     qstats[i].q_ibytes = rxq->stats.rx_bytes;
> +                     if (i < dev->data->nb_tx_queues) {
> +                             qstats[i].q_opackets = txq->stats.tx_pkts;
> +                             qstats[i].q_obytes = txq->stats.tx_bytes;
> +                     }
>               }
> 
>               ipackets += rxq->stats.rx_pkts;
> diff --git a/drivers/net/ark/ark_ethdev_rx.c b/drivers/net/ark/ark_ethdev_rx.c
> index 42f2db6610..adba943fa2 100644
> --- a/drivers/net/ark/ark_ethdev_rx.c
> +++ b/drivers/net/ark/ark_ethdev_rx.c
> @@ -592,10 +592,9 @@ ark_rx_queue_stats_get(void *vqueue, struct
> rte_eth_stats *stats,
>       stats->ibytes += ibytes;
>       stats->imissed += idropped;
> 
> -     if (qstats && queue->queue_index <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -             qstats->q_ipackets[queue->queue_index] = ipackets;
> -             qstats->q_ibytes[queue->queue_index] = ibytes;
> -             qstats->q_errors[queue->queue_index] = idropped;
> +     if (qstats != NULL) {
> +             qstats[queue->queue_index].q_ipackets = ipackets;
> +             qstats[queue->queue_index].q_ibytes = ibytes;
>       }
>  }
> 
> diff --git a/drivers/net/ark/ark_ethdev_tx.c b/drivers/net/ark/ark_ethdev_tx.c
> index c9b5b005ca..0d6a94b919 100644
> --- a/drivers/net/ark/ark_ethdev_tx.c
> +++ b/drivers/net/ark/ark_ethdev_tx.c
> @@ -433,9 +433,9 @@ ark_tx_queue_stats_get(void *vqueue, struct
> rte_eth_stats *stats, struct eth_que
>       stats->obytes += bytes;
>       stats->oerrors += queue->tx_errors;
> 
> -     if (qstats && queue->queue_index <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -             qstats->q_opackets[queue->queue_index] = pkts;
> -             qstats->q_obytes[queue->queue_index] = bytes;
> +     if (qstats != NULL) {
> +             qstats[queue->queue_index].q_opackets = pkts;
> +             qstats[queue->queue_index].q_obytes = bytes;
>       }
>  }
> 
> diff --git a/drivers/net/atlantic/atl_ethdev.c 
> b/drivers/net/atlantic/atl_ethdev.c
> index 0b2033c084..24184bdb18 100644
> --- a/drivers/net/atlantic/atl_ethdev.c
> +++ b/drivers/net/atlantic/atl_ethdev.c
> @@ -954,12 +954,13 @@ atl_dev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>       stats->rx_nombuf = swstats->rx_nombuf;
> 
>       if (qstats != NULL) {
> -             for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
> -                     qstats->q_ipackets[i] = swstats->q_ipackets[i];
> -                     qstats->q_opackets[i] = swstats->q_opackets[i];
> -                     qstats->q_ibytes[i] = swstats->q_ibytes[i];
> -                     qstats->q_obytes[i] = swstats->q_obytes[i];
> -                     qstats->q_errors[i] = swstats->q_errors[i];
> +             for (i = 0; i < dev->data->nb_rx_queues && i <
> AQ_HW_MAX_RX_QUEUES; i++) {
> +                     qstats[i].q_ipackets = swstats->rxq[i].packets;
> +                     qstats[i].q_ibytes = swstats->rxq[i].bytes;
> +             }
> +             for (i = 0; i < dev->data->nb_tx_queues && i <
> AQ_HW_MAX_TX_QUEUES; i++) {
> +                     qstats[i].q_opackets = swstats->txq[i].packets;
> +                     qstats[i].q_obytes = swstats->txq[i].bytes;
>               }
>       }
>       return 0;
> diff --git a/drivers/net/atlantic/atl_rxtx.c b/drivers/net/atlantic/atl_rxtx.c
> index 7b7bf5abbc..8d02b92304 100644
> --- a/drivers/net/atlantic/atl_rxtx.c
> +++ b/drivers/net/atlantic/atl_rxtx.c
> @@ -1075,8 +1075,8 @@ atl_recv_pkts(void *rx_queue, struct rte_mbuf
> **rx_pkts, uint16_t nb_pkts)
>                * of returned packets.
>                */
>               rx_pkts[nb_rx++] = rx_mbuf_first;
> -             adapter->sw_stats.q_ipackets[rxq->queue_id]++;
> -             adapter->sw_stats.q_ibytes[rxq->queue_id] +=
> +             adapter->sw_stats.rxq[rxq->queue_id].packets++;
> +             adapter->sw_stats.rxq[rxq->queue_id].bytes +=
>                       rx_mbuf_first->pkt_len;
> 
>               PMD_RX_LOG(DEBUG, "add mbuf segs=%d pkt_len=%d",
> @@ -1297,8 +1297,8 @@ atl_xmit_pkt(struct aq_hw_s *hw, struct
> atl_tx_queue *txq,
> 
>       txq->tx_free -= desc_count;
> 
> -     adapter->sw_stats.q_opackets[txq->queue_id]++;
> -     adapter->sw_stats.q_obytes[txq->queue_id] += pay_len;
> +     adapter->sw_stats.txq[txq->queue_id].packets++;
> +     adapter->sw_stats.txq[txq->queue_id].bytes += pay_len;
>  }
> 
>  uint16_t
> diff --git a/drivers/net/atlantic/atl_types.h 
> b/drivers/net/atlantic/atl_types.h
> index dfd7016600..be9f3aacc1 100644
> --- a/drivers/net/atlantic/atl_types.h
> +++ b/drivers/net/atlantic/atl_types.h
> @@ -15,6 +15,8 @@
>  #include <rte_common.h>
>  #include <ethdev_driver.h>
> 
> +#include "atl_common.h"
> +
>  typedef uint8_t              u8;
>  typedef int8_t               s8;
>  typedef uint16_t     u16;
> @@ -225,11 +227,14 @@ struct atl_sw_stats {
>       u64 pcrc8ec;
> 
>       u64 rx_nombuf;
> -     u64 q_ipackets[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     u64 q_opackets[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     u64 q_ibytes[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     u64 q_obytes[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     u64 q_errors[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> +     struct {
> +             u64 packets;
> +             u64 bytes;
> +     } rxq[AQ_HW_MAX_RX_QUEUES];
> +     struct {
> +             u64 packets;
> +             u64 bytes;
> +     } txq[AQ_HW_MAX_TX_QUEUES];
>  };
> 
>  #endif
> diff --git a/drivers/net/avp/avp_ethdev.c b/drivers/net/avp/avp_ethdev.c
> index 8af6c45381..d536f764cf 100644
> --- a/drivers/net/avp/avp_ethdev.c
> +++ b/drivers/net/avp/avp_ethdev.c
> @@ -2256,10 +2256,9 @@ avp_dev_stats_get(struct rte_eth_dev *eth_dev,
> struct rte_eth_stats *stats,
>                       stats->ibytes += rxq->bytes;
>                       stats->ierrors += rxq->errors;
> 
> -                     if (qstats != NULL && i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                             qstats->q_ipackets[i] += rxq->packets;
> -                             qstats->q_ibytes[i] += rxq->bytes;
> -                             qstats->q_errors[i] += rxq->errors;
> +                     if (qstats != NULL && i < eth_dev->data-
> >nb_rx_queues) {
> +                             qstats[i].q_ipackets += rxq->packets;
> +                             qstats[i].q_ibytes += rxq->bytes;
>                       }
>               }
>       }
> @@ -2272,9 +2271,9 @@ avp_dev_stats_get(struct rte_eth_dev *eth_dev,
> struct rte_eth_stats *stats,
>                       stats->obytes += txq->bytes;
>                       stats->oerrors += txq->errors;
> 
> -                     if (qstats != NULL && i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                             qstats->q_opackets[i] += txq->packets;
> -                             qstats->q_obytes[i] += txq->bytes;
> +                     if (qstats != NULL && i < eth_dev->data-
> >nb_tx_queues) {
> +                             qstats[i].q_opackets += txq->packets;
> +                             qstats[i].q_obytes += txq->bytes;
>                       }
>               }
>       }
> diff --git a/drivers/net/axgbe/axgbe_ethdev.c
> b/drivers/net/axgbe/axgbe_ethdev.c
> index 61725d55ca..93e198ba95 100644
> --- a/drivers/net/axgbe/axgbe_ethdev.c
> +++ b/drivers/net/axgbe/axgbe_ethdev.c
> @@ -1156,10 +1156,9 @@ axgbe_dev_stats_get(struct rte_eth_dev *dev,
>                       stats->rx_nombuf += rxq->rx_mbuf_alloc_failed;
>                       stats->ierrors += rxq->errors;
> 
> -                     if (qstats != NULL && i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                             qstats->q_ipackets[i] = rxq->pkts;
> -                             qstats->q_ibytes[i] = rxq->bytes;
> -                             qstats->q_errors[i] = rxq->errors + rxq-
> >rx_mbuf_alloc_failed;
> +                     if (qstats != NULL && i < dev->data->nb_rx_queues) {
> +                             qstats[i].q_ipackets = rxq->pkts;
> +                             qstats[i].q_ibytes = rxq->bytes;
>                       }
>               } else {
>                       PMD_DRV_LOG_LINE(DEBUG, "Rx queue not setup for
> port %d",
> @@ -1174,9 +1173,9 @@ axgbe_dev_stats_get(struct rte_eth_dev *dev,
>                       stats->obytes += txq->bytes;
>                       stats->oerrors += txq->errors;
> 
> -                     if (qstats != NULL && i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                             qstats->q_opackets[i] = txq->pkts;
> -                             qstats->q_obytes[i] = txq->bytes;
> +                     if (qstats != NULL && i < dev->data->nb_tx_queues) {
> +                             qstats[i].q_opackets = txq->pkts;
> +                             qstats[i].q_obytes = txq->bytes;
>                       }
>               } else {
>                       PMD_DRV_LOG_LINE(DEBUG, "Tx queue not setup for
> port %d",
> diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
> index 8e8ead8f61..c6f566c214 100644
> --- a/drivers/net/bnxt/bnxt_ethdev.c
> +++ b/drivers/net/bnxt/bnxt_ethdev.c
> @@ -1843,11 +1843,6 @@ int bnxt_dev_start_op(struct rte_eth_dev
> *eth_dev)
>       struct bnxt_tx_queue *txq;
>       uint16_t queue_idx;
> 
> -     if (bp->rx_cp_nr_rings > RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -             PMD_DRV_LOG_LINE(ERR,
> -                         "RxQ cnt %d >
> RTE_ETHDEV_QUEUE_STAT_CNTRS %d",
> -                         bp->rx_cp_nr_rings,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -
>       do {
>               rc = bnxt_hwrm_if_change(bp, true);
>               if (rc == 0 || rc != -EAGAIN)
> diff --git a/drivers/net/bnxt/bnxt_reps.c b/drivers/net/bnxt/bnxt_reps.c
> index e26a086f41..dd0f14d5c6 100644
> --- a/drivers/net/bnxt/bnxt_reps.c
> +++ b/drivers/net/bnxt/bnxt_reps.c
> @@ -909,11 +909,10 @@ int bnxt_rep_stats_get_op(struct rte_eth_dev
> *eth_dev,
>               stats->imissed += rep_bp->rx_drop_pkts[i];
> 
>               if (qstats) {
> -                     qstats->q_ipackets[i] = rep_bp->rx_pkts[i];
> -                     qstats->q_ibytes[i] = rep_bp->rx_bytes[i];
> -                     qstats->q_opackets[i] = rep_bp->tx_pkts[i];
> -                     qstats->q_obytes[i] = rep_bp->tx_bytes[i];
> -                     qstats->q_errors[i] = rep_bp->rx_drop_pkts[i];
> +                     qstats[i].q_ipackets = rep_bp->rx_pkts[i];
> +                     qstats[i].q_ibytes = rep_bp->rx_bytes[i];
> +                     qstats[i].q_opackets = rep_bp->tx_pkts[i];
> +                     qstats[i].q_obytes = rep_bp->tx_bytes[i];
>               }
>       }
> 
> diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
> index ba858710a5..37b33f0505 100644
> --- a/drivers/net/bnxt/bnxt_stats.c
> +++ b/drivers/net/bnxt/bnxt_stats.c
> @@ -576,18 +576,14 @@ static void bnxt_fill_rte_eth_stats_ext(struct
> rte_eth_stats *stats,
>               uint64_t ibytes = ring_stats->rx_ucast_bytes +
>                               ring_stats->rx_mcast_bytes +
>                               ring_stats->rx_bcast_bytes;
> -             uint64_t ierrors = ring_stats->rx_discard_pkts +
> -                             ring_stats->rx_error_pkts;
> -
>               stats->ipackets += ipackets;
>               stats->ibytes += ibytes;
>               stats->imissed += ring_stats->rx_discard_pkts;
>               stats->ierrors += ring_stats->rx_error_pkts;
> 
>               if (qstats) {
> -                     qstats->q_ipackets[i] = ipackets;
> -                     qstats->q_ibytes[i] = ibytes;
> -                     qstats->q_errors[i] = ierrors;
> +                     qstats[i].q_ipackets = ipackets;
> +                     qstats[i].q_ibytes = ibytes;
>               }
>       } else {
>               uint64_t opackets = ring_stats->tx_ucast_pkts +
> @@ -602,8 +598,8 @@ static void bnxt_fill_rte_eth_stats_ext(struct
> rte_eth_stats *stats,
>               stats->oerrors += ring_stats->tx_discard_pkts;
> 
>               if (qstats) {
> -                     qstats->q_opackets[i] = opackets;
> -                     qstats->q_obytes[i] = obytes;
> +                     qstats[i].q_opackets = opackets;
> +                     qstats[i].q_obytes = obytes;
>               }
>       }
>  }
> @@ -620,18 +616,14 @@ static void bnxt_fill_rte_eth_stats(struct
> rte_eth_stats *stats,
>               uint64_t ibytes = ring_stats->rx_ucast_bytes +
>                               ring_stats->rx_mcast_bytes +
>                               ring_stats->rx_bcast_bytes;
> -             uint64_t ierrors = ring_stats->rx_discard_pkts +
> -                             ring_stats->rx_error_pkts;
> -
>               stats->ipackets += ipackets;
>               stats->ibytes += ibytes;
>               stats->imissed += ring_stats->rx_discard_pkts;
>               stats->ierrors += ring_stats->rx_error_pkts;
> 
>               if (qstats) {
> -                     qstats->q_ipackets[i] = ipackets;
> -                     qstats->q_ibytes[i] = ibytes;
> -                     qstats->q_errors[i] = ierrors;
> +                     qstats[i].q_ipackets = ipackets;
> +                     qstats[i].q_ibytes = ibytes;
>               }
>       } else {
>               uint64_t opackets = ring_stats->tx_ucast_pkts +
> @@ -646,8 +638,8 @@ static void bnxt_fill_rte_eth_stats(struct rte_eth_stats
> *stats,
>               stats->oerrors += ring_stats->tx_discard_pkts;
> 
>               if (qstats) {
> -                     qstats->q_opackets[i] = opackets;
> -                     qstats->q_obytes[i] = obytes;
> +                     qstats[i].q_opackets = opackets;
> +                     qstats[i].q_obytes = obytes;
>               }
>       }
>  }
> @@ -661,9 +653,7 @@ static int bnxt_stats_get_ext(struct rte_eth_dev
> *eth_dev,
>       struct bnxt *bp = eth_dev->data->dev_private;
>       unsigned int num_q_stats;
> 
> -     num_q_stats = RTE_MIN(bp->rx_cp_nr_rings,
> -                           (unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -
> +     num_q_stats = RTE_MIN(bp->rx_cp_nr_rings, eth_dev->data-
> >nb_rx_queues);
>       for (i = 0; i < bp->rx_cp_nr_rings; i++) {
>               struct bnxt_rx_queue *rxq = bp->rx_queues[i];
>               struct bnxt_cp_ring_info *cpr = rxq->cp_ring;
> @@ -687,9 +677,7 @@ static int bnxt_stats_get_ext(struct rte_eth_dev
> *eth_dev,
> 
> rte_memory_order_relaxed);
>       }
> 
> -     num_q_stats = RTE_MIN(bp->tx_cp_nr_rings,
> -                           (unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -
> +     num_q_stats = RTE_MIN(bp->tx_cp_nr_rings, eth_dev->data-
> >nb_tx_queues);
>       for (i = 0; i < bp->tx_cp_nr_rings; i++) {
>               struct bnxt_tx_queue *txq = bp->tx_queues[i];
>               struct bnxt_cp_ring_info *cpr = txq->cp_ring;
> @@ -728,9 +716,7 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
>       if (BNXT_TPA_V2_P7(bp))
>               return bnxt_stats_get_ext(eth_dev, bnxt_stats, qstats);
> 
> -     num_q_stats = RTE_MIN(bp->rx_cp_nr_rings,
> -                           (unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -
> +     num_q_stats = RTE_MIN(bp->rx_cp_nr_rings, eth_dev->data-
> >nb_rx_queues);
>       for (i = 0; i < bp->rx_cp_nr_rings; i++) {
>               struct bnxt_rx_queue *rxq = bp->rx_queues[i];
>               struct bnxt_cp_ring_info *cpr = rxq->cp_ring;
> @@ -753,9 +739,7 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
> 
> rte_memory_order_relaxed);
>       }
> 
> -     num_q_stats = RTE_MIN(bp->tx_cp_nr_rings,
> -                           (unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -
> +     num_q_stats = RTE_MIN(bp->tx_cp_nr_rings, eth_dev->data-
> >nb_tx_queues);
>       for (i = 0; i < bp->tx_cp_nr_rings; i++) {
>               struct bnxt_tx_queue *txq = bp->tx_queues[i];
>               struct bnxt_cp_ring_info *cpr = txq->cp_ring;
> diff --git a/drivers/net/cnxk/cnxk_rep_ops.c
> b/drivers/net/cnxk/cnxk_rep_ops.c
> index c481015592..4a9c027bf5 100644
> --- a/drivers/net/cnxk/cnxk_rep_ops.c
> +++ b/drivers/net/cnxk/cnxk_rep_ops.c
> @@ -614,10 +614,10 @@ cnxk_rep_stats_get(struct rte_eth_dev *ethdev,
> struct rte_eth_stats *stats,
>       }
> 
>       if (qstats != NULL) {
> -             qstats->q_ipackets[0] = vf_stats.ipackets;
> -             qstats->q_ibytes[0] = vf_stats.ibytes;
> -             qstats->q_opackets[0] = vf_stats.opackets;
> -             qstats->q_obytes[0] = vf_stats.obytes;
> +             qstats[0].q_ipackets = vf_stats.ipackets;
> +             qstats[0].q_ibytes = vf_stats.ibytes;
> +             qstats[0].q_opackets = vf_stats.opackets;
> +             qstats[0].q_obytes = vf_stats.obytes;
>       }
> 
>       stats->ipackets = vf_stats.ipackets;
> diff --git a/drivers/net/cnxk/cnxk_stats.c b/drivers/net/cnxk/cnxk_stats.c
> index 469a18f93e..c15c8761c1 100644
> --- a/drivers/net/cnxk/cnxk_stats.c
> +++ b/drivers/net/cnxk/cnxk_stats.c
> @@ -39,28 +39,21 @@ cnxk_nix_stats_get(struct rte_eth_dev *eth_dev,
> struct rte_eth_stats *stats,
>       for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
>               struct roc_nix_stats_queue qstats_data;
> 
> -             if (i >= RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                     break;
> -
>               rc = roc_nix_stats_queue_get(nix, i, 0, &qstats_data);
>               if (rc)
>                       goto exit;
> -             qstats->q_opackets[i] = qstats_data.tx_pkts;
> -             qstats->q_obytes[i] = qstats_data.tx_octs;
> +             qstats[i].q_opackets = qstats_data.tx_pkts;
> +             qstats[i].q_obytes = qstats_data.tx_octs;
>       }
> 
>       for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
>               struct roc_nix_stats_queue qstats_data;
> 
> -             if (i >= RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                     break;
> -
>               rc = roc_nix_stats_queue_get(nix, i, 1, &qstats_data);
>               if (rc)
>                       goto exit;
> -             qstats->q_ipackets[i] = qstats_data.rx_pkts;
> -             qstats->q_ibytes[i] = qstats_data.rx_octs;
> -             qstats->q_errors[i] = qstats_data.rx_drop_pkts;
> +             qstats[i].q_ipackets = qstats_data.rx_pkts;
> +             qstats[i].q_ibytes = qstats_data.rx_octs;
>       }
>  exit:
>       return rc;
> diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c
> b/drivers/net/dpaa2/dpaa2_ethdev.c
> index f211357919..8ae4fd89c5 100644
> --- a/drivers/net/dpaa2/dpaa2_ethdev.c
> +++ b/drivers/net/dpaa2/dpaa2_ethdev.c
> @@ -2002,20 +2002,17 @@ dpaa2_dev_stats_get(struct rte_eth_dev *dev,
>       stats->oerrors = value.page_2.egress_discarded_frames;
>       stats->imissed = value.page_2.ingress_nobuffer_discards;
> 
> -     /* Fill in per queue stats */
> +     /* Fill in per queue stats. Byte counting is not implemented. */
>       if (qstats != NULL) {
> -             for (i = 0; (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) &&
> -                     (i < priv->nb_rx_queues || i < priv->nb_tx_queues);
> ++i) {
> +             for (i = 0; i < dev->data->nb_rx_queues; ++i) {
>                       dpaa2_rxq = priv->rx_vq[i];
> -                     dpaa2_txq = priv->tx_vq[i];
>                       if (dpaa2_rxq)
> -                             qstats->q_ipackets[i] = dpaa2_rxq->rx_pkts;
> +                             qstats[i].q_ipackets = dpaa2_rxq->rx_pkts;
> +             }
> +             for (i = 0; i < dev->data->nb_tx_queues; ++i) {
> +                     dpaa2_txq = priv->tx_vq[i];
>                       if (dpaa2_txq)
> -                             qstats->q_opackets[i] = dpaa2_txq->tx_pkts;
> -
> -                     /* Byte counting is not implemented */
> -                     qstats->q_ibytes[i]   = 0;
> -                     qstats->q_obytes[i]   = 0;
> +                             qstats[i].q_opackets = dpaa2_txq->tx_pkts;
>               }
>       }
> 
> diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
> index ad2ac6dbbf..ae48afcfdc 100644
> --- a/drivers/net/ena/ena_ethdev.c
> +++ b/drivers/net/ena/ena_ethdev.c
> @@ -1264,7 +1264,6 @@ static int ena_stats_get(struct rte_eth_dev *dev,
>       struct ena_com_dev *ena_dev = &adapter->ena_dev;
>       int rc;
>       int i;
> -     int max_rings_stats;
> 
>       memset(&ena_stats, 0, sizeof(ena_stats));
> 
> @@ -1295,26 +1294,18 @@ static int ena_stats_get(struct rte_eth_dev *dev,
> 
>       /* Queue statistics */
>       if (qstats) {
> -             max_rings_stats = RTE_MIN(dev->data->nb_rx_queues,
> -                     RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -             for (i = 0; i < max_rings_stats; ++i) {
> +             for (i = 0; i < dev->data->nb_rx_queues; ++i) {
>                       struct ena_stats_rx *rx_stats = &adapter-
> >rx_ring[i].rx_stats;
> 
> -                     qstats->q_ibytes[i] = rx_stats->bytes;
> -                     qstats->q_ipackets[i] = rx_stats->cnt;
> -                     qstats->q_errors[i] = rx_stats->bad_desc_num +
> -                             rx_stats->bad_req_id +
> -                             rx_stats->bad_desc +
> -                             rx_stats->unknown_error;
> +                     qstats[i].q_ibytes = rx_stats->bytes;
> +                     qstats[i].q_ipackets = rx_stats->cnt;
>               }
> 
> -             max_rings_stats = RTE_MIN(dev->data->nb_tx_queues,
> -                     RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -             for (i = 0; i < max_rings_stats; ++i) {
> +             for (i = 0; i < dev->data->nb_tx_queues; ++i) {
>                       struct ena_stats_tx *tx_stats = &adapter-
> >tx_ring[i].tx_stats;
> 
> -                     qstats->q_obytes[i] = tx_stats->bytes;
> -                     qstats->q_opackets[i] = tx_stats->cnt;
> +                     qstats[i].q_obytes = tx_stats->bytes;
> +                     qstats[i].q_opackets = tx_stats->cnt;
>               }
>       }
> 
> diff --git a/drivers/net/hinic/hinic_pmd_ethdev.c
> b/drivers/net/hinic/hinic_pmd_ethdev.c
> index 91a4348fb6..016d632e64 100644
> --- a/drivers/net/hinic/hinic_pmd_ethdev.c
> +++ b/drivers/net/hinic/hinic_pmd_ethdev.c
> @@ -1329,14 +1329,13 @@ hinic_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
> 
>       /* rx queue stats */
>       if (qstats) {
> -             q_num = (nic_dev->num_rq <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
> -                             nic_dev->num_rq :
> RTE_ETHDEV_QUEUE_STAT_CNTRS;
> +             q_num = (nic_dev->num_rq < dev->data->nb_rx_queues) ?
> +                             nic_dev->num_rq : dev->data->nb_rx_queues;
>               for (i = 0; i < q_num; i++) {
>                       rxq = nic_dev->rxqs[i];
>                       hinic_rxq_get_stats(rxq, &rxq_stats);
> -                     qstats->q_ipackets[i] = rxq_stats.packets;
> -                     qstats->q_ibytes[i] = rxq_stats.bytes;
> -                     qstats->q_errors[i] = rxq_stats.rx_discards;
> +                     qstats[i].q_ipackets = rxq_stats.packets;
> +                     qstats[i].q_ibytes = rxq_stats.bytes;
> 
>                       stats->ierrors += rxq_stats.errors;
>                       rx_discards_pmd += rxq_stats.rx_discards;
> @@ -1344,13 +1343,13 @@ hinic_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>               }
> 
>               /* tx queue stats */
> -             q_num = (nic_dev->num_sq <
> RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
> -                     nic_dev->num_sq :
> RTE_ETHDEV_QUEUE_STAT_CNTRS;
> +             q_num = (nic_dev->num_sq < dev->data->nb_tx_queues) ?
> +                     nic_dev->num_sq : dev->data->nb_tx_queues;
>               for (i = 0; i < q_num; i++) {
>                       txq = nic_dev->txqs[i];
>                       hinic_txq_get_stats(txq, &txq_stats);
> -                     qstats->q_opackets[i] = txq_stats.packets;
> -                     qstats->q_obytes[i] = txq_stats.bytes;
> +                     qstats[i].q_opackets = txq_stats.packets;
> +                     qstats[i].q_obytes = txq_stats.bytes;
>                       stats->oerrors += (txq_stats.tx_busy +
> txq_stats.off_errs);
>               }
>       } else {
> diff --git a/drivers/net/hinic3/hinic3_ethdev.c
> b/drivers/net/hinic3/hinic3_ethdev.c
> index 361e52f7b9..eb5ddd9de6 100644
> --- a/drivers/net/hinic3/hinic3_ethdev.c
> +++ b/drivers/net/hinic3/hinic3_ethdev.c
> @@ -2763,10 +2763,9 @@ hinic3_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>               rxq->rxq_stats.errors = rxq->rxq_stats.csum_errors +
>                                       rxq->rxq_stats.other_errors;
> 
> -             if (qstats && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = rxq->rxq_stats.packets;
> -                     qstats->q_ibytes[i] = rxq->rxq_stats.bytes;
> -                     qstats->q_errors[i] = rxq->rxq_stats.errors;
> +             if (qstats && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = rxq->rxq_stats.packets;
> +                     qstats[i].q_ibytes = rxq->rxq_stats.bytes;
>               }
>               stats->ierrors += rxq->rxq_stats.errors;
>               rx_discards_pmd += rxq->rxq_stats.dropped;
> @@ -2777,9 +2776,9 @@ hinic3_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>       for (uint32_t i = 0; i < nic_dev->num_sqs; i++) {
>               struct hinic3_txq *txq = nic_dev->txqs[i];
>               stats->oerrors += (txq->txq_stats.tx_busy + txq-
> >txq_stats.offload_errors);
> -             if (qstats && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = txq->txq_stats.packets;
> -                     qstats->q_obytes[i] = txq->txq_stats.bytes;
> +             if (qstats && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = txq->txq_stats.packets;
> +                     qstats[i].q_obytes = txq->txq_stats.bytes;
>               }
>       }
> 
> diff --git a/drivers/net/intel/e1000/igc_ethdev.c
> b/drivers/net/intel/e1000/igc_ethdev.c
> index 943a479f9a..73dd5dd1a3 100644
> --- a/drivers/net/intel/e1000/igc_ethdev.c
> +++ b/drivers/net/intel/e1000/igc_ethdev.c
> @@ -2059,12 +2059,13 @@ eth_igc_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *rte_stats,
> 
>       /* Get per-queue statuses */
>       if (qstats) {
> -             for (i = 0; i < RTE_MIN(IGC_QUEUE_PAIRS_NUM,
> RTE_ETHDEV_QUEUE_STAT_CNTRS); i++) {
> -                     qstats->q_opackets[i] += queue_stats->pqgptc[i];
> -                     qstats->q_obytes[i] += queue_stats->pqgotc[i];
> -                     qstats->q_ipackets[i] += queue_stats->pqgprc[i];
> -                     qstats->q_ibytes[i] += queue_stats->pqgorc[i];
> -                     qstats->q_errors[i] += queue_stats->rqdpc[i];
> +             for (i = 0; i < RTE_MIN(IGC_QUEUE_PAIRS_NUM, dev->data-
> >nb_rx_queues); i++) {
> +                     qstats[i].q_ipackets += queue_stats->pqgprc[i];
> +                     qstats[i].q_ibytes += queue_stats->pqgorc[i];
> +             }
> +             for (i = 0; i < RTE_MIN(IGC_QUEUE_PAIRS_NUM, dev->data-
> >nb_tx_queues); i++) {
> +                     qstats[i].q_opackets += queue_stats->pqgptc[i];
> +                     qstats[i].q_obytes += queue_stats->pqgotc[i];
>               }
>       }
> 
> diff --git a/drivers/net/intel/fm10k/fm10k_ethdev.c
> b/drivers/net/intel/fm10k/fm10k_ethdev.c
> index ca438d2d02..3b2daba79e 100644
> --- a/drivers/net/intel/fm10k/fm10k_ethdev.c
> +++ b/drivers/net/intel/fm10k/fm10k_ethdev.c
> @@ -1328,14 +1328,16 @@ fm10k_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>       fm10k_update_hw_stats(hw, hw_stats);
> 
>       ipackets = opackets = ibytes = obytes = imissed = 0;
> -     for (i = 0; (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) &&
> -                     (i < hw->mac.max_queues); ++i) {
> +     for (i = 0; i < hw->mac.max_queues; ++i) {
>               if (qstats != NULL) {
> -                     qstats->q_ipackets[i] = hw_stats-
> >q[i].rx_packets.count;
> -                     qstats->q_opackets[i] = hw_stats-
> >q[i].tx_packets.count;
> -                     qstats->q_ibytes[i]   = hw_stats->q[i].rx_bytes.count;
> -                     qstats->q_obytes[i]   = hw_stats->q[i].tx_bytes.count;
> -                     qstats->q_errors[i]   = hw_stats->q[i].rx_drops.count;
> +                     if (i < dev->data->nb_rx_queues) {
> +                             qstats[i].q_ipackets = hw_stats-
> >q[i].rx_packets.count;
> +                             qstats[i].q_ibytes   = hw_stats-
> >q[i].rx_bytes.count;
> +                     }
> +                     if (i < dev->data->nb_tx_queues) {
> +                             qstats[i].q_opackets = hw_stats-
> >q[i].tx_packets.count;
> +                             qstats[i].q_obytes   = hw_stats-
> >q[i].tx_bytes.count;
> +                     }
>               }
>               ipackets += hw_stats->q[i].rx_packets.count;
>               opackets += hw_stats->q[i].tx_packets.count;
> diff --git a/drivers/net/intel/ixgbe/ixgbe_ethdev.c
> b/drivers/net/intel/ixgbe/ixgbe_ethdev.c
> index 5945dd047d..cbb7b4831c 100644
> --- a/drivers/net/intel/ixgbe/ixgbe_ethdev.c
> +++ b/drivers/net/intel/ixgbe/ixgbe_ethdev.c
> @@ -3346,12 +3346,14 @@ ixgbe_dev_stats_get(struct rte_eth_dev *dev,
> 
>       if (qstats != NULL) {
>               for (i = 0; i < RTE_MIN_T(IXGBE_QUEUE_STAT_COUNTERS,
> -                             RTE_ETHDEV_QUEUE_STAT_CNTRS, typeof(i));
> i++) {
> -                     qstats->q_ipackets[i] = hw_stats->qprc[i];
> -                     qstats->q_opackets[i] = hw_stats->qptc[i];
> -                     qstats->q_ibytes[i] = hw_stats->qbrc[i];
> -                     qstats->q_obytes[i] = hw_stats->qbtc[i];
> -                     qstats->q_errors[i] = hw_stats->qprdc[i];
> +                             dev->data->nb_rx_queues, typeof(i)); i++) {
> +                     qstats[i].q_ipackets = hw_stats->qprc[i];
> +                     qstats[i].q_ibytes = hw_stats->qbrc[i];
> +             }
> +             for (i = 0; i < RTE_MIN_T(IXGBE_QUEUE_STAT_COUNTERS,
> +                             dev->data->nb_tx_queues, typeof(i)); i++) {
> +                     qstats[i].q_opackets = hw_stats->qptc[i];
> +                     qstats[i].q_obytes = hw_stats->qbtc[i];
>               }
>       }
> 
> diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
> index b52c8cad88..2443c98881 100644
> --- a/drivers/net/ionic/ionic_lif.c
> +++ b/drivers/net/ionic/ionic_lif.c
> @@ -105,10 +105,15 @@ ionic_lif_get_abs_stats(const struct ionic_lif *lif,
> struct rte_eth_stats *stats
>  {
>       struct ionic_lif_stats *ls = &lif->info->stats;
>       uint32_t i;
> -     uint32_t num_rx_q_counters = RTE_MIN(lif->nrxqcqs, (uint32_t)
> -                     RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -     uint32_t num_tx_q_counters = RTE_MIN(lif->ntxqcqs, (uint32_t)
> -                     RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     /*
> +      * The queue stats array is indexed by queue id and sized by the
> +      * queue counts passed to configure, which is not necessarily the
> +      * number of queues the LIF has allocated.
> +      */
> +     uint32_t num_rx_q_counters = RTE_MIN(lif->nrxqcqs,
> +                     (uint32_t)lif->eth_dev->data->nb_rx_queues);
> +     uint32_t num_tx_q_counters = RTE_MIN(lif->ntxqcqs,
> +                     (uint32_t)lif->eth_dev->data->nb_tx_queues);
> 
>       memset(stats, 0, sizeof(*stats));
> 
> @@ -148,11 +153,8 @@ ionic_lif_get_abs_stats(const struct ionic_lif *lif,
> struct rte_eth_stats *stats
>       if (qstats != NULL) {
>               for (i = 0; i < num_rx_q_counters; i++) {
>                       struct ionic_rx_stats *rx_stats = 
> &lif->rxqcqs[i]->stats;
> -                     qstats->q_ipackets[i] = rx_stats->packets;
> -                     qstats->q_ibytes[i] = rx_stats->bytes;
> -                     qstats->q_errors[i] =
> -                             rx_stats->bad_cq_status +
> -                             rx_stats->bad_len;
> +                     qstats[i].q_ipackets = rx_stats->packets;
> +                     qstats[i].q_ibytes = rx_stats->bytes;
>               }
>       }
> 
> @@ -185,8 +187,8 @@ ionic_lif_get_abs_stats(const struct ionic_lif *lif, 
> struct
> rte_eth_stats *stats
>       if (qstats != NULL) {
>               for (i = 0; i < num_tx_q_counters; i++) {
>                       struct ionic_tx_stats *tx_stats = 
> &lif->txqcqs[i]->stats;
> -                     qstats->q_opackets[i] = tx_stats->packets;
> -                     qstats->q_obytes[i] = tx_stats->bytes;
> +                     qstats[i].q_opackets = tx_stats->packets;
> +                     qstats[i].q_obytes = tx_stats->bytes;
>               }
>       }
>  }
> diff --git a/drivers/net/mana/mana.c b/drivers/net/mana/mana.c
> index 0b72f711a1..72c8501d3c 100644
> --- a/drivers/net/mana/mana.c
> +++ b/drivers/net/mana/mana.c
> @@ -779,9 +779,9 @@ mana_dev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               stats->obytes += txq->stats.bytes;
>               stats->oerrors += txq->stats.errors;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = txq->stats.packets;
> -                     qstats->q_obytes[i] = txq->stats.bytes;
> +             if (qstats != NULL && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = txq->stats.packets;
> +                     qstats[i].q_obytes = txq->stats.bytes;
>               }
>       }
> 
> @@ -798,9 +798,9 @@ mana_dev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
> 
>               /* There is no good way to get stats->imissed, not setting it */
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = rxq->stats.packets;
> -                     qstats->q_ibytes[i] = rxq->stats.bytes;
> +             if (qstats != NULL && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = rxq->stats.packets;
> +                     qstats[i].q_ibytes = rxq->stats.bytes;
>               }
> 
>               stats->rx_nombuf += rxq->stats.nombuf;
> diff --git a/drivers/net/memif/rte_eth_memif.c
> b/drivers/net/memif/rte_eth_memif.c
> index 5d153c3a5a..1c8dc1d5ec 100644
> --- a/drivers/net/memif/rte_eth_memif.c
> +++ b/drivers/net/memif/rte_eth_memif.c
> @@ -1607,15 +1607,15 @@ memif_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
> 
>       tmp = (pmd->role == MEMIF_ROLE_CLIENT) ? pmd-
> >run.num_s2c_rings :
>           pmd->run.num_c2s_rings;
> -     nq = (tmp < RTE_ETHDEV_QUEUE_STAT_CNTRS) ? tmp :
> -         RTE_ETHDEV_QUEUE_STAT_CNTRS;
> +     nq = (tmp < dev->data->nb_rx_queues) ? tmp :
> +         dev->data->nb_rx_queues;
> 
>       /* RX stats */
>       for (i = 0; i < nq; i++) {
>               mq = dev->data->rx_queues[i];
>               if (qstats != NULL) {
> -                     qstats->q_ipackets[i] = mq->n_pkts;
> -                     qstats->q_ibytes[i] = mq->n_bytes;
> +                     qstats[i].q_ipackets = mq->n_pkts;
> +                     qstats[i].q_ibytes = mq->n_bytes;
>               }
>               stats->ipackets += mq->n_pkts;
>               stats->ibytes += mq->n_bytes;
> @@ -1624,15 +1624,15 @@ memif_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
> 
>       tmp = (pmd->role == MEMIF_ROLE_CLIENT) ? pmd-
> >run.num_c2s_rings :
>           pmd->run.num_s2c_rings;
> -     nq = (tmp < RTE_ETHDEV_QUEUE_STAT_CNTRS) ? tmp :
> -         RTE_ETHDEV_QUEUE_STAT_CNTRS;
> +     nq = (tmp < dev->data->nb_tx_queues) ? tmp :
> +         dev->data->nb_tx_queues;
> 
>       /* TX stats */
>       for (i = 0; i < nq; i++) {
>               mq = dev->data->tx_queues[i];
>               if (qstats != NULL) {
> -                     qstats->q_opackets[i] = mq->n_pkts;
> -                     qstats->q_obytes[i] = mq->n_bytes;
> +                     qstats[i].q_opackets = mq->n_pkts;
> +                     qstats[i].q_obytes = mq->n_bytes;
>               }
>               stats->opackets += mq->n_pkts;
>               stats->obytes += mq->n_bytes;
> diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
> index efc6ee4577..4ea79bf1eb 100644
> --- a/drivers/net/mlx4/mlx4_ethdev.c
> +++ b/drivers/net/mlx4/mlx4_ethdev.c
> @@ -717,11 +717,9 @@ mlx4_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               if (rxq == NULL)
>                       continue;
>               idx = rxq->stats.idx;
> -             if (qstats != NULL && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS)
> {
> -                     qstats->q_ipackets[idx] += rxq->stats.ipackets;
> -                     qstats->q_ibytes[idx] += rxq->stats.ibytes;
> -                     qstats->q_errors[idx] += (rxq->stats.idropped +
> -                                           rxq->stats.rx_nombuf);
> +             if (qstats != NULL && idx < dev->data->nb_rx_queues) {
> +                     qstats[idx].q_ipackets += rxq->stats.ipackets;
> +                     qstats[idx].q_ibytes += rxq->stats.ibytes;
>               }
>               tmp.ipackets += rxq->stats.ipackets;
>               tmp.ibytes += rxq->stats.ibytes;
> @@ -734,9 +732,9 @@ mlx4_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               if (txq == NULL)
>                       continue;
>               idx = txq->stats.idx;
> -             if (qstats != NULL && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS)
> {
> -                     qstats->q_opackets[idx] += txq->stats.opackets;
> -                     qstats->q_obytes[idx] += txq->stats.obytes;
> +             if (qstats != NULL && idx < dev->data->nb_tx_queues) {
> +                     qstats[idx].q_opackets += txq->stats.opackets;
> +                     qstats[idx].q_obytes += txq->stats.obytes;
>               }
>               tmp.opackets += txq->stats.opackets;
>               tmp.obytes += txq->stats.obytes;
> diff --git a/drivers/net/mlx5/mlx5_rx.h b/drivers/net/mlx5/mlx5_rx.h
> index cd48ee37ef..0d1eee61b2 100644
> --- a/drivers/net/mlx5/mlx5_rx.h
> +++ b/drivers/net/mlx5/mlx5_rx.h
> @@ -53,9 +53,10 @@ struct mlx5_xstats_name_off {
>       unsigned int offset;
>  };
> 
> +/* Only used with offsetof() for the xstats names table. */
>  struct mlx5_rq_stats {
>       /** Total number of hairpin queue packets received that are dropped.
> */
> -     uint64_t q_oobs[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> +     uint64_t q_oobs;
>  };
> 
>  /* Compressed CQE context. */
> diff --git a/drivers/net/mlx5/mlx5_stats.c b/drivers/net/mlx5/mlx5_stats.c
> index 5cd3e303cc..1fbd298c77 100644
> --- a/drivers/net/mlx5/mlx5_stats.c
> +++ b/drivers/net/mlx5/mlx5_stats.c
> @@ -44,7 +44,7 @@ static int
>  mlx5_rq_xstats_get(struct rte_eth_dev *dev,
>                                       struct rte_eth_xstat *stats)
>  {
> -     uint16_t n_stats_rq = RTE_MIN(dev->data->nb_rx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     uint16_t n_stats_rq = dev->data->nb_rx_queues;
>       int cnt_used_entries = 0;
> 
>       for (unsigned int idx = 0; idx < n_stats_rq; idx++) {
> @@ -101,7 +101,7 @@ mlx5_rq_xstats_get_names(struct rte_eth_dev *dev
> __rte_unused,
>       unsigned int i;
>       int cnt_used_entries = 0;
> 
> -     uint16_t n_stats_rq = RTE_MIN(dev->data->nb_rx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     uint16_t n_stats_rq = dev->data->nb_rx_queues;
> 
>       for (i = 0; (i != n_stats_rq); ++i) {
>               rxq = mlx5_rxq_get(dev, i);
> @@ -227,17 +227,13 @@ mlx5_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               if (rxq == NULL)
>                       continue;
>               idx = rxq->idx;
> -             if (qstats != NULL && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS)
> {
> +             if (qstats != NULL && idx < dev->data->nb_rx_queues) {
>  #ifdef MLX5_PMD_SOFT_COUNTERS
> -                     qstats->q_ipackets[idx] += rxq->stats.ipackets -
> +                     qstats[idx].q_ipackets += rxq->stats.ipackets -
>                               rxq->stats_reset.ipackets;
> -                     qstats->q_ibytes[idx] += rxq->stats.ibytes -
> +                     qstats[idx].q_ibytes += rxq->stats.ibytes -
>                               rxq->stats_reset.ibytes;
>  #endif
> -                     qstats->q_errors[idx] += (rxq->stats.idropped +
> -                                           rxq->stats.rx_nombuf) -
> -                                           (rxq->stats_reset.idropped +
> -                                           rxq->stats_reset.rx_nombuf);
>               }
>  #ifdef MLX5_PMD_SOFT_COUNTERS
>               tmp.ipackets += rxq->stats.ipackets - rxq->stats_reset.ipackets;
> @@ -253,11 +249,11 @@ mlx5_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               if (txq == NULL)
>                       continue;
>               idx = txq->idx;
> -             if (qstats != NULL && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS)
> {
> +             if (qstats != NULL && idx < dev->data->nb_tx_queues) {
>  #ifdef MLX5_PMD_SOFT_COUNTERS
> -                     qstats->q_opackets[idx] += txq->stats.opackets -
> +                     qstats[idx].q_opackets += txq->stats.opackets -
>                                               txq->stats_reset.opackets;
> -                     qstats->q_obytes[idx] += txq->stats.obytes -
> +                     qstats[idx].q_obytes += txq->stats.obytes -
>                                               txq->stats_reset.obytes;
>  #endif
>               }
> @@ -467,7 +463,7 @@ mlx5_xstats_get_names(struct rte_eth_dev *dev,
>  static struct mlx5_stat_counter_ctrl*
>  mlx5_rxq_get_counter_by_id(struct rte_eth_dev *dev, uint64_t id, uint64_t
> *rq_id)
>  {
> -     uint16_t n_stats_rq = RTE_MIN(dev->data->nb_rx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     uint16_t n_stats_rq = dev->data->nb_rx_queues;
> 
>       for (int i = 0; (i != n_stats_rq); i++) {
>               struct mlx5_rxq_data *rxq_data = mlx5_rxq_data_get(dev, i);
> diff --git a/drivers/net/mvpp2/mrvl_ethdev.c
> b/drivers/net/mvpp2/mrvl_ethdev.c
> index bc947ff52e..d7ed504bee 100644
> --- a/drivers/net/mvpp2/mrvl_ethdev.c
> +++ b/drivers/net/mvpp2/mrvl_ethdev.c
> @@ -1505,10 +1505,10 @@ mrvl_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>                       continue;
> 
>               idx = rxq->queue_id;
> -             if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
> +             if (unlikely(idx >= dev->data->nb_rx_queues)) {
>                       MRVL_LOG(ERR,
>                               "rx queue %d stats out of range (0 - %d)",
> -                             idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
> +                             idx, dev->data->nb_rx_queues - 1);
>                       continue;
>               }
> 
> @@ -1523,12 +1523,8 @@ mrvl_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               }
> 
>               if (qstats != NULL) {
> -                     qstats->q_ibytes[idx] = rxq->bytes_recv;
> -                     qstats->q_ipackets[idx] = rx_stats.enq_desc - rxq-
> >drop_mac;
> -                     qstats->q_errors[idx] = rx_stats.drop_early +
> -                                            rx_stats.drop_fullq +
> -                                            rx_stats.drop_bm +
> -                                            rxq->drop_mac;
> +                     qstats[idx].q_ibytes = rxq->bytes_recv;
> +                     qstats[idx].q_ipackets = rx_stats.enq_desc - rxq-
> >drop_mac;
>               }
>               stats->ibytes += rxq->bytes_recv;
>               drop_mac += rxq->drop_mac;
> @@ -1542,10 +1538,10 @@ mrvl_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>                       continue;
> 
>               idx = txq->queue_id;
> -             if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
> +             if (unlikely(idx >= dev->data->nb_tx_queues)) {
>                       MRVL_LOG(ERR,
>                               "tx queue %d stats out of range (0 - %d)",
> -                             idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
> +                             idx, dev->data->nb_tx_queues - 1);
>                       continue;
>               }
> 
> @@ -1558,8 +1554,8 @@ mrvl_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               }
> 
>               if (qstats != NULL) {
> -                     qstats->q_opackets[idx] = tx_stats.deq_desc;
> -                     qstats->q_obytes[idx] = txq->bytes_sent;
> +                     qstats[idx].q_opackets = tx_stats.deq_desc;
> +                     qstats[idx].q_obytes = txq->bytes_sent;
>               }
>               stats->obytes += txq->bytes_sent;
>       }
> diff --git a/drivers/net/nbl/nbl_dev/nbl_dev.c
> b/drivers/net/nbl/nbl_dev/nbl_dev.c
> index 3c0e98d687..320f26619f 100644
> --- a/drivers/net/nbl/nbl_dev/nbl_dev.c
> +++ b/drivers/net/nbl/nbl_dev/nbl_dev.c
> @@ -534,8 +534,6 @@ int nbl_stats_get(struct rte_eth_dev *eth_dev, struct
> rte_eth_stats *rte_stats,
>               goto update_hw_stats_fail;
> 
>       for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
> -             if (qstats && i < RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                     qstats->q_errors[i] = net_dev-
> >hw_stats.total_uvn_stat_pkt_drop[i];
>               rte_stats->imissed += net_dev-
> >hw_stats.total_uvn_stat_pkt_drop[i];
>       }
> 
> diff --git a/drivers/net/nbl/nbl_hw/nbl_txrx.c
> b/drivers/net/nbl/nbl_hw/nbl_txrx.c
> index f29f0a6d5b..7beae85177 100644
> --- a/drivers/net/nbl/nbl_hw/nbl_txrx.c
> +++ b/drivers/net/nbl/nbl_hw/nbl_txrx.c
> @@ -795,10 +795,10 @@ static int nbl_res_txrx_get_stats(void *priv, struct
> rte_eth_stats *rte_stats,
>               rxq_stats_reset = &rxq->rxq_stats_reset;
>               idx = rxq->queue_id;
> 
> -             if (qstats && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[idx] += rxq_stats->rx_packets -
> +             if (qstats && idx < eth_dev->data->nb_rx_queues) {
> +                     qstats[idx].q_ipackets += rxq_stats->rx_packets -
>                                                       rxq_stats_reset-
> >rx_packets;
> -                     qstats->q_ibytes[idx] += rxq_stats->rx_bytes -
> rxq_stats_reset->rx_bytes;
> +                     qstats[idx].q_ibytes += rxq_stats->rx_bytes -
> rxq_stats_reset->rx_bytes;
>               }
>               rte_stats->ipackets += rxq_stats->rx_packets - rxq_stats_reset-
> >rx_packets;
>               rte_stats->ibytes += rxq_stats->rx_bytes - rxq_stats_reset-
> >rx_bytes;
> @@ -814,10 +814,10 @@ static int nbl_res_txrx_get_stats(void *priv, struct
> rte_eth_stats *rte_stats,
>               txq_stats_reset = &txq->txq_stats_reset;
>               idx = txq->queue_id;
> 
> -             if (qstats && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[idx] += txq_stats->tx_packets -
> +             if (qstats && idx < eth_dev->data->nb_tx_queues) {
> +                     qstats[idx].q_opackets += txq_stats->tx_packets -
>                                                       txq_stats_reset-
> >tx_packets;
> -                     qstats->q_obytes[idx] += txq_stats->tx_bytes -
> txq_stats_reset->tx_bytes;
> +                     qstats[idx].q_obytes += txq_stats->tx_bytes -
> txq_stats_reset->tx_bytes;
>               }
>               rte_stats->opackets += txq_stats->tx_packets -
> txq_stats_reset->tx_packets;
>               rte_stats->obytes += txq_stats->tx_bytes - txq_stats_reset-
> >tx_bytes;
> diff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c
> index 9a193e4a7a..e4fdf89873 100644
> --- a/drivers/net/netvsc/hn_ethdev.c
> +++ b/drivers/net/netvsc/hn_ethdev.c
> @@ -1122,9 +1122,9 @@ static int hn_dev_stats_get(struct rte_eth_dev *dev,
>               stats->obytes += txq->stats.bytes;
>               stats->oerrors += txq->stats.errors;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] += txq->stats.packets;
> -                     qstats->q_obytes[i] += txq->stats.bytes;
> +             if (qstats != NULL) {
> +                     qstats[i].q_opackets += txq->stats.packets;
> +                     qstats[i].q_obytes += txq->stats.bytes;
>               }
>       }
> 
> @@ -1139,9 +1139,9 @@ static int hn_dev_stats_get(struct rte_eth_dev *dev,
>               stats->ierrors += rxq->stats.errors;
>               stats->imissed += rxq->stats.ring_full;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] += rxq->stats.packets;
> -                     qstats->q_ibytes[i] += rxq->stats.bytes;
> +             if (qstats != NULL) {
> +                     qstats[i].q_ipackets += rxq->stats.packets;
> +                     qstats[i].q_ibytes += rxq->stats.bytes;
>               }
>       }
> 
> diff --git a/drivers/net/netvsc/hn_vf.c b/drivers/net/netvsc/hn_vf.c
> index 27c46ce404..96e811278a 100644
> --- a/drivers/net/netvsc/hn_vf.c
> +++ b/drivers/net/netvsc/hn_vf.c
> @@ -927,7 +927,8 @@ int hn_vf_stats_get(struct rte_eth_dev *dev,
>                * rte_eth_stats_get API because we need to forward the
>                * per-queue stats (qstats) which the public API does not
>                * support.  The caller (eth_stats_qstats_get) has already
> -              * zeroed stats and qstats before invoking this callback.
> +              * zeroed stats, and qstats is zeroed by its allocation,
> +              * before invoking this callback.
>                */
>               if (vf_dev->dev_ops->stats_get != NULL)
>                       ret = vf_dev->dev_ops->stats_get(vf_dev, stats,
> diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
> index f7a0189ffe..0b4bdc7d18 100644
> --- a/drivers/net/nfb/nfb_stats.c
> +++ b/drivers/net/nfb/nfb_stats.c
> @@ -25,9 +25,9 @@ nfb_eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               if (rx_queue == NULL)
>                       continue;
> 
> -             if (qstats && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = rx_queue->rx_pkts;
> -                     qstats->q_ibytes[i] = rx_queue->rx_bytes;
> +             if (qstats && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = rx_queue->rx_pkts;
> +                     qstats[i].q_ibytes = rx_queue->rx_bytes;
>               }
>       }
> 
> @@ -36,9 +36,9 @@ nfb_eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               if (tx_queue == NULL)
>                       continue;
> 
> -             if (qstats && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = tx_queue->tx_pkts;
> -                     qstats->q_obytes[i] = tx_queue->tx_bytes;
> +             if (qstats && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = tx_queue->tx_pkts;
> +                     qstats[i].q_obytes = tx_queue->tx_bytes;
>               }
>       }
> 
> diff --git a/drivers/net/nfp/flower/nfp_flower.c
> b/drivers/net/nfp/flower/nfp_flower.c
> index 4eeb9aee3b..14a8992376 100644
> --- a/drivers/net/nfp/flower/nfp_flower.c
> +++ b/drivers/net/nfp/flower/nfp_flower.c
> @@ -238,8 +238,8 @@ nfp_flower_multiple_pf_recv_pkts(void *rx_queue,
>               for (i = 0; i < recv; i++)
>                       data_len += rx_pkts[i]->data_len;
> 
> -             repr->repr_qstats.q_ipackets[rxq->qidx] += recv;
> -             repr->repr_qstats.q_ibytes[rxq->qidx] += data_len;
> +             repr->repr_qstats[rxq->qidx].q_ipackets += recv;
> +             repr->repr_qstats[rxq->qidx].q_ibytes += data_len;
>       }
> 
>       return recv;
> @@ -276,8 +276,8 @@ nfp_flower_multiple_pf_xmit_pkts(void *tx_queue,
>               for (i = 0; i < sent; i++)
>                       data_len += tx_pkts[i]->data_len;
> 
> -             repr->repr_qstats.q_opackets[txq->qidx] += sent;
> -             repr->repr_qstats.q_obytes[txq->qidx] += data_len;
> +             repr->repr_qstats[txq->qidx].q_opackets += sent;
> +             repr->repr_qstats[txq->qidx].q_obytes += data_len;
>       }
> 
>       return sent;
> diff --git a/drivers/net/nfp/flower/nfp_flower_representor.c
> b/drivers/net/nfp/flower/nfp_flower_representor.c
> index 9b984dbc8d..231a76980d 100644
> --- a/drivers/net/nfp/flower/nfp_flower_representor.c
> +++ b/drivers/net/nfp/flower/nfp_flower_representor.c
> @@ -324,15 +324,15 @@ nfp_flower_repr_stats_get(struct rte_eth_dev
> *ethdev,
>       repr->repr_stats.ipackets = 0;
>       repr->repr_stats.ibytes = 0;
>       for (i = 0; i < ethdev->data->nb_rx_queues; i++) {
> -             repr->repr_stats.ipackets += repr->repr_qstats.q_ipackets[i];
> -             repr->repr_stats.ibytes += repr->repr_qstats.q_ibytes[i];
> +             repr->repr_stats.ipackets += repr->repr_qstats[i].q_ipackets;
> +             repr->repr_stats.ibytes += repr->repr_qstats[i].q_ibytes;
>       }
> 
>       repr->repr_stats.opackets = 0;
>       repr->repr_stats.obytes = 0;
>       for (i = 0; i < ethdev->data->nb_tx_queues; i++) {
> -             repr->repr_stats.opackets += repr->repr_qstats.q_opackets[i];
> -             repr->repr_stats.obytes += repr->repr_qstats.q_obytes[i];
> +             repr->repr_stats.opackets += repr->repr_qstats[i].q_opackets;
> +             repr->repr_stats.obytes += repr->repr_qstats[i].q_obytes;
>       }
> 
>       *stats = repr->repr_stats;
> @@ -347,7 +347,8 @@ nfp_flower_repr_stats_reset(struct rte_eth_dev
> *ethdev)
> 
>       repr = ethdev->data->dev_private;
>       memset(&repr->repr_stats, 0, sizeof(struct rte_eth_stats));
> -     memset(&repr->repr_qstats, 0, sizeof(struct eth_queue_stats));
> +     memset(repr->repr_qstats, 0,
> +                     sizeof(struct eth_queue_stats) * repr-
> >repr_nb_qstats);
> 
>       return 0;
>  }
> @@ -403,8 +404,8 @@ nfp_flower_repr_rx_burst(void *rx_queue,
>               for (i = 0; i < total_dequeue; i++)
>                       data_len += rx_pkts[i]->data_len;
> 
> -             repr->repr_qstats.q_ipackets[rxq->qidx] += total_dequeue;
> -             repr->repr_qstats.q_ibytes[rxq->qidx] += data_len;
> +             repr->repr_qstats[rxq->qidx].q_ipackets += total_dequeue;
> +             repr->repr_qstats[rxq->qidx].q_ibytes += data_len;
>       }
> 
>       return total_dequeue;
> @@ -451,8 +452,8 @@ nfp_flower_repr_tx_burst(void *tx_queue,
>               for (i = 0; i < sent; i++)
>                       data_len += tx_pkts[i]->data_len;
> 
> -             repr->repr_qstats.q_opackets[txq->qidx] += sent;
> -             repr->repr_qstats.q_obytes[txq->qidx] += data_len;
> +             repr->repr_qstats[txq->qidx].q_opackets += sent;
> +             repr->repr_qstats[txq->qidx].q_obytes += data_len;
>       }
> 
>       return sent;
> @@ -528,6 +529,7 @@ nfp_flower_repr_uninit(struct rte_eth_dev *eth_dev)
> 
>       repr = eth_dev->data->dev_private;
>       nfp_flower_repr_base_uninit(repr);
> +     rte_free(repr->repr_qstats);
>       rte_free(repr->ring);
> 
>       if (nfp_flower_repr_is_phy(repr)) {
> @@ -893,6 +895,17 @@ nfp_flower_repr_init(struct rte_eth_dev *eth_dev,
>               return -ENOMEM;
>       }
> 
> +     repr->repr_nb_qstats = RTE_MAX(app_fw_flower->pf_hw-
> >max_rx_queues,
> +                     app_fw_flower->pf_hw->max_tx_queues);
> +     repr->repr_qstats = rte_zmalloc_socket("nfp_repr_qstats",
> +                     sizeof(struct eth_queue_stats) * repr-
> >repr_nb_qstats,
> +                     RTE_CACHE_LINE_SIZE, numa_node);
> +     if (repr->repr_qstats == NULL) {
> +             PMD_DRV_LOG(ERR, "Queue stats alloc failed for %s.",
> ring_name);
> +             rte_free(repr->ring);
> +             return -ENOMEM;
> +     }
> +
>       eth_dev->dev_ops = &nfp_flower_repr_dev_ops;
>       eth_dev->rx_pkt_burst = nfp_flower_repr_rx_burst;
>       eth_dev->tx_pkt_burst = nfp_flower_repr_tx_burst;
> @@ -928,6 +941,7 @@ nfp_flower_repr_init(struct rte_eth_dev *eth_dev,
>       return 0;
> 
>  ring_cleanup:
> +     rte_free(repr->repr_qstats);
>       rte_free(repr->ring);
> 
>       return ret;
> diff --git a/drivers/net/nfp/flower/nfp_flower_representor.h
> b/drivers/net/nfp/flower/nfp_flower_representor.h
> index 66714d9a51..74e09749f6 100644
> --- a/drivers/net/nfp/flower/nfp_flower_representor.h
> +++ b/drivers/net/nfp/flower/nfp_flower_representor.h
> @@ -22,7 +22,9 @@ struct nfp_flower_representor {
>       struct rte_ring **ring;
>       struct rte_eth_link link;
>       struct rte_eth_stats repr_stats;
> -     struct eth_queue_stats repr_qstats;
> +     /** Per-queue counters, one entry per queue */
> +     struct eth_queue_stats *repr_qstats;
> +     uint16_t repr_nb_qstats;
> 
>       struct rte_eth_xstat *repr_xstats_base;
>       uint8_t *mac_stats;
> diff --git a/drivers/net/nfp/nfp_ethdev.c b/drivers/net/nfp/nfp_ethdev.c
> index d2da18013c..2f7ce812e4 100644
> --- a/drivers/net/nfp/nfp_ethdev.c
> +++ b/drivers/net/nfp/nfp_ethdev.c
> @@ -663,6 +663,7 @@ nfp_net_uninit(struct rte_eth_dev *eth_dev)
>       if ((net_hw->super.cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0)
>               nfp_net_flow_priv_uninit(hw_priv->pf_dev, net_hw->idx);
> 
> +     rte_free(net_hw->eth_qstats_base);
>       rte_free(net_hw->eth_xstats_base);
>       if ((net_hw->super.cap & NFP_NET_CFG_CTRL_TXRWB) != 0)
>               nfp_net_txrwb_free(eth_dev);
> @@ -1091,6 +1092,17 @@ nfp_net_init(struct rte_eth_dev *eth_dev,
>               goto ipsec_exit;
>       }
> 
> +     net_hw->eth_qstats_base = rte_calloc("eth_queue_stats",
> +                     RTE_MAX(net_hw->max_rx_queues, net_hw-
> >max_tx_queues),
> +                     sizeof(struct eth_queue_stats), 0);
> +     if (net_hw->eth_qstats_base == NULL) {
> +             PMD_INIT_LOG(ERR, "No memory for queue stats base values
> on device %s!",
> +                             pci_dev->device.name);
> +             rte_free(net_hw->eth_xstats_base);
> +             err = -ENOMEM;
> +             goto ipsec_exit;
> +     }
> +
>       /* Work out where in the BAR the queues start. */
>       tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
>       rx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_RXQ);
> @@ -1183,6 +1195,7 @@ nfp_net_init(struct rte_eth_dev *eth_dev,
>       if ((hw->cap & NFP_NET_CFG_CTRL_TXRWB) != 0)
>               nfp_net_txrwb_free(eth_dev);
>  xstats_free:
> +     rte_free(net_hw->eth_qstats_base);
>       rte_free(net_hw->eth_xstats_base);
>  ipsec_exit:
>       nfp_ipsec_uninit(eth_dev);
> diff --git a/drivers/net/nfp/nfp_ethdev_vf.c b/drivers/net/nfp/nfp_ethdev_vf.c
> index a86cc36592..d81a5052b9 100644
> --- a/drivers/net/nfp/nfp_ethdev_vf.c
> +++ b/drivers/net/nfp/nfp_ethdev_vf.c
> @@ -172,6 +172,7 @@ nfp_netvf_close(struct rte_eth_dev *dev)
>       pci_dev = RTE_CLASS_TO_BUS_DEVICE(dev, *pci_dev);
>       hw_priv = dev->process_private;
> 
> +     rte_free(net_hw->eth_qstats_base);
>       rte_free(net_hw->eth_xstats_base);
>       rte_free(hw_priv);
> 
> @@ -339,6 +340,17 @@ nfp_netvf_init(struct rte_eth_dev *eth_dev)
>               goto hw_priv_free;
>       }
> 
> +     net_hw->eth_qstats_base = rte_calloc("eth_queue_stats",
> +                     RTE_MAX(net_hw->max_rx_queues, net_hw-
> >max_tx_queues),
> +                     sizeof(struct eth_queue_stats), 0);
> +     if (net_hw->eth_qstats_base == NULL) {
> +             PMD_INIT_LOG(ERR, "No memory for queue stats base values
> on device %s!",
> +                             pci_dev->device.name);
> +             rte_free(net_hw->eth_xstats_base);
> +             err = -ENOMEM;
> +             goto hw_priv_free;
> +     }
> +
>       /* Work out where in the BAR the queues start. */
>       start_q = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
>       tx_bar_off = nfp_qcp_queue_offset(dev_info, start_q);
> @@ -406,6 +418,7 @@ nfp_netvf_init(struct rte_eth_dev *eth_dev)
>       return 0;
> 
>  free_xstats:
> +     rte_free(net_hw->eth_qstats_base);
>       rte_free(net_hw->eth_xstats_base);
>  hw_priv_free:
>       rte_free(hw_priv);
> diff --git a/drivers/net/nfp/nfp_net_common.c
> b/drivers/net/nfp/nfp_net_common.c
> index 2d36311cfe..afa0bc0faf 100644
> --- a/drivers/net/nfp/nfp_net_common.c
> +++ b/drivers/net/nfp/nfp_net_common.c
> @@ -919,35 +919,29 @@ nfp_net_stats_get(struct rte_eth_dev *dev,
> 
>       /* Reading per RX ring stats */
>       for (i = 0; i < dev->data->nb_rx_queues; i++) {
> -             if (i == RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                     break;
> -
>               uint64_t q_ipackets = nn_cfg_readq(&hw->super,
> NFP_NET_CFG_RXR_STATS(i));
> -             q_ipackets -= hw->eth_qstats_base.q_ipackets[i];
> +             q_ipackets -= hw->eth_qstats_base[i].q_ipackets;
> 
>               uint64_t q_ibytes = nn_cfg_readq(&hw->super,
> NFP_NET_CFG_RXR_STATS(i) + 0x8);
> -             q_ibytes -= hw->eth_qstats_base.q_ibytes[i];
> +             q_ibytes -= hw->eth_qstats_base[i].q_ibytes;
> 
>               if (qstats != NULL) {
> -                     qstats->q_ipackets[i] = q_ipackets;
> -                     qstats->q_ibytes[i] = q_ibytes;
> +                     qstats[i].q_ipackets = q_ipackets;
> +                     qstats[i].q_ibytes = q_ibytes;
>               }
>       }
> 
>       /* Reading per TX ring stats */
>       for (i = 0; i < dev->data->nb_tx_queues; i++) {
> -             if (i == RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                     break;
> -
>               uint64_t q_opackets = nn_cfg_readq(&hw->super,
> NFP_NET_CFG_TXR_STATS(i));
> -             q_opackets -= hw->eth_qstats_base.q_opackets[i];
> +             q_opackets -= hw->eth_qstats_base[i].q_opackets;
> 
>               uint64_t q_obytes = nn_cfg_readq(&hw->super,
> NFP_NET_CFG_TXR_STATS(i) + 0x8);
> -             q_obytes -= hw->eth_qstats_base.q_obytes[i];
> +             q_obytes -= hw->eth_qstats_base[i].q_obytes;
> 
>               if (qstats != NULL) {
> -                     qstats->q_opackets[i] = q_opackets;
> -                     qstats->q_obytes[i] = q_obytes;
> +                     qstats[i].q_opackets = q_opackets;
> +                     qstats[i].q_obytes = q_obytes;
>               }
>       }
> 
> @@ -999,25 +993,19 @@ nfp_net_stats_reset(struct rte_eth_dev *dev)
> 
>       /* Reading per RX ring stats */
>       for (i = 0; i < dev->data->nb_rx_queues; i++) {
> -             if (i == RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                     break;
> -
> -             hw->eth_qstats_base.q_ipackets[i] =
> +             hw->eth_qstats_base[i].q_ipackets =
>                               nn_cfg_readq(&hw->super,
> NFP_NET_CFG_RXR_STATS(i));
> 
> -             hw->eth_qstats_base.q_ibytes[i] =
> +             hw->eth_qstats_base[i].q_ibytes =
>                               nn_cfg_readq(&hw->super,
> NFP_NET_CFG_RXR_STATS(i) + 0x8);
>       }
> 
>       /* Reading per TX ring stats */
>       for (i = 0; i < dev->data->nb_tx_queues; i++) {
> -             if (i == RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                     break;
> -
> -             hw->eth_qstats_base.q_opackets[i] =
> +             hw->eth_qstats_base[i].q_opackets =
>                               nn_cfg_readq(&hw->super,
> NFP_NET_CFG_TXR_STATS(i));
> 
> -             hw->eth_qstats_base.q_obytes[i] =
> +             hw->eth_qstats_base[i].q_obytes =
>                               nn_cfg_readq(&hw->super,
> NFP_NET_CFG_TXR_STATS(i) + 0x8);
>       }
> 
> diff --git a/drivers/net/nfp/nfp_net_common.h
> b/drivers/net/nfp/nfp_net_common.h
> index 2bd2d54028..51082c6d29 100644
> --- a/drivers/net/nfp/nfp_net_common.h
> +++ b/drivers/net/nfp/nfp_net_common.h
> @@ -250,7 +250,8 @@ struct nfp_net_hw {
> 
>       /** Records starting point for counters */
>       struct rte_eth_stats eth_stats_base;
> -     struct eth_queue_stats eth_qstats_base;
> +     /** Per-queue counters, one entry per queue */
> +     struct eth_queue_stats *eth_qstats_base;
>       struct rte_eth_xstat *eth_xstats_base;
> 
>       struct nfp_cpp_area *ctrl_area;
> diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c
> index 09bcd791ed..dc8e65ecc2 100644
> --- a/drivers/net/ngbe/ngbe_ethdev.c
> +++ b/drivers/net/ngbe/ngbe_ethdev.c
> @@ -1498,10 +1498,8 @@ ngbe_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>  {
>       struct ngbe_hw *hw = ngbe_dev_hw(dev);
>       struct ngbe_hw_stats *hw_stats = NGBE_DEV_STATS(dev);
> -     struct ngbe_stat_mappings *stat_mappings =
> -                     NGBE_DEV_STAT_MAPPINGS(dev);
>       struct ngbe_tx_queue *txq;
> -     uint32_t i, j;
> +     uint32_t i;
> 
>       ngbe_read_stats_registers(hw, hw_stats);
> 
> @@ -1515,29 +1513,13 @@ ngbe_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>       stats->obytes = hw_stats->tx_bytes;
> 
>       if (qstats != NULL) {
> -             memset(&qstats->q_ipackets, 0, sizeof(qstats->q_ipackets));
> -             memset(&qstats->q_opackets, 0, sizeof(qstats->q_opackets));
> -             memset(&qstats->q_ibytes, 0, sizeof(qstats->q_ibytes));
> -             memset(&qstats->q_obytes, 0, sizeof(qstats->q_obytes));
> -             memset(&qstats->q_errors, 0, sizeof(qstats->q_errors));
> -             for (i = 0; i < NGBE_MAX_QP; i++) {
> -                     uint32_t n = i / NB_QMAP_FIELDS_PER_QSM_REG;
> -                     uint32_t offset = (i %
> NB_QMAP_FIELDS_PER_QSM_REG) * 8;
> -                     uint32_t q_map;
> -
> -                     q_map = (stat_mappings->rqsm[n] >> offset)
> -                                     &
> QMAP_FIELD_RESERVED_BITS_MASK;
> -                     j = (q_map < RTE_ETHDEV_QUEUE_STAT_CNTRS
> -                          ? q_map : q_map %
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -                     qstats->q_ipackets[j] += hw_stats-
> >qp[i].rx_qp_packets;
> -                     qstats->q_ibytes[j] += hw_stats->qp[i].rx_qp_bytes;
> -
> -                     q_map = (stat_mappings->tqsm[n] >> offset)
> -                                     &
> QMAP_FIELD_RESERVED_BITS_MASK;
> -                     j = (q_map < RTE_ETHDEV_QUEUE_STAT_CNTRS
> -                          ? q_map : q_map %
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -                     qstats->q_opackets[j] += hw_stats-
> >qp[i].tx_qp_packets;
> -                     qstats->q_obytes[j] += hw_stats->qp[i].tx_qp_bytes;
> +             for (i = 0; i < NGBE_MAX_QP && i < dev->data->nb_rx_queues;
> i++) {
> +                     qstats[i].q_ipackets += hw_stats->qp[i].rx_qp_packets;
> +                     qstats[i].q_ibytes += hw_stats->qp[i].rx_qp_bytes;
> +             }
> +             for (i = 0; i < NGBE_MAX_QP && i < dev->data->nb_tx_queues;
> i++) {
> +                     qstats[i].q_opackets += hw_stats-
> >qp[i].tx_qp_packets;
> +                     qstats[i].q_obytes += hw_stats->qp[i].tx_qp_bytes;
>               }
>       }
> 
> diff --git a/drivers/net/ngbe/ngbe_ethdev.h b/drivers/net/ngbe/ngbe_ethdev.h
> index 4f8dcff00e..12ee884ce1 100644
> --- a/drivers/net/ngbe/ngbe_ethdev.h
> +++ b/drivers/net/ngbe/ngbe_ethdev.h
> @@ -61,14 +61,6 @@ struct ngbe_interrupt {
>       uint64_t mask_orig; /* save mask during delayed handler */
>  };
> 
> -#define NGBE_NB_STAT_MAPPING  32
> -#define NB_QMAP_FIELDS_PER_QSM_REG 4
> -#define QMAP_FIELD_RESERVED_BITS_MASK 0x0f
> -struct ngbe_stat_mappings {
> -     uint32_t tqsm[NGBE_NB_STAT_MAPPING];
> -     uint32_t rqsm[NGBE_NB_STAT_MAPPING];
> -};
> -
>  struct ngbe_vfta {
>       uint32_t vfta[NGBE_VFTA_SIZE];
>  };
> @@ -127,7 +119,6 @@ struct ngbe_adapter {
>       struct ngbe_hw             hw;
>       struct ngbe_hw_stats       stats;
>       struct ngbe_interrupt      intr;
> -     struct ngbe_stat_mappings  stat_mappings;
>       struct ngbe_vfta           shadow_vfta;
>       struct ngbe_hwstrip        hwstrip;
>       struct ngbe_vf_info        *vfdata;
> @@ -171,9 +162,6 @@ ngbe_dev_intr(struct rte_eth_dev *dev)
>       return intr;
>  }
> 
> -#define NGBE_DEV_STAT_MAPPINGS(dev) \
> -     (&((struct ngbe_adapter *)(dev)->data->dev_private)->stat_mappings)
> -
>  #define NGBE_DEV_VFTA(dev) \
>       (&((struct ngbe_adapter *)(dev)->data->dev_private)->shadow_vfta)
> 
> diff --git a/drivers/net/ntnic/ntnic_ethdev.c 
> b/drivers/net/ntnic/ntnic_ethdev.c
> index bee34d20d7..effaf7cade 100644
> --- a/drivers/net/ntnic/ntnic_ethdev.c
> +++ b/drivers/net/ntnic/ntnic_ethdev.c
> @@ -197,18 +197,18 @@ static int dpdk_stats_collect(struct pmd_internals
> *internals, struct rte_eth_st
>       ntnic_filter_ops->poll_statistics(internals);
> 
>       for (i = 0; i < internals->nb_rx_queues; i++) {
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = internals->rxq_scg[i].rx_pkts;
> -                     qstats->q_ibytes[i] = internals->rxq_scg[i].rx_bytes;
> +             if (qstats != NULL) {
> +                     qstats[i].q_ipackets = internals->rxq_scg[i].rx_pkts;
> +                     qstats[i].q_ibytes = internals->rxq_scg[i].rx_bytes;
>               }
>               rx_total += internals->rxq_scg[i].rx_pkts;
>               rx_total_b += internals->rxq_scg[i].rx_bytes;
>       }
> 
>       for (i = 0; i < internals->nb_tx_queues; i++) {
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = internals->txq_scg[i].tx_pkts;
> -                     qstats->q_obytes[i] = internals->txq_scg[i].tx_bytes;
> +             if (qstats != NULL) {
> +                     qstats[i].q_opackets = internals->txq_scg[i].tx_pkts;
> +                     qstats[i].q_obytes = internals->txq_scg[i].tx_bytes;
>               }
>               tx_total += internals->txq_scg[i].tx_pkts;
>               tx_total_b += internals->txq_scg[i].tx_bytes;
> diff --git a/drivers/net/null/rte_eth_null.c b/drivers/net/null/rte_eth_null.c
> index 7fba3a661b..a469825cb6 100644
> --- a/drivers/net/null/rte_eth_null.c
> +++ b/drivers/net/null/rte_eth_null.c
> @@ -332,9 +332,9 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               stats->ipackets += pkts;
>               stats->ibytes += bytes;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = pkts;
> -                     qstats->q_ibytes[i] = bytes;
> +             if (qstats != NULL && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = pkts;
> +                     qstats[i].q_ibytes = bytes;
>               }
>       }
> 
> @@ -348,9 +348,9 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               stats->opackets += pkts;
>               stats->obytes += bytes;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = pkts;
> -                     qstats->q_obytes[i] = bytes;
> +             if (qstats != NULL && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = pkts;
> +                     qstats[i].q_obytes = bytes;
>               }
>       }
> 
> diff --git a/drivers/net/octeon_ep/otx_ep_ethdev.c
> b/drivers/net/octeon_ep/otx_ep_ethdev.c
> index 876d2f9d7d..85b3c09155 100644
> --- a/drivers/net/octeon_ep/otx_ep_ethdev.c
> +++ b/drivers/net/octeon_ep/otx_ep_ethdev.c
> @@ -626,9 +626,9 @@ otx_ep_dev_stats_get(struct rte_eth_dev *eth_dev,
> 
>       for (i = 0; i < otx_epvf->nb_tx_queues; i++) {
>               ostats = &otx_epvf->instr_queue[i]->stats;
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = ostats->tx_pkts;
> -                     qstats->q_obytes[i] = ostats->tx_bytes;
> +             if (qstats != NULL && i < eth_dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = ostats->tx_pkts;
> +                     qstats[i].q_obytes = ostats->tx_bytes;
>               }
>               stats->opackets += ostats->tx_pkts;
>               stats->obytes += ostats->tx_bytes;
> @@ -636,10 +636,9 @@ otx_ep_dev_stats_get(struct rte_eth_dev *eth_dev,
>       }
>       for (i = 0; i < otx_epvf->nb_rx_queues; i++) {
>               istats = &otx_epvf->droq[i]->stats;
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = istats->pkts_received;
> -                     qstats->q_ibytes[i] = istats->bytes_received;
> -                     qstats->q_errors[i] = istats->rx_err;
> +             if (qstats != NULL && i < eth_dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = istats->pkts_received;
> +                     qstats[i].q_ibytes = istats->bytes_received;
>               }
>               stats->ipackets += istats->pkts_received;
>               stats->ibytes += istats->bytes_received;
> diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
> index 08d3ab9e91..b1f3718c8a 100644
> --- a/drivers/net/pcap/pcap_ethdev.c
> +++ b/drivers/net/pcap/pcap_ethdev.c
> @@ -1075,11 +1075,10 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>       unsigned long tx_packets_err_total = 0;
>       const struct pmd_internals *internal = dev->data->dev_private;
> 
> -     for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> -                     i < dev->data->nb_rx_queues; i++) {
> +     for (i = 0; i < dev->data->nb_rx_queues; i++) {
>               if (qstats != NULL) {
> -                     qstats->q_ipackets[i] = internal-
> >rx_queue[i].rx_stat.pkts;
> -                     qstats->q_ibytes[i] = internal-
> >rx_queue[i].rx_stat.bytes;
> +                     qstats[i].q_ipackets = internal-
> >rx_queue[i].rx_stat.pkts;
> +                     qstats[i].q_ibytes = internal-
> >rx_queue[i].rx_stat.bytes;
>               }
>               rx_nombuf_total += internal->rx_queue[i].rx_stat.rx_nombuf;
>               rx_err_total += internal->rx_queue[i].rx_stat.err_pkts;
> @@ -1088,11 +1087,10 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               rx_missed_total += queue_missed_stat_get(dev, i);
>       }
> 
> -     for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> -                     i < dev->data->nb_tx_queues; i++) {
> +     for (i = 0; i < dev->data->nb_tx_queues; i++) {
>               if (qstats != NULL) {
> -                     qstats->q_opackets[i] = internal-
> >tx_queue[i].tx_stat.pkts;
> -                     qstats->q_obytes[i] = internal-
> >tx_queue[i].tx_stat.bytes;
> +                     qstats[i].q_opackets = internal-
> >tx_queue[i].tx_stat.pkts;
> +                     qstats[i].q_obytes = internal-
> >tx_queue[i].tx_stat.bytes;
>               }
>               tx_packets_total += internal->tx_queue[i].tx_stat.pkts;
>               tx_bytes_total += internal->tx_queue[i].tx_stat.bytes;
> diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
> index 4efc2dd349..b5bbcd6625 100644
> --- a/drivers/net/qede/qede_ethdev.c
> +++ b/drivers/net/qede/qede_ethdev.c
> @@ -397,10 +397,8 @@ static void qede_reset_queue_stats(struct qede_dev
> *qdev, bool xstats)
> 
>       DP_VERBOSE(edev, ECORE_MSG_DEBUG, "Clearing queue stats\n");
> 
> -     rxq_stat_cntrs = RTE_MIN(QEDE_RSS_COUNT(dev),
> -                            RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -     txq_stat_cntrs = RTE_MIN(QEDE_TSS_COUNT(dev),
> -                            RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     rxq_stat_cntrs = QEDE_RSS_COUNT(dev);
> +     txq_stat_cntrs = QEDE_TSS_COUNT(dev);
> 
>       for (qid = 0; qid < qdev->num_rx_queues; qid++) {
>               OSAL_MEMSET(((char *)(qdev->fp_array[qid].rxq)) +
> @@ -1634,20 +1632,11 @@ qede_get_stats(struct rte_eth_dev *eth_dev,
> struct rte_eth_stats *eth_stats,
>       eth_stats->oerrors = stats.common.tx_err_drop_pkts;
> 
>       /* Queue stats */
> -     rxq_stat_cntrs = RTE_MIN(QEDE_RSS_COUNT(eth_dev),
> -                            RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -     txq_stat_cntrs = RTE_MIN(QEDE_TSS_COUNT(eth_dev),
> -                            RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -     if (rxq_stat_cntrs != (unsigned int)QEDE_RSS_COUNT(eth_dev) ||
> -         txq_stat_cntrs != (unsigned int)QEDE_TSS_COUNT(eth_dev))
> -             DP_VERBOSE(edev, ECORE_MSG_DEBUG,
> -                    "Not all the queue stats will be displayed. Set"
> -                    " RTE_ETHDEV_QUEUE_STAT_CNTRS config param"
> -                    " appropriately and retry.\n");
> +     rxq_stat_cntrs = QEDE_RSS_COUNT(eth_dev);
> +     txq_stat_cntrs = QEDE_TSS_COUNT(eth_dev);
> 
>       for (qid = 0; qid < eth_dev->data->nb_rx_queues; qid++) {
>               uint64_t q_ipackets = 0;
> -             uint64_t q_errors = 0;
> 
>               for_each_hwfn(edev, hw_fn) {
>                       idx = qid * edev->num_hwfns + hw_fn;
> @@ -1657,21 +1646,10 @@ qede_get_stats(struct rte_eth_dev *eth_dev,
> struct rte_eth_stats *eth_stats,
>                                       (((char *)(qdev->fp_array[idx].rxq)) +
>                                        offsetof(struct qede_rx_queue,
>                                        rcv_pkts));
> -                     q_errors +=
> -                             *(uint64_t *)
> -                                     (((char *)(qdev->fp_array[idx].rxq)) +
> -                                      offsetof(struct qede_rx_queue,
> -                                      rx_hw_errors)) +
> -                             *(uint64_t *)
> -                                     (((char *)(qdev->fp_array[idx].rxq)) +
> -                                      offsetof(struct qede_rx_queue,
> -                                      rx_alloc_errors));
>               }
> 
> -             if (qstats != NULL) {
> -                     qstats->q_ipackets[i] = q_ipackets;
> -                     qstats->q_errors[i] = q_errors;
> -             }
> +             if (qstats != NULL)
> +                     qstats[i].q_ipackets = q_ipackets;
> 
>               i++;
>               if (i == rxq_stat_cntrs)
> @@ -1693,7 +1671,7 @@ qede_get_stats(struct rte_eth_dev *eth_dev, struct
> rte_eth_stats *eth_stats,
>               }
> 
>               if (qstats != NULL)
> -                     qstats->q_opackets[j] = q_opackets;
> +                     qstats[j].q_opackets = q_opackets;
> 
>               j++;
>               if (j == txq_stat_cntrs)
> diff --git a/drivers/net/ring/rte_eth_ring.c b/drivers/net/ring/rte_eth_ring.c
> index b639544eab..2ba9b66b41 100644
> --- a/drivers/net/ring/rte_eth_ring.c
> +++ b/drivers/net/ring/rte_eth_ring.c
> @@ -203,17 +203,15 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>       unsigned long rx_total = 0, tx_total = 0;
>       const struct pmd_internals *internal = dev->data->dev_private;
> 
> -     for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> -                     i < dev->data->nb_rx_queues; i++) {
> +     for (i = 0; i < dev->data->nb_rx_queues; i++) {
>               if (qstats != NULL)
> -                     qstats->q_ipackets[i] = internal-
> >rx_ring_queues[i].rx_pkts;
> +                     qstats[i].q_ipackets = internal-
> >rx_ring_queues[i].rx_pkts;
>               rx_total += internal->rx_ring_queues[i].rx_pkts;
>       }
> 
> -     for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> -                     i < dev->data->nb_tx_queues; i++) {
> +     for (i = 0; i < dev->data->nb_tx_queues; i++) {
>               if (qstats != NULL)
> -                     qstats->q_opackets[i] = internal-
> >tx_ring_queues[i].tx_pkts;
> +                     qstats[i].q_opackets = internal-
> >tx_ring_queues[i].tx_pkts;
>               tx_total += internal->tx_ring_queues[i].tx_pkts;
>       }
> 
> diff --git a/drivers/net/rnp/rnp_ethdev.c b/drivers/net/rnp/rnp_ethdev.c
> index e48ad0e317..125134f8d4 100644
> --- a/drivers/net/rnp/rnp_ethdev.c
> +++ b/drivers/net/rnp/rnp_ethdev.c
> @@ -1252,9 +1252,9 @@ rnp_dev_stats_get(struct rte_eth_dev *dev,
>                       continue;
>               stats->ipackets += rxq->stats.ipackets;
>               stats->ibytes += rxq->stats.ibytes;
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = rxq->stats.ipackets;
> -                     qstats->q_ibytes[i] = rxq->stats.ibytes;
> +             if (qstats != NULL && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = rxq->stats.ipackets;
> +                     qstats[i].q_ibytes = rxq->stats.ibytes;
>               }
>       }
> 
> @@ -1266,9 +1266,9 @@ rnp_dev_stats_get(struct rte_eth_dev *dev,
>               stats->opackets += txq->stats.opackets;
>               stats->obytes += txq->stats.obytes;
>               stats->oerrors += txq->stats.errors;
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = txq->stats.opackets;
> -                     qstats->q_obytes[i] = txq->stats.obytes;
> +             if (qstats != NULL && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = txq->stats.opackets;
> +                     qstats[i].q_obytes = txq->stats.obytes;
>               }
>       }
>       stats->imissed = eth_stats->rx_trans_drop + eth_stats->rx_trunc_drop;
> diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c
> b/drivers/net/sxe2/sxe2_cmd_chnl.c
> index 050488301c..130e0fa11b 100644
> --- a/drivers/net/sxe2/sxe2_cmd_chnl.c
> +++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
> @@ -1577,15 +1577,11 @@ int32_t sxe2_drv_queue_info_get_update(struct
> sxe2_adapter *adapter, struct eth_
>       struct sxe2_drv_cmd_params param = {0};
>       struct sxe2_queue_map_info resp = {0};
>       struct sxe2_common_device *cdev = adapter->cdev;
> +     struct rte_eth_dev_data *dev_data = adapter->dev_info.dev_data;
>       uint8_t pool_idx;
>       uint8_t index;
>       int32_t ret;
> 
> -     if (!(adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_Q_MAP)) {
> -             ret = 0;
> -             goto l_end;
> -     }
> -
>       sxe2_drv_cmd_params_fill(adapter, &param,
> SXE2_DRV_CMD_TX_RX_MAP_GET,
>                                NULL, 0,
>                                &resp, sizeof(resp));
> @@ -1595,14 +1591,16 @@ int32_t sxe2_drv_queue_info_get_update(struct
> sxe2_adapter *adapter, struct eth_
>               goto l_end;
>       }
> 
> -     for (pool_idx = 0; pool_idx < SXE2_RXQ_STATS_MAP_MAX_NUM;
> pool_idx++) {
> -             qstats->q_ipackets[pool_idx] =
> resp.rxq_stats_map_info[pool_idx].rxq_lan_in_pkt_cnt;
> -             qstats->q_ibytes[pool_idx] =
> resp.rxq_stats_map_info[pool_idx].rxq_lan_in_byte_cnt;
> +     for (pool_idx = 0; pool_idx < SXE2_RXQ_STATS_MAP_MAX_NUM &&
> +                     pool_idx < dev_data->nb_rx_queues; pool_idx++) {
> +             qstats[pool_idx].q_ipackets =
> resp.rxq_stats_map_info[pool_idx].rxq_lan_in_pkt_cnt;
> +             qstats[pool_idx].q_ibytes =
> resp.rxq_stats_map_info[pool_idx].rxq_lan_in_byte_cnt;
>       }
> 
> -     for (index = 0; index < SXE2_TXQ_STATS_MAP_MAX_NUM; index++) {
> -             qstats->q_opackets[index] =
> resp.txq_stats_map_info[index].txq_lan_pkt_cnt;
> -             qstats->q_obytes[index] =
> resp.txq_stats_map_info[index].txq_lan_byte_cnt;
> +     for (index = 0; index < SXE2_TXQ_STATS_MAP_MAX_NUM &&
> +                     index < dev_data->nb_tx_queues; index++) {
> +             qstats[index].q_opackets =
> resp.txq_stats_map_info[index].txq_lan_pkt_cnt;
> +             qstats[index].q_obytes =
> resp.txq_stats_map_info[index].txq_lan_byte_cnt;
>       }
> 
>  l_end:
> diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
> index b93452f168..3d381a47a9 100644
> --- a/drivers/net/tap/rte_eth_tap.c
> +++ b/drivers/net/tap/rte_eth_tap.c
> @@ -1004,9 +1004,9 @@ tap_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *tap_stats,
> 
>               if (rxq == NULL)
>                       continue;
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = rxq->stats.packets;
> -                     qstats->q_ibytes[i] = rxq->stats.bytes;
> +             if (qstats != NULL && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = rxq->stats.packets;
> +                     qstats[i].q_ibytes = rxq->stats.bytes;
>               }
>               rx_total += rxq->stats.packets;
>               rx_bytes_total += rxq->stats.bytes;
> @@ -1019,9 +1019,9 @@ tap_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *tap_stats,
> 
>               if (txq == NULL)
>                       continue;
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = txq->stats.packets;
> -                     qstats->q_obytes[i] = txq->stats.bytes;
> +             if (qstats != NULL && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = txq->stats.packets;
> +                     qstats[i].q_obytes = txq->stats.bytes;
>               }
>               tx_total += txq->stats.packets;
>               tx_bytes_total += txq->stats.bytes;
> diff --git a/drivers/net/thunderx/nicvf_ethdev.c
> b/drivers/net/thunderx/nicvf_ethdev.c
> index 6e34da7c3c..30d03f4db9 100644
> --- a/drivers/net/thunderx/nicvf_ethdev.c
> +++ b/drivers/net/thunderx/nicvf_ethdev.c
> @@ -306,13 +306,13 @@ nicvf_dev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
> 
>       /* Reading per RX ring stats */
>       for (qidx = rx_start; qidx <= rx_end; qidx++) {
> -             if (qidx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)
> +             if (qidx >= dev->data->nb_rx_queues)
>                       break;
> 
>               nicvf_hw_get_rx_qstats(nic, &rx_qstats, qidx);
>               if (qstats != NULL) {
> -                     qstats->q_ibytes[qidx] = rx_qstats.q_rx_bytes;
> -                     qstats->q_ipackets[qidx] = rx_qstats.q_rx_packets;
> +                     qstats[qidx].q_ibytes = rx_qstats.q_rx_bytes;
> +                     qstats[qidx].q_ipackets = rx_qstats.q_rx_packets;
>               }
>       }
> 
> @@ -321,13 +321,13 @@ nicvf_dev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
> 
>       /* Reading per TX ring stats */
>       for (qidx = tx_start; qidx <= tx_end; qidx++) {
> -             if (qidx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)
> +             if (qidx >= dev->data->nb_tx_queues)
>                       break;
> 
>               nicvf_hw_get_tx_qstats(nic, &tx_qstats, qidx);
>               if (qstats != NULL) {
> -                     qstats->q_obytes[qidx] = tx_qstats.q_tx_bytes;
> -                     qstats->q_opackets[qidx] = tx_qstats.q_tx_packets;
> +                     qstats[qidx].q_obytes = tx_qstats.q_tx_bytes;
> +                     qstats[qidx].q_opackets = tx_qstats.q_tx_packets;
>               }
>       }
> 
> @@ -342,14 +342,14 @@ nicvf_dev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
> 
>               /* Reading per RX ring stats */
>               for (qidx = rx_start; qidx <= rx_end; qidx++) {
> -                     if (qidx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)
> +                     if (qidx >= dev->data->nb_rx_queues)
>                               break;
> 
>                       nicvf_hw_get_rx_qstats(snic, &rx_qstats,
>                                              qidx %
> MAX_RCV_QUEUES_PER_QS);
>                       if (qstats != NULL) {
> -                             qstats->q_ibytes[qidx] = rx_qstats.q_rx_bytes;
> -                             qstats->q_ipackets[qidx] =
> rx_qstats.q_rx_packets;
> +                             qstats[qidx].q_ibytes = rx_qstats.q_rx_bytes;
> +                             qstats[qidx].q_ipackets =
> rx_qstats.q_rx_packets;
>                       }
>               }
> 
> @@ -357,14 +357,14 @@ nicvf_dev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               nicvf_tx_range(dev, snic, &tx_start, &tx_end);
>               /* Reading per TX ring stats */
>               for (qidx = tx_start; qidx <= tx_end; qidx++) {
> -                     if (qidx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)
> +                     if (qidx >= dev->data->nb_tx_queues)
>                               break;
> 
>                       nicvf_hw_get_tx_qstats(snic, &tx_qstats,
>                                              qidx %
> MAX_SND_QUEUES_PER_QS);
>                       if (qstats != NULL) {
> -                             qstats->q_obytes[qidx] =
> tx_qstats.q_tx_bytes;
> -                             qstats->q_opackets[qidx] =
> tx_qstats.q_tx_packets;
> +                             qstats[qidx].q_obytes = tx_qstats.q_tx_bytes;
> +                             qstats[qidx].q_opackets =
> tx_qstats.q_tx_packets;
>                       }
>               }
>       }
> diff --git a/drivers/net/txgbe/txgbe_ethdev.c
> b/drivers/net/txgbe/txgbe_ethdev.c
> index 6349aca90f..5eae613d32 100644
> --- a/drivers/net/txgbe/txgbe_ethdev.c
> +++ b/drivers/net/txgbe/txgbe_ethdev.c
> @@ -2452,13 +2452,13 @@ txgbe_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>       stats->obytes = hw_stats->tx_bytes;
> 
>       if (qstats != NULL) {
> -             for (i = 0; i < TXGBE_MAX_QP; i++) {
> -                     if (i >= RTE_ETHDEV_QUEUE_STAT_CNTRS)
> -                             break;
> -                     qstats->q_ipackets[i] += hw_stats-
> >qp[i].rx_qp_packets;
> -                     qstats->q_ibytes[i] += hw_stats->qp[i].rx_qp_bytes;
> -                     qstats->q_opackets[i] += hw_stats-
> >qp[i].tx_qp_packets;
> -                     qstats->q_obytes[i] += hw_stats->qp[i].tx_qp_bytes;
> +             for (i = 0; i < TXGBE_MAX_QP && i < dev->data-
> >nb_rx_queues; i++) {
> +                     qstats[i].q_ipackets += hw_stats->qp[i].rx_qp_packets;
> +                     qstats[i].q_ibytes += hw_stats->qp[i].rx_qp_bytes;
> +             }
> +             for (i = 0; i < TXGBE_MAX_QP && i < dev->data-
> >nb_tx_queues; i++) {
> +                     qstats[i].q_opackets += hw_stats-
> >qp[i].tx_qp_packets;
> +                     qstats[i].q_obytes += hw_stats->qp[i].tx_qp_bytes;
>               }
>       }
> 
> diff --git a/drivers/net/vhost/rte_eth_vhost.c
> b/drivers/net/vhost/rte_eth_vhost.c
> index 05940f2461..f2dfae7175 100644
> --- a/drivers/net/vhost/rte_eth_vhost.c
> +++ b/drivers/net/vhost/rte_eth_vhost.c
> @@ -1319,27 +1319,25 @@ eth_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>       unsigned long tx_total_errors = 0;
>       struct vhost_queue *vq;
> 
> -     for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> -                     i < dev->data->nb_rx_queues; i++) {
> +     for (i = 0; i < dev->data->nb_rx_queues; i++) {
>               if (dev->data->rx_queues[i] == NULL)
>                       continue;
>               vq = dev->data->rx_queues[i];
>               if (qstats != NULL) {
> -                     qstats->q_ipackets[i] = vq->stats.pkts;
> -                     qstats->q_ibytes[i] = vq->stats.bytes;
> +                     qstats[i].q_ipackets = vq->stats.pkts;
> +                     qstats[i].q_ibytes = vq->stats.bytes;
>               }
>               rx_total += vq->stats.pkts;
>               rx_total_bytes += vq->stats.bytes;
>       }
> 
> -     for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> -                     i < dev->data->nb_tx_queues; i++) {
> +     for (i = 0; i < dev->data->nb_tx_queues; i++) {
>               if (dev->data->tx_queues[i] == NULL)
>                       continue;
>               vq = dev->data->tx_queues[i];
>               if (qstats != NULL) {
> -                     qstats->q_opackets[i] = vq->stats.pkts;
> -                     qstats->q_obytes[i] = vq->stats.bytes;
> +                     qstats[i].q_opackets = vq->stats.pkts;
> +                     qstats[i].q_obytes = vq->stats.bytes;
>               }
>               tx_total += vq->stats.pkts;
>               tx_total_bytes += vq->stats.bytes;
> diff --git a/drivers/net/virtio/virtio_ethdev.c 
> b/drivers/net/virtio/virtio_ethdev.c
> index 0b2574bd02..a6fe4f3023 100644
> --- a/drivers/net/virtio/virtio_ethdev.c
> +++ b/drivers/net/virtio/virtio_ethdev.c
> @@ -701,9 +701,9 @@ virtio_update_stats(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               stats->opackets += txvq->stats.packets;
>               stats->obytes += txvq->stats.bytes;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = txvq->stats.packets;
> -                     qstats->q_obytes[i] = txvq->stats.bytes;
> +             if (qstats != NULL && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = txvq->stats.packets;
> +                     qstats[i].q_obytes = txvq->stats.bytes;
>               }
>       }
> 
> @@ -716,9 +716,9 @@ virtio_update_stats(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>               stats->ibytes += rxvq->stats.bytes;
>               stats->ierrors += rxvq->stats.errors;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = rxvq->stats.packets;
> -                     qstats->q_ibytes[i] = rxvq->stats.bytes;
> +             if (qstats != NULL && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = rxvq->stats.packets;
> +                     qstats[i].q_ibytes = rxvq->stats.bytes;
>               }
>       }
> 
> diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> index b7cf217724..4a7c76cfef 100644
> --- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> +++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> @@ -1504,9 +1504,9 @@ vmxnet3_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>               stats->obytes += bytes;
>               stats->oerrors += txStats.pktsTxError + txStats.pktsTxDiscard;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_opackets[i] = packets;
> -                     qstats->q_obytes[i] = bytes;
> +             if (qstats != NULL && i < dev->data->nb_tx_queues) {
> +                     qstats[i].q_opackets = packets;
> +                     qstats[i].q_obytes = bytes;
>               }
>       }
> 
> @@ -1526,10 +1526,9 @@ vmxnet3_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>               stats->ierrors += rxStats.pktsRxError;
>               stats->imissed += rxStats.pktsRxOutOfBuf;
> 
> -             if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> -                     qstats->q_ipackets[i] = packets;
> -                     qstats->q_ibytes[i] = bytes;
> -                     qstats->q_errors[i] = rxStats.pktsRxError;
> +             if (qstats != NULL && i < dev->data->nb_rx_queues) {
> +                     qstats[i].q_ipackets = packets;
> +                     qstats[i].q_ibytes = bytes;
>               }
>       }
> 
> diff --git a/drivers/net/xsc/xsc_ethdev.c b/drivers/net/xsc/xsc_ethdev.c
> index 505f973d66..5fbe68782e 100644
> --- a/drivers/net/xsc/xsc_ethdev.c
> +++ b/drivers/net/xsc/xsc_ethdev.c
> @@ -593,11 +593,9 @@ xsc_ethdev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>                       continue;
> 
>               idx = rxq->idx;
> -             if (qstats != NULL && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS)
> {
> -                     qstats->q_ipackets[idx] += rxq->stats.rx_pkts;
> -                     qstats->q_ibytes[idx] += rxq->stats.rx_bytes;
> -                     qstats->q_errors[idx] += rxq->stats.rx_errors +
> -                                             rxq->stats.rx_nombuf;
> +             if (qstats != NULL && idx < dev->data->nb_rx_queues) {
> +                     qstats[idx].q_ipackets += rxq->stats.rx_pkts;
> +                     qstats[idx].q_ibytes += rxq->stats.rx_bytes;
>               }
>               stats->ipackets += rxq->stats.rx_pkts;
>               stats->ibytes += rxq->stats.rx_bytes;
> @@ -611,9 +609,9 @@ xsc_ethdev_stats_get(struct rte_eth_dev *dev, struct
> rte_eth_stats *stats,
>                       continue;
> 
>               idx = txq->idx;
> -             if (qstats != NULL && idx < RTE_ETHDEV_QUEUE_STAT_CNTRS)
> {
> -                     qstats->q_opackets[idx] += txq->stats.tx_pkts;
> -                     qstats->q_obytes[idx] += txq->stats.tx_bytes;
> +             if (qstats != NULL && idx < dev->data->nb_tx_queues) {
> +                     qstats[idx].q_opackets += txq->stats.tx_pkts;
> +                     qstats[idx].q_obytes += txq->stats.tx_bytes;
>               }
>               stats->opackets += txq->stats.tx_pkts;
>               stats->obytes += txq->stats.tx_bytes;
> diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.c
> b/drivers/net/zxdh/zxdh_ethdev_ops.c
> index 50247116d9..489ef76269 100644
> --- a/drivers/net/zxdh/zxdh_ethdev_ops.c
> +++ b/drivers/net/zxdh/zxdh_ethdev_ops.c
> @@ -1824,37 +1824,29 @@ zxdh_dev_stats_get(struct rte_eth_dev *dev,
> struct rte_eth_stats *stats,
>       }
> 
>       stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed;
> -     for (i = 0; (i < dev->data->nb_rx_queues) && (i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS); i++) {
> +     for (i = 0; i < dev->data->nb_rx_queues; i++) {
>               struct zxdh_virtnet_rx *rxvq = dev->data->rx_queues[i];
> 
>               if (rxvq == NULL)
>                       continue;
>               if (qstats != NULL) {
> -                     qstats->q_ipackets[i] = *(uint64_t *)(((char *)rxvq) +
> +                     qstats[i].q_ipackets = *(uint64_t *)(((char *)rxvq) +
>                                       zxdh_rxq_stat_strings[0].offset);
> -                     qstats->q_ibytes[i] = *(uint64_t *)(((char *)rxvq) +
> +                     qstats[i].q_ibytes = *(uint64_t *)(((char *)rxvq) +
>                                       zxdh_rxq_stat_strings[1].offset);
> -                     qstats->q_errors[i] = *(uint64_t *)(((char *)rxvq) +
> -                                     zxdh_rxq_stat_strings[2].offset);
> -                     qstats->q_errors[i] += *(uint64_t *)(((char *)rxvq) +
> -                                     zxdh_rxq_stat_strings[5].offset);
>               }
>       }
> 
> -     for (i = 0; (i < dev->data->nb_tx_queues) && (i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS); i++) {
> +     for (i = 0; i < dev->data->nb_tx_queues; i++) {
>               struct zxdh_virtnet_tx *txvq = dev->data->tx_queues[i];
> 
>               if (txvq == NULL)
>                       continue;
>               if (qstats != NULL) {
> -                     qstats->q_opackets[i] = *(uint64_t *)(((char *)txvq) +
> +                     qstats[i].q_opackets = *(uint64_t *)(((char *)txvq) +
>                                       zxdh_txq_stat_strings[0].offset);
> -                     qstats->q_obytes[i] = *(uint64_t *)(((char *)txvq) +
> +                     qstats[i].q_obytes = *(uint64_t *)(((char *)txvq) +
>                                       zxdh_txq_stat_strings[1].offset);
> -                     qstats->q_errors[i] += *(uint64_t *)(((char *)txvq) +
> -                                     zxdh_txq_stat_strings[2].offset);
> -                     qstats->q_errors[i] += *(uint64_t *)(((char *)txvq) +
> -                                     zxdh_txq_stat_strings[5].offset);
>               }
>       }
>       return 0;
> @@ -2002,13 +1994,13 @@ int zxdh_dev_stats_reset(struct rte_eth_dev
> *dev)
>       if (hw->is_pf)
>               zxdh_hw_stats_reset(dev, ZXDH_MAC_STATS_RESET);
>       zxdh_np_stats_reset(dev);
> -     for (i = 0; ((i < dev->data->nb_rx_queues) && (i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS)); i++) {
> +     for (i = 0; (i < dev->data->nb_rx_queues); i++) {
>               struct zxdh_virtnet_rx *rxvq = dev->data->rx_queues[i];
>               if (rxvq == NULL)
>                       continue;
>               memset(&rxvq->stats, 0, sizeof(struct zxdh_virtnet_stats));
>       }
> -     for (i = 0; ((i < dev->data->nb_tx_queues) && (i <
> RTE_ETHDEV_QUEUE_STAT_CNTRS)); i++) {
> +     for (i = 0; (i < dev->data->nb_tx_queues); i++) {
>               struct zxdh_virtnet_tx *txvq = dev->data->tx_queues[i];
>               if (txvq == NULL)
>                       continue;
> diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
> index 0477579cc3..041ba6851e 100644
> --- a/lib/ethdev/ethdev_driver.h
> +++ b/lib/ethdev/ethdev_driver.h
> @@ -24,25 +24,16 @@
>  extern "C" {
>  #endif
> 
> -#define RTE_ETHDEV_QUEUE_STAT_CNTRS 16 /* max 256 */
> -
>  /**
>   * @internal
> - * Structure used to pass queue stats back to ethdev
> - * for drivers which rely on ethdev to add the queue stats automatically to
> xstats.
> + * Per-queue counters added to xstats by ethdev.
> + * The array is allocated and zeroed by ethdev, with one entry per queue.
>   */
>  struct eth_queue_stats {
> -     /* Queue stats are limited to max 256 queues. */
> -     /** Total number of queue Rx packets. */
> -     uint64_t q_ipackets[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     /** Total number of queue Tx packets. */
> -     uint64_t q_opackets[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     /** Total number of successfully received queue bytes. */
> -     uint64_t q_ibytes[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     /** Total number of successfully transmitted queue bytes. */
> -     uint64_t q_obytes[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> -     /** Total number of queue packets received that are dropped. */
> -     uint64_t q_errors[RTE_ETHDEV_QUEUE_STAT_CNTRS];
> +     uint64_t q_ipackets;    /**< Number of received packets. */
> +     uint64_t q_opackets;    /**< Number of transmitted packets. */
> +     uint64_t q_ibytes;      /**< Number of received bytes. */
> +     uint64_t q_obytes;      /**< Number of transmitted bytes. */
>  };
> 
>  /**
> @@ -456,7 +447,11 @@ typedef int
> (*eth_speed_lanes_get_capability_t)(struct rte_eth_dev *dev,
>   * @param stats
>   *   The stats structure to be completed by the driver and returned to the 
> user.
>   * @param qstats
> - *   Any queue statistics to be returned.
> + *   Any queue statistics to be returned, indexed by queue id.
> + *   The array has RTE_MAX(nb_rx_queues, nb_tx_queues) entries and is
> + *   zeroed by ethdev before the driver is called. The driver must not
> + *   write past nb_rx_queues for the Rx fields, or past nb_tx_queues
> + *   for the Tx fields.
>   *   @note: This parameter can be NULL
>   */
>  typedef int (*eth_stats_get_t)(struct rte_eth_dev *dev,
> diff --git a/lib/ethdev/ethdev_private.c b/lib/ethdev/ethdev_private.c
> index 75ea3eedff..70cc6ae63c 100644
> --- a/lib/ethdev/ethdev_private.c
> +++ b/lib/ethdev/ethdev_private.c
> @@ -510,8 +510,6 @@ eth_stats_qstats_get(uint16_t port_id, struct
> rte_eth_stats *stats, struct eth_q
>       }
> 
>       memset(stats, 0, sizeof(*stats));
> -     if (qstats != NULL)
> -             memset(qstats, 0, sizeof(*qstats));
> 
>       if (dev->dev_ops->stats_get == NULL)
>               return -ENOTSUP;
> diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
> index d6915a6b08..253f6c0efa 100644
> --- a/lib/ethdev/rte_ethdev.c
> +++ b/lib/ethdev/rte_ethdev.c
> @@ -75,7 +75,6 @@ static const struct rte_eth_xstats_name_off
> eth_dev_stats_strings[] = {
>  static const struct rte_eth_xstats_name_off eth_dev_rxq_stats_strings[] = {
>       {"packets", offsetof(struct eth_queue_stats, q_ipackets)},
>       {"bytes", offsetof(struct eth_queue_stats, q_ibytes)},
> -     {"errors", offsetof(struct eth_queue_stats, q_errors)},
>  };
> 
>  #define RTE_NB_RXQ_STATS RTE_DIM(eth_dev_rxq_stats_strings)
> @@ -3387,8 +3386,8 @@ eth_dev_get_xstats_basic_count(struct rte_eth_dev
> *dev)
>       uint16_t nb_rxqs, nb_txqs;
>       int count;
> 
> -     nb_rxqs = RTE_MIN(dev->data->nb_rx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -     nb_txqs = RTE_MIN(dev->data->nb_tx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     nb_rxqs = dev->data->nb_rx_queues;
> +     nb_txqs = dev->data->nb_tx_queues;
> 
>       count = RTE_NB_STATS;
>       if (dev->data->dev_flags & RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS) {
> @@ -3501,7 +3500,7 @@ eth_basic_stats_get_names(struct rte_eth_dev
> *dev,
>       if ((dev->data->dev_flags & RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS)
> == 0)
>               return cnt_used_entries;
> 
> -     num_q = RTE_MIN(dev->data->nb_rx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     num_q = dev->data->nb_rx_queues;
>       for (id_queue = 0; id_queue < num_q; id_queue++) {
>               for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) {
>                       unsigned int cc;
> @@ -3518,7 +3517,7 @@ eth_basic_stats_get_names(struct rte_eth_dev
> *dev,
>               }
> 
>       }
> -     num_q = RTE_MIN(dev->data->nb_tx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     num_q = dev->data->nb_tx_queues;
>       for (id_queue = 0; id_queue < num_q; id_queue++) {
>               for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) {
>                       unsigned int cc;
> @@ -3708,54 +3707,61 @@ eth_basic_stats_get(uint16_t port_id, struct
> rte_eth_xstat *xstats)
>  {
>       struct rte_eth_dev *dev;
>       struct rte_eth_stats eth_stats;
> -     struct eth_queue_stats queue_stats;
> +     struct eth_queue_stats *queue_stats = NULL;
>       unsigned int count = 0, i, q;
> -     uint64_t val, *stats_ptr;
> -     uint16_t nb_rxqs, nb_txqs;
> +     uint16_t nb_rxqs, nb_txqs, nb_q;
> +     uint64_t *stats_ptr;
>       int ret;
> 
> -     ret = eth_stats_qstats_get(port_id, &eth_stats, &queue_stats);
> -     if (ret < 0)
> -             return ret;
> -
>       dev = &rte_eth_devices[port_id];
> 
> -     nb_rxqs = RTE_MIN(dev->data->nb_rx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> -     nb_txqs = RTE_MIN(dev->data->nb_tx_queues,
> RTE_ETHDEV_QUEUE_STAT_CNTRS);
> +     if (dev->data->dev_flags & RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS) {
> +             nb_rxqs = dev->data->nb_rx_queues;
> +             nb_txqs = dev->data->nb_tx_queues;
> +     } else {
> +             nb_rxqs = 0;
> +             nb_txqs = 0;
> +     }
> +
> +     nb_q = RTE_MAX(nb_rxqs, nb_txqs);
> +     if (nb_q > 0) {
> +             queue_stats = calloc(nb_q, sizeof(*queue_stats));
> +             if (queue_stats == NULL)
> +                     return -ENOMEM;
> +     }
> +
> +     ret = eth_stats_qstats_get(port_id, &eth_stats, queue_stats);
> +     if (ret < 0)
> +             goto out;
> 
>       /* global stats */
>       for (i = 0; i < RTE_NB_STATS; i++) {
>               stats_ptr = RTE_PTR_ADD(&eth_stats,
>                                       eth_dev_stats_strings[i].offset);
> -             val = *stats_ptr;
> -             xstats[count++].value = val;
> +             xstats[count++].value = *stats_ptr;
>       }
> 
> -     if ((dev->data->dev_flags & RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS)
> == 0)
> -             return count;
> -
>       /* per-rxq stats */
>       for (q = 0; q < nb_rxqs; q++) {
>               for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
> -                     stats_ptr = RTE_PTR_ADD(&queue_stats,
> -                                     eth_dev_rxq_stats_strings[i].offset +
> -                                     q * sizeof(uint64_t));
> -                     val = *stats_ptr;
> -                     xstats[count++].value = val;
> +                     stats_ptr = RTE_PTR_ADD(&queue_stats[q],
> +                                     eth_dev_rxq_stats_strings[i].offset);
> +                     xstats[count++].value = *stats_ptr;
>               }
>       }
> 
>       /* per-txq stats */
>       for (q = 0; q < nb_txqs; q++) {
>               for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
> -                     stats_ptr = RTE_PTR_ADD(&queue_stats,
> -                                     eth_dev_txq_stats_strings[i].offset +
> -                                     q * sizeof(uint64_t));
> -                     val = *stats_ptr;
> -                     xstats[count++].value = val;
> +                     stats_ptr = RTE_PTR_ADD(&queue_stats[q],
> +                                     eth_dev_txq_stats_strings[i].offset);
> +                     xstats[count++].value = *stats_ptr;
>               }
>       }
> -     return count;
> +     ret = count;
> +out:
> +     free(queue_stats);
> +     return ret;
>  }
> 
>  static int
> --
> 2.53.0

Reply via email to