Skip to content

Commit 133466c

Browse files
xhackerustckuba-moo
authored andcommitted
net: stmmac: use per-queue 64 bit statistics where necessary
Currently, there are two major issues with stmmac driver statistics First of all, statistics in stmmac_extra_stats, stmmac_rxq_stats and stmmac_txq_stats are 32 bit variables on 32 bit platforms. This can cause some stats to overflow after several minutes of high traffic, for example rx_pkt_n, tx_pkt_n and so on. Secondly, if HW supports multiqueues, there are frequent cacheline ping pongs on some driver statistic vars, for example, normal_irq_n, tx_pkt_n and so on. What's more, frequent cacheline ping pongs on normal_irq_n happens in ISR, this makes the situation worse. To improve the driver, we convert those statistics to 64 bit, implement ndo_get_stats64 and update .get_ethtool_stats implementation accordingly. We also use per-queue statistics where necessary to remove the cacheline ping pongs as much as possible to make multiqueue operations faster. Those statistics which are not possible to overflow and not frequently updated are kept as is. Signed-off-by: Jisheng Zhang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 2eb85b7 commit 133466c

File tree

14 files changed

+335
-158
lines changed

14 files changed

+335
-158
lines changed

drivers/net/ethernet/stmicro/stmmac/common.h

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,25 @@
5959
/* #define FRAME_FILTER_DEBUG */
6060

6161
struct stmmac_txq_stats {
62-
unsigned long tx_pkt_n;
63-
unsigned long tx_normal_irq_n;
62+
u64 tx_bytes;
63+
u64 tx_packets;
64+
u64 tx_pkt_n;
65+
u64 tx_normal_irq_n;
66+
u64 napi_poll;
67+
u64 tx_clean;
68+
u64 tx_set_ic_bit;
69+
u64 tx_tso_frames;
70+
u64 tx_tso_nfrags;
71+
struct u64_stats_sync syncp;
6472
};
6573

6674
struct stmmac_rxq_stats {
67-
unsigned long rx_pkt_n;
68-
unsigned long rx_normal_irq_n;
75+
u64 rx_bytes;
76+
u64 rx_packets;
77+
u64 rx_pkt_n;
78+
u64 rx_normal_irq_n;
79+
u64 napi_poll;
80+
struct u64_stats_sync syncp;
6981
};
7082

