aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-03-20 18:48:21 -0500
committerJeff Garzik <jeff@garzik.org>2006-03-21 16:00:52 -0500
commit8f24664da64f8db094cd9d379b16fc1d8776d1df (patch)
treec954d1ac501e3f4f4c5473cdc96bf46894b129d9
parentd89e1343959200a578465d50bb36c89733cf66a7 (diff)
[PATCH] sky2: transmit recovery
This patch decodes state and revovers from any races in the transmit timeout and NAPI logic. It should never trigger, but if it does then do the right thing. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/net/sky2.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index ffe3aa7e2ab2..ab36a7460a26 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1328,7 +1328,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
1328 } 1328 }
1329 1329
1330 sky2->tx_cons = put; 1330 sky2->tx_cons = put;
1331 if (netif_queue_stopped(dev) && tx_avail(sky2) > MAX_SKB_TX_LE) 1331 if (tx_avail(sky2) > MAX_SKB_TX_LE)
1332 netif_wake_queue(dev); 1332 netif_wake_queue(dev);
1333} 1333}
1334 1334
@@ -1651,17 +1651,40 @@ static void sky2_tx_timeout(struct net_device *dev)
1651 struct sky2_port *sky2 = netdev_priv(dev); 1651 struct sky2_port *sky2 = netdev_priv(dev);
1652 struct sky2_hw *hw = sky2->hw; 1652 struct sky2_hw *hw = sky2->hw;
1653 unsigned txq = txqaddr[sky2->port]; 1653 unsigned txq = txqaddr[sky2->port];
1654 u16 report, done;
1654 1655
1655 if (netif_msg_timer(sky2)) 1656 if (netif_msg_timer(sky2))
1656 printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); 1657 printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
1657 1658
1658 sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); 1659 report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
1659 sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); 1660 done = sky2_read16(hw, Q_ADDR(txq, Q_DONE));
1660 1661
1661 sky2_tx_clean(sky2); 1662 printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
1663 dev->name,
1664 sky2->tx_cons, sky2->tx_prod, report, done);
1665
1666 if (report != done) {
1667 printk(KERN_INFO PFX "status burst pending (irq moderation?)\n");
1668
1669 sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
1670 sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
1671 } else if (report != sky2->tx_cons) {
1672 printk(KERN_INFO PFX "status report lost?\n");
1662 1673
1663 sky2_qset(hw, txq); 1674 spin_lock_bh(&sky2->tx_lock);
1664 sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); 1675 sky2_tx_complete(sky2, report);
1676 spin_unlock_bh(&sky2->tx_lock);
1677 } else {
1678 printk(KERN_INFO PFX "hardware hung? flushing\n");
1679
1680 sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
1681 sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
1682
1683 sky2_tx_clean(sky2);
1684
1685 sky2_qset(hw, txq);
1686 sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
1687 }
1665} 1688}
1666 1689
1667 1690
@@ -2097,6 +2120,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
2097 prefetch(&hw->st_le[hw->st_idx]); 2120 prefetch(&hw->st_le[hw->st_idx]);
2098 if (likely(__netif_rx_schedule_prep(dev0))) 2121 if (likely(__netif_rx_schedule_prep(dev0)))
2099 __netif_rx_schedule(dev0); 2122 __netif_rx_schedule(dev0);
2123 else
2124 printk(KERN_DEBUG PFX "irq race detected\n");
2100 2125
2101 return IRQ_HANDLED; 2126 return IRQ_HANDLED;
2102} 2127}