Skip to content

Commit 0ccb998

Browse files
jco-xilinxdavem330
authored andcommitted
sfc: fix filter_id misinterpretation in edge case
On EF10, hardware filter IDs are 13 bits, but in some places we store 32-bit "full filter IDs" in which higher order bits encode the filter match-priority. This could cause a filter to have a full filter ID of 0xffff, which is also the value EFX_EF10_FILTER_ID_INVALID which we use in 16-bit "short" filter IDs (without match-priority bits). This would occur if the hardware filter ID was 0x1fff and the match-priority was 7. Unfortunately, some code that checks for EFX_EF10_FILTER_ID_INVALID can be called on full filter IDs, and will WARN_ON if this ever happens. So, since we have plenty of spare bits in the full filter ID, this patch shifts the priority bits left one bit when constructing the full filter IDs, ensuring that the 0x2000 bit of a full filter ID will always be 0 and thus no full filter ID can ever equal EFX_EF10_FILTER_ID_INVALID. This patch also replaces open-coded full<->short filter ID conversions with calls to functions, thus keeping the definition of the full filter ID format in one place. Signed-off-by: Edward Cree <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent fbdf0e2 commit 0ccb998

File tree

1 file changed

+30
-18
lines changed
  • drivers/net/ethernet/sfc

1 file changed

+30
-18
lines changed

