diff options
author | Dale Farnsworth <dale@farnsworth.org> | 2006-04-11 18:24:26 -0700 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-04-12 18:11:23 -0400 |
commit | 94843566d7119e049a72618a3c939d5c2be022c7 (patch) | |
tree | 4b0b90677e6ad7cbe70914a3ad33bdf57a55997d /drivers/net | |
parent | 5c5374087707d7848cb13f15e7c175daf346301c (diff) | |
download | op-kernel-dev-94843566d7119e049a72618a3c939d5c2be022c7.zip op-kernel-dev-94843566d7119e049a72618a3c939d5c2be022c7.tar.gz |
[PATCH] mv643xx_eth: Fix tx_timeout to only conditionally wake tx queue
After resetting the hardware on a tx_timeout, call netif_wake_queue()
only if we have free tx descriptors.
Also, attempt to recover if mv643xx_eth_start_xmit() is called when
there are fewer free tx descriptors than expected.
The BUG_ON() call we are replacing was hit on a tx_timeout that
called netif_wake_queue(), indirectly via netif_device_attach(),
even though we did not have enough free tx descriptors.
Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 85ac42c..ea62a3e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -281,10 +281,16 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); - netif_device_detach(dev); + if (!netif_running(dev)) + return; + + netif_stop_queue(dev); + eth_port_reset(mp->port_num); eth_port_start(dev); - netif_device_attach(dev); + + if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) + netif_wake_queue(dev); } /** @@ -1186,7 +1192,12 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(netif_queue_stopped(dev)); BUG_ON(skb == NULL); - BUG_ON(mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB); + + if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) { + printk(KERN_ERR "%s: transmit with queue full\n", dev->name); + netif_stop_queue(dev); + return 1; + } if (has_tiny_unaligned_frags(skb)) { if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { |