| From 2bca9f4f25e1c9937cd0870974cb5758f6d497e2 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: 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c |
| index 26848acec63d..42a6b87d8886 100644 |
| --- a/drivers/net/ethernet/natsemi/sonic.c |
| +++ b/drivers/net/ethernet/natsemi/sonic.c |
| @@ -116,6 +116,24 @@ static int sonic_open(struct net_device *dev) |
| 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 |
| @@ -132,6 +150,9 @@ static int sonic_close(struct net_device *dev) |
| /* |
| * 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); |
| @@ -171,6 +192,9 @@ static void sonic_tx_timeout(struct net_device *dev) |
| * 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); |
| @@ -658,6 +682,7 @@ static int sonic_init(struct net_device *dev) |
| */ |
| SONIC_WRITE(SONIC_CMD, 0); |
| SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); |
| + sonic_quiesce(dev, SONIC_CR_ALL); |
| |
| /* |
| * initialize the receive resource area |
| diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h |
| index cc2f7b4b77e3..1df6d2f06cc4 100644 |
| --- a/drivers/net/ethernet/natsemi/sonic.h |
| +++ b/drivers/net/ethernet/natsemi/sonic.h |
| @@ -110,6 +110,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 |
| */ |
| -- |
| 2.7.4 |
| |