Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8803e150 authored by Ben Hutchings's avatar Ben Hutchings
Browse files

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: default avatarBen Hutchings <bhutchings@solarflare.com>
parent 14990a5d
Loading
Loading
Loading
Loading
+30 −17
Original line number Original line Diff line number Diff line
@@ -2186,23 +2186,17 @@ efx_farch_filter_to_gen_spec(struct efx_filter_spec *gen_spec,
}
}


static void
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
	/* 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->type = EFX_FARCH_FILTER_UC_DEF + filter_idx;
	spec->priority = EFX_FILTER_PRI_REQUIRED;
	spec->priority = EFX_FILTER_PRI_MANUAL;
	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;
	table->used_bitmap[0] |= 1 << filter_idx;
}
}


/* Build a filter entry and return its n-tuple key. */
/* 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;
			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) {
			/* 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 */
	/* Insert the filter */
@@ -2517,6 +2521,7 @@ efx_farch_filter_table_clear_entry(struct efx_nic *efx,
	static efx_oword_t filter;
	static efx_oword_t filter;


	EFX_WARN_ON_PARANOID(!test_bit(filter_idx, table->used_bitmap));
	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);
	__clear_bit(filter_idx, table->used_bitmap);
	--table->used;
	--table->used;
@@ -2550,9 +2555,8 @@ static int efx_farch_filter_remove(struct efx_nic *efx,
	    spec->priority > priority)
	    spec->priority > priority)
		return -ENOENT;
		return -ENOENT;


	if (table->id == EFX_FARCH_FILTER_TABLE_RX_DEF) {
	if (spec->flags & EFX_FILTER_FLAG_RX_STACK) {
		/* RX default filters must always exist */
		efx_farch_filter_init_rx_for_stack(efx, spec);
		efx_farch_filter_reset_rx_def(efx, filter_idx);
		efx_farch_filter_push_rx_config(efx);
		efx_farch_filter_push_rx_config(efx);
	} else {
	} else {
		efx_farch_filter_table_clear_entry(efx, table, filter_idx);
		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);
				     priority);
	efx_farch_filter_table_clear(efx, EFX_FARCH_FILTER_TABLE_RX_MAC,
	efx_farch_filter_table_clear(efx, EFX_FARCH_FILTER_TABLE_RX_MAC,
				     priority);
				     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,
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;
			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 */
		/* RX default filters must always exist */
		struct efx_farch_filter_spec *spec;
		unsigned i;
		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);
	efx_farch_filter_push_rx_config(efx);
+7 −0
Original line number Original line Diff line number Diff line
@@ -78,12 +78,19 @@ 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
 *	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_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 = 0x08,
	EFX_FILTER_FLAG_RX = 0x08,
	EFX_FILTER_FLAG_TX = 0x10,
	EFX_FILTER_FLAG_TX = 0x10,
};
};