| From 722021014fc0332657882ea2161a9d821121600c Mon Sep 17 00:00:00 2001 |
| From: Finn Thain <fthain@telegraphics.com.au> |
| Date: Thu, 23 Jan 2020 09:07:26 +1100 |
| Subject: [PATCH] net/sonic: Prevent tx watchdog timeout |
| |
| commit 686f85d71d095f1d26b807e23b0f0bfd22042c45 upstream. |
| |
| Section 5.5.3.2 of the datasheet says, |
| |
| If FIFO Underrun, Byte Count Mismatch, Excessive Collision, or |
| Excessive Deferral (if enabled) errors occur, transmission ceases. |
| |
| In this situation, the chip asserts a TXER interrupt rather than TXDN. |
| But the handler for the TXDN is the only way that the transmit queue |
| gets restarted. Hence, an aborted transmission can result in a watchdog |
| timeout. |
| |
| This problem can be reproduced on congested link, as that can result in |
| excessive transmitter collisions. Another way to reproduce this is with |
| a FIFO Underrun, which may be caused by DMA latency. |
| |
| In event of a TXER interrupt, prevent a watchdog timeout by restarting |
| transmission. |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Tested-by: Stan Johnson <userm57@yahoo.com> |
| Signed-off-by: Finn Thain <fthain@telegraphics.com.au> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c |
| index 27b6f6585527..05e760444a92 100644 |
| --- a/drivers/net/ethernet/natsemi/sonic.c |
| +++ b/drivers/net/ethernet/natsemi/sonic.c |
| @@ -415,10 +415,19 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) |
| lp->stats.rx_missed_errors += 65536; |
| |
| /* transmit error */ |
| - if (status & SONIC_INT_TXER) |
| - if (SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) |
| - netif_dbg(lp, tx_err, dev, "%s: tx fifo underrun\n", |
| - __func__); |
| + if (status & SONIC_INT_TXER) { |
| + u16 tcr = SONIC_READ(SONIC_TCR); |
| + |
| + netif_dbg(lp, tx_err, dev, "%s: TXER intr, TCR %04x\n", |
| + __func__, tcr); |
| + |
| + if (tcr & (SONIC_TCR_EXD | SONIC_TCR_EXC | |
| + SONIC_TCR_FU | SONIC_TCR_BCM)) { |
| + /* Aborted transmission. Try again. */ |
| + netif_stop_queue(dev); |
| + SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); |
| + } |
| + } |
| |
| /* bus retry */ |
| if (status & SONIC_INT_BR) { |
| -- |
| 2.7.4 |
| |