Commit 0a8a03d9 authored by Ben Hutchings's avatar Ben Hutchings Committed by Ben Hutchings

sfc: Detach net device when stopping queues for reconfiguration

[ Upstream commit 29c69a48 ]

We must only ever stop TX queues when they are full or the net device
is not 'ready' so far as the net core, and specifically the watchdog,
is concerned.  Otherwise, the watchdog may fire *immediately* if no
packets have been added to the queue in the last 5 seconds.

The device is ready if all the following are true:

(a) It has a qdisc
(b) It is marked present
(c) It is running
(d) The link is reported up

(a) and (c) are normally true, and must not be changed by a driver.
(d) is under our control, but fake link changes may disturb userland.
This leaves (b).  We already mark the device absent during reset
and self-test, but we need to do the same during MTU changes and ring
reallocation.  We don't need to do this when the device is brought
down because then (c) is already false.
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 7a825480
...@@ -719,6 +719,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) ...@@ -719,6 +719,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
unsigned i; unsigned i;
int rc; int rc;
efx_device_detach_sync(efx);
efx_stop_all(efx); efx_stop_all(efx);
efx_fini_channels(efx); efx_fini_channels(efx);
...@@ -762,6 +763,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) ...@@ -762,6 +763,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
efx_init_channels(efx); efx_init_channels(efx);
efx_start_all(efx); efx_start_all(efx);
netif_device_attach(efx->net_dev);
return rc; return rc;
rollback: rollback:
...@@ -1530,8 +1532,12 @@ static void efx_stop_all(struct efx_nic *efx) ...@@ -1530,8 +1532,12 @@ static void efx_stop_all(struct efx_nic *efx)
/* Flush efx_mac_work(), refill_workqueue, monitor_work */ /* Flush efx_mac_work(), refill_workqueue, monitor_work */
efx_flush_all(efx); efx_flush_all(efx);
/* Stop the kernel transmit interface late, so the watchdog /* Stop the kernel transmit interface. This is only valid if
* timer isn't ticking over the flush */ * the device is stopped or detached; otherwise the watchdog
* may fire immediately.
*/
WARN_ON(netif_running(efx->net_dev) &&
netif_device_present(efx->net_dev));
if (efx_dev_registered(efx)) { if (efx_dev_registered(efx)) {
netif_tx_stop_all_queues(efx->net_dev); netif_tx_stop_all_queues(efx->net_dev);
netif_tx_lock_bh(efx->net_dev); netif_tx_lock_bh(efx->net_dev);
...@@ -1832,10 +1838,11 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) ...@@ -1832,10 +1838,11 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
if (new_mtu > EFX_MAX_MTU) if (new_mtu > EFX_MAX_MTU)
return -EINVAL; return -EINVAL;
efx_stop_all(efx);
netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu); netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu);
efx_device_detach_sync(efx);
efx_stop_all(efx);
efx_fini_channels(efx); efx_fini_channels(efx);
mutex_lock(&efx->mac_lock); mutex_lock(&efx->mac_lock);
...@@ -1848,6 +1855,7 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) ...@@ -1848,6 +1855,7 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
efx_init_channels(efx); efx_init_channels(efx);
efx_start_all(efx); efx_start_all(efx);
netif_device_attach(efx->net_dev);
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment