| From: Finn Thain <fthain@telegraphics.com.au> |
| Date: Thu, 23 Jan 2020 09:07:26 +1100 |
| Subject: net/sonic: Quiesce SONIC before re-initializing descriptor memory |
| |
| commit 3f4b7e6a2be982fd8820a2b54d46dd9c351db899 upstream. |
| |
| Make sure the SONIC's DMA engine is idle before altering the transmit |
| and receive descriptors. Add a helper for this as it will be needed |
| again. |
| |
| 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: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/net/ethernet/natsemi/sonic.c | 25 +++++++++++++++++++++++++ |
| drivers/net/ethernet/natsemi/sonic.h | 3 +++ |
| 2 files changed, 28 insertions(+) |
| |
| --- a/drivers/net/ethernet/natsemi/sonic.c |
| +++ b/drivers/net/ethernet/natsemi/sonic.c |
| @@ -103,6 +103,24 @@ static int sonic_open(struct net_device |
| return 0; |
| } |
| |
| +/* Wait for the SONIC to become idle. */ |
| +static void sonic_quiesce(struct net_device *dev, u16 mask) |
| +{ |
| + struct sonic_local * __maybe_unused lp = netdev_priv(dev); |
| + int i; |
| + u16 bits; |
| + |
| + for (i = 0; i < 1000; ++i) { |
| + bits = SONIC_READ(SONIC_CMD) & mask; |
| + if (!bits) |
| + return; |
| + if (irqs_disabled() || in_interrupt()) |
| + udelay(20); |
| + else |
| + usleep_range(100, 200); |
| + } |
| + WARN_ONCE(1, "command deadline expired! 0x%04x\n", bits); |
| +} |
| |
| /* |
| * Close the SONIC device |
| @@ -120,6 +138,9 @@ static int sonic_close(struct net_device |
| /* |
| * stop the SONIC, disable interrupts |
| */ |
| + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); |
| + sonic_quiesce(dev, SONIC_CR_ALL); |
| + |
| SONIC_WRITE(SONIC_IMR, 0); |
| SONIC_WRITE(SONIC_ISR, 0x7fff); |
| SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); |
| @@ -159,6 +180,9 @@ static void sonic_tx_timeout(struct net_ |
| * put the Sonic into software-reset mode and |
| * disable all interrupts before releasing DMA buffers |
| */ |
| + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); |
| + sonic_quiesce(dev, SONIC_CR_ALL); |
| + |
| SONIC_WRITE(SONIC_IMR, 0); |
| SONIC_WRITE(SONIC_ISR, 0x7fff); |
| SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); |
| @@ -638,6 +662,7 @@ static int sonic_init(struct net_device |
| */ |
| SONIC_WRITE(SONIC_CMD, 0); |
| SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); |
| + sonic_quiesce(dev, SONIC_CR_ALL); |
| |
| /* |
| * initialize the receive resource area |
| --- a/drivers/net/ethernet/natsemi/sonic.h |
| +++ b/drivers/net/ethernet/natsemi/sonic.h |
| @@ -109,6 +109,9 @@ |
| #define SONIC_CR_TXP 0x0002 |
| #define SONIC_CR_HTX 0x0001 |
| |
| +#define SONIC_CR_ALL (SONIC_CR_LCAM | SONIC_CR_RRRA | \ |
| + SONIC_CR_RXEN | SONIC_CR_TXP) |
| + |
| /* |
| * SONIC data configuration bits |
| */ |