EFX_EF10_FILTER_FLAG_BUSY)
                                        break;
                                if (spec->priority < saved_spec->priority &&
-                                   !(saved_spec->priority ==
-                                     EFX_FILTER_PRI_REQUIRED &&
-                                     saved_spec->flags &
-                                     EFX_FILTER_FLAG_RX_STACK)) {
+                                   spec->priority != EFX_FILTER_PRI_AUTO) {
                                        rc = -EPERM;
                                        goto out_unlock;
                                }
         */
        saved_spec = efx_ef10_filter_entry_spec(table, ins_index);
        if (saved_spec) {
-               if (spec->flags & EFX_FILTER_FLAG_RX_STACK) {
+               if (spec->priority == EFX_FILTER_PRI_AUTO &&
+                   saved_spec->priority >= EFX_FILTER_PRI_AUTO) {
                        /* Just make sure it won't be removed */
-                       saved_spec->flags |= EFX_FILTER_FLAG_RX_STACK;
+                       if (saved_spec->priority > EFX_FILTER_PRI_AUTO)
+                               saved_spec->flags |= EFX_FILTER_FLAG_RX_OVER_AUTO;
                        table->entry[ins_index].spec &=
                                ~EFX_EF10_FILTER_FLAG_STACK_OLD;
                        rc = ins_index;
        if (rc == 0) {
                if (replacing) {
                        /* Update the fields that may differ */
+                       if (saved_spec->priority == EFX_FILTER_PRI_AUTO)
+                               saved_spec->flags |=
+                                       EFX_FILTER_FLAG_RX_OVER_AUTO;
                        saved_spec->priority = spec->priority;
-                       saved_spec->flags &= EFX_FILTER_FLAG_RX_STACK;
+                       saved_spec->flags &= EFX_FILTER_FLAG_RX_OVER_AUTO;
                        saved_spec->flags |= spec->flags;
                        saved_spec->rss_context = spec->rss_context;
                        saved_spec->dmaq_id = spec->dmaq_id;
                spin_unlock_bh(&efx->filter_lock);
                schedule();
        }
+
        spec = efx_ef10_filter_entry_spec(table, filter_idx);
-       if (!spec || spec->priority > priority ||
+       if (!spec ||
            (!stack_requested &&
             efx_ef10_filter_rx_match_pri(table, spec->match_flags) !=
             filter_id / HUNT_FILTER_TBL_ROWS)) {
                rc = -ENOENT;
                goto out_unlock;
        }
+
+       if (spec->flags & EFX_FILTER_FLAG_RX_OVER_AUTO &&
+           priority == EFX_FILTER_PRI_AUTO) {
+               /* Just remove flags */
+               spec->flags &= ~EFX_FILTER_FLAG_RX_OVER_AUTO;
+               table->entry[filter_idx].spec &= ~EFX_EF10_FILTER_FLAG_STACK_OLD;
+               rc = 0;
+               goto out_unlock;
+       }
+
+       if (spec->priority > priority) {
+               rc = -ENOENT;
+               goto out_unlock;
+       }
+
        table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_BUSY;
        spin_unlock_bh(&efx->filter_lock);
 
-       if (spec->flags & EFX_FILTER_FLAG_RX_STACK && !stack_requested) {
+       if (spec->flags & EFX_FILTER_FLAG_RX_OVER_AUTO) {
                /* Reset steering of a stack-owned filter */
 
                struct efx_filter_spec new_spec = *spec;
 
-               new_spec.priority = EFX_FILTER_PRI_REQUIRED;
+               new_spec.priority = EFX_FILTER_PRI_AUTO;
                new_spec.flags = (EFX_FILTER_FLAG_RX |
-                                 EFX_FILTER_FLAG_RX_RSS |
-                                 EFX_FILTER_FLAG_RX_STACK);
+                                 EFX_FILTER_FLAG_RX_RSS);
                new_spec.dmaq_id = 0;
                new_spec.rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT;
                rc = efx_ef10_filter_push(efx, &new_spec,
                        efx_ef10_filter_set_entry(table, filter_idx, NULL, 0);
                }
        }
+
        table->entry[filter_idx].spec &= ~EFX_EF10_FILTER_FLAG_BUSY;
        wake_up_all(&table->waitq);
 out_unlock:
                                rc = -EBUSY;
                                goto fail_unlock;
                        }
-                       EFX_WARN_ON_PARANOID(saved_spec->flags &
-                                            EFX_FILTER_FLAG_RX_STACK);
                        if (spec->priority < saved_spec->priority) {
                                rc = -EPERM;
                                goto fail_unlock;
        /* Insert/renew unicast filters */
        if (table->stack_uc_count >= 0) {
                for (i = 0; i < table->stack_uc_count; i++) {
-                       efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED,
-                                          EFX_FILTER_FLAG_RX_RSS |
-                                          EFX_FILTER_FLAG_RX_STACK,
+                       efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
+                                          EFX_FILTER_FLAG_RX_RSS,
                                           0);
                        efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
                                                 table->stack_uc_list[i].addr);
                                /* Fall back to unicast-promisc */
                                while (i--)
                                        efx_ef10_filter_remove_safe(
-                                               efx, EFX_FILTER_PRI_REQUIRED,
+                                               efx, EFX_FILTER_PRI_AUTO,
                                                table->stack_uc_list[i].id);
                                table->stack_uc_count = -1;
                                break;
                }
        }
        if (table->stack_uc_count < 0) {
-               efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED,
-                                  EFX_FILTER_FLAG_RX_RSS |
-                                  EFX_FILTER_FLAG_RX_STACK,
+               efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
+                                  EFX_FILTER_FLAG_RX_RSS,
                                   0);
                efx_filter_set_uc_def(&spec);
                rc = efx_ef10_filter_insert(efx, &spec, true);
        /* Insert/renew multicast filters */
        if (table->stack_mc_count >= 0) {
                for (i = 0; i < table->stack_mc_count; i++) {
-                       efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED,
-                                          EFX_FILTER_FLAG_RX_RSS |
-                                          EFX_FILTER_FLAG_RX_STACK,
+                       efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
+                                          EFX_FILTER_FLAG_RX_RSS,
                                           0);
                        efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
                                                 table->stack_mc_list[i].addr);
                                /* Fall back to multicast-promisc */
                                while (i--)
                                        efx_ef10_filter_remove_safe(
-                                               efx, EFX_FILTER_PRI_REQUIRED,
+                                               efx, EFX_FILTER_PRI_AUTO,
                                                table->stack_mc_list[i].id);
                                table->stack_mc_count = -1;
                                break;
                }
        }
        if (table->stack_mc_count < 0) {
-               efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED,
-                                  EFX_FILTER_FLAG_RX_RSS |
-                                  EFX_FILTER_FLAG_RX_STACK,
+               efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
+                                  EFX_FILTER_FLAG_RX_RSS,
                                   0);
                efx_filter_set_mc_def(&spec);
                rc = efx_ef10_filter_insert(efx, &spec, true);
        for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) {
                if (ACCESS_ONCE(table->entry[i].spec) &
                    EFX_EF10_FILTER_FLAG_STACK_OLD) {
-                       if (efx_ef10_filter_remove_internal(efx,
-                                       EFX_FILTER_PRI_REQUIRED,
-                                       i, true) < 0)
+                       if (efx_ef10_filter_remove_internal(
+                                   efx, EFX_FILTER_PRI_AUTO, i, true) < 0)
                                remove_failed = true;
                }
        }
 
        /* If there's only one channel then disable RSS for non VF
         * traffic, thereby allowing VFs to use RSS when the PF can't.
         */
