diff options
Diffstat (limited to 'drivers/net/ethernet/sfc/ef10.c')
-rw-r--r-- | drivers/net/ethernet/sfc/ef10.c | 217 |
1 files changed, 134 insertions, 83 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 3f16bd807c6e..4b0e3695a71a 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -553,7 +553,7 @@ static int efx_ef10_probe(struct efx_nic *efx) efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; - nic_data->vport_id = EVB_PORT_ID_ASSIGNED; + efx->vport_id = EVB_PORT_ID_ASSIGNED; /* In case we're recovering from a crash (kexec), we want to * cancel any outstanding request by the previous user of this @@ -1281,13 +1281,13 @@ static int efx_ef10_init_nic(struct efx_nic *efx) nic_data->must_check_datapath_caps = false; } - if (nic_data->must_realloc_vis) { + if (efx->must_realloc_vis) { /* We cannot let the number of VIs change now */ rc = efx_ef10_alloc_vis(efx, nic_data->n_allocated_vis, nic_data->n_allocated_vis); if (rc) return rc; - nic_data->must_realloc_vis = false; + efx->must_realloc_vis = false; } if (nic_data->must_restore_piobufs && nic_data->n_piobufs) { @@ -1326,16 +1326,15 @@ static void efx_ef10_table_reset_mc_allocations(struct efx_nic *efx) #endif /* All our allocations have been reset */ - nic_data->must_realloc_vis = true; - nic_data->must_restore_rss_contexts = true; - nic_data->must_restore_filters = true; + efx->must_realloc_vis = true; + efx_mcdi_filter_table_reset_mc_allocations(efx); nic_data->must_restore_piobufs = true; efx_ef10_forget_old_piobufs(efx); efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; /* Driver-created vswitches and vports must be re-created */ nic_data->must_probe_vswitching = true; - nic_data->vport_id = EVB_PORT_ID_ASSIGNED; + efx->vport_id = EVB_PORT_ID_ASSIGNED; #ifdef CONFIG_SFC_SRIOV if (nic_data->vf) for (i = 0; i < efx->vf_count; i++) @@ -1820,6 +1819,7 @@ static size_t efx_ef10_update_stats_pf(struct efx_nic *efx, u64 *full_stats, } static int efx_ef10_try_update_nic_stats_vf(struct efx_nic *efx) + __must_hold(&efx->stats_lock) { MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN); struct efx_ef10_nic_data *nic_data = efx->nic_data; @@ -2389,6 +2389,86 @@ 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); + struct efx_mcdi_filter_vlan *vlan; + + if (rc) + return rc; + rc = efx_mcdi_filter_table_probe(efx, nic_data->workaround_26807); + + if (rc) + return rc; + + list_for_each_entry(vlan, &nic_data->vlan_list, list) { + rc = efx_mcdi_filter_add_vlan(efx, vlan->vid); + if (rc) + goto fail_add_vlan; + } + return 0; + +fail_add_vlan: + efx_mcdi_filter_table_remove(efx); + return rc; +} + /* 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) @@ -2464,75 +2544,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, @@ -3100,16 +3119,15 @@ void efx_ef10_handle_drain_event(struct efx_nic *efx) static int efx_ef10_fini_dmaq(struct efx_nic *efx) { - struct efx_ef10_nic_data *nic_data = efx->nic_data; - struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; + struct efx_channel *channel; int pending; /* If the MC has just rebooted, the TX/RX queues will have already been * torn down, but efx->active_queues needs to be set to zero. */ - if (nic_data->must_realloc_vis) { + if (efx->must_realloc_vis) { atomic_set(&efx->active_queues, 0); return 0; } @@ -3158,22 +3176,22 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx) efx_mcdi_filter_table_remove(efx); up_write(&efx->filter_sem); - rc = efx_ef10_vadaptor_free(efx, nic_data->vport_id); + rc = efx_ef10_vadaptor_free(efx, efx->vport_id); if (rc) goto restore_filters; ether_addr_copy(mac_old, nic_data->vport_mac); - rc = efx_ef10_vport_del_mac(efx, nic_data->vport_id, + rc = efx_ef10_vport_del_mac(efx, efx->vport_id, nic_data->vport_mac); if (rc) goto restore_vadaptor; - rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, + rc = efx_ef10_vport_add_mac(efx, efx->vport_id, efx->net_dev->dev_addr); if (!rc) { ether_addr_copy(nic_data->vport_mac, efx->net_dev->dev_addr); } else { - rc2 = efx_ef10_vport_add_mac(efx, nic_data->vport_id, mac_old); + rc2 = efx_ef10_vport_add_mac(efx, efx->vport_id, mac_old); if (rc2) { /* Failed to add original MAC, so clear vport_mac */ eth_zero_addr(nic_data->vport_mac); @@ -3182,12 +3200,12 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx) } restore_vadaptor: - rc2 = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); + rc2 = efx_ef10_vadaptor_alloc(efx, efx->vport_id); if (rc2) 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; @@ -3211,7 +3229,6 @@ reset_nic: static int efx_ef10_set_mac_address(struct efx_nic *efx) { MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN); - struct efx_ef10_nic_data *nic_data = efx->nic_data; bool was_enabled = efx->port_enabled; int rc; @@ -3225,11 +3242,11 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) ether_addr_copy(MCDI_PTR(inbuf, VADAPTOR_SET_MAC_IN_MACADDR), efx->net_dev->dev_addr); MCDI_SET_DWORD(inbuf, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID, - nic_data->vport_id); + efx->vport_id); 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); @@ -3239,6 +3256,7 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) #ifdef CONFIG_SFC_SRIOV if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) { + struct efx_ef10_nic_data *nic_data = efx->nic_data; struct pci_dev *pci_dev_pf = efx->pci_dev->physfn; if (rc == -EPERM) { @@ -3961,6 +3979,35 @@ out_unlock: return rc; } +/* EF10 may have multiple datapath firmware variants within a + * single version. Report which variants are running. + */ +static size_t efx_ef10_print_additional_fwver(struct efx_nic *efx, char *buf, + size_t len) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + + return scnprintf(buf, len, " rx%x tx%x", + nic_data->rx_dpcpu_fw_id, + nic_data->tx_dpcpu_fw_id); +} + +static unsigned int ef10_check_caps(const struct efx_nic *efx, + u8 flag, + u32 offset) +{ + const struct efx_ef10_nic_data *nic_data = efx->nic_data; + + switch (offset) { + case(MC_CMD_GET_CAPABILITIES_V4_OUT_FLAGS1_OFST): + return nic_data->datapath_caps & BIT_ULL(flag); + case(MC_CMD_GET_CAPABILITIES_V4_OUT_FLAGS2_OFST): + return nic_data->datapath_caps2 & BIT_ULL(flag); + default: + return 0; + } +} + #define EF10_OFFLOAD_FEATURES \ (NETIF_F_IP_CSUM | \ NETIF_F_HW_VLAN_CTAG_FILTER | \ @@ -4027,7 +4074,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, @@ -4073,6 +4120,8 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL, .rx_hash_key_size = 40, + .check_caps = ef10_check_caps, + .print_additional_fwver = efx_ef10_print_additional_fwver, }; const struct efx_nic_type efx_hunt_a0_nic_type = { @@ -4139,7 +4188,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, @@ -4208,4 +4257,6 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_ALL, .rx_hash_key_size = 40, + .check_caps = ef10_check_caps, + .print_additional_fwver = efx_ef10_print_additional_fwver, }; |