netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n",
raw_smp_processor_id());
+ efx_detach_reps(efx);
netif_stop_queue(net_dev);
efx_stop_all(efx);
efx_mcdi_mac_fini_stats(efx);
mutex_unlock(&efx->mac_lock);
efx->state = STATE_NET_UP;
+ if (netif_running(efx->net_dev))
+ efx_attach_reps(efx);
return 0;
spin_lock_bh(&efx->vf_reps_lock);
list_add_tail(&efv->list, &efx->vf_reps);
spin_unlock_bh(&efx->vf_reps_lock);
- netif_carrier_off(net_dev);
- netif_tx_stop_all_queues(net_dev);
+ if (netif_running(efx->net_dev) && efx->state == STATE_NET_UP) {
+ netif_device_attach(net_dev);
+ netif_carrier_on(net_dev);
+ } else {
+ netif_carrier_off(net_dev);
+ netif_tx_stop_all_queues(net_dev);
+ }
rtnl_unlock();
net_dev->netdev_ops = &efx_ef100_rep_netdev_ops;
{
struct efx_nic *efx = efv->parent;
+ rtnl_lock();
spin_lock_bh(&efx->vf_reps_lock);
list_del(&efv->list);
spin_unlock_bh(&efx->vf_reps_lock);
+ rtnl_unlock();
free_netdev(efv->net_dev);
}
#include "net_driver.h"
#include "ef100_rx.h"
#include "ef100_tx.h"
+#include "efx_common.h"
#include "filter.h"
int efx_net_open(struct net_device *net_dev);
{
struct net_device *dev = efx->net_dev;
+ /* We must stop reps (which use our TX) before we stop ourselves. */
+ efx_detach_reps(efx);
+
/* Lock/freeze all TX queues so that we can be sure the
* TX scheduler is stopped when we're done and before
* netif_device_present() becomes false.
static inline void efx_device_attach_if_not_resetting(struct efx_nic *efx)
{
- if ((efx->state != STATE_DISABLED) && !efx->reset_pending)
+ if ((efx->state != STATE_DISABLED) && !efx->reset_pending) {
netif_device_attach(efx->net_dev);
+ if (efx->state == STATE_NET_UP)
+ efx_attach_reps(efx);
+ }
}
static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem)
#include "mcdi_port_common.h"
#include "io.h"
#include "mcdi_pcol.h"
+#include "ef100_rep.h"
static unsigned int debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
return -EINVAL;
return 0;
}
+
+void efx_detach_reps(struct efx_nic *efx)
+{
+ struct net_device *rep_dev;
+ struct efx_rep *efv;
+
+ ASSERT_RTNL();
+ netif_dbg(efx, drv, efx->net_dev, "Detaching VF representors\n");
+ list_for_each_entry(efv, &efx->vf_reps, list) {
+ rep_dev = efv->net_dev;
+ if (!rep_dev)
+ continue;
+ netif_carrier_off(rep_dev);
+ /* See efx_device_detach_sync() */
+ netif_tx_lock_bh(rep_dev);
+ netif_tx_stop_all_queues(rep_dev);
+ netif_tx_unlock_bh(rep_dev);
+ }
+}
+
+void efx_attach_reps(struct efx_nic *efx)
+{
+ struct net_device *rep_dev;
+ struct efx_rep *efv;
+
+ ASSERT_RTNL();
+ netif_dbg(efx, drv, efx->net_dev, "Attaching VF representors\n");
+ list_for_each_entry(efv, &efx->vf_reps, list) {
+ rep_dev = efv->net_dev;
+ if (!rep_dev)
+ continue;
+ netif_tx_wake_all_queues(rep_dev);
+ netif_carrier_on(rep_dev);
+ }
+}
int efx_get_phys_port_name(struct net_device *net_dev,
char *name, size_t len);
+
+void efx_detach_reps(struct efx_nic *efx);
+void efx_attach_reps(struct efx_nic *efx);
#endif