diff options
Diffstat (limited to 'drivers/net/ethernet/sfc/filter.c')
-rw-r--r-- | drivers/net/ethernet/sfc/filter.c | 255 |
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: |