aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancois Romieu <romieu@fr.zoreil.com>2007-02-15 17:37:44 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-20 11:18:12 -0500
commit83cbb4d2577174e27a91e63a47a2a27c3af50d4e (patch)
tree115297292e852d352ca21b3ce66fd2f46e4d9bd6
parentc014f6c8f870271a8dcfe6e4139d6a651633aaf4 (diff)
8139too: RTNL and flush_scheduled_work deadlock
Your usual dont-flush_scheduled_work-with-RTNL-held stuff. It is a bit different here since the thread runs permanently or is only occasionally kicked for recovery depending on the hardware revision. Signed-off-by: Francois Romieu <romieu@fr.zoreil.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/net/8139too.c40
1 files changed, 17 insertions, 23 deletions
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 35ad5cff18e6..99304b2aa86e 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1109,6 +1109,8 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
1109 1109
1110 assert (dev != NULL); 1110 assert (dev != NULL);
1111 1111
1112 flush_scheduled_work();
1113
1112 unregister_netdev (dev); 1114 unregister_netdev (dev);
1113 1115
1114 __rtl8139_cleanup_dev (dev); 1116 __rtl8139_cleanup_dev (dev);
@@ -1603,18 +1605,21 @@ static void rtl8139_thread (struct work_struct *work)
1603 struct net_device *dev = tp->mii.dev; 1605 struct net_device *dev = tp->mii.dev;
1604 unsigned long thr_delay = next_tick; 1606 unsigned long thr_delay = next_tick;
1605 1607
1608 rtnl_lock();
1609
1610 if (!netif_running(dev))
1611 goto out_unlock;
1612
1606 if (tp->watchdog_fired) { 1613 if (tp->watchdog_fired) {
1607 tp->watchdog_fired = 0; 1614 tp->watchdog_fired = 0;
1608 rtl8139_tx_timeout_task(work); 1615 rtl8139_tx_timeout_task(work);
1609 } else if (rtnl_trylock()) { 1616 } else
1610 rtl8139_thread_iter (dev, tp, tp->mmio_addr); 1617 rtl8139_thread_iter(dev, tp, tp->mmio_addr);
1611 rtnl_unlock ();
1612 } else {
1613 /* unlikely race. mitigate with fast poll. */
1614 thr_delay = HZ / 2;
1615 }
1616 1618
1617 schedule_delayed_work(&tp->thread, thr_delay); 1619 if (tp->have_thread)
1620 schedule_delayed_work(&tp->thread, thr_delay);
1621out_unlock:
1622 rtnl_unlock ();
1618} 1623}
1619 1624
1620static void rtl8139_start_thread(struct rtl8139_private *tp) 1625static void rtl8139_start_thread(struct rtl8139_private *tp)
@@ -1626,19 +1631,11 @@ static void rtl8139_start_thread(struct rtl8139_private *tp)
1626 return; 1631 return;
1627 1632
1628 tp->have_thread = 1; 1633 tp->have_thread = 1;
1634 tp->watchdog_fired = 0;
1629 1635
1630 schedule_delayed_work(&tp->thread, next_tick); 1636 schedule_delayed_work(&tp->thread, next_tick);
1631} 1637}
1632 1638
1633static void rtl8139_stop_thread(struct rtl8139_private *tp)
1634{
1635 if (tp->have_thread) {
1636 cancel_rearming_delayed_work(&tp->thread);
1637 tp->have_thread = 0;
1638 } else
1639 flush_scheduled_work();
1640}
1641
1642static inline void rtl8139_tx_clear (struct rtl8139_private *tp) 1639static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
1643{ 1640{
1644 tp->cur_tx = 0; 1641 tp->cur_tx = 0;
@@ -1696,12 +1693,11 @@ static void rtl8139_tx_timeout (struct net_device *dev)
1696{ 1693{
1697 struct rtl8139_private *tp = netdev_priv(dev); 1694 struct rtl8139_private *tp = netdev_priv(dev);
1698 1695
1696 tp->watchdog_fired = 1;
1699 if (!tp->have_thread) { 1697 if (!tp->have_thread) {
1700 INIT_DELAYED_WORK(&tp->thread, rtl8139_tx_timeout_task); 1698 INIT_DELAYED_WORK(&tp->thread, rtl8139_thread);
1701 schedule_delayed_work(&tp->thread, next_tick); 1699 schedule_delayed_work(&tp->thread, next_tick);
1702 } else 1700 }
1703 tp->watchdog_fired = 1;
1704
1705} 1701}
1706 1702
1707static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) 1703static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
@@ -2233,8 +2229,6 @@ static int rtl8139_close (struct net_device *dev)
2233 2229
2234 netif_stop_queue (dev); 2230 netif_stop_queue (dev);
2235 2231
2236 rtl8139_stop_thread(tp);
2237
2238 if (netif_msg_ifdown(tp)) 2232 if (netif_msg_ifdown(tp))
2239 printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", 2233 printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
2240 dev->name, RTL_R16 (IntrStatus)); 2234 dev->name, RTL_R16 (IntrStatus));