summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/ef10.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/sfc/ef10.c')
-rw-r--r--drivers/net/ethernet/sfc/ef10.c162
1 files changed, 60 insertions, 102 deletions
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 <linux/jhash.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <net/udp_tunnel.h>
/* 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,