162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/**************************************************************************** 362306a36Sopenharmony_ci * Driver for Solarflare network controllers and boards 462306a36Sopenharmony_ci * Copyright 2005-2006 Fen Systems Ltd. 562306a36Sopenharmony_ci * Copyright 2005-2013 Solarflare Communications Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/filter.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/notifier.h> 1562306a36Sopenharmony_ci#include <linux/ip.h> 1662306a36Sopenharmony_ci#include <linux/tcp.h> 1762306a36Sopenharmony_ci#include <linux/in.h> 1862306a36Sopenharmony_ci#include <linux/ethtool.h> 1962306a36Sopenharmony_ci#include <linux/topology.h> 2062306a36Sopenharmony_ci#include <linux/gfp.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include "net_driver.h" 2362306a36Sopenharmony_ci#include <net/gre.h> 2462306a36Sopenharmony_ci#include <net/udp_tunnel.h> 2562306a36Sopenharmony_ci#include "efx.h" 2662306a36Sopenharmony_ci#include "efx_common.h" 2762306a36Sopenharmony_ci#include "efx_channels.h" 2862306a36Sopenharmony_ci#include "rx_common.h" 2962306a36Sopenharmony_ci#include "tx_common.h" 3062306a36Sopenharmony_ci#include "nic.h" 3162306a36Sopenharmony_ci#include "io.h" 3262306a36Sopenharmony_ci#include "selftest.h" 3362306a36Sopenharmony_ci#include "sriov.h" 3462306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 3562306a36Sopenharmony_ci#include "siena_sriov.h" 3662306a36Sopenharmony_ci#endif 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "mcdi_port_common.h" 3962306a36Sopenharmony_ci#include "mcdi_pcol.h" 4062306a36Sopenharmony_ci#include "workarounds.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/************************************************************************** 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * Configurable values 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci *************************************************************************/ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cimodule_param_named(interrupt_mode, efx_siena_interrupt_mode, uint, 0444); 4962306a36Sopenharmony_ciMODULE_PARM_DESC(interrupt_mode, 5062306a36Sopenharmony_ci "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)"); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cimodule_param_named(rss_cpus, efx_siena_rss_cpus, uint, 0444); 5362306a36Sopenharmony_ciMODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling"); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * Use separate channels for TX and RX events 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Set this to 1 to use separate channels for TX and RX. It allows us 5962306a36Sopenharmony_ci * to control interrupt affinity separately for TX and RX. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * This is only used in MSI-X interrupt mode 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cibool efx_siena_separate_tx_channels; 6462306a36Sopenharmony_cimodule_param_named(efx_separate_tx_channels, efx_siena_separate_tx_channels, 6562306a36Sopenharmony_ci bool, 0444); 6662306a36Sopenharmony_ciMODULE_PARM_DESC(efx_separate_tx_channels, 6762306a36Sopenharmony_ci "Use separate channels for TX and RX"); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Initial interrupt moderation settings. They can be modified after 7062306a36Sopenharmony_ci * module load with ethtool. 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * The default for RX should strike a balance between increasing the 7362306a36Sopenharmony_ci * round-trip latency and reducing overhead. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_cistatic unsigned int rx_irq_mod_usec = 60; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* Initial interrupt moderation settings. They can be modified after 7862306a36Sopenharmony_ci * module load with ethtool. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * This default is chosen to ensure that a 10G link does not go idle 8162306a36Sopenharmony_ci * while a TX queue is stopped after it has become full. A queue is 8262306a36Sopenharmony_ci * restarted when it drops below half full. The time this takes (assuming 8362306a36Sopenharmony_ci * worst case 3 descriptors per packet and 1024 descriptors) is 8462306a36Sopenharmony_ci * 512 / 3 * 1.2 = 205 usec. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic unsigned int tx_irq_mod_usec = 150; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic bool phy_flash_cfg; 8962306a36Sopenharmony_cimodule_param(phy_flash_cfg, bool, 0644); 9062306a36Sopenharmony_ciMODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic unsigned debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE | 9362306a36Sopenharmony_ci NETIF_MSG_LINK | NETIF_MSG_IFDOWN | 9462306a36Sopenharmony_ci NETIF_MSG_IFUP | NETIF_MSG_RX_ERR | 9562306a36Sopenharmony_ci NETIF_MSG_TX_ERR | NETIF_MSG_HW); 9662306a36Sopenharmony_cimodule_param(debug, uint, 0); 9762306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/************************************************************************** 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Utility functions and prototypes 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci *************************************************************************/ 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void efx_remove_port(struct efx_nic *efx); 10662306a36Sopenharmony_cistatic int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog); 10762306a36Sopenharmony_cistatic int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp); 10862306a36Sopenharmony_cistatic int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs, 10962306a36Sopenharmony_ci u32 flags); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define EFX_ASSERT_RESET_SERIALISED(efx) \ 11262306a36Sopenharmony_ci do { \ 11362306a36Sopenharmony_ci if ((efx->state == STATE_READY) || \ 11462306a36Sopenharmony_ci (efx->state == STATE_RECOVERY) || \ 11562306a36Sopenharmony_ci (efx->state == STATE_DISABLED)) \ 11662306a36Sopenharmony_ci ASSERT_RTNL(); \ 11762306a36Sopenharmony_ci } while (0) 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/************************************************************************** 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Port handling 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci **************************************************************************/ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void efx_fini_port(struct efx_nic *efx); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int efx_probe_port(struct efx_nic *efx) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci int rc; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "create port\n"); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (phy_flash_cfg) 13462306a36Sopenharmony_ci efx->phy_mode = PHY_MODE_SPECIAL; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Connect up MAC/PHY operations table */ 13762306a36Sopenharmony_ci rc = efx->type->probe_port(efx); 13862306a36Sopenharmony_ci if (rc) 13962306a36Sopenharmony_ci return rc; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Initialise MAC address to permanent address */ 14262306a36Sopenharmony_ci eth_hw_addr_set(efx->net_dev, efx->net_dev->perm_addr); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int efx_init_port(struct efx_nic *efx) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci int rc; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "init port\n"); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci efx->port_initialized = true; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Ensure the PHY advertises the correct flow control settings */ 15862306a36Sopenharmony_ci rc = efx_siena_mcdi_port_reconfigure(efx); 15962306a36Sopenharmony_ci if (rc && rc != -EPERM) 16062306a36Sopenharmony_ci goto fail; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cifail: 16662306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 16762306a36Sopenharmony_ci return rc; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void efx_fini_port(struct efx_nic *efx) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "shut down port\n"); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (!efx->port_initialized) 17562306a36Sopenharmony_ci return; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci efx->port_initialized = false; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci efx->link_state.up = false; 18062306a36Sopenharmony_ci efx_siena_link_status_changed(efx); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void efx_remove_port(struct efx_nic *efx) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "destroying port\n"); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci efx->type->remove_port(efx); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/************************************************************************** 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * NIC handling 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci **************************************************************************/ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic LIST_HEAD(efx_primary_list); 19762306a36Sopenharmony_cistatic LIST_HEAD(efx_unassociated_list); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic bool efx_same_controller(struct efx_nic *left, struct efx_nic *right) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci return left->type == right->type && 20262306a36Sopenharmony_ci left->vpd_sn && right->vpd_sn && 20362306a36Sopenharmony_ci !strcmp(left->vpd_sn, right->vpd_sn); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void efx_associate(struct efx_nic *efx) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct efx_nic *other, *next; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (efx->primary == efx) { 21162306a36Sopenharmony_ci /* Adding primary function; look for secondaries */ 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "adding to primary list\n"); 21462306a36Sopenharmony_ci list_add_tail(&efx->node, &efx_primary_list); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci list_for_each_entry_safe(other, next, &efx_unassociated_list, 21762306a36Sopenharmony_ci node) { 21862306a36Sopenharmony_ci if (efx_same_controller(efx, other)) { 21962306a36Sopenharmony_ci list_del(&other->node); 22062306a36Sopenharmony_ci netif_dbg(other, probe, other->net_dev, 22162306a36Sopenharmony_ci "moving to secondary list of %s %s\n", 22262306a36Sopenharmony_ci pci_name(efx->pci_dev), 22362306a36Sopenharmony_ci efx->net_dev->name); 22462306a36Sopenharmony_ci list_add_tail(&other->node, 22562306a36Sopenharmony_ci &efx->secondary_list); 22662306a36Sopenharmony_ci other->primary = efx; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } else { 23062306a36Sopenharmony_ci /* Adding secondary function; look for primary */ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci list_for_each_entry(other, &efx_primary_list, node) { 23362306a36Sopenharmony_ci if (efx_same_controller(efx, other)) { 23462306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 23562306a36Sopenharmony_ci "adding to secondary list of %s %s\n", 23662306a36Sopenharmony_ci pci_name(other->pci_dev), 23762306a36Sopenharmony_ci other->net_dev->name); 23862306a36Sopenharmony_ci list_add_tail(&efx->node, 23962306a36Sopenharmony_ci &other->secondary_list); 24062306a36Sopenharmony_ci efx->primary = other; 24162306a36Sopenharmony_ci return; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 24662306a36Sopenharmony_ci "adding to unassociated list\n"); 24762306a36Sopenharmony_ci list_add_tail(&efx->node, &efx_unassociated_list); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void efx_dissociate(struct efx_nic *efx) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct efx_nic *other, *next; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci list_del(&efx->node); 25662306a36Sopenharmony_ci efx->primary = NULL; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci list_for_each_entry_safe(other, next, &efx->secondary_list, node) { 25962306a36Sopenharmony_ci list_del(&other->node); 26062306a36Sopenharmony_ci netif_dbg(other, probe, other->net_dev, 26162306a36Sopenharmony_ci "moving to unassociated list\n"); 26262306a36Sopenharmony_ci list_add_tail(&other->node, &efx_unassociated_list); 26362306a36Sopenharmony_ci other->primary = NULL; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int efx_probe_nic(struct efx_nic *efx) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci int rc; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "creating NIC\n"); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Carry out hardware-type specific initialisation */ 27462306a36Sopenharmony_ci rc = efx->type->probe(efx); 27562306a36Sopenharmony_ci if (rc) 27662306a36Sopenharmony_ci return rc; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci do { 27962306a36Sopenharmony_ci if (!efx->max_channels || !efx->max_tx_channels) { 28062306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 28162306a36Sopenharmony_ci "Insufficient resources to allocate" 28262306a36Sopenharmony_ci " any channels\n"); 28362306a36Sopenharmony_ci rc = -ENOSPC; 28462306a36Sopenharmony_ci goto fail1; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* Determine the number of channels and queues by trying 28862306a36Sopenharmony_ci * to hook in MSI-X interrupts. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci rc = efx_siena_probe_interrupts(efx); 29162306a36Sopenharmony_ci if (rc) 29262306a36Sopenharmony_ci goto fail1; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci rc = efx_siena_set_channels(efx); 29562306a36Sopenharmony_ci if (rc) 29662306a36Sopenharmony_ci goto fail1; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* dimension_resources can fail with EAGAIN */ 29962306a36Sopenharmony_ci rc = efx->type->dimension_resources(efx); 30062306a36Sopenharmony_ci if (rc != 0 && rc != -EAGAIN) 30162306a36Sopenharmony_ci goto fail2; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (rc == -EAGAIN) 30462306a36Sopenharmony_ci /* try again with new max_channels */ 30562306a36Sopenharmony_ci efx_siena_remove_interrupts(efx); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci } while (rc == -EAGAIN); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (efx->n_channels > 1) 31062306a36Sopenharmony_ci netdev_rss_key_fill(efx->rss_context.rx_hash_key, 31162306a36Sopenharmony_ci sizeof(efx->rss_context.rx_hash_key)); 31262306a36Sopenharmony_ci efx_siena_set_default_rx_indir_table(efx, &efx->rss_context); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Initialise the interrupt moderation settings */ 31562306a36Sopenharmony_ci efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000); 31662306a36Sopenharmony_ci efx_siena_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, 31762306a36Sopenharmony_ci true, true); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cifail2: 32262306a36Sopenharmony_ci efx_siena_remove_interrupts(efx); 32362306a36Sopenharmony_cifail1: 32462306a36Sopenharmony_ci efx->type->remove(efx); 32562306a36Sopenharmony_ci return rc; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void efx_remove_nic(struct efx_nic *efx) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "destroying NIC\n"); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci efx_siena_remove_interrupts(efx); 33362306a36Sopenharmony_ci efx->type->remove(efx); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/************************************************************************** 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * NIC startup/shutdown 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci *************************************************************************/ 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int efx_probe_all(struct efx_nic *efx) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci int rc; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci rc = efx_probe_nic(efx); 34762306a36Sopenharmony_ci if (rc) { 34862306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "failed to create NIC\n"); 34962306a36Sopenharmony_ci goto fail1; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci rc = efx_probe_port(efx); 35362306a36Sopenharmony_ci if (rc) { 35462306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "failed to create port\n"); 35562306a36Sopenharmony_ci goto fail2; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci BUILD_BUG_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_RXQ_MIN_ENT); 35962306a36Sopenharmony_ci if (WARN_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_TXQ_MIN_ENT(efx))) { 36062306a36Sopenharmony_ci rc = -EINVAL; 36162306a36Sopenharmony_ci goto fail3; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 36562306a36Sopenharmony_ci rc = efx->type->vswitching_probe(efx); 36662306a36Sopenharmony_ci if (rc) /* not fatal; the PF will still work fine */ 36762306a36Sopenharmony_ci netif_warn(efx, probe, efx->net_dev, 36862306a36Sopenharmony_ci "failed to setup vswitching rc=%d;" 36962306a36Sopenharmony_ci " VFs may not function\n", rc); 37062306a36Sopenharmony_ci#endif 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci rc = efx_siena_probe_filters(efx); 37362306a36Sopenharmony_ci if (rc) { 37462306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 37562306a36Sopenharmony_ci "failed to create filter tables\n"); 37662306a36Sopenharmony_ci goto fail4; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci rc = efx_siena_probe_channels(efx); 38062306a36Sopenharmony_ci if (rc) 38162306a36Sopenharmony_ci goto fail5; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci fail5: 38662306a36Sopenharmony_ci efx_siena_remove_filters(efx); 38762306a36Sopenharmony_ci fail4: 38862306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 38962306a36Sopenharmony_ci efx->type->vswitching_remove(efx); 39062306a36Sopenharmony_ci#endif 39162306a36Sopenharmony_ci fail3: 39262306a36Sopenharmony_ci efx_remove_port(efx); 39362306a36Sopenharmony_ci fail2: 39462306a36Sopenharmony_ci efx_remove_nic(efx); 39562306a36Sopenharmony_ci fail1: 39662306a36Sopenharmony_ci return rc; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic void efx_remove_all(struct efx_nic *efx) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci rtnl_lock(); 40262306a36Sopenharmony_ci efx_xdp_setup_prog(efx, NULL); 40362306a36Sopenharmony_ci rtnl_unlock(); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci efx_siena_remove_channels(efx); 40662306a36Sopenharmony_ci efx_siena_remove_filters(efx); 40762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 40862306a36Sopenharmony_ci efx->type->vswitching_remove(efx); 40962306a36Sopenharmony_ci#endif 41062306a36Sopenharmony_ci efx_remove_port(efx); 41162306a36Sopenharmony_ci efx_remove_nic(efx); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/************************************************************************** 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * Interrupt moderation 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci **************************************************************************/ 41962306a36Sopenharmony_ciunsigned int efx_siena_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci if (usecs == 0) 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci if (usecs * 1000 < efx->timer_quantum_ns) 42462306a36Sopenharmony_ci return 1; /* never round down to 0 */ 42562306a36Sopenharmony_ci return usecs * 1000 / efx->timer_quantum_ns; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* Set interrupt moderation parameters */ 42962306a36Sopenharmony_ciint efx_siena_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, 43062306a36Sopenharmony_ci unsigned int rx_usecs, bool rx_adaptive, 43162306a36Sopenharmony_ci bool rx_may_override_tx) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct efx_channel *channel; 43462306a36Sopenharmony_ci unsigned int timer_max_us; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci EFX_ASSERT_RESET_SERIALISED(efx); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci timer_max_us = efx->timer_max_ns / 1000; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (tx_usecs > timer_max_us || rx_usecs > timer_max_us) 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (tx_usecs != rx_usecs && efx->tx_channel_offset == 0 && 44462306a36Sopenharmony_ci !rx_may_override_tx) { 44562306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "Channels are shared. " 44662306a36Sopenharmony_ci "RX and TX IRQ moderation must be equal\n"); 44762306a36Sopenharmony_ci return -EINVAL; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci efx->irq_rx_adaptive = rx_adaptive; 45162306a36Sopenharmony_ci efx->irq_rx_moderation_us = rx_usecs; 45262306a36Sopenharmony_ci efx_for_each_channel(channel, efx) { 45362306a36Sopenharmony_ci if (efx_channel_has_rx_queue(channel)) 45462306a36Sopenharmony_ci channel->irq_moderation_us = rx_usecs; 45562306a36Sopenharmony_ci else if (efx_channel_has_tx_queues(channel)) 45662306a36Sopenharmony_ci channel->irq_moderation_us = tx_usecs; 45762306a36Sopenharmony_ci else if (efx_channel_is_xdp_tx(channel)) 45862306a36Sopenharmony_ci channel->irq_moderation_us = tx_usecs; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_civoid efx_siena_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, 46562306a36Sopenharmony_ci unsigned int *rx_usecs, bool *rx_adaptive) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci *rx_adaptive = efx->irq_rx_adaptive; 46862306a36Sopenharmony_ci *rx_usecs = efx->irq_rx_moderation_us; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* If channels are shared between RX and TX, so is IRQ 47162306a36Sopenharmony_ci * moderation. Otherwise, IRQ moderation is the same for all 47262306a36Sopenharmony_ci * TX channels and is not adaptive. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci if (efx->tx_channel_offset == 0) { 47562306a36Sopenharmony_ci *tx_usecs = *rx_usecs; 47662306a36Sopenharmony_ci } else { 47762306a36Sopenharmony_ci struct efx_channel *tx_channel; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci tx_channel = efx->channel[efx->tx_channel_offset]; 48062306a36Sopenharmony_ci *tx_usecs = tx_channel->irq_moderation_us; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci/************************************************************************** 48562306a36Sopenharmony_ci * 48662306a36Sopenharmony_ci * ioctls 48762306a36Sopenharmony_ci * 48862306a36Sopenharmony_ci *************************************************************************/ 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/* Net device ioctl 49162306a36Sopenharmony_ci * Context: process, rtnl_lock() held. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_cistatic int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 49662306a36Sopenharmony_ci struct mii_ioctl_data *data = if_mii(ifr); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (cmd == SIOCSHWTSTAMP) 49962306a36Sopenharmony_ci return efx_siena_ptp_set_ts_config(efx, ifr); 50062306a36Sopenharmony_ci if (cmd == SIOCGHWTSTAMP) 50162306a36Sopenharmony_ci return efx_siena_ptp_get_ts_config(efx, ifr); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Convert phy_id from older PRTAD/DEVAD format */ 50462306a36Sopenharmony_ci if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && 50562306a36Sopenharmony_ci (data->phy_id & 0xfc00) == 0x0400) 50662306a36Sopenharmony_ci data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return mdio_mii_ioctl(&efx->mdio, data, cmd); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/************************************************************************** 51262306a36Sopenharmony_ci * 51362306a36Sopenharmony_ci * Kernel net device interface 51462306a36Sopenharmony_ci * 51562306a36Sopenharmony_ci *************************************************************************/ 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. */ 51862306a36Sopenharmony_cistatic int efx_net_open(struct net_device *net_dev) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 52162306a36Sopenharmony_ci int rc; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci netif_dbg(efx, ifup, efx->net_dev, "opening device on CPU %d\n", 52462306a36Sopenharmony_ci raw_smp_processor_id()); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci rc = efx_check_disabled(efx); 52762306a36Sopenharmony_ci if (rc) 52862306a36Sopenharmony_ci return rc; 52962306a36Sopenharmony_ci if (efx->phy_mode & PHY_MODE_SPECIAL) 53062306a36Sopenharmony_ci return -EBUSY; 53162306a36Sopenharmony_ci if (efx_siena_mcdi_poll_reboot(efx) && efx_siena_reset(efx, RESET_TYPE_ALL)) 53262306a36Sopenharmony_ci return -EIO; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* Notify the kernel of the link state polled during driver load, 53562306a36Sopenharmony_ci * before the monitor starts running */ 53662306a36Sopenharmony_ci efx_siena_link_status_changed(efx); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci efx_siena_start_all(efx); 53962306a36Sopenharmony_ci if (efx->state == STATE_DISABLED || efx->reset_pending) 54062306a36Sopenharmony_ci netif_device_detach(efx->net_dev); 54162306a36Sopenharmony_ci efx_siena_selftest_async_start(efx); 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. 54662306a36Sopenharmony_ci * Note that the kernel will ignore our return code; this method 54762306a36Sopenharmony_ci * should really be a void. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cistatic int efx_net_stop(struct net_device *net_dev) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n", 55462306a36Sopenharmony_ci raw_smp_processor_id()); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* Stop the device and flush all the channels */ 55762306a36Sopenharmony_ci efx_siena_stop_all(efx); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic int efx_vlan_rx_add_vid(struct net_device *net_dev, __be16 proto, u16 vid) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (efx->type->vlan_rx_add_vid) 56762306a36Sopenharmony_ci return efx->type->vlan_rx_add_vid(efx, proto, vid); 56862306a36Sopenharmony_ci else 56962306a36Sopenharmony_ci return -EOPNOTSUPP; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vid) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct efx_nic *efx = netdev_priv(net_dev); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (efx->type->vlan_rx_kill_vid) 57762306a36Sopenharmony_ci return efx->type->vlan_rx_kill_vid(efx, proto, vid); 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci return -EOPNOTSUPP; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic const struct net_device_ops efx_netdev_ops = { 58362306a36Sopenharmony_ci .ndo_open = efx_net_open, 58462306a36Sopenharmony_ci .ndo_stop = efx_net_stop, 58562306a36Sopenharmony_ci .ndo_get_stats64 = efx_siena_net_stats, 58662306a36Sopenharmony_ci .ndo_tx_timeout = efx_siena_watchdog, 58762306a36Sopenharmony_ci .ndo_start_xmit = efx_siena_hard_start_xmit, 58862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 58962306a36Sopenharmony_ci .ndo_eth_ioctl = efx_ioctl, 59062306a36Sopenharmony_ci .ndo_change_mtu = efx_siena_change_mtu, 59162306a36Sopenharmony_ci .ndo_set_mac_address = efx_siena_set_mac_address, 59262306a36Sopenharmony_ci .ndo_set_rx_mode = efx_siena_set_rx_mode, 59362306a36Sopenharmony_ci .ndo_set_features = efx_siena_set_features, 59462306a36Sopenharmony_ci .ndo_features_check = efx_siena_features_check, 59562306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = efx_vlan_rx_add_vid, 59662306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = efx_vlan_rx_kill_vid, 59762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 59862306a36Sopenharmony_ci .ndo_set_vf_mac = efx_sriov_set_vf_mac, 59962306a36Sopenharmony_ci .ndo_set_vf_vlan = efx_sriov_set_vf_vlan, 60062306a36Sopenharmony_ci .ndo_set_vf_spoofchk = efx_sriov_set_vf_spoofchk, 60162306a36Sopenharmony_ci .ndo_get_vf_config = efx_sriov_get_vf_config, 60262306a36Sopenharmony_ci .ndo_set_vf_link_state = efx_sriov_set_vf_link_state, 60362306a36Sopenharmony_ci#endif 60462306a36Sopenharmony_ci .ndo_get_phys_port_id = efx_siena_get_phys_port_id, 60562306a36Sopenharmony_ci .ndo_get_phys_port_name = efx_siena_get_phys_port_name, 60662306a36Sopenharmony_ci .ndo_setup_tc = efx_siena_setup_tc, 60762306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 60862306a36Sopenharmony_ci .ndo_rx_flow_steer = efx_siena_filter_rfs, 60962306a36Sopenharmony_ci#endif 61062306a36Sopenharmony_ci .ndo_xdp_xmit = efx_xdp_xmit, 61162306a36Sopenharmony_ci .ndo_bpf = efx_xdp 61262306a36Sopenharmony_ci}; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct bpf_prog *old_prog; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (efx->xdp_rxq_info_failed) { 61962306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 62062306a36Sopenharmony_ci "Unable to bind XDP program due to previous failure of rxq_info\n"); 62162306a36Sopenharmony_ci return -EINVAL; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (prog && efx->net_dev->mtu > efx_siena_xdp_max_mtu(efx)) { 62562306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 62662306a36Sopenharmony_ci "Unable to configure XDP with MTU of %d (max: %d)\n", 62762306a36Sopenharmony_ci efx->net_dev->mtu, efx_siena_xdp_max_mtu(efx)); 62862306a36Sopenharmony_ci return -EINVAL; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci old_prog = rtnl_dereference(efx->xdp_prog); 63262306a36Sopenharmony_ci rcu_assign_pointer(efx->xdp_prog, prog); 63362306a36Sopenharmony_ci /* Release the reference that was originally passed by the caller. */ 63462306a36Sopenharmony_ci if (old_prog) 63562306a36Sopenharmony_ci bpf_prog_put(old_prog); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. */ 64162306a36Sopenharmony_cistatic int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct efx_nic *efx = netdev_priv(dev); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci switch (xdp->command) { 64662306a36Sopenharmony_ci case XDP_SETUP_PROG: 64762306a36Sopenharmony_ci return efx_xdp_setup_prog(efx, xdp->prog); 64862306a36Sopenharmony_ci default: 64962306a36Sopenharmony_ci return -EINVAL; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs, 65462306a36Sopenharmony_ci u32 flags) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct efx_nic *efx = netdev_priv(dev); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (!netif_running(dev)) 65962306a36Sopenharmony_ci return -EINVAL; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci return efx_siena_xdp_tx_buffers(efx, n, xdpfs, flags & XDP_XMIT_FLUSH); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic void efx_update_name(struct efx_nic *efx) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci strcpy(efx->name, efx->net_dev->name); 66762306a36Sopenharmony_ci efx_siena_mtd_rename(efx); 66862306a36Sopenharmony_ci efx_siena_set_channel_names(efx); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic int efx_netdev_event(struct notifier_block *this, 67262306a36Sopenharmony_ci unsigned long event, void *ptr) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if ((net_dev->netdev_ops == &efx_netdev_ops) && 67762306a36Sopenharmony_ci event == NETDEV_CHANGENAME) 67862306a36Sopenharmony_ci efx_update_name(netdev_priv(net_dev)); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return NOTIFY_DONE; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic struct notifier_block efx_netdev_notifier = { 68462306a36Sopenharmony_ci .notifier_call = efx_netdev_event, 68562306a36Sopenharmony_ci}; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic ssize_t phy_type_show(struct device *dev, 68862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct efx_nic *efx = dev_get_drvdata(dev); 69162306a36Sopenharmony_ci return sprintf(buf, "%d\n", efx->phy_type); 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(phy_type); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic int efx_register_netdev(struct efx_nic *efx) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct net_device *net_dev = efx->net_dev; 69862306a36Sopenharmony_ci struct efx_channel *channel; 69962306a36Sopenharmony_ci int rc; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci net_dev->watchdog_timeo = 5 * HZ; 70262306a36Sopenharmony_ci net_dev->irq = efx->pci_dev->irq; 70362306a36Sopenharmony_ci net_dev->netdev_ops = &efx_netdev_ops; 70462306a36Sopenharmony_ci if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) 70562306a36Sopenharmony_ci net_dev->priv_flags |= IFF_UNICAST_FLT; 70662306a36Sopenharmony_ci net_dev->ethtool_ops = &efx_siena_ethtool_ops; 70762306a36Sopenharmony_ci netif_set_tso_max_segs(net_dev, EFX_TSO_MAX_SEGS); 70862306a36Sopenharmony_ci net_dev->min_mtu = EFX_MIN_MTU; 70962306a36Sopenharmony_ci net_dev->max_mtu = EFX_MAX_MTU; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci rtnl_lock(); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Enable resets to be scheduled and check whether any were 71462306a36Sopenharmony_ci * already requested. If so, the NIC is probably hosed so we 71562306a36Sopenharmony_ci * abort. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci efx->state = STATE_READY; 71862306a36Sopenharmony_ci smp_mb(); /* ensure we change state before checking reset_pending */ 71962306a36Sopenharmony_ci if (efx->reset_pending) { 72062306a36Sopenharmony_ci pci_err(efx->pci_dev, "aborting probe due to scheduled reset\n"); 72162306a36Sopenharmony_ci rc = -EIO; 72262306a36Sopenharmony_ci goto fail_locked; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci rc = dev_alloc_name(net_dev, net_dev->name); 72662306a36Sopenharmony_ci if (rc < 0) 72762306a36Sopenharmony_ci goto fail_locked; 72862306a36Sopenharmony_ci efx_update_name(efx); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Always start with carrier off; PHY events will detect the link */ 73162306a36Sopenharmony_ci netif_carrier_off(net_dev); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci rc = register_netdevice(net_dev); 73462306a36Sopenharmony_ci if (rc) 73562306a36Sopenharmony_ci goto fail_locked; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci efx_for_each_channel(channel, efx) { 73862306a36Sopenharmony_ci struct efx_tx_queue *tx_queue; 73962306a36Sopenharmony_ci efx_for_each_channel_tx_queue(tx_queue, channel) 74062306a36Sopenharmony_ci efx_siena_init_tx_queue_core_txq(tx_queue); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci efx_associate(efx); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci rtnl_unlock(); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type); 74862306a36Sopenharmony_ci if (rc) { 74962306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 75062306a36Sopenharmony_ci "failed to init net dev attributes\n"); 75162306a36Sopenharmony_ci goto fail_registered; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci efx_siena_init_mcdi_logging(efx); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cifail_registered: 75962306a36Sopenharmony_ci rtnl_lock(); 76062306a36Sopenharmony_ci efx_dissociate(efx); 76162306a36Sopenharmony_ci unregister_netdevice(net_dev); 76262306a36Sopenharmony_cifail_locked: 76362306a36Sopenharmony_ci efx->state = STATE_UNINIT; 76462306a36Sopenharmony_ci rtnl_unlock(); 76562306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "could not register net dev\n"); 76662306a36Sopenharmony_ci return rc; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic void efx_unregister_netdev(struct efx_nic *efx) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci if (!efx->net_dev) 77262306a36Sopenharmony_ci return; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci BUG_ON(netdev_priv(efx->net_dev) != efx); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (efx_dev_registered(efx)) { 77762306a36Sopenharmony_ci strscpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); 77862306a36Sopenharmony_ci efx_siena_fini_mcdi_logging(efx); 77962306a36Sopenharmony_ci device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type); 78062306a36Sopenharmony_ci unregister_netdev(efx->net_dev); 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci/************************************************************************** 78562306a36Sopenharmony_ci * 78662306a36Sopenharmony_ci * List of NICs we support 78762306a36Sopenharmony_ci * 78862306a36Sopenharmony_ci **************************************************************************/ 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci/* PCI device ID table */ 79162306a36Sopenharmony_cistatic const struct pci_device_id efx_pci_table[] = { 79262306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0803), /* SFC9020 */ 79362306a36Sopenharmony_ci .driver_data = (unsigned long)&siena_a0_nic_type}, 79462306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0813), /* SFL9021 */ 79562306a36Sopenharmony_ci .driver_data = (unsigned long)&siena_a0_nic_type}, 79662306a36Sopenharmony_ci {0} /* end of list */ 79762306a36Sopenharmony_ci}; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci/************************************************************************** 80062306a36Sopenharmony_ci * 80162306a36Sopenharmony_ci * Data housekeeping 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci **************************************************************************/ 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_civoid efx_siena_update_sw_stats(struct efx_nic *efx, u64 *stats) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci u64 n_rx_nodesc_trunc = 0; 80862306a36Sopenharmony_ci struct efx_channel *channel; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci efx_for_each_channel(channel, efx) 81162306a36Sopenharmony_ci n_rx_nodesc_trunc += channel->n_rx_nodesc_trunc; 81262306a36Sopenharmony_ci stats[GENERIC_STAT_rx_nodesc_trunc] = n_rx_nodesc_trunc; 81362306a36Sopenharmony_ci stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci/************************************************************************** 81762306a36Sopenharmony_ci * 81862306a36Sopenharmony_ci * PCI interface 81962306a36Sopenharmony_ci * 82062306a36Sopenharmony_ci **************************************************************************/ 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/* Main body of final NIC shutdown code 82362306a36Sopenharmony_ci * This is called only at module unload (or hotplug removal). 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_cistatic void efx_pci_remove_main(struct efx_nic *efx) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci /* Flush reset_work. It can no longer be scheduled since we 82862306a36Sopenharmony_ci * are not READY. 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_ci BUG_ON(efx->state == STATE_READY); 83162306a36Sopenharmony_ci efx_siena_flush_reset_workqueue(efx); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci efx_siena_disable_interrupts(efx); 83462306a36Sopenharmony_ci efx_siena_clear_interrupt_affinity(efx); 83562306a36Sopenharmony_ci efx_siena_fini_interrupt(efx); 83662306a36Sopenharmony_ci efx_fini_port(efx); 83762306a36Sopenharmony_ci efx->type->fini(efx); 83862306a36Sopenharmony_ci efx_siena_fini_napi(efx); 83962306a36Sopenharmony_ci efx_remove_all(efx); 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci/* Final NIC shutdown 84362306a36Sopenharmony_ci * This is called only at module unload (or hotplug removal). A PF can call 84462306a36Sopenharmony_ci * this on its VFs to ensure they are unbound first. 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_cistatic void efx_pci_remove(struct pci_dev *pci_dev) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct efx_nic *efx; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci efx = pci_get_drvdata(pci_dev); 85162306a36Sopenharmony_ci if (!efx) 85262306a36Sopenharmony_ci return; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Mark the NIC as fini, then stop the interface */ 85562306a36Sopenharmony_ci rtnl_lock(); 85662306a36Sopenharmony_ci efx_dissociate(efx); 85762306a36Sopenharmony_ci dev_close(efx->net_dev); 85862306a36Sopenharmony_ci efx_siena_disable_interrupts(efx); 85962306a36Sopenharmony_ci efx->state = STATE_UNINIT; 86062306a36Sopenharmony_ci rtnl_unlock(); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (efx->type->sriov_fini) 86362306a36Sopenharmony_ci efx->type->sriov_fini(efx); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci efx_unregister_netdev(efx); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci efx_siena_mtd_remove(efx); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci efx_pci_remove_main(efx); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci efx_siena_fini_io(efx); 87262306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n"); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci efx_siena_fini_struct(efx); 87562306a36Sopenharmony_ci free_netdev(efx->net_dev); 87662306a36Sopenharmony_ci}; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci/* NIC VPD information 87962306a36Sopenharmony_ci * Called during probe to display the part number of the 88062306a36Sopenharmony_ci * installed NIC. 88162306a36Sopenharmony_ci */ 88262306a36Sopenharmony_cistatic void efx_probe_vpd_strings(struct efx_nic *efx) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct pci_dev *dev = efx->pci_dev; 88562306a36Sopenharmony_ci unsigned int vpd_size, kw_len; 88662306a36Sopenharmony_ci u8 *vpd_data; 88762306a36Sopenharmony_ci int start; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci vpd_data = pci_vpd_alloc(dev, &vpd_size); 89062306a36Sopenharmony_ci if (IS_ERR(vpd_data)) { 89162306a36Sopenharmony_ci pci_warn(dev, "Unable to read VPD\n"); 89262306a36Sopenharmony_ci return; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, 89662306a36Sopenharmony_ci PCI_VPD_RO_KEYWORD_PARTNO, &kw_len); 89762306a36Sopenharmony_ci if (start < 0) 89862306a36Sopenharmony_ci pci_err(dev, "Part number not found or incomplete\n"); 89962306a36Sopenharmony_ci else 90062306a36Sopenharmony_ci pci_info(dev, "Part Number : %.*s\n", kw_len, vpd_data + start); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, 90362306a36Sopenharmony_ci PCI_VPD_RO_KEYWORD_SERIALNO, &kw_len); 90462306a36Sopenharmony_ci if (start < 0) 90562306a36Sopenharmony_ci pci_err(dev, "Serial number not found or incomplete\n"); 90662306a36Sopenharmony_ci else 90762306a36Sopenharmony_ci efx->vpd_sn = kmemdup_nul(vpd_data + start, kw_len, GFP_KERNEL); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci kfree(vpd_data); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/* Main body of NIC initialisation 91462306a36Sopenharmony_ci * This is called at module load (or hotplug insertion, theoretically). 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_cistatic int efx_pci_probe_main(struct efx_nic *efx) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci int rc; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* Do start-of-day initialisation */ 92162306a36Sopenharmony_ci rc = efx_probe_all(efx); 92262306a36Sopenharmony_ci if (rc) 92362306a36Sopenharmony_ci goto fail1; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci efx_siena_init_napi(efx); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci down_write(&efx->filter_sem); 92862306a36Sopenharmony_ci rc = efx->type->init(efx); 92962306a36Sopenharmony_ci up_write(&efx->filter_sem); 93062306a36Sopenharmony_ci if (rc) { 93162306a36Sopenharmony_ci pci_err(efx->pci_dev, "failed to initialise NIC\n"); 93262306a36Sopenharmony_ci goto fail3; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci rc = efx_init_port(efx); 93662306a36Sopenharmony_ci if (rc) { 93762306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 93862306a36Sopenharmony_ci "failed to initialise port\n"); 93962306a36Sopenharmony_ci goto fail4; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci rc = efx_siena_init_interrupt(efx); 94362306a36Sopenharmony_ci if (rc) 94462306a36Sopenharmony_ci goto fail5; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci efx_siena_set_interrupt_affinity(efx); 94762306a36Sopenharmony_ci rc = efx_siena_enable_interrupts(efx); 94862306a36Sopenharmony_ci if (rc) 94962306a36Sopenharmony_ci goto fail6; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci return 0; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci fail6: 95462306a36Sopenharmony_ci efx_siena_clear_interrupt_affinity(efx); 95562306a36Sopenharmony_ci efx_siena_fini_interrupt(efx); 95662306a36Sopenharmony_ci fail5: 95762306a36Sopenharmony_ci efx_fini_port(efx); 95862306a36Sopenharmony_ci fail4: 95962306a36Sopenharmony_ci efx->type->fini(efx); 96062306a36Sopenharmony_ci fail3: 96162306a36Sopenharmony_ci efx_siena_fini_napi(efx); 96262306a36Sopenharmony_ci efx_remove_all(efx); 96362306a36Sopenharmony_ci fail1: 96462306a36Sopenharmony_ci return rc; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_cistatic int efx_pci_probe_post_io(struct efx_nic *efx) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci struct net_device *net_dev = efx->net_dev; 97062306a36Sopenharmony_ci int rc = efx_pci_probe_main(efx); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (rc) 97362306a36Sopenharmony_ci return rc; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (efx->type->sriov_init) { 97662306a36Sopenharmony_ci rc = efx->type->sriov_init(efx); 97762306a36Sopenharmony_ci if (rc) 97862306a36Sopenharmony_ci pci_err(efx->pci_dev, "SR-IOV can't be enabled rc %d\n", 97962306a36Sopenharmony_ci rc); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* Determine netdevice features */ 98362306a36Sopenharmony_ci net_dev->features |= (efx->type->offload_features | NETIF_F_SG | 98462306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_RXALL); 98562306a36Sopenharmony_ci if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) 98662306a36Sopenharmony_ci net_dev->features |= NETIF_F_TSO6; 98762306a36Sopenharmony_ci /* Check whether device supports TSO */ 98862306a36Sopenharmony_ci if (!efx->type->tso_versions || !efx->type->tso_versions(efx)) 98962306a36Sopenharmony_ci net_dev->features &= ~NETIF_F_ALL_TSO; 99062306a36Sopenharmony_ci /* Mask for features that also apply to VLAN devices */ 99162306a36Sopenharmony_ci net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG | 99262306a36Sopenharmony_ci NETIF_F_HIGHDMA | NETIF_F_ALL_TSO | 99362306a36Sopenharmony_ci NETIF_F_RXCSUM); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci net_dev->hw_features |= net_dev->features & ~efx->fixed_features; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* Disable receiving frames with bad FCS, by default. */ 99862306a36Sopenharmony_ci net_dev->features &= ~NETIF_F_RXALL; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* Disable VLAN filtering by default. It may be enforced if 100162306a36Sopenharmony_ci * the feature is fixed (i.e. VLAN filters are required to 100262306a36Sopenharmony_ci * receive VLAN tagged packets due to vPort restrictions). 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 100562306a36Sopenharmony_ci net_dev->features |= efx->fixed_features; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci net_dev->xdp_features = NETDEV_XDP_ACT_BASIC | 100862306a36Sopenharmony_ci NETDEV_XDP_ACT_REDIRECT | 100962306a36Sopenharmony_ci NETDEV_XDP_ACT_NDO_XMIT; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci rc = efx_register_netdev(efx); 101262306a36Sopenharmony_ci if (!rc) 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci efx_pci_remove_main(efx); 101662306a36Sopenharmony_ci return rc; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci/* NIC initialisation 102062306a36Sopenharmony_ci * 102162306a36Sopenharmony_ci * This is called at module load (or hotplug insertion, 102262306a36Sopenharmony_ci * theoretically). It sets up PCI mappings, resets the NIC, 102362306a36Sopenharmony_ci * sets up and registers the network devices with the kernel and hooks 102462306a36Sopenharmony_ci * the interrupt service routine. It does not prepare the device for 102562306a36Sopenharmony_ci * transmission; this is left to the first time one of the network 102662306a36Sopenharmony_ci * interfaces is brought up (i.e. efx_net_open). 102762306a36Sopenharmony_ci */ 102862306a36Sopenharmony_cistatic int efx_pci_probe(struct pci_dev *pci_dev, 102962306a36Sopenharmony_ci const struct pci_device_id *entry) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct net_device *net_dev; 103262306a36Sopenharmony_ci struct efx_nic *efx; 103362306a36Sopenharmony_ci int rc; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* Allocate and initialise a struct net_device and struct efx_nic */ 103662306a36Sopenharmony_ci net_dev = alloc_etherdev_mqs(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES, 103762306a36Sopenharmony_ci EFX_MAX_RX_QUEUES); 103862306a36Sopenharmony_ci if (!net_dev) 103962306a36Sopenharmony_ci return -ENOMEM; 104062306a36Sopenharmony_ci efx = netdev_priv(net_dev); 104162306a36Sopenharmony_ci efx->type = (const struct efx_nic_type *) entry->driver_data; 104262306a36Sopenharmony_ci efx->fixed_features |= NETIF_F_HIGHDMA; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci pci_set_drvdata(pci_dev, efx); 104562306a36Sopenharmony_ci SET_NETDEV_DEV(net_dev, &pci_dev->dev); 104662306a36Sopenharmony_ci rc = efx_siena_init_struct(efx, pci_dev, net_dev); 104762306a36Sopenharmony_ci if (rc) 104862306a36Sopenharmony_ci goto fail1; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci pci_info(pci_dev, "Solarflare NIC detected\n"); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (!efx->type->is_vf) 105362306a36Sopenharmony_ci efx_probe_vpd_strings(efx); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* Set up basic I/O (BAR mappings etc) */ 105662306a36Sopenharmony_ci rc = efx_siena_init_io(efx, efx->type->mem_bar(efx), 105762306a36Sopenharmony_ci efx->type->max_dma_mask, 105862306a36Sopenharmony_ci efx->type->mem_map_size(efx)); 105962306a36Sopenharmony_ci if (rc) 106062306a36Sopenharmony_ci goto fail2; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci rc = efx_pci_probe_post_io(efx); 106362306a36Sopenharmony_ci if (rc) { 106462306a36Sopenharmony_ci /* On failure, retry once immediately. 106562306a36Sopenharmony_ci * If we aborted probe due to a scheduled reset, dismiss it. 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci efx->reset_pending = 0; 106862306a36Sopenharmony_ci rc = efx_pci_probe_post_io(efx); 106962306a36Sopenharmony_ci if (rc) { 107062306a36Sopenharmony_ci /* On another failure, retry once more 107162306a36Sopenharmony_ci * after a 50-305ms delay. 107262306a36Sopenharmony_ci */ 107362306a36Sopenharmony_ci unsigned char r; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci get_random_bytes(&r, 1); 107662306a36Sopenharmony_ci msleep((unsigned int)r + 50); 107762306a36Sopenharmony_ci efx->reset_pending = 0; 107862306a36Sopenharmony_ci rc = efx_pci_probe_post_io(efx); 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci if (rc) 108262306a36Sopenharmony_ci goto fail3; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n"); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* Try to create MTDs, but allow this to fail */ 108762306a36Sopenharmony_ci rtnl_lock(); 108862306a36Sopenharmony_ci rc = efx_mtd_probe(efx); 108962306a36Sopenharmony_ci rtnl_unlock(); 109062306a36Sopenharmony_ci if (rc && rc != -EPERM) 109162306a36Sopenharmony_ci netif_warn(efx, probe, efx->net_dev, 109262306a36Sopenharmony_ci "failed to create MTDs (%d)\n", rc); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (efx->type->udp_tnl_push_ports) 109562306a36Sopenharmony_ci efx->type->udp_tnl_push_ports(efx); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return 0; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci fail3: 110062306a36Sopenharmony_ci efx_siena_fini_io(efx); 110162306a36Sopenharmony_ci fail2: 110262306a36Sopenharmony_ci efx_siena_fini_struct(efx); 110362306a36Sopenharmony_ci fail1: 110462306a36Sopenharmony_ci WARN_ON(rc > 0); 110562306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc); 110662306a36Sopenharmony_ci free_netdev(net_dev); 110762306a36Sopenharmony_ci return rc; 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci/* efx_pci_sriov_configure returns the actual number of Virtual Functions 111162306a36Sopenharmony_ci * enabled on success 111262306a36Sopenharmony_ci */ 111362306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 111462306a36Sopenharmony_cistatic int efx_pci_sriov_configure(struct pci_dev *dev, int num_vfs) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci int rc; 111762306a36Sopenharmony_ci struct efx_nic *efx = pci_get_drvdata(dev); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (efx->type->sriov_configure) { 112062306a36Sopenharmony_ci rc = efx->type->sriov_configure(efx, num_vfs); 112162306a36Sopenharmony_ci if (rc) 112262306a36Sopenharmony_ci return rc; 112362306a36Sopenharmony_ci else 112462306a36Sopenharmony_ci return num_vfs; 112562306a36Sopenharmony_ci } else 112662306a36Sopenharmony_ci return -EOPNOTSUPP; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci#endif 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic int efx_pm_freeze(struct device *dev) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci struct efx_nic *efx = dev_get_drvdata(dev); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci rtnl_lock(); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (efx->state != STATE_DISABLED) { 113762306a36Sopenharmony_ci efx->state = STATE_UNINIT; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci efx_device_detach_sync(efx); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci efx_siena_stop_all(efx); 114262306a36Sopenharmony_ci efx_siena_disable_interrupts(efx); 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci rtnl_unlock(); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci return 0; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic void efx_pci_shutdown(struct pci_dev *pci_dev) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci struct efx_nic *efx = pci_get_drvdata(pci_dev); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (!efx) 115562306a36Sopenharmony_ci return; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci efx_pm_freeze(&pci_dev->dev); 115862306a36Sopenharmony_ci pci_disable_device(pci_dev); 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic int efx_pm_thaw(struct device *dev) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci int rc; 116462306a36Sopenharmony_ci struct efx_nic *efx = dev_get_drvdata(dev); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci rtnl_lock(); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (efx->state != STATE_DISABLED) { 116962306a36Sopenharmony_ci rc = efx_siena_enable_interrupts(efx); 117062306a36Sopenharmony_ci if (rc) 117162306a36Sopenharmony_ci goto fail; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 117462306a36Sopenharmony_ci efx_siena_mcdi_port_reconfigure(efx); 117562306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci efx_siena_start_all(efx); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci efx_device_attach_if_not_resetting(efx); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci efx->state = STATE_READY; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci efx->type->resume_wol(efx); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci rtnl_unlock(); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci /* Reschedule any quenched resets scheduled during efx_pm_freeze() */ 118962306a36Sopenharmony_ci efx_siena_queue_reset_work(efx); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci return 0; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_cifail: 119462306a36Sopenharmony_ci rtnl_unlock(); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci return rc; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic int efx_pm_poweroff(struct device *dev) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 120262306a36Sopenharmony_ci struct efx_nic *efx = pci_get_drvdata(pci_dev); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci efx->type->fini(efx); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci efx->reset_pending = 0; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci pci_save_state(pci_dev); 120962306a36Sopenharmony_ci return pci_set_power_state(pci_dev, PCI_D3hot); 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci/* Used for both resume and restore */ 121362306a36Sopenharmony_cistatic int efx_pm_resume(struct device *dev) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 121662306a36Sopenharmony_ci struct efx_nic *efx = pci_get_drvdata(pci_dev); 121762306a36Sopenharmony_ci int rc; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci rc = pci_set_power_state(pci_dev, PCI_D0); 122062306a36Sopenharmony_ci if (rc) 122162306a36Sopenharmony_ci return rc; 122262306a36Sopenharmony_ci pci_restore_state(pci_dev); 122362306a36Sopenharmony_ci rc = pci_enable_device(pci_dev); 122462306a36Sopenharmony_ci if (rc) 122562306a36Sopenharmony_ci return rc; 122662306a36Sopenharmony_ci pci_set_master(efx->pci_dev); 122762306a36Sopenharmony_ci rc = efx->type->reset(efx, RESET_TYPE_ALL); 122862306a36Sopenharmony_ci if (rc) 122962306a36Sopenharmony_ci return rc; 123062306a36Sopenharmony_ci down_write(&efx->filter_sem); 123162306a36Sopenharmony_ci rc = efx->type->init(efx); 123262306a36Sopenharmony_ci up_write(&efx->filter_sem); 123362306a36Sopenharmony_ci if (rc) 123462306a36Sopenharmony_ci return rc; 123562306a36Sopenharmony_ci rc = efx_pm_thaw(dev); 123662306a36Sopenharmony_ci return rc; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic int efx_pm_suspend(struct device *dev) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci int rc; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci efx_pm_freeze(dev); 124462306a36Sopenharmony_ci rc = efx_pm_poweroff(dev); 124562306a36Sopenharmony_ci if (rc) 124662306a36Sopenharmony_ci efx_pm_resume(dev); 124762306a36Sopenharmony_ci return rc; 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic const struct dev_pm_ops efx_pm_ops = { 125162306a36Sopenharmony_ci .suspend = efx_pm_suspend, 125262306a36Sopenharmony_ci .resume = efx_pm_resume, 125362306a36Sopenharmony_ci .freeze = efx_pm_freeze, 125462306a36Sopenharmony_ci .thaw = efx_pm_thaw, 125562306a36Sopenharmony_ci .poweroff = efx_pm_poweroff, 125662306a36Sopenharmony_ci .restore = efx_pm_resume, 125762306a36Sopenharmony_ci}; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic struct pci_driver efx_pci_driver = { 126062306a36Sopenharmony_ci .name = KBUILD_MODNAME, 126162306a36Sopenharmony_ci .id_table = efx_pci_table, 126262306a36Sopenharmony_ci .probe = efx_pci_probe, 126362306a36Sopenharmony_ci .remove = efx_pci_remove, 126462306a36Sopenharmony_ci .driver.pm = &efx_pm_ops, 126562306a36Sopenharmony_ci .shutdown = efx_pci_shutdown, 126662306a36Sopenharmony_ci .err_handler = &efx_siena_err_handlers, 126762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 126862306a36Sopenharmony_ci .sriov_configure = efx_pci_sriov_configure, 126962306a36Sopenharmony_ci#endif 127062306a36Sopenharmony_ci}; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci/************************************************************************** 127362306a36Sopenharmony_ci * 127462306a36Sopenharmony_ci * Kernel module interface 127562306a36Sopenharmony_ci * 127662306a36Sopenharmony_ci *************************************************************************/ 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic int __init efx_init_module(void) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci int rc; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci pr_info("Solarflare Siena driver\n"); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci rc = register_netdevice_notifier(&efx_netdev_notifier); 128562306a36Sopenharmony_ci if (rc) 128662306a36Sopenharmony_ci goto err_notifier; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 128962306a36Sopenharmony_ci rc = efx_init_sriov(); 129062306a36Sopenharmony_ci if (rc) 129162306a36Sopenharmony_ci goto err_sriov; 129262306a36Sopenharmony_ci#endif 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci rc = efx_siena_create_reset_workqueue(); 129562306a36Sopenharmony_ci if (rc) 129662306a36Sopenharmony_ci goto err_reset; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci rc = pci_register_driver(&efx_pci_driver); 129962306a36Sopenharmony_ci if (rc < 0) 130062306a36Sopenharmony_ci goto err_pci; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci return 0; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci err_pci: 130562306a36Sopenharmony_ci efx_siena_destroy_reset_workqueue(); 130662306a36Sopenharmony_ci err_reset: 130762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 130862306a36Sopenharmony_ci efx_fini_sriov(); 130962306a36Sopenharmony_ci err_sriov: 131062306a36Sopenharmony_ci#endif 131162306a36Sopenharmony_ci unregister_netdevice_notifier(&efx_netdev_notifier); 131262306a36Sopenharmony_ci err_notifier: 131362306a36Sopenharmony_ci return rc; 131462306a36Sopenharmony_ci} 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic void __exit efx_exit_module(void) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci pr_info("Solarflare Siena driver unloading\n"); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci pci_unregister_driver(&efx_pci_driver); 132162306a36Sopenharmony_ci efx_siena_destroy_reset_workqueue(); 132262306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV 132362306a36Sopenharmony_ci efx_fini_sriov(); 132462306a36Sopenharmony_ci#endif 132562306a36Sopenharmony_ci unregister_netdevice_notifier(&efx_netdev_notifier); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci} 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cimodule_init(efx_init_module); 133062306a36Sopenharmony_cimodule_exit(efx_exit_module); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ciMODULE_AUTHOR("Solarflare Communications and " 133362306a36Sopenharmony_ci "Michael Brown <mbrown@fensystems.co.uk>"); 133462306a36Sopenharmony_ciMODULE_DESCRIPTION("Solarflare Siena network driver"); 133562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 133662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, efx_pci_table); 1337