Commit 3a6c12a0 authored by Xiaoliang Yang's avatar Xiaoliang Yang Committed by David S. Miller

net: stmmac: bump tc when get underflow error from DMA descriptor

In DMA threshold mode, frame underflow errors may sometimes occur when
the TC(threshold control) value is not enough. The TC value need to be
bumped up in this case.

There is no underflow interrupt bit on DMA_CH(#i)_Status of dwmac4, so
the DMA threshold cannot be bumped up in stmmac_dma_interrupt(). The
i.mx8mp board observed an underflow error while running NFS boot, the
NFS rootfs could not be mounted.

The underflow error can be got from the DMA descriptor TDES3 on dwmac4.
This patch bump up tc value once underflow error is got from TDES3.
Signed-off-by: default avatarXiaoliang Yang <xiaoliang.yang_1@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9b5bcb19
...@@ -317,6 +317,7 @@ enum tx_frame_status { ...@@ -317,6 +317,7 @@ enum tx_frame_status {
tx_not_ls = 0x1, tx_not_ls = 0x1,
tx_err = 0x2, tx_err = 0x2,
tx_dma_own = 0x4, tx_dma_own = 0x4,
tx_err_bump_tc = 0x8,
}; };
enum dma_irq_status { enum dma_irq_status {
......
...@@ -32,6 +32,8 @@ static int dwmac4_wrback_get_tx_status(void *data, struct stmmac_extra_stats *x, ...@@ -32,6 +32,8 @@ static int dwmac4_wrback_get_tx_status(void *data, struct stmmac_extra_stats *x,
return tx_not_ls; return tx_not_ls;
if (unlikely(tdes3 & TDES3_ERROR_SUMMARY)) { if (unlikely(tdes3 & TDES3_ERROR_SUMMARY)) {
ret = tx_err;
if (unlikely(tdes3 & TDES3_JABBER_TIMEOUT)) if (unlikely(tdes3 & TDES3_JABBER_TIMEOUT))
x->tx_jabber++; x->tx_jabber++;
if (unlikely(tdes3 & TDES3_PACKET_FLUSHED)) if (unlikely(tdes3 & TDES3_PACKET_FLUSHED))
...@@ -53,16 +55,16 @@ static int dwmac4_wrback_get_tx_status(void *data, struct stmmac_extra_stats *x, ...@@ -53,16 +55,16 @@ static int dwmac4_wrback_get_tx_status(void *data, struct stmmac_extra_stats *x,
if (unlikely(tdes3 & TDES3_EXCESSIVE_DEFERRAL)) if (unlikely(tdes3 & TDES3_EXCESSIVE_DEFERRAL))
x->tx_deferred++; x->tx_deferred++;
if (unlikely(tdes3 & TDES3_UNDERFLOW_ERROR)) if (unlikely(tdes3 & TDES3_UNDERFLOW_ERROR)) {
x->tx_underflow++; x->tx_underflow++;
ret |= tx_err_bump_tc;
}
if (unlikely(tdes3 & TDES3_IP_HDR_ERROR)) if (unlikely(tdes3 & TDES3_IP_HDR_ERROR))
x->tx_ip_header_error++; x->tx_ip_header_error++;
if (unlikely(tdes3 & TDES3_PAYLOAD_ERROR)) if (unlikely(tdes3 & TDES3_PAYLOAD_ERROR))
x->tx_payload_error++; x->tx_payload_error++;
ret = tx_err;
} }
if (unlikely(tdes3 & TDES3_DEFERRED)) if (unlikely(tdes3 & TDES3_DEFERRED))
......
...@@ -132,6 +132,8 @@ static irqreturn_t stmmac_msi_intr_tx(int irq, void *data); ...@@ -132,6 +132,8 @@ static irqreturn_t stmmac_msi_intr_tx(int irq, void *data);
static irqreturn_t stmmac_msi_intr_rx(int irq, void *data); static irqreturn_t stmmac_msi_intr_rx(int irq, void *data);
static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue); static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue);
static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue); static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue);
static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
u32 rxmode, u32 chan);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
static const struct net_device_ops stmmac_netdev_ops; static const struct net_device_ops stmmac_netdev_ops;
...@@ -2466,6 +2468,21 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) ...@@ -2466,6 +2468,21 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
return !!budget && work_done; return !!budget && work_done;
} }
static void stmmac_bump_dma_threshold(struct stmmac_priv *priv, u32 chan)
{
if (unlikely(priv->xstats.threshold != SF_DMA_MODE) && tc <= 256) {
tc += 64;
if (priv->plat->force_thresh_dma_mode)
stmmac_set_dma_operation_mode(priv, tc, tc, chan);
else
stmmac_set_dma_operation_mode(priv, tc, SF_DMA_MODE,
chan);
priv->xstats.threshold = tc;
}
}
/** /**
* stmmac_tx_clean - to manage the transmission completion * stmmac_tx_clean - to manage the transmission completion
* @priv: driver private structure * @priv: driver private structure
...@@ -2531,6 +2548,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) ...@@ -2531,6 +2548,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
/* ... verify the status error condition */ /* ... verify the status error condition */
if (unlikely(status & tx_err)) { if (unlikely(status & tx_err)) {
priv->dev->stats.tx_errors++; priv->dev->stats.tx_errors++;
if (unlikely(status & tx_err_bump_tc))
stmmac_bump_dma_threshold(priv, queue);
} else { } else {
priv->dev->stats.tx_packets++; priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++; priv->xstats.tx_pkt_n++;
...@@ -2781,21 +2800,7 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) ...@@ -2781,21 +2800,7 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
for (chan = 0; chan < tx_channel_count; chan++) { for (chan = 0; chan < tx_channel_count; chan++) {
if (unlikely(status[chan] & tx_hard_error_bump_tc)) { if (unlikely(status[chan] & tx_hard_error_bump_tc)) {
/* Try to bump up the dma threshold on this failure */ /* Try to bump up the dma threshold on this failure */
if (unlikely(priv->xstats.threshold != SF_DMA_MODE) && stmmac_bump_dma_threshold(priv, chan);
(tc <= 256)) {
tc += 64;
if (priv->plat->force_thresh_dma_mode)
stmmac_set_dma_operation_mode(priv,
tc,
tc,
chan);
else
stmmac_set_dma_operation_mode(priv,
tc,
SF_DMA_MODE,
chan);
priv->xstats.threshold = tc;
}
} else if (unlikely(status[chan] == tx_hard_error)) { } else if (unlikely(status[chan] == tx_hard_error)) {
stmmac_tx_err(priv, chan); stmmac_tx_err(priv, chan);
} }
...@@ -5745,21 +5750,7 @@ static irqreturn_t stmmac_msi_intr_tx(int irq, void *data) ...@@ -5745,21 +5750,7 @@ static irqreturn_t stmmac_msi_intr_tx(int irq, void *data)
if (unlikely(status & tx_hard_error_bump_tc)) { if (unlikely(status & tx_hard_error_bump_tc)) {
/* Try to bump up the dma threshold on this failure */ /* Try to bump up the dma threshold on this failure */
if (unlikely(priv->xstats.threshold != SF_DMA_MODE) && stmmac_bump_dma_threshold(priv, chan);
tc <= 256) {
tc += 64;
if (priv->plat->force_thresh_dma_mode)
stmmac_set_dma_operation_mode(priv,
tc,
tc,
chan);
else
stmmac_set_dma_operation_mode(priv,
tc,
SF_DMA_MODE,
chan);
priv->xstats.threshold = tc;
}
} else if (unlikely(status == tx_hard_error)) { } else if (unlikely(status == tx_hard_error)) {
stmmac_tx_err(priv, chan); stmmac_tx_err(priv, chan);
} }
......
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