drivers/net/ethernet/sfc/ef10.c

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,22 @@ static void efx_ef10_filter_del_vlan_internal(struct efx_nic *efx,
134134
static void efx_ef10_filter_del_vlan(struct efx_nic *efx, u16 vid);
135135
static int efx_ef10_set_udp_tnl_ports(struct efx_nic *efx, bool unloading);
136136

137+
static u32 efx_ef10_filter_get_unsafe_id(u32 filter_id)
138+
{
139+
WARN_ON_ONCE(filter_id == EFX_EF10_FILTER_ID_INVALID);
140+
return filter_id & (HUNT_FILTER_TBL_ROWS - 1);
141+
}
142+
143+
static unsigned int efx_ef10_filter_get_unsafe_pri(u32 filter_id)
144+
{
145+
return filter_id / (HUNT_FILTER_TBL_ROWS * 2);
146+
}
147+
148+
static u32 efx_ef10_make_filter_id(unsigned int pri, u16 idx)
149+
{
150+
return pri * HUNT_FILTER_TBL_ROWS * 2 + idx;
151+
}
152+
137153
static int efx_ef10_get_warm_boot_count(struct efx_nic *efx)
138154
{
139155
efx_dword_t reg;
@@ -4194,7 +4210,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
41944210

41954211
/* If successful, return the inserted filter ID */
41964212
if (rc == 0)
4197-
rc = match_pri * HUNT_FILTER_TBL_ROWS + ins_index;
4213+
rc = efx_ef10_make_filter_id(match_pri, ins_index);
41984214

41994215
wake_up_all(&table->waitq);
42004216
out_unlock:
@@ -4217,7 +4233,7 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
42174233
unsigned int priority_mask,
42184234
u32 filter_id, bool by_index)
42194235
{
4220-
unsigned int filter_idx = filter_id % HUNT_FILTER_TBL_ROWS;
4236+
unsigned int filter_idx = efx_ef10_filter_get_unsafe_id(filter_id);
42214237
struct efx_ef10_filter_table *table = efx->filter_state;
42224238
MCDI_DECLARE_BUF(inbuf,
42234239
MC_CMD_FILTER_OP_IN_HANDLE_OFST +
@@ -4244,7 +4260,7 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
42444260
if (!spec ||
42454261
(!by_index &&
42464262
efx_ef10_filter_pri(table, spec) !=
4247-
filter_id / HUNT_FILTER_TBL_ROWS)) {
4263+
efx_ef10_filter_get_unsafe_pri(filter_id))) {
42484264
rc = -ENOENT;
42494265
goto out_unlock;
42504266
}
@@ -4319,11 +4335,6 @@ static int efx_ef10_filter_remove_safe(struct efx_nic *efx,
43194335
filter_id, false);
43204336
}
43214337

4322-
static u32 efx_ef10_filter_get_unsafe_id(struct efx_nic *efx, u32 filter_id)
4323-
{
4324-
return filter_id % HUNT_FILTER_TBL_ROWS;
4325-
}
4326-
43274338
static void efx_ef10_filter_remove_unsafe(struct efx_nic *efx,
43284339
enum efx_filter_priority priority,
43294340
u32 filter_id)
@@ -4337,7 +4348,7 @@ static int efx_ef10_filter_get_safe(struct efx_nic *efx,
43374348
enum efx_filter_priority priority,
43384349
u32 filter_id, struct efx_filter_spec *spec)
43394350
{
4340-
unsigned int filter_idx = filter_id % HUNT_FILTER_TBL_ROWS;
4351+
unsigned int filter_idx = efx_ef10_filter_get_unsafe_id(filter_id);
43414352
struct efx_ef10_filter_table *table = efx->filter_state;
43424353
const struct efx_filter_spec *saved_spec;
43434354
int rc;
@@ -4346,7 +4357,7 @@ static int efx_ef10_filter_get_safe(struct efx_nic *efx,
43464357
saved_spec = efx_ef10_filter_entry_spec(table, filter_idx);
43474358
if (saved_spec && saved_spec->priority == priority &&
43484359
efx_ef10_filter_pri(table, saved_spec) ==
4349-
filter_id / HUNT_FILTER_TBL_ROWS) {
4360+
efx_ef10_filter_get_unsafe_pri(filter_id)) {
43504361
*spec = *saved_spec;
43514362
rc = 0;
43524363
} else {
@@ -4398,7 +4409,7 @@ static u32 efx_ef10_filter_get_rx_id_limit(struct efx_nic *efx)
43984409
{
43994410
struct efx_ef10_filter_table *table = efx->filter_state;
44004411

4401-
return table->rx_match_count * HUNT_FILTER_TBL_ROWS;
4412+
return table->rx_match_count * HUNT_FILTER_TBL_ROWS * 2;
44024413
}
44034414

44044415
static s32 efx_ef10_filter_get_rx_ids(struct efx_nic *efx,
@@ -4418,8 +4429,9 @@ static s32 efx_ef10_filter_get_rx_ids(struct efx_nic *efx,
44184429
count = -EMSGSIZE;
44194430
break;
44204431
}
4421-
buf[count++] = (efx_ef10_filter_pri(table, spec) *
4422-
HUNT_FILTER_TBL_ROWS +
4432+
buf[count++] =
4433+
efx_ef10_make_filter_id(
4434+
efx_ef10_filter_pri(table, spec),
44234435
filter_idx);
44244436
}
44254437
}
@@ -4971,7 +4983,7 @@ static void efx_ef10_filter_mark_one_old(struct efx_nic *efx, uint16_t *id)
49714983
unsigned int filter_idx;
49724984

49734985
if (*id != EFX_EF10_FILTER_ID_INVALID) {
4974-
filter_idx = efx_ef10_filter_get_unsafe_id(efx, *id);
4986+
filter_idx = efx_ef10_filter_get_unsafe_id(*id);
49754987
if (!table->entry[filter_idx].spec)
49764988
netif_dbg(efx, drv, efx->net_dev,
49774989
"marked null spec old %04x:%04x\n", *id,
@@ -5106,7 +5118,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
51065118
rc = EFX_EF10_FILTER_ID_INVALID;
51075119
}
51085120
}
5109-
ids[i] = efx_ef10_filter_get_unsafe_id(efx, rc);
5121+
ids[i] = efx_ef10_filter_get_unsafe_id(rc);
51105122
}
51115123

51125124
if (multicast && rollback) {
@@ -5130,7 +5142,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
51305142
return rc;
51315143
} else {
51325144
vlan->default_filters[EFX_EF10_BCAST] =
5133-
efx_ef10_filter_get_unsafe_id(efx, rc);
5145+
efx_ef10_filter_get_unsafe_id(rc);
51345146
}
51355147
}
51365148

@@ -5225,7 +5237,7 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx,
52255237
id = &vlan->default_filters[map[encap_type]];
52265238

52275239
EFX_WARN_ON_PARANOID(*id != EFX_EF10_FILTER_ID_INVALID);
5228-
*id = efx_ef10_filter_get_unsafe_id(efx, rc);
5240+
*id = efx_ef10_filter_get_unsafe_id(rc);
52295241
if (!nic_data->workaround_26807 && !encap_type) {
52305242
/* Also need an Ethernet broadcast filter */
52315243
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
@@ -5250,7 +5262,7 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx,
52505262
vlan->default_filters[EFX_EF10_BCAST] !=
52515263
EFX_EF10_FILTER_ID_INVALID);
52525264
vlan->default_filters[EFX_EF10_BCAST] =
5253-
efx_ef10_filter_get_unsafe_id(efx, rc);
5265+
efx_ef10_filter_get_unsafe_id(rc);
52545266
}
52555267
}
52565268
rc = 0;

0 commit comments

Comments
 (0)