diff options
| -rw-r--r-- | drivers/net/ethernet/sfc/ef10.c | 141 | ||||
| -rw-r--r-- | drivers/net/ethernet/sfc/mcdi_filters.c | 15 | ||||
| -rw-r--r-- | drivers/net/ethernet/sfc/mcdi_filters.h | 9 |
3 files changed, 90 insertions, 75 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index b33bd6b77501..0779dda7d29f 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2388,6 +2388,76 @@ static void efx_ef10_tx_write(struct efx_tx_queue *tx_queue) } } +static int efx_ef10_probe_multicast_chaining(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + unsigned int enabled, implemented; + bool want_workaround_26807; + int rc; + + rc = efx_mcdi_get_workarounds(efx, &implemented, &enabled); + if (rc == -ENOSYS) { + /* GET_WORKAROUNDS was implemented before this workaround, + * thus it must be unavailable in this firmware. + */ + nic_data->workaround_26807 = false; + return 0; + } + if (rc) + return rc; + want_workaround_26807 = + implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807; + nic_data->workaround_26807 = + !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); + + if (want_workaround_26807 && !nic_data->workaround_26807) { + unsigned int flags; + + rc = efx_mcdi_set_workaround(efx, + MC_CMD_WORKAROUND_BUG26807, + true, &flags); + if (!rc) { + if (flags & + 1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN) { + netif_info(efx, drv, efx->net_dev, + "other functions on NIC have been reset\n"); + + /* With MCFW v4.6.x and earlier, the + * boot count will have incremented, + * so re-read the warm_boot_count + * value now to ensure this function + * doesn't think it has changed next + * time it checks. + */ + rc = efx_ef10_get_warm_boot_count(efx); + if (rc >= 0) { + nic_data->warm_boot_count = rc; + rc = 0; + } + } + nic_data->workaround_26807 = true; + } else if (rc == -EPERM) { + rc = 0; + } + } + return rc; +} + +static int efx_ef10_filter_table_probe(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc = efx_ef10_probe_multicast_chaining(efx); + + if (rc) + return rc; + rc = efx_mcdi_filter_table_probe(efx, nic_data->workaround_26807); + + if (rc) + return rc; + + return 0; +} + /* This creates an entry in the RX descriptor queue */ static inline void efx_ef10_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index) @@ -2463,75 +2533,14 @@ static int efx_ef10_ev_init(struct efx_channel *channel) { struct efx_nic *efx = channel->efx; struct efx_ef10_nic_data *nic_data; - unsigned int enabled, implemented; bool use_v2, cut_thru; - int rc; nic_data = efx->nic_data; use_v2 = nic_data->datapath_caps2 & 1 << MC_CMD_GET_CAPABILITIES_V2_OUT_INIT_EVQ_V2_LBN; cut_thru = !(nic_data->datapath_caps & 1 << MC_CMD_GET_CAPABILITIES_OUT_RX_BATCHING_LBN); - rc = efx_mcdi_ev_init(channel, cut_thru, use_v2); - - /* IRQ return is ignored */ - if (channel->channel || rc) - return rc; - - /* Successfully created event queue on channel 0 */ - rc = efx_mcdi_get_workarounds(efx, &implemented, &enabled); - if (rc == -ENOSYS) { - /* GET_WORKAROUNDS was implemented before this workaround, - * thus it must be unavailable in this firmware. - */ - nic_data->workaround_26807 = false; - rc = 0; - } else if (rc) { - goto fail; - } else { - nic_data->workaround_26807 = - !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); - - if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && - !nic_data->workaround_26807) { - unsigned int flags; - - rc = efx_mcdi_set_workaround(efx, - MC_CMD_WORKAROUND_BUG26807, - true, &flags); - - if (!rc) { - if (flags & - 1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN) { - netif_info(efx, drv, efx->net_dev, - "other functions on NIC have been reset\n"); - - /* With MCFW v4.6.x and earlier, the - * boot count will have incremented, - * so re-read the warm_boot_count - * value now to ensure this function - * doesn't think it has changed next - * time it checks. - */ - rc = efx_ef10_get_warm_boot_count(efx); - if (rc >= 0) { - nic_data->warm_boot_count = rc; - rc = 0; - } - } - nic_data->workaround_26807 = true; - } else if (rc == -EPERM) { - rc = 0; - } - } - } - - if (!rc) - return 0; - -fail: - efx_mcdi_ev_fini(channel); - return rc; + return efx_mcdi_ev_init(channel, cut_thru, use_v2); } static void efx_ef10_handle_rx_wrong_queue(struct efx_rx_queue *rx_queue, @@ -3185,7 +3194,7 @@ restore_vadaptor: goto reset_nic; restore_filters: down_write(&efx->filter_sem); - rc2 = efx_mcdi_filter_table_probe(efx); + rc2 = efx_ef10_filter_table_probe(efx); up_write(&efx->filter_sem); if (rc2) goto reset_nic; @@ -3227,7 +3236,7 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf, sizeof(inbuf), NULL, 0, NULL); - efx_mcdi_filter_table_probe(efx); + efx_ef10_filter_table_probe(efx); up_write(&efx->filter_sem); mutex_unlock(&efx->mac_lock); @@ -4041,7 +4050,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { .ev_process = efx_ef10_ev_process, .ev_read_ack = efx_ef10_ev_read_ack, .ev_test_generate = efx_ef10_ev_test_generate, - .filter_table_probe = efx_mcdi_filter_table_probe, + .filter_table_probe = efx_ef10_filter_table_probe, .filter_table_restore = efx_mcdi_filter_table_restore, .filter_table_remove = efx_mcdi_filter_table_remove, .filter_update_rx_scatter = efx_mcdi_update_rx_scatter, @@ -4154,7 +4163,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .ev_process = efx_ef10_ev_process, .ev_read_ack = efx_ef10_ev_read_ack, .ev_test_generate = efx_ef10_ev_test_generate, - .filter_table_probe = efx_mcdi_filter_table_probe, + .filter_table_probe = efx_ef10_filter_table_probe, .filter_table_restore = efx_mcdi_filter_table_restore, .filter_table_remove = efx_mcdi_filter_table_remove, .filter_update_rx_scatter = efx_mcdi_update_rx_scatter, diff --git a/drivers/net/ethernet/sfc/mcdi_filters.c b/drivers/net/ethernet/sfc/mcdi_filters.c index bb29fc0063bf..d3c2e6eb3191 100644 --- a/drivers/net/ethernet/sfc/mcdi_filters.c +++ b/drivers/net/ethernet/sfc/mcdi_filters.c @@ -811,7 +811,7 @@ static int efx_mcdi_filter_insert_def(struct efx_nic *efx, enum efx_encap_type encap_type, bool multicast, bool rollback) { - struct efx_ef10_nic_data *nic_data = efx->nic_data; + struct efx_mcdi_filter_table *table = efx->filter_state; enum efx_filter_flags filter_flags; struct efx_filter_spec spec; u8 baddr[ETH_ALEN]; @@ -896,7 +896,7 @@ static int efx_mcdi_filter_insert_def(struct efx_nic *efx, EFX_WARN_ON_PARANOID(*id != EFX_EF10_FILTER_ID_INVALID); *id = efx_mcdi_filter_get_unsafe_id(rc); - if (!nic_data->workaround_26807 && !encap_type) { + if (!table->mc_chaining && !encap_type) { /* Also need an Ethernet broadcast filter */ efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0); @@ -962,7 +962,6 @@ static void efx_mcdi_filter_vlan_sync_rx_mode(struct efx_nic *efx, struct efx_mcdi_filter_vlan *vlan) { struct efx_mcdi_filter_table *table = efx->filter_state; - struct efx_ef10_nic_data *nic_data = efx->nic_data; /* * Do not install unspecified VID if VLAN filtering is enabled. @@ -1009,11 +1008,10 @@ static void efx_mcdi_filter_vlan_sync_rx_mode(struct efx_nic *efx, * If changing promiscuous state with cascaded multicast filters, remove * old filters first, so that packets are dropped rather than duplicated */ - if (nic_data->workaround_26807 && - table->mc_promisc_last != table->mc_promisc) + if (table->mc_chaining && table->mc_promisc_last != table->mc_promisc) efx_mcdi_filter_remove_old(efx); if (table->mc_promisc) { - if (nic_data->workaround_26807) { + if (table->mc_chaining) { /* * If we failed to insert promiscuous filters, rollback * and fall back to individual multicast filters @@ -1048,7 +1046,7 @@ static void efx_mcdi_filter_vlan_sync_rx_mode(struct efx_nic *efx, */ if (efx_mcdi_filter_insert_addr_list(efx, vlan, true, true)) { /* Changing promisc state, so remove old filters */ - if (nic_data->workaround_26807) + if (table->mc_chaining) efx_mcdi_filter_remove_old(efx); if (efx_mcdi_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_NONE, @@ -1285,7 +1283,7 @@ efx_mcdi_filter_table_probe_matches(struct efx_nic *efx, return 0; } -int efx_mcdi_filter_table_probe(struct efx_nic *efx) +int efx_mcdi_filter_table_probe(struct efx_nic *efx, bool multicast_chaining) { struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; @@ -1303,6 +1301,7 @@ int efx_mcdi_filter_table_probe(struct efx_nic *efx) if (!table) return -ENOMEM; + table->mc_chaining = multicast_chaining; table->rx_match_count = 0; rc = efx_mcdi_filter_table_probe_matches(efx, table, false); if (rc) diff --git a/drivers/net/ethernet/sfc/mcdi_filters.h b/drivers/net/ethernet/sfc/mcdi_filters.h index 884ba9731131..15b5d62e3670 100644 --- a/drivers/net/ethernet/sfc/mcdi_filters.h +++ b/drivers/net/ethernet/sfc/mcdi_filters.h @@ -79,11 +79,18 @@ struct efx_mcdi_filter_table { bool must_restore_rss_contexts; /* filters have yet to be restored after MC reboot */ bool must_restore_filters; + /* Multicast filter chaining allows less-specific filters to receive + * multicast packets that matched more-specific filters. Early EF10 + * firmware didn't support this (SF bug 26807); if mc_chaining == false + * then we still subscribe the dev_mc_list even when mc_promisc to + * prevent another VI stealing the traffic. + */ + bool mc_chaining; bool vlan_filter; struct list_head vlan_list; }; -int efx_mcdi_filter_table_probe(struct efx_nic *efx); +int efx_mcdi_filter_table_probe(struct efx_nic *efx, bool multicast_chaining); void efx_mcdi_filter_table_remove(struct efx_nic *efx); void efx_mcdi_filter_table_restore(struct efx_nic *efx); |
