diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 15616dd9ed418e165c8a9e2d2efbba3bb0af1cb9..1009d1eeba828be9e7bc8f0534869dc3bf204c14 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -688,11 +688,18 @@ static void efx_phy_work(struct work_struct *data)
 	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);
 }
 
@@ -771,7 +778,12 @@ static void efx_start_port(struct efx_nic *efx)
 
 	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);
 }
 
@@ -1534,16 +1546,14 @@ static void efx_set_multicast_list(struct net_device *net_dev)
 	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));
@@ -1553,17 +1563,17 @@ static void efx_set_multicast_list(struct net_device *net_dev)
 			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 = {
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index fac534a274c8dc98c1932140ca8ae22820e6b360..e26043eb01b54ff1225ceb1b7f283f630aead8ed 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1993,7 +1993,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 	efx_writeo(efx, &reg, 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.
@@ -2327,15 +2327,11 @@ void falcon_remove_port(struct efx_nic *efx)
  **************************************************************************
  */
 
-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);
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 9ae1b6c8474e302ff49bf77291cb9a7f52e0932c..c70bb084216ffa2d2b828aa63621c01f0b83f955 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -163,7 +163,7 @@ extern void falcon_remove_nic(struct efx_nic *efx);
 extern void falcon_update_nic_stats(struct efx_nic *efx);
 extern void falcon_start_nic_stats(struct efx_nic *efx);
 extern void falcon_stop_nic_stats(struct efx_nic *efx);
-extern void falcon_set_multicast_hash(struct efx_nic *efx);
+extern void falcon_push_multicast_hash(struct efx_nic *efx);
 extern int falcon_reset_xaui(struct efx_nic *efx);
 
 /* Tests */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index cc1a97b0a0d36f8e8f00b2a347f09ded47bddf9b..ead1c982365b8b5fc3779e6dec0fe79d4c543dbe 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -730,7 +730,7 @@ union efx_multicast_hash {
  * @multicast_hash: Multicast hash table
  * @wanted_fc: Wanted flow control flags
  * @phy_work: work item for dealing with PHY events
- * @mac_work: work item for dealing with MAC events
+ * @mac_work: Work item for changing MAC promiscuity and multicast hash
  * @loopback_mode: Loopback status
  * @loopback_modes: Supported loopback mode bitmask
  * @loopback_selftest: Offline self-test private state