Merge branch 'stmmac-per-queue-stats'
Vijayakannan Ayyathurai says: ==================== net: stmmac: Add ethtool per-queue statistic Adding generic ethtool per-queue statistic framework to display the statistics for each rx/tx queue. In future, users can avail it to add more per-queue specific counters. Number of rx/tx queues displayed is depending on the available rx/tx queues in that particular MAC config and this number is limited up to the MTL_MAX_{RX|TX}_QUEUES defined in the driver. Ethtool per-queue statistic display will look like below, when users start adding more counters. Example - 1: q0_tx_statA: q0_tx_statB: q0_tx_statC: | q0_tx_statX: . . . qMAX_tx_statA: qMAX_tx_statB: qMAX_tx_statC: | qMAX_tx_statX: q0_rx_statA: q0_rx_statB: q0_rx_statC: | q0_rx_statX: . . . qMAX_rx_statA: qMAX_rx_statB: qMAX_rx_statC: | qMAX_rx_statX: Example - 2: Ping test using the tx queue 3. $ tc qdisc add dev enp0s30f4 root mqprio num_tc 2 map 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 queues 3@0 1@3 hw 0 Statistic before ping: --------------------- $ ethtool -S enp0s30f4 [ snip ] q3_tx_pkt_n: 7916 q3_tx_irq_n: 316 [ snip ] $ cat /proc/interrupts [ snip ] 143: 0 0 0 316 0 0 0 0 IR-PCI-MSI 499719-edge enp0s30f4:tx-3 [ snip ] $ ping -I enp0s30f4 192.168.1.10 -i 0.01 -c 100 > /dev/null Statistic after ping: --------------------- $ ethtool -S enp0s30f4 [ snip ] q3_tx_pkt_n: 8016 q3_tx_irq_n: 320 [ snip ] $ cat /proc/interrupts [ snip ] 143: 0 0 0 320 0 0 0 0 IR-PCI-MSI 499719-edge enp0s30f4:tx-3 [ snip ] ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
23a44b77e0
@ -58,6 +58,16 @@
|
||||
#undef FRAME_FILTER_DEBUG
|
||||
/* #define FRAME_FILTER_DEBUG */
|
||||
|
||||
struct stmmac_txq_stats {
|
||||
unsigned long tx_pkt_n;
|
||||
unsigned long tx_normal_irq_n;
|
||||
};
|
||||
|
||||
struct stmmac_rxq_stats {
|
||||
unsigned long rx_pkt_n;
|
||||
unsigned long rx_normal_irq_n;
|
||||
};
|
||||
|
||||
/* Extra statistic and debug information exposed by ethtool */
|
||||
struct stmmac_extra_stats {
|
||||
/* Transmit errors */
|
||||
@ -189,6 +199,9 @@ struct stmmac_extra_stats {
|
||||
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 */
|
||||
|
@ -170,13 +170,16 @@ int dwmac4_dma_interrupt(void __iomem *ioaddr,
|
||||
x->normal_irq_n++;
|
||||
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
|
||||
x->rx_normal_irq_n++;
|
||||
x->rxq_stats[chan].rx_normal_irq_n++;
|
||||
ret |= handle_rx;
|
||||
}
|
||||
if (likely(intr_status & (DMA_CHAN_STATUS_TI |
|
||||
DMA_CHAN_STATUS_TBU))) {
|
||||
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
|
||||
x->tx_normal_irq_n++;
|
||||
x->txq_stats[chan].tx_normal_irq_n++;
|
||||
ret |= handle_tx;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_TBU))
|
||||
ret |= handle_tx;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
|
||||
x->rx_early_irq++;
|
||||
|
||||
|
@ -261,6 +261,18 @@ static const struct stmmac_stats stmmac_mmc[] = {
|
||||
};
|
||||
#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc)
|
||||
|
||||
static const char stmmac_qstats_tx_string[][ETH_GSTRING_LEN] = {
|
||||
"tx_pkt_n",
|
||||
"tx_irq_n",
|
||||
#define STMMAC_TXQ_STATS ARRAY_SIZE(stmmac_qstats_tx_string)
|
||||
};
|
||||
|
||||
static const char stmmac_qstats_rx_string[][ETH_GSTRING_LEN] = {
|
||||
"rx_pkt_n",
|
||||
"rx_irq_n",
|
||||
#define STMMAC_RXQ_STATS ARRAY_SIZE(stmmac_qstats_rx_string)
|
||||
};
|
||||
|
||||
static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
@ -510,6 +522,31 @@ stmmac_set_pauseparam(struct net_device *netdev,
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -560,16 +597,21 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
|
||||
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;
|
||||
@ -592,6 +634,28 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -622,6 +686,7 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
|
||||
ETH_GSTRING_LEN);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
stmmac_get_qstats_string(priv, p);
|
||||
break;
|
||||
case ETH_SS_TEST:
|
||||
stmmac_selftest_get_strings(priv, p);
|
||||
|
@ -2500,6 +2500,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
|
||||
} 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);
|
||||
@ -5000,6 +5001,9 @@ read_again:
|
||||
|
||||
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);
|
||||
@ -5287,6 +5291,7 @@ drain_data:
|
||||
stmmac_rx_refill(priv, queue);
|
||||
|
||||
priv->xstats.rx_pkt_n += count;
|
||||
priv->xstats.rxq_stats[queue].rx_pkt_n += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user