From: Linus Torvalds Date: Fri, 28 Oct 2011 21:20:44 +0000 (-0700) Subject: Merge branch 'next-rebase' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=0e59e7e7feb5a12938fbf9135147eeda3238c6c4;p=~shefty%2Frdma-dev.git Merge branch 'next-rebase' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci * 'next-rebase' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci: PCI: Clean-up MPS debug output pci: Clamp pcie_set_readrq() when using "performance" settings PCI: enable MPS "performance" setting to properly handle bridge MPS PCI: Workaround for Intel MPS errata PCI: Add support for PASID capability PCI: Add implementation for PRI capability PCI: Export ATS functions to modules PCI: Move ATS implementation into own file PCI / PM: Remove unnecessary error variable from acpi_dev_run_wake() PCI hotplug: acpiphp: Prevent deadlock on PCI-to-PCI bridge remove PCI / PM: Extend PME polling to all PCI devices PCI quirk: mmc: Always check for lower base frequency quirk for Ricoh 1180:e823 PCI: Make pci_setup_bridge() non-static for use by arch code x86: constify PCI raw ops structures PCI: Add quirk for known incorrect MPSS PCI: Add Solarflare vendor ID and SFC4000 device IDs --- 0e59e7e7feb5a12938fbf9135147eeda3238c6c4 diff --cc drivers/net/ethernet/sfc/efx.c index de9afebe183,00000000000..d5731f1fe6d mode 100644,000000..100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@@ -1,2732 -1,0 +1,2734 @@@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2005-2011 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "net_driver.h" +#include "efx.h" +#include "nic.h" + +#include "mcdi.h" +#include "workarounds.h" + +/************************************************************************** + * + * Type name strings + * + ************************************************************************** + */ + +/* Loopback mode names (see LOOPBACK_MODE()) */ +const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; +const char *efx_loopback_mode_names[] = { + [LOOPBACK_NONE] = "NONE", + [LOOPBACK_DATA] = "DATAPATH", + [LOOPBACK_GMAC] = "GMAC", + [LOOPBACK_XGMII] = "XGMII", + [LOOPBACK_XGXS] = "XGXS", + [LOOPBACK_XAUI] = "XAUI", + [LOOPBACK_GMII] = "GMII", + [LOOPBACK_SGMII] = "SGMII", + [LOOPBACK_XGBR] = "XGBR", + [LOOPBACK_XFI] = "XFI", + [LOOPBACK_XAUI_FAR] = "XAUI_FAR", + [LOOPBACK_GMII_FAR] = "GMII_FAR", + [LOOPBACK_SGMII_FAR] = "SGMII_FAR", + [LOOPBACK_XFI_FAR] = "XFI_FAR", + [LOOPBACK_GPHY] = "GPHY", + [LOOPBACK_PHYXS] = "PHYXS", + [LOOPBACK_PCS] = "PCS", + [LOOPBACK_PMAPMD] = "PMA/PMD", + [LOOPBACK_XPORT] = "XPORT", + [LOOPBACK_XGMII_WS] = "XGMII_WS", + [LOOPBACK_XAUI_WS] = "XAUI_WS", + [LOOPBACK_XAUI_WS_FAR] = "XAUI_WS_FAR", + [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR", + [LOOPBACK_GMII_WS] = "GMII_WS", + [LOOPBACK_XFI_WS] = "XFI_WS", + [LOOPBACK_XFI_WS_FAR] = "XFI_WS_FAR", + [LOOPBACK_PHYXS_WS] = "PHYXS_WS", +}; + +const unsigned int efx_reset_type_max = RESET_TYPE_MAX; +const char *efx_reset_type_names[] = { + [RESET_TYPE_INVISIBLE] = "INVISIBLE", + [RESET_TYPE_ALL] = "ALL", + [RESET_TYPE_WORLD] = "WORLD", + [RESET_TYPE_DISABLE] = "DISABLE", + [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG", + [RESET_TYPE_INT_ERROR] = "INT_ERROR", + [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY", + [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", + [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", + [RESET_TYPE_TX_SKIP] = "TX_SKIP", + [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", +}; + +#define EFX_MAX_MTU (9 * 1024) + +/* Reset workqueue. If any NIC has a hardware failure then a reset will be + * queued onto this work queue. This is not a per-nic work queue, because + * efx_reset_work() acquires the rtnl lock, so resets are naturally serialised. + */ +static struct workqueue_struct *reset_workqueue; + +/************************************************************************** + * + * Configurable values + * + *************************************************************************/ + +/* + * Use separate channels for TX and RX events + * + * Set this to 1 to use separate channels for TX and RX. It allows us + * to control interrupt affinity separately for TX and RX. + * + * This is only used in MSI-X interrupt mode + */ +static unsigned int separate_tx_channels; +module_param(separate_tx_channels, uint, 0444); +MODULE_PARM_DESC(separate_tx_channels, + "Use separate channels for TX and RX"); + +/* This is the weight assigned to each of the (per-channel) virtual + * NAPI devices. + */ +static int napi_weight = 64; + +/* This is the time (in jiffies) between invocations of the hardware + * monitor. On Falcon-based NICs, this will: + * - Check the on-board hardware monitor; + * - Poll the link state and reconfigure the hardware as necessary. + */ +static unsigned int efx_monitor_interval = 1 * HZ; + +/* This controls whether or not the driver will initialise devices + * with invalid MAC addresses stored in the EEPROM or flash. If true, + * such devices will be initialised with a random locally-generated + * MAC address. This allows for loading the sfc_mtd driver to + * reprogram the flash, even if the flash contents (including the MAC + * address) have previously been erased. + */ +static unsigned int allow_bad_hwaddr; + +/* Initial interrupt moderation settings. They can be modified after + * module load with ethtool. + * + * The default for RX should strike a balance between increasing the + * round-trip latency and reducing overhead. + */ +static unsigned int rx_irq_mod_usec = 60; + +/* Initial interrupt moderation settings. They can be modified after + * module load with ethtool. + * + * This default is chosen to ensure that a 10G link does not go idle + * while a TX queue is stopped after it has become full. A queue is + * restarted when it drops below half full. The time this takes (assuming + * worst case 3 descriptors per packet and 1024 descriptors) is + * 512 / 3 * 1.2 = 205 usec. + */ +static unsigned int tx_irq_mod_usec = 150; + +/* This is the first interrupt mode to try out of: + * 0 => MSI-X + * 1 => MSI + * 2 => legacy + */ +static unsigned int interrupt_mode; + +/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS), + * i.e. the number of CPUs among which we may distribute simultaneous + * interrupt handling. + * + * Cards without MSI-X will only target one CPU via legacy or MSI interrupt. + * The default (0) means to assign an interrupt to each package (level II cache) + */ +static unsigned int rss_cpus; +module_param(rss_cpus, uint, 0444); +MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling"); + +static int phy_flash_cfg; +module_param(phy_flash_cfg, int, 0644); +MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); + +static unsigned irq_adapt_low_thresh = 10000; +module_param(irq_adapt_low_thresh, uint, 0644); +MODULE_PARM_DESC(irq_adapt_low_thresh, + "Threshold score for reducing IRQ moderation"); + +static unsigned irq_adapt_high_thresh = 20000; +module_param(irq_adapt_high_thresh, uint, 0644); +MODULE_PARM_DESC(irq_adapt_high_thresh, + "Threshold score for increasing IRQ moderation"); + +static unsigned debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE | + NETIF_MSG_LINK | NETIF_MSG_IFDOWN | + NETIF_MSG_IFUP | NETIF_MSG_RX_ERR | + NETIF_MSG_TX_ERR | NETIF_MSG_HW); +module_param(debug, uint, 0); +MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); + +/************************************************************************** + * + * Utility functions and prototypes + * + *************************************************************************/ + +static void efx_remove_channels(struct efx_nic *efx); +static void efx_remove_port(struct efx_nic *efx); +static void efx_init_napi(struct efx_nic *efx); +static void efx_fini_napi(struct efx_nic *efx); +static void efx_fini_napi_channel(struct efx_channel *channel); +static void efx_fini_struct(struct efx_nic *efx); +static void efx_start_all(struct efx_nic *efx); +static void efx_stop_all(struct efx_nic *efx); + +#define EFX_ASSERT_RESET_SERIALISED(efx) \ + do { \ + if ((efx->state == STATE_RUNNING) || \ + (efx->state == STATE_DISABLED)) \ + ASSERT_RTNL(); \ + } while (0) + +/************************************************************************** + * + * Event queue processing + * + *************************************************************************/ + +/* Process channel's event queue + * + * This function is responsible for processing the event queue of a + * single channel. The caller must guarantee that this function will + * never be concurrently called more than once on the same channel, + * though different channels may be being processed concurrently. + */ +static int efx_process_channel(struct efx_channel *channel, int budget) +{ + struct efx_nic *efx = channel->efx; + int spent; + + if (unlikely(efx->reset_pending || !channel->enabled)) + return 0; + + spent = efx_nic_process_eventq(channel, budget); + if (spent == 0) + return 0; + + /* Deliver last RX packet. */ + if (channel->rx_pkt) { + __efx_rx_packet(channel, channel->rx_pkt, + channel->rx_pkt_csummed); + channel->rx_pkt = NULL; + } + + efx_rx_strategy(channel); + + efx_fast_push_rx_descriptors(efx_channel_get_rx_queue(channel)); + + return spent; +} + +/* Mark channel as finished processing + * + * Note that since we will not receive further interrupts for this + * channel before we finish processing and call the eventq_read_ack() + * method, there is no need to use the interrupt hold-off timers. + */ +static inline void efx_channel_processed(struct efx_channel *channel) +{ + /* The interrupt handler for this channel may set work_pending + * as soon as we acknowledge the events we've seen. Make sure + * it's cleared before then. */ + channel->work_pending = false; + smp_wmb(); + + efx_nic_eventq_read_ack(channel); +} + +/* NAPI poll handler + * + * NAPI guarantees serialisation of polls of the same device, which + * provides the guarantee required by efx_process_channel(). + */ +static int efx_poll(struct napi_struct *napi, int budget) +{ + struct efx_channel *channel = + container_of(napi, struct efx_channel, napi_str); + struct efx_nic *efx = channel->efx; + int spent; + + netif_vdbg(efx, intr, efx->net_dev, + "channel %d NAPI poll executing on CPU %d\n", + channel->channel, raw_smp_processor_id()); + + spent = efx_process_channel(channel, budget); + + if (spent < budget) { + if (channel->channel < efx->n_rx_channels && + efx->irq_rx_adaptive && + unlikely(++channel->irq_count == 1000)) { + if (unlikely(channel->irq_mod_score < + irq_adapt_low_thresh)) { + if (channel->irq_moderation > 1) { + channel->irq_moderation -= 1; + efx->type->push_irq_moderation(channel); + } + } else if (unlikely(channel->irq_mod_score > + irq_adapt_high_thresh)) { + if (channel->irq_moderation < + efx->irq_rx_moderation) { + channel->irq_moderation += 1; + efx->type->push_irq_moderation(channel); + } + } + channel->irq_count = 0; + channel->irq_mod_score = 0; + } + + efx_filter_rfs_expire(channel); + + /* There is no race here; although napi_disable() will + * only wait for napi_complete(), this isn't a problem + * since efx_channel_processed() will have no effect if + * interrupts have already been disabled. + */ + napi_complete(napi); + efx_channel_processed(channel); + } + + return spent; +} + +/* Process the eventq of the specified channel immediately on this CPU + * + * Disable hardware generated interrupts, wait for any existing + * processing to finish, then directly poll (and ack ) the eventq. + * Finally reenable NAPI and interrupts. + * + * This is for use only during a loopback self-test. It must not + * deliver any packets up the stack as this can result in deadlock. + */ +void efx_process_channel_now(struct efx_channel *channel) +{ + struct efx_nic *efx = channel->efx; + + BUG_ON(channel->channel >= efx->n_channels); + BUG_ON(!channel->enabled); + BUG_ON(!efx->loopback_selftest); + + /* Disable interrupts and wait for ISRs to complete */ + efx_nic_disable_interrupts(efx); + if (efx->legacy_irq) { + synchronize_irq(efx->legacy_irq); + efx->legacy_irq_enabled = false; + } + if (channel->irq) + synchronize_irq(channel->irq); + + /* Wait for any NAPI processing to complete */ + napi_disable(&channel->napi_str); + + /* Poll the channel */ + efx_process_channel(channel, channel->eventq_mask + 1); + + /* Ack the eventq. This may cause an interrupt to be generated + * when they are reenabled */ + efx_channel_processed(channel); + + napi_enable(&channel->napi_str); + if (efx->legacy_irq) + efx->legacy_irq_enabled = true; + efx_nic_enable_interrupts(efx); +} + +/* Create event queue + * Event queue memory allocations are done only once. If the channel + * is reset, the memory buffer will be reused; this guards against + * errors during channel reset and also simplifies interrupt handling. + */ +static int efx_probe_eventq(struct efx_channel *channel) +{ + struct efx_nic *efx = channel->efx; + unsigned long entries; + + netif_dbg(channel->efx, probe, channel->efx->net_dev, + "chan %d create event queue\n", channel->channel); + + /* Build an event queue with room for one event per tx and rx buffer, + * plus some extra for link state events and MCDI completions. */ + entries = roundup_pow_of_two(efx->rxq_entries + efx->txq_entries + 128); + EFX_BUG_ON_PARANOID(entries > EFX_MAX_EVQ_SIZE); + channel->eventq_mask = max(entries, EFX_MIN_EVQ_SIZE) - 1; + + return efx_nic_probe_eventq(channel); +} + +/* Prepare channel's event queue */ +static void efx_init_eventq(struct efx_channel *channel) +{ + netif_dbg(channel->efx, drv, channel->efx->net_dev, + "chan %d init event queue\n", channel->channel); + + channel->eventq_read_ptr = 0; + + efx_nic_init_eventq(channel); +} + +static void efx_fini_eventq(struct efx_channel *channel) +{ + netif_dbg(channel->efx, drv, channel->efx->net_dev, + "chan %d fini event queue\n", channel->channel); + + efx_nic_fini_eventq(channel); +} + +static void efx_remove_eventq(struct efx_channel *channel) +{ + netif_dbg(channel->efx, drv, channel->efx->net_dev, + "chan %d remove event queue\n", channel->channel); + + efx_nic_remove_eventq(channel); +} + +/************************************************************************** + * + * Channel handling + * + *************************************************************************/ + +/* Allocate and initialise a channel structure, optionally copying + * parameters (but not resources) from an old channel structure. */ +static struct efx_channel * +efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) +{ + struct efx_channel *channel; + struct efx_rx_queue *rx_queue; + struct efx_tx_queue *tx_queue; + int j; + + if (old_channel) { + channel = kmalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return NULL; + + *channel = *old_channel; + + channel->napi_dev = NULL; + memset(&channel->eventq, 0, sizeof(channel->eventq)); + + rx_queue = &channel->rx_queue; + rx_queue->buffer = NULL; + memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); + + for (j = 0; j < EFX_TXQ_TYPES; j++) { + tx_queue = &channel->tx_queue[j]; + if (tx_queue->channel) + tx_queue->channel = channel; + tx_queue->buffer = NULL; + memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); + } + } else { + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return NULL; + + channel->efx = efx; + channel->channel = i; + + for (j = 0; j < EFX_TXQ_TYPES; j++) { + tx_queue = &channel->tx_queue[j]; + tx_queue->efx = efx; + tx_queue->queue = i * EFX_TXQ_TYPES + j; + tx_queue->channel = channel; + } + } + + rx_queue = &channel->rx_queue; + rx_queue->efx = efx; + setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, + (unsigned long)rx_queue); + + return channel; +} + +static int efx_probe_channel(struct efx_channel *channel) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + int rc; + + netif_dbg(channel->efx, probe, channel->efx->net_dev, + "creating channel %d\n", channel->channel); + + rc = efx_probe_eventq(channel); + if (rc) + goto fail1; + + efx_for_each_channel_tx_queue(tx_queue, channel) { + rc = efx_probe_tx_queue(tx_queue); + if (rc) + goto fail2; + } + + efx_for_each_channel_rx_queue(rx_queue, channel) { + rc = efx_probe_rx_queue(rx_queue); + if (rc) + goto fail3; + } + + channel->n_rx_frm_trunc = 0; + + return 0; + + fail3: + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_remove_rx_queue(rx_queue); + fail2: + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_remove_tx_queue(tx_queue); + fail1: + return rc; +} + + +static void efx_set_channel_names(struct efx_nic *efx) +{ + struct efx_channel *channel; + const char *type = ""; + int number; + + efx_for_each_channel(channel, efx) { + number = channel->channel; + if (efx->n_channels > efx->n_rx_channels) { + if (channel->channel < efx->n_rx_channels) { + type = "-rx"; + } else { + type = "-tx"; + number -= efx->n_rx_channels; + } + } + snprintf(efx->channel_name[channel->channel], + sizeof(efx->channel_name[0]), + "%s%s-%d", efx->name, type, number); + } +} + +static int efx_probe_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + int rc; + + /* Restart special buffer allocation */ + efx->next_buffer_table = 0; + + efx_for_each_channel(channel, efx) { + rc = efx_probe_channel(channel); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to create channel %d\n", + channel->channel); + goto fail; + } + } + efx_set_channel_names(efx); + + return 0; + +fail: + efx_remove_channels(efx); + return rc; +} + +/* Channels are shutdown and reinitialised whilst the NIC is running + * to propagate configuration changes (mtu, checksum offload), or + * to clear hardware error conditions + */ +static void efx_init_channels(struct efx_nic *efx) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + struct efx_channel *channel; + + /* Calculate the rx buffer allocation parameters required to + * support the current MTU, including padding for header + * alignment and overruns. + */ + efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) + + EFX_MAX_FRAME_LEN(efx->net_dev->mtu) + + efx->type->rx_buffer_hash_size + + efx->type->rx_buffer_padding); + efx->rx_buffer_order = get_order(efx->rx_buffer_len + + sizeof(struct efx_rx_page_state)); + + /* Initialise the channels */ + efx_for_each_channel(channel, efx) { + netif_dbg(channel->efx, drv, channel->efx->net_dev, + "init chan %d\n", channel->channel); + + efx_init_eventq(channel); + + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_init_tx_queue(tx_queue); + + /* The rx buffer allocation strategy is MTU dependent */ + efx_rx_strategy(channel); + + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_init_rx_queue(rx_queue); + + WARN_ON(channel->rx_pkt != NULL); + efx_rx_strategy(channel); + } +} + +/* This enables event queue processing and packet transmission. + * + * Note that this function is not allowed to fail, since that would + * introduce too much complexity into the suspend/resume path. + */ +static void efx_start_channel(struct efx_channel *channel) +{ + struct efx_rx_queue *rx_queue; + + netif_dbg(channel->efx, ifup, channel->efx->net_dev, + "starting chan %d\n", channel->channel); + + /* The interrupt handler for this channel may set work_pending + * as soon as we enable it. Make sure it's cleared before + * then. Similarly, make sure it sees the enabled flag set. */ + channel->work_pending = false; + channel->enabled = true; + smp_wmb(); + + /* Fill the queues before enabling NAPI */ + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_fast_push_rx_descriptors(rx_queue); + + napi_enable(&channel->napi_str); +} + +/* This disables event queue processing and packet transmission. + * This function does not guarantee that all queue processing + * (e.g. RX refill) is complete. + */ +static void efx_stop_channel(struct efx_channel *channel) +{ + if (!channel->enabled) + return; + + netif_dbg(channel->efx, ifdown, channel->efx->net_dev, + "stop chan %d\n", channel->channel); + + channel->enabled = false; + napi_disable(&channel->napi_str); +} + +static void efx_fini_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + int rc; + + EFX_ASSERT_RESET_SERIALISED(efx); + BUG_ON(efx->port_enabled); + + rc = efx_nic_flush_queues(efx); + if (rc && EFX_WORKAROUND_7803(efx)) { + /* Schedule a reset to recover from the flush failure. The + * descriptor caches reference memory we're about to free, + * but falcon_reconfigure_mac_wrapper() won't reconnect + * the MACs because of the pending reset. */ + netif_err(efx, drv, efx->net_dev, + "Resetting to recover from flush failure\n"); + efx_schedule_reset(efx, RESET_TYPE_ALL); + } else if (rc) { + netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); + } else { + netif_dbg(efx, drv, efx->net_dev, + "successfully flushed all queues\n"); + } + + efx_for_each_channel(channel, efx) { + netif_dbg(channel->efx, drv, channel->efx->net_dev, + "shut down chan %d\n", channel->channel); + + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_fini_rx_queue(rx_queue); + efx_for_each_possible_channel_tx_queue(tx_queue, channel) + efx_fini_tx_queue(tx_queue); + efx_fini_eventq(channel); + } +} + +static void efx_remove_channel(struct efx_channel *channel) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + + netif_dbg(channel->efx, drv, channel->efx->net_dev, + "destroy chan %d\n", channel->channel); + + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_remove_rx_queue(rx_queue); + efx_for_each_possible_channel_tx_queue(tx_queue, channel) + efx_remove_tx_queue(tx_queue); + efx_remove_eventq(channel); +} + +static void efx_remove_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) + efx_remove_channel(channel); +} + +int +efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) +{ + struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; + u32 old_rxq_entries, old_txq_entries; + unsigned i; + int rc; + + efx_stop_all(efx); + efx_fini_channels(efx); + + /* Clone channels */ + memset(other_channel, 0, sizeof(other_channel)); + for (i = 0; i < efx->n_channels; i++) { + channel = efx_alloc_channel(efx, i, efx->channel[i]); + if (!channel) { + rc = -ENOMEM; + goto out; + } + other_channel[i] = channel; + } + + /* Swap entry counts and channel pointers */ + old_rxq_entries = efx->rxq_entries; + old_txq_entries = efx->txq_entries; + efx->rxq_entries = rxq_entries; + efx->txq_entries = txq_entries; + for (i = 0; i < efx->n_channels; i++) { + channel = efx->channel[i]; + efx->channel[i] = other_channel[i]; + other_channel[i] = channel; + } + + rc = efx_probe_channels(efx); + if (rc) + goto rollback; + + efx_init_napi(efx); + + /* Destroy old channels */ + for (i = 0; i < efx->n_channels; i++) { + efx_fini_napi_channel(other_channel[i]); + efx_remove_channel(other_channel[i]); + } +out: + /* Free unused channel structures */ + for (i = 0; i < efx->n_channels; i++) + kfree(other_channel[i]); + + efx_init_channels(efx); + efx_start_all(efx); + return rc; + +rollback: + /* Swap back */ + efx->rxq_entries = old_rxq_entries; + efx->txq_entries = old_txq_entries; + for (i = 0; i < efx->n_channels; i++) { + channel = efx->channel[i]; + efx->channel[i] = other_channel[i]; + other_channel[i] = channel; + } + goto out; +} + +void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue) +{ + mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); +} + +/************************************************************************** + * + * Port handling + * + **************************************************************************/ + +/* This ensures that the kernel is kept informed (via + * netif_carrier_on/off) of the link status, and also maintains the + * link status's stop on the port's TX queue. + */ +void efx_link_status_changed(struct efx_nic *efx) +{ + struct efx_link_state *link_state = &efx->link_state; + + /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure + * that no events are triggered between unregister_netdev() and the + * driver unloading. A more general condition is that NETDEV_CHANGE + * can only be generated between NETDEV_UP and NETDEV_DOWN */ + if (!netif_running(efx->net_dev)) + return; + + if (link_state->up != netif_carrier_ok(efx->net_dev)) { + efx->n_link_state_changes++; + + if (link_state->up) + netif_carrier_on(efx->net_dev); + else + netif_carrier_off(efx->net_dev); + } + + /* Status message for kernel log */ + if (link_state->up) { + netif_info(efx, link, efx->net_dev, + "link up at %uMbps %s-duplex (MTU %d)%s\n", + link_state->speed, link_state->fd ? "full" : "half", + efx->net_dev->mtu, + (efx->promiscuous ? " [PROMISC]" : "")); + } else { + netif_info(efx, link, efx->net_dev, "link down\n"); + } + +} + +void efx_link_set_advertising(struct efx_nic *efx, u32 advertising) +{ + efx->link_advertising = advertising; + if (advertising) { + if (advertising & ADVERTISED_Pause) + efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX); + else + efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX); + if (advertising & ADVERTISED_Asym_Pause) + efx->wanted_fc ^= EFX_FC_TX; + } +} + +void efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc) +{ + efx->wanted_fc = wanted_fc; + if (efx->link_advertising) { + if (wanted_fc & EFX_FC_RX) + efx->link_advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + else + efx->link_advertising &= ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + if (wanted_fc & EFX_FC_TX) + efx->link_advertising ^= ADVERTISED_Asym_Pause; + } +} + +static void efx_fini_port(struct efx_nic *efx); + +/* Push loopback/power/transmit disable settings to the PHY, and reconfigure + * the MAC appropriately. All other PHY configuration changes are pushed + * through phy_op->set_settings(), and pushed asynchronously to the MAC + * through efx_monitor(). + * + * Callers must hold the mac_lock + */ +int __efx_reconfigure_port(struct efx_nic *efx) +{ + enum efx_phy_mode phy_mode; + int rc; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + /* Serialise the promiscuous flag with efx_set_multicast_list. */ + if (efx_dev_registered(efx)) { + netif_addr_lock_bh(efx->net_dev); + netif_addr_unlock_bh(efx->net_dev); + } + + /* Disable PHY transmit in mac level loopbacks */ + phy_mode = efx->phy_mode; + if (LOOPBACK_INTERNAL(efx)) + efx->phy_mode |= PHY_MODE_TX_DISABLED; + else + efx->phy_mode &= ~PHY_MODE_TX_DISABLED; + + rc = efx->type->reconfigure_port(efx); + + if (rc) + efx->phy_mode = phy_mode; + + return rc; +} + +/* Reinitialise the MAC to pick up new PHY settings, even if the port is + * disabled. */ +int efx_reconfigure_port(struct efx_nic *efx) +{ + int rc; + + EFX_ASSERT_RESET_SERIALISED(efx); + + mutex_lock(&efx->mac_lock); + rc = __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); + + return rc; +} + +/* Asynchronous work item for changing MAC promiscuity and multicast + * hash. Avoid a drain/rx_ingress enable by reconfiguring the current + * MAC directly. */ +static void efx_mac_work(struct work_struct *data) +{ + struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); + + mutex_lock(&efx->mac_lock); + if (efx->port_enabled) { + efx->type->push_multicast_hash(efx); + efx->mac_op->reconfigure(efx); + } + mutex_unlock(&efx->mac_lock); +} + +static int efx_probe_port(struct efx_nic *efx) +{ + unsigned char *perm_addr; + int rc; + + netif_dbg(efx, probe, efx->net_dev, "create port\n"); + + if (phy_flash_cfg) + efx->phy_mode = PHY_MODE_SPECIAL; + + /* Connect up MAC/PHY operations table */ + rc = efx->type->probe_port(efx); + if (rc) + return rc; + + /* Sanity check MAC address */ + perm_addr = efx->net_dev->perm_addr; + if (is_valid_ether_addr(perm_addr)) { + memcpy(efx->net_dev->dev_addr, perm_addr, ETH_ALEN); + } else { + netif_err(efx, probe, efx->net_dev, "invalid MAC address %pM\n", + perm_addr); + if (!allow_bad_hwaddr) { + rc = -EINVAL; + goto err; + } + random_ether_addr(efx->net_dev->dev_addr); + netif_info(efx, probe, efx->net_dev, + "using locally-generated MAC %pM\n", + efx->net_dev->dev_addr); + } + + return 0; + + err: + efx->type->remove_port(efx); + return rc; +} + +static int efx_init_port(struct efx_nic *efx) +{ + int rc; + + netif_dbg(efx, drv, efx->net_dev, "init port\n"); + + mutex_lock(&efx->mac_lock); + + rc = efx->phy_op->init(efx); + if (rc) + goto fail1; + + efx->port_initialized = true; + + /* Reconfigure the MAC before creating dma queues (required for + * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */ + efx->mac_op->reconfigure(efx); + + /* Ensure the PHY advertises the correct flow control settings */ + rc = efx->phy_op->reconfigure(efx); + if (rc) + goto fail2; + + mutex_unlock(&efx->mac_lock); + return 0; + +fail2: + efx->phy_op->fini(efx); +fail1: + mutex_unlock(&efx->mac_lock); + return rc; +} + +static void efx_start_port(struct efx_nic *efx) +{ + netif_dbg(efx, ifup, efx->net_dev, "start port\n"); + BUG_ON(efx->port_enabled); + + mutex_lock(&efx->mac_lock); + efx->port_enabled = true; + + /* efx_mac_work() might have been scheduled after efx_stop_port(), + * and then cancelled by efx_flush_all() */ + efx->type->push_multicast_hash(efx); + efx->mac_op->reconfigure(efx); + + mutex_unlock(&efx->mac_lock); +} + +/* Prevent efx_mac_work() and efx_monitor() from working */ +static void efx_stop_port(struct efx_nic *efx) +{ + netif_dbg(efx, ifdown, efx->net_dev, "stop port\n"); + + mutex_lock(&efx->mac_lock); + efx->port_enabled = false; + mutex_unlock(&efx->mac_lock); + + /* Serialise against efx_set_multicast_list() */ + if (efx_dev_registered(efx)) { + netif_addr_lock_bh(efx->net_dev); + netif_addr_unlock_bh(efx->net_dev); + } +} + +static void efx_fini_port(struct efx_nic *efx) +{ + netif_dbg(efx, drv, efx->net_dev, "shut down port\n"); + + if (!efx->port_initialized) + return; + + efx->phy_op->fini(efx); + efx->port_initialized = false; + + efx->link_state.up = false; + efx_link_status_changed(efx); +} + +static void efx_remove_port(struct efx_nic *efx) +{ + netif_dbg(efx, drv, efx->net_dev, "destroying port\n"); + + efx->type->remove_port(efx); +} + +/************************************************************************** + * + * NIC handling + * + **************************************************************************/ + +/* This configures the PCI device to enable I/O and DMA. */ +static int efx_init_io(struct efx_nic *efx) +{ + struct pci_dev *pci_dev = efx->pci_dev; + dma_addr_t dma_mask = efx->type->max_dma_mask; + int rc; + + netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); + + rc = pci_enable_device(pci_dev); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to enable PCI device\n"); + goto fail1; + } + + pci_set_master(pci_dev); + + /* Set the PCI DMA mask. Try all possibilities from our + * genuine mask down to 32 bits, because some architectures + * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit + * masks event though they reject 46 bit masks. + */ + while (dma_mask > 0x7fffffffUL) { + if (pci_dma_supported(pci_dev, dma_mask) && + ((rc = pci_set_dma_mask(pci_dev, dma_mask)) == 0)) + break; + dma_mask >>= 1; + } + if (rc) { + netif_err(efx, probe, efx->net_dev, + "could not find a suitable DMA mask\n"); + goto fail2; + } + netif_dbg(efx, probe, efx->net_dev, + "using DMA mask %llx\n", (unsigned long long) dma_mask); + rc = pci_set_consistent_dma_mask(pci_dev, dma_mask); + if (rc) { + /* pci_set_consistent_dma_mask() is not *allowed* to + * fail with a mask that pci_set_dma_mask() accepted, + * but just in case... + */ + netif_err(efx, probe, efx->net_dev, + "failed to set consistent DMA mask\n"); + goto fail2; + } + + efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR); + rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc"); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "request for memory BAR failed\n"); + rc = -EIO; + goto fail3; + } + efx->membase = ioremap_nocache(efx->membase_phys, + efx->type->mem_map_size); + if (!efx->membase) { + netif_err(efx, probe, efx->net_dev, + "could not map memory BAR at %llx+%x\n", + (unsigned long long)efx->membase_phys, + efx->type->mem_map_size); + rc = -ENOMEM; + goto fail4; + } + netif_dbg(efx, probe, efx->net_dev, + "memory BAR at %llx+%x (virtual %p)\n", + (unsigned long long)efx->membase_phys, + efx->type->mem_map_size, efx->membase); + + return 0; + + fail4: + pci_release_region(efx->pci_dev, EFX_MEM_BAR); + fail3: + efx->membase_phys = 0; + fail2: + pci_disable_device(efx->pci_dev); + fail1: + return rc; +} + +static void efx_fini_io(struct efx_nic *efx) +{ + netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n"); + + if (efx->membase) { + iounmap(efx->membase); + efx->membase = NULL; + } + + if (efx->membase_phys) { + pci_release_region(efx->pci_dev, EFX_MEM_BAR); + efx->membase_phys = 0; + } + + pci_disable_device(efx->pci_dev); +} + +/* Get number of channels wanted. Each channel will have its own IRQ, + * 1 RX queue and/or 2 TX queues. */ +static int efx_wanted_channels(void) +{ + cpumask_var_t core_mask; + int count; + int cpu; + + if (rss_cpus) + return rss_cpus; + + if (unlikely(!zalloc_cpumask_var(&core_mask, GFP_KERNEL))) { + printk(KERN_WARNING + "sfc: RSS disabled due to allocation failure\n"); + return 1; + } + + count = 0; + for_each_online_cpu(cpu) { + if (!cpumask_test_cpu(cpu, core_mask)) { + ++count; + cpumask_or(core_mask, core_mask, + topology_core_cpumask(cpu)); + } + } + + free_cpumask_var(core_mask); + return count; +} + +static int +efx_init_rx_cpu_rmap(struct efx_nic *efx, struct msix_entry *xentries) +{ +#ifdef CONFIG_RFS_ACCEL + int i, rc; + + efx->net_dev->rx_cpu_rmap = alloc_irq_cpu_rmap(efx->n_rx_channels); + if (!efx->net_dev->rx_cpu_rmap) + return -ENOMEM; + for (i = 0; i < efx->n_rx_channels; i++) { + rc = irq_cpu_rmap_add(efx->net_dev->rx_cpu_rmap, + xentries[i].vector); + if (rc) { + free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); + efx->net_dev->rx_cpu_rmap = NULL; + return rc; + } + } +#endif + return 0; +} + +/* Probe the number and type of interrupts we are able to obtain, and + * the resulting numbers of channels and RX queues. + */ +static int efx_probe_interrupts(struct efx_nic *efx) +{ + int max_channels = + min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS); + int rc, i; + + if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { + struct msix_entry xentries[EFX_MAX_CHANNELS]; + int n_channels; + + n_channels = efx_wanted_channels(); + if (separate_tx_channels) + n_channels *= 2; + n_channels = min(n_channels, max_channels); + + for (i = 0; i < n_channels; i++) + xentries[i].entry = i; + rc = pci_enable_msix(efx->pci_dev, xentries, n_channels); + if (rc > 0) { + netif_err(efx, drv, efx->net_dev, + "WARNING: Insufficient MSI-X vectors" + " available (%d < %d).\n", rc, n_channels); + netif_err(efx, drv, efx->net_dev, + "WARNING: Performance may be reduced.\n"); + EFX_BUG_ON_PARANOID(rc >= n_channels); + n_channels = rc; + rc = pci_enable_msix(efx->pci_dev, xentries, + n_channels); + } + + if (rc == 0) { + efx->n_channels = n_channels; + if (separate_tx_channels) { + efx->n_tx_channels = + max(efx->n_channels / 2, 1U); + efx->n_rx_channels = + max(efx->n_channels - + efx->n_tx_channels, 1U); + } else { + efx->n_tx_channels = efx->n_channels; + efx->n_rx_channels = efx->n_channels; + } + rc = efx_init_rx_cpu_rmap(efx, xentries); + if (rc) { + pci_disable_msix(efx->pci_dev); + return rc; + } + for (i = 0; i < n_channels; i++) + efx_get_channel(efx, i)->irq = + xentries[i].vector; + } else { + /* Fall back to single channel MSI */ + efx->interrupt_mode = EFX_INT_MODE_MSI; + netif_err(efx, drv, efx->net_dev, + "could not enable MSI-X\n"); + } + } + + /* Try single interrupt MSI */ + if (efx->interrupt_mode == EFX_INT_MODE_MSI) { + efx->n_channels = 1; + efx->n_rx_channels = 1; + efx->n_tx_channels = 1; + rc = pci_enable_msi(efx->pci_dev); + if (rc == 0) { + efx_get_channel(efx, 0)->irq = efx->pci_dev->irq; + } else { + netif_err(efx, drv, efx->net_dev, + "could not enable MSI\n"); + efx->interrupt_mode = EFX_INT_MODE_LEGACY; + } + } + + /* Assume legacy interrupts */ + if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) { + efx->n_channels = 1 + (separate_tx_channels ? 1 : 0); + efx->n_rx_channels = 1; + efx->n_tx_channels = 1; + efx->legacy_irq = efx->pci_dev->irq; + } + + return 0; +} + +static void efx_remove_interrupts(struct efx_nic *efx) +{ + struct efx_channel *channel; + + /* Remove MSI/MSI-X interrupts */ + efx_for_each_channel(channel, efx) + channel->irq = 0; + pci_disable_msi(efx->pci_dev); + pci_disable_msix(efx->pci_dev); + + /* Remove legacy interrupt */ + efx->legacy_irq = 0; +} + +static void efx_set_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + + efx->tx_channel_offset = + separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; + + /* We need to adjust the TX queue numbers if we have separate + * RX-only and TX-only channels. + */ + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) + tx_queue->queue -= (efx->tx_channel_offset * + EFX_TXQ_TYPES); + } +} + +static int efx_probe_nic(struct efx_nic *efx) +{ + size_t i; + int rc; + + netif_dbg(efx, probe, efx->net_dev, "creating NIC\n"); + + /* Carry out hardware-type specific initialisation */ + rc = efx->type->probe(efx); + if (rc) + return rc; + + /* Determine the number of channels and queues by trying to hook + * in MSI-X interrupts. */ + rc = efx_probe_interrupts(efx); + if (rc) + goto fail; + + if (efx->n_channels > 1) + get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); + for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) + efx->rx_indir_table[i] = i % efx->n_rx_channels; + + efx_set_channels(efx); + netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); + netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); + + /* Initialise the interrupt moderation settings */ + efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true, + true); + + return 0; + +fail: + efx->type->remove(efx); + return rc; +} + +static void efx_remove_nic(struct efx_nic *efx) +{ + netif_dbg(efx, drv, efx->net_dev, "destroying NIC\n"); + + efx_remove_interrupts(efx); + efx->type->remove(efx); +} + +/************************************************************************** + * + * NIC startup/shutdown + * + *************************************************************************/ + +static int efx_probe_all(struct efx_nic *efx) +{ + int rc; + + rc = efx_probe_nic(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, "failed to create NIC\n"); + goto fail1; + } + + rc = efx_probe_port(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, "failed to create port\n"); + goto fail2; + } + + efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; + rc = efx_probe_channels(efx); + if (rc) + goto fail3; + + rc = efx_probe_filters(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to create filter tables\n"); + goto fail4; + } + + return 0; + + fail4: + efx_remove_channels(efx); + fail3: + efx_remove_port(efx); + fail2: + efx_remove_nic(efx); + fail1: + return rc; +} + +/* Called after previous invocation(s) of efx_stop_all, restarts the + * port, kernel transmit queue, NAPI processing and hardware interrupts, + * and ensures that the port is scheduled to be reconfigured. + * This function is safe to call multiple times when the NIC is in any + * state. */ +static void efx_start_all(struct efx_nic *efx) +{ + struct efx_channel *channel; + + EFX_ASSERT_RESET_SERIALISED(efx); + + /* Check that it is appropriate to restart the interface. All + * of these flags are safe to read under just the rtnl lock */ + if (efx->port_enabled) + return; + if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT)) + return; + if (efx_dev_registered(efx) && !netif_running(efx->net_dev)) + return; + + /* Mark the port as enabled so port reconfigurations can start, then + * restart the transmit interface early so the watchdog timer stops */ + efx_start_port(efx); + + if (efx_dev_registered(efx) && netif_device_present(efx->net_dev)) + netif_tx_wake_all_queues(efx->net_dev); + + efx_for_each_channel(channel, efx) + efx_start_channel(channel); + + if (efx->legacy_irq) + efx->legacy_irq_enabled = true; + efx_nic_enable_interrupts(efx); + + /* Switch to event based MCDI completions after enabling interrupts. + * If a reset has been scheduled, then we need to stay in polled mode. + * Rather than serialising efx_mcdi_mode_event() [which sleeps] and + * reset_pending [modified from an atomic context], we instead guarantee + * that efx_mcdi_mode_poll() isn't reverted erroneously */ + efx_mcdi_mode_event(efx); + if (efx->reset_pending) + efx_mcdi_mode_poll(efx); + + /* Start the hardware monitor if there is one. Otherwise (we're link + * event driven), we have to poll the PHY because after an event queue + * flush, we could have a missed a link state change */ + if (efx->type->monitor != NULL) { + queue_delayed_work(efx->workqueue, &efx->monitor_work, + efx_monitor_interval); + } else { + mutex_lock(&efx->mac_lock); + if (efx->phy_op->poll(efx)) + efx_link_status_changed(efx); + mutex_unlock(&efx->mac_lock); + } + + efx->type->start_stats(efx); +} + +/* Flush all delayed work. Should only be called when no more delayed work + * will be scheduled. This doesn't flush pending online resets (efx_reset), + * since we're holding the rtnl_lock at this point. */ +static void efx_flush_all(struct efx_nic *efx) +{ + /* Make sure the hardware monitor is stopped */ + cancel_delayed_work_sync(&efx->monitor_work); + /* Stop scheduled port reconfigurations */ + cancel_work_sync(&efx->mac_work); +} + +/* Quiesce hardware and software without bringing the link down. + * Safe to call multiple times, when the nic and interface is in any + * state. The caller is guaranteed to subsequently be in a position + * to modify any hardware and software state they see fit without + * taking locks. */ +static void efx_stop_all(struct efx_nic *efx) +{ + struct efx_channel *channel; + + EFX_ASSERT_RESET_SERIALISED(efx); + + /* port_enabled can be read safely under the rtnl lock */ + if (!efx->port_enabled) + return; + + efx->type->stop_stats(efx); + + /* Switch to MCDI polling on Siena before disabling interrupts */ + efx_mcdi_mode_poll(efx); + + /* Disable interrupts and wait for ISR to complete */ + efx_nic_disable_interrupts(efx); + if (efx->legacy_irq) { + synchronize_irq(efx->legacy_irq); + efx->legacy_irq_enabled = false; + } + efx_for_each_channel(channel, efx) { + if (channel->irq) + synchronize_irq(channel->irq); + } + + /* Stop all NAPI processing and synchronous rx refills */ + efx_for_each_channel(channel, efx) + efx_stop_channel(channel); + + /* Stop all asynchronous port reconfigurations. Since all + * event processing has already been stopped, there is no + * window to loose phy events */ + efx_stop_port(efx); + + /* Flush efx_mac_work(), refill_workqueue, monitor_work */ + efx_flush_all(efx); + + /* Stop the kernel transmit interface late, so the watchdog + * timer isn't ticking over the flush */ + if (efx_dev_registered(efx)) { + netif_tx_stop_all_queues(efx->net_dev); + netif_tx_lock_bh(efx->net_dev); + netif_tx_unlock_bh(efx->net_dev); + } +} + +static void efx_remove_all(struct efx_nic *efx) +{ + efx_remove_filters(efx); + efx_remove_channels(efx); + efx_remove_port(efx); + efx_remove_nic(efx); +} + +/************************************************************************** + * + * Interrupt moderation + * + **************************************************************************/ + +static unsigned int irq_mod_ticks(unsigned int usecs, unsigned int resolution) +{ + if (usecs == 0) + return 0; + if (usecs < resolution) + return 1; /* never round down to 0 */ + return usecs / resolution; +} + +/* Set interrupt moderation parameters */ +int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, + unsigned int rx_usecs, bool rx_adaptive, + bool rx_may_override_tx) +{ + struct efx_channel *channel; + unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); + unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION); + + EFX_ASSERT_RESET_SERIALISED(efx); + + if (tx_ticks > EFX_IRQ_MOD_MAX || rx_ticks > EFX_IRQ_MOD_MAX) + return -EINVAL; + + if (tx_ticks != rx_ticks && efx->tx_channel_offset == 0 && + !rx_may_override_tx) { + netif_err(efx, drv, efx->net_dev, "Channels are shared. " + "RX and TX IRQ moderation must be equal\n"); + return -EINVAL; + } + + efx->irq_rx_adaptive = rx_adaptive; + efx->irq_rx_moderation = rx_ticks; + efx_for_each_channel(channel, efx) { + if (efx_channel_has_rx_queue(channel)) + channel->irq_moderation = rx_ticks; + else if (efx_channel_has_tx_queues(channel)) + channel->irq_moderation = tx_ticks; + } + + return 0; +} + +void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, + unsigned int *rx_usecs, bool *rx_adaptive) +{ + *rx_adaptive = efx->irq_rx_adaptive; + *rx_usecs = efx->irq_rx_moderation * EFX_IRQ_MOD_RESOLUTION; + + /* If channels are shared between RX and TX, so is IRQ + * moderation. Otherwise, IRQ moderation is the same for all + * TX channels and is not adaptive. + */ + if (efx->tx_channel_offset == 0) + *tx_usecs = *rx_usecs; + else + *tx_usecs = + efx->channel[efx->tx_channel_offset]->irq_moderation * + EFX_IRQ_MOD_RESOLUTION; +} + +/************************************************************************** + * + * Hardware monitor + * + **************************************************************************/ + +/* Run periodically off the general workqueue */ +static void efx_monitor(struct work_struct *data) +{ + struct efx_nic *efx = container_of(data, struct efx_nic, + monitor_work.work); + + netif_vdbg(efx, timer, efx->net_dev, + "hardware monitor executing on CPU %d\n", + raw_smp_processor_id()); + BUG_ON(efx->type->monitor == NULL); + + /* If the mac_lock is already held then it is likely a port + * reconfiguration is already in place, which will likely do + * most of the work of monitor() anyway. */ + if (mutex_trylock(&efx->mac_lock)) { + if (efx->port_enabled) + efx->type->monitor(efx); + mutex_unlock(&efx->mac_lock); + } + + queue_delayed_work(efx->workqueue, &efx->monitor_work, + efx_monitor_interval); +} + +/************************************************************************** + * + * ioctls + * + *************************************************************************/ + +/* Net device ioctl + * Context: process, rtnl_lock() held. + */ +static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct mii_ioctl_data *data = if_mii(ifr); + + EFX_ASSERT_RESET_SERIALISED(efx); + + /* Convert phy_id from older PRTAD/DEVAD format */ + if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && + (data->phy_id & 0xfc00) == 0x0400) + data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400; + + return mdio_mii_ioctl(&efx->mdio, data, cmd); +} + +/************************************************************************** + * + * NAPI interface + * + **************************************************************************/ + +static void efx_init_napi(struct efx_nic *efx) +{ + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) { + channel->napi_dev = efx->net_dev; + netif_napi_add(channel->napi_dev, &channel->napi_str, + efx_poll, napi_weight); + } +} + +static void efx_fini_napi_channel(struct efx_channel *channel) +{ + if (channel->napi_dev) + netif_napi_del(&channel->napi_str); + channel->napi_dev = NULL; +} + +static void efx_fini_napi(struct efx_nic *efx) +{ + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) + efx_fini_napi_channel(channel); +} + +/************************************************************************** + * + * Kernel netpoll interface + * + *************************************************************************/ + +#ifdef CONFIG_NET_POLL_CONTROLLER + +/* Although in the common case interrupts will be disabled, this is not + * guaranteed. However, all our work happens inside the NAPI callback, + * so no locking is required. + */ +static void efx_netpoll(struct net_device *net_dev) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) + efx_schedule_channel(channel); +} + +#endif + +/************************************************************************** + * + * Kernel net device interface + * + *************************************************************************/ + +/* Context: process, rtnl_lock() held. */ +static int efx_net_open(struct net_device *net_dev) +{ + struct efx_nic *efx = netdev_priv(net_dev); + EFX_ASSERT_RESET_SERIALISED(efx); + + netif_dbg(efx, ifup, efx->net_dev, "opening device on CPU %d\n", + raw_smp_processor_id()); + + if (efx->state == STATE_DISABLED) + return -EIO; + if (efx->phy_mode & PHY_MODE_SPECIAL) + return -EBUSY; + if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL)) + return -EIO; + + /* Notify the kernel of the link state polled during driver load, + * before the monitor starts running */ + efx_link_status_changed(efx); + + efx_start_all(efx); + return 0; +} + +/* Context: process, rtnl_lock() held. + * Note that the kernel will ignore our return code; this method + * should really be a void. + */ +static int efx_net_stop(struct net_device *net_dev) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n", + raw_smp_processor_id()); + + if (efx->state != STATE_DISABLED) { + /* Stop the device and flush all the channels */ + efx_stop_all(efx); + efx_fini_channels(efx); + efx_init_channels(efx); + } + + return 0; +} + +/* Context: process, dev_base_lock or RTNL held, non-blocking. */ +static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_mac_stats *mac_stats = &efx->mac_stats; + + spin_lock_bh(&efx->stats_lock); + efx->type->update_stats(efx); + spin_unlock_bh(&efx->stats_lock); + + stats->rx_packets = mac_stats->rx_packets; + stats->tx_packets = mac_stats->tx_packets; + stats->rx_bytes = mac_stats->rx_bytes; + stats->tx_bytes = mac_stats->tx_bytes; + stats->rx_dropped = efx->n_rx_nodesc_drop_cnt; + stats->multicast = mac_stats->rx_multicast; + stats->collisions = mac_stats->tx_collision; + stats->rx_length_errors = (mac_stats->rx_gtjumbo + + mac_stats->rx_length_error); + stats->rx_crc_errors = mac_stats->rx_bad; + stats->rx_frame_errors = mac_stats->rx_align_error; + stats->rx_fifo_errors = mac_stats->rx_overflow; + stats->rx_missed_errors = mac_stats->rx_missed; + stats->tx_window_errors = mac_stats->tx_late_collision; + + stats->rx_errors = (stats->rx_length_errors + + stats->rx_crc_errors + + stats->rx_frame_errors + + mac_stats->rx_symbol_error); + stats->tx_errors = (stats->tx_window_errors + + mac_stats->tx_bad); + + return stats; +} + +/* Context: netif_tx_lock held, BHs disabled. */ +static void efx_watchdog(struct net_device *net_dev) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + netif_err(efx, tx_err, efx->net_dev, + "TX stuck with port_enabled=%d: resetting channels\n", + efx->port_enabled); + + efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG); +} + + +/* Context: process, rtnl_lock() held. */ +static int efx_change_mtu(struct net_device *net_dev, int new_mtu) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int rc = 0; + + EFX_ASSERT_RESET_SERIALISED(efx); + + if (new_mtu > EFX_MAX_MTU) + return -EINVAL; + + efx_stop_all(efx); + + netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu); + + efx_fini_channels(efx); + + mutex_lock(&efx->mac_lock); + /* Reconfigure the MAC before enabling the dma queues so that + * the RX buffers don't overflow */ + net_dev->mtu = new_mtu; + efx->mac_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); + + efx_init_channels(efx); + + efx_start_all(efx); + return rc; +} + +static int efx_set_mac_address(struct net_device *net_dev, void *data) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct sockaddr *addr = data; + char *new_addr = addr->sa_data; + + EFX_ASSERT_RESET_SERIALISED(efx); + + if (!is_valid_ether_addr(new_addr)) { + netif_err(efx, drv, efx->net_dev, + "invalid ethernet MAC address requested: %pM\n", + new_addr); + return -EINVAL; + } + + memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); + + /* Reconfigure the MAC */ + mutex_lock(&efx->mac_lock); + efx->mac_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); + + return 0; +} + +/* Context: netif_addr_lock held, BHs disabled. */ +static void efx_set_multicast_list(struct net_device *net_dev) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct netdev_hw_addr *ha; + union efx_multicast_hash *mc_hash = &efx->multicast_hash; + u32 crc; + int bit; + + efx->promiscuous = !!(net_dev->flags & IFF_PROMISC); + + /* Build multicast hash table */ + if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) { + memset(mc_hash, 0xff, sizeof(*mc_hash)); + } else { + memset(mc_hash, 0x00, sizeof(*mc_hash)); + netdev_for_each_mc_addr(ha, net_dev) { + crc = ether_crc_le(ETH_ALEN, ha->addr); + bit = crc & (EFX_MCAST_HASH_ENTRIES - 1); + set_bit_le(bit, mc_hash->byte); + } + + /* Broadcast packets go through the multicast hash filter. + * ether_crc_le() of the broadcast address is 0xbe2612ff + * so we always add bit 0xff to the mask. + */ + set_bit_le(0xff, mc_hash->byte); + } + + if (efx->port_enabled) + queue_work(efx->workqueue, &efx->mac_work); + /* Otherwise efx_start_port() will do this */ +} + +static int efx_set_features(struct net_device *net_dev, u32 data) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + /* If disabling RX n-tuple filtering, clear existing filters */ + if (net_dev->features & ~data & NETIF_F_NTUPLE) + efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); + + return 0; +} + +static const struct net_device_ops efx_netdev_ops = { + .ndo_open = efx_net_open, + .ndo_stop = efx_net_stop, + .ndo_get_stats64 = efx_net_stats, + .ndo_tx_timeout = efx_watchdog, + .ndo_start_xmit = efx_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = efx_ioctl, + .ndo_change_mtu = efx_change_mtu, + .ndo_set_mac_address = efx_set_mac_address, + .ndo_set_rx_mode = efx_set_multicast_list, + .ndo_set_features = efx_set_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = efx_netpoll, +#endif + .ndo_setup_tc = efx_setup_tc, +#ifdef CONFIG_RFS_ACCEL + .ndo_rx_flow_steer = efx_filter_rfs, +#endif +}; + +static void efx_update_name(struct efx_nic *efx) +{ + strcpy(efx->name, efx->net_dev->name); + efx_mtd_rename(efx); + efx_set_channel_names(efx); +} + +static int efx_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *net_dev = ptr; + + if (net_dev->netdev_ops == &efx_netdev_ops && + event == NETDEV_CHANGENAME) + efx_update_name(netdev_priv(net_dev)); + + return NOTIFY_DONE; +} + +static struct notifier_block efx_netdev_notifier = { + .notifier_call = efx_netdev_event, +}; + +static ssize_t +show_phy_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + return sprintf(buf, "%d\n", efx->phy_type); +} +static DEVICE_ATTR(phy_type, 0644, show_phy_type, NULL); + +static int efx_register_netdev(struct efx_nic *efx) +{ + struct net_device *net_dev = efx->net_dev; + struct efx_channel *channel; + int rc; + + net_dev->watchdog_timeo = 5 * HZ; + net_dev->irq = efx->pci_dev->irq; + net_dev->netdev_ops = &efx_netdev_ops; + SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); + + /* Clear MAC statistics */ + efx->mac_op->update_stats(efx); + memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); + + rtnl_lock(); + + rc = dev_alloc_name(net_dev, net_dev->name); + if (rc < 0) + goto fail_locked; + efx_update_name(efx); + + rc = register_netdevice(net_dev); + if (rc) + goto fail_locked; + + efx_for_each_channel(channel, efx) { + struct efx_tx_queue *tx_queue; + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_init_tx_queue_core_txq(tx_queue); + } + + /* Always start with carrier off; PHY events will detect the link */ + netif_carrier_off(efx->net_dev); + + rtnl_unlock(); + + rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type); + if (rc) { + netif_err(efx, drv, efx->net_dev, + "failed to init net dev attributes\n"); + goto fail_registered; + } + + return 0; + +fail_locked: + rtnl_unlock(); + netif_err(efx, drv, efx->net_dev, "could not register net dev\n"); + return rc; + +fail_registered: + unregister_netdev(net_dev); + return rc; +} + +static void efx_unregister_netdev(struct efx_nic *efx) +{ + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + + if (!efx->net_dev) + return; + + BUG_ON(netdev_priv(efx->net_dev) != efx); + + /* Free up any skbs still remaining. This has to happen before + * we try to unregister the netdev as running their destructors + * may be needed to get the device ref. count to 0. */ + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_release_tx_buffers(tx_queue); + } + + if (efx_dev_registered(efx)) { + strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type); + unregister_netdev(efx->net_dev); + } +} + +/************************************************************************** + * + * Device reset and suspend + * + **************************************************************************/ + +/* Tears down the entire software state and most of the hardware state + * before reset. */ +void efx_reset_down(struct efx_nic *efx, enum reset_type method) +{ + EFX_ASSERT_RESET_SERIALISED(efx); + + efx_stop_all(efx); + mutex_lock(&efx->mac_lock); + + efx_fini_channels(efx); + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) + efx->phy_op->fini(efx); + efx->type->fini(efx); +} + +/* This function will always ensure that the locks acquired in + * efx_reset_down() are released. A failure return code indicates + * that we were unable to reinitialise the hardware, and the + * driver should be disabled. If ok is false, then the rx and tx + * engines are not restarted, pending a RESET_DISABLE. */ +int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) +{ + int rc; + + EFX_ASSERT_RESET_SERIALISED(efx); + + rc = efx->type->init(efx); + if (rc) { + netif_err(efx, drv, efx->net_dev, "failed to initialise NIC\n"); + goto fail; + } + + if (!ok) + goto fail; + + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { + rc = efx->phy_op->init(efx); + if (rc) + goto fail; + if (efx->phy_op->reconfigure(efx)) + netif_err(efx, drv, efx->net_dev, + "could not restore PHY settings\n"); + } + + efx->mac_op->reconfigure(efx); + + efx_init_channels(efx); + efx_restore_filters(efx); + + mutex_unlock(&efx->mac_lock); + + efx_start_all(efx); + + return 0; + +fail: + efx->port_initialized = false; + + mutex_unlock(&efx->mac_lock); + + return rc; +} + +/* Reset the NIC using the specified method. Note that the reset may + * fail, in which case the card will be left in an unusable state. + * + * Caller must hold the rtnl_lock. + */ +int efx_reset(struct efx_nic *efx, enum reset_type method) +{ + int rc, rc2; + bool disabled; + + netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", + RESET_TYPE(method)); + + netif_device_detach(efx->net_dev); + efx_reset_down(efx, method); + + rc = efx->type->reset(efx, method); + if (rc) { + netif_err(efx, drv, efx->net_dev, "failed to reset hardware\n"); + goto out; + } + + /* Clear flags for the scopes we covered. We assume the NIC and + * driver are now quiescent so that there is no race here. + */ + efx->reset_pending &= -(1 << (method + 1)); + + /* Reinitialise bus-mastering, which may have been turned off before + * the reset was scheduled. This is still appropriate, even in the + * RESET_TYPE_DISABLE since this driver generally assumes the hardware + * can respond to requests. */ + pci_set_master(efx->pci_dev); + +out: + /* Leave device stopped if necessary */ + disabled = rc || method == RESET_TYPE_DISABLE; + rc2 = efx_reset_up(efx, method, !disabled); + if (rc2) { + disabled = true; + if (!rc) + rc = rc2; + } + + if (disabled) { + dev_close(efx->net_dev); + netif_err(efx, drv, efx->net_dev, "has been disabled\n"); + efx->state = STATE_DISABLED; + } else { + netif_dbg(efx, drv, efx->net_dev, "reset complete\n"); + netif_device_attach(efx->net_dev); + } + return rc; +} + +/* The worker thread exists so that code that cannot sleep can + * schedule a reset for later. + */ +static void efx_reset_work(struct work_struct *data) +{ + struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); + unsigned long pending = ACCESS_ONCE(efx->reset_pending); + + if (!pending) + return; + + /* If we're not RUNNING then don't reset. Leave the reset_pending + * flags set so that efx_pci_probe_main will be retried */ + if (efx->state != STATE_RUNNING) { + netif_info(efx, drv, efx->net_dev, + "scheduled reset quenched. NIC not RUNNING\n"); + return; + } + + rtnl_lock(); + (void)efx_reset(efx, fls(pending) - 1); + rtnl_unlock(); +} + +void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) +{ + enum reset_type method; + + switch (type) { + case RESET_TYPE_INVISIBLE: + case RESET_TYPE_ALL: + case RESET_TYPE_WORLD: + case RESET_TYPE_DISABLE: + method = type; + netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n", + RESET_TYPE(method)); + break; + default: + method = efx->type->map_reset_reason(type); + netif_dbg(efx, drv, efx->net_dev, + "scheduling %s reset for %s\n", + RESET_TYPE(method), RESET_TYPE(type)); + break; + } + + set_bit(method, &efx->reset_pending); + + /* efx_process_channel() will no longer read events once a + * reset is scheduled. So switch back to poll'd MCDI completions. */ + efx_mcdi_mode_poll(efx); + + queue_work(reset_workqueue, &efx->reset_work); +} + +/************************************************************************** + * + * List of NICs we support + * + **************************************************************************/ + +/* PCI device ID table */ +static DEFINE_PCI_DEVICE_TABLE(efx_pci_table) = { - {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID), ++ {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, ++ PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0), + .driver_data = (unsigned long) &falcon_a1_nic_type}, - {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), ++ {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, ++ PCI_DEVICE_ID_SOLARFLARE_SFC4000B), + .driver_data = (unsigned long) &falcon_b0_nic_type}, - {PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID), ++ {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, BETHPAGE_A_P_DEVID), + .driver_data = (unsigned long) &siena_a0_nic_type}, - {PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID), ++ {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, SIENA_A_P_DEVID), + .driver_data = (unsigned long) &siena_a0_nic_type}, + {0} /* end of list */ +}; + +/************************************************************************** + * + * Dummy PHY/MAC operations + * + * Can be used for some unimplemented operations + * Needed so all function pointers are valid and do not have to be tested + * before use + * + **************************************************************************/ +int efx_port_dummy_op_int(struct efx_nic *efx) +{ + return 0; +} +void efx_port_dummy_op_void(struct efx_nic *efx) {} + +static bool efx_port_dummy_op_poll(struct efx_nic *efx) +{ + return false; +} + +static const struct efx_phy_operations efx_dummy_phy_operations = { + .init = efx_port_dummy_op_int, + .reconfigure = efx_port_dummy_op_int, + .poll = efx_port_dummy_op_poll, + .fini = efx_port_dummy_op_void, +}; + +/************************************************************************** + * + * Data housekeeping + * + **************************************************************************/ + +/* This zeroes out and then fills in the invariants in a struct + * efx_nic (including all sub-structures). + */ +static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type, + struct pci_dev *pci_dev, struct net_device *net_dev) +{ + int i; + + /* Initialise common structures */ + memset(efx, 0, sizeof(*efx)); + spin_lock_init(&efx->biu_lock); +#ifdef CONFIG_SFC_MTD + INIT_LIST_HEAD(&efx->mtd_list); +#endif + INIT_WORK(&efx->reset_work, efx_reset_work); + INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); + efx->pci_dev = pci_dev; + efx->msg_enable = debug; + efx->state = STATE_INIT; + strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); + + efx->net_dev = net_dev; + spin_lock_init(&efx->stats_lock); + mutex_init(&efx->mac_lock); + efx->mac_op = type->default_mac_ops; + efx->phy_op = &efx_dummy_phy_operations; + efx->mdio.dev = net_dev; + INIT_WORK(&efx->mac_work, efx_mac_work); + + for (i = 0; i < EFX_MAX_CHANNELS; i++) { + efx->channel[i] = efx_alloc_channel(efx, i, NULL); + if (!efx->channel[i]) + goto fail; + } + + efx->type = type; + + EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS); + + /* Higher numbered interrupt modes are less capable! */ + efx->interrupt_mode = max(efx->type->max_interrupt_mode, + interrupt_mode); + + /* Would be good to use the net_dev name, but we're too early */ + snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s", + pci_name(pci_dev)); + efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); + if (!efx->workqueue) + goto fail; + + return 0; + +fail: + efx_fini_struct(efx); + return -ENOMEM; +} + +static void efx_fini_struct(struct efx_nic *efx) +{ + int i; + + for (i = 0; i < EFX_MAX_CHANNELS; i++) + kfree(efx->channel[i]); + + if (efx->workqueue) { + destroy_workqueue(efx->workqueue); + efx->workqueue = NULL; + } +} + +/************************************************************************** + * + * PCI interface + * + **************************************************************************/ + +/* Main body of final NIC shutdown code + * This is called only at module unload (or hotplug removal). + */ +static void efx_pci_remove_main(struct efx_nic *efx) +{ +#ifdef CONFIG_RFS_ACCEL + free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); + efx->net_dev->rx_cpu_rmap = NULL; +#endif + efx_nic_fini_interrupt(efx); + efx_fini_channels(efx); + efx_fini_port(efx); + efx->type->fini(efx); + efx_fini_napi(efx); + efx_remove_all(efx); +} + +/* Final NIC shutdown + * This is called only at module unload (or hotplug removal). + */ +static void efx_pci_remove(struct pci_dev *pci_dev) +{ + struct efx_nic *efx; + + efx = pci_get_drvdata(pci_dev); + if (!efx) + return; + + /* Mark the NIC as fini, then stop the interface */ + rtnl_lock(); + efx->state = STATE_FINI; + dev_close(efx->net_dev); + + /* Allow any queued efx_resets() to complete */ + rtnl_unlock(); + + efx_unregister_netdev(efx); + + efx_mtd_remove(efx); + + /* Wait for any scheduled resets to complete. No more will be + * scheduled from this point because efx_stop_all() has been + * called, we are no longer registered with driverlink, and + * the net_device's have been removed. */ + cancel_work_sync(&efx->reset_work); + + efx_pci_remove_main(efx); + + efx_fini_io(efx); + netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n"); + + pci_set_drvdata(pci_dev, NULL); + efx_fini_struct(efx); + free_netdev(efx->net_dev); +}; + +/* Main body of NIC initialisation + * This is called at module load (or hotplug insertion, theoretically). + */ +static int efx_pci_probe_main(struct efx_nic *efx) +{ + int rc; + + /* Do start-of-day initialisation */ + rc = efx_probe_all(efx); + if (rc) + goto fail1; + + efx_init_napi(efx); + + rc = efx->type->init(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to initialise NIC\n"); + goto fail3; + } + + rc = efx_init_port(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to initialise port\n"); + goto fail4; + } + + efx_init_channels(efx); + + rc = efx_nic_init_interrupt(efx); + if (rc) + goto fail5; + + return 0; + + fail5: + efx_fini_channels(efx); + efx_fini_port(efx); + fail4: + efx->type->fini(efx); + fail3: + efx_fini_napi(efx); + efx_remove_all(efx); + fail1: + return rc; +} + +/* NIC initialisation + * + * This is called at module load (or hotplug insertion, + * theoretically). It sets up PCI mappings, tests and resets the NIC, + * sets up and registers the network devices with the kernel and hooks + * the interrupt service routine. It does not prepare the device for + * transmission; this is left to the first time one of the network + * interfaces is brought up (i.e. efx_net_open). + */ +static int __devinit efx_pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *entry) +{ + const struct efx_nic_type *type = (const struct efx_nic_type *) entry->driver_data; + struct net_device *net_dev; + struct efx_nic *efx; + int i, rc; + + /* Allocate and initialise a struct net_device and struct efx_nic */ + net_dev = alloc_etherdev_mqs(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES, + EFX_MAX_RX_QUEUES); + if (!net_dev) + return -ENOMEM; + net_dev->features |= (type->offload_features | NETIF_F_SG | + NETIF_F_HIGHDMA | NETIF_F_TSO | + NETIF_F_RXCSUM); + if (type->offload_features & NETIF_F_V6_CSUM) + net_dev->features |= NETIF_F_TSO6; + /* Mask for features that also apply to VLAN devices */ + net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | + NETIF_F_HIGHDMA | NETIF_F_ALL_TSO | + NETIF_F_RXCSUM); + /* All offloads can be toggled */ + net_dev->hw_features = net_dev->features & ~NETIF_F_HIGHDMA; + efx = netdev_priv(net_dev); + pci_set_drvdata(pci_dev, efx); + SET_NETDEV_DEV(net_dev, &pci_dev->dev); + rc = efx_init_struct(efx, type, pci_dev, net_dev); + if (rc) + goto fail1; + + netif_info(efx, probe, efx->net_dev, + "Solarflare NIC detected\n"); + + /* Set up basic I/O (BAR mappings etc) */ + rc = efx_init_io(efx); + if (rc) + goto fail2; + + /* No serialisation is required with the reset path because + * we're in STATE_INIT. */ + for (i = 0; i < 5; i++) { + rc = efx_pci_probe_main(efx); + + /* Serialise against efx_reset(). No more resets will be + * scheduled since efx_stop_all() has been called, and we + * have not and never have been registered with either + * the rtnetlink or driverlink layers. */ + cancel_work_sync(&efx->reset_work); + + if (rc == 0) { + if (efx->reset_pending) { + /* If there was a scheduled reset during + * probe, the NIC is probably hosed anyway */ + efx_pci_remove_main(efx); + rc = -EIO; + } else { + break; + } + } + + /* Retry if a recoverably reset event has been scheduled */ + if (efx->reset_pending & + ~(1 << RESET_TYPE_INVISIBLE | 1 << RESET_TYPE_ALL) || + !efx->reset_pending) + goto fail3; + + efx->reset_pending = 0; + } + + if (rc) { + netif_err(efx, probe, efx->net_dev, "Could not reset NIC\n"); + goto fail4; + } + + /* Switch to the running state before we expose the device to the OS, + * so that dev_open()|efx_start_all() will actually start the device */ + efx->state = STATE_RUNNING; + + rc = efx_register_netdev(efx); + if (rc) + goto fail5; + + netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n"); + + rtnl_lock(); + efx_mtd_probe(efx); /* allowed to fail */ + rtnl_unlock(); + return 0; + + fail5: + efx_pci_remove_main(efx); + fail4: + fail3: + efx_fini_io(efx); + fail2: + efx_fini_struct(efx); + fail1: + WARN_ON(rc > 0); + netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc); + free_netdev(net_dev); + return rc; +} + +static int efx_pm_freeze(struct device *dev) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + efx->state = STATE_FINI; + + netif_device_detach(efx->net_dev); + + efx_stop_all(efx); + efx_fini_channels(efx); + + return 0; +} + +static int efx_pm_thaw(struct device *dev) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + efx->state = STATE_INIT; + + efx_init_channels(efx); + + mutex_lock(&efx->mac_lock); + efx->phy_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); + + efx_start_all(efx); + + netif_device_attach(efx->net_dev); + + efx->state = STATE_RUNNING; + + efx->type->resume_wol(efx); + + /* Reschedule any quenched resets scheduled during efx_pm_freeze() */ + queue_work(reset_workqueue, &efx->reset_work); + + return 0; +} + +static int efx_pm_poweroff(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct efx_nic *efx = pci_get_drvdata(pci_dev); + + efx->type->fini(efx); + + efx->reset_pending = 0; + + pci_save_state(pci_dev); + return pci_set_power_state(pci_dev, PCI_D3hot); +} + +/* Used for both resume and restore */ +static int efx_pm_resume(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct efx_nic *efx = pci_get_drvdata(pci_dev); + int rc; + + rc = pci_set_power_state(pci_dev, PCI_D0); + if (rc) + return rc; + pci_restore_state(pci_dev); + rc = pci_enable_device(pci_dev); + if (rc) + return rc; + pci_set_master(efx->pci_dev); + rc = efx->type->reset(efx, RESET_TYPE_ALL); + if (rc) + return rc; + rc = efx->type->init(efx); + if (rc) + return rc; + efx_pm_thaw(dev); + return 0; +} + +static int efx_pm_suspend(struct device *dev) +{ + int rc; + + efx_pm_freeze(dev); + rc = efx_pm_poweroff(dev); + if (rc) + efx_pm_resume(dev); + return rc; +} + +static struct dev_pm_ops efx_pm_ops = { + .suspend = efx_pm_suspend, + .resume = efx_pm_resume, + .freeze = efx_pm_freeze, + .thaw = efx_pm_thaw, + .poweroff = efx_pm_poweroff, + .restore = efx_pm_resume, +}; + +static struct pci_driver efx_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = efx_pci_table, + .probe = efx_pci_probe, + .remove = efx_pci_remove, + .driver.pm = &efx_pm_ops, +}; + +/************************************************************************** + * + * Kernel module interface + * + *************************************************************************/ + +module_param(interrupt_mode, uint, 0444); +MODULE_PARM_DESC(interrupt_mode, + "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)"); + +static int __init efx_init_module(void) +{ + int rc; + + printk(KERN_INFO "Solarflare NET driver v" EFX_DRIVER_VERSION "\n"); + + rc = register_netdevice_notifier(&efx_netdev_notifier); + if (rc) + goto err_notifier; + + reset_workqueue = create_singlethread_workqueue("sfc_reset"); + if (!reset_workqueue) { + rc = -ENOMEM; + goto err_reset; + } + + rc = pci_register_driver(&efx_pci_driver); + if (rc < 0) + goto err_pci; + + return 0; + + err_pci: + destroy_workqueue(reset_workqueue); + err_reset: + unregister_netdevice_notifier(&efx_netdev_notifier); + err_notifier: + return rc; +} + +static void __exit efx_exit_module(void) +{ + printk(KERN_INFO "Solarflare NET driver unloading\n"); + + pci_unregister_driver(&efx_pci_driver); + destroy_workqueue(reset_workqueue); + unregister_netdevice_notifier(&efx_netdev_notifier); + +} + +module_init(efx_init_module); +module_exit(efx_exit_module); + +MODULE_AUTHOR("Solarflare Communications and " + "Michael Brown "); +MODULE_DESCRIPTION("Solarflare Communications network driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, efx_pci_table); diff --cc drivers/net/ethernet/sfc/efx.h index 442f4d0c247,00000000000..4764793ed23 mode 100644,000000..100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@@ -1,150 -1,0 +1,146 @@@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2010 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EFX_EFX_H +#define EFX_EFX_H + +#include "net_driver.h" +#include "filter.h" + +/* PCI IDs */ - #define EFX_VENDID_SFC 0x1924 - #define FALCON_A_P_DEVID 0x0703 - #define FALCON_A_S_DEVID 0x6703 - #define FALCON_B_P_DEVID 0x0710 +#define BETHPAGE_A_P_DEVID 0x0803 +#define SIENA_A_P_DEVID 0x0813 + +/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ +#define EFX_MEM_BAR 2 + +/* TX */ +extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue); +extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); +extern netdev_tx_t +efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +extern netdev_tx_t +efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); +extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); +extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc); + +/* RX */ +extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_rx_strategy(struct efx_channel *channel); +extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); +extern void efx_rx_slow_fill(unsigned long context); +extern void __efx_rx_packet(struct efx_channel *channel, + struct efx_rx_buffer *rx_buf, bool checksummed); +extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, + unsigned int len, bool checksummed, bool discard); +extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue); + +#define EFX_MAX_DMAQ_SIZE 4096UL +#define EFX_DEFAULT_DMAQ_SIZE 1024UL +#define EFX_MIN_DMAQ_SIZE 512UL + +#define EFX_MAX_EVQ_SIZE 16384UL +#define EFX_MIN_EVQ_SIZE 512UL + +/* The smallest [rt]xq_entries that the driver supports. Callers of + * efx_wake_queue() assume that they can subsequently send at least one + * skb. Falcon/A1 may require up to three descriptors per skb_frag. */ +#define EFX_MIN_RING_SIZE (roundup_pow_of_two(2 * 3 * MAX_SKB_FRAGS)) + +/* Filters */ +extern int efx_probe_filters(struct efx_nic *efx); +extern void efx_restore_filters(struct efx_nic *efx); +extern void efx_remove_filters(struct efx_nic *efx); +extern int efx_filter_insert_filter(struct efx_nic *efx, + struct efx_filter_spec *spec, + bool replace); +extern int efx_filter_remove_filter(struct efx_nic *efx, + struct efx_filter_spec *spec); +extern void efx_filter_clear_rx(struct efx_nic *efx, + enum efx_filter_priority priority); +#ifdef CONFIG_RFS_ACCEL +extern int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, + u16 rxq_index, u32 flow_id); +extern bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned quota); +static inline void efx_filter_rfs_expire(struct efx_channel *channel) +{ + if (channel->rfs_filters_added >= 60 && + __efx_filter_rfs_expire(channel->efx, 100)) + channel->rfs_filters_added -= 60; +} +#define efx_filter_rfs_enabled() 1 +#else +static inline void efx_filter_rfs_expire(struct efx_channel *channel) {} +#define efx_filter_rfs_enabled() 0 +#endif + +/* Channels */ +extern void efx_process_channel_now(struct efx_channel *channel); +extern int +efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries); + +/* Ports */ +extern int efx_reconfigure_port(struct efx_nic *efx); +extern int __efx_reconfigure_port(struct efx_nic *efx); + +/* Ethtool support */ +extern const struct ethtool_ops efx_ethtool_ops; + +/* Reset handling */ +extern int efx_reset(struct efx_nic *efx, enum reset_type method); +extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); +extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); + +/* Global */ +extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); +extern int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, + unsigned int rx_usecs, bool rx_adaptive, + bool rx_may_override_tx); +extern void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, + unsigned int *rx_usecs, bool *rx_adaptive); + +/* Dummy PHY ops for PHY drivers */ +extern int efx_port_dummy_op_int(struct efx_nic *efx); +extern void efx_port_dummy_op_void(struct efx_nic *efx); + + +/* MTD */ +#ifdef CONFIG_SFC_MTD +extern int efx_mtd_probe(struct efx_nic *efx); +extern void efx_mtd_rename(struct efx_nic *efx); +extern void efx_mtd_remove(struct efx_nic *efx); +#else +static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; } +static inline void efx_mtd_rename(struct efx_nic *efx) {} +static inline void efx_mtd_remove(struct efx_nic *efx) {} +#endif + +static inline void efx_schedule_channel(struct efx_channel *channel) +{ + netif_vdbg(channel->efx, intr, channel->efx->net_dev, + "channel %d scheduling NAPI poll on CPU%d\n", + channel->channel, raw_smp_processor_id()); + channel->work_pending = true; + + napi_schedule(&channel->napi_str); +} + +extern void efx_link_status_changed(struct efx_nic *efx); +extern void efx_link_set_advertising(struct efx_nic *efx, u32); +extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8); + +#endif /* EFX_EFX_H */ diff --cc drivers/net/ethernet/sfc/falcon.c index 4dd1748a19c,00000000000..97b606b92e8 mode 100644,000000..100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@@ -1,1843 -1,0 +1,1844 @@@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2010 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "net_driver.h" +#include "bitfield.h" +#include "efx.h" +#include "mac.h" +#include "spi.h" +#include "nic.h" +#include "regs.h" +#include "io.h" +#include "phy.h" +#include "workarounds.h" + +/* Hardware control for SFC4000 (aka Falcon). */ + +static const unsigned int +/* "Large" EEPROM device: Atmel AT25640 or similar + * 8 KB, 16-bit address, 32 B write block */ +large_eeprom_type = ((13 << SPI_DEV_TYPE_SIZE_LBN) + | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)), +/* Default flash device: Atmel AT25F1024 + * 128 KB, 24-bit address, 32 KB erase block, 256 B write block */ +default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) + | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN) + | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) + | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)); + +/************************************************************************** + * + * I2C bus - this is a bit-bashing interface using GPIO pins + * Note that it uses the output enables to tristate the outputs + * SDA is the data pin and SCL is the clock + * + ************************************************************************** + */ +static void falcon_setsda(void *data, int state) +{ + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + + efx_reado(efx, ®, FR_AB_GPIO_CTL); + EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state); + efx_writeo(efx, ®, FR_AB_GPIO_CTL); +} + +static void falcon_setscl(void *data, int state) +{ + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + + efx_reado(efx, ®, FR_AB_GPIO_CTL); + EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state); + efx_writeo(efx, ®, FR_AB_GPIO_CTL); +} + +static int falcon_getsda(void *data) +{ + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + + efx_reado(efx, ®, FR_AB_GPIO_CTL); + return EFX_OWORD_FIELD(reg, FRF_AB_GPIO3_IN); +} + +static int falcon_getscl(void *data) +{ + struct efx_nic *efx = (struct efx_nic *)data; + efx_oword_t reg; + + efx_reado(efx, ®, FR_AB_GPIO_CTL); + return EFX_OWORD_FIELD(reg, FRF_AB_GPIO0_IN); +} + +static struct i2c_algo_bit_data falcon_i2c_bit_operations = { + .setsda = falcon_setsda, + .setscl = falcon_setscl, + .getsda = falcon_getsda, + .getscl = falcon_getscl, + .udelay = 5, + /* Wait up to 50 ms for slave to let us pull SCL high */ + .timeout = DIV_ROUND_UP(HZ, 20), +}; + +static void falcon_push_irq_moderation(struct efx_channel *channel) +{ + efx_dword_t timer_cmd; + struct efx_nic *efx = channel->efx; + + BUILD_BUG_ON(EFX_IRQ_MOD_MAX > (1 << FRF_AB_TC_TIMER_VAL_WIDTH)); + + /* Set timer register */ + if (channel->irq_moderation) { + EFX_POPULATE_DWORD_2(timer_cmd, + FRF_AB_TC_TIMER_MODE, + FFE_BB_TIMER_MODE_INT_HLDOFF, + FRF_AB_TC_TIMER_VAL, + channel->irq_moderation - 1); + } else { + EFX_POPULATE_DWORD_2(timer_cmd, + FRF_AB_TC_TIMER_MODE, + FFE_BB_TIMER_MODE_DIS, + FRF_AB_TC_TIMER_VAL, 0); + } + BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0); + efx_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, + channel->channel); +} + +static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); + +static void falcon_prepare_flush(struct efx_nic *efx) +{ + falcon_deconfigure_mac_wrapper(efx); + + /* Wait for the tx and rx fifo's to get to the next packet boundary + * (~1ms without back-pressure), then to drain the remainder of the + * fifo's at data path speeds (negligible), with a healthy margin. */ + msleep(10); +} + +/* Acknowledge a legacy interrupt from Falcon + * + * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG. + * + * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the + * BIU. Interrupt acknowledge is read sensitive so must write instead + * (then read to ensure the BIU collector is flushed) + * + * NB most hardware supports MSI interrupts + */ +inline void falcon_irq_ack_a1(struct efx_nic *efx) +{ + efx_dword_t reg; + + EFX_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e); + efx_writed(efx, ®, FR_AA_INT_ACK_KER); + efx_readd(efx, ®, FR_AA_WORK_AROUND_BROKEN_PCI_READS); +} + + +irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) +{ + struct efx_nic *efx = dev_id; + efx_oword_t *int_ker = efx->irq_status.addr; + int syserr; + int queues; + + /* Check to see if this is our interrupt. If it isn't, we + * exit without having touched the hardware. + */ + if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) { + netif_vdbg(efx, intr, efx->net_dev, + "IRQ %d on CPU %d not for me\n", irq, + raw_smp_processor_id()); + return IRQ_NONE; + } + efx->last_irq_cpu = raw_smp_processor_id(); + netif_vdbg(efx, intr, efx->net_dev, + "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", + irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); + + /* Determine interrupting queues, clear interrupt status + * register and acknowledge the device interrupt. + */ + BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS); + queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q); + + /* Check to see if we have a serious error condition */ + if (queues & (1U << efx->fatal_irq_level)) { + syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); + if (unlikely(syserr)) + return efx_nic_fatal_interrupt(efx); + } + + EFX_ZERO_OWORD(*int_ker); + wmb(); /* Ensure the vector is cleared before interrupt ack */ + falcon_irq_ack_a1(efx); + + if (queues & 1) + efx_schedule_channel(efx_get_channel(efx, 0)); + if (queues & 2) + efx_schedule_channel(efx_get_channel(efx, 1)); + return IRQ_HANDLED; +} +/************************************************************************** + * + * EEPROM/flash + * + ************************************************************************** + */ + +#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t) + +static int falcon_spi_poll(struct efx_nic *efx) +{ + efx_oword_t reg; + efx_reado(efx, ®, FR_AB_EE_SPI_HCMD); + return EFX_OWORD_FIELD(reg, FRF_AB_EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; +} + +/* Wait for SPI command completion */ +static int falcon_spi_wait(struct efx_nic *efx) +{ + /* Most commands will finish quickly, so we start polling at + * very short intervals. Sometimes the command may have to + * wait for VPD or expansion ROM access outside of our + * control, so we allow up to 100 ms. */ + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10); + int i; + + for (i = 0; i < 10; i++) { + if (!falcon_spi_poll(efx)) + return 0; + udelay(10); + } + + for (;;) { + if (!falcon_spi_poll(efx)) + return 0; + if (time_after_eq(jiffies, timeout)) { + netif_err(efx, hw, efx->net_dev, + "timed out waiting for SPI\n"); + return -ETIMEDOUT; + } + schedule_timeout_uninterruptible(1); + } +} + +int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, + unsigned int command, int address, + const void *in, void *out, size_t len) +{ + bool addressed = (address >= 0); + bool reading = (out != NULL); + efx_oword_t reg; + int rc; + + /* Input validation */ + if (len > FALCON_SPI_MAX_LEN) + return -EINVAL; + + /* Check that previous command is not still running */ + rc = falcon_spi_poll(efx); + if (rc) + return rc; + + /* Program address register, if we have an address */ + if (addressed) { + EFX_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address); + efx_writeo(efx, ®, FR_AB_EE_SPI_HADR); + } + + /* Program data register, if we have data */ + if (in != NULL) { + memcpy(®, in, len); + efx_writeo(efx, ®, FR_AB_EE_SPI_HDATA); + } + + /* Issue read/write command */ + EFX_POPULATE_OWORD_7(reg, + FRF_AB_EE_SPI_HCMD_CMD_EN, 1, + FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id, + FRF_AB_EE_SPI_HCMD_DABCNT, len, + FRF_AB_EE_SPI_HCMD_READ, reading, + FRF_AB_EE_SPI_HCMD_DUBCNT, 0, + FRF_AB_EE_SPI_HCMD_ADBCNT, + (addressed ? spi->addr_len : 0), + FRF_AB_EE_SPI_HCMD_ENC, command); + efx_writeo(efx, ®, FR_AB_EE_SPI_HCMD); + + /* Wait for read/write to complete */ + rc = falcon_spi_wait(efx); + if (rc) + return rc; + + /* Read data */ + if (out != NULL) { + efx_reado(efx, ®, FR_AB_EE_SPI_HDATA); + memcpy(out, ®, len); + } + + return 0; +} + +static size_t +falcon_spi_write_limit(const struct efx_spi_device *spi, size_t start) +{ + return min(FALCON_SPI_MAX_LEN, + (spi->block_size - (start & (spi->block_size - 1)))); +} + +static inline u8 +efx_spi_munge_command(const struct efx_spi_device *spi, + const u8 command, const unsigned int address) +{ + return command | (((address >> 8) & spi->munge_address) << 3); +} + +/* Wait up to 10 ms for buffered write completion */ +int +falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi) +{ + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); + u8 status; + int rc; + + for (;;) { + rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); + if (rc) + return rc; + if (!(status & SPI_STATUS_NRDY)) + return 0; + if (time_after_eq(jiffies, timeout)) { + netif_err(efx, hw, efx->net_dev, + "SPI write timeout on device %d" + " last status=0x%02x\n", + spi->device_id, status); + return -ETIMEDOUT; + } + schedule_timeout_uninterruptible(1); + } +} + +int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi, + loff_t start, size_t len, size_t *retlen, u8 *buffer) +{ + size_t block_len, pos = 0; + unsigned int command; + int rc = 0; + + while (pos < len) { + block_len = min(len - pos, FALCON_SPI_MAX_LEN); + + command = efx_spi_munge_command(spi, SPI_READ, start + pos); + rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, + buffer + pos, block_len); + if (rc) + break; + pos += block_len; + + /* Avoid locking up the system */ + cond_resched(); + if (signal_pending(current)) { + rc = -EINTR; + break; + } + } + + if (retlen) + *retlen = pos; + return rc; +} + +int +falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi, + loff_t start, size_t len, size_t *retlen, const u8 *buffer) +{ + u8 verify_buffer[FALCON_SPI_MAX_LEN]; + size_t block_len, pos = 0; + unsigned int command; + int rc = 0; + + while (pos < len) { + rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + break; + + block_len = min(len - pos, + falcon_spi_write_limit(spi, start + pos)); + command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); + rc = falcon_spi_cmd(efx, spi, command, start + pos, + buffer + pos, NULL, block_len); + if (rc) + break; + + rc = falcon_spi_wait_write(efx, spi); + if (rc) + break; + + command = efx_spi_munge_command(spi, SPI_READ, start + pos); + rc = falcon_spi_cmd(efx, spi, command, start + pos, + NULL, verify_buffer, block_len); + if (memcmp(verify_buffer, buffer + pos, block_len)) { + rc = -EIO; + break; + } + + pos += block_len; + + /* Avoid locking up the system */ + cond_resched(); + if (signal_pending(current)) { + rc = -EINTR; + break; + } + } + + if (retlen) + *retlen = pos; + return rc; +} + +/************************************************************************** + * + * MAC wrapper + * + ************************************************************************** + */ + +static void falcon_push_multicast_hash(struct efx_nic *efx) +{ + union efx_multicast_hash *mc_hash = &efx->multicast_hash; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); + efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); +} + +static void falcon_reset_macs(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg, mac_ctrl; + int count; + + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { + /* It's not safe to use GLB_CTL_REG to reset the + * macs, so instead use the internal MAC resets + */ + EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); + efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); + + for (count = 0; count < 10000; count++) { + efx_reado(efx, ®, FR_AB_XM_GLB_CFG); + if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == + 0) + return; + udelay(10); + } + + netif_err(efx, hw, efx->net_dev, + "timed out waiting for XMAC core reset\n"); + } + + /* Mac stats will fail whist the TX fifo is draining */ + WARN_ON(nic_data->stats_disable_count == 0); + + efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL); + EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1); + efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); + + efx_reado(efx, ®, FR_AB_GLB_CTL); + EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1); + EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGRX, 1); + EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_EM, 1); + efx_writeo(efx, ®, FR_AB_GLB_CTL); + + count = 0; + while (1) { + efx_reado(efx, ®, FR_AB_GLB_CTL); + if (!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGTX) && + !EFX_OWORD_FIELD(reg, FRF_AB_RST_XGRX) && + !EFX_OWORD_FIELD(reg, FRF_AB_RST_EM)) { + netif_dbg(efx, hw, efx->net_dev, + "Completed MAC reset after %d loops\n", + count); + break; + } + if (count > 20) { + netif_err(efx, hw, efx->net_dev, "MAC reset failed\n"); + break; + } + count++; + udelay(10); + } + + /* Ensure the correct MAC is selected before statistics + * are re-enabled by the caller */ + efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); + + falcon_setup_xaui(efx); +} + +void falcon_drain_tx_fifo(struct efx_nic *efx) +{ + efx_oword_t reg; + + if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) || + (efx->loopback_mode != LOOPBACK_NONE)) + return; + + efx_reado(efx, ®, FR_AB_MAC_CTRL); + /* There is no point in draining more than once */ + if (EFX_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN)) + return; + + falcon_reset_macs(efx); +} + +static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) +{ + efx_oword_t reg; + + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) + return; + + /* Isolate the MAC -> RX */ + efx_reado(efx, ®, FR_AZ_RX_CFG); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0); + efx_writeo(efx, ®, FR_AZ_RX_CFG); + + /* Isolate TX -> MAC */ + falcon_drain_tx_fifo(efx); +} + +void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) +{ + struct efx_link_state *link_state = &efx->link_state; + efx_oword_t reg; + int link_speed, isolate; + + isolate = !!ACCESS_ONCE(efx->reset_pending); + + switch (link_state->speed) { + case 10000: link_speed = 3; break; + case 1000: link_speed = 2; break; + case 100: link_speed = 1; break; + default: link_speed = 0; break; + } + /* MAC_LINK_STATUS controls MAC backpressure but doesn't work + * as advertised. Disable to ensure packets are not + * indefinitely held and TX queue can be flushed at any point + * while the link is down. */ + EFX_POPULATE_OWORD_5(reg, + FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */, + FRF_AB_MAC_BCAD_ACPT, 1, + FRF_AB_MAC_UC_PROM, efx->promiscuous, + FRF_AB_MAC_LINK_STATUS, 1, /* always set */ + FRF_AB_MAC_SPEED, link_speed); + /* On B0, MAC backpressure can be disabled and packets get + * discarded. */ + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, + !link_state->up || isolate); + } + + efx_writeo(efx, ®, FR_AB_MAC_CTRL); + + /* Restore the multicast hash registers. */ + falcon_push_multicast_hash(efx); + + efx_reado(efx, ®, FR_AZ_RX_CFG); + /* Enable XOFF signal from RX FIFO (we enabled it during NIC + * initialisation but it may read back as 0) */ + EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); + /* Unisolate the MAC -> RX */ + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate); + efx_writeo(efx, ®, FR_AZ_RX_CFG); +} + +static void falcon_stats_request(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg; + + WARN_ON(nic_data->stats_pending); + WARN_ON(nic_data->stats_disable_count); + + if (nic_data->stats_dma_done == NULL) + return; /* no mac selected */ + + *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE; + nic_data->stats_pending = true; + wmb(); /* ensure done flag is clear */ + + /* Initiate DMA transfer of stats */ + EFX_POPULATE_OWORD_2(reg, + FRF_AB_MAC_STAT_DMA_CMD, 1, + FRF_AB_MAC_STAT_DMA_ADR, + efx->stats_buffer.dma_addr); + efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA); + + mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2)); +} + +static void falcon_stats_complete(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + + if (!nic_data->stats_pending) + return; + + nic_data->stats_pending = 0; + if (*nic_data->stats_dma_done == FALCON_STATS_DONE) { + rmb(); /* read the done flag before the stats */ + efx->mac_op->update_stats(efx); + } else { + netif_err(efx, hw, efx->net_dev, + "timed out waiting for statistics\n"); + } +} + +static void falcon_stats_timer_func(unsigned long context) +{ + struct efx_nic *efx = (struct efx_nic *)context; + struct falcon_nic_data *nic_data = efx->nic_data; + + spin_lock(&efx->stats_lock); + + falcon_stats_complete(efx); + if (nic_data->stats_disable_count == 0) + falcon_stats_request(efx); + + spin_unlock(&efx->stats_lock); +} + +static bool falcon_loopback_link_poll(struct efx_nic *efx) +{ + struct efx_link_state old_state = efx->link_state; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + WARN_ON(!LOOPBACK_INTERNAL(efx)); + + efx->link_state.fd = true; + efx->link_state.fc = efx->wanted_fc; + efx->link_state.up = true; + efx->link_state.speed = 10000; + + return !efx_link_state_equal(&efx->link_state, &old_state); +} + +static int falcon_reconfigure_port(struct efx_nic *efx) +{ + int rc; + + WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0); + + /* Poll the PHY link state *before* reconfiguring it. This means we + * will pick up the correct speed (in loopback) to select the correct + * MAC. + */ + if (LOOPBACK_INTERNAL(efx)) + falcon_loopback_link_poll(efx); + else + efx->phy_op->poll(efx); + + falcon_stop_nic_stats(efx); + falcon_deconfigure_mac_wrapper(efx); + + falcon_reset_macs(efx); + + efx->phy_op->reconfigure(efx); + rc = efx->mac_op->reconfigure(efx); + BUG_ON(rc); + + falcon_start_nic_stats(efx); + + /* Synchronise efx->link_state with the kernel */ + efx_link_status_changed(efx); + + return 0; +} + +/************************************************************************** + * + * PHY access via GMII + * + ************************************************************************** + */ + +/* Wait for GMII access to complete */ +static int falcon_gmii_wait(struct efx_nic *efx) +{ + efx_oword_t md_stat; + int count; + + /* wait up to 50ms - taken max from datasheet */ + for (count = 0; count < 5000; count++) { + efx_reado(efx, &md_stat, FR_AB_MD_STAT); + if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) { + if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 || + EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) { + netif_err(efx, hw, efx->net_dev, + "error from GMII access " + EFX_OWORD_FMT"\n", + EFX_OWORD_VAL(md_stat)); + return -EIO; + } + return 0; + } + udelay(10); + } + netif_err(efx, hw, efx->net_dev, "timed out waiting for GMII\n"); + return -ETIMEDOUT; +} + +/* Write an MDIO register of a PHY connected to Falcon. */ +static int falcon_mdio_write(struct net_device *net_dev, + int prtad, int devad, u16 addr, u16 value) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg; + int rc; + + netif_vdbg(efx, hw, efx->net_dev, + "writing MDIO %d register %d.%d with 0x%04x\n", + prtad, devad, addr, value); + + mutex_lock(&nic_data->mdio_lock); + + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); + if (rc) + goto out; + + /* Write the address/ID register */ + EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); + efx_writeo(efx, ®, FR_AB_MD_PHY_ADR); + + EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, + FRF_AB_MD_DEV_ADR, devad); + efx_writeo(efx, ®, FR_AB_MD_ID); + + /* Write data */ + EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value); + efx_writeo(efx, ®, FR_AB_MD_TXD); + + EFX_POPULATE_OWORD_2(reg, + FRF_AB_MD_WRC, 1, + FRF_AB_MD_GC, 0); + efx_writeo(efx, ®, FR_AB_MD_CS); + + /* Wait for data to be written */ + rc = falcon_gmii_wait(efx); + if (rc) { + /* Abort the write operation */ + EFX_POPULATE_OWORD_2(reg, + FRF_AB_MD_WRC, 0, + FRF_AB_MD_GC, 1); + efx_writeo(efx, ®, FR_AB_MD_CS); + udelay(10); + } + +out: + mutex_unlock(&nic_data->mdio_lock); + return rc; +} + +/* Read an MDIO register of a PHY connected to Falcon. */ +static int falcon_mdio_read(struct net_device *net_dev, + int prtad, int devad, u16 addr) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg; + int rc; + + mutex_lock(&nic_data->mdio_lock); + + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); + if (rc) + goto out; + + EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); + efx_writeo(efx, ®, FR_AB_MD_PHY_ADR); + + EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, + FRF_AB_MD_DEV_ADR, devad); + efx_writeo(efx, ®, FR_AB_MD_ID); + + /* Request data to be read */ + EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0); + efx_writeo(efx, ®, FR_AB_MD_CS); + + /* Wait for data to become available */ + rc = falcon_gmii_wait(efx); + if (rc == 0) { + efx_reado(efx, ®, FR_AB_MD_RXD); + rc = EFX_OWORD_FIELD(reg, FRF_AB_MD_RXD); + netif_vdbg(efx, hw, efx->net_dev, + "read from MDIO %d register %d.%d, got %04x\n", + prtad, devad, addr, rc); + } else { + /* Abort the read operation */ + EFX_POPULATE_OWORD_2(reg, + FRF_AB_MD_RIC, 0, + FRF_AB_MD_GC, 1); + efx_writeo(efx, ®, FR_AB_MD_CS); + + netif_dbg(efx, hw, efx->net_dev, + "read from MDIO %d register %d.%d, got error %d\n", + prtad, devad, addr, rc); + } + +out: + mutex_unlock(&nic_data->mdio_lock); + return rc; +} + +/* This call is responsible for hooking in the MAC and PHY operations */ +static int falcon_probe_port(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + int rc; + + switch (efx->phy_type) { + case PHY_TYPE_SFX7101: + efx->phy_op = &falcon_sfx7101_phy_ops; + break; + case PHY_TYPE_QT2022C2: + case PHY_TYPE_QT2025C: + efx->phy_op = &falcon_qt202x_phy_ops; + break; + case PHY_TYPE_TXC43128: + efx->phy_op = &falcon_txc_phy_ops; + break; + default: + netif_err(efx, probe, efx->net_dev, "Unknown PHY type %d\n", + efx->phy_type); + return -ENODEV; + } + + /* Fill out MDIO structure and loopback modes */ + mutex_init(&nic_data->mdio_lock); + efx->mdio.mdio_read = falcon_mdio_read; + efx->mdio.mdio_write = falcon_mdio_write; + rc = efx->phy_op->probe(efx); + if (rc != 0) + return rc; + + /* Initial assumption */ + efx->link_state.speed = 10000; + efx->link_state.fd = true; + + /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) + efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; + else + efx->wanted_fc = EFX_FC_RX; + if (efx->mdio.mmds & MDIO_DEVS_AN) + efx->wanted_fc |= EFX_FC_AUTO; + + /* Allocate buffer for stats */ + rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, + FALCON_MAC_STATS_SIZE); + if (rc) + return rc; + netif_dbg(efx, probe, efx->net_dev, + "stats buffer at %llx (virt %p phys %llx)\n", + (u64)efx->stats_buffer.dma_addr, + efx->stats_buffer.addr, + (u64)virt_to_phys(efx->stats_buffer.addr)); + nic_data->stats_dma_done = efx->stats_buffer.addr + XgDmaDone_offset; + + return 0; +} + +static void falcon_remove_port(struct efx_nic *efx) +{ + efx->phy_op->remove(efx); + efx_nic_free_buffer(efx, &efx->stats_buffer); +} + +/* Global events are basically PHY events */ +static bool +falcon_handle_global_event(struct efx_channel *channel, efx_qword_t *event) +{ + struct efx_nic *efx = channel->efx; + struct falcon_nic_data *nic_data = efx->nic_data; + + if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || + EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || + EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) + /* Ignored */ + return true; + + if ((efx_nic_rev(efx) == EFX_REV_FALCON_B0) && + EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) { + nic_data->xmac_poll_required = true; + return true; + } + + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ? + EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) : + EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) { + netif_err(efx, rx_err, efx->net_dev, + "channel %d seen global RX_RESET event. Resetting.\n", + channel->channel); + + atomic_inc(&efx->rx_reset); + efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? + RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); + return true; + } + + return false; +} + +/************************************************************************** + * + * Falcon test code + * + **************************************************************************/ + +static int +falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + struct falcon_nvconfig *nvconfig; + struct efx_spi_device *spi; + void *region; + int rc, magic_num, struct_ver; + __le16 *word, *limit; + u32 csum; + + if (efx_spi_present(&nic_data->spi_flash)) + spi = &nic_data->spi_flash; + else if (efx_spi_present(&nic_data->spi_eeprom)) + spi = &nic_data->spi_eeprom; + else + return -EINVAL; + + region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL); + if (!region) + return -ENOMEM; + nvconfig = region + FALCON_NVCONFIG_OFFSET; + + mutex_lock(&nic_data->spi_lock); + rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region); + mutex_unlock(&nic_data->spi_lock); + if (rc) { + netif_err(efx, hw, efx->net_dev, "Failed to read %s\n", + efx_spi_present(&nic_data->spi_flash) ? + "flash" : "EEPROM"); + rc = -EIO; + goto out; + } + + magic_num = le16_to_cpu(nvconfig->board_magic_num); + struct_ver = le16_to_cpu(nvconfig->board_struct_ver); + + rc = -EINVAL; + if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) { + netif_err(efx, hw, efx->net_dev, + "NVRAM bad magic 0x%x\n", magic_num); + goto out; + } + if (struct_ver < 2) { + netif_err(efx, hw, efx->net_dev, + "NVRAM has ancient version 0x%x\n", struct_ver); + goto out; + } else if (struct_ver < 4) { + word = &nvconfig->board_magic_num; + limit = (__le16 *) (nvconfig + 1); + } else { + word = region; + limit = region + FALCON_NVCONFIG_END; + } + for (csum = 0; word < limit; ++word) + csum += le16_to_cpu(*word); + + if (~csum & 0xffff) { + netif_err(efx, hw, efx->net_dev, + "NVRAM has incorrect checksum\n"); + goto out; + } + + rc = 0; + if (nvconfig_out) + memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig)); + + out: + kfree(region); + return rc; +} + +static int falcon_test_nvram(struct efx_nic *efx) +{ + return falcon_read_nvram(efx, NULL); +} + +static const struct efx_nic_register_test falcon_b0_register_tests[] = { + { FR_AZ_ADR_REGION, + EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) }, + { FR_AZ_RX_CFG, + EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, + { FR_AZ_TX_CFG, + EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AZ_TX_RESERVED, + EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, + { FR_AB_MAC_CTRL, + EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AZ_SRM_TX_DC_CFG, + EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AZ_RX_DC_CFG, + EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AZ_RX_DC_PF_WM, + EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_BZ_DP_CTRL, + EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_GM_CFG2, + EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_GMF_CFG0, + EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_XM_GLB_CFG, + EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_XM_TX_CFG, + EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_XM_RX_CFG, + EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_XM_RX_PARAM, + EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_XM_FC, + EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_XM_ADR_LO, + EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AB_XX_SD_CTL, + EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, +}; + +static int falcon_b0_test_registers(struct efx_nic *efx) +{ + return efx_nic_test_registers(efx, falcon_b0_register_tests, + ARRAY_SIZE(falcon_b0_register_tests)); +} + +/************************************************************************** + * + * Device reset + * + ************************************************************************** + */ + +static enum reset_type falcon_map_reset_reason(enum reset_type reason) +{ + switch (reason) { + case RESET_TYPE_RX_RECOVERY: + case RESET_TYPE_RX_DESC_FETCH: + case RESET_TYPE_TX_DESC_FETCH: + case RESET_TYPE_TX_SKIP: + /* These can occasionally occur due to hardware bugs. + * We try to reset without disrupting the link. + */ + return RESET_TYPE_INVISIBLE; + default: + return RESET_TYPE_ALL; + } +} + +static int falcon_map_reset_flags(u32 *flags) +{ + enum { + FALCON_RESET_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER | + ETH_RESET_OFFLOAD | ETH_RESET_MAC), + FALCON_RESET_ALL = FALCON_RESET_INVISIBLE | ETH_RESET_PHY, + FALCON_RESET_WORLD = FALCON_RESET_ALL | ETH_RESET_IRQ, + }; + + if ((*flags & FALCON_RESET_WORLD) == FALCON_RESET_WORLD) { + *flags &= ~FALCON_RESET_WORLD; + return RESET_TYPE_WORLD; + } + + if ((*flags & FALCON_RESET_ALL) == FALCON_RESET_ALL) { + *flags &= ~FALCON_RESET_ALL; + return RESET_TYPE_ALL; + } + + if ((*flags & FALCON_RESET_INVISIBLE) == FALCON_RESET_INVISIBLE) { + *flags &= ~FALCON_RESET_INVISIBLE; + return RESET_TYPE_INVISIBLE; + } + + return -EINVAL; +} + +/* Resets NIC to known state. This routine must be called in process + * context and is allowed to sleep. */ +static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t glb_ctl_reg_ker; + int rc; + + netif_dbg(efx, hw, efx->net_dev, "performing %s hardware reset\n", + RESET_TYPE(method)); + + /* Initiate device reset */ + if (method == RESET_TYPE_WORLD) { + rc = pci_save_state(efx->pci_dev); + if (rc) { + netif_err(efx, drv, efx->net_dev, + "failed to backup PCI state of primary " + "function prior to hardware reset\n"); + goto fail1; + } + if (efx_nic_is_dual_func(efx)) { + rc = pci_save_state(nic_data->pci_dev2); + if (rc) { + netif_err(efx, drv, efx->net_dev, + "failed to backup PCI state of " + "secondary function prior to " + "hardware reset\n"); + goto fail2; + } + } + + EFX_POPULATE_OWORD_2(glb_ctl_reg_ker, + FRF_AB_EXT_PHY_RST_DUR, + FFE_AB_EXT_PHY_RST_DUR_10240US, + FRF_AB_SWRST, 1); + } else { + EFX_POPULATE_OWORD_7(glb_ctl_reg_ker, + /* exclude PHY from "invisible" reset */ + FRF_AB_EXT_PHY_RST_CTL, + method == RESET_TYPE_INVISIBLE, + /* exclude EEPROM/flash and PCIe */ + FRF_AB_PCIE_CORE_RST_CTL, 1, + FRF_AB_PCIE_NSTKY_RST_CTL, 1, + FRF_AB_PCIE_SD_RST_CTL, 1, + FRF_AB_EE_RST_CTL, 1, + FRF_AB_EXT_PHY_RST_DUR, + FFE_AB_EXT_PHY_RST_DUR_10240US, + FRF_AB_SWRST, 1); + } + efx_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); + + netif_dbg(efx, hw, efx->net_dev, "waiting for hardware reset\n"); + schedule_timeout_uninterruptible(HZ / 20); + + /* Restore PCI configuration if needed */ + if (method == RESET_TYPE_WORLD) { + if (efx_nic_is_dual_func(efx)) + pci_restore_state(nic_data->pci_dev2); + pci_restore_state(efx->pci_dev); + netif_dbg(efx, drv, efx->net_dev, + "successfully restored PCI config\n"); + } + + /* Assert that reset complete */ + efx_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); + if (EFX_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) { + rc = -ETIMEDOUT; + netif_err(efx, hw, efx->net_dev, + "timed out waiting for hardware reset\n"); + goto fail3; + } + netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n"); + + return 0; + + /* pci_save_state() and pci_restore_state() MUST be called in pairs */ +fail2: + pci_restore_state(efx->pci_dev); +fail1: +fail3: + return rc; +} + +static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + int rc; + + mutex_lock(&nic_data->spi_lock); + rc = __falcon_reset_hw(efx, method); + mutex_unlock(&nic_data->spi_lock); + + return rc; +} + +static void falcon_monitor(struct efx_nic *efx) +{ + bool link_changed; + int rc; + + BUG_ON(!mutex_is_locked(&efx->mac_lock)); + + rc = falcon_board(efx)->type->monitor(efx); + if (rc) { + netif_err(efx, hw, efx->net_dev, + "Board sensor %s; shutting down PHY\n", + (rc == -ERANGE) ? "reported fault" : "failed"); + efx->phy_mode |= PHY_MODE_LOW_POWER; + rc = __efx_reconfigure_port(efx); + WARN_ON(rc); + } + + if (LOOPBACK_INTERNAL(efx)) + link_changed = falcon_loopback_link_poll(efx); + else + link_changed = efx->phy_op->poll(efx); + + if (link_changed) { + falcon_stop_nic_stats(efx); + falcon_deconfigure_mac_wrapper(efx); + + falcon_reset_macs(efx); + rc = efx->mac_op->reconfigure(efx); + BUG_ON(rc); + + falcon_start_nic_stats(efx); + + efx_link_status_changed(efx); + } + + falcon_poll_xmac(efx); +} + +/* Zeroes out the SRAM contents. This routine must be called in + * process context and is allowed to sleep. + */ +static int falcon_reset_sram(struct efx_nic *efx) +{ + efx_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker; + int count; + + /* Set the SRAM wake/sleep GPIO appropriately. */ + efx_reado(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); + EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OEN, 1); + EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OUT, 1); + efx_writeo(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); + + /* Initiate SRAM reset */ + EFX_POPULATE_OWORD_2(srm_cfg_reg_ker, + FRF_AZ_SRM_INIT_EN, 1, + FRF_AZ_SRM_NB_SZ, 0); + efx_writeo(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); + + /* Wait for SRAM reset to complete */ + count = 0; + do { + netif_dbg(efx, hw, efx->net_dev, + "waiting for SRAM reset (attempt %d)...\n", count); + + /* SRAM reset is slow; expect around 16ms */ + schedule_timeout_uninterruptible(HZ / 50); + + /* Check for reset complete */ + efx_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); + if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) { + netif_dbg(efx, hw, efx->net_dev, + "SRAM reset complete\n"); + + return 0; + } + } while (++count < 20); /* wait up to 0.4 sec */ + + netif_err(efx, hw, efx->net_dev, "timed out waiting for SRAM reset\n"); + return -ETIMEDOUT; +} + +static void falcon_spi_device_init(struct efx_nic *efx, + struct efx_spi_device *spi_device, + unsigned int device_id, u32 device_type) +{ + if (device_type != 0) { + spi_device->device_id = device_id; + spi_device->size = + 1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE); + spi_device->addr_len = + SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN); + spi_device->munge_address = (spi_device->size == 1 << 9 && + spi_device->addr_len == 1); + spi_device->erase_command = + SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD); + spi_device->erase_size = + 1 << SPI_DEV_TYPE_FIELD(device_type, + SPI_DEV_TYPE_ERASE_SIZE); + spi_device->block_size = + 1 << SPI_DEV_TYPE_FIELD(device_type, + SPI_DEV_TYPE_BLOCK_SIZE); + } else { + spi_device->size = 0; + } +} + +/* Extract non-volatile configuration */ +static int falcon_probe_nvconfig(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + struct falcon_nvconfig *nvconfig; + int rc; + + nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL); + if (!nvconfig) + return -ENOMEM; + + rc = falcon_read_nvram(efx, nvconfig); + if (rc) + goto out; + + efx->phy_type = nvconfig->board_v2.port0_phy_type; + efx->mdio.prtad = nvconfig->board_v2.port0_phy_addr; + + if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { + falcon_spi_device_init( + efx, &nic_data->spi_flash, FFE_AB_SPI_DEVICE_FLASH, + le32_to_cpu(nvconfig->board_v3 + .spi_device_type[FFE_AB_SPI_DEVICE_FLASH])); + falcon_spi_device_init( + efx, &nic_data->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM, + le32_to_cpu(nvconfig->board_v3 + .spi_device_type[FFE_AB_SPI_DEVICE_EEPROM])); + } + + /* Read the MAC addresses */ + memcpy(efx->net_dev->perm_addr, nvconfig->mac_address[0], ETH_ALEN); + + netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n", + efx->phy_type, efx->mdio.prtad); + + rc = falcon_probe_board(efx, + le16_to_cpu(nvconfig->board_v2.board_revision)); +out: + kfree(nvconfig); + return rc; +} + +/* Probe all SPI devices on the NIC */ +static void falcon_probe_spi_devices(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; + int boot_dev; + + efx_reado(efx, &gpio_ctl, FR_AB_GPIO_CTL); + efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); + efx_reado(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); + + if (EFX_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) { + boot_dev = (EFX_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ? + FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM); + netif_dbg(efx, probe, efx->net_dev, "Booted from %s\n", + boot_dev == FFE_AB_SPI_DEVICE_FLASH ? + "flash" : "EEPROM"); + } else { + /* Disable VPD and set clock dividers to safe + * values for initial programming. */ + boot_dev = -1; + netif_dbg(efx, probe, efx->net_dev, + "Booted from internal ASIC settings;" + " setting SPI config\n"); + EFX_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0, + /* 125 MHz / 7 ~= 20 MHz */ + FRF_AB_EE_SF_CLOCK_DIV, 7, + /* 125 MHz / 63 ~= 2 MHz */ + FRF_AB_EE_EE_CLOCK_DIV, 63); + efx_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); + } + + mutex_init(&nic_data->spi_lock); + + if (boot_dev == FFE_AB_SPI_DEVICE_FLASH) + falcon_spi_device_init(efx, &nic_data->spi_flash, + FFE_AB_SPI_DEVICE_FLASH, + default_flash_type); + if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM) + falcon_spi_device_init(efx, &nic_data->spi_eeprom, + FFE_AB_SPI_DEVICE_EEPROM, + large_eeprom_type); +} + +static int falcon_probe_nic(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data; + struct falcon_board *board; + int rc; + + /* Allocate storage for hardware specific data */ + nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL); + if (!nic_data) + return -ENOMEM; + efx->nic_data = nic_data; + + rc = -ENODEV; + + if (efx_nic_fpga_ver(efx) != 0) { + netif_err(efx, probe, efx->net_dev, + "Falcon FPGA not supported\n"); + goto fail1; + } + + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { + efx_oword_t nic_stat; + struct pci_dev *dev; + u8 pci_rev = efx->pci_dev->revision; + + if ((pci_rev == 0xff) || (pci_rev == 0)) { + netif_err(efx, probe, efx->net_dev, + "Falcon rev A0 not supported\n"); + goto fail1; + } + efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); + if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) { + netif_err(efx, probe, efx->net_dev, + "Falcon rev A1 1G not supported\n"); + goto fail1; + } + if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) { + netif_err(efx, probe, efx->net_dev, + "Falcon rev A1 PCI-X not supported\n"); + goto fail1; + } + + dev = pci_dev_get(efx->pci_dev); - while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID, ++ while ((dev = pci_get_device(PCI_VENDOR_ID_SOLARFLARE, ++ PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1, + dev))) { + if (dev->bus == efx->pci_dev->bus && + dev->devfn == efx->pci_dev->devfn + 1) { + nic_data->pci_dev2 = dev; + break; + } + } + if (!nic_data->pci_dev2) { + netif_err(efx, probe, efx->net_dev, + "failed to find secondary function\n"); + rc = -ENODEV; + goto fail2; + } + } + + /* Now we can reset the NIC */ + rc = __falcon_reset_hw(efx, RESET_TYPE_ALL); + if (rc) { + netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n"); + goto fail3; + } + + /* Allocate memory for INT_KER */ + rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); + if (rc) + goto fail4; + BUG_ON(efx->irq_status.dma_addr & 0x0f); + + netif_dbg(efx, probe, efx->net_dev, + "INT_KER at %llx (virt %p phys %llx)\n", + (u64)efx->irq_status.dma_addr, + efx->irq_status.addr, + (u64)virt_to_phys(efx->irq_status.addr)); + + falcon_probe_spi_devices(efx); + + /* Read in the non-volatile configuration */ + rc = falcon_probe_nvconfig(efx); + if (rc) { + if (rc == -EINVAL) + netif_err(efx, probe, efx->net_dev, "NVRAM is invalid\n"); + goto fail5; + } + + /* Initialise I2C adapter */ + board = falcon_board(efx); + board->i2c_adap.owner = THIS_MODULE; + board->i2c_data = falcon_i2c_bit_operations; + board->i2c_data.data = efx; + board->i2c_adap.algo_data = &board->i2c_data; + board->i2c_adap.dev.parent = &efx->pci_dev->dev; + strlcpy(board->i2c_adap.name, "SFC4000 GPIO", + sizeof(board->i2c_adap.name)); + rc = i2c_bit_add_bus(&board->i2c_adap); + if (rc) + goto fail5; + + rc = falcon_board(efx)->type->init(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to initialise board\n"); + goto fail6; + } + + nic_data->stats_disable_count = 1; + setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func, + (unsigned long)efx); + + return 0; + + fail6: + BUG_ON(i2c_del_adapter(&board->i2c_adap)); + memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); + fail5: + efx_nic_free_buffer(efx, &efx->irq_status); + fail4: + fail3: + if (nic_data->pci_dev2) { + pci_dev_put(nic_data->pci_dev2); + nic_data->pci_dev2 = NULL; + } + fail2: + fail1: + kfree(efx->nic_data); + return rc; +} + +static void falcon_init_rx_cfg(struct efx_nic *efx) +{ + /* Prior to Siena the RX DMA engine will split each frame at + * intervals of RX_USR_BUF_SIZE (32-byte units). We set it to + * be so large that that never happens. */ + const unsigned huge_buf_size = (3 * 4096) >> 5; + /* RX control FIFO thresholds (32 entries) */ + const unsigned ctrl_xon_thr = 20; + const unsigned ctrl_xoff_thr = 25; + efx_oword_t reg; + + efx_reado(efx, ®, FR_AZ_RX_CFG); + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { + /* Data FIFO size is 5.5K */ + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0); + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE, + huge_buf_size); + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, 512 >> 8); + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, 2048 >> 8); + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr); + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr); + } else { + /* Data FIFO size is 80K; register fields moved */ + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE, + huge_buf_size); + /* Send XON and XOFF at ~3 * max MTU away from empty/full */ + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, 27648 >> 8); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, 54272 >> 8); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); + + /* Enable hash insertion. This is broken for the + * 'Falcon' hash so also select Toeplitz TCP/IPv4 and + * IPv4 hashes. */ + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_INSRT_HDR, 1); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_ALG, 1); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_IP_HASH, 1); + } + /* Always enable XOFF signal from RX FIFO. We enable + * or disable transmission of pause frames at the MAC. */ + EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); + efx_writeo(efx, ®, FR_AZ_RX_CFG); +} + +/* This call performs hardware-specific global initialisation, such as + * defining the descriptor cache sizes and number of RSS channels. + * It does not set up any buffers, descriptor rings or event queues. + */ +static int falcon_init_nic(struct efx_nic *efx) +{ + efx_oword_t temp; + int rc; + + /* Use on-chip SRAM */ + efx_reado(efx, &temp, FR_AB_NIC_STAT); + EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1); + efx_writeo(efx, &temp, FR_AB_NIC_STAT); + + rc = falcon_reset_sram(efx); + if (rc) + return rc; + + /* Clear the parity enables on the TX data fifos as + * they produce false parity errors because of timing issues + */ + if (EFX_WORKAROUND_5129(efx)) { + efx_reado(efx, &temp, FR_AZ_CSR_SPARE); + EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0); + efx_writeo(efx, &temp, FR_AZ_CSR_SPARE); + } + + if (EFX_WORKAROUND_7244(efx)) { + efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL); + EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8); + EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_WILD_SRCH_LIMIT, 8); + EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_FULL_SRCH_LIMIT, 8); + EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_WILD_SRCH_LIMIT, 8); + efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL); + } + + /* XXX This is documented only for Falcon A0/A1 */ + /* Setup RX. Wait for descriptor is broken and must + * be disabled. RXDP recovery shouldn't be needed, but is. + */ + efx_reado(efx, &temp, FR_AA_RX_SELF_RST); + EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_NODESC_WAIT_DIS, 1); + EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_SELF_RST_EN, 1); + if (EFX_WORKAROUND_5583(efx)) + EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1); + efx_writeo(efx, &temp, FR_AA_RX_SELF_RST); + + /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 + * descriptors (which is bad). + */ + efx_reado(efx, &temp, FR_AZ_TX_CFG); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); + efx_writeo(efx, &temp, FR_AZ_TX_CFG); + + falcon_init_rx_cfg(efx); + + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + /* Set hash key for IPv4 */ + memcpy(&temp, efx->rx_hash_key, sizeof(temp)); + efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY); + + /* Set destination of both TX and RX Flush events */ + EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); + efx_writeo(efx, &temp, FR_BZ_DP_CTRL); + } + + efx_nic_init_common(efx); + + return 0; +} + +static void falcon_remove_nic(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + struct falcon_board *board = falcon_board(efx); + int rc; + + board->type->fini(efx); + + /* Remove I2C adapter and clear it in preparation for a retry */ + rc = i2c_del_adapter(&board->i2c_adap); + BUG_ON(rc); + memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); + + efx_nic_free_buffer(efx, &efx->irq_status); + + __falcon_reset_hw(efx, RESET_TYPE_ALL); + + /* Release the second function after the reset */ + if (nic_data->pci_dev2) { + pci_dev_put(nic_data->pci_dev2); + nic_data->pci_dev2 = NULL; + } + + /* Tear down the private nic state */ + kfree(efx->nic_data); + efx->nic_data = NULL; +} + +static void falcon_update_nic_stats(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t cnt; + + if (nic_data->stats_disable_count) + return; + + efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP); + efx->n_rx_nodesc_drop_cnt += + EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT); + + if (nic_data->stats_pending && + *nic_data->stats_dma_done == FALCON_STATS_DONE) { + nic_data->stats_pending = false; + rmb(); /* read the done flag before the stats */ + efx->mac_op->update_stats(efx); + } +} + +void falcon_start_nic_stats(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + + spin_lock_bh(&efx->stats_lock); + if (--nic_data->stats_disable_count == 0) + falcon_stats_request(efx); + spin_unlock_bh(&efx->stats_lock); +} + +void falcon_stop_nic_stats(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + int i; + + might_sleep(); + + spin_lock_bh(&efx->stats_lock); + ++nic_data->stats_disable_count; + spin_unlock_bh(&efx->stats_lock); + + del_timer_sync(&nic_data->stats_timer); + + /* Wait enough time for the most recent transfer to + * complete. */ + for (i = 0; i < 4 && nic_data->stats_pending; i++) { + if (*nic_data->stats_dma_done == FALCON_STATS_DONE) + break; + msleep(1); + } + + spin_lock_bh(&efx->stats_lock); + falcon_stats_complete(efx); + spin_unlock_bh(&efx->stats_lock); +} + +static void falcon_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) +{ + falcon_board(efx)->type->set_id_led(efx, mode); +} + +/************************************************************************** + * + * Wake on LAN + * + ************************************************************************** + */ + +static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int falcon_set_wol(struct efx_nic *efx, u32 type) +{ + if (type != 0) + return -EINVAL; + return 0; +} + +/************************************************************************** + * + * Revision-dependent attributes used by efx.c and nic.c + * + ************************************************************************** + */ + +const struct efx_nic_type falcon_a1_nic_type = { + .probe = falcon_probe_nic, + .remove = falcon_remove_nic, + .init = falcon_init_nic, + .fini = efx_port_dummy_op_void, + .monitor = falcon_monitor, + .map_reset_reason = falcon_map_reset_reason, + .map_reset_flags = falcon_map_reset_flags, + .reset = falcon_reset_hw, + .probe_port = falcon_probe_port, + .remove_port = falcon_remove_port, + .handle_global_event = falcon_handle_global_event, + .prepare_flush = falcon_prepare_flush, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, + .set_id_led = falcon_set_id_led, + .push_irq_moderation = falcon_push_irq_moderation, + .push_multicast_hash = falcon_push_multicast_hash, + .reconfigure_port = falcon_reconfigure_port, + .get_wol = falcon_get_wol, + .set_wol = falcon_set_wol, + .resume_wol = efx_port_dummy_op_void, + .test_nvram = falcon_test_nvram, + .default_mac_ops = &falcon_xmac_operations, + + .revision = EFX_REV_FALCON_A1, + .mem_map_size = 0x20000, + .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, + .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, + .buf_tbl_base = FR_AA_BUF_FULL_TBL_KER, + .evq_ptr_tbl_base = FR_AA_EVQ_PTR_TBL_KER, + .evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER, + .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), + .rx_buffer_padding = 0x24, + .max_interrupt_mode = EFX_INT_MODE_MSI, + .phys_addr_channels = 4, + .tx_dc_base = 0x130000, + .rx_dc_base = 0x100000, + .offload_features = NETIF_F_IP_CSUM, +}; + +const struct efx_nic_type falcon_b0_nic_type = { + .probe = falcon_probe_nic, + .remove = falcon_remove_nic, + .init = falcon_init_nic, + .fini = efx_port_dummy_op_void, + .monitor = falcon_monitor, + .map_reset_reason = falcon_map_reset_reason, + .map_reset_flags = falcon_map_reset_flags, + .reset = falcon_reset_hw, + .probe_port = falcon_probe_port, + .remove_port = falcon_remove_port, + .handle_global_event = falcon_handle_global_event, + .prepare_flush = falcon_prepare_flush, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, + .set_id_led = falcon_set_id_led, + .push_irq_moderation = falcon_push_irq_moderation, + .push_multicast_hash = falcon_push_multicast_hash, + .reconfigure_port = falcon_reconfigure_port, + .get_wol = falcon_get_wol, + .set_wol = falcon_set_wol, + .resume_wol = efx_port_dummy_op_void, + .test_registers = falcon_b0_test_registers, + .test_nvram = falcon_test_nvram, + .default_mac_ops = &falcon_xmac_operations, + + .revision = EFX_REV_FALCON_B0, + /* Map everything up to and including the RSS indirection + * table. Don't map MSI-X table, MSI-X PBA since Linux + * requires that they not be mapped. */ + .mem_map_size = (FR_BZ_RX_INDIRECTION_TBL + + FR_BZ_RX_INDIRECTION_TBL_STEP * + FR_BZ_RX_INDIRECTION_TBL_ROWS), + .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, + .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, + .buf_tbl_base = FR_BZ_BUF_FULL_TBL, + .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, + .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, + .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), + .rx_buffer_hash_size = 0x10, + .rx_buffer_padding = 0, + .max_interrupt_mode = EFX_INT_MODE_MSIX, + .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy + * interrupt handler only supports 32 + * channels */ + .tx_dc_base = 0x130000, + .rx_dc_base = 0x100000, + .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE, +}; + diff --cc drivers/net/ethernet/sfc/falcon_boards.c index b9cc846811d,00000000000..6cc16b8cc6f mode 100644,000000..100644 --- a/drivers/net/ethernet/sfc/falcon_boards.c +++ b/drivers/net/ethernet/sfc/falcon_boards.c @@@ -1,776 -1,0 +1,777 @@@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2007-2010 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include + +#include "net_driver.h" +#include "phy.h" +#include "efx.h" +#include "nic.h" +#include "workarounds.h" + +/* Macros for unpacking the board revision */ +/* The revision info is in host byte order. */ +#define FALCON_BOARD_TYPE(_rev) (_rev >> 8) +#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) +#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf) + +/* Board types */ +#define FALCON_BOARD_SFE4001 0x01 +#define FALCON_BOARD_SFE4002 0x02 +#define FALCON_BOARD_SFE4003 0x03 +#define FALCON_BOARD_SFN4112F 0x52 + +/* Board temperature is about 15°C above ambient when air flow is + * limited. The maximum acceptable ambient temperature varies + * depending on the PHY specifications but the critical temperature + * above which we should shut down to avoid damage is 80°C. */ +#define FALCON_BOARD_TEMP_BIAS 15 +#define FALCON_BOARD_TEMP_CRIT (80 + FALCON_BOARD_TEMP_BIAS) + +/* SFC4000 datasheet says: 'The maximum permitted junction temperature + * is 125°C; the thermal design of the environment for the SFC4000 + * should aim to keep this well below 100°C.' */ +#define FALCON_JUNC_TEMP_MIN 0 +#define FALCON_JUNC_TEMP_MAX 90 +#define FALCON_JUNC_TEMP_CRIT 125 + +/***************************************************************************** + * Support for LM87 sensor chip used on several boards + */ +#define LM87_REG_TEMP_HW_INT_LOCK 0x13 +#define LM87_REG_TEMP_HW_EXT_LOCK 0x14 +#define LM87_REG_TEMP_HW_INT 0x17 +#define LM87_REG_TEMP_HW_EXT 0x18 +#define LM87_REG_TEMP_EXT1 0x26 +#define LM87_REG_TEMP_INT 0x27 +#define LM87_REG_ALARMS1 0x41 +#define LM87_REG_ALARMS2 0x42 +#define LM87_IN_LIMITS(nr, _min, _max) \ + 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min +#define LM87_AIN_LIMITS(nr, _min, _max) \ + 0x3B + (nr), _max, 0x1A + (nr), _min +#define LM87_TEMP_INT_LIMITS(_min, _max) \ + 0x39, _max, 0x3A, _min +#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ + 0x37, _max, 0x38, _min + +#define LM87_ALARM_TEMP_INT 0x10 +#define LM87_ALARM_TEMP_EXT1 0x20 + +#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE) + +static int efx_poke_lm87(struct i2c_client *client, const u8 *reg_values) +{ + while (*reg_values) { + u8 reg = *reg_values++; + u8 value = *reg_values++; + int rc = i2c_smbus_write_byte_data(client, reg, value); + if (rc) + return rc; + } + return 0; +} + +static const u8 falcon_lm87_common_regs[] = { + LM87_REG_TEMP_HW_INT_LOCK, FALCON_BOARD_TEMP_CRIT, + LM87_REG_TEMP_HW_INT, FALCON_BOARD_TEMP_CRIT, + LM87_TEMP_EXT1_LIMITS(FALCON_JUNC_TEMP_MIN, FALCON_JUNC_TEMP_MAX), + LM87_REG_TEMP_HW_EXT_LOCK, FALCON_JUNC_TEMP_CRIT, + LM87_REG_TEMP_HW_EXT, FALCON_JUNC_TEMP_CRIT, + 0 +}; + +static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, + const u8 *reg_values) +{ + struct falcon_board *board = falcon_board(efx); + struct i2c_client *client = i2c_new_device(&board->i2c_adap, info); + int rc; + + if (!client) + return -EIO; + + /* Read-to-clear alarm/interrupt status */ + i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); + i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); + + rc = efx_poke_lm87(client, reg_values); + if (rc) + goto err; + rc = efx_poke_lm87(client, falcon_lm87_common_regs); + if (rc) + goto err; + + board->hwmon_client = client; + return 0; + +err: + i2c_unregister_device(client); + return rc; +} + +static void efx_fini_lm87(struct efx_nic *efx) +{ + i2c_unregister_device(falcon_board(efx)->hwmon_client); +} + +static int efx_check_lm87(struct efx_nic *efx, unsigned mask) +{ + struct i2c_client *client = falcon_board(efx)->hwmon_client; + bool temp_crit, elec_fault, is_failure; + u16 alarms; + s32 reg; + + /* If link is up then do not monitor temperature */ + if (EFX_WORKAROUND_7884(efx) && efx->link_state.up) + return 0; + + reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); + if (reg < 0) + return reg; + alarms = reg; + reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); + if (reg < 0) + return reg; + alarms |= reg << 8; + alarms &= mask; + + temp_crit = false; + if (alarms & LM87_ALARM_TEMP_INT) { + reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_INT); + if (reg < 0) + return reg; + if (reg > FALCON_BOARD_TEMP_CRIT) + temp_crit = true; + } + if (alarms & LM87_ALARM_TEMP_EXT1) { + reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_EXT1); + if (reg < 0) + return reg; + if (reg > FALCON_JUNC_TEMP_CRIT) + temp_crit = true; + } + elec_fault = alarms & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1); + is_failure = temp_crit || elec_fault; + + if (alarms) + netif_err(efx, hw, efx->net_dev, + "LM87 detected a hardware %s (status %02x:%02x)" + "%s%s%s%s\n", + is_failure ? "failure" : "problem", + alarms & 0xff, alarms >> 8, + (alarms & LM87_ALARM_TEMP_INT) ? + "; board is overheating" : "", + (alarms & LM87_ALARM_TEMP_EXT1) ? + "; controller is overheating" : "", + temp_crit ? "; reached critical temperature" : "", + elec_fault ? "; electrical fault" : ""); + + return is_failure ? -ERANGE : 0; +} + +#else /* !CONFIG_SENSORS_LM87 */ + +static inline int +efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, + const u8 *reg_values) +{ + return 0; +} +static inline void efx_fini_lm87(struct efx_nic *efx) +{ +} +static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) +{ + return 0; +} + +#endif /* CONFIG_SENSORS_LM87 */ + +/***************************************************************************** + * Support for the SFE4001 NIC. + * + * The SFE4001 does not power-up fully at reset due to its high power + * consumption. We control its power via a PCA9539 I/O expander. + * It also has a MAX6647 temperature monitor which we expose to + * the lm90 driver. + * + * This also provides minimal support for reflashing the PHY, which is + * initiated by resetting it with the FLASH_CFG_1 pin pulled down. + * On SFE4001 rev A2 and later this is connected to the 3V3X output of + * the IO-expander. + * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually + * exclusive with the network device being open. + */ + +/************************************************************************** + * Support for I2C IO Expander device on SFE4001 + */ +#define PCA9539 0x74 + +#define P0_IN 0x00 +#define P0_OUT 0x02 +#define P0_INVERT 0x04 +#define P0_CONFIG 0x06 + +#define P0_EN_1V0X_LBN 0 +#define P0_EN_1V0X_WIDTH 1 +#define P0_EN_1V2_LBN 1 +#define P0_EN_1V2_WIDTH 1 +#define P0_EN_2V5_LBN 2 +#define P0_EN_2V5_WIDTH 1 +#define P0_EN_3V3X_LBN 3 +#define P0_EN_3V3X_WIDTH 1 +#define P0_EN_5V_LBN 4 +#define P0_EN_5V_WIDTH 1 +#define P0_SHORTEN_JTAG_LBN 5 +#define P0_SHORTEN_JTAG_WIDTH 1 +#define P0_X_TRST_LBN 6 +#define P0_X_TRST_WIDTH 1 +#define P0_DSP_RESET_LBN 7 +#define P0_DSP_RESET_WIDTH 1 + +#define P1_IN 0x01 +#define P1_OUT 0x03 +#define P1_INVERT 0x05 +#define P1_CONFIG 0x07 + +#define P1_AFE_PWD_LBN 0 +#define P1_AFE_PWD_WIDTH 1 +#define P1_DSP_PWD25_LBN 1 +#define P1_DSP_PWD25_WIDTH 1 +#define P1_RESERVED_LBN 2 +#define P1_RESERVED_WIDTH 2 +#define P1_SPARE_LBN 4 +#define P1_SPARE_WIDTH 4 + +/* Temperature Sensor */ +#define MAX664X_REG_RSL 0x02 +#define MAX664X_REG_WLHO 0x0B + +static void sfe4001_poweroff(struct efx_nic *efx) +{ + struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; + struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; + + /* Turn off all power rails and disable outputs */ + i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); + i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); + i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); + + /* Clear any over-temperature alert */ + i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); +} + +static int sfe4001_poweron(struct efx_nic *efx) +{ + struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; + struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; + unsigned int i, j; + int rc; + u8 out; + + /* Clear any previous over-temperature alert */ + rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); + if (rc < 0) + return rc; + + /* Enable port 0 and port 1 outputs on IO expander */ + rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); + if (rc) + return rc; + rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, + 0xff & ~(1 << P1_SPARE_LBN)); + if (rc) + goto fail_on; + + /* If PHY power is on, turn it all off and wait 1 second to + * ensure a full reset. + */ + rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); + if (rc < 0) + goto fail_on; + out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | + (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | + (0 << P0_EN_1V0X_LBN)); + if (rc != out) { + netif_info(efx, hw, efx->net_dev, "power-cycling PHY\n"); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); + if (rc) + goto fail_on; + schedule_timeout_uninterruptible(HZ); + } + + for (i = 0; i < 20; ++i) { + /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ + out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | + (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | + (1 << P0_X_TRST_LBN)); + if (efx->phy_mode & PHY_MODE_SPECIAL) + out |= 1 << P0_EN_3V3X_LBN; + + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); + if (rc) + goto fail_on; + msleep(10); + + /* Turn on 1V power rail */ + out &= ~(1 << P0_EN_1V0X_LBN); + rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); + if (rc) + goto fail_on; + + netif_info(efx, hw, efx->net_dev, + "waiting for DSP boot (attempt %d)...\n", i); + + /* In flash config mode, DSP does not turn on AFE, so + * just wait 1 second. + */ + if (efx->phy_mode & PHY_MODE_SPECIAL) { + schedule_timeout_uninterruptible(HZ); + return 0; + } + + for (j = 0; j < 10; ++j) { + msleep(100); + + /* Check DSP has asserted AFE power line */ + rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); + if (rc < 0) + goto fail_on; + if (rc & (1 << P1_AFE_PWD_LBN)) + return 0; + } + } + + netif_info(efx, hw, efx->net_dev, "timed out waiting for DSP boot\n"); + rc = -ETIMEDOUT; +fail_on: + sfe4001_poweroff(efx); + return rc; +} + +static ssize_t show_phy_flash_cfg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); +} + +static ssize_t set_phy_flash_cfg(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + enum efx_phy_mode old_mode, new_mode; + int err; + + rtnl_lock(); + old_mode = efx->phy_mode; + if (count == 0 || *buf == '0') + new_mode = old_mode & ~PHY_MODE_SPECIAL; + else + new_mode = PHY_MODE_SPECIAL; + if (!((old_mode ^ new_mode) & PHY_MODE_SPECIAL)) { + err = 0; + } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { + err = -EBUSY; + } else { + /* Reset the PHY, reconfigure the MAC and enable/disable + * MAC stats accordingly. */ + efx->phy_mode = new_mode; + if (new_mode & PHY_MODE_SPECIAL) + falcon_stop_nic_stats(efx); + err = sfe4001_poweron(efx); + if (!err) + err = efx_reconfigure_port(efx); + if (!(new_mode & PHY_MODE_SPECIAL)) + falcon_start_nic_stats(efx); + } + rtnl_unlock(); + + return err ? err : count; +} + +static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); + +static void sfe4001_fini(struct efx_nic *efx) +{ + struct falcon_board *board = falcon_board(efx); + + netif_info(efx, drv, efx->net_dev, "%s\n", __func__); + + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); + sfe4001_poweroff(efx); + i2c_unregister_device(board->ioexp_client); + i2c_unregister_device(board->hwmon_client); +} + +static int sfe4001_check_hw(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + s32 status; + + /* If XAUI link is up then do not monitor */ + if (EFX_WORKAROUND_7884(efx) && !nic_data->xmac_poll_required) + return 0; + + /* Check the powered status of the PHY. Lack of power implies that + * the MAX6647 has shut down power to it, probably due to a temp. + * alarm. Reading the power status rather than the MAX6647 status + * directly because the later is read-to-clear and would thus + * start to power up the PHY again when polled, causing us to blip + * the power undesirably. + * We know we can read from the IO expander because we did + * it during power-on. Assume failure now is bad news. */ + status = i2c_smbus_read_byte_data(falcon_board(efx)->ioexp_client, P1_IN); + if (status >= 0 && + (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) + return 0; + + /* Use board power control, not PHY power control */ + sfe4001_poweroff(efx); + efx->phy_mode = PHY_MODE_OFF; + + return (status < 0) ? -EIO : -ERANGE; +} + +static struct i2c_board_info sfe4001_hwmon_info = { + I2C_BOARD_INFO("max6647", 0x4e), +}; + +/* This board uses an I2C expander to provider power to the PHY, which needs to + * be turned on before the PHY can be used. + * Context: Process context, rtnl lock held + */ +static int sfe4001_init(struct efx_nic *efx) +{ + struct falcon_board *board = falcon_board(efx); + int rc; + +#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) + board->hwmon_client = + i2c_new_device(&board->i2c_adap, &sfe4001_hwmon_info); +#else + board->hwmon_client = + i2c_new_dummy(&board->i2c_adap, sfe4001_hwmon_info.addr); +#endif + if (!board->hwmon_client) + return -EIO; + + /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ + rc = i2c_smbus_write_byte_data(board->hwmon_client, + MAX664X_REG_WLHO, 90); + if (rc) + goto fail_hwmon; + + board->ioexp_client = i2c_new_dummy(&board->i2c_adap, PCA9539); + if (!board->ioexp_client) { + rc = -EIO; + goto fail_hwmon; + } + + if (efx->phy_mode & PHY_MODE_SPECIAL) { + /* PHY won't generate a 156.25 MHz clock and MAC stats fetch + * will fail. */ + falcon_stop_nic_stats(efx); + } + rc = sfe4001_poweron(efx); + if (rc) + goto fail_ioexp; + + rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); + if (rc) + goto fail_on; + + netif_info(efx, hw, efx->net_dev, "PHY is powered on\n"); + return 0; + +fail_on: + sfe4001_poweroff(efx); +fail_ioexp: + i2c_unregister_device(board->ioexp_client); +fail_hwmon: + i2c_unregister_device(board->hwmon_client); + return rc; +} + +/***************************************************************************** + * Support for the SFE4002 + * + */ +static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ + +static const u8 sfe4002_lm87_regs[] = { + LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */ + LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ + LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ + LM87_IN_LIMITS(3, 0xac, 0xd4), /* 5V: 5.0V +/- 10% */ + LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ + LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ + LM87_AIN_LIMITS(0, 0x98, 0xbb), /* AIN1: 1.66V +/- 10% */ + LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */ + LM87_TEMP_INT_LIMITS(0, 80 + FALCON_BOARD_TEMP_BIAS), + LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX), + 0 +}; + +static struct i2c_board_info sfe4002_hwmon_info = { + I2C_BOARD_INFO("lm87", 0x2e), + .platform_data = &sfe4002_lm87_channel, +}; + +/****************************************************************************/ +/* LED allocations. Note that on rev A0 boards the schematic and the reality + * differ: red and green are swapped. Below is the fixed (A1) layout (there + * are only 3 A0 boards in existence, so no real reason to make this + * conditional). + */ +#define SFE4002_FAULT_LED (2) /* Red */ +#define SFE4002_RX_LED (0) /* Green */ +#define SFE4002_TX_LED (1) /* Amber */ + +static void sfe4002_init_phy(struct efx_nic *efx) +{ + /* Set the TX and RX LEDs to reflect status and activity, and the + * fault LED off */ + falcon_qt202x_set_led(efx, SFE4002_TX_LED, + QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); + falcon_qt202x_set_led(efx, SFE4002_RX_LED, + QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); + falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); +} + +static void sfe4002_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) +{ + falcon_qt202x_set_led( + efx, SFE4002_FAULT_LED, + (mode == EFX_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF); +} + +static int sfe4002_check_hw(struct efx_nic *efx) +{ + struct falcon_board *board = falcon_board(efx); + + /* A0 board rev. 4002s report a temperature fault the whole time + * (bad sensor) so we mask it out. */ + unsigned alarm_mask = + (board->major == 0 && board->minor == 0) ? + ~LM87_ALARM_TEMP_EXT1 : ~0; + + return efx_check_lm87(efx, alarm_mask); +} + +static int sfe4002_init(struct efx_nic *efx) +{ + return efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); +} + +/***************************************************************************** + * Support for the SFN4112F + * + */ +static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ + +static const u8 sfn4112f_lm87_regs[] = { + LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */ + LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ + LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ + LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ + LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ + LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */ + LM87_TEMP_INT_LIMITS(0, 60 + FALCON_BOARD_TEMP_BIAS), + LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX), + 0 +}; + +static struct i2c_board_info sfn4112f_hwmon_info = { + I2C_BOARD_INFO("lm87", 0x2e), + .platform_data = &sfn4112f_lm87_channel, +}; + +#define SFN4112F_ACT_LED 0 +#define SFN4112F_LINK_LED 1 + +static void sfn4112f_init_phy(struct efx_nic *efx) +{ + falcon_qt202x_set_led(efx, SFN4112F_ACT_LED, + QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); + falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, + QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); +} + +static void sfn4112f_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) +{ + int reg; + + switch (mode) { + case EFX_LED_OFF: + reg = QUAKE_LED_OFF; + break; + case EFX_LED_ON: + reg = QUAKE_LED_ON; + break; + default: + reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT; + break; + } + + falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, reg); +} + +static int sfn4112f_check_hw(struct efx_nic *efx) +{ + /* Mask out unused sensors */ + return efx_check_lm87(efx, ~0x48); +} + +static int sfn4112f_init(struct efx_nic *efx) +{ + return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); +} + +/***************************************************************************** + * Support for the SFE4003 + * + */ +static u8 sfe4003_lm87_channel = 0x03; /* use AIN not FAN inputs */ + +static const u8 sfe4003_lm87_regs[] = { + LM87_IN_LIMITS(0, 0x67, 0x7f), /* 2.5V: 1.5V +/- 10% */ + LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ + LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ + LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ + LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ + LM87_TEMP_INT_LIMITS(0, 70 + FALCON_BOARD_TEMP_BIAS), + 0 +}; + +static struct i2c_board_info sfe4003_hwmon_info = { + I2C_BOARD_INFO("lm87", 0x2e), + .platform_data = &sfe4003_lm87_channel, +}; + +/* Board-specific LED info. */ +#define SFE4003_RED_LED_GPIO 11 +#define SFE4003_LED_ON 1 +#define SFE4003_LED_OFF 0 + +static void sfe4003_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) +{ + struct falcon_board *board = falcon_board(efx); + + /* The LEDs were not wired to GPIOs before A3 */ + if (board->minor < 3 && board->major == 0) + return; + + falcon_txc_set_gpio_val( + efx, SFE4003_RED_LED_GPIO, + (mode == EFX_LED_ON) ? SFE4003_LED_ON : SFE4003_LED_OFF); +} + +static void sfe4003_init_phy(struct efx_nic *efx) +{ + struct falcon_board *board = falcon_board(efx); + + /* The LEDs were not wired to GPIOs before A3 */ + if (board->minor < 3 && board->major == 0) + return; + + falcon_txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT); + falcon_txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF); +} + +static int sfe4003_check_hw(struct efx_nic *efx) +{ + struct falcon_board *board = falcon_board(efx); + + /* A0/A1/A2 board rev. 4003s report a temperature fault the whole time + * (bad sensor) so we mask it out. */ + unsigned alarm_mask = + (board->major == 0 && board->minor <= 2) ? + ~LM87_ALARM_TEMP_EXT1 : ~0; + + return efx_check_lm87(efx, alarm_mask); +} + +static int sfe4003_init(struct efx_nic *efx) +{ + return efx_init_lm87(efx, &sfe4003_hwmon_info, sfe4003_lm87_regs); +} + +static const struct falcon_board_type board_types[] = { + { + .id = FALCON_BOARD_SFE4001, + .ref_model = "SFE4001", + .gen_type = "10GBASE-T adapter", + .init = sfe4001_init, + .init_phy = efx_port_dummy_op_void, + .fini = sfe4001_fini, + .set_id_led = tenxpress_set_id_led, + .monitor = sfe4001_check_hw, + }, + { + .id = FALCON_BOARD_SFE4002, + .ref_model = "SFE4002", + .gen_type = "XFP adapter", + .init = sfe4002_init, + .init_phy = sfe4002_init_phy, + .fini = efx_fini_lm87, + .set_id_led = sfe4002_set_id_led, + .monitor = sfe4002_check_hw, + }, + { + .id = FALCON_BOARD_SFE4003, + .ref_model = "SFE4003", + .gen_type = "10GBASE-CX4 adapter", + .init = sfe4003_init, + .init_phy = sfe4003_init_phy, + .fini = efx_fini_lm87, + .set_id_led = sfe4003_set_id_led, + .monitor = sfe4003_check_hw, + }, + { + .id = FALCON_BOARD_SFN4112F, + .ref_model = "SFN4112F", + .gen_type = "SFP+ adapter", + .init = sfn4112f_init, + .init_phy = sfn4112f_init_phy, + .fini = efx_fini_lm87, + .set_id_led = sfn4112f_set_id_led, + .monitor = sfn4112f_check_hw, + }, +}; + +int falcon_probe_board(struct efx_nic *efx, u16 revision_info) +{ + struct falcon_board *board = falcon_board(efx); + u8 type_id = FALCON_BOARD_TYPE(revision_info); + int i; + + board->major = FALCON_BOARD_MAJOR(revision_info); + board->minor = FALCON_BOARD_MINOR(revision_info); + + for (i = 0; i < ARRAY_SIZE(board_types); i++) + if (board_types[i].id == type_id) + board->type = &board_types[i]; + + if (board->type) { + netif_info(efx, probe, efx->net_dev, "board is %s rev %c%d\n", - (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) ++ (efx->pci_dev->subsystem_vendor == ++ PCI_VENDOR_ID_SOLARFLARE) + ? board->type->ref_model : board->type->gen_type, + 'A' + board->major, board->minor); + return 0; + } else { + netif_err(efx, probe, efx->net_dev, "unknown board type %d\n", + type_id); + return -ENODEV; + } +}