Skip to content

Commit

Permalink
sfc: Change priority and flags for automatic MAC filters
Browse files Browse the repository at this point in the history
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: Ben Hutchings <bhutchings@solarflare.com>
  • Loading branch information
Ben Hutchings committed Dec 12, 2013
1 parent d43050c commit 7665d1a
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 54 deletions.
73 changes: 42 additions & 31 deletions drivers/net/ethernet/sfc/ef10.c
Original file line number Diff line number Diff line change
Expand Up @@ -2341,10 +2341,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
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;
}
Expand Down Expand Up @@ -2398,9 +2395,11 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
*/
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;
Expand Down Expand Up @@ -2442,8 +2441,11 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
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;
Expand Down Expand Up @@ -2542,26 +2544,41 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
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,
Expand Down Expand Up @@ -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);
}
}

table->entry[filter_idx].spec &= ~EFX_EF10_FILTER_FLAG_BUSY;
wake_up_all(&table->waitq);
out_unlock:
Expand Down Expand Up @@ -2731,8 +2749,6 @@ static s32 efx_ef10_filter_rfs_insert(struct efx_nic *efx,
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;
Expand Down Expand Up @@ -3118,9 +3134,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* 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);
Expand All @@ -3129,7 +3144,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* 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;
Expand All @@ -3138,9 +3153,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
}
}
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);
Expand All @@ -3155,9 +3169,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* 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);
Expand All @@ -3166,7 +3179,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
/* 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;
Expand All @@ -3175,9 +3188,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
}
}
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);
Expand All @@ -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++) {
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;
}
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/sfc/efx.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ efx_filter_get_filter_safe(struct efx_nic *efx,
* efx_farch_filter_clear_rx - remove RX filters by priority
* @efx: NIC from which to remove the filters
* @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,
enum efx_filter_priority priority)
Expand Down
28 changes: 12 additions & 16 deletions drivers/net/ethernet/sfc/farch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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;
Expand Down Expand Up @@ -2456,20 +2456,13 @@ s32 efx_farch_filter_insert(struct efx_nic *efx,
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 */
Expand Down Expand Up @@ -2553,7 +2546,7 @@ static int efx_farch_filter_remove(struct efx_nic *efx,
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 {
Expand Down Expand Up @@ -2637,8 +2630,11 @@ efx_farch_filter_table_clear(struct efx_nic *efx,
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);
}

Expand Down
17 changes: 10 additions & 7 deletions drivers/net/ethernet/sfc/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,16 @@ enum efx_filter_match_flags {
/**
* 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,
};
Expand All @@ -78,19 +82,18 @@ enum efx_filter_priority {
* 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,
};
Expand Down

0 comments on commit 7665d1a

Please sign in to comment.