};
 
 struct efx_farch_filter_state {
+       struct rw_semaphore lock; /* Protects table contents */
        struct efx_farch_filter_table table[EFX_FARCH_FILTER_TABLE_COUNT];
 };
 
        if (rc)
                return rc;
 
+       down_write(&state->lock);
+
        table = &state->table[efx_farch_filter_spec_table_id(&spec)];
-       if (table->size == 0)
-               return -EINVAL;
+       if (table->size == 0) {
+               rc = -EINVAL;
+               goto out_unlock;
+       }
 
        netif_vdbg(efx, hw, efx->net_dev,
                   "%s: type %d search_limit=%d", __func__, spec.type,
                             EFX_FARCH_FILTER_MC_DEF - EFX_FARCH_FILTER_UC_DEF);
                rep_index = spec.type - EFX_FARCH_FILTER_UC_DEF;
                ins_index = rep_index;
-
-               spin_lock_bh(&efx->filter_lock);
        } else {
                /* Search concurrently for
                 * (1) a filter to be replaced (rep_index): any filter
                ins_index = -1;
                depth = 1;
 
-               spin_lock_bh(&efx->filter_lock);
-
                for (;;) {
                        if (!test_bit(i, table->used_bitmap)) {
                                if (ins_index < 0)
                                /* Case (b) */
                                if (ins_index < 0) {
                                        rc = -EBUSY;
-                                       goto out;
+                                       goto out_unlock;
                                }
                                rep_index = -1;
                                break;
 
                if (spec.priority == saved_spec->priority && !replace_equal) {
                        rc = -EEXIST;
-                       goto out;
+                       goto out_unlock;
                }
                if (spec.priority < saved_spec->priority) {
                        rc = -EPERM;
-                       goto out;
+                       goto out_unlock;
                }
                if (saved_spec->priority == EFX_FILTER_PRI_AUTO ||
                    saved_spec->flags & EFX_FILTER_FLAG_RX_OVER_AUTO)
                   __func__, spec.type, ins_index, spec.dmaq_id);
        rc = efx_farch_filter_make_id(&spec, ins_index);
 
-out:
-       spin_unlock_bh(&efx->filter_lock);
+out_unlock:
+       up_write(&state->lock);
        return rc;
 }
 
        filter_idx = efx_farch_filter_id_index(filter_id);
        if (filter_idx >= table->size)
                return -ENOENT;
+       down_write(&state->lock);
        spec = &table->spec[filter_idx];
 
-       spin_lock_bh(&efx->filter_lock);
        rc = efx_farch_filter_remove(efx, table, filter_idx, priority);
-       spin_unlock_bh(&efx->filter_lock);
+       up_write(&state->lock);
 
        return rc;
 }
        struct efx_farch_filter_table *table;
        struct efx_farch_filter_spec *spec;
        unsigned int filter_idx;
-       int rc;
+       int rc = -ENOENT;
+
+       down_read(&state->lock);
 
        table_id = efx_farch_filter_id_table_id(filter_id);
        if ((unsigned int)table_id >= EFX_FARCH_FILTER_TABLE_COUNT)
-               return -ENOENT;
+               goto out_unlock;
        table = &state->table[table_id];
 
        filter_idx = efx_farch_filter_id_index(filter_id);
        if (filter_idx >= table->size)
-               return -ENOENT;
+               goto out_unlock;
        spec = &table->spec[filter_idx];
 
-       spin_lock_bh(&efx->filter_lock);
-
        if (test_bit(filter_idx, table->used_bitmap) &&
            spec->priority == priority) {
                efx_farch_filter_to_gen_spec(spec_buf, spec);
                rc = 0;
-       } else {
-               rc = -ENOENT;
        }
 
-       spin_unlock_bh(&efx->filter_lock);
-
+out_unlock:
+       up_read(&state->lock);
        return rc;
 }
 
        struct efx_farch_filter_table *table = &state->table[table_id];
        unsigned int filter_idx;
 
-       spin_lock_bh(&efx->filter_lock);
+       down_write(&state->lock);
        for (filter_idx = 0; filter_idx < table->size; ++filter_idx) {
                if (table->spec[filter_idx].priority != EFX_FILTER_PRI_AUTO)
                        efx_farch_filter_remove(efx, table,
                                                filter_idx, priority);
        }
-       spin_unlock_bh(&efx->filter_lock);
+       up_write(&state->lock);
 }
 
 int efx_farch_filter_clear_rx(struct efx_nic *efx,
        unsigned int filter_idx;
        u32 count = 0;
 
-       spin_lock_bh(&efx->filter_lock);
+       down_read(&state->lock);
 
        for (table_id = EFX_FARCH_FILTER_TABLE_RX_IP;
             table_id <= EFX_FARCH_FILTER_TABLE_RX_DEF;
                }
        }
 
-       spin_unlock_bh(&efx->filter_lock);
+       up_read(&state->lock);
 
        return count;
 }
        unsigned int filter_idx;
        s32 count = 0;
 
-       spin_lock_bh(&efx->filter_lock);
+       down_read(&state->lock);
 
        for (table_id = EFX_FARCH_FILTER_TABLE_RX_IP;
             table_id <= EFX_FARCH_FILTER_TABLE_RX_DEF;
                }
        }
 out:
-       spin_unlock_bh(&efx->filter_lock);
+       up_read(&state->lock);
 
        return count;
 }
        efx_oword_t filter;
        unsigned int filter_idx;
 
-       spin_lock_bh(&efx->filter_lock);
+       down_write(&state->lock);
 
        for (table_id = 0; table_id < EFX_FARCH_FILTER_TABLE_COUNT; table_id++) {
                table = &state->table[table_id];
        efx_farch_filter_push_rx_config(efx);
        efx_farch_filter_push_tx_limits(efx);
 
-       spin_unlock_bh(&efx->filter_lock);
+       up_write(&state->lock);
 }
 
 void efx_farch_filter_table_remove(struct efx_nic *efx)
        efx_oword_t filter;
        unsigned int filter_idx;
 
-       spin_lock_bh(&efx->filter_lock);
+       down_write(&state->lock);
 
        for (table_id = EFX_FARCH_FILTER_TABLE_RX_IP;
             table_id <= EFX_FARCH_FILTER_TABLE_RX_DEF;
 
        efx_farch_filter_push_rx_config(efx);
 
-       spin_unlock_bh(&efx->filter_lock);
+       up_write(&state->lock);
 }
 
 #ifdef CONFIG_RFS_ACCEL
        struct efx_farch_filter_table *table;
        bool ret = false;
 
-       spin_lock_bh(&efx->filter_lock);
+       down_write(&state->lock);
        table = &state->table[EFX_FARCH_FILTER_TABLE_RX_IP];
        if (test_bit(index, table->used_bitmap) &&
            table->spec[index].priority == EFX_FILTER_PRI_HINT &&
                ret = true;
        }
 
-       spin_unlock_bh(&efx->filter_lock);
+       up_write(&state->lock);
        return ret;
 }