{
struct efx_ef10_filter_table *table = efx->filter_state;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ unsigned int invalid_filters = 0, failed = 0;
+ struct efx_ef10_filter_vlan *vlan;
struct efx_filter_spec *spec;
unsigned int filter_idx;
- bool failed = false;
+ u32 mcdi_flags;
+ int match_pri;
int rc;
WARN_ON(!rwsem_is_locked(&efx->filter_sem));
if (!spec)
continue;
+ mcdi_flags = efx_ef10_filter_mcdi_flags_from_spec(spec);
+ match_pri = 0;
+ while (match_pri < table->rx_match_count &&
+ table->rx_match_mcdi_flags[match_pri] != mcdi_flags)
+ ++match_pri;
+ if (match_pri >= table->rx_match_count) {
+ invalid_filters++;
+ goto not_restored;
+ }
+ if (spec->rss_context != EFX_FILTER_RSS_CONTEXT_DEFAULT &&
+ spec->rss_context != nic_data->rx_rss_context)
+ netif_warn(efx, drv, efx->net_dev,
+ "Warning: unable to restore a filter with specific RSS context.\n");
+
table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_BUSY;
spin_unlock_bh(&efx->filter_lock);
&table->entry[filter_idx].handle,
false);
if (rc)
- failed = true;
-
+ failed++;
spin_lock_bh(&efx->filter_lock);
+
if (rc) {
+not_restored:
+ list_for_each_entry(vlan, &table->vlan_list, list) {
+ if (vlan->ucdef == filter_idx)
+ vlan->ucdef = EFX_EF10_FILTER_ID_INVALID;
+ if (vlan->mcdef == filter_idx)
+ vlan->mcdef = EFX_EF10_FILTER_ID_INVALID;
+ if (vlan->bcast == filter_idx)
+ vlan->bcast = EFX_EF10_FILTER_ID_INVALID;
+ }
kfree(spec);
efx_ef10_filter_set_entry(table, filter_idx, NULL, 0);
} else {
spin_unlock_bh(&efx->filter_lock);
+ /* This can happen validly if the MC's capabilities have changed, so
+ * is not an error.
+ */
+ if (invalid_filters)
+ netif_dbg(efx, drv, efx->net_dev,
+ "Did not restore %u filters that are now unsupported.\n",
+ invalid_filters);
+
if (failed)
netif_err(efx, hw, efx->net_dev,
- "unable to restore all filters\n");
+ "unable to restore %u filters\n", failed);
else
nic_data->must_restore_filters = false;
}