From 205a55f4e65353dd4846547d376a6f85cdda3d04 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 22 Jul 2020 12:05:10 -0700 Subject: sfc: convert to new udp_tunnel infrastructure Check MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED, before setting the info, which will hopefully protect us from -EPERM errors the previous code was gracefully ignoring. Ed reports this is not the 100% correct bit, but it's the best approximation we have. Shared code reports the port information back to user space, so we really want to know what was added and what failed. Ignoring -EPERM is not an option. The driver does not call udp_tunnel_get_rx_info(), so its own management of table state is not really all that problematic, we can leave it be. This allows the driver to continue with its copious table syncing, and matching the ports to TX frames, which it will reportedly do one day. Leave the feature checking in the callbacks, as the device may remove the capabilities on reset. Inline the loop from __efx_ef10_udp_tnl_lookup_port() into efx_ef10_udp_tnl_has_port(), since it's the only caller now. With new infra this driver gains port replace - when space frees up in a full table a new port will be selected for offload. Plus efx will no longer sleep in an atomic context. v2: - amend the commit message about TRUSTED not being 100% - add TUNNEL_ENCAP_UDP_PORT_ENTRY_INVALID to mark unsed entries Signed-off-by: Jakub Kicinski Acked-By: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 162 +++++++++++++++------------------------- 1 file changed, 60 insertions(+), 102 deletions(-) (limited to 'drivers/net/ethernet/sfc/ef10.c') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index cb7b634a1150..fa7229fff2ff 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -22,6 +22,7 @@ #include #include #include +#include /* Hardware control for EF10 architecture including 'Huntington'. */ @@ -38,6 +39,7 @@ struct efx_ef10_vlan { }; static int efx_ef10_set_udp_tnl_ports(struct efx_nic *efx, bool unloading); +static const struct udp_tunnel_nic_info efx_ef10_udp_tunnels; static int efx_ef10_get_warm_boot_count(struct efx_nic *efx) { @@ -564,6 +566,9 @@ static int efx_ef10_probe(struct efx_nic *efx) goto fail2; mutex_init(&nic_data->udp_tunnels_lock); + for (i = 0; i < ARRAY_SIZE(nic_data->udp_tunnels); ++i) + nic_data->udp_tunnels[i].type = + TUNNEL_ENCAP_UDP_PORT_ENTRY_INVALID; /* Reset (most) configuration for this function */ rc = efx_mcdi_reset(efx, RESET_TYPE_ALL); @@ -665,6 +670,12 @@ static int efx_ef10_probe(struct efx_nic *efx) if (rc) goto fail_add_vid_0; + if (nic_data->datapath_caps & + (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN) && + efx->mcdi->fn_flags & + (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) + efx->net_dev->udp_tunnel_nic_info = &efx_ef10_udp_tunnels; + return 0; fail_add_vid_0: @@ -3702,8 +3713,8 @@ static int efx_ef10_set_udp_tnl_ports(struct efx_nic *efx, bool unloading) MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM); for (i = 0; i < ARRAY_SIZE(nic_data->udp_tunnels); ++i) { - if (nic_data->udp_tunnels[i].count && - nic_data->udp_tunnels[i].port) { + if (nic_data->udp_tunnels[i].type != + TUNNEL_ENCAP_UDP_PORT_ENTRY_INVALID) { efx_dword_t entry; EFX_POPULATE_DWORD_2(entry, @@ -3789,79 +3800,34 @@ static int efx_ef10_udp_tnl_push_ports(struct efx_nic *efx) return rc; } -static struct efx_udp_tunnel *__efx_ef10_udp_tnl_lookup_port(struct efx_nic *efx, - __be16 port) +static int efx_ef10_udp_tnl_set_port(struct net_device *dev, + unsigned int table, unsigned int entry, + struct udp_tunnel_info *ti) { - struct efx_ef10_nic_data *nic_data = efx->nic_data; - size_t i; + struct efx_nic *efx = netdev_priv(dev); + struct efx_ef10_nic_data *nic_data; + int efx_tunnel_type, rc; - for (i = 0; i < ARRAY_SIZE(nic_data->udp_tunnels); ++i) { - if (!nic_data->udp_tunnels[i].count) - continue; - if (nic_data->udp_tunnels[i].port == port) - return &nic_data->udp_tunnels[i]; - } - return NULL; -} - -static int efx_ef10_udp_tnl_add_port(struct efx_nic *efx, - struct efx_udp_tunnel tnl) -{ - struct efx_ef10_nic_data *nic_data = efx->nic_data; - struct efx_udp_tunnel *match; - char typebuf[8]; - size_t i; - int rc; + if (ti->type == UDP_TUNNEL_TYPE_VXLAN) + efx_tunnel_type = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN; + else + efx_tunnel_type = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE; + nic_data = efx->nic_data; if (!(nic_data->datapath_caps & (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN))) - return 0; - - efx_get_udp_tunnel_type_name(tnl.type, typebuf, sizeof(typebuf)); - netif_dbg(efx, drv, efx->net_dev, "Adding UDP tunnel (%s) port %d\n", - typebuf, ntohs(tnl.port)); + return -EOPNOTSUPP; mutex_lock(&nic_data->udp_tunnels_lock); /* Make sure all TX are stopped while we add to the table, else we * might race against an efx_features_check(). */ efx_device_detach_sync(efx); - - match = __efx_ef10_udp_tnl_lookup_port(efx, tnl.port); - if (match != NULL) { - if (match->type == tnl.type) { - netif_dbg(efx, drv, efx->net_dev, - "Referencing existing tunnel entry\n"); - match->count++; - /* No need to cause an MCDI update */ - rc = 0; - goto unlock_out; - } - efx_get_udp_tunnel_type_name(match->type, - typebuf, sizeof(typebuf)); - netif_dbg(efx, drv, efx->net_dev, - "UDP port %d is already in use by %s\n", - ntohs(tnl.port), typebuf); - rc = -EEXIST; - goto unlock_out; - } - - for (i = 0; i < ARRAY_SIZE(nic_data->udp_tunnels); ++i) - if (!nic_data->udp_tunnels[i].count) { - nic_data->udp_tunnels[i] = tnl; - nic_data->udp_tunnels[i].count = 1; - rc = efx_ef10_set_udp_tnl_ports(efx, false); - goto unlock_out; - } - - netif_dbg(efx, drv, efx->net_dev, - "Unable to add UDP tunnel (%s) port %d; insufficient resources.\n", - typebuf, ntohs(tnl.port)); - - rc = -ENOMEM; - -unlock_out: + nic_data->udp_tunnels[entry].type = efx_tunnel_type; + nic_data->udp_tunnels[entry].port = ti->port; + rc = efx_ef10_set_udp_tnl_ports(efx, false); mutex_unlock(&nic_data->udp_tunnels_lock); + return rc; } @@ -3873,6 +3839,7 @@ unlock_out: static bool efx_ef10_udp_tnl_has_port(struct efx_nic *efx, __be16 port) { struct efx_ef10_nic_data *nic_data = efx->nic_data; + size_t i; if (!(nic_data->datapath_caps & (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN))) @@ -3884,58 +3851,51 @@ static bool efx_ef10_udp_tnl_has_port(struct efx_nic *efx, __be16 port) */ return false; - return __efx_ef10_udp_tnl_lookup_port(efx, port) != NULL; + for (i = 0; i < ARRAY_SIZE(nic_data->udp_tunnels); ++i) + if (nic_data->udp_tunnels[i].type != + TUNNEL_ENCAP_UDP_PORT_ENTRY_INVALID && + nic_data->udp_tunnels[i].port == port) + return true; + + return false; } -static int efx_ef10_udp_tnl_del_port(struct efx_nic *efx, - struct efx_udp_tunnel tnl) +static int efx_ef10_udp_tnl_unset_port(struct net_device *dev, + unsigned int table, unsigned int entry, + struct udp_tunnel_info *ti) { - struct efx_ef10_nic_data *nic_data = efx->nic_data; - struct efx_udp_tunnel *match; - char typebuf[8]; + struct efx_nic *efx = netdev_priv(dev); + struct efx_ef10_nic_data *nic_data; int rc; - if (!(nic_data->datapath_caps & - (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN))) - return 0; - - efx_get_udp_tunnel_type_name(tnl.type, typebuf, sizeof(typebuf)); - netif_dbg(efx, drv, efx->net_dev, "Removing UDP tunnel (%s) port %d\n", - typebuf, ntohs(tnl.port)); + nic_data = efx->nic_data; mutex_lock(&nic_data->udp_tunnels_lock); /* Make sure all TX are stopped while we remove from the table, else we * might race against an efx_features_check(). */ efx_device_detach_sync(efx); - - match = __efx_ef10_udp_tnl_lookup_port(efx, tnl.port); - if (match != NULL) { - if (match->type == tnl.type) { - if (--match->count) { - /* Port is still in use, so nothing to do */ - netif_dbg(efx, drv, efx->net_dev, - "UDP tunnel port %d remains active\n", - ntohs(tnl.port)); - rc = 0; - goto out_unlock; - } - rc = efx_ef10_set_udp_tnl_ports(efx, false); - goto out_unlock; - } - efx_get_udp_tunnel_type_name(match->type, - typebuf, sizeof(typebuf)); - netif_warn(efx, drv, efx->net_dev, - "UDP port %d is actually in use by %s, not removing\n", - ntohs(tnl.port), typebuf); - } - rc = -ENOENT; - -out_unlock: + nic_data->udp_tunnels[entry].type = TUNNEL_ENCAP_UDP_PORT_ENTRY_INVALID; + nic_data->udp_tunnels[entry].port = 0; + rc = efx_ef10_set_udp_tnl_ports(efx, false); mutex_unlock(&nic_data->udp_tunnels_lock); + return rc; } +static const struct udp_tunnel_nic_info efx_ef10_udp_tunnels = { + .set_port = efx_ef10_udp_tnl_set_port, + .unset_port = efx_ef10_udp_tnl_unset_port, + .flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP, + .tables = { + { + .n_entries = 16, + .tunnel_types = UDP_TUNNEL_TYPE_VXLAN | + UDP_TUNNEL_TYPE_GENEVE, + }, + }, +}; + /* EF10 may have multiple datapath firmware variants within a * single version. Report which variants are running. */ @@ -4172,9 +4132,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .vlan_rx_add_vid = efx_ef10_vlan_rx_add_vid, .vlan_rx_kill_vid = efx_ef10_vlan_rx_kill_vid, .udp_tnl_push_ports = efx_ef10_udp_tnl_push_ports, - .udp_tnl_add_port = efx_ef10_udp_tnl_add_port, .udp_tnl_has_port = efx_ef10_udp_tnl_has_port, - .udp_tnl_del_port = efx_ef10_udp_tnl_del_port, #ifdef CONFIG_SFC_SRIOV .sriov_configure = efx_ef10_sriov_configure, .sriov_init = efx_ef10_sriov_init, -- cgit v1.2.3-70-g09d2