diff options
author | Auke Kok <auke-jan.h.kok@intel.com> | 2006-06-27 12:06:28 -0400 |
---|---|---|
committer | Auke Kok <juke-jan.h.kok@intel.com> | 2006-06-27 12:06:28 -0400 |
commit | 2db10a081c5c1082d58809a1bcf1a6073f4db160 (patch) | |
tree | f54772ef60f2c5bf5f8d602a83d6dc508158a0e0 /drivers/net/e1000/e1000_ethtool.c | |
parent | acfbc9fde2ec7f304398f6ad7644002e07bf84bc (diff) |
e1000: rework driver hardware reset locking
After studying the driver mac reset code it was found that there
were multiple race conditions possible to reset the unit twice or
bring it e1000_up() double. This fixes all occurences where the
driver needs to reset the mac.
We also remove irq requesting/releasing into _open and _close so
that while the device is _up we will never touch the irq's. This fixes
the double free irq bug that people saw.
To make sure that the watchdog task doesn't cause another race we let
it run as a non-scheduled task.
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Diffstat (limited to 'drivers/net/e1000/e1000_ethtool.c')
-rw-r--r-- | drivers/net/e1000/e1000_ethtool.c | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 845d293b2f6a..cf5c5f46341f 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c | |||
@@ -203,11 +203,9 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |||
203 | 203 | ||
204 | /* reset the link */ | 204 | /* reset the link */ |
205 | 205 | ||
206 | if (netif_running(adapter->netdev)) { | 206 | if (netif_running(adapter->netdev)) |
207 | e1000_down(adapter); | 207 | e1000_reinit_locked(adapter); |
208 | e1000_reset(adapter); | 208 | else |
209 | e1000_up(adapter); | ||
210 | } else | ||
211 | e1000_reset(adapter); | 209 | e1000_reset(adapter); |
212 | 210 | ||
213 | return 0; | 211 | return 0; |
@@ -254,10 +252,9 @@ e1000_set_pauseparam(struct net_device *netdev, | |||
254 | hw->original_fc = hw->fc; | 252 | hw->original_fc = hw->fc; |
255 | 253 | ||
256 | if (adapter->fc_autoneg == AUTONEG_ENABLE) { | 254 | if (adapter->fc_autoneg == AUTONEG_ENABLE) { |
257 | if (netif_running(adapter->netdev)) { | 255 | if (netif_running(adapter->netdev)) |
258 | e1000_down(adapter); | 256 | e1000_reinit_locked(adapter); |
259 | e1000_up(adapter); | 257 | else |
260 | } else | ||
261 | e1000_reset(adapter); | 258 | e1000_reset(adapter); |
262 | } else | 259 | } else |
263 | return ((hw->media_type == e1000_media_type_fiber) ? | 260 | return ((hw->media_type == e1000_media_type_fiber) ? |
@@ -279,10 +276,9 @@ e1000_set_rx_csum(struct net_device *netdev, uint32_t data) | |||
279 | struct e1000_adapter *adapter = netdev_priv(netdev); | 276 | struct e1000_adapter *adapter = netdev_priv(netdev); |
280 | adapter->rx_csum = data; | 277 | adapter->rx_csum = data; |
281 | 278 | ||
282 | if (netif_running(netdev)) { | 279 | if (netif_running(netdev)) |
283 | e1000_down(adapter); | 280 | e1000_reinit_locked(adapter); |
284 | e1000_up(adapter); | 281 | else |
285 | } else | ||
286 | e1000_reset(adapter); | 282 | e1000_reset(adapter); |
287 | return 0; | 283 | return 0; |
288 | } | 284 | } |
@@ -631,6 +627,9 @@ e1000_set_ringparam(struct net_device *netdev, | |||
631 | tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; | 627 | tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; |
632 | rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; | 628 | rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; |
633 | 629 | ||
630 | while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) | ||
631 | msleep(1); | ||
632 | |||
634 | if (netif_running(adapter->netdev)) | 633 | if (netif_running(adapter->netdev)) |
635 | e1000_down(adapter); | 634 | e1000_down(adapter); |
636 | 635 | ||
@@ -691,9 +690,11 @@ e1000_set_ringparam(struct net_device *netdev, | |||
691 | adapter->rx_ring = rx_new; | 690 | adapter->rx_ring = rx_new; |
692 | adapter->tx_ring = tx_new; | 691 | adapter->tx_ring = tx_new; |
693 | if ((err = e1000_up(adapter))) | 692 | if ((err = e1000_up(adapter))) |
694 | return err; | 693 | goto err_setup; |
695 | } | 694 | } |
696 | 695 | ||
696 | clear_bit(__E1000_RESETTING, &adapter->flags); | ||
697 | |||
697 | return 0; | 698 | return 0; |
698 | err_setup_tx: | 699 | err_setup_tx: |
699 | e1000_free_all_rx_resources(adapter); | 700 | e1000_free_all_rx_resources(adapter); |
@@ -701,6 +702,8 @@ err_setup_rx: | |||
701 | adapter->rx_ring = rx_old; | 702 | adapter->rx_ring = rx_old; |
702 | adapter->tx_ring = tx_old; | 703 | adapter->tx_ring = tx_old; |
703 | e1000_up(adapter); | 704 | e1000_up(adapter); |
705 | err_setup: | ||
706 | clear_bit(__E1000_RESETTING, &adapter->flags); | ||
704 | return err; | 707 | return err; |
705 | } | 708 | } |
706 | 709 | ||
@@ -1568,6 +1571,7 @@ e1000_diag_test(struct net_device *netdev, | |||
1568 | struct e1000_adapter *adapter = netdev_priv(netdev); | 1571 | struct e1000_adapter *adapter = netdev_priv(netdev); |
1569 | boolean_t if_running = netif_running(netdev); | 1572 | boolean_t if_running = netif_running(netdev); |
1570 | 1573 | ||
1574 | set_bit(__E1000_DRIVER_TESTING, &adapter->flags); | ||
1571 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { | 1575 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { |
1572 | /* Offline tests */ | 1576 | /* Offline tests */ |
1573 | 1577 | ||
@@ -1582,7 +1586,8 @@ e1000_diag_test(struct net_device *netdev, | |||
1582 | eth_test->flags |= ETH_TEST_FL_FAILED; | 1586 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1583 | 1587 | ||
1584 | if (if_running) | 1588 | if (if_running) |
1585 | e1000_down(adapter); | 1589 | /* indicate we're in test mode */ |
1590 | dev_close(netdev); | ||
1586 | else | 1591 | else |
1587 | e1000_reset(adapter); | 1592 | e1000_reset(adapter); |
1588 | 1593 | ||
@@ -1607,8 +1612,9 @@ e1000_diag_test(struct net_device *netdev, | |||
1607 | adapter->hw.autoneg = autoneg; | 1612 | adapter->hw.autoneg = autoneg; |
1608 | 1613 | ||
1609 | e1000_reset(adapter); | 1614 | e1000_reset(adapter); |
1615 | clear_bit(__E1000_DRIVER_TESTING, &adapter->flags); | ||
1610 | if (if_running) | 1616 | if (if_running) |
1611 | e1000_up(adapter); | 1617 | dev_open(netdev); |
1612 | } else { | 1618 | } else { |
1613 | /* Online tests */ | 1619 | /* Online tests */ |
1614 | if (e1000_link_test(adapter, &data[4])) | 1620 | if (e1000_link_test(adapter, &data[4])) |
@@ -1619,6 +1625,8 @@ e1000_diag_test(struct net_device *netdev, | |||
1619 | data[1] = 0; | 1625 | data[1] = 0; |
1620 | data[2] = 0; | 1626 | data[2] = 0; |
1621 | data[3] = 0; | 1627 | data[3] = 0; |
1628 | |||
1629 | clear_bit(__E1000_DRIVER_TESTING, &adapter->flags); | ||
1622 | } | 1630 | } |
1623 | msleep_interruptible(4 * 1000); | 1631 | msleep_interruptible(4 * 1000); |
1624 | } | 1632 | } |
@@ -1807,10 +1815,8 @@ static int | |||
1807 | e1000_nway_reset(struct net_device *netdev) | 1815 | e1000_nway_reset(struct net_device *netdev) |
1808 | { | 1816 | { |
1809 | struct e1000_adapter *adapter = netdev_priv(netdev); | 1817 | struct e1000_adapter *adapter = netdev_priv(netdev); |
1810 | if (netif_running(netdev)) { | 1818 | if (netif_running(netdev)) |
1811 | e1000_down(adapter); | 1819 | e1000_reinit_locked(adapter); |
1812 | e1000_up(adapter); | ||
1813 | } | ||
1814 | return 0; | 1820 | return 0; |
1815 | } | 1821 | } |
1816 | 1822 | ||