diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-01-17 16:43:20 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-17 19:27:30 -0500 |
commit | 302d12522a36790858ce93b69ebf2220f9e5173a (patch) | |
tree | 29b049801298aff6e889f9c15bcd5963cb33aebc /drivers/net | |
parent | 28bd181a8e4abf1126de56f0934ba7c910276475 (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.c | 43 |
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 | ||
901 | static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) | 901 | static 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 */ |
1319 | static void sky2_tx_clean(struct sky2_port *sky2) | 1321 | static 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 | */ | ||
1611 | static void sky2_tx_timeout(struct net_device *dev) | 1619 | static 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 | } |