summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/efx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/sfc/efx.c')
-rw-r--r--drivers/net/ethernet/sfc/efx.c279
1 files changed, 187 insertions, 92 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 5a5dcad8c49a..334bcc6df6b2 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -23,12 +23,15 @@
#include <linux/aer.h>
#include <linux/interrupt.h>
#include "net_driver.h"
+#include <net/gre.h>
+#include <net/udp_tunnel.h>
#include "efx.h"
#include "nic.h"
#include "selftest.h"
#include "sriov.h"
#include "mcdi.h"
+#include "mcdi_pcol.h"
#include "workarounds.h"
/**************************************************************************
@@ -88,6 +91,21 @@ const char *const efx_reset_type_names[] = {
[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
* 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.
@@ -308,9 +326,6 @@ static int efx_poll(struct napi_struct *napi, int budget)
struct efx_nic *efx = channel->efx;
int spent;
- if (!efx_channel_lock_napi(channel))
- return budget;
-
netif_vdbg(efx, intr, efx->net_dev,
"channel %d NAPI poll executing on CPU %d\n",
channel->channel, raw_smp_processor_id());
@@ -331,11 +346,10 @@ static int efx_poll(struct napi_struct *napi, int budget)
* since efx_nic_eventq_read_ack() will have no effect if
* interrupts have already been disabled.
*/
- napi_complete(napi);
- efx_nic_eventq_read_ack(channel);
+ if (napi_complete_done(napi, spent))
+ efx_nic_eventq_read_ack(channel);
}
- efx_channel_unlock_napi(channel);
return spent;
}
@@ -391,7 +405,6 @@ void efx_start_eventq(struct efx_channel *channel)
channel->enabled = true;
smp_wmb();
- efx_channel_enable(channel);
napi_enable(&channel->napi_str);
efx_nic_eventq_read_ack(channel);
}
@@ -403,8 +416,6 @@ void efx_stop_eventq(struct efx_channel *channel)
return;
napi_disable(&channel->napi_str);
- while (!efx_channel_disable(channel))
- usleep_range(1000, 20000);
channel->enabled = false;
}
@@ -865,7 +876,7 @@ out:
efx_schedule_reset(efx, RESET_TYPE_DISABLE);
} else {
efx_start_all(efx);
- netif_device_attach(efx->net_dev);
+ efx_device_attach_if_not_resetting(efx);
}
return rc;
@@ -1409,9 +1420,12 @@ static int efx_probe_interrupts(struct efx_nic *efx)
xentries, 1, n_channels);
if (rc < 0) {
/* Fall back to single channel MSI */
- efx->interrupt_mode = EFX_INT_MODE_MSI;
netif_err(efx, drv, efx->net_dev,
"could not enable MSI-X\n");
+ if (efx->type->min_interrupt_mode >= EFX_INT_MODE_MSI)
+ efx->interrupt_mode = EFX_INT_MODE_MSI;
+ else
+ return rc;
} else if (rc < n_channels) {
netif_err(efx, drv, efx->net_dev,
"WARNING: Insufficient MSI-X vectors"
@@ -1454,7 +1468,10 @@ static int efx_probe_interrupts(struct efx_nic *efx)
} else {
netif_err(efx, drv, efx->net_dev,
"could not enable MSI\n");
- efx->interrupt_mode = EFX_INT_MODE_LEGACY;
+ if (efx->type->min_interrupt_mode >= EFX_INT_MODE_LEGACY)
+ efx->interrupt_mode = EFX_INT_MODE_LEGACY;
+ else
+ return rc;
}
}
@@ -2088,7 +2105,6 @@ static void efx_init_napi_channel(struct efx_channel *channel)
channel->napi_dev = efx->net_dev;
netif_napi_add(channel->napi_dev, &channel->napi_str,
efx_poll, napi_weight);
- efx_channel_busy_poll_init(channel);
}
static void efx_init_napi(struct efx_nic *efx)
@@ -2138,37 +2154,6 @@ static void efx_netpoll(struct net_device *net_dev)
#endif
-#ifdef CONFIG_NET_RX_BUSY_POLL
-static int efx_busy_poll(struct napi_struct *napi)
-{
- struct efx_channel *channel =
- container_of(napi, struct efx_channel, napi_str);
- struct efx_nic *efx = channel->efx;
- int budget = 4;
- int old_rx_packets, rx_packets;
-
- if (!netif_running(efx->net_dev))
- return LL_FLUSH_FAILED;
-
- if (!efx_channel_try_lock_poll(channel))
- return LL_FLUSH_BUSY;
-
- old_rx_packets = channel->rx_queue.rx_packets;
- efx_process_channel(channel, budget);
-
- rx_packets = channel->rx_queue.rx_packets - old_rx_packets;
-
- /* There is no race condition with NAPI here.
- * NAPI will automatically be rescheduled if it yielded during busy
- * polling, because it was not able to take the lock and thus returned
- * the full budget.
- */
- efx_channel_unlock_poll(channel);
-
- return rx_packets;
-}
-#endif
-
/**************************************************************************
*
* Kernel net device interface
@@ -2197,6 +2182,8 @@ int efx_net_open(struct net_device *net_dev)
efx_link_status_changed(efx);
efx_start_all(efx);
+ if (efx->state == STATE_DISABLED || efx->reset_pending)
+ netif_device_detach(efx->net_dev);
efx_selftest_async_start(efx);
return 0;
}
@@ -2219,16 +2206,14 @@ int efx_net_stop(struct net_device *net_dev)
}
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
-static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev,
- struct rtnl_link_stats64 *stats)
+static void efx_net_stats(struct net_device *net_dev,
+ struct rtnl_link_stats64 *stats)
{
struct efx_nic *efx = netdev_priv(net_dev);
spin_lock_bh(&efx->stats_lock);
efx->type->update_stats(efx, NULL, stats);
spin_unlock_bh(&efx->stats_lock);
-
- return stats;
}
/* Context: netif_tx_lock held, BHs disabled. */
@@ -2265,7 +2250,7 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
mutex_unlock(&efx->mac_lock);
efx_start_all(efx);
- netif_device_attach(efx->net_dev);
+ efx_device_attach_if_not_resetting(efx);
return 0;
}
@@ -2336,6 +2321,27 @@ static int efx_set_features(struct net_device *net_dev, netdev_features_t data)
return 0;
}
+static int efx_get_phys_port_id(struct net_device *net_dev,
+ struct netdev_phys_item_id *ppid)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (efx->type->get_phys_port_id)
+ return efx->type->get_phys_port_id(efx, ppid);
+ else
+ return -EOPNOTSUPP;
+}
+
+static int efx_get_phys_port_name(struct net_device *net_dev,
+ char *name, size_t len)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (snprintf(name, len, "p%u", efx->port_num) >= len)
+ return -EINVAL;
+ return 0;
+}
+
static int efx_vlan_rx_add_vid(struct net_device *net_dev, __be16 proto, u16 vid)
{
struct efx_nic *efx = netdev_priv(net_dev);
@@ -2356,6 +2362,52 @@ static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vi
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 = {
.ndo_open = efx_net_open,
.ndo_stop = efx_net_stop,
@@ -2376,18 +2428,18 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_set_vf_spoofchk = efx_sriov_set_vf_spoofchk,
.ndo_get_vf_config = efx_sriov_get_vf_config,
.ndo_set_vf_link_state = efx_sriov_set_vf_link_state,
- .ndo_get_phys_port_id = efx_sriov_get_phys_port_id,
#endif
+ .ndo_get_phys_port_id = efx_get_phys_port_id,
+ .ndo_get_phys_port_name = efx_get_phys_port_name,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = efx_netpoll,
#endif
.ndo_setup_tc = efx_setup_tc,
-#ifdef CONFIG_NET_RX_BUSY_POLL
- .ndo_busy_poll = efx_busy_poll,
-#endif
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = efx_filter_rfs,
#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)
@@ -2627,6 +2679,9 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
efx_start_all(efx);
+ if (efx->type->udp_tnl_push_ports)
+ efx->type->udp_tnl_push_ports(efx);
+
return 0;
fail:
@@ -2691,7 +2746,7 @@ out:
efx->state = STATE_DISABLED;
} else {
netif_dbg(efx, drv, efx->net_dev, "reset complete\n");
- netif_device_attach(efx->net_dev);
+ efx_device_attach_if_not_resetting(efx);
}
return rc;
}
@@ -2888,7 +2943,7 @@ static const struct efx_phy_operations efx_dummy_phy_operations = {
static int efx_init_struct(struct efx_nic *efx,
struct pci_dev *pci_dev, struct net_device *net_dev)
{
- int i;
+ int rc = -ENOMEM, i;
/* Initialise common structures */
INIT_LIST_HEAD(&efx->node);
@@ -2929,8 +2984,15 @@ static int efx_init_struct(struct efx_nic *efx,
}
/* Higher numbered interrupt modes are less capable! */
+ if (WARN_ON_ONCE(efx->type->max_interrupt_mode >
+ efx->type->min_interrupt_mode)) {
+ rc = -EIO;
+ goto fail;
+ }
efx->interrupt_mode = max(efx->type->max_interrupt_mode,
interrupt_mode);
+ efx->interrupt_mode = min(efx->type->min_interrupt_mode,
+ interrupt_mode);
/* Would be good to use the net_dev name, but we're too early */
snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s",
@@ -2943,7 +3005,7 @@ static int efx_init_struct(struct efx_nic *efx,
fail:
efx_fini_struct(efx);
- return -ENOMEM;
+ return rc;
}
static void efx_fini_struct(struct efx_nic *efx)
@@ -3158,6 +3220,51 @@ static int efx_pci_probe_main(struct efx_nic *efx)
return rc;
}
+static int efx_pci_probe_post_io(struct efx_nic *efx)
+{
+ struct net_device *net_dev = efx->net_dev;
+ int rc = efx_pci_probe_main(efx);
+
+ if (rc)
+ return rc;
+
+ if (efx->type->sriov_init) {
+ rc = efx->type->sriov_init(efx);
+ if (rc)
+ netif_err(efx, probe, efx->net_dev,
+ "SR-IOV can't be enabled rc %d\n", rc);
+ }
+
+ /* Determine netdevice features */
+ net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_RXCSUM);
+ if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
+ net_dev->features |= NETIF_F_TSO6;
+ /* Check whether device supports TSO */
+ if (!efx->type->tso_versions || !efx->type->tso_versions(efx))
+ net_dev->features &= ~NETIF_F_ALL_TSO;
+ /* Mask for features that also apply to VLAN devices */
+ net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
+ NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
+ NETIF_F_RXCSUM);
+
+ net_dev->hw_features = net_dev->features & ~efx->fixed_features;
+
+ /* Disable VLAN filtering by default. It may be enforced if
+ * the feature is fixed (i.e. VLAN filters are required to
+ * receive VLAN tagged packets due to vPort restrictions).
+ */
+ net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
+ net_dev->features |= efx->fixed_features;
+
+ rc = efx_register_netdev(efx);
+ if (!rc)
+ return 0;
+
+ efx_pci_remove_main(efx);
+ return rc;
+}
+
/* NIC initialisation
*
* This is called at module load (or hotplug insertion,
@@ -3200,42 +3307,28 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail2;
- rc = efx_pci_probe_main(efx);
+ rc = efx_pci_probe_post_io(efx);
+ if (rc) {
+ /* On failure, retry once immediately.
+ * If we aborted probe due to a scheduled reset, dismiss it.
+ */
+ efx->reset_pending = 0;
+ rc = efx_pci_probe_post_io(efx);
+ if (rc) {
+ /* On another failure, retry once more
+ * after a 50-305ms delay.
+ */
+ unsigned char r;
+
+ get_random_bytes(&r, 1);
+ msleep((unsigned int)r + 50);
+ efx->reset_pending = 0;
+ rc = efx_pci_probe_post_io(efx);
+ }
+ }
if (rc)
goto fail3;
- net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
- NETIF_F_TSO | NETIF_F_RXCSUM);
- if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
- net_dev->features |= NETIF_F_TSO6;
- /* Check whether device supports TSO */
- if (!efx->type->tso_versions || !efx->type->tso_versions(efx))
- net_dev->features &= ~NETIF_F_ALL_TSO;
- /* Mask for features that also apply to VLAN devices */
- net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
- NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
- NETIF_F_RXCSUM);
-
- net_dev->hw_features = net_dev->features & ~efx->fixed_features;
-
- /* Disable VLAN filtering by default. It may be enforced if
- * the feature is fixed (i.e. VLAN filters are required to
- * receive VLAN tagged packets due to vPort restrictions).
- */
- net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
- net_dev->features |= efx->fixed_features;
-
- rc = efx_register_netdev(efx);
- if (rc)
- goto fail4;
-
- if (efx->type->sriov_init) {
- rc = efx->type->sriov_init(efx);
- if (rc)
- netif_err(efx, probe, efx->net_dev,
- "SR-IOV can't be enabled rc %d\n", rc);
- }
-
netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");
/* Try to create MTDs, but allow this to fail */
@@ -3252,10 +3345,11 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
"PCIE error reporting unavailable (%d).\n",
rc);
+ if (efx->type->udp_tnl_push_ports)
+ efx->type->udp_tnl_push_ports(efx);
+
return 0;
- fail4:
- efx_pci_remove_main(efx);
fail3:
efx_fini_io(efx);
fail2:
@@ -3325,7 +3419,7 @@ static int efx_pm_thaw(struct device *dev)
efx_start_all(efx);
- netif_device_attach(efx->net_dev);
+ efx_device_attach_if_not_resetting(efx);
efx->state = STATE_READY;
@@ -3585,3 +3679,4 @@ MODULE_AUTHOR("Solarflare Communications and "
MODULE_DESCRIPTION("Solarflare network driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, efx_pci_table);
+MODULE_VERSION(EFX_DRIVER_VERSION);