-       spec->priority = EFX_FILTER_PRI_REQUIRED;
-       spec->flags = (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_STACK |
+       spec->priority = EFX_FILTER_PRI_AUTO;
+       spec->flags = (EFX_FILTER_FLAG_RX |
                       (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) |
                       (efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0));
        spec->dmaq_id = 0;
                        rc = -EEXIST;
                        goto out;
                }
-               if (spec.priority < saved_spec->priority &&
-                   !(saved_spec->priority == EFX_FILTER_PRI_REQUIRED &&
-                     saved_spec->flags & EFX_FILTER_FLAG_RX_STACK)) {
+               if (spec.priority < saved_spec->priority) {
                        rc = -EPERM;
                        goto out;
                }
-               if (spec.flags & EFX_FILTER_FLAG_RX_STACK) {
-                       /* Just make sure it won't be removed */
-                       saved_spec->flags |= EFX_FILTER_FLAG_RX_STACK;
-                       rc = 0;
-                       goto out;
-               }
-               /* Retain the RX_STACK flag */
-               spec.flags |= saved_spec->flags & EFX_FILTER_FLAG_RX_STACK;
+               if (saved_spec->priority == EFX_FILTER_PRI_AUTO ||
+                   saved_spec->flags & EFX_FILTER_FLAG_RX_OVER_AUTO)
+                       spec.flags |= EFX_FILTER_FLAG_RX_OVER_AUTO;
        }
 
        /* Insert the filter */
            spec->priority > priority)
                return -ENOENT;
 
