2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-28 07:04:00 +08:00

sfc: Fix dup unknown multicast/unicast filters after datapath reset

Filter match flags are not unique criteria to be mapped to priority
because of both unknown unicast and unknown multicast are mapped to
LOC_MAC_IG. So, local MAC is required to map filter to priority.
MCDI filter flags is unique criteria to find filter priority.

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Andrew Rybchenko 2016-06-15 17:49:30 +01:00 committed by David S. Miller
parent 8c91562075
commit 7ac0dd9de6

View File

@ -76,8 +76,8 @@ struct efx_ef10_dev_addr {
};
struct efx_ef10_filter_table {
/* The RX match field masks supported by this fw & hw, in order of priority */
enum efx_filter_match_flags rx_match_flags[
/* The MCDI match masks supported by this fw & hw, in order of priority */
u32 rx_match_mcdi_flags[
MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_MAXNUM];
unsigned int rx_match_count;
@ -3214,15 +3214,55 @@ static int efx_ef10_filter_push(struct efx_nic *efx,
return rc;
}
static int efx_ef10_filter_rx_match_pri(struct efx_ef10_filter_table *table,
enum efx_filter_match_flags match_flags)
static u32 efx_ef10_filter_mcdi_flags_from_spec(const struct efx_filter_spec *spec)
{
unsigned int match_flags = spec->match_flags;
u32 mcdi_flags = 0;
if (match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) {
match_flags &= ~EFX_FILTER_MATCH_LOC_MAC_IG;
mcdi_flags |=
is_multicast_ether_addr(spec->loc_mac) ?
(1 << MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) :
(1 << MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN);
}
#define MAP_FILTER_TO_MCDI_FLAG(gen_flag, mcdi_field) { \
unsigned int old_match_flags = match_flags; \
match_flags &= ~EFX_FILTER_MATCH_ ## gen_flag; \
if (match_flags != old_match_flags) \
mcdi_flags |= \
(1 << MC_CMD_FILTER_OP_IN_MATCH_ ## \
mcdi_field ## _LBN); \
}
MAP_FILTER_TO_MCDI_FLAG(REM_HOST, SRC_IP);
MAP_FILTER_TO_MCDI_FLAG(LOC_HOST, DST_IP);
MAP_FILTER_TO_MCDI_FLAG(REM_MAC, SRC_MAC);
MAP_FILTER_TO_MCDI_FLAG(REM_PORT, SRC_PORT);
MAP_FILTER_TO_MCDI_FLAG(LOC_MAC, DST_MAC);
MAP_FILTER_TO_MCDI_FLAG(LOC_PORT, DST_PORT);
MAP_FILTER_TO_MCDI_FLAG(ETHER_TYPE, ETHER_TYPE);
MAP_FILTER_TO_MCDI_FLAG(INNER_VID, INNER_VLAN);
MAP_FILTER_TO_MCDI_FLAG(OUTER_VID, OUTER_VLAN);
MAP_FILTER_TO_MCDI_FLAG(IP_PROTO, IP_PROTO);
#undef MAP_FILTER_TO_MCDI_FLAG
/* Did we map them all? */
WARN_ON_ONCE(match_flags);
return mcdi_flags;
}
static int efx_ef10_filter_pri(struct efx_ef10_filter_table *table,
const struct efx_filter_spec *spec)
{
u32 mcdi_flags = efx_ef10_filter_mcdi_flags_from_spec(spec);
unsigned int match_pri;
for (match_pri = 0;
match_pri < table->rx_match_count;
match_pri++)
if (table->rx_match_flags[match_pri] == match_flags)
if (table->rx_match_mcdi_flags[match_pri] == mcdi_flags)
return match_pri;
return -EPROTONOSUPPORT;
@ -3248,7 +3288,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
EFX_FILTER_FLAG_RX)
return -EINVAL;
rc = efx_ef10_filter_rx_match_pri(table, spec->match_flags);
rc = efx_ef10_filter_pri(table, spec);
if (rc < 0)
return rc;
match_pri = rc;
@ -3487,7 +3527,7 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
spec = efx_ef10_filter_entry_spec(table, filter_idx);
if (!spec ||
(!by_index &&
efx_ef10_filter_rx_match_pri(table, spec->match_flags) !=
efx_ef10_filter_pri(table, spec) !=
filter_id / HUNT_FILTER_TBL_ROWS)) {
rc = -ENOENT;
goto out_unlock;
@ -3589,7 +3629,7 @@ static int efx_ef10_filter_get_safe(struct efx_nic *efx,
spin_lock_bh(&efx->filter_lock);
saved_spec = efx_ef10_filter_entry_spec(table, filter_idx);
if (saved_spec && saved_spec->priority == priority &&
efx_ef10_filter_rx_match_pri(table, saved_spec->match_flags) ==
efx_ef10_filter_pri(table, saved_spec) ==
filter_id / HUNT_FILTER_TBL_ROWS) {
*spec = *saved_spec;
rc = 0;
@ -3662,8 +3702,7 @@ static s32 efx_ef10_filter_get_rx_ids(struct efx_nic *efx,
count = -EMSGSIZE;
break;
}
buf[count++] = (efx_ef10_filter_rx_match_pri(
table, spec->match_flags) *
buf[count++] = (efx_ef10_filter_pri(table, spec) *
HUNT_FILTER_TBL_ROWS +
filter_idx);
}
@ -3915,6 +3954,24 @@ static void efx_ef10_filter_cleanup_vlans(struct efx_nic *efx)
efx_ef10_filter_del_vlan_internal(efx, vlan);
}
static bool efx_ef10_filter_match_supported(struct efx_ef10_filter_table *table,
enum efx_filter_match_flags match_flags)
{
unsigned int match_pri;
int mf;
for (match_pri = 0;
match_pri < table->rx_match_count;
match_pri++) {
mf = efx_ef10_filter_match_flags_from_mcdi(
table->rx_match_mcdi_flags[match_pri]);
if (mf == match_flags)
return true;
}
return false;
}
static int efx_ef10_filter_table_probe(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PARSER_DISP_INFO_IN_LEN);
@ -3964,7 +4021,8 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx)
"%s: fw flags %#x pri %u supported as driver flags %#x pri %u\n",
__func__, mcdi_flags, pd_match_pri,
rc, table->rx_match_count);
table->rx_match_flags[table->rx_match_count++] = rc;
table->rx_match_mcdi_flags[table->rx_match_count] = mcdi_flags;
table->rx_match_count++;
}
}