summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2025-08-20 15:03:46 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-13 20:29:52 +0300
commitb3e0ead2417a30df046b237e7fc6959976f97541 (patch)
treecbde9fcba97d41349e2e1d21fdd4c1fe467fc5cf
parent5b30901e83d34769a3e59fdfde75cb4eb50fb554 (diff)
downloadlinux-b3e0ead2417a30df046b237e7fc6959976f97541.tar.gz
linux-b3e0ead2417a30df046b237e7fc6959976f97541.zip
net: stmmac: dwmac1000: Collect DMA missing frames statistics
DW GMACs have been supporting the missing frames (due to Rx buffer unavailable or MTL FIFO overflow events) statistics from very initial controller release. It has been implemented in the same way as can be found on the even older DW MAC100 devices. It isn't clear why the support hasn't been added to the driver for both versions of the controller together, but let's fix that flaw especially seeing the counters are exceptionally useful on the interface performance debugging. The solution is to just reuse the already implemented dwmac100_dma_diagnostic_fr() method for DW GMACs too by moving the function to the dwmac_lib.c module. Note the change also fixes the counter data missing after overflows. Indeed the former dwmac_dma_diagnostic_fr() method didn't add the current counters value if the counters overflow had happened. It's wrong since the counters will continue to be incremented even after that. In the meantime reading the CSR will erase the current values from the CSR. Fixes: 1c901a46d576 ("stmmac: add MMC support exported via ethtool (v3)") Fixes: 47dd7a540b8a ("net: add support for STMicroelectronics Ethernet controllers.") Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100.h6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c28
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c19
5 files changed, 30 insertions, 33 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100.h b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h
index 547863cb982f..576cbf766cc1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h
@@ -68,12 +68,6 @@ enum ttc_control {
DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */
};
-/* STMAC110 DMA Missed Frame Counter register defines */
-#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */
-#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */
-#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
-#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
-
extern const struct stmmac_dma_ops dwmac100_dma_ops;
#endif /* __DWMAC100_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index 3ac7a7949529..a4b5b1a51f0a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -259,6 +259,7 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = {
.dump_regs = dwmac1000_dump_dma_regs,
.dma_rx_mode = dwmac1000_dma_operation_mode_rx,
.dma_tx_mode = dwmac1000_dma_operation_mode_tx,
+ .dma_diagnostic_fr = dwmac_dma_diagnostic_fr,
.enable_dma_transmission = dwmac_enable_dma_transmission,
.enable_dma_reception = dwmac_enable_dma_reception,
.enable_dma_irq = dwmac_enable_dma_irq,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index 0acdf3e23ac1..093d09267e38 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -82,32 +82,6 @@ static void dwmac100_dump_dma_regs(struct stmmac_priv *priv,
readl(ioaddr + DMA_CUR_RX_BUF_ADDR);
}
-/* DMA controller has two counters to track the number of the missed frames. */
-static void dwmac100_dma_diagnostic_fr(struct stmmac_priv *priv,
- void __iomem *ioaddr,
- struct stmmac_extra_stats *x,
- u32 chan)
-{
- u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
-
- if (unlikely(csr8)) {
- if (csr8 & DMA_MISSED_FRAME_OVE) {
- x->rx_overflow_cntr += 0x800;
- } else {
- unsigned int ove_cntr;
- ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
- x->rx_overflow_cntr += ove_cntr;
- }
-
- if (csr8 & DMA_MISSED_FRAME_OVE_M) {
- x->rx_missed_cntr += 0xffff;
- } else {
- unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
- x->rx_missed_cntr += miss_f;
- }
- }
-}
-
const struct stmmac_dma_ops dwmac100_dma_ops = {
.reset = dwmac_dma_reset,
.init = dwmac100_dma_init,
@@ -115,7 +89,7 @@ const struct stmmac_dma_ops dwmac100_dma_ops = {
.init_tx_chan = dwmac100_dma_init_tx,
.dump_regs = dwmac100_dump_dma_regs,
.dma_tx_mode = dwmac100_dma_operation_mode_tx,
- .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
+ .dma_diagnostic_fr = dwmac_dma_diagnostic_fr,
.enable_dma_transmission = dwmac_enable_dma_transmission,
.enable_dma_irq = dwmac_enable_dma_irq,
.disable_dma_irq = dwmac_disable_dma_irq,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index 79c4eb8f42d4..a4e034c9fecf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -119,9 +119,16 @@ static inline u32 dma_chan_base_addr(u32 base, u32 chan)
#define DMA_CHAN_STATUS(chan) dma_chan_base_addr(DMA_STATUS, chan)
#define DMA_CHAN_CONTROL(chan) dma_chan_base_addr(DMA_CONTROL, chan)
#define DMA_CHAN_INTR_ENA(chan) dma_chan_base_addr(DMA_INTR_ENA, chan)
+#define DMA_CHAN_MISSED_FRAME_CTR(chan) \
+ dma_chan_base_addr(DMA_MISSED_FRAME_CTR, chan)
#define DMA_CHAN_RX_WATCHDOG(chan) \
dma_chan_base_addr(DMA_RX_WATCHDOG, chan)
+/* DMA Missed Frame Counter */
+#define DMA_MISSED_FRAME_OVFCNTOVF BIT(28)
+#define DMA_MISSED_FRAME_OVFFRMCNT GENMASK(27, 17)
+#define DMA_MISSED_FRAME_MISCNTOVF BIT(16)
+#define DMA_MISSED_FRAME_MISFRMCNT GENMASK(15, 0)
/* Rx watchdog register */
#define DMA_RX_WATCHDOG 0x00001024
@@ -162,6 +169,8 @@ void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
u32 chan);
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir);
+void dwmac_dma_diagnostic_fr(struct stmmac_priv *priv, void __iomem *ioaddr,
+ struct stmmac_extra_stats *x, u32 chan);
int dwmac_dma_reset(void __iomem *ioaddr);
#endif /* __DWMAC_DMA_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 64e43adc51a6..75dd1d370f64 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -246,6 +246,25 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
return ret;
}
+void dwmac_dma_diagnostic_fr(struct stmmac_priv *priv, void __iomem *ioaddr,
+ struct stmmac_extra_stats *x, u32 chan)
+{
+ u32 csr8 = readl(ioaddr + DMA_CHAN_MISSED_FRAME_CTR(chan));
+ unsigned long cntr;
+
+ cntr = FIELD_GET(DMA_MISSED_FRAME_OVFFRMCNT, csr8);
+ if (csr8 & DMA_MISSED_FRAME_OVFCNTOVF)
+ cntr += FIELD_MAX(DMA_MISSED_FRAME_OVFFRMCNT) + 1;
+
+ x->rx_overflow_cntr += cntr;
+
+ cntr = FIELD_GET(DMA_MISSED_FRAME_MISFRMCNT, csr8);
+ if (csr8 & DMA_MISSED_FRAME_MISCNTOVF)
+ cntr += FIELD_MAX(DMA_MISSED_FRAME_MISFRMCNT) + 1;
+
+ x->rx_missed_cntr += cntr;
+}
+
void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
unsigned int high, unsigned int low)
{