diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-02-06 13:45:42 -0500 |
---|---|---|
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 e97dc299b563..c96362dae800 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -1840,48 +1840,37 @@ out: | |||
1840 | } | 1840 | } |
1841 | 1841 | ||
1842 | 1842 | ||
1843 | /* Transmit timeout is only called if we are running, carries is up | 1843 | /* Transmit timeout is only called if we are running, carrier is up |
1844 | * and tx queue is full (stopped). | 1844 | * and tx queue is full (stopped). |
1845 | * Called with netif_tx_lock held. | ||
1845 | */ | 1846 | */ |
1846 | static void sky2_tx_timeout(struct net_device *dev) | 1847 | static void sky2_tx_timeout(struct net_device *dev) |
1847 | { | 1848 | { |
1848 | struct sky2_port *sky2 = netdev_priv(dev); | 1849 | struct sky2_port *sky2 = netdev_priv(dev); |
1849 | struct sky2_hw *hw = sky2->hw; | 1850 | struct sky2_hw *hw = sky2->hw; |
1850 | unsigned txq = txqaddr[sky2->port]; | 1851 | u32 imask; |
1851 | u16 report, done; | ||
1852 | 1852 | ||
1853 | if (netif_msg_timer(sky2)) | 1853 | if (netif_msg_timer(sky2)) |
1854 | printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); | 1854 | printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); |
1855 | 1855 | ||
1856 | report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX); | ||
1857 | done = sky2_read16(hw, Q_ADDR(txq, Q_DONE)); | ||
1858 | |||
1859 | printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n", | 1856 | printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n", |
1860 | dev->name, | 1857 | dev->name, sky2->tx_cons, sky2->tx_prod, |
1861 | sky2->tx_cons, sky2->tx_prod, report, done); | 1858 | sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), |
1862 | 1859 | sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); | |
1863 | if (report != done) { | ||
1864 | printk(KERN_INFO PFX "status burst pending (irq moderation?)\n"); | ||
1865 | 1860 | ||
1866 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); | 1861 | imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */ |
1867 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); | 1862 | sky2_write32(hw, B0_IMSK, 0); |
1868 | } else if (report != sky2->tx_cons) { | 1863 | sky2_read32(hw, B0_IMSK); |
1869 | printk(KERN_INFO PFX "status report lost?\n"); | ||
1870 | 1864 | ||
1871 | netif_tx_lock_bh(dev); | 1865 | netif_poll_disable(hw->dev[0]); /* stop NAPI poll */ |
1872 | sky2_tx_complete(sky2, report); | 1866 | synchronize_irq(hw->pdev->irq); |
1873 | netif_tx_unlock_bh(dev); | ||
1874 | } else { | ||
1875 | printk(KERN_INFO PFX "hardware hung? flushing\n"); | ||
1876 | 1867 | ||
1877 | sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); | 1868 | netif_start_queue(dev); /* don't wakeup during flush */ |
1878 | sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); | 1869 | sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */ |
1879 | 1870 | ||
1880 | sky2_tx_clean(dev); | 1871 | sky2_write32(hw, B0_IMSK, imask); |
1881 | 1872 | ||
1882 | sky2_qset(hw, txq); | 1873 | sky2_phy_reinit(sky2); /* this clears flow control etc */ |
1883 | sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); | ||
1884 | } | ||
1885 | } | 1874 | } |
1886 | 1875 | ||
1887 | static int sky2_change_mtu(struct net_device *dev, int new_mtu) | 1876 | static int sky2_change_mtu(struct net_device *dev, int new_mtu) |