#undef FRAME_FILTER_DEBUG
 /* #define FRAME_FILTER_DEBUG */
 
+struct stmmac_txq_stats {
+       unsigned long tx_pkt_n;
+};
+
+struct stmmac_rxq_stats {
+       unsigned long rx_pkt_n;
+};
+
 /* Extra statistic and debug information exposed by ethtool */
 struct stmmac_extra_stats {
        /* Transmit errors */
        unsigned long mtl_est_hlbf;
        unsigned long mtl_est_btre;
        unsigned long mtl_est_btrlm;
+       /* per queue statistics */
+       struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
+       struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
 };
 
 /* Safety Feature statistics exposed by ethtool */
 
 };
 #define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc)
 
+static const char stmmac_qstats_tx_string[][ETH_GSTRING_LEN] = {
+       "tx_pkt_n",
+#define STMMAC_TXQ_STATS ARRAY_SIZE(stmmac_qstats_tx_string)
+};
+
+static const char stmmac_qstats_rx_string[][ETH_GSTRING_LEN] = {
+       "rx_pkt_n",
+#define STMMAC_RXQ_STATS ARRAY_SIZE(stmmac_qstats_rx_string)
+};
+
 static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
                                      struct ethtool_drvinfo *info)
 {
        }
 }
 
+static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
+{
+       u32 tx_cnt = priv->plat->tx_queues_to_use;
+       u32 rx_cnt = priv->plat->rx_queues_to_use;
+       int q, stat;
+       char *p;
+
+       for (q = 0; q < tx_cnt; q++) {
+               p = (char *)priv + offsetof(struct stmmac_priv,
+                                           xstats.txq_stats[q].tx_pkt_n);
+               for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
+                       *data++ = (*(u64 *)p);
+                       p += sizeof(u64 *);
+               }
+       }
+       for (q = 0; q < rx_cnt; q++) {
+               p = (char *)priv + offsetof(struct stmmac_priv,
+                                           xstats.rxq_stats[q].rx_pkt_n);
+               for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
+                       *data++ = (*(u64 *)p);
+                       p += sizeof(u64 *);
+               }
+       }
+}
+
 static void stmmac_get_ethtool_stats(struct net_device *dev,
                                 struct ethtool_stats *dummy, u64 *data)
 {
                data[j++] = (stmmac_gstrings_stats[i].sizeof_stat ==
                             sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
        }
+       stmmac_get_per_qstats(priv, &data[j]);
 }
 
 static int stmmac_get_sset_count(struct net_device *netdev, int sset)
 {
        struct stmmac_priv *priv = netdev_priv(netdev);
+       u32 tx_cnt = priv->plat->tx_queues_to_use;
+       u32 rx_cnt = priv->plat->rx_queues_to_use;
        int i, len, safety_len = 0;
 
        switch (sset) {
        case ETH_SS_STATS:
-               len = STMMAC_STATS_LEN;
+               len = STMMAC_STATS_LEN +
+                     STMMAC_TXQ_STATS * tx_cnt +
+                     STMMAC_RXQ_STATS * rx_cnt;
 
                if (priv->dma_cap.rmon)
                        len += STMMAC_MMC_STATS_LEN;
        }
 }
 
+static void stmmac_get_qstats_string(struct stmmac_priv *priv, u8 *data)
+{
+       u32 tx_cnt = priv->plat->tx_queues_to_use;
+       u32 rx_cnt = priv->plat->rx_queues_to_use;
+       int q, stat;
+
+       for (q = 0; q < tx_cnt; q++) {
+               for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
+                       snprintf(data, ETH_GSTRING_LEN, "q%d_%s", q,
+                                stmmac_qstats_tx_string[stat]);
+                       data += ETH_GSTRING_LEN;
+               }
+       }
+       for (q = 0; q < rx_cnt; q++) {
+               for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
+                       snprintf(data, ETH_GSTRING_LEN, "q%d_%s", q,
+                                stmmac_qstats_rx_string[stat]);
+                       data += ETH_GSTRING_LEN;
+               }
+       }
+}
+
 static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
        int i;
                                ETH_GSTRING_LEN);
                        p += ETH_GSTRING_LEN;
                }
+               stmmac_get_qstats_string(priv, p);
                break;
        case ETH_SS_TEST:
                stmmac_selftest_get_strings(priv, p);
 
                        } else {
                                priv->dev->stats.tx_packets++;
                                priv->xstats.tx_pkt_n++;
+                               priv->xstats.txq_stats[queue].tx_pkt_n++;
                        }
                        if (skb)
                                stmmac_get_tx_hwtstamp(priv, p, skb);
 
        stmmac_finalize_xdp_rx(priv, xdp_status);
 
+       priv->xstats.rx_pkt_n += count;
+       priv->xstats.rxq_stats[queue].rx_pkt_n += count;
+
        if (xsk_uses_need_wakeup(rx_q->xsk_pool)) {
                if (failure || stmmac_rx_dirty(priv, queue) > 0)
                        xsk_set_rx_need_wakeup(rx_q->xsk_pool);
        stmmac_rx_refill(priv, queue);
 
        priv->xstats.rx_pkt_n += count;
+       priv->xstats.rxq_stats[queue].rx_pkt_n += count;
 
        return count;
 }