aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-01-17 16:43:20 -0500
committerJeff Garzik <jgarzik@pobox.com>2006-01-17 19:27:30 -0500
commit302d12522a36790858ce93b69ebf2220f9e5173a (patch)
tree29b049801298aff6e889f9c15bcd5963cb33aebc /drivers/net
parent28bd181a8e4abf1126de56f0934ba7c910276475 (diff)
[PATCH] sky2: more conservative transmit locking
Be more careful about transmit locking, this solves a possible race between tx_complete and transmit, that would cause a tx timeout. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/sky2.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index f03bf79ca1f5..0c7665e465db 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -889,13 +889,13 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
889 struct sky2_hw *hw = sky2->hw; 889 struct sky2_hw *hw = sky2->hw;
890 u16 port = sky2->port; 890 u16 port = sky2->port;
891 891
892 spin_lock(&sky2->tx_lock); 892 spin_lock_bh(&sky2->tx_lock);
893 893
894 sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON); 894 sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON);
895 sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON); 895 sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON);
896 sky2->vlgrp = grp; 896 sky2->vlgrp = grp;
897 897
898 spin_unlock(&sky2->tx_lock); 898 spin_unlock_bh(&sky2->tx_lock);
899} 899}
900 900
901static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) 901static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
@@ -904,14 +904,14 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
904 struct sky2_hw *hw = sky2->hw; 904 struct sky2_hw *hw = sky2->hw;
905 u16 port = sky2->port; 905 u16 port = sky2->port;
906 906
907 spin_lock(&sky2->tx_lock); 907 spin_lock_bh(&sky2->tx_lock);
908 908
909 sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); 909 sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF);
910 sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); 910 sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF);
911 if (sky2->vlgrp) 911 if (sky2->vlgrp)
912 sky2->vlgrp->vlan_devices[vid] = NULL; 912 sky2->vlgrp->vlan_devices[vid] = NULL;
913 913
914 spin_unlock(&sky2->tx_lock); 914 spin_unlock_bh(&sky2->tx_lock);
915} 915}
916#endif 916#endif
917 917
@@ -1116,6 +1116,10 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
1116 u16 mss; 1116 u16 mss;
1117 u8 ctrl; 1117 u8 ctrl;
1118 1118
1119 /* No BH disabling for tx_lock here. We are running in BH disabled
1120 * context and TX reclaim runs via poll inside of a software
1121 * interrupt, and no related locks in IRQ processing.
1122 */
1119 if (!spin_trylock(&sky2->tx_lock)) 1123 if (!spin_trylock(&sky2->tx_lock))
1120 return NETDEV_TX_LOCKED; 1124 return NETDEV_TX_LOCKED;
1121 1125
@@ -1308,17 +1312,17 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
1308 dev_kfree_skb_any(skb); 1312 dev_kfree_skb_any(skb);
1309 } 1313 }
1310 1314
1311 spin_lock(&sky2->tx_lock);
1312 sky2->tx_cons = put; 1315 sky2->tx_cons = put;
1313 if (netif_queue_stopped(dev) && tx_avail(sky2) > MAX_SKB_TX_LE) 1316 if (netif_queue_stopped(dev) && tx_avail(sky2) > MAX_SKB_TX_LE)
1314 netif_wake_queue(dev); 1317 netif_wake_queue(dev);
1315 spin_unlock(&sky2->tx_lock);
1316} 1318}
1317 1319
1318/* Cleanup all untransmitted buffers, assume transmitter not running */ 1320/* Cleanup all untransmitted buffers, assume transmitter not running */
1319static void sky2_tx_clean(struct sky2_port *sky2) 1321static void sky2_tx_clean(struct sky2_port *sky2)
1320{ 1322{
1323 spin_lock_bh(&sky2->tx_lock);
1321 sky2_tx_complete(sky2, sky2->tx_prod); 1324 sky2_tx_complete(sky2, sky2->tx_prod);
1325 spin_unlock_bh(&sky2->tx_lock);
1322} 1326}
1323 1327
1324/* Network shutdown */ 1328/* Network shutdown */
@@ -1608,28 +1612,40 @@ out:
1608 local_irq_enable(); 1612 local_irq_enable();
1609} 1613}
1610 1614
1615
1616/* Transmit timeout is only called if we are running, carries is up
1617 * and tx queue is full (stopped).
1618 */
1611static void sky2_tx_timeout(struct net_device *dev) 1619static void sky2_tx_timeout(struct net_device *dev)
1612{ 1620{
1613 struct sky2_port *sky2 = netdev_priv(dev); 1621 struct sky2_port *sky2 = netdev_priv(dev);
1614 struct sky2_hw *hw = sky2->hw; 1622 struct sky2_hw *hw = sky2->hw;
1615 unsigned txq = txqaddr[sky2->port]; 1623 unsigned txq = txqaddr[sky2->port];
1624 u16 ridx;
1625
1626 /* Maybe we just missed an status interrupt */
1627 spin_lock(&sky2->tx_lock);
1628 ridx = sky2_read16(hw,
1629 sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
1630 sky2_tx_complete(sky2, ridx);
1631 spin_unlock(&sky2->tx_lock);
1632
1633 if (!netif_queue_stopped(dev)) {
1634 if (net_ratelimit())
1635 pr_info(PFX "transmit interrupt missed? recovered\n");
1636 return;
1637 }
1616 1638
1617 if (netif_msg_timer(sky2)) 1639 if (netif_msg_timer(sky2))
1618 printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); 1640 printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
1619 1641
1620 netif_stop_queue(dev);
1621
1622 sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); 1642 sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
1623 sky2_read32(hw, Q_ADDR(txq, Q_CSR));
1624
1625 sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); 1643 sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
1626 1644
1627 sky2_tx_clean(sky2); 1645 sky2_tx_clean(sky2);
1628 1646
1629 sky2_qset(hw, txq); 1647 sky2_qset(hw, txq);
1630 sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); 1648 sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
1631
1632 netif_wake_queue(dev);
1633} 1649}
1634 1650
1635 1651
@@ -1798,7 +1814,10 @@ static void sky2_tx_check(struct sky2_hw *hw, int port, u16 last)
1798 struct net_device *dev = hw->dev[port]; 1814 struct net_device *dev = hw->dev[port];
1799 if (dev && netif_running(dev)) { 1815 if (dev && netif_running(dev)) {
1800 struct sky2_port *sky2 = netdev_priv(dev); 1816 struct sky2_port *sky2 = netdev_priv(dev);
1817
1818 spin_lock(&sky2->tx_lock);
1801 sky2_tx_complete(sky2, last); 1819 sky2_tx_complete(sky2, last);
1820 spin_unlock(&sky2->tx_lock);
1802 } 1821 }
1803 } 1822 }
1804} 1823}