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/module.h> 962306a36Sopenharmony_ci#include <linux/pci.h> 1062306a36Sopenharmony_ci#include <linux/netdevice.h> 1162306a36Sopenharmony_ci#include <linux/etherdevice.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/notifier.h> 1462306a36Sopenharmony_ci#include <linux/ip.h> 1562306a36Sopenharmony_ci#include <linux/tcp.h> 1662306a36Sopenharmony_ci#include <linux/in.h> 1762306a36Sopenharmony_ci#include <linux/ethtool.h> 1862306a36Sopenharmony_ci#include <linux/topology.h> 1962306a36Sopenharmony_ci#include <linux/gfp.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include "net_driver.h" 2262306a36Sopenharmony_ci#include "efx.h" 2362306a36Sopenharmony_ci#include "nic.h" 2462306a36Sopenharmony_ci#include "selftest.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "workarounds.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/************************************************************************** 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Type name strings 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci ************************************************************************** 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Loopback mode names (see LOOPBACK_MODE()) */ 3662306a36Sopenharmony_ciconst unsigned int ef4_loopback_mode_max = LOOPBACK_MAX; 3762306a36Sopenharmony_ciconst char *const ef4_loopback_mode_names[] = { 3862306a36Sopenharmony_ci [LOOPBACK_NONE] = "NONE", 3962306a36Sopenharmony_ci [LOOPBACK_DATA] = "DATAPATH", 4062306a36Sopenharmony_ci [LOOPBACK_GMAC] = "GMAC", 4162306a36Sopenharmony_ci [LOOPBACK_XGMII] = "XGMII", 4262306a36Sopenharmony_ci [LOOPBACK_XGXS] = "XGXS", 4362306a36Sopenharmony_ci [LOOPBACK_XAUI] = "XAUI", 4462306a36Sopenharmony_ci [LOOPBACK_GMII] = "GMII", 4562306a36Sopenharmony_ci [LOOPBACK_SGMII] = "SGMII", 4662306a36Sopenharmony_ci [LOOPBACK_XGBR] = "XGBR", 4762306a36Sopenharmony_ci [LOOPBACK_XFI] = "XFI", 4862306a36Sopenharmony_ci [LOOPBACK_XAUI_FAR] = "XAUI_FAR", 4962306a36Sopenharmony_ci [LOOPBACK_GMII_FAR] = "GMII_FAR", 5062306a36Sopenharmony_ci [LOOPBACK_SGMII_FAR] = "SGMII_FAR", 5162306a36Sopenharmony_ci [LOOPBACK_XFI_FAR] = "XFI_FAR", 5262306a36Sopenharmony_ci [LOOPBACK_GPHY] = "GPHY", 5362306a36Sopenharmony_ci [LOOPBACK_PHYXS] = "PHYXS", 5462306a36Sopenharmony_ci [LOOPBACK_PCS] = "PCS", 5562306a36Sopenharmony_ci [LOOPBACK_PMAPMD] = "PMA/PMD", 5662306a36Sopenharmony_ci [LOOPBACK_XPORT] = "XPORT", 5762306a36Sopenharmony_ci [LOOPBACK_XGMII_WS] = "XGMII_WS", 5862306a36Sopenharmony_ci [LOOPBACK_XAUI_WS] = "XAUI_WS", 5962306a36Sopenharmony_ci [LOOPBACK_XAUI_WS_FAR] = "XAUI_WS_FAR", 6062306a36Sopenharmony_ci [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR", 6162306a36Sopenharmony_ci [LOOPBACK_GMII_WS] = "GMII_WS", 6262306a36Sopenharmony_ci [LOOPBACK_XFI_WS] = "XFI_WS", 6362306a36Sopenharmony_ci [LOOPBACK_XFI_WS_FAR] = "XFI_WS_FAR", 6462306a36Sopenharmony_ci [LOOPBACK_PHYXS_WS] = "PHYXS_WS", 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciconst unsigned int ef4_reset_type_max = RESET_TYPE_MAX; 6862306a36Sopenharmony_ciconst char *const ef4_reset_type_names[] = { 6962306a36Sopenharmony_ci [RESET_TYPE_INVISIBLE] = "INVISIBLE", 7062306a36Sopenharmony_ci [RESET_TYPE_ALL] = "ALL", 7162306a36Sopenharmony_ci [RESET_TYPE_RECOVER_OR_ALL] = "RECOVER_OR_ALL", 7262306a36Sopenharmony_ci [RESET_TYPE_WORLD] = "WORLD", 7362306a36Sopenharmony_ci [RESET_TYPE_RECOVER_OR_DISABLE] = "RECOVER_OR_DISABLE", 7462306a36Sopenharmony_ci [RESET_TYPE_DATAPATH] = "DATAPATH", 7562306a36Sopenharmony_ci [RESET_TYPE_DISABLE] = "DISABLE", 7662306a36Sopenharmony_ci [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG", 7762306a36Sopenharmony_ci [RESET_TYPE_INT_ERROR] = "INT_ERROR", 7862306a36Sopenharmony_ci [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY", 7962306a36Sopenharmony_ci [RESET_TYPE_DMA_ERROR] = "DMA_ERROR", 8062306a36Sopenharmony_ci [RESET_TYPE_TX_SKIP] = "TX_SKIP", 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Reset workqueue. If any NIC has a hardware failure then a reset will be 8462306a36Sopenharmony_ci * queued onto this work queue. This is not a per-nic work queue, because 8562306a36Sopenharmony_ci * ef4_reset_work() acquires the rtnl lock, so resets are naturally serialised. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistatic struct workqueue_struct *reset_workqueue; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* How often and how many times to poll for a reset while waiting for a 9062306a36Sopenharmony_ci * BIST that another function started to complete. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci#define BIST_WAIT_DELAY_MS 100 9362306a36Sopenharmony_ci#define BIST_WAIT_DELAY_COUNT 100 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/************************************************************************** 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * Configurable values 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci *************************************************************************/ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * Use separate channels for TX and RX events 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Set this to 1 to use separate channels for TX and RX. It allows us 10562306a36Sopenharmony_ci * to control interrupt affinity separately for TX and RX. 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * This is only used in MSI-X interrupt mode 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cibool ef4_separate_tx_channels; 11062306a36Sopenharmony_cimodule_param(ef4_separate_tx_channels, bool, 0444); 11162306a36Sopenharmony_ciMODULE_PARM_DESC(ef4_separate_tx_channels, 11262306a36Sopenharmony_ci "Use separate channels for TX and RX"); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* This is the time (in jiffies) between invocations of the hardware 11562306a36Sopenharmony_ci * monitor. 11662306a36Sopenharmony_ci * On Falcon-based NICs, this will: 11762306a36Sopenharmony_ci * - Check the on-board hardware monitor; 11862306a36Sopenharmony_ci * - Poll the link state and reconfigure the hardware as necessary. 11962306a36Sopenharmony_ci * On Siena-based NICs for power systems with EEH support, this will give EEH a 12062306a36Sopenharmony_ci * chance to start. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cistatic unsigned int ef4_monitor_interval = 1 * HZ; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* Initial interrupt moderation settings. They can be modified after 12562306a36Sopenharmony_ci * module load with ethtool. 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * The default for RX should strike a balance between increasing the 12862306a36Sopenharmony_ci * round-trip latency and reducing overhead. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_cistatic unsigned int rx_irq_mod_usec = 60; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* Initial interrupt moderation settings. They can be modified after 13362306a36Sopenharmony_ci * module load with ethtool. 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * This default is chosen to ensure that a 10G link does not go idle 13662306a36Sopenharmony_ci * while a TX queue is stopped after it has become full. A queue is 13762306a36Sopenharmony_ci * restarted when it drops below half full. The time this takes (assuming 13862306a36Sopenharmony_ci * worst case 3 descriptors per packet and 1024 descriptors) is 13962306a36Sopenharmony_ci * 512 / 3 * 1.2 = 205 usec. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_cistatic unsigned int tx_irq_mod_usec = 150; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* This is the first interrupt mode to try out of: 14462306a36Sopenharmony_ci * 0 => MSI-X 14562306a36Sopenharmony_ci * 1 => MSI 14662306a36Sopenharmony_ci * 2 => legacy 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic unsigned int interrupt_mode; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS), 15162306a36Sopenharmony_ci * i.e. the number of CPUs among which we may distribute simultaneous 15262306a36Sopenharmony_ci * interrupt handling. 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * Cards without MSI-X will only target one CPU via legacy or MSI interrupt. 15562306a36Sopenharmony_ci * The default (0) means to assign an interrupt to each core. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic unsigned int rss_cpus; 15862306a36Sopenharmony_cimodule_param(rss_cpus, uint, 0444); 15962306a36Sopenharmony_ciMODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling"); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic bool phy_flash_cfg; 16262306a36Sopenharmony_cimodule_param(phy_flash_cfg, bool, 0644); 16362306a36Sopenharmony_ciMODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic unsigned irq_adapt_low_thresh = 8000; 16662306a36Sopenharmony_cimodule_param(irq_adapt_low_thresh, uint, 0644); 16762306a36Sopenharmony_ciMODULE_PARM_DESC(irq_adapt_low_thresh, 16862306a36Sopenharmony_ci "Threshold score for reducing IRQ moderation"); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic unsigned irq_adapt_high_thresh = 16000; 17162306a36Sopenharmony_cimodule_param(irq_adapt_high_thresh, uint, 0644); 17262306a36Sopenharmony_ciMODULE_PARM_DESC(irq_adapt_high_thresh, 17362306a36Sopenharmony_ci "Threshold score for increasing IRQ moderation"); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic unsigned debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE | 17662306a36Sopenharmony_ci NETIF_MSG_LINK | NETIF_MSG_IFDOWN | 17762306a36Sopenharmony_ci NETIF_MSG_IFUP | NETIF_MSG_RX_ERR | 17862306a36Sopenharmony_ci NETIF_MSG_TX_ERR | NETIF_MSG_HW); 17962306a36Sopenharmony_cimodule_param(debug, uint, 0); 18062306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/************************************************************************** 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * Utility functions and prototypes 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci *************************************************************************/ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int ef4_soft_enable_interrupts(struct ef4_nic *efx); 18962306a36Sopenharmony_cistatic void ef4_soft_disable_interrupts(struct ef4_nic *efx); 19062306a36Sopenharmony_cistatic void ef4_remove_channel(struct ef4_channel *channel); 19162306a36Sopenharmony_cistatic void ef4_remove_channels(struct ef4_nic *efx); 19262306a36Sopenharmony_cistatic const struct ef4_channel_type ef4_default_channel_type; 19362306a36Sopenharmony_cistatic void ef4_remove_port(struct ef4_nic *efx); 19462306a36Sopenharmony_cistatic void ef4_init_napi_channel(struct ef4_channel *channel); 19562306a36Sopenharmony_cistatic void ef4_fini_napi(struct ef4_nic *efx); 19662306a36Sopenharmony_cistatic void ef4_fini_napi_channel(struct ef4_channel *channel); 19762306a36Sopenharmony_cistatic void ef4_fini_struct(struct ef4_nic *efx); 19862306a36Sopenharmony_cistatic void ef4_start_all(struct ef4_nic *efx); 19962306a36Sopenharmony_cistatic void ef4_stop_all(struct ef4_nic *efx); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#define EF4_ASSERT_RESET_SERIALISED(efx) \ 20262306a36Sopenharmony_ci do { \ 20362306a36Sopenharmony_ci if ((efx->state == STATE_READY) || \ 20462306a36Sopenharmony_ci (efx->state == STATE_RECOVERY) || \ 20562306a36Sopenharmony_ci (efx->state == STATE_DISABLED)) \ 20662306a36Sopenharmony_ci ASSERT_RTNL(); \ 20762306a36Sopenharmony_ci } while (0) 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int ef4_check_disabled(struct ef4_nic *efx) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci if (efx->state == STATE_DISABLED || efx->state == STATE_RECOVERY) { 21262306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 21362306a36Sopenharmony_ci "device is disabled due to earlier errors\n"); 21462306a36Sopenharmony_ci return -EIO; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/************************************************************************** 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * Event queue processing 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci *************************************************************************/ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* Process channel's event queue 22662306a36Sopenharmony_ci * 22762306a36Sopenharmony_ci * This function is responsible for processing the event queue of a 22862306a36Sopenharmony_ci * single channel. The caller must guarantee that this function will 22962306a36Sopenharmony_ci * never be concurrently called more than once on the same channel, 23062306a36Sopenharmony_ci * though different channels may be being processed concurrently. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_cistatic int ef4_process_channel(struct ef4_channel *channel, int budget) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 23562306a36Sopenharmony_ci int spent; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (unlikely(!channel->enabled)) 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) { 24162306a36Sopenharmony_ci tx_queue->pkts_compl = 0; 24262306a36Sopenharmony_ci tx_queue->bytes_compl = 0; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci spent = ef4_nic_process_eventq(channel, budget); 24662306a36Sopenharmony_ci if (spent && ef4_channel_has_rx_queue(channel)) { 24762306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue = 24862306a36Sopenharmony_ci ef4_channel_get_rx_queue(channel); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci ef4_rx_flush_packet(channel); 25162306a36Sopenharmony_ci ef4_fast_push_rx_descriptors(rx_queue, true); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* Update BQL */ 25562306a36Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) { 25662306a36Sopenharmony_ci if (tx_queue->bytes_compl) { 25762306a36Sopenharmony_ci netdev_tx_completed_queue(tx_queue->core_txq, 25862306a36Sopenharmony_ci tx_queue->pkts_compl, tx_queue->bytes_compl); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return spent; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* NAPI poll handler 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * NAPI guarantees serialisation of polls of the same device, which 26862306a36Sopenharmony_ci * provides the guarantee required by ef4_process_channel(). 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_cistatic void ef4_update_irq_mod(struct ef4_nic *efx, struct ef4_channel *channel) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci int step = efx->irq_mod_step_us; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (channel->irq_mod_score < irq_adapt_low_thresh) { 27562306a36Sopenharmony_ci if (channel->irq_moderation_us > step) { 27662306a36Sopenharmony_ci channel->irq_moderation_us -= step; 27762306a36Sopenharmony_ci efx->type->push_irq_moderation(channel); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } else if (channel->irq_mod_score > irq_adapt_high_thresh) { 28062306a36Sopenharmony_ci if (channel->irq_moderation_us < 28162306a36Sopenharmony_ci efx->irq_rx_moderation_us) { 28262306a36Sopenharmony_ci channel->irq_moderation_us += step; 28362306a36Sopenharmony_ci efx->type->push_irq_moderation(channel); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci channel->irq_count = 0; 28862306a36Sopenharmony_ci channel->irq_mod_score = 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int ef4_poll(struct napi_struct *napi, int budget) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct ef4_channel *channel = 29462306a36Sopenharmony_ci container_of(napi, struct ef4_channel, napi_str); 29562306a36Sopenharmony_ci struct ef4_nic *efx = channel->efx; 29662306a36Sopenharmony_ci int spent; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci netif_vdbg(efx, intr, efx->net_dev, 29962306a36Sopenharmony_ci "channel %d NAPI poll executing on CPU %d\n", 30062306a36Sopenharmony_ci channel->channel, raw_smp_processor_id()); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci spent = ef4_process_channel(channel, budget); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (spent < budget) { 30562306a36Sopenharmony_ci if (ef4_channel_has_rx_queue(channel) && 30662306a36Sopenharmony_ci efx->irq_rx_adaptive && 30762306a36Sopenharmony_ci unlikely(++channel->irq_count == 1000)) { 30862306a36Sopenharmony_ci ef4_update_irq_mod(efx, channel); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ef4_filter_rfs_expire(channel); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* There is no race here; although napi_disable() will 31462306a36Sopenharmony_ci * only wait for napi_complete(), this isn't a problem 31562306a36Sopenharmony_ci * since ef4_nic_eventq_read_ack() will have no effect if 31662306a36Sopenharmony_ci * interrupts have already been disabled. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci napi_complete_done(napi, spent); 31962306a36Sopenharmony_ci ef4_nic_eventq_read_ack(channel); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return spent; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* Create event queue 32662306a36Sopenharmony_ci * Event queue memory allocations are done only once. If the channel 32762306a36Sopenharmony_ci * is reset, the memory buffer will be reused; this guards against 32862306a36Sopenharmony_ci * errors during channel reset and also simplifies interrupt handling. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistatic int ef4_probe_eventq(struct ef4_channel *channel) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct ef4_nic *efx = channel->efx; 33362306a36Sopenharmony_ci unsigned long entries; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 33662306a36Sopenharmony_ci "chan %d create event queue\n", channel->channel); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Build an event queue with room for one event per tx and rx buffer, 33962306a36Sopenharmony_ci * plus some extra for link state events and MCDI completions. */ 34062306a36Sopenharmony_ci entries = roundup_pow_of_two(efx->rxq_entries + efx->txq_entries + 128); 34162306a36Sopenharmony_ci EF4_BUG_ON_PARANOID(entries > EF4_MAX_EVQ_SIZE); 34262306a36Sopenharmony_ci channel->eventq_mask = max(entries, EF4_MIN_EVQ_SIZE) - 1; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return ef4_nic_probe_eventq(channel); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* Prepare channel's event queue */ 34862306a36Sopenharmony_cistatic int ef4_init_eventq(struct ef4_channel *channel) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct ef4_nic *efx = channel->efx; 35162306a36Sopenharmony_ci int rc; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci EF4_WARN_ON_PARANOID(channel->eventq_init); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 35662306a36Sopenharmony_ci "chan %d init event queue\n", channel->channel); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci rc = ef4_nic_init_eventq(channel); 35962306a36Sopenharmony_ci if (rc == 0) { 36062306a36Sopenharmony_ci efx->type->push_irq_moderation(channel); 36162306a36Sopenharmony_ci channel->eventq_read_ptr = 0; 36262306a36Sopenharmony_ci channel->eventq_init = true; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci return rc; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* Enable event queue processing and NAPI */ 36862306a36Sopenharmony_civoid ef4_start_eventq(struct ef4_channel *channel) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci netif_dbg(channel->efx, ifup, channel->efx->net_dev, 37162306a36Sopenharmony_ci "chan %d start event queue\n", channel->channel); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Make sure the NAPI handler sees the enabled flag set */ 37462306a36Sopenharmony_ci channel->enabled = true; 37562306a36Sopenharmony_ci smp_wmb(); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci napi_enable(&channel->napi_str); 37862306a36Sopenharmony_ci ef4_nic_eventq_read_ack(channel); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* Disable event queue processing and NAPI */ 38262306a36Sopenharmony_civoid ef4_stop_eventq(struct ef4_channel *channel) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci if (!channel->enabled) 38562306a36Sopenharmony_ci return; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci napi_disable(&channel->napi_str); 38862306a36Sopenharmony_ci channel->enabled = false; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void ef4_fini_eventq(struct ef4_channel *channel) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci if (!channel->eventq_init) 39462306a36Sopenharmony_ci return; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci netif_dbg(channel->efx, drv, channel->efx->net_dev, 39762306a36Sopenharmony_ci "chan %d fini event queue\n", channel->channel); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ef4_nic_fini_eventq(channel); 40062306a36Sopenharmony_ci channel->eventq_init = false; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void ef4_remove_eventq(struct ef4_channel *channel) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci netif_dbg(channel->efx, drv, channel->efx->net_dev, 40662306a36Sopenharmony_ci "chan %d remove event queue\n", channel->channel); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ef4_nic_remove_eventq(channel); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/************************************************************************** 41262306a36Sopenharmony_ci * 41362306a36Sopenharmony_ci * Channel handling 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci *************************************************************************/ 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* Allocate and initialise a channel structure. */ 41862306a36Sopenharmony_cistatic struct ef4_channel * 41962306a36Sopenharmony_cief4_alloc_channel(struct ef4_nic *efx, int i, struct ef4_channel *old_channel) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct ef4_channel *channel; 42262306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue; 42362306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 42462306a36Sopenharmony_ci int j; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci channel = kzalloc(sizeof(*channel), GFP_KERNEL); 42762306a36Sopenharmony_ci if (!channel) 42862306a36Sopenharmony_ci return NULL; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci channel->efx = efx; 43162306a36Sopenharmony_ci channel->channel = i; 43262306a36Sopenharmony_ci channel->type = &ef4_default_channel_type; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci for (j = 0; j < EF4_TXQ_TYPES; j++) { 43562306a36Sopenharmony_ci tx_queue = &channel->tx_queue[j]; 43662306a36Sopenharmony_ci tx_queue->efx = efx; 43762306a36Sopenharmony_ci tx_queue->queue = i * EF4_TXQ_TYPES + j; 43862306a36Sopenharmony_ci tx_queue->channel = channel; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci rx_queue = &channel->rx_queue; 44262306a36Sopenharmony_ci rx_queue->efx = efx; 44362306a36Sopenharmony_ci timer_setup(&rx_queue->slow_fill, ef4_rx_slow_fill, 0); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return channel; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci/* Allocate and initialise a channel structure, copying parameters 44962306a36Sopenharmony_ci * (but not resources) from an old channel structure. 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_cistatic struct ef4_channel * 45262306a36Sopenharmony_cief4_copy_channel(const struct ef4_channel *old_channel) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct ef4_channel *channel; 45562306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue; 45662306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 45762306a36Sopenharmony_ci int j; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci channel = kmalloc(sizeof(*channel), GFP_KERNEL); 46062306a36Sopenharmony_ci if (!channel) 46162306a36Sopenharmony_ci return NULL; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci *channel = *old_channel; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci channel->napi_dev = NULL; 46662306a36Sopenharmony_ci INIT_HLIST_NODE(&channel->napi_str.napi_hash_node); 46762306a36Sopenharmony_ci channel->napi_str.napi_id = 0; 46862306a36Sopenharmony_ci channel->napi_str.state = 0; 46962306a36Sopenharmony_ci memset(&channel->eventq, 0, sizeof(channel->eventq)); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci for (j = 0; j < EF4_TXQ_TYPES; j++) { 47262306a36Sopenharmony_ci tx_queue = &channel->tx_queue[j]; 47362306a36Sopenharmony_ci if (tx_queue->channel) 47462306a36Sopenharmony_ci tx_queue->channel = channel; 47562306a36Sopenharmony_ci tx_queue->buffer = NULL; 47662306a36Sopenharmony_ci memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci rx_queue = &channel->rx_queue; 48062306a36Sopenharmony_ci rx_queue->buffer = NULL; 48162306a36Sopenharmony_ci memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); 48262306a36Sopenharmony_ci timer_setup(&rx_queue->slow_fill, ef4_rx_slow_fill, 0); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return channel; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int ef4_probe_channel(struct ef4_channel *channel) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 49062306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue; 49162306a36Sopenharmony_ci int rc; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci netif_dbg(channel->efx, probe, channel->efx->net_dev, 49462306a36Sopenharmony_ci "creating channel %d\n", channel->channel); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci rc = channel->type->pre_probe(channel); 49762306a36Sopenharmony_ci if (rc) 49862306a36Sopenharmony_ci goto fail; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci rc = ef4_probe_eventq(channel); 50162306a36Sopenharmony_ci if (rc) 50262306a36Sopenharmony_ci goto fail; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) { 50562306a36Sopenharmony_ci rc = ef4_probe_tx_queue(tx_queue); 50662306a36Sopenharmony_ci if (rc) 50762306a36Sopenharmony_ci goto fail; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ef4_for_each_channel_rx_queue(rx_queue, channel) { 51162306a36Sopenharmony_ci rc = ef4_probe_rx_queue(rx_queue); 51262306a36Sopenharmony_ci if (rc) 51362306a36Sopenharmony_ci goto fail; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cifail: 51962306a36Sopenharmony_ci ef4_remove_channel(channel); 52062306a36Sopenharmony_ci return rc; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic void 52462306a36Sopenharmony_cief4_get_channel_name(struct ef4_channel *channel, char *buf, size_t len) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct ef4_nic *efx = channel->efx; 52762306a36Sopenharmony_ci const char *type; 52862306a36Sopenharmony_ci int number; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci number = channel->channel; 53162306a36Sopenharmony_ci if (efx->tx_channel_offset == 0) { 53262306a36Sopenharmony_ci type = ""; 53362306a36Sopenharmony_ci } else if (channel->channel < efx->tx_channel_offset) { 53462306a36Sopenharmony_ci type = "-rx"; 53562306a36Sopenharmony_ci } else { 53662306a36Sopenharmony_ci type = "-tx"; 53762306a36Sopenharmony_ci number -= efx->tx_channel_offset; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci snprintf(buf, len, "%s%s-%d", efx->name, type, number); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic void ef4_set_channel_names(struct ef4_nic *efx) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct ef4_channel *channel; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 54762306a36Sopenharmony_ci channel->type->get_name(channel, 54862306a36Sopenharmony_ci efx->msi_context[channel->channel].name, 54962306a36Sopenharmony_ci sizeof(efx->msi_context[0].name)); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic int ef4_probe_channels(struct ef4_nic *efx) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct ef4_channel *channel; 55562306a36Sopenharmony_ci int rc; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Restart special buffer allocation */ 55862306a36Sopenharmony_ci efx->next_buffer_table = 0; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Probe channels in reverse, so that any 'extra' channels 56162306a36Sopenharmony_ci * use the start of the buffer table. This allows the traffic 56262306a36Sopenharmony_ci * channels to be resized without moving them or wasting the 56362306a36Sopenharmony_ci * entries before them. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci ef4_for_each_channel_rev(channel, efx) { 56662306a36Sopenharmony_ci rc = ef4_probe_channel(channel); 56762306a36Sopenharmony_ci if (rc) { 56862306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 56962306a36Sopenharmony_ci "failed to create channel %d\n", 57062306a36Sopenharmony_ci channel->channel); 57162306a36Sopenharmony_ci goto fail; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci ef4_set_channel_names(efx); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cifail: 57962306a36Sopenharmony_ci ef4_remove_channels(efx); 58062306a36Sopenharmony_ci return rc; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/* Channels are shutdown and reinitialised whilst the NIC is running 58462306a36Sopenharmony_ci * to propagate configuration changes (mtu, checksum offload), or 58562306a36Sopenharmony_ci * to clear hardware error conditions 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_cistatic void ef4_start_datapath(struct ef4_nic *efx) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci netdev_features_t old_features = efx->net_dev->features; 59062306a36Sopenharmony_ci bool old_rx_scatter = efx->rx_scatter; 59162306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 59262306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue; 59362306a36Sopenharmony_ci struct ef4_channel *channel; 59462306a36Sopenharmony_ci size_t rx_buf_len; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* Calculate the rx buffer allocation parameters required to 59762306a36Sopenharmony_ci * support the current MTU, including padding for header 59862306a36Sopenharmony_ci * alignment and overruns. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci efx->rx_dma_len = (efx->rx_prefix_size + 60162306a36Sopenharmony_ci EF4_MAX_FRAME_LEN(efx->net_dev->mtu) + 60262306a36Sopenharmony_ci efx->type->rx_buffer_padding); 60362306a36Sopenharmony_ci rx_buf_len = (sizeof(struct ef4_rx_page_state) + 60462306a36Sopenharmony_ci efx->rx_ip_align + efx->rx_dma_len); 60562306a36Sopenharmony_ci if (rx_buf_len <= PAGE_SIZE) { 60662306a36Sopenharmony_ci efx->rx_scatter = efx->type->always_rx_scatter; 60762306a36Sopenharmony_ci efx->rx_buffer_order = 0; 60862306a36Sopenharmony_ci } else if (efx->type->can_rx_scatter) { 60962306a36Sopenharmony_ci BUILD_BUG_ON(EF4_RX_USR_BUF_SIZE % L1_CACHE_BYTES); 61062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ef4_rx_page_state) + 61162306a36Sopenharmony_ci 2 * ALIGN(NET_IP_ALIGN + EF4_RX_USR_BUF_SIZE, 61262306a36Sopenharmony_ci EF4_RX_BUF_ALIGNMENT) > 61362306a36Sopenharmony_ci PAGE_SIZE); 61462306a36Sopenharmony_ci efx->rx_scatter = true; 61562306a36Sopenharmony_ci efx->rx_dma_len = EF4_RX_USR_BUF_SIZE; 61662306a36Sopenharmony_ci efx->rx_buffer_order = 0; 61762306a36Sopenharmony_ci } else { 61862306a36Sopenharmony_ci efx->rx_scatter = false; 61962306a36Sopenharmony_ci efx->rx_buffer_order = get_order(rx_buf_len); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci ef4_rx_config_page_split(efx); 62362306a36Sopenharmony_ci if (efx->rx_buffer_order) 62462306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 62562306a36Sopenharmony_ci "RX buf len=%u; page order=%u batch=%u\n", 62662306a36Sopenharmony_ci efx->rx_dma_len, efx->rx_buffer_order, 62762306a36Sopenharmony_ci efx->rx_pages_per_batch); 62862306a36Sopenharmony_ci else 62962306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 63062306a36Sopenharmony_ci "RX buf len=%u step=%u bpp=%u; page batch=%u\n", 63162306a36Sopenharmony_ci efx->rx_dma_len, efx->rx_page_buf_step, 63262306a36Sopenharmony_ci efx->rx_bufs_per_page, efx->rx_pages_per_batch); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* Restore previously fixed features in hw_features and remove 63562306a36Sopenharmony_ci * features which are fixed now 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_ci efx->net_dev->hw_features |= efx->net_dev->features; 63862306a36Sopenharmony_ci efx->net_dev->hw_features &= ~efx->fixed_features; 63962306a36Sopenharmony_ci efx->net_dev->features |= efx->fixed_features; 64062306a36Sopenharmony_ci if (efx->net_dev->features != old_features) 64162306a36Sopenharmony_ci netdev_features_change(efx->net_dev); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* RX filters may also have scatter-enabled flags */ 64462306a36Sopenharmony_ci if (efx->rx_scatter != old_rx_scatter) 64562306a36Sopenharmony_ci efx->type->filter_update_rx_scatter(efx); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* We must keep at least one descriptor in a TX ring empty. 64862306a36Sopenharmony_ci * We could avoid this when the queue size does not exactly 64962306a36Sopenharmony_ci * match the hardware ring size, but it's not that important. 65062306a36Sopenharmony_ci * Therefore we stop the queue when one more skb might fill 65162306a36Sopenharmony_ci * the ring completely. We wake it when half way back to 65262306a36Sopenharmony_ci * empty. 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_ci efx->txq_stop_thresh = efx->txq_entries - ef4_tx_max_skb_descs(efx); 65562306a36Sopenharmony_ci efx->txq_wake_thresh = efx->txq_stop_thresh / 2; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Initialise the channels */ 65862306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 65962306a36Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) { 66062306a36Sopenharmony_ci ef4_init_tx_queue(tx_queue); 66162306a36Sopenharmony_ci atomic_inc(&efx->active_queues); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci ef4_for_each_channel_rx_queue(rx_queue, channel) { 66562306a36Sopenharmony_ci ef4_init_rx_queue(rx_queue); 66662306a36Sopenharmony_ci atomic_inc(&efx->active_queues); 66762306a36Sopenharmony_ci ef4_stop_eventq(channel); 66862306a36Sopenharmony_ci ef4_fast_push_rx_descriptors(rx_queue, false); 66962306a36Sopenharmony_ci ef4_start_eventq(channel); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci WARN_ON(channel->rx_pkt_n_frags); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (netif_device_present(efx->net_dev)) 67662306a36Sopenharmony_ci netif_tx_wake_all_queues(efx->net_dev); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic void ef4_stop_datapath(struct ef4_nic *efx) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct ef4_channel *channel; 68262306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 68362306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue; 68462306a36Sopenharmony_ci int rc; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 68762306a36Sopenharmony_ci BUG_ON(efx->port_enabled); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Stop RX refill */ 69062306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 69162306a36Sopenharmony_ci ef4_for_each_channel_rx_queue(rx_queue, channel) 69262306a36Sopenharmony_ci rx_queue->refill_enabled = false; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 69662306a36Sopenharmony_ci /* RX packet processing is pipelined, so wait for the 69762306a36Sopenharmony_ci * NAPI handler to complete. At least event queue 0 69862306a36Sopenharmony_ci * might be kept active by non-data events, so don't 69962306a36Sopenharmony_ci * use napi_synchronize() but actually disable NAPI 70062306a36Sopenharmony_ci * temporarily. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_ci if (ef4_channel_has_rx_queue(channel)) { 70362306a36Sopenharmony_ci ef4_stop_eventq(channel); 70462306a36Sopenharmony_ci ef4_start_eventq(channel); 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci rc = efx->type->fini_dmaq(efx); 70962306a36Sopenharmony_ci if (rc && EF4_WORKAROUND_7803(efx)) { 71062306a36Sopenharmony_ci /* Schedule a reset to recover from the flush failure. The 71162306a36Sopenharmony_ci * descriptor caches reference memory we're about to free, 71262306a36Sopenharmony_ci * but falcon_reconfigure_mac_wrapper() won't reconnect 71362306a36Sopenharmony_ci * the MACs because of the pending reset. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 71662306a36Sopenharmony_ci "Resetting to recover from flush failure\n"); 71762306a36Sopenharmony_ci ef4_schedule_reset(efx, RESET_TYPE_ALL); 71862306a36Sopenharmony_ci } else if (rc) { 71962306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); 72062306a36Sopenharmony_ci } else { 72162306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 72262306a36Sopenharmony_ci "successfully flushed all queues\n"); 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 72662306a36Sopenharmony_ci ef4_for_each_channel_rx_queue(rx_queue, channel) 72762306a36Sopenharmony_ci ef4_fini_rx_queue(rx_queue); 72862306a36Sopenharmony_ci ef4_for_each_possible_channel_tx_queue(tx_queue, channel) 72962306a36Sopenharmony_ci ef4_fini_tx_queue(tx_queue); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void ef4_remove_channel(struct ef4_channel *channel) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 73662306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci netif_dbg(channel->efx, drv, channel->efx->net_dev, 73962306a36Sopenharmony_ci "destroy chan %d\n", channel->channel); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci ef4_for_each_channel_rx_queue(rx_queue, channel) 74262306a36Sopenharmony_ci ef4_remove_rx_queue(rx_queue); 74362306a36Sopenharmony_ci ef4_for_each_possible_channel_tx_queue(tx_queue, channel) 74462306a36Sopenharmony_ci ef4_remove_tx_queue(tx_queue); 74562306a36Sopenharmony_ci ef4_remove_eventq(channel); 74662306a36Sopenharmony_ci channel->type->post_remove(channel); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic void ef4_remove_channels(struct ef4_nic *efx) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct ef4_channel *channel; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 75462306a36Sopenharmony_ci ef4_remove_channel(channel); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ciint 75862306a36Sopenharmony_cief4_realloc_channels(struct ef4_nic *efx, u32 rxq_entries, u32 txq_entries) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct ef4_channel *other_channel[EF4_MAX_CHANNELS], *channel; 76162306a36Sopenharmony_ci u32 old_rxq_entries, old_txq_entries; 76262306a36Sopenharmony_ci unsigned i, next_buffer_table = 0; 76362306a36Sopenharmony_ci int rc, rc2; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci rc = ef4_check_disabled(efx); 76662306a36Sopenharmony_ci if (rc) 76762306a36Sopenharmony_ci return rc; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Not all channels should be reallocated. We must avoid 77062306a36Sopenharmony_ci * reallocating their buffer table entries. 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 77362306a36Sopenharmony_ci struct ef4_rx_queue *rx_queue; 77462306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (channel->type->copy) 77762306a36Sopenharmony_ci continue; 77862306a36Sopenharmony_ci next_buffer_table = max(next_buffer_table, 77962306a36Sopenharmony_ci channel->eventq.index + 78062306a36Sopenharmony_ci channel->eventq.entries); 78162306a36Sopenharmony_ci ef4_for_each_channel_rx_queue(rx_queue, channel) 78262306a36Sopenharmony_ci next_buffer_table = max(next_buffer_table, 78362306a36Sopenharmony_ci rx_queue->rxd.index + 78462306a36Sopenharmony_ci rx_queue->rxd.entries); 78562306a36Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) 78662306a36Sopenharmony_ci next_buffer_table = max(next_buffer_table, 78762306a36Sopenharmony_ci tx_queue->txd.index + 78862306a36Sopenharmony_ci tx_queue->txd.entries); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ef4_device_detach_sync(efx); 79262306a36Sopenharmony_ci ef4_stop_all(efx); 79362306a36Sopenharmony_ci ef4_soft_disable_interrupts(efx); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci /* Clone channels (where possible) */ 79662306a36Sopenharmony_ci memset(other_channel, 0, sizeof(other_channel)); 79762306a36Sopenharmony_ci for (i = 0; i < efx->n_channels; i++) { 79862306a36Sopenharmony_ci channel = efx->channel[i]; 79962306a36Sopenharmony_ci if (channel->type->copy) 80062306a36Sopenharmony_ci channel = channel->type->copy(channel); 80162306a36Sopenharmony_ci if (!channel) { 80262306a36Sopenharmony_ci rc = -ENOMEM; 80362306a36Sopenharmony_ci goto out; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci other_channel[i] = channel; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* Swap entry counts and channel pointers */ 80962306a36Sopenharmony_ci old_rxq_entries = efx->rxq_entries; 81062306a36Sopenharmony_ci old_txq_entries = efx->txq_entries; 81162306a36Sopenharmony_ci efx->rxq_entries = rxq_entries; 81262306a36Sopenharmony_ci efx->txq_entries = txq_entries; 81362306a36Sopenharmony_ci for (i = 0; i < efx->n_channels; i++) { 81462306a36Sopenharmony_ci swap(efx->channel[i], other_channel[i]); 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* Restart buffer table allocation */ 81862306a36Sopenharmony_ci efx->next_buffer_table = next_buffer_table; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci for (i = 0; i < efx->n_channels; i++) { 82162306a36Sopenharmony_ci channel = efx->channel[i]; 82262306a36Sopenharmony_ci if (!channel->type->copy) 82362306a36Sopenharmony_ci continue; 82462306a36Sopenharmony_ci rc = ef4_probe_channel(channel); 82562306a36Sopenharmony_ci if (rc) 82662306a36Sopenharmony_ci goto rollback; 82762306a36Sopenharmony_ci ef4_init_napi_channel(efx->channel[i]); 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ciout: 83162306a36Sopenharmony_ci /* Destroy unused channel structures */ 83262306a36Sopenharmony_ci for (i = 0; i < efx->n_channels; i++) { 83362306a36Sopenharmony_ci channel = other_channel[i]; 83462306a36Sopenharmony_ci if (channel && channel->type->copy) { 83562306a36Sopenharmony_ci ef4_fini_napi_channel(channel); 83662306a36Sopenharmony_ci ef4_remove_channel(channel); 83762306a36Sopenharmony_ci kfree(channel); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci rc2 = ef4_soft_enable_interrupts(efx); 84262306a36Sopenharmony_ci if (rc2) { 84362306a36Sopenharmony_ci rc = rc ? rc : rc2; 84462306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 84562306a36Sopenharmony_ci "unable to restart interrupts on channel reallocation\n"); 84662306a36Sopenharmony_ci ef4_schedule_reset(efx, RESET_TYPE_DISABLE); 84762306a36Sopenharmony_ci } else { 84862306a36Sopenharmony_ci ef4_start_all(efx); 84962306a36Sopenharmony_ci netif_device_attach(efx->net_dev); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci return rc; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cirollback: 85462306a36Sopenharmony_ci /* Swap back */ 85562306a36Sopenharmony_ci efx->rxq_entries = old_rxq_entries; 85662306a36Sopenharmony_ci efx->txq_entries = old_txq_entries; 85762306a36Sopenharmony_ci for (i = 0; i < efx->n_channels; i++) { 85862306a36Sopenharmony_ci swap(efx->channel[i], other_channel[i]); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci goto out; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_civoid ef4_schedule_slow_fill(struct ef4_rx_queue *rx_queue) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic const struct ef4_channel_type ef4_default_channel_type = { 86962306a36Sopenharmony_ci .pre_probe = ef4_channel_dummy_op_int, 87062306a36Sopenharmony_ci .post_remove = ef4_channel_dummy_op_void, 87162306a36Sopenharmony_ci .get_name = ef4_get_channel_name, 87262306a36Sopenharmony_ci .copy = ef4_copy_channel, 87362306a36Sopenharmony_ci .keep_eventq = false, 87462306a36Sopenharmony_ci}; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ciint ef4_channel_dummy_op_int(struct ef4_channel *channel) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_civoid ef4_channel_dummy_op_void(struct ef4_channel *channel) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/************************************************************************** 88662306a36Sopenharmony_ci * 88762306a36Sopenharmony_ci * Port handling 88862306a36Sopenharmony_ci * 88962306a36Sopenharmony_ci **************************************************************************/ 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci/* This ensures that the kernel is kept informed (via 89262306a36Sopenharmony_ci * netif_carrier_on/off) of the link status, and also maintains the 89362306a36Sopenharmony_ci * link status's stop on the port's TX queue. 89462306a36Sopenharmony_ci */ 89562306a36Sopenharmony_civoid ef4_link_status_changed(struct ef4_nic *efx) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct ef4_link_state *link_state = &efx->link_state; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure 90062306a36Sopenharmony_ci * that no events are triggered between unregister_netdev() and the 90162306a36Sopenharmony_ci * driver unloading. A more general condition is that NETDEV_CHANGE 90262306a36Sopenharmony_ci * can only be generated between NETDEV_UP and NETDEV_DOWN */ 90362306a36Sopenharmony_ci if (!netif_running(efx->net_dev)) 90462306a36Sopenharmony_ci return; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (link_state->up != netif_carrier_ok(efx->net_dev)) { 90762306a36Sopenharmony_ci efx->n_link_state_changes++; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (link_state->up) 91062306a36Sopenharmony_ci netif_carrier_on(efx->net_dev); 91162306a36Sopenharmony_ci else 91262306a36Sopenharmony_ci netif_carrier_off(efx->net_dev); 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci /* Status message for kernel log */ 91662306a36Sopenharmony_ci if (link_state->up) 91762306a36Sopenharmony_ci netif_info(efx, link, efx->net_dev, 91862306a36Sopenharmony_ci "link up at %uMbps %s-duplex (MTU %d)\n", 91962306a36Sopenharmony_ci link_state->speed, link_state->fd ? "full" : "half", 92062306a36Sopenharmony_ci efx->net_dev->mtu); 92162306a36Sopenharmony_ci else 92262306a36Sopenharmony_ci netif_info(efx, link, efx->net_dev, "link down\n"); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_civoid ef4_link_set_advertising(struct ef4_nic *efx, u32 advertising) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci efx->link_advertising = advertising; 92862306a36Sopenharmony_ci if (advertising) { 92962306a36Sopenharmony_ci if (advertising & ADVERTISED_Pause) 93062306a36Sopenharmony_ci efx->wanted_fc |= (EF4_FC_TX | EF4_FC_RX); 93162306a36Sopenharmony_ci else 93262306a36Sopenharmony_ci efx->wanted_fc &= ~(EF4_FC_TX | EF4_FC_RX); 93362306a36Sopenharmony_ci if (advertising & ADVERTISED_Asym_Pause) 93462306a36Sopenharmony_ci efx->wanted_fc ^= EF4_FC_TX; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_civoid ef4_link_set_wanted_fc(struct ef4_nic *efx, u8 wanted_fc) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci efx->wanted_fc = wanted_fc; 94162306a36Sopenharmony_ci if (efx->link_advertising) { 94262306a36Sopenharmony_ci if (wanted_fc & EF4_FC_RX) 94362306a36Sopenharmony_ci efx->link_advertising |= (ADVERTISED_Pause | 94462306a36Sopenharmony_ci ADVERTISED_Asym_Pause); 94562306a36Sopenharmony_ci else 94662306a36Sopenharmony_ci efx->link_advertising &= ~(ADVERTISED_Pause | 94762306a36Sopenharmony_ci ADVERTISED_Asym_Pause); 94862306a36Sopenharmony_ci if (wanted_fc & EF4_FC_TX) 94962306a36Sopenharmony_ci efx->link_advertising ^= ADVERTISED_Asym_Pause; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic void ef4_fini_port(struct ef4_nic *efx); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci/* We assume that efx->type->reconfigure_mac will always try to sync RX 95662306a36Sopenharmony_ci * filters and therefore needs to read-lock the filter table against freeing 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_civoid ef4_mac_reconfigure(struct ef4_nic *efx) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci down_read(&efx->filter_sem); 96162306a36Sopenharmony_ci efx->type->reconfigure_mac(efx); 96262306a36Sopenharmony_ci up_read(&efx->filter_sem); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci/* Push loopback/power/transmit disable settings to the PHY, and reconfigure 96662306a36Sopenharmony_ci * the MAC appropriately. All other PHY configuration changes are pushed 96762306a36Sopenharmony_ci * through phy_op->set_link_ksettings(), and pushed asynchronously to the MAC 96862306a36Sopenharmony_ci * through ef4_monitor(). 96962306a36Sopenharmony_ci * 97062306a36Sopenharmony_ci * Callers must hold the mac_lock 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ciint __ef4_reconfigure_port(struct ef4_nic *efx) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci enum ef4_phy_mode phy_mode; 97562306a36Sopenharmony_ci int rc; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci WARN_ON(!mutex_is_locked(&efx->mac_lock)); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* Disable PHY transmit in mac level loopbacks */ 98062306a36Sopenharmony_ci phy_mode = efx->phy_mode; 98162306a36Sopenharmony_ci if (LOOPBACK_INTERNAL(efx)) 98262306a36Sopenharmony_ci efx->phy_mode |= PHY_MODE_TX_DISABLED; 98362306a36Sopenharmony_ci else 98462306a36Sopenharmony_ci efx->phy_mode &= ~PHY_MODE_TX_DISABLED; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci rc = efx->type->reconfigure_port(efx); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (rc) 98962306a36Sopenharmony_ci efx->phy_mode = phy_mode; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return rc; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci/* Reinitialise the MAC to pick up new PHY settings, even if the port is 99562306a36Sopenharmony_ci * disabled. */ 99662306a36Sopenharmony_ciint ef4_reconfigure_port(struct ef4_nic *efx) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci int rc; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 100362306a36Sopenharmony_ci rc = __ef4_reconfigure_port(efx); 100462306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci return rc; 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci/* Asynchronous work item for changing MAC promiscuity and multicast 101062306a36Sopenharmony_ci * hash. Avoid a drain/rx_ingress enable by reconfiguring the current 101162306a36Sopenharmony_ci * MAC directly. */ 101262306a36Sopenharmony_cistatic void ef4_mac_work(struct work_struct *data) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct ef4_nic *efx = container_of(data, struct ef4_nic, mac_work); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 101762306a36Sopenharmony_ci if (efx->port_enabled) 101862306a36Sopenharmony_ci ef4_mac_reconfigure(efx); 101962306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic int ef4_probe_port(struct ef4_nic *efx) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci int rc; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "create port\n"); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (phy_flash_cfg) 102962306a36Sopenharmony_ci efx->phy_mode = PHY_MODE_SPECIAL; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* Connect up MAC/PHY operations table */ 103262306a36Sopenharmony_ci rc = efx->type->probe_port(efx); 103362306a36Sopenharmony_ci if (rc) 103462306a36Sopenharmony_ci return rc; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* Initialise MAC address to permanent address */ 103762306a36Sopenharmony_ci eth_hw_addr_set(efx->net_dev, efx->net_dev->perm_addr); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int ef4_init_port(struct ef4_nic *efx) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci int rc; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "init port\n"); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci rc = efx->phy_op->init(efx); 105162306a36Sopenharmony_ci if (rc) 105262306a36Sopenharmony_ci goto fail1; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci efx->port_initialized = true; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* Reconfigure the MAC before creating dma queues (required for 105762306a36Sopenharmony_ci * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */ 105862306a36Sopenharmony_ci ef4_mac_reconfigure(efx); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* Ensure the PHY advertises the correct flow control settings */ 106162306a36Sopenharmony_ci rc = efx->phy_op->reconfigure(efx); 106262306a36Sopenharmony_ci if (rc && rc != -EPERM) 106362306a36Sopenharmony_ci goto fail2; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 106662306a36Sopenharmony_ci return 0; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cifail2: 106962306a36Sopenharmony_ci efx->phy_op->fini(efx); 107062306a36Sopenharmony_cifail1: 107162306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 107262306a36Sopenharmony_ci return rc; 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic void ef4_start_port(struct ef4_nic *efx) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci netif_dbg(efx, ifup, efx->net_dev, "start port\n"); 107862306a36Sopenharmony_ci BUG_ON(efx->port_enabled); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 108162306a36Sopenharmony_ci efx->port_enabled = true; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* Ensure MAC ingress/egress is enabled */ 108462306a36Sopenharmony_ci ef4_mac_reconfigure(efx); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci/* Cancel work for MAC reconfiguration, periodic hardware monitoring 109062306a36Sopenharmony_ci * and the async self-test, wait for them to finish and prevent them 109162306a36Sopenharmony_ci * being scheduled again. This doesn't cover online resets, which 109262306a36Sopenharmony_ci * should only be cancelled when removing the device. 109362306a36Sopenharmony_ci */ 109462306a36Sopenharmony_cistatic void ef4_stop_port(struct ef4_nic *efx) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci netif_dbg(efx, ifdown, efx->net_dev, "stop port\n"); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 110162306a36Sopenharmony_ci efx->port_enabled = false; 110262306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* Serialise against ef4_set_multicast_list() */ 110562306a36Sopenharmony_ci netif_addr_lock_bh(efx->net_dev); 110662306a36Sopenharmony_ci netif_addr_unlock_bh(efx->net_dev); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci cancel_delayed_work_sync(&efx->monitor_work); 110962306a36Sopenharmony_ci ef4_selftest_async_cancel(efx); 111062306a36Sopenharmony_ci cancel_work_sync(&efx->mac_work); 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic void ef4_fini_port(struct ef4_nic *efx) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "shut down port\n"); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (!efx->port_initialized) 111862306a36Sopenharmony_ci return; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci efx->phy_op->fini(efx); 112162306a36Sopenharmony_ci efx->port_initialized = false; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci efx->link_state.up = false; 112462306a36Sopenharmony_ci ef4_link_status_changed(efx); 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic void ef4_remove_port(struct ef4_nic *efx) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "destroying port\n"); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci efx->type->remove_port(efx); 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci/************************************************************************** 113562306a36Sopenharmony_ci * 113662306a36Sopenharmony_ci * NIC handling 113762306a36Sopenharmony_ci * 113862306a36Sopenharmony_ci **************************************************************************/ 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic LIST_HEAD(ef4_primary_list); 114162306a36Sopenharmony_cistatic LIST_HEAD(ef4_unassociated_list); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic bool ef4_same_controller(struct ef4_nic *left, struct ef4_nic *right) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci return left->type == right->type && 114662306a36Sopenharmony_ci left->vpd_sn && right->vpd_sn && 114762306a36Sopenharmony_ci !strcmp(left->vpd_sn, right->vpd_sn); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic void ef4_associate(struct ef4_nic *efx) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci struct ef4_nic *other, *next; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (efx->primary == efx) { 115562306a36Sopenharmony_ci /* Adding primary function; look for secondaries */ 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "adding to primary list\n"); 115862306a36Sopenharmony_ci list_add_tail(&efx->node, &ef4_primary_list); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci list_for_each_entry_safe(other, next, &ef4_unassociated_list, 116162306a36Sopenharmony_ci node) { 116262306a36Sopenharmony_ci if (ef4_same_controller(efx, other)) { 116362306a36Sopenharmony_ci list_del(&other->node); 116462306a36Sopenharmony_ci netif_dbg(other, probe, other->net_dev, 116562306a36Sopenharmony_ci "moving to secondary list of %s %s\n", 116662306a36Sopenharmony_ci pci_name(efx->pci_dev), 116762306a36Sopenharmony_ci efx->net_dev->name); 116862306a36Sopenharmony_ci list_add_tail(&other->node, 116962306a36Sopenharmony_ci &efx->secondary_list); 117062306a36Sopenharmony_ci other->primary = efx; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci } else { 117462306a36Sopenharmony_ci /* Adding secondary function; look for primary */ 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci list_for_each_entry(other, &ef4_primary_list, node) { 117762306a36Sopenharmony_ci if (ef4_same_controller(efx, other)) { 117862306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 117962306a36Sopenharmony_ci "adding to secondary list of %s %s\n", 118062306a36Sopenharmony_ci pci_name(other->pci_dev), 118162306a36Sopenharmony_ci other->net_dev->name); 118262306a36Sopenharmony_ci list_add_tail(&efx->node, 118362306a36Sopenharmony_ci &other->secondary_list); 118462306a36Sopenharmony_ci efx->primary = other; 118562306a36Sopenharmony_ci return; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 119062306a36Sopenharmony_ci "adding to unassociated list\n"); 119162306a36Sopenharmony_ci list_add_tail(&efx->node, &ef4_unassociated_list); 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic void ef4_dissociate(struct ef4_nic *efx) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct ef4_nic *other, *next; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci list_del(&efx->node); 120062306a36Sopenharmony_ci efx->primary = NULL; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci list_for_each_entry_safe(other, next, &efx->secondary_list, node) { 120362306a36Sopenharmony_ci list_del(&other->node); 120462306a36Sopenharmony_ci netif_dbg(other, probe, other->net_dev, 120562306a36Sopenharmony_ci "moving to unassociated list\n"); 120662306a36Sopenharmony_ci list_add_tail(&other->node, &ef4_unassociated_list); 120762306a36Sopenharmony_ci other->primary = NULL; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci/* This configures the PCI device to enable I/O and DMA. */ 121262306a36Sopenharmony_cistatic int ef4_init_io(struct ef4_nic *efx) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct pci_dev *pci_dev = efx->pci_dev; 121562306a36Sopenharmony_ci dma_addr_t dma_mask = efx->type->max_dma_mask; 121662306a36Sopenharmony_ci unsigned int mem_map_size = efx->type->mem_map_size(efx); 121762306a36Sopenharmony_ci int rc, bar; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci bar = efx->type->mem_bar; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci rc = pci_enable_device(pci_dev); 122462306a36Sopenharmony_ci if (rc) { 122562306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 122662306a36Sopenharmony_ci "failed to enable PCI device\n"); 122762306a36Sopenharmony_ci goto fail1; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci pci_set_master(pci_dev); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci /* Set the PCI DMA mask. Try all possibilities from our genuine mask 123362306a36Sopenharmony_ci * down to 32 bits, because some architectures will allow 40 bit 123462306a36Sopenharmony_ci * masks event though they reject 46 bit masks. 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_ci while (dma_mask > 0x7fffffffUL) { 123762306a36Sopenharmony_ci rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask); 123862306a36Sopenharmony_ci if (rc == 0) 123962306a36Sopenharmony_ci break; 124062306a36Sopenharmony_ci dma_mask >>= 1; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci if (rc) { 124362306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 124462306a36Sopenharmony_ci "could not find a suitable DMA mask\n"); 124562306a36Sopenharmony_ci goto fail2; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 124862306a36Sopenharmony_ci "using DMA mask %llx\n", (unsigned long long) dma_mask); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci efx->membase_phys = pci_resource_start(efx->pci_dev, bar); 125162306a36Sopenharmony_ci rc = pci_request_region(pci_dev, bar, "sfc"); 125262306a36Sopenharmony_ci if (rc) { 125362306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 125462306a36Sopenharmony_ci "request for memory BAR failed\n"); 125562306a36Sopenharmony_ci rc = -EIO; 125662306a36Sopenharmony_ci goto fail3; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci efx->membase = ioremap(efx->membase_phys, mem_map_size); 125962306a36Sopenharmony_ci if (!efx->membase) { 126062306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 126162306a36Sopenharmony_ci "could not map memory BAR at %llx+%x\n", 126262306a36Sopenharmony_ci (unsigned long long)efx->membase_phys, mem_map_size); 126362306a36Sopenharmony_ci rc = -ENOMEM; 126462306a36Sopenharmony_ci goto fail4; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, 126762306a36Sopenharmony_ci "memory BAR at %llx+%x (virtual %p)\n", 126862306a36Sopenharmony_ci (unsigned long long)efx->membase_phys, mem_map_size, 126962306a36Sopenharmony_ci efx->membase); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci return 0; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci fail4: 127462306a36Sopenharmony_ci pci_release_region(efx->pci_dev, bar); 127562306a36Sopenharmony_ci fail3: 127662306a36Sopenharmony_ci efx->membase_phys = 0; 127762306a36Sopenharmony_ci fail2: 127862306a36Sopenharmony_ci pci_disable_device(efx->pci_dev); 127962306a36Sopenharmony_ci fail1: 128062306a36Sopenharmony_ci return rc; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic void ef4_fini_io(struct ef4_nic *efx) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci int bar; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n"); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (efx->membase) { 129062306a36Sopenharmony_ci iounmap(efx->membase); 129162306a36Sopenharmony_ci efx->membase = NULL; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (efx->membase_phys) { 129562306a36Sopenharmony_ci bar = efx->type->mem_bar; 129662306a36Sopenharmony_ci pci_release_region(efx->pci_dev, bar); 129762306a36Sopenharmony_ci efx->membase_phys = 0; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* Don't disable bus-mastering if VFs are assigned */ 130162306a36Sopenharmony_ci if (!pci_vfs_assigned(efx->pci_dev)) 130262306a36Sopenharmony_ci pci_disable_device(efx->pci_dev); 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_civoid ef4_set_default_rx_indir_table(struct ef4_nic *efx) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci size_t i; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) 131062306a36Sopenharmony_ci efx->rx_indir_table[i] = 131162306a36Sopenharmony_ci ethtool_rxfh_indir_default(i, efx->rss_spread); 131262306a36Sopenharmony_ci} 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic unsigned int ef4_wanted_parallelism(struct ef4_nic *efx) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci cpumask_var_t thread_mask; 131762306a36Sopenharmony_ci unsigned int count; 131862306a36Sopenharmony_ci int cpu; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci if (rss_cpus) { 132162306a36Sopenharmony_ci count = rss_cpus; 132262306a36Sopenharmony_ci } else { 132362306a36Sopenharmony_ci if (unlikely(!zalloc_cpumask_var(&thread_mask, GFP_KERNEL))) { 132462306a36Sopenharmony_ci netif_warn(efx, probe, efx->net_dev, 132562306a36Sopenharmony_ci "RSS disabled due to allocation failure\n"); 132662306a36Sopenharmony_ci return 1; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci count = 0; 133062306a36Sopenharmony_ci for_each_online_cpu(cpu) { 133162306a36Sopenharmony_ci if (!cpumask_test_cpu(cpu, thread_mask)) { 133262306a36Sopenharmony_ci ++count; 133362306a36Sopenharmony_ci cpumask_or(thread_mask, thread_mask, 133462306a36Sopenharmony_ci topology_sibling_cpumask(cpu)); 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci free_cpumask_var(thread_mask); 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci if (count > EF4_MAX_RX_QUEUES) { 134262306a36Sopenharmony_ci netif_cond_dbg(efx, probe, efx->net_dev, !rss_cpus, warn, 134362306a36Sopenharmony_ci "Reducing number of rx queues from %u to %u.\n", 134462306a36Sopenharmony_ci count, EF4_MAX_RX_QUEUES); 134562306a36Sopenharmony_ci count = EF4_MAX_RX_QUEUES; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci return count; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci/* Probe the number and type of interrupts we are able to obtain, and 135262306a36Sopenharmony_ci * the resulting numbers of channels and RX queues. 135362306a36Sopenharmony_ci */ 135462306a36Sopenharmony_cistatic int ef4_probe_interrupts(struct ef4_nic *efx) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci unsigned int extra_channels = 0; 135762306a36Sopenharmony_ci unsigned int i, j; 135862306a36Sopenharmony_ci int rc; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci for (i = 0; i < EF4_MAX_EXTRA_CHANNELS; i++) 136162306a36Sopenharmony_ci if (efx->extra_channel_type[i]) 136262306a36Sopenharmony_ci ++extra_channels; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci if (efx->interrupt_mode == EF4_INT_MODE_MSIX) { 136562306a36Sopenharmony_ci struct msix_entry xentries[EF4_MAX_CHANNELS]; 136662306a36Sopenharmony_ci unsigned int n_channels; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci n_channels = ef4_wanted_parallelism(efx); 136962306a36Sopenharmony_ci if (ef4_separate_tx_channels) 137062306a36Sopenharmony_ci n_channels *= 2; 137162306a36Sopenharmony_ci n_channels += extra_channels; 137262306a36Sopenharmony_ci n_channels = min(n_channels, efx->max_channels); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci for (i = 0; i < n_channels; i++) 137562306a36Sopenharmony_ci xentries[i].entry = i; 137662306a36Sopenharmony_ci rc = pci_enable_msix_range(efx->pci_dev, 137762306a36Sopenharmony_ci xentries, 1, n_channels); 137862306a36Sopenharmony_ci if (rc < 0) { 137962306a36Sopenharmony_ci /* Fall back to single channel MSI */ 138062306a36Sopenharmony_ci efx->interrupt_mode = EF4_INT_MODE_MSI; 138162306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 138262306a36Sopenharmony_ci "could not enable MSI-X\n"); 138362306a36Sopenharmony_ci } else if (rc < n_channels) { 138462306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 138562306a36Sopenharmony_ci "WARNING: Insufficient MSI-X vectors" 138662306a36Sopenharmony_ci " available (%d < %u).\n", rc, n_channels); 138762306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 138862306a36Sopenharmony_ci "WARNING: Performance may be reduced.\n"); 138962306a36Sopenharmony_ci n_channels = rc; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (rc > 0) { 139362306a36Sopenharmony_ci efx->n_channels = n_channels; 139462306a36Sopenharmony_ci if (n_channels > extra_channels) 139562306a36Sopenharmony_ci n_channels -= extra_channels; 139662306a36Sopenharmony_ci if (ef4_separate_tx_channels) { 139762306a36Sopenharmony_ci efx->n_tx_channels = min(max(n_channels / 2, 139862306a36Sopenharmony_ci 1U), 139962306a36Sopenharmony_ci efx->max_tx_channels); 140062306a36Sopenharmony_ci efx->n_rx_channels = max(n_channels - 140162306a36Sopenharmony_ci efx->n_tx_channels, 140262306a36Sopenharmony_ci 1U); 140362306a36Sopenharmony_ci } else { 140462306a36Sopenharmony_ci efx->n_tx_channels = min(n_channels, 140562306a36Sopenharmony_ci efx->max_tx_channels); 140662306a36Sopenharmony_ci efx->n_rx_channels = n_channels; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci for (i = 0; i < efx->n_channels; i++) 140962306a36Sopenharmony_ci ef4_get_channel(efx, i)->irq = 141062306a36Sopenharmony_ci xentries[i].vector; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci /* Try single interrupt MSI */ 141562306a36Sopenharmony_ci if (efx->interrupt_mode == EF4_INT_MODE_MSI) { 141662306a36Sopenharmony_ci efx->n_channels = 1; 141762306a36Sopenharmony_ci efx->n_rx_channels = 1; 141862306a36Sopenharmony_ci efx->n_tx_channels = 1; 141962306a36Sopenharmony_ci rc = pci_enable_msi(efx->pci_dev); 142062306a36Sopenharmony_ci if (rc == 0) { 142162306a36Sopenharmony_ci ef4_get_channel(efx, 0)->irq = efx->pci_dev->irq; 142262306a36Sopenharmony_ci } else { 142362306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 142462306a36Sopenharmony_ci "could not enable MSI\n"); 142562306a36Sopenharmony_ci efx->interrupt_mode = EF4_INT_MODE_LEGACY; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci /* Assume legacy interrupts */ 143062306a36Sopenharmony_ci if (efx->interrupt_mode == EF4_INT_MODE_LEGACY) { 143162306a36Sopenharmony_ci efx->n_channels = 1 + (ef4_separate_tx_channels ? 1 : 0); 143262306a36Sopenharmony_ci efx->n_rx_channels = 1; 143362306a36Sopenharmony_ci efx->n_tx_channels = 1; 143462306a36Sopenharmony_ci efx->legacy_irq = efx->pci_dev->irq; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* Assign extra channels if possible */ 143862306a36Sopenharmony_ci j = efx->n_channels; 143962306a36Sopenharmony_ci for (i = 0; i < EF4_MAX_EXTRA_CHANNELS; i++) { 144062306a36Sopenharmony_ci if (!efx->extra_channel_type[i]) 144162306a36Sopenharmony_ci continue; 144262306a36Sopenharmony_ci if (efx->interrupt_mode != EF4_INT_MODE_MSIX || 144362306a36Sopenharmony_ci efx->n_channels <= extra_channels) { 144462306a36Sopenharmony_ci efx->extra_channel_type[i]->handle_no_channel(efx); 144562306a36Sopenharmony_ci } else { 144662306a36Sopenharmony_ci --j; 144762306a36Sopenharmony_ci ef4_get_channel(efx, j)->type = 144862306a36Sopenharmony_ci efx->extra_channel_type[i]; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci efx->rss_spread = efx->n_rx_channels; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci return 0; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_cistatic int ef4_soft_enable_interrupts(struct ef4_nic *efx) 145862306a36Sopenharmony_ci{ 145962306a36Sopenharmony_ci struct ef4_channel *channel, *end_channel; 146062306a36Sopenharmony_ci int rc; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci BUG_ON(efx->state == STATE_DISABLED); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci efx->irq_soft_enabled = true; 146562306a36Sopenharmony_ci smp_wmb(); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 146862306a36Sopenharmony_ci if (!channel->type->keep_eventq) { 146962306a36Sopenharmony_ci rc = ef4_init_eventq(channel); 147062306a36Sopenharmony_ci if (rc) 147162306a36Sopenharmony_ci goto fail; 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci ef4_start_eventq(channel); 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci return 0; 147762306a36Sopenharmony_cifail: 147862306a36Sopenharmony_ci end_channel = channel; 147962306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 148062306a36Sopenharmony_ci if (channel == end_channel) 148162306a36Sopenharmony_ci break; 148262306a36Sopenharmony_ci ef4_stop_eventq(channel); 148362306a36Sopenharmony_ci if (!channel->type->keep_eventq) 148462306a36Sopenharmony_ci ef4_fini_eventq(channel); 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci return rc; 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_cistatic void ef4_soft_disable_interrupts(struct ef4_nic *efx) 149162306a36Sopenharmony_ci{ 149262306a36Sopenharmony_ci struct ef4_channel *channel; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci if (efx->state == STATE_DISABLED) 149562306a36Sopenharmony_ci return; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci efx->irq_soft_enabled = false; 149862306a36Sopenharmony_ci smp_wmb(); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (efx->legacy_irq) 150162306a36Sopenharmony_ci synchronize_irq(efx->legacy_irq); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 150462306a36Sopenharmony_ci if (channel->irq) 150562306a36Sopenharmony_ci synchronize_irq(channel->irq); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci ef4_stop_eventq(channel); 150862306a36Sopenharmony_ci if (!channel->type->keep_eventq) 150962306a36Sopenharmony_ci ef4_fini_eventq(channel); 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic int ef4_enable_interrupts(struct ef4_nic *efx) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci struct ef4_channel *channel, *end_channel; 151662306a36Sopenharmony_ci int rc; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci BUG_ON(efx->state == STATE_DISABLED); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci if (efx->eeh_disabled_legacy_irq) { 152162306a36Sopenharmony_ci enable_irq(efx->legacy_irq); 152262306a36Sopenharmony_ci efx->eeh_disabled_legacy_irq = false; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci efx->type->irq_enable_master(efx); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 152862306a36Sopenharmony_ci if (channel->type->keep_eventq) { 152962306a36Sopenharmony_ci rc = ef4_init_eventq(channel); 153062306a36Sopenharmony_ci if (rc) 153162306a36Sopenharmony_ci goto fail; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci rc = ef4_soft_enable_interrupts(efx); 153662306a36Sopenharmony_ci if (rc) 153762306a36Sopenharmony_ci goto fail; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci return 0; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cifail: 154262306a36Sopenharmony_ci end_channel = channel; 154362306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 154462306a36Sopenharmony_ci if (channel == end_channel) 154562306a36Sopenharmony_ci break; 154662306a36Sopenharmony_ci if (channel->type->keep_eventq) 154762306a36Sopenharmony_ci ef4_fini_eventq(channel); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci efx->type->irq_disable_non_ev(efx); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci return rc; 155362306a36Sopenharmony_ci} 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_cistatic void ef4_disable_interrupts(struct ef4_nic *efx) 155662306a36Sopenharmony_ci{ 155762306a36Sopenharmony_ci struct ef4_channel *channel; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci ef4_soft_disable_interrupts(efx); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 156262306a36Sopenharmony_ci if (channel->type->keep_eventq) 156362306a36Sopenharmony_ci ef4_fini_eventq(channel); 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci efx->type->irq_disable_non_ev(efx); 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic void ef4_remove_interrupts(struct ef4_nic *efx) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci struct ef4_channel *channel; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* Remove MSI/MSI-X interrupts */ 157462306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 157562306a36Sopenharmony_ci channel->irq = 0; 157662306a36Sopenharmony_ci pci_disable_msi(efx->pci_dev); 157762306a36Sopenharmony_ci pci_disable_msix(efx->pci_dev); 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci /* Remove legacy interrupt */ 158062306a36Sopenharmony_ci efx->legacy_irq = 0; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cistatic void ef4_set_channels(struct ef4_nic *efx) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci struct ef4_channel *channel; 158662306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci efx->tx_channel_offset = 158962306a36Sopenharmony_ci ef4_separate_tx_channels ? 159062306a36Sopenharmony_ci efx->n_channels - efx->n_tx_channels : 0; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci /* We need to mark which channels really have RX and TX 159362306a36Sopenharmony_ci * queues, and adjust the TX queue numbers if we have separate 159462306a36Sopenharmony_ci * RX-only and TX-only channels. 159562306a36Sopenharmony_ci */ 159662306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 159762306a36Sopenharmony_ci if (channel->channel < efx->n_rx_channels) 159862306a36Sopenharmony_ci channel->rx_queue.core_index = channel->channel; 159962306a36Sopenharmony_ci else 160062306a36Sopenharmony_ci channel->rx_queue.core_index = -1; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) 160362306a36Sopenharmony_ci tx_queue->queue -= (efx->tx_channel_offset * 160462306a36Sopenharmony_ci EF4_TXQ_TYPES); 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic int ef4_probe_nic(struct ef4_nic *efx) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci int rc; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "creating NIC\n"); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci /* Carry out hardware-type specific initialisation */ 161562306a36Sopenharmony_ci rc = efx->type->probe(efx); 161662306a36Sopenharmony_ci if (rc) 161762306a36Sopenharmony_ci return rc; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci do { 162062306a36Sopenharmony_ci if (!efx->max_channels || !efx->max_tx_channels) { 162162306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 162262306a36Sopenharmony_ci "Insufficient resources to allocate" 162362306a36Sopenharmony_ci " any channels\n"); 162462306a36Sopenharmony_ci rc = -ENOSPC; 162562306a36Sopenharmony_ci goto fail1; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci /* Determine the number of channels and queues by trying 162962306a36Sopenharmony_ci * to hook in MSI-X interrupts. 163062306a36Sopenharmony_ci */ 163162306a36Sopenharmony_ci rc = ef4_probe_interrupts(efx); 163262306a36Sopenharmony_ci if (rc) 163362306a36Sopenharmony_ci goto fail1; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci ef4_set_channels(efx); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci /* dimension_resources can fail with EAGAIN */ 163862306a36Sopenharmony_ci rc = efx->type->dimension_resources(efx); 163962306a36Sopenharmony_ci if (rc != 0 && rc != -EAGAIN) 164062306a36Sopenharmony_ci goto fail2; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (rc == -EAGAIN) 164362306a36Sopenharmony_ci /* try again with new max_channels */ 164462306a36Sopenharmony_ci ef4_remove_interrupts(efx); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci } while (rc == -EAGAIN); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if (efx->n_channels > 1) 164962306a36Sopenharmony_ci netdev_rss_key_fill(&efx->rx_hash_key, 165062306a36Sopenharmony_ci sizeof(efx->rx_hash_key)); 165162306a36Sopenharmony_ci ef4_set_default_rx_indir_table(efx); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); 165462306a36Sopenharmony_ci netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci /* Initialise the interrupt moderation settings */ 165762306a36Sopenharmony_ci efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000); 165862306a36Sopenharmony_ci ef4_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true, 165962306a36Sopenharmony_ci true); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci return 0; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_cifail2: 166462306a36Sopenharmony_ci ef4_remove_interrupts(efx); 166562306a36Sopenharmony_cifail1: 166662306a36Sopenharmony_ci efx->type->remove(efx); 166762306a36Sopenharmony_ci return rc; 166862306a36Sopenharmony_ci} 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_cistatic void ef4_remove_nic(struct ef4_nic *efx) 167162306a36Sopenharmony_ci{ 167262306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "destroying NIC\n"); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci ef4_remove_interrupts(efx); 167562306a36Sopenharmony_ci efx->type->remove(efx); 167662306a36Sopenharmony_ci} 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_cistatic int ef4_probe_filters(struct ef4_nic *efx) 167962306a36Sopenharmony_ci{ 168062306a36Sopenharmony_ci int rc; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci spin_lock_init(&efx->filter_lock); 168362306a36Sopenharmony_ci init_rwsem(&efx->filter_sem); 168462306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 168562306a36Sopenharmony_ci down_write(&efx->filter_sem); 168662306a36Sopenharmony_ci rc = efx->type->filter_table_probe(efx); 168762306a36Sopenharmony_ci if (rc) 168862306a36Sopenharmony_ci goto out_unlock; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 169162306a36Sopenharmony_ci if (efx->type->offload_features & NETIF_F_NTUPLE) { 169262306a36Sopenharmony_ci struct ef4_channel *channel; 169362306a36Sopenharmony_ci int i, success = 1; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 169662306a36Sopenharmony_ci channel->rps_flow_id = 169762306a36Sopenharmony_ci kcalloc(efx->type->max_rx_ip_filters, 169862306a36Sopenharmony_ci sizeof(*channel->rps_flow_id), 169962306a36Sopenharmony_ci GFP_KERNEL); 170062306a36Sopenharmony_ci if (!channel->rps_flow_id) 170162306a36Sopenharmony_ci success = 0; 170262306a36Sopenharmony_ci else 170362306a36Sopenharmony_ci for (i = 0; 170462306a36Sopenharmony_ci i < efx->type->max_rx_ip_filters; 170562306a36Sopenharmony_ci ++i) 170662306a36Sopenharmony_ci channel->rps_flow_id[i] = 170762306a36Sopenharmony_ci RPS_FLOW_ID_INVALID; 170862306a36Sopenharmony_ci } 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci if (!success) { 171162306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 171262306a36Sopenharmony_ci kfree(channel->rps_flow_id); 171362306a36Sopenharmony_ci efx->type->filter_table_remove(efx); 171462306a36Sopenharmony_ci rc = -ENOMEM; 171562306a36Sopenharmony_ci goto out_unlock; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci efx->rps_expire_index = efx->rps_expire_channel = 0; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci#endif 172162306a36Sopenharmony_ciout_unlock: 172262306a36Sopenharmony_ci up_write(&efx->filter_sem); 172362306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 172462306a36Sopenharmony_ci return rc; 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic void ef4_remove_filters(struct ef4_nic *efx) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 173062306a36Sopenharmony_ci struct ef4_channel *channel; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 173362306a36Sopenharmony_ci kfree(channel->rps_flow_id); 173462306a36Sopenharmony_ci#endif 173562306a36Sopenharmony_ci down_write(&efx->filter_sem); 173662306a36Sopenharmony_ci efx->type->filter_table_remove(efx); 173762306a36Sopenharmony_ci up_write(&efx->filter_sem); 173862306a36Sopenharmony_ci} 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_cistatic void ef4_restore_filters(struct ef4_nic *efx) 174162306a36Sopenharmony_ci{ 174262306a36Sopenharmony_ci down_read(&efx->filter_sem); 174362306a36Sopenharmony_ci efx->type->filter_table_restore(efx); 174462306a36Sopenharmony_ci up_read(&efx->filter_sem); 174562306a36Sopenharmony_ci} 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci/************************************************************************** 174862306a36Sopenharmony_ci * 174962306a36Sopenharmony_ci * NIC startup/shutdown 175062306a36Sopenharmony_ci * 175162306a36Sopenharmony_ci *************************************************************************/ 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistatic int ef4_probe_all(struct ef4_nic *efx) 175462306a36Sopenharmony_ci{ 175562306a36Sopenharmony_ci int rc; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci rc = ef4_probe_nic(efx); 175862306a36Sopenharmony_ci if (rc) { 175962306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "failed to create NIC\n"); 176062306a36Sopenharmony_ci goto fail1; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci rc = ef4_probe_port(efx); 176462306a36Sopenharmony_ci if (rc) { 176562306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "failed to create port\n"); 176662306a36Sopenharmony_ci goto fail2; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci BUILD_BUG_ON(EF4_DEFAULT_DMAQ_SIZE < EF4_RXQ_MIN_ENT); 177062306a36Sopenharmony_ci if (WARN_ON(EF4_DEFAULT_DMAQ_SIZE < EF4_TXQ_MIN_ENT(efx))) { 177162306a36Sopenharmony_ci rc = -EINVAL; 177262306a36Sopenharmony_ci goto fail3; 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci efx->rxq_entries = efx->txq_entries = EF4_DEFAULT_DMAQ_SIZE; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci rc = ef4_probe_filters(efx); 177762306a36Sopenharmony_ci if (rc) { 177862306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 177962306a36Sopenharmony_ci "failed to create filter tables\n"); 178062306a36Sopenharmony_ci goto fail4; 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci rc = ef4_probe_channels(efx); 178462306a36Sopenharmony_ci if (rc) 178562306a36Sopenharmony_ci goto fail5; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci return 0; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci fail5: 179062306a36Sopenharmony_ci ef4_remove_filters(efx); 179162306a36Sopenharmony_ci fail4: 179262306a36Sopenharmony_ci fail3: 179362306a36Sopenharmony_ci ef4_remove_port(efx); 179462306a36Sopenharmony_ci fail2: 179562306a36Sopenharmony_ci ef4_remove_nic(efx); 179662306a36Sopenharmony_ci fail1: 179762306a36Sopenharmony_ci return rc; 179862306a36Sopenharmony_ci} 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci/* If the interface is supposed to be running but is not, start 180162306a36Sopenharmony_ci * the hardware and software data path, regular activity for the port 180262306a36Sopenharmony_ci * (MAC statistics, link polling, etc.) and schedule the port to be 180362306a36Sopenharmony_ci * reconfigured. Interrupts must already be enabled. This function 180462306a36Sopenharmony_ci * is safe to call multiple times, so long as the NIC is not disabled. 180562306a36Sopenharmony_ci * Requires the RTNL lock. 180662306a36Sopenharmony_ci */ 180762306a36Sopenharmony_cistatic void ef4_start_all(struct ef4_nic *efx) 180862306a36Sopenharmony_ci{ 180962306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 181062306a36Sopenharmony_ci BUG_ON(efx->state == STATE_DISABLED); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci /* Check that it is appropriate to restart the interface. All 181362306a36Sopenharmony_ci * of these flags are safe to read under just the rtnl lock */ 181462306a36Sopenharmony_ci if (efx->port_enabled || !netif_running(efx->net_dev) || 181562306a36Sopenharmony_ci efx->reset_pending) 181662306a36Sopenharmony_ci return; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci ef4_start_port(efx); 181962306a36Sopenharmony_ci ef4_start_datapath(efx); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci /* Start the hardware monitor if there is one */ 182262306a36Sopenharmony_ci if (efx->type->monitor != NULL) 182362306a36Sopenharmony_ci queue_delayed_work(efx->workqueue, &efx->monitor_work, 182462306a36Sopenharmony_ci ef4_monitor_interval); 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci efx->type->start_stats(efx); 182762306a36Sopenharmony_ci efx->type->pull_stats(efx); 182862306a36Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 182962306a36Sopenharmony_ci efx->type->update_stats(efx, NULL, NULL); 183062306a36Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci/* Quiesce the hardware and software data path, and regular activity 183462306a36Sopenharmony_ci * for the port without bringing the link down. Safe to call multiple 183562306a36Sopenharmony_ci * times with the NIC in almost any state, but interrupts should be 183662306a36Sopenharmony_ci * enabled. Requires the RTNL lock. 183762306a36Sopenharmony_ci */ 183862306a36Sopenharmony_cistatic void ef4_stop_all(struct ef4_nic *efx) 183962306a36Sopenharmony_ci{ 184062306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* port_enabled can be read safely under the rtnl lock */ 184362306a36Sopenharmony_ci if (!efx->port_enabled) 184462306a36Sopenharmony_ci return; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci /* update stats before we go down so we can accurately count 184762306a36Sopenharmony_ci * rx_nodesc_drops 184862306a36Sopenharmony_ci */ 184962306a36Sopenharmony_ci efx->type->pull_stats(efx); 185062306a36Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 185162306a36Sopenharmony_ci efx->type->update_stats(efx, NULL, NULL); 185262306a36Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 185362306a36Sopenharmony_ci efx->type->stop_stats(efx); 185462306a36Sopenharmony_ci ef4_stop_port(efx); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci /* Stop the kernel transmit interface. This is only valid if 185762306a36Sopenharmony_ci * the device is stopped or detached; otherwise the watchdog 185862306a36Sopenharmony_ci * may fire immediately. 185962306a36Sopenharmony_ci */ 186062306a36Sopenharmony_ci WARN_ON(netif_running(efx->net_dev) && 186162306a36Sopenharmony_ci netif_device_present(efx->net_dev)); 186262306a36Sopenharmony_ci netif_tx_disable(efx->net_dev); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci ef4_stop_datapath(efx); 186562306a36Sopenharmony_ci} 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_cistatic void ef4_remove_all(struct ef4_nic *efx) 186862306a36Sopenharmony_ci{ 186962306a36Sopenharmony_ci ef4_remove_channels(efx); 187062306a36Sopenharmony_ci ef4_remove_filters(efx); 187162306a36Sopenharmony_ci ef4_remove_port(efx); 187262306a36Sopenharmony_ci ef4_remove_nic(efx); 187362306a36Sopenharmony_ci} 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci/************************************************************************** 187662306a36Sopenharmony_ci * 187762306a36Sopenharmony_ci * Interrupt moderation 187862306a36Sopenharmony_ci * 187962306a36Sopenharmony_ci **************************************************************************/ 188062306a36Sopenharmony_ciunsigned int ef4_usecs_to_ticks(struct ef4_nic *efx, unsigned int usecs) 188162306a36Sopenharmony_ci{ 188262306a36Sopenharmony_ci if (usecs == 0) 188362306a36Sopenharmony_ci return 0; 188462306a36Sopenharmony_ci if (usecs * 1000 < efx->timer_quantum_ns) 188562306a36Sopenharmony_ci return 1; /* never round down to 0 */ 188662306a36Sopenharmony_ci return usecs * 1000 / efx->timer_quantum_ns; 188762306a36Sopenharmony_ci} 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ciunsigned int ef4_ticks_to_usecs(struct ef4_nic *efx, unsigned int ticks) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci /* We must round up when converting ticks to microseconds 189262306a36Sopenharmony_ci * because we round down when converting the other way. 189362306a36Sopenharmony_ci */ 189462306a36Sopenharmony_ci return DIV_ROUND_UP(ticks * efx->timer_quantum_ns, 1000); 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci/* Set interrupt moderation parameters */ 189862306a36Sopenharmony_ciint ef4_init_irq_moderation(struct ef4_nic *efx, unsigned int tx_usecs, 189962306a36Sopenharmony_ci unsigned int rx_usecs, bool rx_adaptive, 190062306a36Sopenharmony_ci bool rx_may_override_tx) 190162306a36Sopenharmony_ci{ 190262306a36Sopenharmony_ci struct ef4_channel *channel; 190362306a36Sopenharmony_ci unsigned int timer_max_us; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci timer_max_us = efx->timer_max_ns / 1000; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci if (tx_usecs > timer_max_us || rx_usecs > timer_max_us) 191062306a36Sopenharmony_ci return -EINVAL; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci if (tx_usecs != rx_usecs && efx->tx_channel_offset == 0 && 191362306a36Sopenharmony_ci !rx_may_override_tx) { 191462306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "Channels are shared. " 191562306a36Sopenharmony_ci "RX and TX IRQ moderation must be equal\n"); 191662306a36Sopenharmony_ci return -EINVAL; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci efx->irq_rx_adaptive = rx_adaptive; 192062306a36Sopenharmony_ci efx->irq_rx_moderation_us = rx_usecs; 192162306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 192262306a36Sopenharmony_ci if (ef4_channel_has_rx_queue(channel)) 192362306a36Sopenharmony_ci channel->irq_moderation_us = rx_usecs; 192462306a36Sopenharmony_ci else if (ef4_channel_has_tx_queues(channel)) 192562306a36Sopenharmony_ci channel->irq_moderation_us = tx_usecs; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci return 0; 192962306a36Sopenharmony_ci} 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_civoid ef4_get_irq_moderation(struct ef4_nic *efx, unsigned int *tx_usecs, 193262306a36Sopenharmony_ci unsigned int *rx_usecs, bool *rx_adaptive) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci *rx_adaptive = efx->irq_rx_adaptive; 193562306a36Sopenharmony_ci *rx_usecs = efx->irq_rx_moderation_us; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci /* If channels are shared between RX and TX, so is IRQ 193862306a36Sopenharmony_ci * moderation. Otherwise, IRQ moderation is the same for all 193962306a36Sopenharmony_ci * TX channels and is not adaptive. 194062306a36Sopenharmony_ci */ 194162306a36Sopenharmony_ci if (efx->tx_channel_offset == 0) { 194262306a36Sopenharmony_ci *tx_usecs = *rx_usecs; 194362306a36Sopenharmony_ci } else { 194462306a36Sopenharmony_ci struct ef4_channel *tx_channel; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci tx_channel = efx->channel[efx->tx_channel_offset]; 194762306a36Sopenharmony_ci *tx_usecs = tx_channel->irq_moderation_us; 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci} 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci/************************************************************************** 195262306a36Sopenharmony_ci * 195362306a36Sopenharmony_ci * Hardware monitor 195462306a36Sopenharmony_ci * 195562306a36Sopenharmony_ci **************************************************************************/ 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci/* Run periodically off the general workqueue */ 195862306a36Sopenharmony_cistatic void ef4_monitor(struct work_struct *data) 195962306a36Sopenharmony_ci{ 196062306a36Sopenharmony_ci struct ef4_nic *efx = container_of(data, struct ef4_nic, 196162306a36Sopenharmony_ci monitor_work.work); 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci netif_vdbg(efx, timer, efx->net_dev, 196462306a36Sopenharmony_ci "hardware monitor executing on CPU %d\n", 196562306a36Sopenharmony_ci raw_smp_processor_id()); 196662306a36Sopenharmony_ci BUG_ON(efx->type->monitor == NULL); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci /* If the mac_lock is already held then it is likely a port 196962306a36Sopenharmony_ci * reconfiguration is already in place, which will likely do 197062306a36Sopenharmony_ci * most of the work of monitor() anyway. */ 197162306a36Sopenharmony_ci if (mutex_trylock(&efx->mac_lock)) { 197262306a36Sopenharmony_ci if (efx->port_enabled) 197362306a36Sopenharmony_ci efx->type->monitor(efx); 197462306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci queue_delayed_work(efx->workqueue, &efx->monitor_work, 197862306a36Sopenharmony_ci ef4_monitor_interval); 197962306a36Sopenharmony_ci} 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci/************************************************************************** 198262306a36Sopenharmony_ci * 198362306a36Sopenharmony_ci * ioctls 198462306a36Sopenharmony_ci * 198562306a36Sopenharmony_ci *************************************************************************/ 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci/* Net device ioctl 198862306a36Sopenharmony_ci * Context: process, rtnl_lock() held. 198962306a36Sopenharmony_ci */ 199062306a36Sopenharmony_cistatic int ef4_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) 199162306a36Sopenharmony_ci{ 199262306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 199362306a36Sopenharmony_ci struct mii_ioctl_data *data = if_mii(ifr); 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci /* Convert phy_id from older PRTAD/DEVAD format */ 199662306a36Sopenharmony_ci if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && 199762306a36Sopenharmony_ci (data->phy_id & 0xfc00) == 0x0400) 199862306a36Sopenharmony_ci data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci return mdio_mii_ioctl(&efx->mdio, data, cmd); 200162306a36Sopenharmony_ci} 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci/************************************************************************** 200462306a36Sopenharmony_ci * 200562306a36Sopenharmony_ci * NAPI interface 200662306a36Sopenharmony_ci * 200762306a36Sopenharmony_ci **************************************************************************/ 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_cistatic void ef4_init_napi_channel(struct ef4_channel *channel) 201062306a36Sopenharmony_ci{ 201162306a36Sopenharmony_ci struct ef4_nic *efx = channel->efx; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci channel->napi_dev = efx->net_dev; 201462306a36Sopenharmony_ci netif_napi_add(channel->napi_dev, &channel->napi_str, ef4_poll); 201562306a36Sopenharmony_ci} 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_cistatic void ef4_init_napi(struct ef4_nic *efx) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci struct ef4_channel *channel; 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 202262306a36Sopenharmony_ci ef4_init_napi_channel(channel); 202362306a36Sopenharmony_ci} 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_cistatic void ef4_fini_napi_channel(struct ef4_channel *channel) 202662306a36Sopenharmony_ci{ 202762306a36Sopenharmony_ci if (channel->napi_dev) 202862306a36Sopenharmony_ci netif_napi_del(&channel->napi_str); 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci channel->napi_dev = NULL; 203162306a36Sopenharmony_ci} 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_cistatic void ef4_fini_napi(struct ef4_nic *efx) 203462306a36Sopenharmony_ci{ 203562306a36Sopenharmony_ci struct ef4_channel *channel; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 203862306a36Sopenharmony_ci ef4_fini_napi_channel(channel); 203962306a36Sopenharmony_ci} 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci/************************************************************************** 204262306a36Sopenharmony_ci * 204362306a36Sopenharmony_ci * Kernel net device interface 204462306a36Sopenharmony_ci * 204562306a36Sopenharmony_ci *************************************************************************/ 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. */ 204862306a36Sopenharmony_ciint ef4_net_open(struct net_device *net_dev) 204962306a36Sopenharmony_ci{ 205062306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 205162306a36Sopenharmony_ci int rc; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci netif_dbg(efx, ifup, efx->net_dev, "opening device on CPU %d\n", 205462306a36Sopenharmony_ci raw_smp_processor_id()); 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci rc = ef4_check_disabled(efx); 205762306a36Sopenharmony_ci if (rc) 205862306a36Sopenharmony_ci return rc; 205962306a36Sopenharmony_ci if (efx->phy_mode & PHY_MODE_SPECIAL) 206062306a36Sopenharmony_ci return -EBUSY; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci /* Notify the kernel of the link state polled during driver load, 206362306a36Sopenharmony_ci * before the monitor starts running */ 206462306a36Sopenharmony_ci ef4_link_status_changed(efx); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci ef4_start_all(efx); 206762306a36Sopenharmony_ci ef4_selftest_async_start(efx); 206862306a36Sopenharmony_ci return 0; 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. 207262306a36Sopenharmony_ci * Note that the kernel will ignore our return code; this method 207362306a36Sopenharmony_ci * should really be a void. 207462306a36Sopenharmony_ci */ 207562306a36Sopenharmony_ciint ef4_net_stop(struct net_device *net_dev) 207662306a36Sopenharmony_ci{ 207762306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n", 208062306a36Sopenharmony_ci raw_smp_processor_id()); 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci /* Stop the device and flush all the channels */ 208362306a36Sopenharmony_ci ef4_stop_all(efx); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci return 0; 208662306a36Sopenharmony_ci} 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci/* Context: process, dev_base_lock or RTNL held, non-blocking. */ 208962306a36Sopenharmony_cistatic void ef4_net_stats(struct net_device *net_dev, 209062306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 209162306a36Sopenharmony_ci{ 209262306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci spin_lock_bh(&efx->stats_lock); 209562306a36Sopenharmony_ci efx->type->update_stats(efx, NULL, stats); 209662306a36Sopenharmony_ci spin_unlock_bh(&efx->stats_lock); 209762306a36Sopenharmony_ci} 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci/* Context: netif_tx_lock held, BHs disabled. */ 210062306a36Sopenharmony_cistatic void ef4_watchdog(struct net_device *net_dev, unsigned int txqueue) 210162306a36Sopenharmony_ci{ 210262306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci netif_err(efx, tx_err, efx->net_dev, 210562306a36Sopenharmony_ci "TX stuck with port_enabled=%d: resetting channels\n", 210662306a36Sopenharmony_ci efx->port_enabled); 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci ef4_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG); 210962306a36Sopenharmony_ci} 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. */ 211362306a36Sopenharmony_cistatic int ef4_change_mtu(struct net_device *net_dev, int new_mtu) 211462306a36Sopenharmony_ci{ 211562306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 211662306a36Sopenharmony_ci int rc; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci rc = ef4_check_disabled(efx); 211962306a36Sopenharmony_ci if (rc) 212062306a36Sopenharmony_ci return rc; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu); 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci ef4_device_detach_sync(efx); 212562306a36Sopenharmony_ci ef4_stop_all(efx); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 212862306a36Sopenharmony_ci net_dev->mtu = new_mtu; 212962306a36Sopenharmony_ci ef4_mac_reconfigure(efx); 213062306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci ef4_start_all(efx); 213362306a36Sopenharmony_ci netif_device_attach(efx->net_dev); 213462306a36Sopenharmony_ci return 0; 213562306a36Sopenharmony_ci} 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_cistatic int ef4_set_mac_address(struct net_device *net_dev, void *data) 213862306a36Sopenharmony_ci{ 213962306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 214062306a36Sopenharmony_ci struct sockaddr *addr = data; 214162306a36Sopenharmony_ci u8 *new_addr = addr->sa_data; 214262306a36Sopenharmony_ci u8 old_addr[6]; 214362306a36Sopenharmony_ci int rc; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (!is_valid_ether_addr(new_addr)) { 214662306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 214762306a36Sopenharmony_ci "invalid ethernet MAC address requested: %pM\n", 214862306a36Sopenharmony_ci new_addr); 214962306a36Sopenharmony_ci return -EADDRNOTAVAIL; 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci /* save old address */ 215362306a36Sopenharmony_ci ether_addr_copy(old_addr, net_dev->dev_addr); 215462306a36Sopenharmony_ci eth_hw_addr_set(net_dev, new_addr); 215562306a36Sopenharmony_ci if (efx->type->set_mac_address) { 215662306a36Sopenharmony_ci rc = efx->type->set_mac_address(efx); 215762306a36Sopenharmony_ci if (rc) { 215862306a36Sopenharmony_ci eth_hw_addr_set(net_dev, old_addr); 215962306a36Sopenharmony_ci return rc; 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci } 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci /* Reconfigure the MAC */ 216462306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 216562306a36Sopenharmony_ci ef4_mac_reconfigure(efx); 216662306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci return 0; 216962306a36Sopenharmony_ci} 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci/* Context: netif_addr_lock held, BHs disabled. */ 217262306a36Sopenharmony_cistatic void ef4_set_rx_mode(struct net_device *net_dev) 217362306a36Sopenharmony_ci{ 217462306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci if (efx->port_enabled) 217762306a36Sopenharmony_ci queue_work(efx->workqueue, &efx->mac_work); 217862306a36Sopenharmony_ci /* Otherwise ef4_start_port() will do this */ 217962306a36Sopenharmony_ci} 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_cistatic int ef4_set_features(struct net_device *net_dev, netdev_features_t data) 218262306a36Sopenharmony_ci{ 218362306a36Sopenharmony_ci struct ef4_nic *efx = netdev_priv(net_dev); 218462306a36Sopenharmony_ci int rc; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci /* If disabling RX n-tuple filtering, clear existing filters */ 218762306a36Sopenharmony_ci if (net_dev->features & ~data & NETIF_F_NTUPLE) { 218862306a36Sopenharmony_ci rc = efx->type->filter_clear_rx(efx, EF4_FILTER_PRI_MANUAL); 218962306a36Sopenharmony_ci if (rc) 219062306a36Sopenharmony_ci return rc; 219162306a36Sopenharmony_ci } 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci /* If Rx VLAN filter is changed, update filters via mac_reconfigure */ 219462306a36Sopenharmony_ci if ((net_dev->features ^ data) & NETIF_F_HW_VLAN_CTAG_FILTER) { 219562306a36Sopenharmony_ci /* ef4_set_rx_mode() will schedule MAC work to update filters 219662306a36Sopenharmony_ci * when a new features are finally set in net_dev. 219762306a36Sopenharmony_ci */ 219862306a36Sopenharmony_ci ef4_set_rx_mode(net_dev); 219962306a36Sopenharmony_ci } 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci return 0; 220262306a36Sopenharmony_ci} 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_cistatic const struct net_device_ops ef4_netdev_ops = { 220562306a36Sopenharmony_ci .ndo_open = ef4_net_open, 220662306a36Sopenharmony_ci .ndo_stop = ef4_net_stop, 220762306a36Sopenharmony_ci .ndo_get_stats64 = ef4_net_stats, 220862306a36Sopenharmony_ci .ndo_tx_timeout = ef4_watchdog, 220962306a36Sopenharmony_ci .ndo_start_xmit = ef4_hard_start_xmit, 221062306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 221162306a36Sopenharmony_ci .ndo_eth_ioctl = ef4_ioctl, 221262306a36Sopenharmony_ci .ndo_change_mtu = ef4_change_mtu, 221362306a36Sopenharmony_ci .ndo_set_mac_address = ef4_set_mac_address, 221462306a36Sopenharmony_ci .ndo_set_rx_mode = ef4_set_rx_mode, 221562306a36Sopenharmony_ci .ndo_set_features = ef4_set_features, 221662306a36Sopenharmony_ci .ndo_setup_tc = ef4_setup_tc, 221762306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 221862306a36Sopenharmony_ci .ndo_rx_flow_steer = ef4_filter_rfs, 221962306a36Sopenharmony_ci#endif 222062306a36Sopenharmony_ci}; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_cistatic void ef4_update_name(struct ef4_nic *efx) 222362306a36Sopenharmony_ci{ 222462306a36Sopenharmony_ci strcpy(efx->name, efx->net_dev->name); 222562306a36Sopenharmony_ci ef4_mtd_rename(efx); 222662306a36Sopenharmony_ci ef4_set_channel_names(efx); 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_cistatic int ef4_netdev_event(struct notifier_block *this, 223062306a36Sopenharmony_ci unsigned long event, void *ptr) 223162306a36Sopenharmony_ci{ 223262306a36Sopenharmony_ci struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci if ((net_dev->netdev_ops == &ef4_netdev_ops) && 223562306a36Sopenharmony_ci event == NETDEV_CHANGENAME) 223662306a36Sopenharmony_ci ef4_update_name(netdev_priv(net_dev)); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci return NOTIFY_DONE; 223962306a36Sopenharmony_ci} 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_cistatic struct notifier_block ef4_netdev_notifier = { 224262306a36Sopenharmony_ci .notifier_call = ef4_netdev_event, 224362306a36Sopenharmony_ci}; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_cistatic ssize_t 224662306a36Sopenharmony_ciphy_type_show(struct device *dev, struct device_attribute *attr, char *buf) 224762306a36Sopenharmony_ci{ 224862306a36Sopenharmony_ci struct ef4_nic *efx = dev_get_drvdata(dev); 224962306a36Sopenharmony_ci return sprintf(buf, "%d\n", efx->phy_type); 225062306a36Sopenharmony_ci} 225162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(phy_type); 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_cistatic int ef4_register_netdev(struct ef4_nic *efx) 225462306a36Sopenharmony_ci{ 225562306a36Sopenharmony_ci struct net_device *net_dev = efx->net_dev; 225662306a36Sopenharmony_ci struct ef4_channel *channel; 225762306a36Sopenharmony_ci int rc; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci net_dev->watchdog_timeo = 5 * HZ; 226062306a36Sopenharmony_ci net_dev->irq = efx->pci_dev->irq; 226162306a36Sopenharmony_ci net_dev->netdev_ops = &ef4_netdev_ops; 226262306a36Sopenharmony_ci net_dev->ethtool_ops = &ef4_ethtool_ops; 226362306a36Sopenharmony_ci netif_set_tso_max_segs(net_dev, EF4_TSO_MAX_SEGS); 226462306a36Sopenharmony_ci net_dev->min_mtu = EF4_MIN_MTU; 226562306a36Sopenharmony_ci net_dev->max_mtu = EF4_MAX_MTU; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci rtnl_lock(); 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci /* Enable resets to be scheduled and check whether any were 227062306a36Sopenharmony_ci * already requested. If so, the NIC is probably hosed so we 227162306a36Sopenharmony_ci * abort. 227262306a36Sopenharmony_ci */ 227362306a36Sopenharmony_ci efx->state = STATE_READY; 227462306a36Sopenharmony_ci smp_mb(); /* ensure we change state before checking reset_pending */ 227562306a36Sopenharmony_ci if (efx->reset_pending) { 227662306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 227762306a36Sopenharmony_ci "aborting probe due to scheduled reset\n"); 227862306a36Sopenharmony_ci rc = -EIO; 227962306a36Sopenharmony_ci goto fail_locked; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci rc = dev_alloc_name(net_dev, net_dev->name); 228362306a36Sopenharmony_ci if (rc < 0) 228462306a36Sopenharmony_ci goto fail_locked; 228562306a36Sopenharmony_ci ef4_update_name(efx); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci /* Always start with carrier off; PHY events will detect the link */ 228862306a36Sopenharmony_ci netif_carrier_off(net_dev); 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci rc = register_netdevice(net_dev); 229162306a36Sopenharmony_ci if (rc) 229262306a36Sopenharmony_ci goto fail_locked; 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) { 229562306a36Sopenharmony_ci struct ef4_tx_queue *tx_queue; 229662306a36Sopenharmony_ci ef4_for_each_channel_tx_queue(tx_queue, channel) 229762306a36Sopenharmony_ci ef4_init_tx_queue_core_txq(tx_queue); 229862306a36Sopenharmony_ci } 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci ef4_associate(efx); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci rtnl_unlock(); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type); 230562306a36Sopenharmony_ci if (rc) { 230662306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 230762306a36Sopenharmony_ci "failed to init net dev attributes\n"); 230862306a36Sopenharmony_ci goto fail_registered; 230962306a36Sopenharmony_ci } 231062306a36Sopenharmony_ci return 0; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_cifail_registered: 231362306a36Sopenharmony_ci rtnl_lock(); 231462306a36Sopenharmony_ci ef4_dissociate(efx); 231562306a36Sopenharmony_ci unregister_netdevice(net_dev); 231662306a36Sopenharmony_cifail_locked: 231762306a36Sopenharmony_ci efx->state = STATE_UNINIT; 231862306a36Sopenharmony_ci rtnl_unlock(); 231962306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "could not register net dev\n"); 232062306a36Sopenharmony_ci return rc; 232162306a36Sopenharmony_ci} 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_cistatic void ef4_unregister_netdev(struct ef4_nic *efx) 232462306a36Sopenharmony_ci{ 232562306a36Sopenharmony_ci if (!efx->net_dev) 232662306a36Sopenharmony_ci return; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci BUG_ON(netdev_priv(efx->net_dev) != efx); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci if (ef4_dev_registered(efx)) { 233162306a36Sopenharmony_ci strscpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); 233262306a36Sopenharmony_ci device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type); 233362306a36Sopenharmony_ci unregister_netdev(efx->net_dev); 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci} 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci/************************************************************************** 233862306a36Sopenharmony_ci * 233962306a36Sopenharmony_ci * Device reset and suspend 234062306a36Sopenharmony_ci * 234162306a36Sopenharmony_ci **************************************************************************/ 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci/* Tears down the entire software state and most of the hardware state 234462306a36Sopenharmony_ci * before reset. */ 234562306a36Sopenharmony_civoid ef4_reset_down(struct ef4_nic *efx, enum reset_type method) 234662306a36Sopenharmony_ci{ 234762306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci ef4_stop_all(efx); 235062306a36Sopenharmony_ci ef4_disable_interrupts(efx); 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 235362306a36Sopenharmony_ci if (efx->port_initialized && method != RESET_TYPE_INVISIBLE && 235462306a36Sopenharmony_ci method != RESET_TYPE_DATAPATH) 235562306a36Sopenharmony_ci efx->phy_op->fini(efx); 235662306a36Sopenharmony_ci efx->type->fini(efx); 235762306a36Sopenharmony_ci} 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci/* This function will always ensure that the locks acquired in 236062306a36Sopenharmony_ci * ef4_reset_down() are released. A failure return code indicates 236162306a36Sopenharmony_ci * that we were unable to reinitialise the hardware, and the 236262306a36Sopenharmony_ci * driver should be disabled. If ok is false, then the rx and tx 236362306a36Sopenharmony_ci * engines are not restarted, pending a RESET_DISABLE. */ 236462306a36Sopenharmony_ciint ef4_reset_up(struct ef4_nic *efx, enum reset_type method, bool ok) 236562306a36Sopenharmony_ci{ 236662306a36Sopenharmony_ci int rc; 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci EF4_ASSERT_RESET_SERIALISED(efx); 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* Ensure that SRAM is initialised even if we're disabling the device */ 237162306a36Sopenharmony_ci rc = efx->type->init(efx); 237262306a36Sopenharmony_ci if (rc) { 237362306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "failed to initialise NIC\n"); 237462306a36Sopenharmony_ci goto fail; 237562306a36Sopenharmony_ci } 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci if (!ok) 237862306a36Sopenharmony_ci goto fail; 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci if (efx->port_initialized && method != RESET_TYPE_INVISIBLE && 238162306a36Sopenharmony_ci method != RESET_TYPE_DATAPATH) { 238262306a36Sopenharmony_ci rc = efx->phy_op->init(efx); 238362306a36Sopenharmony_ci if (rc) 238462306a36Sopenharmony_ci goto fail; 238562306a36Sopenharmony_ci rc = efx->phy_op->reconfigure(efx); 238662306a36Sopenharmony_ci if (rc && rc != -EPERM) 238762306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 238862306a36Sopenharmony_ci "could not restore PHY settings\n"); 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci rc = ef4_enable_interrupts(efx); 239262306a36Sopenharmony_ci if (rc) 239362306a36Sopenharmony_ci goto fail; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci down_read(&efx->filter_sem); 239662306a36Sopenharmony_ci ef4_restore_filters(efx); 239762306a36Sopenharmony_ci up_read(&efx->filter_sem); 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci ef4_start_all(efx); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci return 0; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_cifail: 240662306a36Sopenharmony_ci efx->port_initialized = false; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci return rc; 241162306a36Sopenharmony_ci} 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci/* Reset the NIC using the specified method. Note that the reset may 241462306a36Sopenharmony_ci * fail, in which case the card will be left in an unusable state. 241562306a36Sopenharmony_ci * 241662306a36Sopenharmony_ci * Caller must hold the rtnl_lock. 241762306a36Sopenharmony_ci */ 241862306a36Sopenharmony_ciint ef4_reset(struct ef4_nic *efx, enum reset_type method) 241962306a36Sopenharmony_ci{ 242062306a36Sopenharmony_ci int rc, rc2; 242162306a36Sopenharmony_ci bool disabled; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", 242462306a36Sopenharmony_ci RESET_TYPE(method)); 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci ef4_device_detach_sync(efx); 242762306a36Sopenharmony_ci ef4_reset_down(efx, method); 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci rc = efx->type->reset(efx, method); 243062306a36Sopenharmony_ci if (rc) { 243162306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "failed to reset hardware\n"); 243262306a36Sopenharmony_ci goto out; 243362306a36Sopenharmony_ci } 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci /* Clear flags for the scopes we covered. We assume the NIC and 243662306a36Sopenharmony_ci * driver are now quiescent so that there is no race here. 243762306a36Sopenharmony_ci */ 243862306a36Sopenharmony_ci if (method < RESET_TYPE_MAX_METHOD) 243962306a36Sopenharmony_ci efx->reset_pending &= -(1 << (method + 1)); 244062306a36Sopenharmony_ci else /* it doesn't fit into the well-ordered scope hierarchy */ 244162306a36Sopenharmony_ci __clear_bit(method, &efx->reset_pending); 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci /* Reinitialise bus-mastering, which may have been turned off before 244462306a36Sopenharmony_ci * the reset was scheduled. This is still appropriate, even in the 244562306a36Sopenharmony_ci * RESET_TYPE_DISABLE since this driver generally assumes the hardware 244662306a36Sopenharmony_ci * can respond to requests. */ 244762306a36Sopenharmony_ci pci_set_master(efx->pci_dev); 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ciout: 245062306a36Sopenharmony_ci /* Leave device stopped if necessary */ 245162306a36Sopenharmony_ci disabled = rc || 245262306a36Sopenharmony_ci method == RESET_TYPE_DISABLE || 245362306a36Sopenharmony_ci method == RESET_TYPE_RECOVER_OR_DISABLE; 245462306a36Sopenharmony_ci rc2 = ef4_reset_up(efx, method, !disabled); 245562306a36Sopenharmony_ci if (rc2) { 245662306a36Sopenharmony_ci disabled = true; 245762306a36Sopenharmony_ci if (!rc) 245862306a36Sopenharmony_ci rc = rc2; 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci if (disabled) { 246262306a36Sopenharmony_ci dev_close(efx->net_dev); 246362306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "has been disabled\n"); 246462306a36Sopenharmony_ci efx->state = STATE_DISABLED; 246562306a36Sopenharmony_ci } else { 246662306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "reset complete\n"); 246762306a36Sopenharmony_ci netif_device_attach(efx->net_dev); 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci return rc; 247062306a36Sopenharmony_ci} 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci/* Try recovery mechanisms. 247362306a36Sopenharmony_ci * For now only EEH is supported. 247462306a36Sopenharmony_ci * Returns 0 if the recovery mechanisms are unsuccessful. 247562306a36Sopenharmony_ci * Returns a non-zero value otherwise. 247662306a36Sopenharmony_ci */ 247762306a36Sopenharmony_ciint ef4_try_recovery(struct ef4_nic *efx) 247862306a36Sopenharmony_ci{ 247962306a36Sopenharmony_ci#ifdef CONFIG_EEH 248062306a36Sopenharmony_ci /* A PCI error can occur and not be seen by EEH because nothing 248162306a36Sopenharmony_ci * happens on the PCI bus. In this case the driver may fail and 248262306a36Sopenharmony_ci * schedule a 'recover or reset', leading to this recovery handler. 248362306a36Sopenharmony_ci * Manually call the eeh failure check function. 248462306a36Sopenharmony_ci */ 248562306a36Sopenharmony_ci struct eeh_dev *eehdev = pci_dev_to_eeh_dev(efx->pci_dev); 248662306a36Sopenharmony_ci if (eeh_dev_check_failure(eehdev)) { 248762306a36Sopenharmony_ci /* The EEH mechanisms will handle the error and reset the 248862306a36Sopenharmony_ci * device if necessary. 248962306a36Sopenharmony_ci */ 249062306a36Sopenharmony_ci return 1; 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci#endif 249362306a36Sopenharmony_ci return 0; 249462306a36Sopenharmony_ci} 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci/* The worker thread exists so that code that cannot sleep can 249762306a36Sopenharmony_ci * schedule a reset for later. 249862306a36Sopenharmony_ci */ 249962306a36Sopenharmony_cistatic void ef4_reset_work(struct work_struct *data) 250062306a36Sopenharmony_ci{ 250162306a36Sopenharmony_ci struct ef4_nic *efx = container_of(data, struct ef4_nic, reset_work); 250262306a36Sopenharmony_ci unsigned long pending; 250362306a36Sopenharmony_ci enum reset_type method; 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci pending = READ_ONCE(efx->reset_pending); 250662306a36Sopenharmony_ci method = fls(pending) - 1; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci if ((method == RESET_TYPE_RECOVER_OR_DISABLE || 250962306a36Sopenharmony_ci method == RESET_TYPE_RECOVER_OR_ALL) && 251062306a36Sopenharmony_ci ef4_try_recovery(efx)) 251162306a36Sopenharmony_ci return; 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci if (!pending) 251462306a36Sopenharmony_ci return; 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci rtnl_lock(); 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci /* We checked the state in ef4_schedule_reset() but it may 251962306a36Sopenharmony_ci * have changed by now. Now that we have the RTNL lock, 252062306a36Sopenharmony_ci * it cannot change again. 252162306a36Sopenharmony_ci */ 252262306a36Sopenharmony_ci if (efx->state == STATE_READY) 252362306a36Sopenharmony_ci (void)ef4_reset(efx, method); 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci rtnl_unlock(); 252662306a36Sopenharmony_ci} 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_civoid ef4_schedule_reset(struct ef4_nic *efx, enum reset_type type) 252962306a36Sopenharmony_ci{ 253062306a36Sopenharmony_ci enum reset_type method; 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci if (efx->state == STATE_RECOVERY) { 253362306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 253462306a36Sopenharmony_ci "recovering: skip scheduling %s reset\n", 253562306a36Sopenharmony_ci RESET_TYPE(type)); 253662306a36Sopenharmony_ci return; 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci switch (type) { 254062306a36Sopenharmony_ci case RESET_TYPE_INVISIBLE: 254162306a36Sopenharmony_ci case RESET_TYPE_ALL: 254262306a36Sopenharmony_ci case RESET_TYPE_RECOVER_OR_ALL: 254362306a36Sopenharmony_ci case RESET_TYPE_WORLD: 254462306a36Sopenharmony_ci case RESET_TYPE_DISABLE: 254562306a36Sopenharmony_ci case RESET_TYPE_RECOVER_OR_DISABLE: 254662306a36Sopenharmony_ci case RESET_TYPE_DATAPATH: 254762306a36Sopenharmony_ci method = type; 254862306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n", 254962306a36Sopenharmony_ci RESET_TYPE(method)); 255062306a36Sopenharmony_ci break; 255162306a36Sopenharmony_ci default: 255262306a36Sopenharmony_ci method = efx->type->map_reset_reason(type); 255362306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 255462306a36Sopenharmony_ci "scheduling %s reset for %s\n", 255562306a36Sopenharmony_ci RESET_TYPE(method), RESET_TYPE(type)); 255662306a36Sopenharmony_ci break; 255762306a36Sopenharmony_ci } 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci set_bit(method, &efx->reset_pending); 256062306a36Sopenharmony_ci smp_mb(); /* ensure we change reset_pending before checking state */ 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci /* If we're not READY then just leave the flags set as the cue 256362306a36Sopenharmony_ci * to abort probing or reschedule the reset later. 256462306a36Sopenharmony_ci */ 256562306a36Sopenharmony_ci if (READ_ONCE(efx->state) != STATE_READY) 256662306a36Sopenharmony_ci return; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci queue_work(reset_workqueue, &efx->reset_work); 256962306a36Sopenharmony_ci} 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci/************************************************************************** 257262306a36Sopenharmony_ci * 257362306a36Sopenharmony_ci * List of NICs we support 257462306a36Sopenharmony_ci * 257562306a36Sopenharmony_ci **************************************************************************/ 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci/* PCI device ID table */ 257862306a36Sopenharmony_cistatic const struct pci_device_id ef4_pci_table[] = { 257962306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 258062306a36Sopenharmony_ci PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0), 258162306a36Sopenharmony_ci .driver_data = (unsigned long) &falcon_a1_nic_type}, 258262306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 258362306a36Sopenharmony_ci PCI_DEVICE_ID_SOLARFLARE_SFC4000B), 258462306a36Sopenharmony_ci .driver_data = (unsigned long) &falcon_b0_nic_type}, 258562306a36Sopenharmony_ci {0} /* end of list */ 258662306a36Sopenharmony_ci}; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci/************************************************************************** 258962306a36Sopenharmony_ci * 259062306a36Sopenharmony_ci * Dummy PHY/MAC operations 259162306a36Sopenharmony_ci * 259262306a36Sopenharmony_ci * Can be used for some unimplemented operations 259362306a36Sopenharmony_ci * Needed so all function pointers are valid and do not have to be tested 259462306a36Sopenharmony_ci * before use 259562306a36Sopenharmony_ci * 259662306a36Sopenharmony_ci **************************************************************************/ 259762306a36Sopenharmony_ciint ef4_port_dummy_op_int(struct ef4_nic *efx) 259862306a36Sopenharmony_ci{ 259962306a36Sopenharmony_ci return 0; 260062306a36Sopenharmony_ci} 260162306a36Sopenharmony_civoid ef4_port_dummy_op_void(struct ef4_nic *efx) {} 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_cistatic bool ef4_port_dummy_op_poll(struct ef4_nic *efx) 260462306a36Sopenharmony_ci{ 260562306a36Sopenharmony_ci return false; 260662306a36Sopenharmony_ci} 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_cistatic const struct ef4_phy_operations ef4_dummy_phy_operations = { 260962306a36Sopenharmony_ci .init = ef4_port_dummy_op_int, 261062306a36Sopenharmony_ci .reconfigure = ef4_port_dummy_op_int, 261162306a36Sopenharmony_ci .poll = ef4_port_dummy_op_poll, 261262306a36Sopenharmony_ci .fini = ef4_port_dummy_op_void, 261362306a36Sopenharmony_ci}; 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci/************************************************************************** 261662306a36Sopenharmony_ci * 261762306a36Sopenharmony_ci * Data housekeeping 261862306a36Sopenharmony_ci * 261962306a36Sopenharmony_ci **************************************************************************/ 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci/* This zeroes out and then fills in the invariants in a struct 262262306a36Sopenharmony_ci * ef4_nic (including all sub-structures). 262362306a36Sopenharmony_ci */ 262462306a36Sopenharmony_cistatic int ef4_init_struct(struct ef4_nic *efx, 262562306a36Sopenharmony_ci struct pci_dev *pci_dev, struct net_device *net_dev) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci int i; 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci /* Initialise common structures */ 263062306a36Sopenharmony_ci INIT_LIST_HEAD(&efx->node); 263162306a36Sopenharmony_ci INIT_LIST_HEAD(&efx->secondary_list); 263262306a36Sopenharmony_ci spin_lock_init(&efx->biu_lock); 263362306a36Sopenharmony_ci#ifdef CONFIG_SFC_FALCON_MTD 263462306a36Sopenharmony_ci INIT_LIST_HEAD(&efx->mtd_list); 263562306a36Sopenharmony_ci#endif 263662306a36Sopenharmony_ci INIT_WORK(&efx->reset_work, ef4_reset_work); 263762306a36Sopenharmony_ci INIT_DELAYED_WORK(&efx->monitor_work, ef4_monitor); 263862306a36Sopenharmony_ci INIT_DELAYED_WORK(&efx->selftest_work, ef4_selftest_async_work); 263962306a36Sopenharmony_ci efx->pci_dev = pci_dev; 264062306a36Sopenharmony_ci efx->msg_enable = debug; 264162306a36Sopenharmony_ci efx->state = STATE_UNINIT; 264262306a36Sopenharmony_ci strscpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_ci efx->net_dev = net_dev; 264562306a36Sopenharmony_ci efx->rx_prefix_size = efx->type->rx_prefix_size; 264662306a36Sopenharmony_ci efx->rx_ip_align = 264762306a36Sopenharmony_ci NET_IP_ALIGN ? (efx->rx_prefix_size + NET_IP_ALIGN) % 4 : 0; 264862306a36Sopenharmony_ci efx->rx_packet_hash_offset = 264962306a36Sopenharmony_ci efx->type->rx_hash_offset - efx->type->rx_prefix_size; 265062306a36Sopenharmony_ci efx->rx_packet_ts_offset = 265162306a36Sopenharmony_ci efx->type->rx_ts_offset - efx->type->rx_prefix_size; 265262306a36Sopenharmony_ci spin_lock_init(&efx->stats_lock); 265362306a36Sopenharmony_ci mutex_init(&efx->mac_lock); 265462306a36Sopenharmony_ci efx->phy_op = &ef4_dummy_phy_operations; 265562306a36Sopenharmony_ci efx->mdio.dev = net_dev; 265662306a36Sopenharmony_ci INIT_WORK(&efx->mac_work, ef4_mac_work); 265762306a36Sopenharmony_ci init_waitqueue_head(&efx->flush_wq); 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci for (i = 0; i < EF4_MAX_CHANNELS; i++) { 266062306a36Sopenharmony_ci efx->channel[i] = ef4_alloc_channel(efx, i, NULL); 266162306a36Sopenharmony_ci if (!efx->channel[i]) 266262306a36Sopenharmony_ci goto fail; 266362306a36Sopenharmony_ci efx->msi_context[i].efx = efx; 266462306a36Sopenharmony_ci efx->msi_context[i].index = i; 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci /* Higher numbered interrupt modes are less capable! */ 266862306a36Sopenharmony_ci efx->interrupt_mode = max(efx->type->max_interrupt_mode, 266962306a36Sopenharmony_ci interrupt_mode); 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci /* Would be good to use the net_dev name, but we're too early */ 267262306a36Sopenharmony_ci snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s", 267362306a36Sopenharmony_ci pci_name(pci_dev)); 267462306a36Sopenharmony_ci efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); 267562306a36Sopenharmony_ci if (!efx->workqueue) 267662306a36Sopenharmony_ci goto fail; 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci return 0; 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_cifail: 268162306a36Sopenharmony_ci ef4_fini_struct(efx); 268262306a36Sopenharmony_ci return -ENOMEM; 268362306a36Sopenharmony_ci} 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_cistatic void ef4_fini_struct(struct ef4_nic *efx) 268662306a36Sopenharmony_ci{ 268762306a36Sopenharmony_ci int i; 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci for (i = 0; i < EF4_MAX_CHANNELS; i++) 269062306a36Sopenharmony_ci kfree(efx->channel[i]); 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci kfree(efx->vpd_sn); 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci if (efx->workqueue) { 269562306a36Sopenharmony_ci destroy_workqueue(efx->workqueue); 269662306a36Sopenharmony_ci efx->workqueue = NULL; 269762306a36Sopenharmony_ci } 269862306a36Sopenharmony_ci} 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_civoid ef4_update_sw_stats(struct ef4_nic *efx, u64 *stats) 270162306a36Sopenharmony_ci{ 270262306a36Sopenharmony_ci u64 n_rx_nodesc_trunc = 0; 270362306a36Sopenharmony_ci struct ef4_channel *channel; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci ef4_for_each_channel(channel, efx) 270662306a36Sopenharmony_ci n_rx_nodesc_trunc += channel->n_rx_nodesc_trunc; 270762306a36Sopenharmony_ci stats[GENERIC_STAT_rx_nodesc_trunc] = n_rx_nodesc_trunc; 270862306a36Sopenharmony_ci stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops); 270962306a36Sopenharmony_ci} 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci/************************************************************************** 271262306a36Sopenharmony_ci * 271362306a36Sopenharmony_ci * PCI interface 271462306a36Sopenharmony_ci * 271562306a36Sopenharmony_ci **************************************************************************/ 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci/* Main body of final NIC shutdown code 271862306a36Sopenharmony_ci * This is called only at module unload (or hotplug removal). 271962306a36Sopenharmony_ci */ 272062306a36Sopenharmony_cistatic void ef4_pci_remove_main(struct ef4_nic *efx) 272162306a36Sopenharmony_ci{ 272262306a36Sopenharmony_ci /* Flush reset_work. It can no longer be scheduled since we 272362306a36Sopenharmony_ci * are not READY. 272462306a36Sopenharmony_ci */ 272562306a36Sopenharmony_ci BUG_ON(efx->state == STATE_READY); 272662306a36Sopenharmony_ci cancel_work_sync(&efx->reset_work); 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci ef4_disable_interrupts(efx); 272962306a36Sopenharmony_ci ef4_nic_fini_interrupt(efx); 273062306a36Sopenharmony_ci ef4_fini_port(efx); 273162306a36Sopenharmony_ci efx->type->fini(efx); 273262306a36Sopenharmony_ci ef4_fini_napi(efx); 273362306a36Sopenharmony_ci ef4_remove_all(efx); 273462306a36Sopenharmony_ci} 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci/* Final NIC shutdown 273762306a36Sopenharmony_ci * This is called only at module unload (or hotplug removal). A PF can call 273862306a36Sopenharmony_ci * this on its VFs to ensure they are unbound first. 273962306a36Sopenharmony_ci */ 274062306a36Sopenharmony_cistatic void ef4_pci_remove(struct pci_dev *pci_dev) 274162306a36Sopenharmony_ci{ 274262306a36Sopenharmony_ci struct ef4_nic *efx; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci efx = pci_get_drvdata(pci_dev); 274562306a36Sopenharmony_ci if (!efx) 274662306a36Sopenharmony_ci return; 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci /* Mark the NIC as fini, then stop the interface */ 274962306a36Sopenharmony_ci rtnl_lock(); 275062306a36Sopenharmony_ci ef4_dissociate(efx); 275162306a36Sopenharmony_ci dev_close(efx->net_dev); 275262306a36Sopenharmony_ci ef4_disable_interrupts(efx); 275362306a36Sopenharmony_ci efx->state = STATE_UNINIT; 275462306a36Sopenharmony_ci rtnl_unlock(); 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci ef4_unregister_netdev(efx); 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci ef4_mtd_remove(efx); 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci ef4_pci_remove_main(efx); 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci ef4_fini_io(efx); 276362306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n"); 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci ef4_fini_struct(efx); 276662306a36Sopenharmony_ci free_netdev(efx->net_dev); 276762306a36Sopenharmony_ci}; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci/* NIC VPD information 277062306a36Sopenharmony_ci * Called during probe to display the part number of the installed NIC. 277162306a36Sopenharmony_ci */ 277262306a36Sopenharmony_cistatic void ef4_probe_vpd_strings(struct ef4_nic *efx) 277362306a36Sopenharmony_ci{ 277462306a36Sopenharmony_ci struct pci_dev *dev = efx->pci_dev; 277562306a36Sopenharmony_ci unsigned int vpd_size, kw_len; 277662306a36Sopenharmony_ci u8 *vpd_data; 277762306a36Sopenharmony_ci int start; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci vpd_data = pci_vpd_alloc(dev, &vpd_size); 278062306a36Sopenharmony_ci if (IS_ERR(vpd_data)) { 278162306a36Sopenharmony_ci pci_warn(dev, "Unable to read VPD\n"); 278262306a36Sopenharmony_ci return; 278362306a36Sopenharmony_ci } 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, 278662306a36Sopenharmony_ci PCI_VPD_RO_KEYWORD_PARTNO, &kw_len); 278762306a36Sopenharmony_ci if (start < 0) 278862306a36Sopenharmony_ci pci_warn(dev, "Part number not found or incomplete\n"); 278962306a36Sopenharmony_ci else 279062306a36Sopenharmony_ci pci_info(dev, "Part Number : %.*s\n", kw_len, vpd_data + start); 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, 279362306a36Sopenharmony_ci PCI_VPD_RO_KEYWORD_SERIALNO, &kw_len); 279462306a36Sopenharmony_ci if (start < 0) 279562306a36Sopenharmony_ci pci_warn(dev, "Serial number not found or incomplete\n"); 279662306a36Sopenharmony_ci else 279762306a36Sopenharmony_ci efx->vpd_sn = kmemdup_nul(vpd_data + start, kw_len, GFP_KERNEL); 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci kfree(vpd_data); 280062306a36Sopenharmony_ci} 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci/* Main body of NIC initialisation 280462306a36Sopenharmony_ci * This is called at module load (or hotplug insertion, theoretically). 280562306a36Sopenharmony_ci */ 280662306a36Sopenharmony_cistatic int ef4_pci_probe_main(struct ef4_nic *efx) 280762306a36Sopenharmony_ci{ 280862306a36Sopenharmony_ci int rc; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci /* Do start-of-day initialisation */ 281162306a36Sopenharmony_ci rc = ef4_probe_all(efx); 281262306a36Sopenharmony_ci if (rc) 281362306a36Sopenharmony_ci goto fail1; 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci ef4_init_napi(efx); 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci rc = efx->type->init(efx); 281862306a36Sopenharmony_ci if (rc) { 281962306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 282062306a36Sopenharmony_ci "failed to initialise NIC\n"); 282162306a36Sopenharmony_ci goto fail3; 282262306a36Sopenharmony_ci } 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci rc = ef4_init_port(efx); 282562306a36Sopenharmony_ci if (rc) { 282662306a36Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 282762306a36Sopenharmony_ci "failed to initialise port\n"); 282862306a36Sopenharmony_ci goto fail4; 282962306a36Sopenharmony_ci } 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci rc = ef4_nic_init_interrupt(efx); 283262306a36Sopenharmony_ci if (rc) 283362306a36Sopenharmony_ci goto fail5; 283462306a36Sopenharmony_ci rc = ef4_enable_interrupts(efx); 283562306a36Sopenharmony_ci if (rc) 283662306a36Sopenharmony_ci goto fail6; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci return 0; 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci fail6: 284162306a36Sopenharmony_ci ef4_nic_fini_interrupt(efx); 284262306a36Sopenharmony_ci fail5: 284362306a36Sopenharmony_ci ef4_fini_port(efx); 284462306a36Sopenharmony_ci fail4: 284562306a36Sopenharmony_ci efx->type->fini(efx); 284662306a36Sopenharmony_ci fail3: 284762306a36Sopenharmony_ci ef4_fini_napi(efx); 284862306a36Sopenharmony_ci ef4_remove_all(efx); 284962306a36Sopenharmony_ci fail1: 285062306a36Sopenharmony_ci return rc; 285162306a36Sopenharmony_ci} 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci/* NIC initialisation 285462306a36Sopenharmony_ci * 285562306a36Sopenharmony_ci * This is called at module load (or hotplug insertion, 285662306a36Sopenharmony_ci * theoretically). It sets up PCI mappings, resets the NIC, 285762306a36Sopenharmony_ci * sets up and registers the network devices with the kernel and hooks 285862306a36Sopenharmony_ci * the interrupt service routine. It does not prepare the device for 285962306a36Sopenharmony_ci * transmission; this is left to the first time one of the network 286062306a36Sopenharmony_ci * interfaces is brought up (i.e. ef4_net_open). 286162306a36Sopenharmony_ci */ 286262306a36Sopenharmony_cistatic int ef4_pci_probe(struct pci_dev *pci_dev, 286362306a36Sopenharmony_ci const struct pci_device_id *entry) 286462306a36Sopenharmony_ci{ 286562306a36Sopenharmony_ci struct net_device *net_dev; 286662306a36Sopenharmony_ci struct ef4_nic *efx; 286762306a36Sopenharmony_ci int rc; 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci /* Allocate and initialise a struct net_device and struct ef4_nic */ 287062306a36Sopenharmony_ci net_dev = alloc_etherdev_mqs(sizeof(*efx), EF4_MAX_CORE_TX_QUEUES, 287162306a36Sopenharmony_ci EF4_MAX_RX_QUEUES); 287262306a36Sopenharmony_ci if (!net_dev) 287362306a36Sopenharmony_ci return -ENOMEM; 287462306a36Sopenharmony_ci efx = netdev_priv(net_dev); 287562306a36Sopenharmony_ci efx->type = (const struct ef4_nic_type *) entry->driver_data; 287662306a36Sopenharmony_ci efx->fixed_features |= NETIF_F_HIGHDMA; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci pci_set_drvdata(pci_dev, efx); 287962306a36Sopenharmony_ci SET_NETDEV_DEV(net_dev, &pci_dev->dev); 288062306a36Sopenharmony_ci rc = ef4_init_struct(efx, pci_dev, net_dev); 288162306a36Sopenharmony_ci if (rc) 288262306a36Sopenharmony_ci goto fail1; 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci netif_info(efx, probe, efx->net_dev, 288562306a36Sopenharmony_ci "Solarflare NIC detected\n"); 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci ef4_probe_vpd_strings(efx); 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci /* Set up basic I/O (BAR mappings etc) */ 289062306a36Sopenharmony_ci rc = ef4_init_io(efx); 289162306a36Sopenharmony_ci if (rc) 289262306a36Sopenharmony_ci goto fail2; 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci rc = ef4_pci_probe_main(efx); 289562306a36Sopenharmony_ci if (rc) 289662306a36Sopenharmony_ci goto fail3; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci net_dev->features |= (efx->type->offload_features | NETIF_F_SG | 289962306a36Sopenharmony_ci NETIF_F_RXCSUM); 290062306a36Sopenharmony_ci /* Mask for features that also apply to VLAN devices */ 290162306a36Sopenharmony_ci net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG | 290262306a36Sopenharmony_ci NETIF_F_HIGHDMA | NETIF_F_RXCSUM); 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci net_dev->hw_features = net_dev->features & ~efx->fixed_features; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci /* Disable VLAN filtering by default. It may be enforced if 290762306a36Sopenharmony_ci * the feature is fixed (i.e. VLAN filters are required to 290862306a36Sopenharmony_ci * receive VLAN tagged packets due to vPort restrictions). 290962306a36Sopenharmony_ci */ 291062306a36Sopenharmony_ci net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 291162306a36Sopenharmony_ci net_dev->features |= efx->fixed_features; 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci rc = ef4_register_netdev(efx); 291462306a36Sopenharmony_ci if (rc) 291562306a36Sopenharmony_ci goto fail4; 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n"); 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci /* Try to create MTDs, but allow this to fail */ 292062306a36Sopenharmony_ci rtnl_lock(); 292162306a36Sopenharmony_ci rc = ef4_mtd_probe(efx); 292262306a36Sopenharmony_ci rtnl_unlock(); 292362306a36Sopenharmony_ci if (rc && rc != -EPERM) 292462306a36Sopenharmony_ci netif_warn(efx, probe, efx->net_dev, 292562306a36Sopenharmony_ci "failed to create MTDs (%d)\n", rc); 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci return 0; 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci fail4: 293062306a36Sopenharmony_ci ef4_pci_remove_main(efx); 293162306a36Sopenharmony_ci fail3: 293262306a36Sopenharmony_ci ef4_fini_io(efx); 293362306a36Sopenharmony_ci fail2: 293462306a36Sopenharmony_ci ef4_fini_struct(efx); 293562306a36Sopenharmony_ci fail1: 293662306a36Sopenharmony_ci WARN_ON(rc > 0); 293762306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc); 293862306a36Sopenharmony_ci free_netdev(net_dev); 293962306a36Sopenharmony_ci return rc; 294062306a36Sopenharmony_ci} 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_cistatic int ef4_pm_freeze(struct device *dev) 294362306a36Sopenharmony_ci{ 294462306a36Sopenharmony_ci struct ef4_nic *efx = dev_get_drvdata(dev); 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci rtnl_lock(); 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci if (efx->state != STATE_DISABLED) { 294962306a36Sopenharmony_ci efx->state = STATE_UNINIT; 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci ef4_device_detach_sync(efx); 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci ef4_stop_all(efx); 295462306a36Sopenharmony_ci ef4_disable_interrupts(efx); 295562306a36Sopenharmony_ci } 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci rtnl_unlock(); 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci return 0; 296062306a36Sopenharmony_ci} 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_cistatic int ef4_pm_thaw(struct device *dev) 296362306a36Sopenharmony_ci{ 296462306a36Sopenharmony_ci int rc; 296562306a36Sopenharmony_ci struct ef4_nic *efx = dev_get_drvdata(dev); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci rtnl_lock(); 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci if (efx->state != STATE_DISABLED) { 297062306a36Sopenharmony_ci rc = ef4_enable_interrupts(efx); 297162306a36Sopenharmony_ci if (rc) 297262306a36Sopenharmony_ci goto fail; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 297562306a36Sopenharmony_ci efx->phy_op->reconfigure(efx); 297662306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci ef4_start_all(efx); 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci netif_device_attach(efx->net_dev); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci efx->state = STATE_READY; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci efx->type->resume_wol(efx); 298562306a36Sopenharmony_ci } 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci rtnl_unlock(); 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci /* Reschedule any quenched resets scheduled during ef4_pm_freeze() */ 299062306a36Sopenharmony_ci queue_work(reset_workqueue, &efx->reset_work); 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci return 0; 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_cifail: 299562306a36Sopenharmony_ci rtnl_unlock(); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci return rc; 299862306a36Sopenharmony_ci} 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_cistatic int ef4_pm_poweroff(struct device *dev) 300162306a36Sopenharmony_ci{ 300262306a36Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 300362306a36Sopenharmony_ci struct ef4_nic *efx = pci_get_drvdata(pci_dev); 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci efx->type->fini(efx); 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci efx->reset_pending = 0; 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci pci_save_state(pci_dev); 301062306a36Sopenharmony_ci return pci_set_power_state(pci_dev, PCI_D3hot); 301162306a36Sopenharmony_ci} 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci/* Used for both resume and restore */ 301462306a36Sopenharmony_cistatic int ef4_pm_resume(struct device *dev) 301562306a36Sopenharmony_ci{ 301662306a36Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 301762306a36Sopenharmony_ci struct ef4_nic *efx = pci_get_drvdata(pci_dev); 301862306a36Sopenharmony_ci int rc; 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci rc = pci_set_power_state(pci_dev, PCI_D0); 302162306a36Sopenharmony_ci if (rc) 302262306a36Sopenharmony_ci return rc; 302362306a36Sopenharmony_ci pci_restore_state(pci_dev); 302462306a36Sopenharmony_ci rc = pci_enable_device(pci_dev); 302562306a36Sopenharmony_ci if (rc) 302662306a36Sopenharmony_ci return rc; 302762306a36Sopenharmony_ci pci_set_master(efx->pci_dev); 302862306a36Sopenharmony_ci rc = efx->type->reset(efx, RESET_TYPE_ALL); 302962306a36Sopenharmony_ci if (rc) 303062306a36Sopenharmony_ci return rc; 303162306a36Sopenharmony_ci rc = efx->type->init(efx); 303262306a36Sopenharmony_ci if (rc) 303362306a36Sopenharmony_ci return rc; 303462306a36Sopenharmony_ci rc = ef4_pm_thaw(dev); 303562306a36Sopenharmony_ci return rc; 303662306a36Sopenharmony_ci} 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_cistatic int ef4_pm_suspend(struct device *dev) 303962306a36Sopenharmony_ci{ 304062306a36Sopenharmony_ci int rc; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci ef4_pm_freeze(dev); 304362306a36Sopenharmony_ci rc = ef4_pm_poweroff(dev); 304462306a36Sopenharmony_ci if (rc) 304562306a36Sopenharmony_ci ef4_pm_resume(dev); 304662306a36Sopenharmony_ci return rc; 304762306a36Sopenharmony_ci} 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_cistatic const struct dev_pm_ops ef4_pm_ops = { 305062306a36Sopenharmony_ci .suspend = ef4_pm_suspend, 305162306a36Sopenharmony_ci .resume = ef4_pm_resume, 305262306a36Sopenharmony_ci .freeze = ef4_pm_freeze, 305362306a36Sopenharmony_ci .thaw = ef4_pm_thaw, 305462306a36Sopenharmony_ci .poweroff = ef4_pm_poweroff, 305562306a36Sopenharmony_ci .restore = ef4_pm_resume, 305662306a36Sopenharmony_ci}; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci/* A PCI error affecting this device was detected. 305962306a36Sopenharmony_ci * At this point MMIO and DMA may be disabled. 306062306a36Sopenharmony_ci * Stop the software path and request a slot reset. 306162306a36Sopenharmony_ci */ 306262306a36Sopenharmony_cistatic pci_ers_result_t ef4_io_error_detected(struct pci_dev *pdev, 306362306a36Sopenharmony_ci pci_channel_state_t state) 306462306a36Sopenharmony_ci{ 306562306a36Sopenharmony_ci pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 306662306a36Sopenharmony_ci struct ef4_nic *efx = pci_get_drvdata(pdev); 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci if (state == pci_channel_io_perm_failure) 306962306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci rtnl_lock(); 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci if (efx->state != STATE_DISABLED) { 307462306a36Sopenharmony_ci efx->state = STATE_RECOVERY; 307562306a36Sopenharmony_ci efx->reset_pending = 0; 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci ef4_device_detach_sync(efx); 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci ef4_stop_all(efx); 308062306a36Sopenharmony_ci ef4_disable_interrupts(efx); 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci status = PCI_ERS_RESULT_NEED_RESET; 308362306a36Sopenharmony_ci } else { 308462306a36Sopenharmony_ci /* If the interface is disabled we don't want to do anything 308562306a36Sopenharmony_ci * with it. 308662306a36Sopenharmony_ci */ 308762306a36Sopenharmony_ci status = PCI_ERS_RESULT_RECOVERED; 308862306a36Sopenharmony_ci } 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci rtnl_unlock(); 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci pci_disable_device(pdev); 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci return status; 309562306a36Sopenharmony_ci} 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci/* Fake a successful reset, which will be performed later in ef4_io_resume. */ 309862306a36Sopenharmony_cistatic pci_ers_result_t ef4_io_slot_reset(struct pci_dev *pdev) 309962306a36Sopenharmony_ci{ 310062306a36Sopenharmony_ci struct ef4_nic *efx = pci_get_drvdata(pdev); 310162306a36Sopenharmony_ci pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 310462306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 310562306a36Sopenharmony_ci "Cannot re-enable PCI device after reset.\n"); 310662306a36Sopenharmony_ci status = PCI_ERS_RESULT_DISCONNECT; 310762306a36Sopenharmony_ci } 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_ci return status; 311062306a36Sopenharmony_ci} 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci/* Perform the actual reset and resume I/O operations. */ 311362306a36Sopenharmony_cistatic void ef4_io_resume(struct pci_dev *pdev) 311462306a36Sopenharmony_ci{ 311562306a36Sopenharmony_ci struct ef4_nic *efx = pci_get_drvdata(pdev); 311662306a36Sopenharmony_ci int rc; 311762306a36Sopenharmony_ci 311862306a36Sopenharmony_ci rtnl_lock(); 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci if (efx->state == STATE_DISABLED) 312162306a36Sopenharmony_ci goto out; 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci rc = ef4_reset(efx, RESET_TYPE_ALL); 312462306a36Sopenharmony_ci if (rc) { 312562306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 312662306a36Sopenharmony_ci "ef4_reset failed after PCI error (%d)\n", rc); 312762306a36Sopenharmony_ci } else { 312862306a36Sopenharmony_ci efx->state = STATE_READY; 312962306a36Sopenharmony_ci netif_dbg(efx, hw, efx->net_dev, 313062306a36Sopenharmony_ci "Done resetting and resuming IO after PCI error.\n"); 313162306a36Sopenharmony_ci } 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ciout: 313462306a36Sopenharmony_ci rtnl_unlock(); 313562306a36Sopenharmony_ci} 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci/* For simplicity and reliability, we always require a slot reset and try to 313862306a36Sopenharmony_ci * reset the hardware when a pci error affecting the device is detected. 313962306a36Sopenharmony_ci * We leave both the link_reset and mmio_enabled callback unimplemented: 314062306a36Sopenharmony_ci * with our request for slot reset the mmio_enabled callback will never be 314162306a36Sopenharmony_ci * called, and the link_reset callback is not used by AER or EEH mechanisms. 314262306a36Sopenharmony_ci */ 314362306a36Sopenharmony_cistatic const struct pci_error_handlers ef4_err_handlers = { 314462306a36Sopenharmony_ci .error_detected = ef4_io_error_detected, 314562306a36Sopenharmony_ci .slot_reset = ef4_io_slot_reset, 314662306a36Sopenharmony_ci .resume = ef4_io_resume, 314762306a36Sopenharmony_ci}; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_cistatic struct pci_driver ef4_pci_driver = { 315062306a36Sopenharmony_ci .name = KBUILD_MODNAME, 315162306a36Sopenharmony_ci .id_table = ef4_pci_table, 315262306a36Sopenharmony_ci .probe = ef4_pci_probe, 315362306a36Sopenharmony_ci .remove = ef4_pci_remove, 315462306a36Sopenharmony_ci .driver.pm = &ef4_pm_ops, 315562306a36Sopenharmony_ci .err_handler = &ef4_err_handlers, 315662306a36Sopenharmony_ci}; 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci/************************************************************************** 315962306a36Sopenharmony_ci * 316062306a36Sopenharmony_ci * Kernel module interface 316162306a36Sopenharmony_ci * 316262306a36Sopenharmony_ci *************************************************************************/ 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_cimodule_param(interrupt_mode, uint, 0444); 316562306a36Sopenharmony_ciMODULE_PARM_DESC(interrupt_mode, 316662306a36Sopenharmony_ci "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)"); 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_cistatic int __init ef4_init_module(void) 316962306a36Sopenharmony_ci{ 317062306a36Sopenharmony_ci int rc; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci printk(KERN_INFO "Solarflare Falcon driver v" EF4_DRIVER_VERSION "\n"); 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci rc = register_netdevice_notifier(&ef4_netdev_notifier); 317562306a36Sopenharmony_ci if (rc) 317662306a36Sopenharmony_ci goto err_notifier; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci reset_workqueue = create_singlethread_workqueue("sfc_reset"); 317962306a36Sopenharmony_ci if (!reset_workqueue) { 318062306a36Sopenharmony_ci rc = -ENOMEM; 318162306a36Sopenharmony_ci goto err_reset; 318262306a36Sopenharmony_ci } 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci rc = pci_register_driver(&ef4_pci_driver); 318562306a36Sopenharmony_ci if (rc < 0) 318662306a36Sopenharmony_ci goto err_pci; 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci return 0; 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci err_pci: 319162306a36Sopenharmony_ci destroy_workqueue(reset_workqueue); 319262306a36Sopenharmony_ci err_reset: 319362306a36Sopenharmony_ci unregister_netdevice_notifier(&ef4_netdev_notifier); 319462306a36Sopenharmony_ci err_notifier: 319562306a36Sopenharmony_ci return rc; 319662306a36Sopenharmony_ci} 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_cistatic void __exit ef4_exit_module(void) 319962306a36Sopenharmony_ci{ 320062306a36Sopenharmony_ci printk(KERN_INFO "Solarflare Falcon driver unloading\n"); 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci pci_unregister_driver(&ef4_pci_driver); 320362306a36Sopenharmony_ci destroy_workqueue(reset_workqueue); 320462306a36Sopenharmony_ci unregister_netdevice_notifier(&ef4_netdev_notifier); 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci} 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_cimodule_init(ef4_init_module); 320962306a36Sopenharmony_cimodule_exit(ef4_exit_module); 321062306a36Sopenharmony_ci 321162306a36Sopenharmony_ciMODULE_AUTHOR("Solarflare Communications and " 321262306a36Sopenharmony_ci "Michael Brown <mbrown@fensystems.co.uk>"); 321362306a36Sopenharmony_ciMODULE_DESCRIPTION("Solarflare Falcon network driver"); 321462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 321562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ef4_pci_table); 321662306a36Sopenharmony_ciMODULE_VERSION(EF4_DRIVER_VERSION); 3217