diff options
author | Daniel Pieczko <dpieczko@solarflare.com> | 2012-10-17 08:21:23 -0400 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-11-30 21:37:35 -0500 |
commit | c2f3b8e3a44b6fe9e36704e30157ebe1a88c08b1 (patch) | |
tree | a33870250f24b7b832a52bb039aee7f4b20d842b /drivers/net/ethernet/sfc | |
parent | 525d9e824018cd7cc8d8d44832ddcd363abfe6e1 (diff) |
sfc: lock TX queues when calling netif_device_detach()
The assertion of netif_device_present() at the top of
efx_hard_start_xmit() may fail if we don't do this.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.h | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/selftest.c | 2 |
3 files changed, 16 insertions, 3 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 4f86d0cd516a..6f073d014ad3 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -2279,7 +2279,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method) | |||
2279 | netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", | 2279 | netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", |
2280 | RESET_TYPE(method)); | 2280 | RESET_TYPE(method)); |
2281 | 2281 | ||
2282 | netif_device_detach(efx->net_dev); | 2282 | efx_device_detach_sync(efx); |
2283 | efx_reset_down(efx, method); | 2283 | efx_reset_down(efx, method); |
2284 | 2284 | ||
2285 | rc = efx->type->reset(efx, method); | 2285 | rc = efx->type->reset(efx, method); |
@@ -2758,7 +2758,7 @@ static int efx_pm_freeze(struct device *dev) | |||
2758 | if (efx->state != STATE_DISABLED) { | 2758 | if (efx->state != STATE_DISABLED) { |
2759 | efx->state = STATE_UNINIT; | 2759 | efx->state = STATE_UNINIT; |
2760 | 2760 | ||
2761 | netif_device_detach(efx->net_dev); | 2761 | efx_device_detach_sync(efx); |
2762 | 2762 | ||
2763 | efx_stop_all(efx); | 2763 | efx_stop_all(efx); |
2764 | efx_stop_interrupts(efx, false); | 2764 | efx_stop_interrupts(efx, false); |
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index f11170bc48bf..50247dfe8f57 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h | |||
@@ -163,4 +163,17 @@ extern void efx_link_status_changed(struct efx_nic *efx); | |||
163 | extern void efx_link_set_advertising(struct efx_nic *efx, u32); | 163 | extern void efx_link_set_advertising(struct efx_nic *efx, u32); |
164 | extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8); | 164 | extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8); |
165 | 165 | ||
166 | static inline void efx_device_detach_sync(struct efx_nic *efx) | ||
167 | { | ||
168 | struct net_device *dev = efx->net_dev; | ||
169 | |||
170 | /* Lock/freeze all TX queues so that we can be sure the | ||
171 | * TX scheduler is stopped when we're done and before | ||
172 | * netif_device_present() becomes false. | ||
173 | */ | ||
174 | netif_tx_lock(dev); | ||
175 | netif_device_detach(dev); | ||
176 | netif_tx_unlock(dev); | ||
177 | } | ||
178 | |||
166 | #endif /* EFX_EFX_H */ | 179 | #endif /* EFX_EFX_H */ |
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index f6651d35d615..2069f51b2aa9 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c | |||
@@ -722,7 +722,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
722 | /* Detach the device so the kernel doesn't transmit during the | 722 | /* Detach the device so the kernel doesn't transmit during the |
723 | * loopback test and the watchdog timeout doesn't fire. | 723 | * loopback test and the watchdog timeout doesn't fire. |
724 | */ | 724 | */ |
725 | netif_device_detach(efx->net_dev); | 725 | efx_device_detach_sync(efx); |
726 | 726 | ||
727 | if (efx->type->test_chip) { | 727 | if (efx->type->test_chip) { |
728 | rc_reset = efx->type->test_chip(efx, tests); | 728 | rc_reset = efx->type->test_chip(efx, tests); |