mutex_unlock(&efx->mac_lock);
 }
 
+/* Asynchronous work item for changing MAC promiscuity and multicast
+ * hash.  Avoid a drain/rx_ingress enable by reconfiguring the current
+ * MAC directly. */
 static void efx_mac_work(struct work_struct *data)
 {
        struct efx_nic *efx = container_of(data, struct efx_nic, mac_work);
 
        mutex_lock(&efx->mac_lock);
+       if (efx->port_enabled) {
+               falcon_push_multicast_hash(efx);
+               efx->mac_op->reconfigure(efx);
+       }
        mutex_unlock(&efx->mac_lock);
 }
 
 
        mutex_lock(&efx->mac_lock);
        efx->port_enabled = true;
-       __efx_reconfigure_port(efx);
+
+       /* efx_mac_work() might have been scheduled after efx_stop_port(),
+        * and then cancelled by efx_flush_all() */
+       falcon_push_multicast_hash(efx);
+       efx->mac_op->reconfigure(efx);
+
        mutex_unlock(&efx->mac_lock);
 }
 
        struct efx_nic *efx = netdev_priv(net_dev);
        struct dev_mc_list *mc_list = net_dev->mc_list;
        union efx_multicast_hash *mc_hash = &efx->multicast_hash;
-       bool promiscuous = !!(net_dev->flags & IFF_PROMISC);
-       bool changed = (efx->promiscuous != promiscuous);
        u32 crc;
        int bit;
        int i;
 
-       efx->promiscuous = promiscuous;
+       efx->promiscuous = !!(net_dev->flags & IFF_PROMISC);
 
        /* Build multicast hash table */
-       if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
+       if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
                memset(mc_hash, 0xff, sizeof(*mc_hash));
        } else {
                memset(mc_hash, 0x00, sizeof(*mc_hash));
                        set_bit_le(bit, mc_hash->byte);
                        mc_list = mc_list->next;
                }
-       }
 
-       if (!efx->port_enabled)
-               /* Delay pushing settings until efx_start_port() */
-               return;
-
-       if (changed)
-               queue_work(efx->workqueue, &efx->phy_work);
+               /* Broadcast packets go through the multicast hash filter.
+                * ether_crc_le() of the broadcast address is 0xbe2612ff
+                * so we always add bit 0xff to the mask.
+                */
+               set_bit_le(0xff, mc_hash->byte);
+       }
 
-       /* Create and activate new global multicast hash table */
-       falcon_set_multicast_hash(efx);
+       if (efx->port_enabled)
+               queue_work(efx->workqueue, &efx->mac_work);
+       /* Otherwise efx_start_port() will do this */
 }
 
 static const struct net_device_ops efx_netdev_ops = {
 
        efx_writeo(efx, ®, FR_AB_MAC_CTRL);
 
        /* Restore the multicast hash registers. */
-       falcon_set_multicast_hash(efx);
+       falcon_push_multicast_hash(efx);
 
        /* Transmission of pause frames when RX crosses the threshold is
         * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
  **************************************************************************
  */
 
-void falcon_set_multicast_hash(struct efx_nic *efx)
+void falcon_push_multicast_hash(struct efx_nic *efx)
 {
        union efx_multicast_hash *mc_hash = &efx->multicast_hash;
 
-       /* Broadcast packets go through the multicast hash filter.
-        * ether_crc_le() of the broadcast address is 0xbe2612ff
-        * so we always add bit 0xff to the mask.
-        */
-       set_bit_le(0xff, mc_hash->byte);
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
 
        efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
        efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);