7183
/* Extra statistic and debug information exposed by ethtool */
@@ -81,6 +93,7 @@ struct stmmac_extra_stats {
8193
unsigned long tx_frame_flushed;
8294
unsigned long tx_payload_error;
8395
unsigned long tx_ip_header_error;
96+
unsigned long tx_collision;
8497
/* Receive errors */
8598
unsigned long rx_desc;
8699
unsigned long sa_filter_fail;
@@ -113,14 +126,6 @@ struct stmmac_extra_stats {
113126
/* Tx/Rx IRQ Events */
114127
unsigned long rx_early_irq;
115128
unsigned long threshold;
116-
unsigned long tx_pkt_n;
117-
unsigned long rx_pkt_n;
118-
unsigned long normal_irq_n;
119-
unsigned long rx_normal_irq_n;
120-
unsigned long napi_poll;
121-
unsigned long tx_normal_irq_n;
122-
unsigned long tx_clean;
123-
unsigned long tx_set_ic_bit;
124129
unsigned long irq_receive_pmt_irq_n;
125130
/* MMC info */
126131
unsigned long mmc_tx_irq_n;
@@ -190,18 +195,16 @@ struct stmmac_extra_stats {
190195
unsigned long mtl_rx_fifo_ctrl_active;
191196
unsigned long mac_rx_frame_ctrl_fifo;
192197
unsigned long mac_gmii_rx_proto_engine;
193-
/* TSO */
194-
unsigned long tx_tso_frames;
195-
unsigned long tx_tso_nfrags;
196198
/* EST */
197199
unsigned long mtl_est_cgce;
198200
unsigned long mtl_est_hlbs;
199201
unsigned long mtl_est_hlbf;
200202
unsigned long mtl_est_btre;
201203
unsigned long mtl_est_btrlm;
202-
/* per queue statistics */
203-
struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
204-
struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
204+
unsigned long rx_dropped;
205+
unsigned long rx_errors;
206+
unsigned long tx_dropped;
207+
unsigned long tx_errors;
205208
};
206209

207210
/* Safety Feature statistics exposed by ethtool */

drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,10 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
440440
struct stmmac_extra_stats *x, u32 chan,
441441
u32 dir)
442442
{
443-
u32 v;
443+
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
444+
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
444445
int ret = 0;
446+
u32 v;
445447

446448
v = readl(ioaddr + EMAC_INT_STA);
447449

@@ -452,7 +454,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
452454

453455
if (v & EMAC_TX_INT) {
454456
ret |= handle_tx;
455-
x->tx_normal_irq_n++;
457+
u64_stats_update_begin(&tx_q->txq_stats.syncp);
458+
tx_q->txq_stats.tx_normal_irq_n++;
459+
u64_stats_update_end(&tx_q->txq_stats.syncp);
456460
}
457461

458462
if (v & EMAC_TX_DMA_STOP_INT)
@@ -474,7 +478,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
474478

475479
if (v & EMAC_RX_INT) {
476480
ret |= handle_rx;
477-
x->rx_normal_irq_n++;
481+
u64_stats_update_begin(&rx_q->rxq_stats.syncp);
482+
rx_q->rxq_stats.rx_normal_irq_n++;
483+
u64_stats_update_end(&rx_q->rxq_stats.syncp);
478484
}
479485

480486
if (v & EMAC_RX_BUF_UA_INT)

drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,29 +82,24 @@ static void dwmac100_dump_dma_regs(struct stmmac_priv *priv,
8282
}
8383

8484
/* DMA controller has two counters to track the number of the missed frames. */
85-
static void dwmac100_dma_diagnostic_fr(struct net_device_stats *stats,
86-
struct stmmac_extra_stats *x,
85+
static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x,
8786
void __iomem *ioaddr)
8887
{
8988
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
9089

9190
if (unlikely(csr8)) {
9291
if (csr8 & DMA_MISSED_FRAME_OVE) {
93-
stats->rx_over_errors += 0x800;
9492
x->rx_overflow_cntr += 0x800;
9593
} else {
9694
unsigned int ove_cntr;
9795
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
98-
stats->rx_over_errors += ove_cntr;
9996
x->rx_overflow_cntr += ove_cntr;
10097
}
10198

10299
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
103-
stats->rx_missed_errors += 0xffff;
104100
x->rx_missed_cntr += 0xffff;
105101
} else {
106102
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
107-
stats->rx_missed_errors += miss_f;
108103
x->rx_missed_cntr += miss_f;
109104
}
110105
}

drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
#include "dwmac4.h"
1414
#include "dwmac4_descs.h"
1515

16-
static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
17-
struct stmmac_extra_stats *x,
16+
static int dwmac4_wrback_get_tx_status(struct stmmac_extra_stats *x,
1817
struct dma_desc *p,
1918
void __iomem *ioaddr)
2019
{
@@ -40,15 +39,13 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
4039
x->tx_frame_flushed++;
4140
if (unlikely(tdes3 & TDES3_LOSS_CARRIER)) {
4241
x->tx_losscarrier++;
43-
stats->tx_carrier_errors++;
4442
}
4543
if (unlikely(tdes3 & TDES3_NO_CARRIER)) {
4644
x->tx_carrier++;
47-
stats->tx_carrier_errors++;
4845
}
4946
if (unlikely((tdes3 & TDES3_LATE_COLLISION) ||
5047
(tdes3 & TDES3_EXCESSIVE_COLLISION)))
51-
stats->collisions +=
48+
x->tx_collision +=
5249
(tdes3 & TDES3_COLLISION_COUNT_MASK)
5350
>> TDES3_COLLISION_COUNT_SHIFT;
5451

@@ -73,8 +70,7 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
7370
return ret;
7471
}
7572

76-
static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
77-
struct stmmac_extra_stats *x,
73+
static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x,
7874
struct dma_desc *p)
7975
{
8076
unsigned int rdes1 = le32_to_cpu(p->des1);
@@ -93,7 +89,7 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
9389

9490
if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) {
9591
if (unlikely(rdes3 & RDES3_GIANT_PACKET))
96-
stats->rx_length_errors++;
92+
x->rx_length++;
9793
if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR))
9894
x->rx_gmac_overflow++;
9995

@@ -103,10 +99,8 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
10399
if (unlikely(rdes3 & RDES3_RECEIVE_ERROR))
104100
x->rx_mii++;
105101

106-
if (unlikely(rdes3 & RDES3_CRC_ERROR)) {
102+
if (unlikely(rdes3 & RDES3_CRC_ERROR))
107103
x->rx_crc_errors++;
108-
stats->rx_crc_errors++;
109-
}
110104

111105
if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR))
112106
x->dribbling_bit++;

drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
171171
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
172172
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
173173
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
174+
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
175+
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
174176
int ret = 0;
175177

