diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-02-06 10:45:42 -0800 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-07 18:50:44 -0500 |
commit | 62335ab013d9eaef502bd402eb2eb72e8cff58f1 (patch) | |
tree | 0b8fbb6019b4e3002a9d7e64838b04761376d2ba /drivers/net/sky2.c | |
parent | 4a50a876ac325a45de1b582571c1248648801b52 (diff) |
sky2: safer transmit timeout
Rather than trying to be "smart" about possible transmit timeout
causes. Just clear all pending frames and reset the PHY.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 41 |
1 files changed, 15 insertions, 26 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index e97dc299b56..c96362dae80 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1840,48 +1840,37 @@ out: } -/* Transmit timeout is only called if we are running, carries is up +/* Transmit timeout is only called if we are running, carrier is up * and tx queue is full (stopped). + * Called with netif_tx_lock held. */ static void sky2_tx_timeout(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - unsigned txq = txqaddr[sky2->port]; - u16 report, done; + u32 imask; if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); - report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX); - done = sky2_read16(hw, Q_ADDR(txq, Q_DONE)); - printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n", - dev->name, - sky2->tx_cons, sky2->tx_prod, report, done); - - if (report != done) { - printk(KERN_INFO PFX "status burst pending (irq moderation?)\n"); + dev->name, sky2->tx_cons, sky2->tx_prod, + sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), + sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); - } else if (report != sky2->tx_cons) { - printk(KERN_INFO PFX "status report lost?\n"); + imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */ + sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); - netif_tx_lock_bh(dev); - sky2_tx_complete(sky2, report); - netif_tx_unlock_bh(dev); - } else { - printk(KERN_INFO PFX "hardware hung? flushing\n"); + netif_poll_disable(hw->dev[0]); /* stop NAPI poll */ + synchronize_irq(hw->pdev->irq); - sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); - sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); + netif_start_queue(dev); /* don't wakeup during flush */ + sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */ - sky2_tx_clean(dev); + sky2_write32(hw, B0_IMSK, imask); - sky2_qset(hw, txq); - sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); - } + sky2_phy_reinit(sky2); /* this clears flow control etc */ } static int sky2_change_mtu(struct net_device *dev, int new_mtu) |