-       if (spec->flags & EFX_FILTER_FLAG_RX_STACK) {
+       if (spec->flags & EFX_FILTER_FLAG_RX_OVER_AUTO) {
                efx_farch_filter_init_rx_for_stack(efx, spec);
                efx_farch_filter_push_rx_config(efx);
        } else {
        unsigned int filter_idx;
 
        spin_lock_bh(&efx->filter_lock);
-       for (filter_idx = 0; filter_idx < table->size; ++filter_idx)
-               efx_farch_filter_remove(efx, table, filter_idx, priority);
+       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);
 }
 
 
 /**
  * enum efx_filter_priority - priority of a hardware filter specification
  * @EFX_FILTER_PRI_HINT: Performance hint
+ * @EFX_FILTER_PRI_AUTO: Automatic filter based on device address list
+ *     or hardware requirements.  This may only be used by the filter
+ *     implementation for each NIC type.
  * @EFX_FILTER_PRI_MANUAL: Manually configured filter
  * @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour (user-level
  *     networking and SR-IOV)
  */
 enum efx_filter_priority {
        EFX_FILTER_PRI_HINT = 0,
+       EFX_FILTER_PRI_AUTO,
        EFX_FILTER_PRI_MANUAL,
        EFX_FILTER_PRI_REQUIRED,
 };
  *     according to the indirection table.
  * @EFX_FILTER_FLAG_RX_SCATTER: Enable DMA scatter on the receiving
  *     queue.
- * @EFX_FILTER_FLAG_RX_STACK: Indicates a filter inserted for the
- *     network stack.  The filter must have a priority of
- *     %EFX_FILTER_PRI_REQUIRED.  It can be steered by a replacement
- *     request with priority %EFX_FILTER_PRI_MANUAL, and a removal
- *     request with priority %EFX_FILTER_PRI_MANUAL will reset the
- *     steering (but not remove the filter).
+ * @EFX_FILTER_FLAG_RX_OVER_AUTO: Indicates a filter that is
+ *     overriding an automatic filter (priority
+ *     %EFX_FILTER_PRI_AUTO).  This may only be set by the filter
+ *     implementation for each type.  A removal request will restore
+ *     the automatic filter in its place.
  * @EFX_FILTER_FLAG_RX: Filter is for RX
  * @EFX_FILTER_FLAG_TX: Filter is for TX
  */
 enum efx_filter_flags {
        EFX_FILTER_FLAG_RX_RSS = 0x01,
        EFX_FILTER_FLAG_RX_SCATTER = 0x02,
-       EFX_FILTER_FLAG_RX_STACK = 0x04,
+       EFX_FILTER_FLAG_RX_OVER_AUTO = 0x04,
        EFX_FILTER_FLAG_RX = 0x08,
        EFX_FILTER_FLAG_TX = 0x10,
 };