176178
if (dir == DMA_DIR_RX)
@@ -198,18 +200,19 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
198200
}
199201
}
200202
/* TX/RX NORMAL interrupts */
201-
if (likely(intr_status & DMA_CHAN_STATUS_NIS))
202-
x->normal_irq_n++;
203203
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
204-
x->rx_normal_irq_n++;
205-
x->rxq_stats[chan].rx_normal_irq_n++;
204+
u64_stats_update_begin(&rx_q->rxq_stats.syncp);
205+
rx_q->rxq_stats.rx_normal_irq_n++;
206+
u64_stats_update_end(&rx_q->rxq_stats.syncp);
206207
ret |= handle_rx;
207208
}
208209
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
209-
x->tx_normal_irq_n++;
210-
x->txq_stats[chan].tx_normal_irq_n++;
210+
u64_stats_update_begin(&tx_q->txq_stats.syncp);
211+
tx_q->txq_stats.tx_normal_irq_n++;
212+
u64_stats_update_end(&tx_q->txq_stats.syncp);
211213
ret |= handle_tx;
212214
}
215+
213216
if (unlikely(intr_status & DMA_CHAN_STATUS_TBU))
214217
ret |= handle_tx;
215218
if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))

drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/iopoll.h>
1111
#include "common.h"
1212
#include "dwmac_dma.h"
13+
#include "stmmac.h"
1314

1415
#define GMAC_HI_REG_AE 0x80000000
1516

@@ -161,6 +162,8 @@ static void show_rx_process_state(unsigned int status)
161162
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
162163
struct stmmac_extra_stats *x, u32 chan, u32 dir)
163164
{
165+
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
166+
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
164167
int ret = 0;
165168
/* read the status register (CSR5) */
166169
u32 intr_status = readl(ioaddr + DMA_STATUS);
@@ -208,17 +211,20 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
208211
}
209212
/* TX/RX NORMAL interrupts */
210213
if (likely(intr_status & DMA_STATUS_NIS)) {
211-
x->normal_irq_n++;
212214
if (likely(intr_status & DMA_STATUS_RI)) {
213215
u32 value = readl(ioaddr + DMA_INTR_ENA);
214216
/* to schedule NAPI on real RIE event. */
215217
if (likely(value & DMA_INTR_ENA_RIE)) {
216-
x->rx_normal_irq_n++;
218+
u64_stats_update_begin(&rx_q->rxq_stats.syncp);
219+
rx_q->rxq_stats.rx_normal_irq_n++;
220+
u64_stats_update_end(&rx_q->rxq_stats.syncp);
217221
ret |= handle_rx;
218222
}
219223
}
220224
if (likely(intr_status & DMA_STATUS_TI)) {
221-
x->tx_normal_irq_n++;
225+
u64_stats_update_begin(&tx_q->txq_stats.syncp);
226+
tx_q->txq_stats.tx_normal_irq_n++;
227+
u64_stats_update_end(&tx_q->txq_stats.syncp);
222228
ret |= handle_tx;
223229
}
224230
if (unlikely(intr_status & DMA_STATUS_ERI))

drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
#include "common.h"
99
#include "dwxgmac2.h"
1010

11-
static int dwxgmac2_get_tx_status(struct net_device_stats *stats,
12-
struct stmmac_extra_stats *x,
11+
static int dwxgmac2_get_tx_status(struct stmmac_extra_stats *x,
1312
struct dma_desc *p, void __iomem *ioaddr)
1413
{
1514
unsigned int tdes3 = le32_to_cpu(p->des3);
@@ -23,8 +22,7 @@ static int dwxgmac2_get_tx_status(struct net_device_stats *stats,
2322
return ret;
2423
}
2524

26-
static int dwxgmac2_get_rx_status(struct net_device_stats *stats,
27-
struct stmmac_extra_stats *x,
25+
static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
2826
struct dma_desc *p)
2927
{
3028
unsigned int rdes3 = le32_to_cpu(p->des3);

drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
337337
struct stmmac_extra_stats *x, u32 chan,
338338
u32 dir)
339339
{
340+
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
341+
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
340342
u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
341343
u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
342344
int ret = 0;
@@ -364,16 +366,16 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
364366

365367
/* TX/RX NORMAL interrupts */
366368
if (likely(intr_status & XGMAC_NIS)) {
367-
x->normal_irq_n++;
368-
369369
if (likely(intr_status & XGMAC_RI)) {
370-
x->rx_normal_irq_n++;
371-
x->rxq_stats[chan].rx_normal_irq_n++;
370+
u64_stats_update_begin(&rx_q->rxq_stats.syncp);
371+
rx_q->rxq_stats.rx_normal_irq_n++;
372+
u64_stats_update_end(&rx_q->rxq_stats.syncp);
372373
ret |= handle_rx;
373374
}
374375
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
375-
x->tx_normal_irq_n++;
376-
x->txq_stats[chan].tx_normal_irq_n++;
376+
u64_stats_update_begin(&tx_q->txq_stats.syncp);
377+
tx_q->txq_stats.tx_normal_irq_n++;
378+
u64_stats_update_end(&tx_q->txq_stats.syncp);
377379
ret |= handle_tx;
378380
}
379381
}

0 commit comments

Comments
 (0)