aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/sfc/filter.c')
-rw-r--r--drivers/net/ethernet/sfc/filter.c255
1 files changed, 223 insertions, 32 deletions
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c
index 1fbbbee7b1ae..fea7f7300675 100644
--- a/drivers/net/ethernet/sfc/filter.c
+++ b/drivers/net/ethernet/sfc/filter.c
@@ -35,9 +35,17 @@
enum efx_filter_table_id {
EFX_FILTER_TABLE_RX_IP = 0,
EFX_FILTER_TABLE_RX_MAC,
+ EFX_FILTER_TABLE_RX_DEF,
+ EFX_FILTER_TABLE_TX_MAC,
EFX_FILTER_TABLE_COUNT,
};
+enum efx_filter_index {
+ EFX_FILTER_INDEX_UC_DEF,
+ EFX_FILTER_INDEX_MC_DEF,
+ EFX_FILTER_SIZE_RX_DEF,
+};
+
struct efx_filter_table {
enum efx_filter_table_id id;
u32 offset; /* address of table relative to BAR */
@@ -90,8 +98,9 @@ efx_filter_spec_table_id(const struct efx_filter_spec *spec)
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_WILD >> 2));
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_FULL >> 2));
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_WILD >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_TX_MAC != EFX_FILTER_TABLE_RX_MAC + 2);
EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC);
- return spec->type >> 2;
+ return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0);
}
static struct efx_filter_table *
@@ -109,7 +118,7 @@ static void efx_filter_table_reset_search_depth(struct efx_filter_table *table)
memset(table->search_depth, 0, sizeof(table->search_depth));
}
-static void efx_filter_push_rx_limits(struct efx_nic *efx)
+static void efx_filter_push_rx_config(struct efx_nic *efx)
{
struct efx_filter_state *state = efx->filter_state;
struct efx_filter_table *table;
@@ -143,9 +152,58 @@ static void efx_filter_push_rx_limits(struct efx_nic *efx)
FILTER_CTL_SRCH_FUDGE_WILD);
}
+ table = &state->table[EFX_FILTER_TABLE_RX_DEF];
+ if (table->size) {
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_UNICAST_NOMATCH_Q_ID,
+ table->spec[EFX_FILTER_INDEX_UC_DEF].dmaq_id);
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED,
+ !!(table->spec[EFX_FILTER_INDEX_UC_DEF].flags &
+ EFX_FILTER_FLAG_RX_RSS));
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE,
+ !!(table->spec[EFX_FILTER_INDEX_UC_DEF].flags &
+ EFX_FILTER_FLAG_RX_OVERRIDE_IP));
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_MULTICAST_NOMATCH_Q_ID,
+ table->spec[EFX_FILTER_INDEX_MC_DEF].dmaq_id);
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED,
+ !!(table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
+ EFX_FILTER_FLAG_RX_RSS));
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE,
+ !!(table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
+ EFX_FILTER_FLAG_RX_OVERRIDE_IP));
+ }
+
efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
}
+static void efx_filter_push_tx_limits(struct efx_nic *efx)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ struct efx_filter_table *table;
+ efx_oword_t tx_cfg;
+
+ efx_reado(efx, &tx_cfg, FR_AZ_TX_CFG);
+
+ table = &state->table[EFX_FILTER_TABLE_TX_MAC];
+ if (table->size) {
+ EFX_SET_OWORD_FIELD(
+ tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
+ table->search_depth[EFX_FILTER_MAC_FULL] +
+ FILTER_CTL_SRCH_FUDGE_FULL);
+ EFX_SET_OWORD_FIELD(
+ tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
+ table->search_depth[EFX_FILTER_MAC_WILD] +
+ FILTER_CTL_SRCH_FUDGE_WILD);
+ }
+
+ efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG);
+}
+
static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec,
__be32 host1, __be16 port1,
__be32 host2, __be16 port2)
@@ -300,7 +358,8 @@ int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec,
int efx_filter_set_eth_local(struct efx_filter_spec *spec,
u16 vid, const u8 *addr)
{
- EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
+ EFX_BUG_ON_PARANOID(!(spec->flags &
+ (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
/* This cannot currently be combined with other filtering */
if (spec->type != EFX_FILTER_UNSPEC)
@@ -319,6 +378,52 @@ int efx_filter_set_eth_local(struct efx_filter_spec *spec,
return 0;
}
+/**
+ * efx_filter_set_uc_def - specify matching otherwise-unmatched unicast
+ * @spec: Specification to initialise
+ */
+int efx_filter_set_uc_def(struct efx_filter_spec *spec)
+{
+ EFX_BUG_ON_PARANOID(!(spec->flags &
+ (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
+
+ if (spec->type != EFX_FILTER_UNSPEC)
+ return -EINVAL;
+
+ spec->type = EFX_FILTER_UC_DEF;
+ memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */
+ return 0;
+}
+
+/**
+ * efx_filter_set_mc_def - specify matching otherwise-unmatched multicast
+ * @spec: Specification to initialise
+ */
+int efx_filter_set_mc_def(struct efx_filter_spec *spec)
+{
+ EFX_BUG_ON_PARANOID(!(spec->flags &
+ (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
+
+ if (spec->type != EFX_FILTER_UNSPEC)
+ return -EINVAL;
+
+ spec->type = EFX_FILTER_MC_DEF;
+ memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */
+ return 0;
+}
+
+static void efx_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ struct efx_filter_table *table = &state->table[EFX_FILTER_TABLE_RX_DEF];
+ struct efx_filter_spec *spec = &table->spec[filter_idx];
+
+ efx_filter_init_rx(spec, EFX_FILTER_PRI_MANUAL,
+ EFX_FILTER_FLAG_RX_RSS, 0);
+ spec->type = EFX_FILTER_UC_DEF + filter_idx;
+ table->used_bitmap[0] |= 1 << filter_idx;
+}
+
int efx_filter_get_eth_local(const struct efx_filter_spec *spec,
u16 *vid, u8 *addr)
{
@@ -366,6 +471,13 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
break;
}
+ case EFX_FILTER_TABLE_RX_DEF:
+ /* One filter spec per type */
+ BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0);
+ BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF !=
+ EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF);
+ return spec->type - EFX_FILTER_UC_DEF;
+
case EFX_FILTER_TABLE_RX_MAC: {
bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
EFX_POPULATE_OWORD_8(
@@ -385,6 +497,18 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
break;
}
+ case EFX_FILTER_TABLE_TX_MAC: {
+ bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
+ EFX_POPULATE_OWORD_5(*filter,
+ FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id,
+ FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
+ FRF_CZ_TMFT_SRC_MAC_HI, spec->data[2],
+ FRF_CZ_TMFT_SRC_MAC_LO, spec->data[1],
+ FRF_CZ_TMFT_VLAN_ID, spec->data[0]);
+ data3 = is_wild | spec->dmaq_id << 1;
+ break;
+ }
+
default:
BUG();
}
@@ -399,6 +523,10 @@ static bool efx_filter_equal(const struct efx_filter_spec *left,
memcmp(left->data, right->data, sizeof(left->data)))
return false;
+ if (left->flags & EFX_FILTER_FLAG_TX &&
+ left->dmaq_id != right->dmaq_id)
+ return false;
+
return true;
}
@@ -448,23 +576,40 @@ static int efx_filter_search(struct efx_filter_table *table,
* MAC filters without overriding behaviour.
*/
+#define EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP 0
+#define EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP 1
+#define EFX_FILTER_MATCH_PRI_NORMAL_BASE 2
+
#define EFX_FILTER_INDEX_WIDTH 13
#define EFX_FILTER_INDEX_MASK ((1 << EFX_FILTER_INDEX_WIDTH) - 1)
static inline u32 efx_filter_make_id(enum efx_filter_table_id table_id,
unsigned int index, u8 flags)
{
- return (table_id == EFX_FILTER_TABLE_RX_MAC &&
- flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) ?
- index :
- (table_id + 1) << EFX_FILTER_INDEX_WIDTH | index;
+ unsigned int match_pri = EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id;
+
+ if (flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) {
+ if (table_id == EFX_FILTER_TABLE_RX_MAC)
+ match_pri = EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP;
+ else if (table_id == EFX_FILTER_TABLE_RX_DEF)
+ match_pri = EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP;
+ }
+
+ return match_pri << EFX_FILTER_INDEX_WIDTH | index;
}
static inline enum efx_filter_table_id efx_filter_id_table_id(u32 id)
{
- return (id <= EFX_FILTER_INDEX_MASK) ?
- EFX_FILTER_TABLE_RX_MAC :
- (id >> EFX_FILTER_INDEX_WIDTH) - 1;
+ unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
+
+ switch (match_pri) {
+ case EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP:
+ return EFX_FILTER_TABLE_RX_MAC;
+ case EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP:
+ return EFX_FILTER_TABLE_RX_DEF;
+ default:
+ return match_pri - EFX_FILTER_MATCH_PRI_NORMAL_BASE;
+ }
}
static inline unsigned int efx_filter_id_index(u32 id)
@@ -474,23 +619,30 @@ static inline unsigned int efx_filter_id_index(u32 id)
static inline u8 efx_filter_id_flags(u32 id)
{
- return (id <= EFX_FILTER_INDEX_MASK) ?
- EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP :
- EFX_FILTER_FLAG_RX;
+ unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
+
+ if (match_pri < EFX_FILTER_MATCH_PRI_NORMAL_BASE)
+ return EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP;
+ else if (match_pri <=
+ EFX_FILTER_MATCH_PRI_NORMAL_BASE + EFX_FILTER_TABLE_RX_DEF)
+ return EFX_FILTER_FLAG_RX;
+ else
+ return EFX_FILTER_FLAG_TX;
}
u32 efx_filter_get_rx_id_limit(struct efx_nic *efx)
{
struct efx_filter_state *state = efx->filter_state;
+ unsigned int table_id = EFX_FILTER_TABLE_RX_DEF;
- if (state->table[EFX_FILTER_TABLE_RX_MAC].size != 0)
- return ((EFX_FILTER_TABLE_RX_MAC + 1) << EFX_FILTER_INDEX_WIDTH)
- + state->table[EFX_FILTER_TABLE_RX_MAC].size;
- else if (state->table[EFX_FILTER_TABLE_RX_IP].size != 0)
- return ((EFX_FILTER_TABLE_RX_IP + 1) << EFX_FILTER_INDEX_WIDTH)
- + state->table[EFX_FILTER_TABLE_RX_IP].size;
- else
- return 0;
+ do {
+ if (state->table[table_id].size != 0)
+ return ((EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id)
+ << EFX_FILTER_INDEX_WIDTH) +
+ state->table[table_id].size;
+ } while (table_id--);
+
+ return 0;
}
/**
@@ -548,12 +700,20 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
}
*saved_spec = *spec;
- if (table->search_depth[spec->type] < depth) {
- table->search_depth[spec->type] = depth;
- efx_filter_push_rx_limits(efx);
- }
+ if (table->id == EFX_FILTER_TABLE_RX_DEF) {
+ efx_filter_push_rx_config(efx);
+ } else {
+ if (table->search_depth[spec->type] < depth) {
+ table->search_depth[spec->type] = depth;
+ if (spec->flags & EFX_FILTER_FLAG_TX)
+ efx_filter_push_tx_limits(efx);
+ else
+ efx_filter_push_rx_config(efx);
+ }
- efx_writeo(efx, &filter, table->offset + table->step * filter_idx);
+ efx_writeo(efx, &filter,
+ table->offset + table->step * filter_idx);
+ }
netif_vdbg(efx, hw, efx->net_dev,
"%s: filter type %d index %d rxq %u set",
@@ -571,7 +731,11 @@ static void efx_filter_table_clear_entry(struct efx_nic *efx,
{
static efx_oword_t filter;
- if (test_bit(filter_idx, table->used_bitmap)) {
+ if (table->id == EFX_FILTER_TABLE_RX_DEF) {
+ /* RX default filters must always exist */
+ efx_filter_reset_rx_def(efx, filter_idx);
+ efx_filter_push_rx_config(efx);
+ } else if (test_bit(filter_idx, table->used_bitmap)) {
__clear_bit(filter_idx, table->used_bitmap);
--table->used;
memset(&table->spec[filter_idx], 0, sizeof(table->spec[0]));
@@ -617,7 +781,8 @@ int efx_filter_remove_id_safe(struct efx_nic *efx,
spin_lock_bh(&state->lock);
if (test_bit(filter_idx, table->used_bitmap) &&
- spec->priority == priority && spec->flags == filter_flags) {
+ spec->priority == priority &&
+ !((spec->flags ^ filter_flags) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
efx_filter_table_clear_entry(efx, table, filter_idx);
if (table->used == 0)
efx_filter_table_reset_search_depth(table);
@@ -668,7 +833,8 @@ int efx_filter_get_filter_safe(struct efx_nic *efx,
spin_lock_bh(&state->lock);
if (test_bit(filter_idx, table->used_bitmap) &&
- spec->priority == priority && spec->flags == filter_flags) {
+ spec->priority == priority &&
+ !((spec->flags ^ filter_flags) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
*spec_buf = *spec;
rc = 0;
} else {
@@ -722,7 +888,7 @@ u32 efx_filter_count_rx_used(struct efx_nic *efx,
spin_lock_bh(&state->lock);
for (table_id = EFX_FILTER_TABLE_RX_IP;
- table_id <= EFX_FILTER_TABLE_RX_MAC;
+ table_id <= EFX_FILTER_TABLE_RX_DEF;
table_id++) {
table = &state->table[table_id];
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
@@ -750,7 +916,7 @@ s32 efx_filter_get_rx_ids(struct efx_nic *efx,
spin_lock_bh(&state->lock);
for (table_id = EFX_FILTER_TABLE_RX_IP;
- table_id <= EFX_FILTER_TABLE_RX_MAC;
+ table_id <= EFX_FILTER_TABLE_RX_DEF;
table_id++) {
table = &state->table[table_id];
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
@@ -785,6 +951,11 @@ void efx_restore_filters(struct efx_nic *efx)
for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
table = &state->table[table_id];
+
+ /* Check whether this is a regular register table */
+ if (table->step == 0)
+ continue;
+
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
if (!test_bit(filter_idx, table->used_bitmap))
continue;
@@ -794,7 +965,8 @@ void efx_restore_filters(struct efx_nic *efx)
}
}
- efx_filter_push_rx_limits(efx);
+ efx_filter_push_rx_config(efx);
+ efx_filter_push_tx_limits(efx);
spin_unlock_bh(&state->lock);
}
@@ -833,6 +1005,16 @@ int efx_probe_filters(struct efx_nic *efx)
table->offset = FR_CZ_RX_MAC_FILTER_TBL0;
table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP;
+
+ table = &state->table[EFX_FILTER_TABLE_RX_DEF];
+ table->id = EFX_FILTER_TABLE_RX_DEF;
+ table->size = EFX_FILTER_SIZE_RX_DEF;
+
+ table = &state->table[EFX_FILTER_TABLE_TX_MAC];
+ table->id = EFX_FILTER_TABLE_TX_MAC;
+ table->offset = FR_CZ_TX_MAC_FILTER_TBL0;
+ table->size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
+ table->step = FR_CZ_TX_MAC_FILTER_TBL0_STEP;
}
for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
@@ -849,6 +1031,15 @@ int efx_probe_filters(struct efx_nic *efx)
goto fail;
}
+ if (state->table[EFX_FILTER_TABLE_RX_DEF].size) {
+ /* RX default filters must always exist */
+ unsigned i;
+ for (i = 0; i < EFX_FILTER_SIZE_RX_DEF; i++)
+ efx_filter_reset_rx_def(efx, i);
+ }
+
+ efx_filter_push_rx_config(efx);
+
return 0;
fail: