Merge branch 'next-rebase' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Oct 2011 21:20:44 +0000 (14:20 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Oct 2011 21:20:44 +0000 (14:20 -0700)
* '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

1  2 
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/falcon.c
drivers/net/ethernet/sfc/falcon_boards.c
drivers/pci/quirks.c
include/linux/pci.h

index de9afeb,0000000..d5731f1
mode 100644,000000..100644
--- /dev/null
@@@ -1,2732 -1,0 +1,2734 @@@
-       {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
 +/****************************************************************************
 + * 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 <linux/module.h>
 +#include <linux/pci.h>
 +#include <linux/netdevice.h>
 +#include <linux/etherdevice.h>
 +#include <linux/delay.h>
 +#include <linux/notifier.h>
 +#include <linux/ip.h>
 +#include <linux/tcp.h>
 +#include <linux/in.h>
 +#include <linux/crc32.h>
 +#include <linux/ethtool.h>
 +#include <linux/topology.h>
 +#include <linux/gfp.h>
 +#include <linux/cpu_rmap.h>
 +#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_B_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, BETHPAGE_A_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, SIENA_A_P_DEVID),
++      {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, BETHPAGE_A_P_DEVID),
 +       .driver_data = (unsigned long) &siena_a0_nic_type},
++      {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 <mbrown@fensystems.co.uk>");
 +MODULE_DESCRIPTION("Solarflare Communications network driver");
 +MODULE_LICENSE("GPL");
 +MODULE_DEVICE_TABLE(pci, efx_pci_table);
index 442f4d0,0000000..4764793
mode 100644,000000..100644
--- /dev/null
@@@ -1,150 -1,0 +1,146 @@@
- #define EFX_VENDID_SFC                0x1924
- #define FALCON_A_P_DEVID      0x0703
- #define FALCON_A_S_DEVID        0x6703
- #define FALCON_B_P_DEVID        0x0710
 +/****************************************************************************
 + * 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 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 */
index 4dd1748,0000000..97b606b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1843 -1,0 +1,1844 @@@
-               while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
 +/****************************************************************************
 + * 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 <linux/bitops.h>
 +#include <linux/delay.h>
 +#include <linux/pci.h>
 +#include <linux/module.h>
 +#include <linux/seq_file.h>
 +#include <linux/i2c.h>
 +#include <linux/mii.h>
 +#include <linux/slab.h>
 +#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, &reg, FR_AB_GPIO_CTL);
 +      EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state);
 +      efx_writeo(efx, &reg, 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, &reg, FR_AB_GPIO_CTL);
 +      EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state);
 +      efx_writeo(efx, &reg, 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, &reg, 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, &reg, 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, &reg, FR_AA_INT_ACK_KER);
 +      efx_readd(efx, &reg, 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, &reg, 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, &reg, FR_AB_EE_SPI_HADR);
 +      }
 +
 +      /* Program data register, if we have data */
 +      if (in != NULL) {
 +              memcpy(&reg, in, len);
 +              efx_writeo(efx, &reg, 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, &reg, 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, &reg, FR_AB_EE_SPI_HDATA);
 +              memcpy(out, &reg, 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, &reg, FR_AB_XM_GLB_CFG);
 +
 +              for (count = 0; count < 10000; count++) {
 +                      efx_reado(efx, &reg, 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, &reg, 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, &reg, FR_AB_GLB_CTL);
 +
 +      count = 0;
 +      while (1) {
 +              efx_reado(efx, &reg, 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, &reg, 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, &reg, FR_AZ_RX_CFG);
 +      EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
 +      efx_writeo(efx, &reg, 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, &reg, FR_AB_MAC_CTRL);
 +
 +      /* Restore the multicast hash registers. */
 +      falcon_push_multicast_hash(efx);
 +
 +      efx_reado(efx, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, FR_AB_MD_ID);
 +
 +      /* Write data */
 +      EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value);
 +      efx_writeo(efx, &reg, FR_AB_MD_TXD);
 +
 +      EFX_POPULATE_OWORD_2(reg,
 +                           FRF_AB_MD_WRC, 1,
 +                           FRF_AB_MD_GC, 0);
 +      efx_writeo(efx, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, FR_AB_MD_CS);
 +
 +      /* Wait for data to become available */
 +      rc = falcon_gmii_wait(efx);
 +      if (rc == 0) {
 +              efx_reado(efx, &reg, 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, &reg, 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(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, &reg, 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, &reg, 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,
 +};
 +
index b9cc846,0000000..6cc16b8
mode 100644,000000..100644
--- /dev/null
@@@ -1,776 -1,0 +1,777 @@@
-                        (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
 +/****************************************************************************
 + * 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 <linux/rtnetlink.h>
 +
 +#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 ==
++                        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;
 +      }
 +}
Simple merge
Simple merge