diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2015-01-01 21:04:22 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2015-01-06 14:56:40 +0100 |
commit | fec4b794499a628e534a45a3da82d9c0ed94561c (patch) | |
tree | 9a6f8cdef5d9b4946de788e6942ac799d3b54a01 /drivers/net/smc91111.c | |
parent | 556a39131f61efe78e0df14982d014e813dc159c (diff) | |
download | barebox-fec4b794499a628e534a45a3da82d9c0ed94561c.tar.gz barebox-fec4b794499a628e534a45a3da82d9c0ed94561c.tar.xz |
net: smc1111: fix memory congestions
As the SMC1111 has a shared pool of 2k memory buckets for both
transmission and reception, and as there are variants which have as few
as 4 buckets in total, the memory pool can be hogged by unclaimed
receptions, and impeed any further transmission.
This happens on the zylonite pxa board, where 4 packets, most probably
icmp and arp, fill the 4 buckets, preventing any further ethernet
transmission, and stalling the driver.
The fix is rather rough : whenever all the buckets are filled by
reception packets, and if a transmission is required, the transmission
code path will empty up all received packets.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/net/smc91111.c')
-rw-r--r-- | drivers/net/smc91111.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c index 55d93676b2..91bb845c05 100644 --- a/drivers/net/smc91111.c +++ b/drivers/net/smc91111.c @@ -152,6 +152,7 @@ /* Memory Information Register */ /* BANK 0 */ #define MIR_REG 0x0008 +#define MIR_FREE_MASK 0xff00 /* Receive/Phy Control Register */ /* BANK 0 */ @@ -916,6 +917,30 @@ static int smc91c111_eth_open(struct eth_device *edev) return 0; } +static void smc91c111_ensure_freemem(struct eth_device *edev) +{ + struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv; + u16 mir, rxfifo; + + SMC_SELECT_BANK(priv, 0); + mir = SMC_inw(priv, MIR_REG); + SMC_SELECT_BANK(priv, 2); + + if ((mir & MIR_FREE_MASK) == 0) { + do { + SMC_outw(priv, MC_RELEASE, MMU_CMD_REG); + smc_wait_mmu_release_complete(priv); + + SMC_SELECT_BANK(priv, 0); + mir = SMC_inw(priv, MIR_REG); + SMC_SELECT_BANK(priv, 2); + rxfifo = SMC_inw(priv, RXFIFO_REG); + dev_dbg(&edev->dev, "%s: card memory saturated, tidying up (rx_tx_fifo=0x%04x mir=0x%04x)\n", + SMC_DEV_NAME, rxfifo, mir); + } while (!(rxfifo & RXFIFO_REMPTY)); + } +} + static int smc91c111_eth_send(struct eth_device *edev, void *packet, int packet_length) { @@ -957,6 +982,7 @@ static int smc91c111_eth_send(struct eth_device *edev, void *packet, return -EOVERFLOW; } + smc91c111_ensure_freemem(edev); /* now, try to allocate the memory */ SMC_SELECT_BANK(priv, 2); SMC_outw(priv, MC_ALLOC | numPages, MMU_CMD_REG); |