Commit 2faf5ad2 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-stmmac-improve-driver-statistics'

Jisheng Zhang says:

====================
net: stmmac: improve driver statistics

improve the stmmac driver statistics:

1. don't clear network driver statistics in .ndo_close() and
.ndo_open() cycle
2. avoid some network driver statistics overflow on 32 bit platforms
3. use per-queue statistics where necessary to remove frequent
cacheline ping pongs.
====================

Link: https://lore.kernel.org/r/20230717160630.1892-1-jszhang@kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 567b12fe 133466c3
...@@ -59,13 +59,25 @@ ...@@ -59,13 +59,25 @@
/* #define FRAME_FILTER_DEBUG */ /* #define FRAME_FILTER_DEBUG */
struct stmmac_txq_stats { struct stmmac_txq_stats {
unsigned long tx_pkt_n; u64 tx_bytes;
unsigned long tx_normal_irq_n; u64 tx_packets;
u64 tx_pkt_n;
u64 tx_normal_irq_n;
u64 napi_poll;
u64 tx_clean;
u64 tx_set_ic_bit;
u64 tx_tso_frames;
u64 tx_tso_nfrags;
struct u64_stats_sync syncp;
}; };
struct stmmac_rxq_stats { struct stmmac_rxq_stats {
unsigned long rx_pkt_n; u64 rx_bytes;
unsigned long rx_normal_irq_n; u64 rx_packets;
u64 rx_pkt_n;
u64 rx_normal_irq_n;
u64 napi_poll;
struct u64_stats_sync syncp;
}; };
/* Extra statistic and debug information exposed by ethtool */ /* Extra statistic and debug information exposed by ethtool */
...@@ -81,6 +93,7 @@ struct stmmac_extra_stats { ...@@ -81,6 +93,7 @@ struct stmmac_extra_stats {
unsigned long tx_frame_flushed; unsigned long tx_frame_flushed;
unsigned long tx_payload_error; unsigned long tx_payload_error;
unsigned long tx_ip_header_error; unsigned long tx_ip_header_error;
unsigned long tx_collision;
/* Receive errors */ /* Receive errors */
unsigned long rx_desc; unsigned long rx_desc;
unsigned long sa_filter_fail; unsigned long sa_filter_fail;
...@@ -113,14 +126,6 @@ struct stmmac_extra_stats { ...@@ -113,14 +126,6 @@ struct stmmac_extra_stats {
/* Tx/Rx IRQ Events */ /* Tx/Rx IRQ Events */
unsigned long rx_early_irq; unsigned long rx_early_irq;
unsigned long threshold; unsigned long threshold;
unsigned long tx_pkt_n;
unsigned long rx_pkt_n;
unsigned long normal_irq_n;
unsigned long rx_normal_irq_n;
unsigned long napi_poll;
unsigned long tx_normal_irq_n;
unsigned long tx_clean;
unsigned long tx_set_ic_bit;
unsigned long irq_receive_pmt_irq_n; unsigned long irq_receive_pmt_irq_n;
/* MMC info */ /* MMC info */
unsigned long mmc_tx_irq_n; unsigned long mmc_tx_irq_n;
...@@ -190,18 +195,16 @@ struct stmmac_extra_stats { ...@@ -190,18 +195,16 @@ struct stmmac_extra_stats {
unsigned long mtl_rx_fifo_ctrl_active; unsigned long mtl_rx_fifo_ctrl_active;
unsigned long mac_rx_frame_ctrl_fifo; unsigned long mac_rx_frame_ctrl_fifo;
unsigned long mac_gmii_rx_proto_engine; unsigned long mac_gmii_rx_proto_engine;
/* TSO */
unsigned long tx_tso_frames;
unsigned long tx_tso_nfrags;
/* EST */ /* EST */
unsigned long mtl_est_cgce; unsigned long mtl_est_cgce;
unsigned long mtl_est_hlbs; unsigned long mtl_est_hlbs;
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 */ unsigned long rx_dropped;
struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; unsigned long rx_errors;
struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; unsigned long tx_dropped;
unsigned long tx_errors;
}; };
/* Safety Feature statistics exposed by ethtool */ /* Safety Feature statistics exposed by ethtool */
......
...@@ -440,8 +440,10 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, ...@@ -440,8 +440,10 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
struct stmmac_extra_stats *x, u32 chan, struct stmmac_extra_stats *x, u32 chan,
u32 dir) u32 dir)
{ {
u32 v; struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
int ret = 0; int ret = 0;
u32 v;
v = readl(ioaddr + EMAC_INT_STA); v = readl(ioaddr + EMAC_INT_STA);
...@@ -452,7 +454,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, ...@@ -452,7 +454,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
if (v & EMAC_TX_INT) { if (v & EMAC_TX_INT) {
ret |= handle_tx; ret |= handle_tx;
x->tx_normal_irq_n++; u64_stats_update_begin(&tx_q->txq_stats.syncp);
tx_q->txq_stats.tx_normal_irq_n++;
u64_stats_update_end(&tx_q->txq_stats.syncp);
} }
if (v & EMAC_TX_DMA_STOP_INT) if (v & EMAC_TX_DMA_STOP_INT)
...@@ -474,7 +478,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, ...@@ -474,7 +478,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
if (v & EMAC_RX_INT) { if (v & EMAC_RX_INT) {
ret |= handle_rx; ret |= handle_rx;
x->rx_normal_irq_n++; u64_stats_update_begin(&rx_q->rxq_stats.syncp);
rx_q->rxq_stats.rx_normal_irq_n++;
u64_stats_update_end(&rx_q->rxq_stats.syncp);
} }
if (v & EMAC_RX_BUF_UA_INT) if (v & EMAC_RX_BUF_UA_INT)
......
...@@ -82,29 +82,24 @@ static void dwmac100_dump_dma_regs(struct stmmac_priv *priv, ...@@ -82,29 +82,24 @@ static void dwmac100_dump_dma_regs(struct stmmac_priv *priv,
} }
/* DMA controller has two counters to track the number of the missed frames. */ /* DMA controller has two counters to track the number of the missed frames. */
static void dwmac100_dma_diagnostic_fr(struct net_device_stats *stats, static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
void __iomem *ioaddr) void __iomem *ioaddr)
{ {
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR); u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
if (unlikely(csr8)) { if (unlikely(csr8)) {
if (csr8 & DMA_MISSED_FRAME_OVE) { if (csr8 & DMA_MISSED_FRAME_OVE) {
stats->rx_over_errors += 0x800;
x->rx_overflow_cntr += 0x800; x->rx_overflow_cntr += 0x800;
} else { } else {
unsigned int ove_cntr; unsigned int ove_cntr;
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17); ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
stats->rx_over_errors += ove_cntr;
x->rx_overflow_cntr += ove_cntr; x->rx_overflow_cntr += ove_cntr;
} }
if (csr8 & DMA_MISSED_FRAME_OVE_M) { if (csr8 & DMA_MISSED_FRAME_OVE_M) {
stats->rx_missed_errors += 0xffff;
x->rx_missed_cntr += 0xffff; x->rx_missed_cntr += 0xffff;
} else { } else {
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR); unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
stats->rx_missed_errors += miss_f;
x->rx_missed_cntr += miss_f; x->rx_missed_cntr += miss_f;
} }
} }
......
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
#include "dwmac4.h" #include "dwmac4.h"
#include "dwmac4_descs.h" #include "dwmac4_descs.h"
static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats, static int dwmac4_wrback_get_tx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p, struct dma_desc *p,
void __iomem *ioaddr) void __iomem *ioaddr)
{ {
...@@ -40,15 +39,13 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats, ...@@ -40,15 +39,13 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
x->tx_frame_flushed++; x->tx_frame_flushed++;
if (unlikely(tdes3 & TDES3_LOSS_CARRIER)) { if (unlikely(tdes3 & TDES3_LOSS_CARRIER)) {
x->tx_losscarrier++; x->tx_losscarrier++;
stats->tx_carrier_errors++;
} }
if (unlikely(tdes3 & TDES3_NO_CARRIER)) { if (unlikely(tdes3 & TDES3_NO_CARRIER)) {
x->tx_carrier++; x->tx_carrier++;
stats->tx_carrier_errors++;
} }
if (unlikely((tdes3 & TDES3_LATE_COLLISION) || if (unlikely((tdes3 & TDES3_LATE_COLLISION) ||
(tdes3 & TDES3_EXCESSIVE_COLLISION))) (tdes3 & TDES3_EXCESSIVE_COLLISION)))
stats->collisions += x->tx_collision +=
(tdes3 & TDES3_COLLISION_COUNT_MASK) (tdes3 & TDES3_COLLISION_COUNT_MASK)
>> TDES3_COLLISION_COUNT_SHIFT; >> TDES3_COLLISION_COUNT_SHIFT;
...@@ -73,8 +70,7 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats, ...@@ -73,8 +70,7 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
return ret; return ret;
} }
static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats, static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p) struct dma_desc *p)
{ {
unsigned int rdes1 = le32_to_cpu(p->des1); unsigned int rdes1 = le32_to_cpu(p->des1);
...@@ -93,7 +89,7 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats, ...@@ -93,7 +89,7 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) { if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) {
if (unlikely(rdes3 & RDES3_GIANT_PACKET)) if (unlikely(rdes3 & RDES3_GIANT_PACKET))
stats->rx_length_errors++; x->rx_length++;
if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR)) if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR))
x->rx_gmac_overflow++; x->rx_gmac_overflow++;
...@@ -103,10 +99,8 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats, ...@@ -103,10 +99,8 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
if (unlikely(rdes3 & RDES3_RECEIVE_ERROR)) if (unlikely(rdes3 & RDES3_RECEIVE_ERROR))
x->rx_mii++; x->rx_mii++;
if (unlikely(rdes3 & RDES3_CRC_ERROR)) { if (unlikely(rdes3 & RDES3_CRC_ERROR))
x->rx_crc_errors++; x->rx_crc_errors++;
stats->rx_crc_errors++;
}
if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR)) if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR))
x->dribbling_bit++; x->dribbling_bit++;
......
...@@ -171,6 +171,8 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, ...@@ -171,6 +171,8 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan)); u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
int ret = 0; int ret = 0;
if (dir == DMA_DIR_RX) if (dir == DMA_DIR_RX)
...@@ -198,18 +200,19 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, ...@@ -198,18 +200,19 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
} }
} }
/* TX/RX NORMAL interrupts */ /* TX/RX NORMAL interrupts */
if (likely(intr_status & DMA_CHAN_STATUS_NIS))
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++; u64_stats_update_begin(&rx_q->rxq_stats.syncp);
x->rxq_stats[chan].rx_normal_irq_n++; rx_q->rxq_stats.rx_normal_irq_n++;
u64_stats_update_end(&rx_q->rxq_stats.syncp);
ret |= handle_rx; ret |= handle_rx;
} }
if (likely(intr_status & DMA_CHAN_STATUS_TI)) { if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
x->tx_normal_irq_n++; u64_stats_update_begin(&tx_q->txq_stats.syncp);
x->txq_stats[chan].tx_normal_irq_n++; tx_q->txq_stats.tx_normal_irq_n++;
u64_stats_update_end(&tx_q->txq_stats.syncp);
ret |= handle_tx; ret |= handle_tx;
} }
if (unlikely(intr_status & DMA_CHAN_STATUS_TBU)) if (unlikely(intr_status & DMA_CHAN_STATUS_TBU))
ret |= handle_tx; ret |= handle_tx;
if (unlikely(intr_status & DMA_CHAN_STATUS_ERI)) if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include "common.h" #include "common.h"
#include "dwmac_dma.h" #include "dwmac_dma.h"
#include "stmmac.h"
#define GMAC_HI_REG_AE 0x80000000 #define GMAC_HI_REG_AE 0x80000000
...@@ -161,6 +162,8 @@ static void show_rx_process_state(unsigned int status) ...@@ -161,6 +162,8 @@ static void show_rx_process_state(unsigned int status)
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir) struct stmmac_extra_stats *x, u32 chan, u32 dir)
{ {
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
int ret = 0; int ret = 0;
/* read the status register (CSR5) */ /* read the status register (CSR5) */
u32 intr_status = readl(ioaddr + DMA_STATUS); u32 intr_status = readl(ioaddr + DMA_STATUS);
...@@ -208,17 +211,20 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, ...@@ -208,17 +211,20 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
} }
/* TX/RX NORMAL interrupts */ /* TX/RX NORMAL interrupts */
if (likely(intr_status & DMA_STATUS_NIS)) { if (likely(intr_status & DMA_STATUS_NIS)) {
x->normal_irq_n++;
if (likely(intr_status & DMA_STATUS_RI)) { if (likely(intr_status & DMA_STATUS_RI)) {
u32 value = readl(ioaddr + DMA_INTR_ENA); u32 value = readl(ioaddr + DMA_INTR_ENA);
/* to schedule NAPI on real RIE event. */ /* to schedule NAPI on real RIE event. */
if (likely(value & DMA_INTR_ENA_RIE)) { if (likely(value & DMA_INTR_ENA_RIE)) {
x->rx_normal_irq_n++; u64_stats_update_begin(&rx_q->rxq_stats.syncp);
rx_q->rxq_stats.rx_normal_irq_n++;
u64_stats_update_end(&rx_q->rxq_stats.syncp);
ret |= handle_rx; ret |= handle_rx;
} }
} }
if (likely(intr_status & DMA_STATUS_TI)) { if (likely(intr_status & DMA_STATUS_TI)) {
x->tx_normal_irq_n++; u64_stats_update_begin(&tx_q->txq_stats.syncp);
tx_q->txq_stats.tx_normal_irq_n++;
u64_stats_update_end(&tx_q->txq_stats.syncp);
ret |= handle_tx; ret |= handle_tx;
} }
if (unlikely(intr_status & DMA_STATUS_ERI)) if (unlikely(intr_status & DMA_STATUS_ERI))
......
...@@ -8,8 +8,7 @@ ...@@ -8,8 +8,7 @@
#include "common.h" #include "common.h"
#include "dwxgmac2.h" #include "dwxgmac2.h"
static int dwxgmac2_get_tx_status(struct net_device_stats *stats, static int dwxgmac2_get_tx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr) struct dma_desc *p, void __iomem *ioaddr)
{ {
unsigned int tdes3 = le32_to_cpu(p->des3); unsigned int tdes3 = le32_to_cpu(p->des3);
...@@ -23,8 +22,7 @@ static int dwxgmac2_get_tx_status(struct net_device_stats *stats, ...@@ -23,8 +22,7 @@ static int dwxgmac2_get_tx_status(struct net_device_stats *stats,
return ret; return ret;
} }
static int dwxgmac2_get_rx_status(struct net_device_stats *stats, static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p) struct dma_desc *p)
{ {
unsigned int rdes3 = le32_to_cpu(p->des3); unsigned int rdes3 = le32_to_cpu(p->des3);
......
...@@ -337,6 +337,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, ...@@ -337,6 +337,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
struct stmmac_extra_stats *x, u32 chan, struct stmmac_extra_stats *x, u32 chan,
u32 dir) u32 dir)
{ {
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan)); u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
int ret = 0; int ret = 0;
...@@ -364,16 +366,16 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, ...@@ -364,16 +366,16 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
/* TX/RX NORMAL interrupts */ /* TX/RX NORMAL interrupts */
if (likely(intr_status & XGMAC_NIS)) { if (likely(intr_status & XGMAC_NIS)) {
x->normal_irq_n++;
if (likely(intr_status & XGMAC_RI)) { if (likely(intr_status & XGMAC_RI)) {
x->rx_normal_irq_n++; u64_stats_update_begin(&rx_q->rxq_stats.syncp);
x->rxq_stats[chan].rx_normal_irq_n++; rx_q->rxq_stats.rx_normal_irq_n++;
u64_stats_update_end(&rx_q->rxq_stats.syncp);
ret |= handle_rx; ret |= handle_rx;
} }
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
x->tx_normal_irq_n++; u64_stats_update_begin(&tx_q->txq_stats.syncp);
x->txq_stats[chan].tx_normal_irq_n++; tx_q->txq_stats.tx_normal_irq_n++;
u64_stats_update_end(&tx_q->txq_stats.syncp);
ret |= handle_tx; ret |= handle_tx;
} }
} }
......
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
#include "common.h" #include "common.h"
#include "descs_com.h" #include "descs_com.h"
static int enh_desc_get_tx_status(struct net_device_stats *stats, static int enh_desc_get_tx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr) struct dma_desc *p, void __iomem *ioaddr)
{ {
unsigned int tdes0 = le32_to_cpu(p->des0); unsigned int tdes0 = le32_to_cpu(p->des0);
...@@ -38,15 +37,13 @@ static int enh_desc_get_tx_status(struct net_device_stats *stats, ...@@ -38,15 +37,13 @@ static int enh_desc_get_tx_status(struct net_device_stats *stats,
if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) { if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) {
x->tx_losscarrier++; x->tx_losscarrier++;
stats->tx_carrier_errors++;
} }
if (unlikely(tdes0 & ETDES0_NO_CARRIER)) { if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
x->tx_carrier++; x->tx_carrier++;
stats->tx_carrier_errors++;
} }
if (unlikely((tdes0 & ETDES0_LATE_COLLISION) || if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
(tdes0 & ETDES0_EXCESSIVE_COLLISIONS))) (tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
stats->collisions += x->tx_collision +=
(tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3; (tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3;
if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL)) if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL))
...@@ -117,8 +114,7 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err) ...@@ -117,8 +114,7 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
return ret; return ret;
} }
static void enh_desc_get_ext_status(struct net_device_stats *stats, static void enh_desc_get_ext_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_extended_desc *p) struct dma_extended_desc *p)
{ {
unsigned int rdes0 = le32_to_cpu(p->basic.des0); unsigned int rdes0 = le32_to_cpu(p->basic.des0);
...@@ -182,8 +178,7 @@ static void enh_desc_get_ext_status(struct net_device_stats *stats, ...@@ -182,8 +178,7 @@ static void enh_desc_get_ext_status(struct net_device_stats *stats,
} }
} }
static int enh_desc_get_rx_status(struct net_device_stats *stats, static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p) struct dma_desc *p)
{ {
unsigned int rdes0 = le32_to_cpu(p->des0); unsigned int rdes0 = le32_to_cpu(p->des0);
...@@ -193,14 +188,14 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats, ...@@ -193,14 +188,14 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats,
return dma_own; return dma_own;
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
stats->rx_length_errors++; x->rx_length++;
return discard_frame; return discard_frame;
} }
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) { if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) { if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
x->rx_desc++; x->rx_desc++;
stats->rx_length_errors++; x->rx_length++;
} }
if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR)) if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
x->rx_gmac_overflow++; x->rx_gmac_overflow++;
...@@ -209,7 +204,7 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats, ...@@ -209,7 +204,7 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats,
pr_err("\tIPC Csum Error/Giant frame\n"); pr_err("\tIPC Csum Error/Giant frame\n");
if (unlikely(rdes0 & RDES0_COLLISION)) if (unlikely(rdes0 & RDES0_COLLISION))
stats->collisions++; x->rx_collision++;
if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG)) if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
x->rx_watchdog++; x->rx_watchdog++;
...@@ -218,7 +213,6 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats, ...@@ -218,7 +213,6 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats,
if (unlikely(rdes0 & RDES0_CRC_ERROR)) { if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++; x->rx_crc_errors++;
stats->rx_crc_errors++;
} }
ret = discard_frame; ret = discard_frame;
} }
......
...@@ -57,8 +57,7 @@ struct stmmac_desc_ops { ...@@ -57,8 +57,7 @@ struct stmmac_desc_ops {
/* Last tx segment reports the transmit status */ /* Last tx segment reports the transmit status */
int (*get_tx_ls)(struct dma_desc *p); int (*get_tx_ls)(struct dma_desc *p);
/* Return the transmit status looking at the TDES1 */ /* Return the transmit status looking at the TDES1 */
int (*tx_status)(struct net_device_stats *stats, int (*tx_status)(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr); struct dma_desc *p, void __iomem *ioaddr);
/* Get the buffer size from the descriptor */ /* Get the buffer size from the descriptor */
int (*get_tx_len)(struct dma_desc *p); int (*get_tx_len)(struct dma_desc *p);
...@@ -67,11 +66,9 @@ struct stmmac_desc_ops { ...@@ -67,11 +66,9 @@ struct stmmac_desc_ops {
/* Get the receive frame size */ /* Get the receive frame size */
int (*get_rx_frame_len)(struct dma_desc *p, int rx_coe_type); int (*get_rx_frame_len)(struct dma_desc *p, int rx_coe_type);
/* Return the reception status looking at the RDES1 */ /* Return the reception status looking at the RDES1 */
int (*rx_status)(struct net_device_stats *stats, int (*rx_status)(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p); struct dma_desc *p);
void (*rx_extended_status)(struct net_device_stats *stats, void (*rx_extended_status)(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_extended_desc *p); struct dma_extended_desc *p);
/* Set tx timestamp enable bit */ /* Set tx timestamp enable bit */
void (*enable_tx_timestamp) (struct dma_desc *p); void (*enable_tx_timestamp) (struct dma_desc *p);
...@@ -191,8 +188,7 @@ struct stmmac_dma_ops { ...@@ -191,8 +188,7 @@ struct stmmac_dma_ops {
void (*dma_tx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr, void (*dma_tx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
int mode, u32 channel, int fifosz, u8 qmode); int mode, u32 channel, int fifosz, u8 qmode);
/* To track extra statistic (if supported) */ /* To track extra statistic (if supported) */
void (*dma_diagnostic_fr)(struct net_device_stats *stats, void (*dma_diagnostic_fr)(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
void __iomem *ioaddr); void __iomem *ioaddr);
void (*enable_dma_transmission) (void __iomem *ioaddr); void (*enable_dma_transmission) (void __iomem *ioaddr);
void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr, void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
......
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
#include "common.h" #include "common.h"
#include "descs_com.h" #include "descs_com.h"
static int ndesc_get_tx_status(struct net_device_stats *stats, static int ndesc_get_tx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr) struct dma_desc *p, void __iomem *ioaddr)
{ {
unsigned int tdes0 = le32_to_cpu(p->des0); unsigned int tdes0 = le32_to_cpu(p->des0);
...@@ -31,15 +30,12 @@ static int ndesc_get_tx_status(struct net_device_stats *stats, ...@@ -31,15 +30,12 @@ static int ndesc_get_tx_status(struct net_device_stats *stats,
if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) { if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) { if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
x->tx_underflow++; x->tx_underflow++;
stats->tx_fifo_errors++;
} }
if (unlikely(tdes0 & TDES0_NO_CARRIER)) { if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
x->tx_carrier++; x->tx_carrier++;
stats->tx_carrier_errors++;
} }
if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) { if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
x->tx_losscarrier++; x->tx_losscarrier++;
stats->tx_carrier_errors++;
} }
if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) || if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
(tdes0 & TDES0_EXCESSIVE_COLLISIONS) || (tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
...@@ -47,7 +43,7 @@ static int ndesc_get_tx_status(struct net_device_stats *stats, ...@@ -47,7 +43,7 @@ static int ndesc_get_tx_status(struct net_device_stats *stats,
unsigned int collisions; unsigned int collisions;
collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3; collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
stats->collisions += collisions; x->tx_collision += collisions;
} }
ret = tx_err; ret = tx_err;
} }
...@@ -70,8 +66,7 @@ static int ndesc_get_tx_len(struct dma_desc *p) ...@@ -70,8 +66,7 @@ static int ndesc_get_tx_len(struct dma_desc *p)
* and, if required, updates the multicast statistics. * and, if required, updates the multicast statistics.
* In case of success, it returns good_frame because the GMAC device * In case of success, it returns good_frame because the GMAC device
* is supposed to be able to compute the csum in HW. */ * is supposed to be able to compute the csum in HW. */
static int ndesc_get_rx_status(struct net_device_stats *stats, static int ndesc_get_rx_status(struct stmmac_extra_stats *x,
struct stmmac_extra_stats *x,
struct dma_desc *p) struct dma_desc *p)
{ {
int ret = good_frame; int ret = good_frame;
...@@ -81,7 +76,7 @@ static int ndesc_get_rx_status(struct net_device_stats *stats, ...@@ -81,7 +76,7 @@ static int ndesc_get_rx_status(struct net_device_stats *stats,
return dma_own; return dma_own;
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
stats->rx_length_errors++; x->rx_length++;
return discard_frame; return discard_frame;
} }
...@@ -96,11 +91,9 @@ static int ndesc_get_rx_status(struct net_device_stats *stats, ...@@ -96,11 +91,9 @@ static int ndesc_get_rx_status(struct net_device_stats *stats,
x->ipc_csum_error++; x->ipc_csum_error++;
if (unlikely(rdes0 & RDES0_COLLISION)) { if (unlikely(rdes0 & RDES0_COLLISION)) {
x->rx_collision++; x->rx_collision++;
stats->collisions++;
} }
if (unlikely(rdes0 & RDES0_CRC_ERROR)) { if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++; x->rx_crc_errors++;
stats->rx_crc_errors++;
} }
ret = discard_frame; ret = discard_frame;
} }
......
...@@ -77,6 +77,7 @@ struct stmmac_tx_queue { ...@@ -77,6 +77,7 @@ struct stmmac_tx_queue {
dma_addr_t dma_tx_phy; dma_addr_t dma_tx_phy;
dma_addr_t tx_tail_addr; dma_addr_t tx_tail_addr;
u32 mss; u32 mss;
struct stmmac_txq_stats txq_stats;
}; };
struct stmmac_rx_buffer { struct stmmac_rx_buffer {
...@@ -121,6 +122,7 @@ struct stmmac_rx_queue { ...@@ -121,6 +122,7 @@ struct stmmac_rx_queue {
unsigned int len; unsigned int len;
unsigned int error; unsigned int error;
} state; } state;
struct stmmac_rxq_stats rxq_stats;
}; };
struct stmmac_channel { struct stmmac_channel {
......
...@@ -89,14 +89,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { ...@@ -89,14 +89,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
/* Tx/Rx IRQ Events */ /* Tx/Rx IRQ Events */
STMMAC_STAT(rx_early_irq), STMMAC_STAT(rx_early_irq),
STMMAC_STAT(threshold), STMMAC_STAT(threshold),
STMMAC_STAT(tx_pkt_n),
STMMAC_STAT(rx_pkt_n),
STMMAC_STAT(normal_irq_n),
STMMAC_STAT(rx_normal_irq_n),
STMMAC_STAT(napi_poll),
STMMAC_STAT(tx_normal_irq_n),
STMMAC_STAT(tx_clean),
STMMAC_STAT(tx_set_ic_bit),
STMMAC_STAT(irq_receive_pmt_irq_n), STMMAC_STAT(irq_receive_pmt_irq_n),
/* MMC info */ /* MMC info */
STMMAC_STAT(mmc_tx_irq_n), STMMAC_STAT(mmc_tx_irq_n),
...@@ -163,9 +155,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { ...@@ -163,9 +155,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(mtl_rx_fifo_ctrl_active), STMMAC_STAT(mtl_rx_fifo_ctrl_active),
STMMAC_STAT(mac_rx_frame_ctrl_fifo), STMMAC_STAT(mac_rx_frame_ctrl_fifo),
STMMAC_STAT(mac_gmii_rx_proto_engine), STMMAC_STAT(mac_gmii_rx_proto_engine),
/* TSO */
STMMAC_STAT(tx_tso_frames),
STMMAC_STAT(tx_tso_nfrags),
/* EST */ /* EST */
STMMAC_STAT(mtl_est_cgce), STMMAC_STAT(mtl_est_cgce),
STMMAC_STAT(mtl_est_hlbs), STMMAC_STAT(mtl_est_hlbs),
...@@ -175,6 +164,23 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { ...@@ -175,6 +164,23 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
}; };
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) #define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
/* statistics collected in queue which will be summed up for all TX or RX
* queues, or summed up for both TX and RX queues(napi_poll, normal_irq_n).
*/
static const char stmmac_qstats_string[][ETH_GSTRING_LEN] = {
"rx_pkt_n",
"rx_normal_irq_n",
"tx_pkt_n",
"tx_normal_irq_n",
"tx_clean",
"tx_set_ic_bit",
"tx_tso_frames",
"tx_tso_nfrags",
"normal_irq_n",
"napi_poll",
};
#define STMMAC_QSTATS ARRAY_SIZE(stmmac_qstats_string)
/* HW MAC Management counters (if supported) */ /* HW MAC Management counters (if supported) */
#define STMMAC_MMC_STAT(m) \ #define STMMAC_MMC_STAT(m) \
{ #m, sizeof_field(struct stmmac_counters, m), \ { #m, sizeof_field(struct stmmac_counters, m), \
...@@ -535,23 +541,44 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data) ...@@ -535,23 +541,44 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
{ {
u32 tx_cnt = priv->plat->tx_queues_to_use; u32 tx_cnt = priv->plat->tx_queues_to_use;
u32 rx_cnt = priv->plat->rx_queues_to_use; u32 rx_cnt = priv->plat->rx_queues_to_use;
unsigned int start;
int q, stat; int q, stat;
u64 *pos;
char *p; char *p;
pos = data;
for (q = 0; q < tx_cnt; q++) { for (q = 0; q < tx_cnt; q++) {
p = (char *)priv + offsetof(struct stmmac_priv, struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[q];
xstats.txq_stats[q].tx_pkt_n); struct stmmac_txq_stats snapshot;
data = pos;
do {
start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp);
snapshot = tx_q->txq_stats;
} while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start));
p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n);
for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) { for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
*data++ = (*(unsigned long *)p); *data++ += (*(u64 *)p);
p += sizeof(unsigned long); p += sizeof(u64);
} }
} }
pos = data;
for (q = 0; q < rx_cnt; q++) { for (q = 0; q < rx_cnt; q++) {
p = (char *)priv + offsetof(struct stmmac_priv, struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[q];
xstats.rxq_stats[q].rx_pkt_n); struct stmmac_rxq_stats snapshot;
data = pos;
do {
start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp);
snapshot = rx_q->rxq_stats;
} while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start));
p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n);
for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) { for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
*data++ = (*(unsigned long *)p); *data++ += (*(u64 *)p);
p += sizeof(unsigned long); p += sizeof(u64);
} }
} }
} }
...@@ -562,8 +589,10 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, ...@@ -562,8 +589,10 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
u32 rx_queues_count = priv->plat->rx_queues_to_use; u32 rx_queues_count = priv->plat->rx_queues_to_use;
u32 tx_queues_count = priv->plat->tx_queues_to_use; u32 tx_queues_count = priv->plat->tx_queues_to_use;
u64 napi_poll = 0, normal_irq_n = 0;
int i, j = 0, pos, ret;
unsigned long count; unsigned long count;
int i, j = 0, ret; unsigned int start;
if (priv->dma_cap.asp) { if (priv->dma_cap.asp) {
for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) { for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) {
...@@ -574,8 +603,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, ...@@ -574,8 +603,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
} }
/* Update the DMA HW counters for dwmac10/100 */ /* Update the DMA HW counters for dwmac10/100 */
ret = stmmac_dma_diagnostic_fr(priv, &dev->stats, (void *) &priv->xstats, ret = stmmac_dma_diagnostic_fr(priv, &priv->xstats, priv->ioaddr);
priv->ioaddr);
if (ret) { if (ret) {
/* If supported, for new GMAC chips expose the MMC counters */ /* If supported, for new GMAC chips expose the MMC counters */
if (priv->dma_cap.rmon) { if (priv->dma_cap.rmon) {
...@@ -606,6 +634,48 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, ...@@ -606,6 +634,48 @@ 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);
} }
pos = j;
for (i = 0; i < rx_queues_count; i++) {
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[i];
struct stmmac_rxq_stats snapshot;
j = pos;
do {
start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp);
snapshot = rx_q->rxq_stats;
} while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start));
data[j++] += snapshot.rx_pkt_n;
data[j++] += snapshot.rx_normal_irq_n;
normal_irq_n += snapshot.rx_normal_irq_n;
napi_poll += snapshot.napi_poll;
}
pos = j;
for (i = 0; i < tx_queues_count; i++) {
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[i];
struct stmmac_txq_stats snapshot;
j = pos;
do {
start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp);
snapshot = tx_q->txq_stats;
} while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start));
data[j++] += snapshot.tx_pkt_n;
data[j++] += snapshot.tx_normal_irq_n;
normal_irq_n += snapshot.tx_normal_irq_n;
data[j++] += snapshot.tx_clean;
data[j++] += snapshot.tx_set_ic_bit;
data[j++] += snapshot.tx_tso_frames;
data[j++] += snapshot.tx_tso_nfrags;
napi_poll += snapshot.napi_poll;
}
normal_irq_n += priv->xstats.rx_early_irq;
data[j++] = normal_irq_n;
data[j++] = napi_poll;
stmmac_get_per_qstats(priv, &data[j]); stmmac_get_per_qstats(priv, &data[j]);
} }
...@@ -618,7 +688,7 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset) ...@@ -618,7 +688,7 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset)
switch (sset) { switch (sset) {
case ETH_SS_STATS: case ETH_SS_STATS:
len = STMMAC_STATS_LEN + len = STMMAC_STATS_LEN + STMMAC_QSTATS +
STMMAC_TXQ_STATS * tx_cnt + STMMAC_TXQ_STATS * tx_cnt +
STMMAC_RXQ_STATS * rx_cnt; STMMAC_RXQ_STATS * rx_cnt;
...@@ -691,8 +761,11 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) ...@@ -691,8 +761,11 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
for (i = 0; i < STMMAC_STATS_LEN; i++) { for (i = 0; i < STMMAC_STATS_LEN; i++) {
memcpy(p, stmmac_gstrings_stats[i].stat_string, memcpy(p, stmmac_gstrings_stats[i].stat_string, ETH_GSTRING_LEN);
ETH_GSTRING_LEN); p += ETH_GSTRING_LEN;
}
for (i = 0; i < STMMAC_QSTATS; i++) {
memcpy(p, stmmac_qstats_string[i], ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
stmmac_get_qstats_string(priv, p); stmmac_get_qstats_string(priv, p);
......
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