diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-10-17 16:26:42 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-17 20:17:34 -0400 |
commit | 6de16237c78a9df6c7cb2d1b3bbd788322ecb344 (patch) | |
tree | 8315150fd91c39a6f7763ab87150e963d4039a5f | |
parent | c264c3dee9f20bad1f42ef5821300791291d0f77 (diff) |
sky2: shutdown cleanup
Solve issues with dual port devices due to shared NAPI.
* shutting down one device shouldn't kill other one.
* suspend shouldn't hang.
Also fix potential race between restart and shutdown.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/net/sky2.c | 46 |
1 files changed, 20 insertions, 26 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7967240534d5..6b2fc508fe00 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -1384,13 +1384,9 @@ static int sky2_up(struct net_device *dev) | |||
1384 | sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, | 1384 | sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, |
1385 | TX_RING_SIZE - 1); | 1385 | TX_RING_SIZE - 1); |
1386 | 1386 | ||
1387 | napi_enable(&hw->napi); | ||
1388 | |||
1389 | err = sky2_rx_start(sky2); | 1387 | err = sky2_rx_start(sky2); |
1390 | if (err) { | 1388 | if (err) |
1391 | napi_disable(&hw->napi); | ||
1392 | goto err_out; | 1389 | goto err_out; |
1393 | } | ||
1394 | 1390 | ||
1395 | /* Enable interrupts from phy/mac for port */ | 1391 | /* Enable interrupts from phy/mac for port */ |
1396 | imask = sky2_read32(hw, B0_IMSK); | 1392 | imask = sky2_read32(hw, B0_IMSK); |
@@ -1679,13 +1675,13 @@ static int sky2_down(struct net_device *dev) | |||
1679 | /* Stop more packets from being queued */ | 1675 | /* Stop more packets from being queued */ |
1680 | netif_stop_queue(dev); | 1676 | netif_stop_queue(dev); |
1681 | 1677 | ||
1682 | napi_disable(&hw->napi); | ||
1683 | |||
1684 | /* Disable port IRQ */ | 1678 | /* Disable port IRQ */ |
1685 | imask = sky2_read32(hw, B0_IMSK); | 1679 | imask = sky2_read32(hw, B0_IMSK); |
1686 | imask &= ~portirq_msk[port]; | 1680 | imask &= ~portirq_msk[port]; |
1687 | sky2_write32(hw, B0_IMSK, imask); | 1681 | sky2_write32(hw, B0_IMSK, imask); |
1688 | 1682 | ||
1683 | synchronize_irq(hw->pdev->irq); | ||
1684 | |||
1689 | sky2_gmac_reset(hw, port); | 1685 | sky2_gmac_reset(hw, port); |
1690 | 1686 | ||
1691 | /* Stop transmitter */ | 1687 | /* Stop transmitter */ |
@@ -1699,6 +1695,9 @@ static int sky2_down(struct net_device *dev) | |||
1699 | ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA); | 1695 | ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA); |
1700 | gma_write16(hw, port, GM_GP_CTRL, ctrl); | 1696 | gma_write16(hw, port, GM_GP_CTRL, ctrl); |
1701 | 1697 | ||
1698 | /* Make sure no packets are pending */ | ||
1699 | napi_synchronize(&hw->napi); | ||
1700 | |||
1702 | sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); | 1701 | sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); |
1703 | 1702 | ||
1704 | /* Workaround shared GMAC reset */ | 1703 | /* Workaround shared GMAC reset */ |
@@ -1736,8 +1735,6 @@ static int sky2_down(struct net_device *dev) | |||
1736 | /* turn off LED's */ | 1735 | /* turn off LED's */ |
1737 | sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); | 1736 | sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); |
1738 | 1737 | ||
1739 | synchronize_irq(hw->pdev->irq); | ||
1740 | |||
1741 | sky2_tx_clean(dev); | 1738 | sky2_tx_clean(dev); |
1742 | sky2_rx_clean(sky2); | 1739 | sky2_rx_clean(sky2); |
1743 | 1740 | ||
@@ -2048,9 +2045,6 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) | |||
2048 | err = sky2_rx_start(sky2); | 2045 | err = sky2_rx_start(sky2); |
2049 | sky2_write32(hw, B0_IMSK, imask); | 2046 | sky2_write32(hw, B0_IMSK, imask); |
2050 | 2047 | ||
2051 | /* Unconditionally re-enable NAPI because even if we | ||
2052 | * call dev_close() that will do a napi_disable(). | ||
2053 | */ | ||
2054 | napi_enable(&hw->napi); | 2048 | napi_enable(&hw->napi); |
2055 | 2049 | ||
2056 | if (err) | 2050 | if (err) |
@@ -2915,6 +2909,7 @@ static void sky2_restart(struct work_struct *work) | |||
2915 | rtnl_lock(); | 2909 | rtnl_lock(); |
2916 | sky2_write32(hw, B0_IMSK, 0); | 2910 | sky2_write32(hw, B0_IMSK, 0); |
2917 | sky2_read32(hw, B0_IMSK); | 2911 | sky2_read32(hw, B0_IMSK); |
2912 | napi_disable(&hw->napi); | ||
2918 | 2913 | ||
2919 | for (i = 0; i < hw->ports; i++) { | 2914 | for (i = 0; i < hw->ports; i++) { |
2920 | dev = hw->dev[i]; | 2915 | dev = hw->dev[i]; |
@@ -2924,6 +2919,7 @@ static void sky2_restart(struct work_struct *work) | |||
2924 | 2919 | ||
2925 | sky2_reset(hw); | 2920 | sky2_reset(hw); |
2926 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); | 2921 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); |
2922 | napi_enable(&hw->napi); | ||
2927 | 2923 | ||
2928 | for (i = 0; i < hw->ports; i++) { | 2924 | for (i = 0; i < hw->ports; i++) { |
2929 | dev = hw->dev[i]; | 2925 | dev = hw->dev[i]; |
@@ -4191,7 +4187,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
4191 | err = -ENOMEM; | 4187 | err = -ENOMEM; |
4192 | goto err_out_free_pci; | 4188 | goto err_out_free_pci; |
4193 | } | 4189 | } |
4194 | netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT); | ||
4195 | 4190 | ||
4196 | if (!disable_msi && pci_enable_msi(pdev) == 0) { | 4191 | if (!disable_msi && pci_enable_msi(pdev) == 0) { |
4197 | err = sky2_test_msi(hw); | 4192 | err = sky2_test_msi(hw); |
@@ -4207,6 +4202,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
4207 | goto err_out_free_netdev; | 4202 | goto err_out_free_netdev; |
4208 | } | 4203 | } |
4209 | 4204 | ||
4205 | netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT); | ||
4206 | |||
4210 | err = request_irq(pdev->irq, sky2_intr, | 4207 | err = request_irq(pdev->irq, sky2_intr, |
4211 | (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED, | 4208 | (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED, |
4212 | dev->name, hw); | 4209 | dev->name, hw); |
@@ -4215,6 +4212,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
4215 | goto err_out_unregister; | 4212 | goto err_out_unregister; |
4216 | } | 4213 | } |
4217 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); | 4214 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); |
4215 | napi_enable(&hw->napi); | ||
4218 | 4216 | ||
4219 | sky2_show_addr(dev); | 4217 | sky2_show_addr(dev); |
4220 | 4218 | ||
@@ -4265,23 +4263,18 @@ err_out: | |||
4265 | static void __devexit sky2_remove(struct pci_dev *pdev) | 4263 | static void __devexit sky2_remove(struct pci_dev *pdev) |
4266 | { | 4264 | { |
4267 | struct sky2_hw *hw = pci_get_drvdata(pdev); | 4265 | struct sky2_hw *hw = pci_get_drvdata(pdev); |
4268 | struct net_device *dev0, *dev1; | 4266 | int i; |
4269 | 4267 | ||
4270 | if (!hw) | 4268 | if (!hw) |
4271 | return; | 4269 | return; |
4272 | 4270 | ||
4273 | del_timer_sync(&hw->watchdog_timer); | 4271 | del_timer_sync(&hw->watchdog_timer); |
4272 | cancel_work_sync(&hw->restart_work); | ||
4274 | 4273 | ||
4275 | flush_scheduled_work(); | 4274 | for (i = hw->ports; i >= 0; --i) |
4275 | unregister_netdev(hw->dev[i]); | ||
4276 | 4276 | ||
4277 | sky2_write32(hw, B0_IMSK, 0); | 4277 | sky2_write32(hw, B0_IMSK, 0); |
4278 | synchronize_irq(hw->pdev->irq); | ||
4279 | |||
4280 | dev0 = hw->dev[0]; | ||
4281 | dev1 = hw->dev[1]; | ||
4282 | if (dev1) | ||
4283 | unregister_netdev(dev1); | ||
4284 | unregister_netdev(dev0); | ||
4285 | 4278 | ||
4286 | sky2_power_aux(hw); | 4279 | sky2_power_aux(hw); |
4287 | 4280 | ||
@@ -4296,9 +4289,9 @@ static void __devexit sky2_remove(struct pci_dev *pdev) | |||
4296 | pci_release_regions(pdev); | 4289 | pci_release_regions(pdev); |
4297 | pci_disable_device(pdev); | 4290 | pci_disable_device(pdev); |
4298 | 4291 | ||
4299 | if (dev1) | 4292 | for (i = hw->ports; i >= 0; --i) |
4300 | free_netdev(dev1); | 4293 | free_netdev(hw->dev[i]); |
4301 | free_netdev(dev0); | 4294 | |
4302 | iounmap(hw->regs); | 4295 | iounmap(hw->regs); |
4303 | kfree(hw); | 4296 | kfree(hw); |
4304 | 4297 | ||
@@ -4328,6 +4321,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) | |||
4328 | } | 4321 | } |
4329 | 4322 | ||
4330 | sky2_write32(hw, B0_IMSK, 0); | 4323 | sky2_write32(hw, B0_IMSK, 0); |
4324 | napi_disable(&hw->napi); | ||
4331 | sky2_power_aux(hw); | 4325 | sky2_power_aux(hw); |
4332 | 4326 | ||
4333 | pci_save_state(pdev); | 4327 | pci_save_state(pdev); |
@@ -4362,8 +4356,8 @@ static int sky2_resume(struct pci_dev *pdev) | |||
4362 | pci_write_config_dword(pdev, PCI_DEV_REG3, 0); | 4356 | pci_write_config_dword(pdev, PCI_DEV_REG3, 0); |
4363 | 4357 | ||
4364 | sky2_reset(hw); | 4358 | sky2_reset(hw); |
4365 | |||
4366 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); | 4359 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); |
4360 | napi_enable(&hw->napi); | ||
4367 | 4361 | ||
4368 | for (i = 0; i < hw->ports; i++) { | 4362 | for (i = 0; i < hw->ports; i++) { |
4369 | struct net_device *dev = hw->dev[i]; | 4363 | struct net_device *dev = hw->dev[i]; |