return rc;
 }
 
+/* Caller must hold efx->filter_sem for read if race against
+ * efx_ef10_filter_table_remove() is possible
+ */
 static void efx_ef10_filter_table_restore(struct efx_nic *efx)
 {
        struct efx_ef10_filter_table *table = efx->filter_state;
        bool failed = false;
        int rc;
 
+       WARN_ON(!rwsem_is_locked(&efx->filter_sem));
+
        if (!nic_data->must_restore_filters)
                return;
 
+       if (!table)
+               return;
+
        spin_lock_bh(&efx->filter_lock);
 
        for (filter_idx = 0; filter_idx < HUNT_FILTER_TBL_ROWS; filter_idx++) {
                nic_data->must_restore_filters = false;
 }
 
+/* Caller must hold efx->filter_sem for write */
 static void efx_ef10_filter_table_remove(struct efx_nic *efx)
 {
        struct efx_ef10_filter_table *table = efx->filter_state;
        unsigned int filter_idx;
        int rc;
 
+       efx->filter_state = NULL;
+       if (!table)
+               return;
+
        for (filter_idx = 0; filter_idx < HUNT_FILTER_TBL_ROWS; filter_idx++) {
                spec = efx_ef10_filter_entry_spec(table, filter_idx);
                if (!spec)
        kfree(table);
 }
 
+/* Caller must hold efx->filter_sem for read if race against
+ * efx_ef10_filter_table_remove() is possible
+ */
 static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 {
        struct efx_ef10_filter_table *table = efx->filter_state;
        if (!efx_dev_registered(efx))
                return;
 
+       if (!table)
+               return;
+
        /* Mark old filters that may need to be removed */
        spin_lock_bh(&efx->filter_lock);
        n = table->dev_uc_count < 0 ? 1 : table->dev_uc_count;
 
 
 static void efx_fini_port(struct efx_nic *efx);
 
+/* We assume that efx->type->reconfigure_mac will always try to sync RX
+ * filters and therefore needs to read-lock the filter table against freeing
+ */
+void efx_mac_reconfigure(struct efx_nic *efx)
+{
+       down_read(&efx->filter_sem);
+       efx->type->reconfigure_mac(efx);
+       up_read(&efx->filter_sem);
+}
+
 /* Push loopback/power/transmit disable settings to the PHY, and reconfigure
  * the MAC appropriately. All other PHY configuration changes are pushed
  * through phy_op->set_settings(), and pushed asynchronously to the MAC
 
        mutex_lock(&efx->mac_lock);
        if (efx->port_enabled)
-               efx->type->reconfigure_mac(efx);
+               efx_mac_reconfigure(efx);
        mutex_unlock(&efx->mac_lock);
 }
 
 
        /* Reconfigure the MAC before creating dma queues (required for
         * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */
-       efx->type->reconfigure_mac(efx);
+       efx_mac_reconfigure(efx);
 
        /* Ensure the PHY advertises the correct flow control settings */
        rc = efx->phy_op->reconfigure(efx);
        efx->port_enabled = true;
 
        /* Ensure MAC ingress/egress is enabled */
-       efx->type->reconfigure_mac(efx);
+       efx_mac_reconfigure(efx);
 
        mutex_unlock(&efx->mac_lock);
 }
        int rc;
 
        spin_lock_init(&efx->filter_lock);
-
+       init_rwsem(&efx->filter_sem);
+       down_write(&efx->filter_sem);
        rc = efx->type->filter_table_probe(efx);
        if (rc)
-               return rc;
+               goto out_unlock;
 
 #ifdef CONFIG_RFS_ACCEL
        if (efx->type->offload_features & NETIF_F_NTUPLE) {
                                           GFP_KERNEL);
                if (!efx->rps_flow_id) {
                        efx->type->filter_table_remove(efx);
-                       return -ENOMEM;
+                       rc = -ENOMEM;
+                       goto out_unlock;
                }
        }
 #endif
-
-       return 0;
+out_unlock:
+       up_write(&efx->filter_sem);
+       return rc;
 }
 
 static void efx_remove_filters(struct efx_nic *efx)
 #ifdef CONFIG_RFS_ACCEL
        kfree(efx->rps_flow_id);
 #endif
+       down_write(&efx->filter_sem);
        efx->type->filter_table_remove(efx);
+       up_write(&efx->filter_sem);
 }
 
 static void efx_restore_filters(struct efx_nic *efx)
 {
+       down_read(&efx->filter_sem);
        efx->type->filter_table_restore(efx);
+       up_read(&efx->filter_sem);
 }
 
 /**************************************************************************
 
        mutex_lock(&efx->mac_lock);
        net_dev->mtu = new_mtu;
-       efx->type->reconfigure_mac(efx);
+       efx_mac_reconfigure(efx);
        mutex_unlock(&efx->mac_lock);
 
        efx_start_all(efx);
 
        /* Reconfigure the MAC */
        mutex_lock(&efx->mac_lock);
-       efx->type->reconfigure_mac(efx);
+       efx_mac_reconfigure(efx);
        mutex_unlock(&efx->mac_lock);
 
        return 0;
                           " VFs may not function\n", rc);
 #endif
 
+       down_read(&efx->filter_sem);
        efx_restore_filters(efx);
+       up_read(&efx->filter_sem);
        if (efx->type->sriov_reset)
                efx->type->sriov_reset(efx);
 
 
 #include <linux/highmem.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
+#include <linux/rwsem.h>
 #include <linux/vmalloc.h>
 #include <linux/i2c.h>
 #include <linux/mtd/mtd.h>
  * @loopback_mode: Loopback status
  * @loopback_modes: Supported loopback mode bitmask
  * @loopback_selftest: Offline self-test private state
- * @filter_lock: Filter table lock
+ * @filter_sem: Filter table rw_semaphore, for freeing the table
+ * @filter_lock: Filter table lock, for mere content changes
  * @filter_state: Architecture-dependent filter table state
  * @rps_flow_id: Flow IDs of filters allocated for accelerated RFS,
  *     indexed by filter ID
 
        void *loopback_selftest;
 
+       struct rw_semaphore filter_sem;
        spinlock_t filter_lock;
        void *filter_state;
 #ifdef CONFIG_RFS_ACCEL