aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFrancois Romieu <romieu@fr.zoreil.com>2006-01-30 19:04:33 -0500
committerFrancois Romieu <romieu@electric-eye.fr.zoreil.com>2006-02-01 16:04:37 -0500
commit371e8bc2af11b0571982390932bc07b5ffed9aba (patch)
treebf474e4de38792fc48833f26cabff286c0f50573 /drivers
parent8351538db6613f40089789ec90e1b58304eb7ffd (diff)
8139too: fix a TX timeout watchdog thread against NAPI softirq race
Ingo's stealth lock validator detected that both thread acquire dev->xmit_lock and tp->rx_lock in reverse order. Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/8139too.c38
1 files changed, 26 insertions, 12 deletions
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index adfba44dac5a..2beac55b57d6 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -586,6 +586,7 @@ struct rtl8139_private {
586 dma_addr_t tx_bufs_dma; 586 dma_addr_t tx_bufs_dma;
587 signed char phys[4]; /* MII device addresses. */ 587 signed char phys[4]; /* MII device addresses. */
588 char twistie, twist_row, twist_col; /* Twister tune state. */ 588 char twistie, twist_row, twist_col; /* Twister tune state. */
589 unsigned int watchdog_fired : 1;
589 unsigned int default_port : 4; /* Last dev->if_port value. */ 590 unsigned int default_port : 4; /* Last dev->if_port value. */
590 unsigned int have_thread : 1; 591 unsigned int have_thread : 1;
591 spinlock_t lock; 592 spinlock_t lock;
@@ -638,6 +639,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev);
638static void __set_rx_mode (struct net_device *dev); 639static void __set_rx_mode (struct net_device *dev);
639static void rtl8139_hw_start (struct net_device *dev); 640static void rtl8139_hw_start (struct net_device *dev);
640static void rtl8139_thread (void *_data); 641static void rtl8139_thread (void *_data);
642static void rtl8139_tx_timeout_task(void *_data);
641static struct ethtool_ops rtl8139_ethtool_ops; 643static struct ethtool_ops rtl8139_ethtool_ops;
642 644
643/* write MMIO register, with flush */ 645/* write MMIO register, with flush */
@@ -1598,13 +1600,14 @@ static void rtl8139_thread (void *_data)
1598{ 1600{
1599 struct net_device *dev = _data; 1601 struct net_device *dev = _data;
1600 struct rtl8139_private *tp = netdev_priv(dev); 1602 struct rtl8139_private *tp = netdev_priv(dev);
1601 unsigned long thr_delay; 1603 unsigned long thr_delay = next_tick;
1602 1604
1603 if (rtnl_shlock_nowait() == 0) { 1605 if (tp->watchdog_fired) {
1606 tp->watchdog_fired = 0;
1607 rtl8139_tx_timeout_task(_data);
1608 } else if (rtnl_shlock_nowait() == 0) {
1604 rtl8139_thread_iter (dev, tp, tp->mmio_addr); 1609 rtl8139_thread_iter (dev, tp, tp->mmio_addr);
1605 rtnl_unlock (); 1610 rtnl_unlock ();
1606
1607 thr_delay = next_tick;
1608 } else { 1611 } else {
1609 /* unlikely race. mitigate with fast poll. */ 1612 /* unlikely race. mitigate with fast poll. */
1610 thr_delay = HZ / 2; 1613 thr_delay = HZ / 2;
@@ -1631,7 +1634,8 @@ static void rtl8139_stop_thread(struct rtl8139_private *tp)
1631 if (tp->have_thread) { 1634 if (tp->have_thread) {
1632 cancel_rearming_delayed_work(&tp->thread); 1635 cancel_rearming_delayed_work(&tp->thread);
1633 tp->have_thread = 0; 1636 tp->have_thread = 0;
1634 } 1637 } else
1638 flush_scheduled_work();
1635} 1639}
1636 1640
1637static inline void rtl8139_tx_clear (struct rtl8139_private *tp) 1641static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
@@ -1642,14 +1646,13 @@ static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
1642 /* XXX account for unsent Tx packets in tp->stats.tx_dropped */ 1646 /* XXX account for unsent Tx packets in tp->stats.tx_dropped */
1643} 1647}
1644 1648
1645 1649static void rtl8139_tx_timeout_task (void *_data)
1646static void rtl8139_tx_timeout (struct net_device *dev)
1647{ 1650{
1651 struct net_device *dev = _data;
1648 struct rtl8139_private *tp = netdev_priv(dev); 1652 struct rtl8139_private *tp = netdev_priv(dev);
1649 void __iomem *ioaddr = tp->mmio_addr; 1653 void __iomem *ioaddr = tp->mmio_addr;
1650 int i; 1654 int i;
1651 u8 tmp8; 1655 u8 tmp8;
1652 unsigned long flags;
1653 1656
1654 printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x " 1657 printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x "
1655 "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd), 1658 "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd),
@@ -1670,23 +1673,34 @@ static void rtl8139_tx_timeout (struct net_device *dev)
1670 if (tmp8 & CmdTxEnb) 1673 if (tmp8 & CmdTxEnb)
1671 RTL_W8 (ChipCmd, CmdRxEnb); 1674 RTL_W8 (ChipCmd, CmdRxEnb);
1672 1675
1673 spin_lock(&tp->rx_lock); 1676 spin_lock_bh(&tp->rx_lock);
1674 /* Disable interrupts by clearing the interrupt mask. */ 1677 /* Disable interrupts by clearing the interrupt mask. */
1675 RTL_W16 (IntrMask, 0x0000); 1678 RTL_W16 (IntrMask, 0x0000);
1676 1679
1677 /* Stop a shared interrupt from scavenging while we are. */ 1680 /* Stop a shared interrupt from scavenging while we are. */
1678 spin_lock_irqsave (&tp->lock, flags); 1681 spin_lock_irq(&tp->lock);
1679 rtl8139_tx_clear (tp); 1682 rtl8139_tx_clear (tp);
1680 spin_unlock_irqrestore (&tp->lock, flags); 1683 spin_unlock_irq(&tp->lock);
1681 1684
1682 /* ...and finally, reset everything */ 1685 /* ...and finally, reset everything */
1683 if (netif_running(dev)) { 1686 if (netif_running(dev)) {
1684 rtl8139_hw_start (dev); 1687 rtl8139_hw_start (dev);
1685 netif_wake_queue (dev); 1688 netif_wake_queue (dev);
1686 } 1689 }
1687 spin_unlock(&tp->rx_lock); 1690 spin_unlock_bh(&tp->rx_lock);
1688} 1691}
1689 1692
1693static void rtl8139_tx_timeout (struct net_device *dev)
1694{
1695 struct rtl8139_private *tp = netdev_priv(dev);
1696
1697 if (!tp->have_thread) {
1698 INIT_WORK(&tp->thread, rtl8139_tx_timeout_task, dev);
1699 schedule_delayed_work(&tp->thread, next_tick);
1700 } else
1701 tp->watchdog_fired = 1;
1702
1703}
1690 1704
1691static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) 1705static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
1692{ 1706{