diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-11-19 23:08:20 +0000 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2013-08-22 19:25:59 +0100 |
commit | 8803e15042fbf5bd53b9b43147a91e3f50cffb03 (patch) | |
tree | d2235bad8fa93762996e6004be336572a266a71b /drivers/net | |
parent | 14990a5d66b5b51a422bc46a9e8fedb20d8a770c (diff) | |
download | linux-8803e15042fbf5bd53b9b43147a91e3f50cffb03.tar.bz2 |
sfc: Add flag for stack-owned RX MAC filters
MAC filters inserted on request from the stack (ndo_set_rx_mode)
should allow manual steering but not removal. Currently we have a
special case for Siena's all-multicast and all-unicast MAC filters,
but on EF10 we need to allow for steering of precise MAC filters as
well.
The EFX_FILTER_FLAG_RX_STACK flag changes the behaviour of replacement
and removal requests:
- Replacement *of* a filter with this flag never clears the flag but
does change steering and saved priority
- Replacement *by* a filter with this flag only sets the flag but does
not change steering
- Removal with priority < EFX_FILTER_PRI_REQUIRED really resets RX
steering and saved priority
This could support precise MAC filtering on Siena in future.
As a side-benefit, the default MAC filters are hidden from ethtool
until they are steered.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/sfc/farch.c | 47 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/filter.h | 7 |
2 files changed, 37 insertions, 17 deletions
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index d91bcedb9971..1e21e51a808b 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -2186,23 +2186,17 @@ efx_farch_filter_to_gen_spec(struct efx_filter_spec *gen_spec, } static void -efx_farch_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx) +efx_farch_filter_init_rx_for_stack(struct efx_nic *efx, + struct efx_farch_filter_spec *spec) { - struct efx_farch_filter_state *state = efx->filter_state; - struct efx_farch_filter_table *table = - &state->table[EFX_FARCH_FILTER_TABLE_RX_DEF]; - struct efx_farch_filter_spec *spec = &table->spec[filter_idx]; - /* 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->type = EFX_FARCH_FILTER_UC_DEF + filter_idx; - spec->priority = EFX_FILTER_PRI_MANUAL; - spec->flags = (EFX_FILTER_FLAG_RX | + spec->priority = EFX_FILTER_PRI_REQUIRED; + spec->flags = (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_STACK | (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) | (efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0)); spec->dmaq_id = 0; - table->used_bitmap[0] |= 1 << filter_idx; } /* Build a filter entry and return its n-tuple key. */ @@ -2464,10 +2458,20 @@ s32 efx_farch_filter_insert(struct efx_nic *efx, rc = -EEXIST; 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; 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; } /* Insert the filter */ @@ -2517,6 +2521,7 @@ efx_farch_filter_table_clear_entry(struct efx_nic *efx, static efx_oword_t filter; EFX_WARN_ON_PARANOID(!test_bit(filter_idx, table->used_bitmap)); + BUG_ON(table->offset == 0); /* can't clear MAC default filters */ __clear_bit(filter_idx, table->used_bitmap); --table->used; @@ -2550,9 +2555,8 @@ static int efx_farch_filter_remove(struct efx_nic *efx, spec->priority > priority) return -ENOENT; - if (table->id == EFX_FARCH_FILTER_TABLE_RX_DEF) { - /* RX default filters must always exist */ - efx_farch_filter_reset_rx_def(efx, filter_idx); + if (spec->flags & EFX_FILTER_FLAG_RX_STACK) { + efx_farch_filter_init_rx_for_stack(efx, spec); efx_farch_filter_push_rx_config(efx); } else { efx_farch_filter_table_clear_entry(efx, table, filter_idx); @@ -2647,6 +2651,8 @@ void efx_farch_filter_clear_rx(struct efx_nic *efx, priority); efx_farch_filter_table_clear(efx, EFX_FARCH_FILTER_TABLE_RX_MAC, priority); + efx_farch_filter_table_clear(efx, EFX_FARCH_FILTER_TABLE_RX_DEF, + priority); } u32 efx_farch_filter_count_rx_used(struct efx_nic *efx, @@ -2806,11 +2812,18 @@ int efx_farch_filter_table_probe(struct efx_nic *efx) goto fail; } - if (state->table[EFX_FARCH_FILTER_TABLE_RX_DEF].size) { + table = &state->table[EFX_FARCH_FILTER_TABLE_RX_DEF]; + if (table->size) { /* RX default filters must always exist */ + struct efx_farch_filter_spec *spec; unsigned i; - for (i = 0; i < EFX_FARCH_FILTER_SIZE_RX_DEF; i++) - efx_farch_filter_reset_rx_def(efx, i); + + for (i = 0; i < EFX_FARCH_FILTER_SIZE_RX_DEF; i++) { + spec = &table->spec[i]; + spec->type = EFX_FARCH_FILTER_UC_DEF + i; + efx_farch_filter_init_rx_for_stack(efx, spec); + __set_bit(i, table->used_bitmap); + } } efx_farch_filter_push_rx_config(efx); diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h index 1b410defccec..e459e43a2798 100644 --- a/drivers/net/ethernet/sfc/filter.h +++ b/drivers/net/ethernet/sfc/filter.h @@ -78,12 +78,19 @@ 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: 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 = 0x08, EFX_FILTER_FLAG_TX = 0x10, }; |