Commit 23a44b77 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 022522ac af9bf701
...@@ -58,6 +58,16 @@ ...@@ -58,6 +58,16 @@
#undef FRAME_FILTER_DEBUG #undef FRAME_FILTER_DEBUG
/* #define 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 */ /* Extra statistic and debug information exposed by ethtool */
struct stmmac_extra_stats { struct stmmac_extra_stats {
/* Transmit errors */ /* Transmit errors */
...@@ -189,6 +199,9 @@ struct stmmac_extra_stats { ...@@ -189,6 +199,9 @@ struct stmmac_extra_stats {
unsigned long mtl_est_hlbf; unsigned long mtl_est_hlbf;
unsigned long mtl_est_btre; unsigned long mtl_est_btre;
unsigned long mtl_est_btrlm; 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 */ /* Safety Feature statistics exposed by ethtool */
......
...@@ -170,13 +170,16 @@ int dwmac4_dma_interrupt(void __iomem *ioaddr, ...@@ -170,13 +170,16 @@ int dwmac4_dma_interrupt(void __iomem *ioaddr,
x->normal_irq_n++; x->normal_irq_n++;
if (likely(intr_status & DMA_CHAN_STATUS_RI)) { if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
x->rx_normal_irq_n++; x->rx_normal_irq_n++;
x->rxq_stats[chan].rx_normal_irq_n++;
ret |= handle_rx; ret |= handle_rx;
} }
if (likely(intr_status & (DMA_CHAN_STATUS_TI | if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
DMA_CHAN_STATUS_TBU))) {
x->tx_normal_irq_n++; x->tx_normal_irq_n++;
x->txq_stats[chan].tx_normal_irq_n++;
ret |= handle_tx; ret |= handle_tx;
} }
if (unlikely(intr_status & DMA_CHAN_STATUS_TBU))
ret |= handle_tx;
if (unlikely(intr_status & DMA_CHAN_STATUS_ERI)) if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
x->rx_early_irq++; x->rx_early_irq++;
......
...@@ -261,6 +261,18 @@ static const struct stmmac_stats stmmac_mmc[] = { ...@@ -261,6 +261,18 @@ static const struct stmmac_stats stmmac_mmc[] = {
}; };
#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(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, static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info) struct ethtool_drvinfo *info)
{ {
...@@ -510,6 +522,31 @@ stmmac_set_pauseparam(struct net_device *netdev, ...@@ -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, static void stmmac_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *dummy, u64 *data) struct ethtool_stats *dummy, u64 *data)
{ {
...@@ -560,16 +597,21 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, ...@@ -560,16 +597,21 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
data[j++] = (stmmac_gstrings_stats[i].sizeof_stat == data[j++] = (stmmac_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); 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) static int stmmac_get_sset_count(struct net_device *netdev, int sset)
{ {
struct stmmac_priv *priv = netdev_priv(netdev); 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; int i, len, safety_len = 0;
switch (sset) { switch (sset) {
case ETH_SS_STATS: 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) if (priv->dma_cap.rmon)
len += STMMAC_MMC_STATS_LEN; len += STMMAC_MMC_STATS_LEN;
...@@ -592,6 +634,28 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset) ...@@ -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) static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{ {
int i; int i;
...@@ -622,6 +686,7 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) ...@@ -622,6 +686,7 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
stmmac_get_qstats_string(priv, p);
break; break;
case ETH_SS_TEST: case ETH_SS_TEST:
stmmac_selftest_get_strings(priv, p); stmmac_selftest_get_strings(priv, p);
......
...@@ -2500,6 +2500,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) ...@@ -2500,6 +2500,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
} else { } else {
priv->dev->stats.tx_packets++; priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++; priv->xstats.tx_pkt_n++;
priv->xstats.txq_stats[queue].tx_pkt_n++;
} }
if (skb) if (skb)
stmmac_get_tx_hwtstamp(priv, p, skb); stmmac_get_tx_hwtstamp(priv, p, skb);
...@@ -5000,6 +5001,9 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -5000,6 +5001,9 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_finalize_xdp_rx(priv, xdp_status); 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 (xsk_uses_need_wakeup(rx_q->xsk_pool)) {
if (failure || stmmac_rx_dirty(priv, queue) > 0) if (failure || stmmac_rx_dirty(priv, queue) > 0)
xsk_set_rx_need_wakeup(rx_q->xsk_pool); xsk_set_rx_need_wakeup(rx_q->xsk_pool);
...@@ -5287,6 +5291,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -5287,6 +5291,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_rx_refill(priv, queue); stmmac_rx_refill(priv, queue);
priv->xstats.rx_pkt_n += count; priv->xstats.rx_pkt_n += count;
priv->xstats.rxq_stats[queue].rx_pkt_n += count;
return count; return count;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment