提交 7665d1ab 编写于 作者: B Ben Hutchings

sfc: Change priority and flags for automatic MAC filters

MAC filters inserted automatically by the driver, based on the device
address list (EF10) or no-match filters (Siena), should be overridable
at MANUAL or REQUIRED priority.  Currently they themselves have
REQUIRED priority and this requires some odd special-casing.

We also can't reliably tell whether such a MAC filter has or has
not been overridden.  We just remember that it is wanted by the
stack (RX_STACK flag).

Add another priority level, AUTO, between HINT and MANUAL, and
use this for the automatic filters while they have not been
overridden.  Remove the RX_STACK flag.  Add an RX_OVER_AUTO
flag which is set only when an AUTO filter has been overridden
(or was requested to be inserted while a higher-priority filter
existed).
Signed-off-by: NBen Hutchings <bhutchings@solarflare.com>
上级 d43050c0
...@@ -2341,10 +2341,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx, ...@@ -2341,10 +2341,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
EFX_EF10_FILTER_FLAG_BUSY) EFX_EF10_FILTER_FLAG_BUSY)
break; break;
if (spec->priority < saved_spec->priority && if (spec->priority < saved_spec->priority &&
!(saved_spec->priority == spec->priority != EFX_FILTER_PRI_AUTO) {
EFX_FILTER_PRI_REQUIRED &&
saved_spec->flags &
EFX_FILTER_FLAG_RX_STACK)) {
rc = -EPERM; rc = -EPERM;
goto out_unlock; goto out_unlock;
} }
...@@ -2398,9 +2395,11 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx, ...@@ -2398,9 +2395,11 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
*/ */
saved_spec = efx_ef10_filter_entry_spec(table, ins_index); saved_spec = efx_ef10_filter_entry_spec(table, ins_index);
if (saved_spec) { 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 */ /* 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 &= table->entry[ins_index].spec &=
~EFX_EF10_FILTER_FLAG_STACK_OLD; ~EFX_EF10_FILTER_FLAG_STACK_OLD;
rc = ins_index; rc = ins_index;
...@@ -2442,8 +2441,11 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx, ...@@ -2442,8 +2441,11 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
if (rc == 0) { if (rc == 0) {
if (replacing) { if (replacing) {
/* Update the fields that may differ */ /* 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->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->flags |= spec->flags;
saved_spec->rss_context = spec->rss_context; saved_spec->rss_context = spec->rss_context;
saved_spec->dmaq_id = spec->dmaq_id; saved_spec->dmaq_id = spec->dmaq_id;
...@@ -2542,26 +2544,41 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx, ...@@ -2542,26 +2544,41 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
spin_unlock_bh(&efx->filter_lock); spin_unlock_bh(&efx->filter_lock);
schedule(); schedule();
} }
spec = efx_ef10_filter_entry_spec(table, filter_idx); spec = efx_ef10_filter_entry_spec(table, filter_idx);
if (!spec || spec->priority > priority || if (!spec ||
(!stack_requested && (!stack_requested &&
efx_ef10_filter_rx_match_pri(table, spec->match_flags) != efx_ef10_filter_rx_match_pri(table, spec->match_flags) !=
filter_id / HUNT_FILTER_TBL_ROWS)) { filter_id / HUNT_FILTER_TBL_ROWS)) {
rc = -ENOENT; rc = -ENOENT;
goto out_unlock; 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; table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_BUSY;
spin_unlock_bh(&efx->filter_lock); 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 */ /* Reset steering of a stack-owned filter */
struct efx_filter_spec new_spec = *spec; 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 | new_spec.flags = (EFX_FILTER_FLAG_RX |
EFX_FILTER_FLAG_RX_RSS | EFX_FILTER_FLAG_RX_RSS);
EFX_FILTER_FLAG_RX_STACK);
new_spec.dmaq_id = 0; new_spec.dmaq_id = 0;
new_spec.rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT; new_spec.rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT;
rc = efx_ef10_filter_push(efx, &new_spec, rc = efx_ef10_filter_push(efx, &new_spec,
...@@ -2589,6 +2606,7 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx, ...@@ -2589,6 +2606,7 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
efx_ef10_filter_set_entry(table, filter_idx, NULL, 0); efx_ef10_filter_set_entry(table, filter_idx, NULL, 0);
} }
} }
table->entry[filter_idx].spec &= ~EFX_EF10_FILTER_FLAG_BUSY; table->entry[filter_idx].spec &= ~EFX_EF10_FILTER_FLAG_BUSY;
wake_up_all(&table->waitq); wake_up_all(&table->waitq);
out_unlock: out_unlock:
...@@ -2731,8 +2749,6 @@ static s32 efx_ef10_filter_rfs_insert(struct efx_nic *efx, ...@@ -2731,8 +2749,6 @@ static s32 efx_ef10_filter_rfs_insert(struct efx_nic *efx,
rc = -EBUSY; rc = -EBUSY;
goto fail_unlock; goto fail_unlock;
} }
EFX_WARN_ON_PARANOID(saved_spec->flags &
EFX_FILTER_FLAG_RX_STACK);
if (spec->priority < saved_spec->priority) { if (spec->priority < saved_spec->priority) {
rc = -EPERM; rc = -EPERM;
goto fail_unlock; goto fail_unlock;
...@@ -3118,9 +3134,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3118,9 +3134,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* Insert/renew unicast filters */ /* Insert/renew unicast filters */
if (table->stack_uc_count >= 0) { if (table->stack_uc_count >= 0) {
for (i = 0; i < table->stack_uc_count; i++) { for (i = 0; i < table->stack_uc_count; i++) {
efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED, efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
EFX_FILTER_FLAG_RX_RSS | EFX_FILTER_FLAG_RX_RSS,
EFX_FILTER_FLAG_RX_STACK,
0); 0);
efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
table->stack_uc_list[i].addr); table->stack_uc_list[i].addr);
...@@ -3129,7 +3144,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3129,7 +3144,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* Fall back to unicast-promisc */ /* Fall back to unicast-promisc */
while (i--) while (i--)
efx_ef10_filter_remove_safe( efx_ef10_filter_remove_safe(
efx, EFX_FILTER_PRI_REQUIRED, efx, EFX_FILTER_PRI_AUTO,
table->stack_uc_list[i].id); table->stack_uc_list[i].id);
table->stack_uc_count = -1; table->stack_uc_count = -1;
break; break;
...@@ -3138,9 +3153,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3138,9 +3153,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
} }
} }
if (table->stack_uc_count < 0) { if (table->stack_uc_count < 0) {
efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED, efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
EFX_FILTER_FLAG_RX_RSS | EFX_FILTER_FLAG_RX_RSS,
EFX_FILTER_FLAG_RX_STACK,
0); 0);
efx_filter_set_uc_def(&spec); efx_filter_set_uc_def(&spec);
rc = efx_ef10_filter_insert(efx, &spec, true); rc = efx_ef10_filter_insert(efx, &spec, true);
...@@ -3155,9 +3169,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3155,9 +3169,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* Insert/renew multicast filters */ /* Insert/renew multicast filters */
if (table->stack_mc_count >= 0) { if (table->stack_mc_count >= 0) {
for (i = 0; i < table->stack_mc_count; i++) { for (i = 0; i < table->stack_mc_count; i++) {
efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED, efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
EFX_FILTER_FLAG_RX_RSS | EFX_FILTER_FLAG_RX_RSS,
EFX_FILTER_FLAG_RX_STACK,
0); 0);
efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
table->stack_mc_list[i].addr); table->stack_mc_list[i].addr);
...@@ -3166,7 +3179,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3166,7 +3179,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* Fall back to multicast-promisc */ /* Fall back to multicast-promisc */
while (i--) while (i--)
efx_ef10_filter_remove_safe( efx_ef10_filter_remove_safe(
efx, EFX_FILTER_PRI_REQUIRED, efx, EFX_FILTER_PRI_AUTO,
table->stack_mc_list[i].id); table->stack_mc_list[i].id);
table->stack_mc_count = -1; table->stack_mc_count = -1;
break; break;
...@@ -3175,9 +3188,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3175,9 +3188,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
} }
} }
if (table->stack_mc_count < 0) { if (table->stack_mc_count < 0) {
efx_filter_init_rx(&spec, EFX_FILTER_PRI_REQUIRED, efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
EFX_FILTER_FLAG_RX_RSS | EFX_FILTER_FLAG_RX_RSS,
EFX_FILTER_FLAG_RX_STACK,
0); 0);
efx_filter_set_mc_def(&spec); efx_filter_set_mc_def(&spec);
rc = efx_ef10_filter_insert(efx, &spec, true); rc = efx_ef10_filter_insert(efx, &spec, true);
...@@ -3197,9 +3209,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ...@@ -3197,9 +3209,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) { for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) {
if (ACCESS_ONCE(table->entry[i].spec) & if (ACCESS_ONCE(table->entry[i].spec) &
EFX_EF10_FILTER_FLAG_STACK_OLD) { EFX_EF10_FILTER_FLAG_STACK_OLD) {
if (efx_ef10_filter_remove_internal(efx, if (efx_ef10_filter_remove_internal(
EFX_FILTER_PRI_REQUIRED, efx, EFX_FILTER_PRI_AUTO, i, true) < 0)
i, true) < 0)
remove_failed = true; remove_failed = true;
} }
} }
......
...@@ -138,6 +138,9 @@ efx_filter_get_filter_safe(struct efx_nic *efx, ...@@ -138,6 +138,9 @@ efx_filter_get_filter_safe(struct efx_nic *efx,
* efx_farch_filter_clear_rx - remove RX filters by priority * efx_farch_filter_clear_rx - remove RX filters by priority
* @efx: NIC from which to remove the filters * @efx: NIC from which to remove the filters
* @priority: Maximum priority to remove * @priority: Maximum priority to remove
*
* Remove all RX filters whose priority is less than or equal to the
* given @priority and is not %EFX_FILTER_PRI_AUTO.
*/ */
static inline void efx_filter_clear_rx(struct efx_nic *efx, static inline void efx_filter_clear_rx(struct efx_nic *efx,
enum efx_filter_priority priority) enum efx_filter_priority priority)
......
...@@ -2190,8 +2190,8 @@ efx_farch_filter_init_rx_for_stack(struct efx_nic *efx, ...@@ -2190,8 +2190,8 @@ efx_farch_filter_init_rx_for_stack(struct efx_nic *efx,
/* If there's only one channel then disable RSS for non VF /* If there's only one channel then disable RSS for non VF
* traffic, thereby allowing VFs to use RSS when the PF can't. * traffic, thereby allowing VFs to use RSS when the PF can't.
*/ */
spec->priority = EFX_FILTER_PRI_REQUIRED; spec->priority = EFX_FILTER_PRI_AUTO;
spec->flags = (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_STACK | spec->flags = (EFX_FILTER_FLAG_RX |
(efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) | (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) |
(efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0)); (efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0));
spec->dmaq_id = 0; spec->dmaq_id = 0;
...@@ -2456,20 +2456,13 @@ s32 efx_farch_filter_insert(struct efx_nic *efx, ...@@ -2456,20 +2456,13 @@ s32 efx_farch_filter_insert(struct efx_nic *efx,
rc = -EEXIST; rc = -EEXIST;
goto out; goto out;
} }
if (spec.priority < saved_spec->priority && if (spec.priority < saved_spec->priority) {
!(saved_spec->priority == EFX_FILTER_PRI_REQUIRED &&
saved_spec->flags & EFX_FILTER_FLAG_RX_STACK)) {
rc = -EPERM; rc = -EPERM;
goto out; goto out;
} }
if (spec.flags & EFX_FILTER_FLAG_RX_STACK) { if (saved_spec->priority == EFX_FILTER_PRI_AUTO ||
/* Just make sure it won't be removed */ saved_spec->flags & EFX_FILTER_FLAG_RX_OVER_AUTO)
saved_spec->flags |= EFX_FILTER_FLAG_RX_STACK; spec.flags |= EFX_FILTER_FLAG_RX_OVER_AUTO;
rc = 0;
goto out;
}
/* Retain the RX_STACK flag */
spec.flags |= saved_spec->flags & EFX_FILTER_FLAG_RX_STACK;
} }
/* Insert the filter */ /* Insert the filter */
...@@ -2553,7 +2546,7 @@ static int efx_farch_filter_remove(struct efx_nic *efx, ...@@ -2553,7 +2546,7 @@ static int efx_farch_filter_remove(struct efx_nic *efx,
spec->priority > priority) spec->priority > priority)
return -ENOENT; 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_init_rx_for_stack(efx, spec);
efx_farch_filter_push_rx_config(efx); efx_farch_filter_push_rx_config(efx);
} else { } else {
...@@ -2637,8 +2630,11 @@ efx_farch_filter_table_clear(struct efx_nic *efx, ...@@ -2637,8 +2630,11 @@ efx_farch_filter_table_clear(struct efx_nic *efx,
unsigned int filter_idx; unsigned int filter_idx;
spin_lock_bh(&efx->filter_lock); spin_lock_bh(&efx->filter_lock);
for (filter_idx = 0; filter_idx < table->size; ++filter_idx) for (filter_idx = 0; filter_idx < table->size; ++filter_idx) {
efx_farch_filter_remove(efx, table, filter_idx, priority); 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); spin_unlock_bh(&efx->filter_lock);
} }
......
...@@ -59,12 +59,16 @@ enum efx_filter_match_flags { ...@@ -59,12 +59,16 @@ enum efx_filter_match_flags {
/** /**
* enum efx_filter_priority - priority of a hardware filter specification * enum efx_filter_priority - priority of a hardware filter specification
* @EFX_FILTER_PRI_HINT: Performance hint * @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_MANUAL: Manually configured filter
* @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour (user-level * @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour (user-level
* networking and SR-IOV) * networking and SR-IOV)
*/ */
enum efx_filter_priority { enum efx_filter_priority {
EFX_FILTER_PRI_HINT = 0, EFX_FILTER_PRI_HINT = 0,
EFX_FILTER_PRI_AUTO,
EFX_FILTER_PRI_MANUAL, EFX_FILTER_PRI_MANUAL,
EFX_FILTER_PRI_REQUIRED, EFX_FILTER_PRI_REQUIRED,
}; };
...@@ -78,19 +82,18 @@ enum efx_filter_priority { ...@@ -78,19 +82,18 @@ enum efx_filter_priority {
* according to the indirection table. * according to the indirection table.
* @EFX_FILTER_FLAG_RX_SCATTER: Enable DMA scatter on the receiving * @EFX_FILTER_FLAG_RX_SCATTER: Enable DMA scatter on the receiving
* queue. * queue.
* @EFX_FILTER_FLAG_RX_STACK: Indicates a filter inserted for the * @EFX_FILTER_FLAG_RX_OVER_AUTO: Indicates a filter that is
* network stack. The filter must have a priority of * overriding an automatic filter (priority
* %EFX_FILTER_PRI_REQUIRED. It can be steered by a replacement * %EFX_FILTER_PRI_AUTO). This may only be set by the filter
* request with priority %EFX_FILTER_PRI_MANUAL, and a removal * implementation for each type. A removal request will restore
* request with priority %EFX_FILTER_PRI_MANUAL will reset the * the automatic filter in its place.
* steering (but not remove the filter).
* @EFX_FILTER_FLAG_RX: Filter is for RX * @EFX_FILTER_FLAG_RX: Filter is for RX
* @EFX_FILTER_FLAG_TX: Filter is for TX * @EFX_FILTER_FLAG_TX: Filter is for TX
*/ */
enum efx_filter_flags { enum efx_filter_flags {
EFX_FILTER_FLAG_RX_RSS = 0x01, EFX_FILTER_FLAG_RX_RSS = 0x01,
EFX_FILTER_FLAG_RX_SCATTER = 0x02, 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_RX = 0x08,
EFX_FILTER_FLAG_TX = 0x10, EFX_FILTER_FLAG_TX = 0x10,
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册