Commit e5fbd977 authored by Jon Cooper's avatar Jon Cooper Committed by David S. Miller

sfc: configure UDP tunnel offload ports

Implement ndo_udp_tunnel_{add,del} to update the NIC's list of VXLAN and
 GENEVE UDP ports.  Also reset the port list to empty on driver load and
 on driver unload, with appropriate flag set on the unload case.
These port numbers are used for RX inner checksum offload, and in future
 will also be used for TX inner checksum offload and encapsulated TSO.
Signed-off-by: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d4e85477
This diff is collapsed.
...@@ -23,12 +23,15 @@ ...@@ -23,12 +23,15 @@
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "net_driver.h" #include "net_driver.h"
#include <net/gre.h>
#include <net/udp_tunnel.h>
#include "efx.h" #include "efx.h"
#include "nic.h" #include "nic.h"
#include "selftest.h" #include "selftest.h"
#include "sriov.h" #include "sriov.h"
#include "mcdi.h" #include "mcdi.h"
#include "mcdi_pcol.h"
#include "workarounds.h" #include "workarounds.h"
/************************************************************************** /**************************************************************************
...@@ -88,6 +91,21 @@ const char *const efx_reset_type_names[] = { ...@@ -88,6 +91,21 @@ const char *const efx_reset_type_names[] = {
[RESET_TYPE_MCDI_TIMEOUT] = "MCDI_TIMEOUT (FLR)", [RESET_TYPE_MCDI_TIMEOUT] = "MCDI_TIMEOUT (FLR)",
}; };
/* UDP tunnel type names */
static const char *const efx_udp_tunnel_type_names[] = {
[TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN] = "vxlan",
[TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE] = "geneve",
};
void efx_get_udp_tunnel_type_name(u16 type, char *buf, size_t buflen)
{
if (type < ARRAY_SIZE(efx_udp_tunnel_type_names) &&
efx_udp_tunnel_type_names[type] != NULL)
snprintf(buf, buflen, "%s", efx_udp_tunnel_type_names[type]);
else
snprintf(buf, buflen, "type %d", type);
}
/* Reset workqueue. If any NIC has a hardware failure then a reset will be /* Reset workqueue. If any NIC has a hardware failure then a reset will be
* queued onto this work queue. This is not a per-nic work queue, because * queued onto this work queue. This is not a per-nic work queue, because
* efx_reset_work() acquires the rtnl lock, so resets are naturally serialised. * efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
...@@ -2336,6 +2354,52 @@ static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vi ...@@ -2336,6 +2354,52 @@ static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vi
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int efx_udp_tunnel_type_map(enum udp_parsable_tunnel_type in)
{
switch (in) {
case UDP_TUNNEL_TYPE_VXLAN:
return TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN;
case UDP_TUNNEL_TYPE_GENEVE:
return TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE;
default:
return -1;
}
}
static void efx_udp_tunnel_add(struct net_device *dev, struct udp_tunnel_info *ti)
{
struct efx_nic *efx = netdev_priv(dev);
struct efx_udp_tunnel tnl;
int efx_tunnel_type;
efx_tunnel_type = efx_udp_tunnel_type_map(ti->type);
if (efx_tunnel_type < 0)
return;
tnl.type = (u16)efx_tunnel_type;
tnl.port = ti->port;
if (efx->type->udp_tnl_add_port)
(void)efx->type->udp_tnl_add_port(efx, tnl);
}
static void efx_udp_tunnel_del(struct net_device *dev, struct udp_tunnel_info *ti)
{
struct efx_nic *efx = netdev_priv(dev);
struct efx_udp_tunnel tnl;
int efx_tunnel_type;
efx_tunnel_type = efx_udp_tunnel_type_map(ti->type);
if (efx_tunnel_type < 0)
return;
tnl.type = (u16)efx_tunnel_type;
tnl.port = ti->port;
if (efx->type->udp_tnl_add_port)
(void)efx->type->udp_tnl_del_port(efx, tnl);
}
static const struct net_device_ops efx_netdev_ops = { static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open, .ndo_open = efx_net_open,
.ndo_stop = efx_net_stop, .ndo_stop = efx_net_stop,
...@@ -2366,6 +2430,8 @@ static const struct net_device_ops efx_netdev_ops = { ...@@ -2366,6 +2430,8 @@ static const struct net_device_ops efx_netdev_ops = {
#ifdef CONFIG_RFS_ACCEL #ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = efx_filter_rfs, .ndo_rx_flow_steer = efx_filter_rfs,
#endif #endif
.ndo_udp_tunnel_add = efx_udp_tunnel_add,
.ndo_udp_tunnel_del = efx_udp_tunnel_del,
}; };
static void efx_update_name(struct efx_nic *efx) static void efx_update_name(struct efx_nic *efx)
...@@ -2605,6 +2671,9 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) ...@@ -2605,6 +2671,9 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
efx_start_all(efx); efx_start_all(efx);
if (efx->type->udp_tnl_push_ports)
efx->type->udp_tnl_push_ports(efx);
return 0; return 0;
fail: fail:
...@@ -3261,6 +3330,9 @@ static int efx_pci_probe(struct pci_dev *pci_dev, ...@@ -3261,6 +3330,9 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
"PCIE error reporting unavailable (%d).\n", "PCIE error reporting unavailable (%d).\n",
rc); rc);
if (efx->type->udp_tnl_push_ports)
efx->type->udp_tnl_push_ports(efx);
return 0; return 0;
fail3: fail3:
......
...@@ -128,7 +128,7 @@ int efx_mcdi_init(struct efx_nic *efx) ...@@ -128,7 +128,7 @@ int efx_mcdi_init(struct efx_nic *efx)
return rc; return rc;
} }
void efx_mcdi_fini(struct efx_nic *efx) void efx_mcdi_detach(struct efx_nic *efx)
{ {
if (!efx->mcdi) if (!efx->mcdi)
return; return;
...@@ -137,6 +137,12 @@ void efx_mcdi_fini(struct efx_nic *efx) ...@@ -137,6 +137,12 @@ void efx_mcdi_fini(struct efx_nic *efx)
/* Relinquish the device (back to the BMC, if this is a LOM) */ /* Relinquish the device (back to the BMC, if this is a LOM) */
efx_mcdi_drv_attach(efx, false, NULL); efx_mcdi_drv_attach(efx, false, NULL);
}
void efx_mcdi_fini(struct efx_nic *efx)
{
if (!efx->mcdi)
return;
#ifdef CONFIG_SFC_MCDI_LOGGING #ifdef CONFIG_SFC_MCDI_LOGGING
free_page((unsigned long)efx->mcdi->iface.logging_buffer); free_page((unsigned long)efx->mcdi->iface.logging_buffer);
......
...@@ -142,6 +142,7 @@ static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx) ...@@ -142,6 +142,7 @@ static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx)
#endif #endif
int efx_mcdi_init(struct efx_nic *efx); int efx_mcdi_init(struct efx_nic *efx);
void efx_mcdi_detach(struct efx_nic *efx);
void efx_mcdi_fini(struct efx_nic *efx); void efx_mcdi_fini(struct efx_nic *efx);
int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const efx_dword_t *inbuf, int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const efx_dword_t *inbuf,
......
...@@ -554,6 +554,8 @@ extern const unsigned int efx_reset_type_max; ...@@ -554,6 +554,8 @@ extern const unsigned int efx_reset_type_max;
#define RESET_TYPE(type) \ #define RESET_TYPE(type) \
STRING_TABLE_LOOKUP(type, efx_reset_type) STRING_TABLE_LOOKUP(type, efx_reset_type)
void efx_get_udp_tunnel_type_name(u16 type, char *buf, size_t buflen);
enum efx_int_mode { enum efx_int_mode {
/* Be careful if altering to correct macro below */ /* Be careful if altering to correct macro below */
EFX_INT_MODE_MSIX = 0, EFX_INT_MODE_MSIX = 0,
...@@ -993,6 +995,15 @@ struct efx_mtd_partition { ...@@ -993,6 +995,15 @@ struct efx_mtd_partition {
char name[IFNAMSIZ + 20]; char name[IFNAMSIZ + 20];
}; };
struct efx_udp_tunnel {
u16 type; /* TUNNEL_ENCAP_UDP_PORT_ENTRY_foo, see mcdi_pcol.h */
__be16 port;
/* Count of repeated adds of the same port. Used only inside the list,
* not in request arguments.
*/
u16 count;
};
/** /**
* struct efx_nic_type - Efx device type definition * struct efx_nic_type - Efx device type definition
* @mem_bar: Get the memory BAR * @mem_bar: Get the memory BAR
...@@ -1113,6 +1124,10 @@ struct efx_mtd_partition { ...@@ -1113,6 +1124,10 @@ struct efx_mtd_partition {
* @set_mac_address: Set the MAC address of the device * @set_mac_address: Set the MAC address of the device
* @tso_versions: Returns mask of firmware-assisted TSO versions supported. * @tso_versions: Returns mask of firmware-assisted TSO versions supported.
* If %NULL, then device does not support any TSO version. * If %NULL, then device does not support any TSO version.
* @udp_tnl_push_ports: Push the list of UDP tunnel ports to the NIC if required.
* @udp_tnl_add_port: Add a UDP tunnel port
* @udp_tnl_has_port: Check if a port has been added as UDP tunnel
* @udp_tnl_del_port: Remove a UDP tunnel port
* @revision: Hardware architecture revision * @revision: Hardware architecture revision
* @txd_ptr_tbl_base: TX descriptor ring base address * @txd_ptr_tbl_base: TX descriptor ring base address
* @rxd_ptr_tbl_base: RX descriptor ring base address * @rxd_ptr_tbl_base: RX descriptor ring base address
...@@ -1272,6 +1287,10 @@ struct efx_nic_type { ...@@ -1272,6 +1287,10 @@ struct efx_nic_type {
int (*get_mac_address)(struct efx_nic *efx, unsigned char *perm_addr); int (*get_mac_address)(struct efx_nic *efx, unsigned char *perm_addr);
int (*set_mac_address)(struct efx_nic *efx); int (*set_mac_address)(struct efx_nic *efx);
u32 (*tso_versions)(struct efx_nic *efx); u32 (*tso_versions)(struct efx_nic *efx);
int (*udp_tnl_push_ports)(struct efx_nic *efx);
int (*udp_tnl_add_port)(struct efx_nic *efx, struct efx_udp_tunnel tnl);
bool (*udp_tnl_has_port)(struct efx_nic *efx, __be16 port);
int (*udp_tnl_del_port)(struct efx_nic *efx, struct efx_udp_tunnel tnl);
int revision; int revision;
unsigned int txd_ptr_tbl_base; unsigned int txd_ptr_tbl_base;
......
...@@ -369,6 +369,10 @@ enum { ...@@ -369,6 +369,10 @@ enum {
* @vport_mac: The MAC address on the vport, only for PFs; VFs will be zero * @vport_mac: The MAC address on the vport, only for PFs; VFs will be zero
* @vlan_list: List of VLANs added over the interface. Serialised by vlan_lock. * @vlan_list: List of VLANs added over the interface. Serialised by vlan_lock.
* @vlan_lock: Lock to serialize access to vlan_list. * @vlan_lock: Lock to serialize access to vlan_list.
* @udp_tunnels: UDP tunnel port numbers and types.
* @udp_tunnels_dirty: flag indicating a reboot occurred while pushing
* @udp_tunnels to hardware and thus the push must be re-done.
* @udp_tunnels_lock: Serialises writes to @udp_tunnels and @udp_tunnels_dirty.
*/ */
struct efx_ef10_nic_data { struct efx_ef10_nic_data {
struct efx_buffer mcdi_buf; struct efx_buffer mcdi_buf;
...@@ -405,6 +409,9 @@ struct efx_ef10_nic_data { ...@@ -405,6 +409,9 @@ struct efx_ef10_nic_data {
u8 vport_mac[ETH_ALEN]; u8 vport_mac[ETH_ALEN];
struct list_head vlan_list; struct list_head vlan_list;
struct mutex vlan_lock; struct mutex vlan_lock;
struct efx_udp_tunnel udp_tunnels[16];
bool udp_tunnels_dirty;
struct mutex udp_tunnels_lock;
}; };
int efx_init_sriov(void); int efx_init_sriov(void);
......
...@@ -326,6 +326,7 @@ static int siena_probe_nic(struct efx_nic *efx) ...@@ -326,6 +326,7 @@ static int siena_probe_nic(struct efx_nic *efx)
efx_nic_free_buffer(efx, &efx->irq_status); efx_nic_free_buffer(efx, &efx->irq_status);
fail4: fail4:
fail3: fail3:
efx_mcdi_detach(efx);
efx_mcdi_fini(efx); efx_mcdi_fini(efx);
fail1: fail1:
kfree(efx->nic_data); kfree(efx->nic_data);
...@@ -450,6 +451,7 @@ static void siena_remove_nic(struct efx_nic *efx) ...@@ -450,6 +451,7 @@ static void siena_remove_nic(struct efx_nic *efx)
efx_mcdi_reset(efx, RESET_TYPE_ALL); efx_mcdi_reset(efx, RESET_TYPE_ALL);
efx_mcdi_detach(efx);
efx_mcdi_fini(efx); efx_mcdi_fini(efx);
/* Tear down the private nic state */ /* Tear down the private nic state */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment