aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-02-16 18:37:39 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-20 11:18:13 -0500
commit208491d8f92e5aa129acb27e223e75d0173a3edd (patch)
treefaa36a58a552f2a4c36bdc362701e81d7e7d7261 /drivers/net
parent8b5b46718113166b5f6bcdf40e67ea867461e209 (diff)
skge: race with workq and RTNL
If a workqueue function that needs RTNL is running when skge_down is called then a deadlock is possible. Fix by only clearing the timer, and handling the flush_scheduled_work on removal. This work queue is only ever used for the old fiber based boards. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/skge.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index e482e7fcbb2b..c3d2e0a2c4e6 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -1419,7 +1419,8 @@ static void xm_link_timer(struct work_struct *work)
1419 mutex_unlock(&hw->phy_mutex); 1419 mutex_unlock(&hw->phy_mutex);
1420 1420
1421nochange: 1421nochange:
1422 schedule_delayed_work(&skge->link_thread, LINK_HZ); 1422 if (netif_running(dev))
1423 schedule_delayed_work(&skge->link_thread, LINK_HZ);
1423} 1424}
1424 1425
1425static void genesis_mac_init(struct skge_hw *hw, int port) 1426static void genesis_mac_init(struct skge_hw *hw, int port)
@@ -2530,7 +2531,7 @@ static int skge_down(struct net_device *dev)
2530 2531
2531 netif_stop_queue(dev); 2532 netif_stop_queue(dev);
2532 if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) 2533 if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
2533 cancel_rearming_delayed_work(&skge->link_thread); 2534 cancel_delayed_work(&skge->link_thread);
2534 2535
2535 skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); 2536 skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
2536 if (hw->chip_id == CHIP_ID_GENESIS) 2537 if (hw->chip_id == CHIP_ID_GENESIS)
@@ -3690,6 +3691,8 @@ static void __devexit skge_remove(struct pci_dev *pdev)
3690 if (!hw) 3691 if (!hw)
3691 return; 3692 return;
3692 3693
3694 flush_scheduled_work();
3695
3693 if ((dev1 = hw->dev[1])) 3696 if ((dev1 = hw->dev[1]))
3694 unregister_netdev(dev1); 3697 unregister_netdev(dev1);
3695 dev0 = hw->dev[0]; 3698 dev0 = hw->dev[0];
@@ -3704,8 +3707,6 @@ static void __devexit skge_remove(struct pci_dev *pdev)
3704 skge_write16(hw, B0_LED, LED_STAT_OFF); 3707 skge_write16(hw, B0_LED, LED_STAT_OFF);
3705 skge_write8(hw, B0_CTST, CS_RST_SET); 3708 skge_write8(hw, B0_CTST, CS_RST_SET);
3706 3709
3707 flush_scheduled_work();
3708
3709 free_irq(pdev->irq, hw); 3710 free_irq(pdev->irq, hw);
3710 pci_release_regions(pdev); 3711 pci_release_regions(pdev);
3711 pci_disable_device(pdev); 3712 pci_disable_device(pdev);