diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2025-08-09 02:09:26 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:25:04 +0300 |
| commit | 6133c10112cb185cd01d712f317537206bd03b58 (patch) | |
| tree | fcedd872c6d25163110c63eb90744354969cc623 | |
| parent | 08481939bba24ff25fd22b4f659c072893477e43 (diff) | |
| download | linux-6133c10112cb185cd01d712f317537206bd03b58.tar.gz linux-6133c10112cb185cd01d712f317537206bd03b58.zip | |
net: stmmac: Add MTL FIFO threshold correction for modern IP-cores
Currently the MTL FIFO threshold doesn't get to be dynamically adjusted
for the DW QoS Ether and DW XGMAC/XLGMAC/etc controllers. In case of the
Cut-through DMA mode and relatively slow DMA-interface it will cause the
interfaces to occasionally loose packets due to the Rx FIFO overflow and
Tx FIFO underflow.
For the hardware setups relying on the Cut-through DMA mode let's add the
MTL FIFO threshold correction support for the DW QoS Ether and DW
XGMAC/XLGMAC/etc IP-cores in the same way it has been already done for DW
MAC100/GMAC. The only difference is that the Rx FIFO overflow and Tx FIFO
underflow IRQs are handled not via DMA CSRs but by means of the MTL CSRs.
Note earlier there already was an attempt to add provide the solution for
the denoted problem for the DW QoS Ether IP-core in the framework of the
commit 3a6c12a0c6c3 ("net: stmmac: bump tc when get underflow error from
DMA descriptor"). The problem is that solution was first incomplete due to
lack the Rx MTL FIFO threshold correction and second relied on the Tx
descriptor status which might be detected too late so more comming frames
could be corrupted due to the FIFO underflows. Moreover the commit claimed
that there was no underflow interrupt bit on DW GMAC4, which as you can
see is incorrect.
Fixes: 3a6c12a0c6c3 ("net: stmmac: bump tc when get underflow error from DMA descriptor")
Fixes: d6ddfacd95c7 ("net: stmmac: Add DMA related callbacks for XGMAC2")
Fixes: 477286b53f55 ("stmmac: add GMAC4 core support")
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/common.h | 18 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 12 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 8 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 24 |
9 files changed, 49 insertions, 28 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 45d068daded9..6a5973e7b197 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -370,7 +370,6 @@ enum tx_frame_status { tx_not_ls = 0x1, tx_err = 0x2, tx_dma_own = 0x4, - tx_err_bump_tc = 0x8, }; enum dma_irq_status { @@ -390,6 +389,15 @@ enum dma_irq_dir { DMA_DIR_RXTX = 0x3, }; +enum mtl_irq_status { + CORE_IRQ_TX_PATH_IN_LPI_MODE = 0x1, + CORE_IRQ_TX_PATH_EXIT_LPI_MODE = 0x2, + CORE_IRQ_RX_PATH_IN_LPI_MODE = 0x4, + CORE_IRQ_RX_PATH_EXIT_LPI_MODE = 0x8, + CORE_IRQ_MTL_RX_OVERFLOW = 0x100, + CORE_IRQ_MTL_TX_UNDERFLOW = 0x200, +}; + enum request_irq_err { REQ_IRQ_ERR_ALL, REQ_IRQ_ERR_TX, @@ -402,12 +410,6 @@ enum request_irq_err { REQ_IRQ_ERR_NO, }; -/* EEE and LPI defines */ -#define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 0) -#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 1) -#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 2) -#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 3) - /* FPE defines */ #define FPE_EVENT_UNKNOWN 0 #define FPE_EVENT_TRSP BIT(0) @@ -415,8 +417,6 @@ enum request_irq_err { #define FPE_EVENT_RRSP BIT(2) #define FPE_EVENT_RVER BIT(3) -#define CORE_IRQ_MTL_RX_OVERFLOW BIT(8) - /* DMA HW capabilities */ struct dma_features { unsigned int mbps_10_100; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index d797d936aee1..dff584ea5ab2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -457,6 +457,9 @@ static inline u32 mtl_low_credx_base_addr(const struct dwmac4_addrs *addrs, /* MTL interrupt */ #define MTL_RX_OVERFLOW_INT_EN BIT(24) #define MTL_RX_OVERFLOW_INT BIT(16) +#define MTL_TX_UNDERFLOW_INT_EN BIT(8) +#define MTL_TX_UNDERFLOW_INT BIT(0) +#define MTL_INT_DEFAULT_ENABLE (MTL_RX_OVERFLOW_INT | MTL_TX_UNDERFLOW_INT) /* Default operating mode of the MAC */ #define GMAC_CORE_INIT (GMAC_CONFIG_JD | GMAC_CONFIG_PS | \ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 7665aa5c3d91..429a344a7896 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -603,12 +603,12 @@ static int dwmac4_irq_mtl_status(struct stmmac_priv *priv, u32 status = readl(ioaddr + MTL_CHAN_INT_CTRL(dwmac4_addrs, chan)); - if (status & MTL_RX_OVERFLOW_INT) { - /* clear Interrupt */ - writel(status | MTL_RX_OVERFLOW_INT, - ioaddr + MTL_CHAN_INT_CTRL(dwmac4_addrs, chan)); - ret = CORE_IRQ_MTL_RX_OVERFLOW; - } + if (unlikely(status & MTL_RX_OVERFLOW_INT)) + ret |= CORE_IRQ_MTL_RX_OVERFLOW; + if (unlikely(status & MTL_TX_UNDERFLOW_INT)) + ret |= CORE_IRQ_MTL_TX_UNDERFLOW; + + writel(status, ioaddr + MTL_CHAN_INT_CTRL(dwmac4_addrs, chan)); } return ret; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index e226dc6a1b17..d722f7378818 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -49,10 +49,8 @@ static int dwmac4_wrback_get_tx_status(struct stmmac_extra_stats *x, if (unlikely(tdes3 & TDES3_EXCESSIVE_DEFERRAL)) x->tx_deferred++; - if (unlikely(tdes3 & TDES3_UNDERFLOW_ERROR)) { + if (unlikely(tdes3 & TDES3_UNDERFLOW_ERROR)) x->tx_underflow++; - ret |= tx_err_bump_tc; - } if (unlikely(tdes3 & TDES3_IP_HDR_ERROR)) x->tx_ip_header_error++; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 1868683f0f02..398ca3df560f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -128,6 +128,10 @@ static void dwmac4_dma_init_channel(struct stmmac_priv *priv, /* Mask interrupts by writing to CSR7 */ writel(DMA_CHAN_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); + + /* Enable interrupts by writing to MTL INT CSR */ + writel(MTL_INT_DEFAULT_ENABLE, + ioaddr + MTL_CHAN_INT_CTRL(dwmac4_addrs, chan)); } static void dwmac410_dma_init_channel(struct stmmac_priv *priv, @@ -147,6 +151,10 @@ static void dwmac410_dma_init_channel(struct stmmac_priv *priv, /* Mask interrupts by writing to CSR7 */ writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); + + /* Enable interrupts by writing to MTL INT CSR */ + writel(MTL_INT_DEFAULT_ENABLE, + ioaddr + MTL_CHAN_INT_CTRL(dwmac4_addrs, chan)); } static void dwmac4_dma_init(void __iomem *ioaddr, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 88954be64f45..eb6c9bab94cb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -311,6 +311,8 @@ #define XGMAC_RFA GENMASK(15, 1) #define XGMAC_MTL_QINTEN(x) (0x00001170 + (0x80 * (x))) #define XGMAC_RXOIE BIT(16) +#define XGMAC_TXUIE BIT(0) +#define XGMAC_MTL_INT_DEFAULT_EN (XGMAC_RXOIE | XGMAC_TXUIE) #define XGMAC_MTL_QINT_STATUS(x) (0x00001174 + (0x80 * (x))) #define XGMAC_RXOVFIS BIT(16) #define XGMAC_ABPSIS BIT(1) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 8d77f6e7e71b..639ba71a728a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -346,8 +346,10 @@ static int dwxgmac2_host_mtl_irq_status(struct stmmac_priv *priv, if (chan_status & XGMAC_RXOVFIS) ret |= CORE_IRQ_MTL_RX_OVERFLOW; + if (chan_status & XGMAC_TXUNFIS) + ret |= CORE_IRQ_MTL_TX_UNDERFLOW; - writel(~0x0, ioaddr + XGMAC_MTL_QINT_STATUS(chan)); + writel(chan_status, ioaddr + XGMAC_MTL_QINT_STATUS(chan)); } return ret; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 696eba7d3a12..17be7e46aa23 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -44,6 +44,8 @@ static void dwxgmac2_dma_init_chan(struct stmmac_priv *priv, writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan)); writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); + + writel(XGMAC_MTL_INT_DEFAULT_EN, ioaddr + XGMAC_MTL_QINTEN(chan)); } static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 0d23189c0cb7..81f28aba6df4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2972,13 +2972,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue, /* Just consider the last segment and ...*/ if (likely(!(status & tx_not_ls))) { /* ... verify the status error condition */ - if (unlikely(status & tx_err)) { + if (unlikely(status & tx_err)) tx_errors++; - if (unlikely(status & tx_err_bump_tc)) - stmmac_handle_tx_unf_error(priv, queue); - } else { + else tx_packets++; - } + if (skb) { stmmac_get_tx_hwtstamp(priv, p, skb); } else if (tx_q->xsk_pool && @@ -6259,6 +6257,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) u32 rx_cnt = priv->plat->rx_queues_to_use; u32 tx_cnt = priv->plat->tx_queues_to_use; u32 queues_count; + int status; u32 queue; bool xmac; @@ -6277,7 +6276,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) /* To handle GMAC own interrupts */ if (priv->plat->core_type == DWMAC_CORE_GMAC || xmac) { - int status = stmmac_host_irq_status(priv, &priv->xstats); + status = stmmac_host_irq_status(priv, &priv->xstats); if (unlikely(status)) { /* For LPI we need to save the tx status */ @@ -6287,11 +6286,18 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) priv->tx_path_in_lpi_mode = false; } - for (queue = 0; queue < queues_count; queue++) - stmmac_host_mtl_irq_status(priv, priv->hw, queue); - stmmac_timestamp_interrupt(priv, priv); } + + if (xmac) { + for (queue = 0; queue < queues_count; queue++) { + status = stmmac_host_mtl_irq_status(priv, priv->hw, queue); + if (unlikely(status & CORE_IRQ_MTL_RX_OVERFLOW)) + stmmac_handle_rx_ovf_error(priv, queue); + if (unlikely(status & CORE_IRQ_MTL_TX_UNDERFLOW)) + stmmac_handle_tx_unf_error(priv, queue); + } + } } /** |
