Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ef10.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
 * Driver for Solarflare network controllers and boards
 * Copyright 2012-2013 Solarflare Communications Inc.
 */


#include "net_driver.h"
#include "rx_common.h"
#include "tx_common.h"
#include "ef10_regs.h"
#include "io.h"
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "mcdi_port.h"
#include "mcdi_port_common.h"
#include "mcdi_functions.h"
#include "nic.h"
#include "mcdi_filters.h"
#include "workarounds.h"
#include "selftest.h"
#include "ef10_sriov.h"
#include <linux/in.h>
#include <linux/jhash.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <net/udp_tunnel.h>

/* Hardware control for EF10 architecture including 'Huntington'. */

#define EFX_EF10_DRVGEN_EV  7
enum {
 EFX_EF10_TEST = 1,
 EFX_EF10_REFILL,
};

/* VLAN list entry */
struct efx_ef10_vlan {
 struct list_head list;
 u16 vid;
};

static int efx_ef10_set_udp_tnl_ports(struct efx_nic *efx, bool unloading);
static const struct udp_tunnel_nic_info efx_ef10_udp_tunnels;

static int efx_ef10_get_warm_boot_count(struct efx_nic *efx)
{
 efx_dword_t reg;

 efx_readd(efx, ®, ER_DZ_BIU_MC_SFT_STATUS);
 return EFX_DWORD_FIELD(reg, EFX_WORD_1) == 0xb007 ?
  EFX_DWORD_FIELD(reg, EFX_WORD_0) : -EIO;
}

/* On all EF10s up to and including SFC9220 (Medford1), all PFs use BAR 0 for
 * I/O space and BAR 2(&3) for memory.  On SFC9250 (Medford2), there is no I/O
 * bar; PFs use BAR 0/1 for memory.
 */

static unsigned int efx_ef10_pf_mem_bar(struct efx_nic *efx)
{
 switch (efx->pci_dev->device) {
 case 0x0b03: /* SFC9250 PF */
  return 0;
 default:
  return 2;
 }
}

/* All VFs use BAR 0/1 for memory */
static unsigned int efx_ef10_vf_mem_bar(struct efx_nic *efx)
{
 return 0;
}

static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx)
{
 int bar;

 bar = efx->type->mem_bar(efx);
 return resource_size(&efx->pci_dev->resource[bar]);
}

static bool efx_ef10_is_vf(struct efx_nic *efx)
{
 return efx->type->is_vf;
}

#ifdef CONFIG_SFC_SRIOV
static int efx_ef10_get_vf_index(struct efx_nic *efx)
{
 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 size_t outlen;
 int rc;

 rc = efx_mcdi_rpc(efx, MC_CMD_GET_FUNCTION_INFO, NULL, 0, outbuf,
     sizeof(outbuf), &outlen);
 if (rc)
  return rc;
 if (outlen < sizeof(outbuf))
  return -EIO;

 nic_data->vf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_VF);
 return 0;
}
#endif

static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
{
 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V4_OUT_LEN);
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 size_t outlen;
 int rc;

 BUILD_BUG_ON(MC_CMD_GET_CAPABILITIES_IN_LEN != 0);

 rc = efx_mcdi_rpc(efx, MC_CMD_GET_CAPABILITIES, NULL, 0,
     outbuf, sizeof(outbuf), &outlen);
 if (rc)
  return rc;
 if (outlen < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
  netif_err(efx, drv, efx->net_dev,
     "unable to read datapath firmware capabilities\n");
  return -EIO;
 }

 nic_data->datapath_caps =
  MCDI_DWORD(outbuf, GET_CAPABILITIES_OUT_FLAGS1);

 if (outlen >= MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) {
  nic_data->datapath_caps2 = MCDI_DWORD(outbuf,
    GET_CAPABILITIES_V2_OUT_FLAGS2);
  nic_data->piobuf_size = MCDI_WORD(outbuf,
    GET_CAPABILITIES_V2_OUT_SIZE_PIO_BUFF);
 } else {
  nic_data->datapath_caps2 = 0;
  nic_data->piobuf_size = ER_DZ_TX_PIOBUF_SIZE;
 }

 /* record the DPCPU firmware IDs to determine VEB vswitching support.
 */

 nic_data->rx_dpcpu_fw_id =
  MCDI_WORD(outbuf, GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID);
 nic_data->tx_dpcpu_fw_id =
  MCDI_WORD(outbuf, GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID);

 if (!(nic_data->datapath_caps &
       (1 << MC_CMD_GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14_LBN))) {
  netif_err(efx, probe, efx->net_dev,
     "current firmware does not support an RX prefix\n");
  return -ENODEV;
 }

 if (outlen >= MC_CMD_GET_CAPABILITIES_V3_OUT_LEN) {
  u8 vi_window_mode = MCDI_BYTE(outbuf,
    GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE);

  rc = efx_mcdi_window_mode_to_stride(efx, vi_window_mode);
  if (rc)
   return rc;
 } else {
  /* keep default VI stride */
  netif_dbg(efx, probe, efx->net_dev,
     "firmware did not report VI window mode, assuming vi_stride = %u\n",
     efx->vi_stride);
 }

 if (outlen >= MC_CMD_GET_CAPABILITIES_V4_OUT_LEN) {
  efx->num_mac_stats = MCDI_WORD(outbuf,
    GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS);
  netif_dbg(efx, probe, efx->net_dev,
     "firmware reports num_mac_stats = %u\n",
     efx->num_mac_stats);
 } else {
  /* leave num_mac_stats as the default value, MC_CMD_MAC_NSTATS */
  netif_dbg(efx, probe, efx->net_dev,
     "firmware did not report num_mac_stats, assuming %u\n",
     efx->num_mac_stats);
 }

 return 0;
}

static void efx_ef10_read_licensed_features(struct efx_nic *efx)
{
 MCDI_DECLARE_BUF(inbuf, MC_CMD_LICENSING_V3_IN_LEN);
 MCDI_DECLARE_BUF(outbuf, MC_CMD_LICENSING_V3_OUT_LEN);
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 size_t outlen;
 int rc;

 MCDI_SET_DWORD(inbuf, LICENSING_V3_IN_OP,
         MC_CMD_LICENSING_V3_IN_OP_REPORT_LICENSE);
 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_LICENSING_V3, inbuf, sizeof(inbuf),
    outbuf, sizeof(outbuf), &outlen);
 if (rc || (outlen < MC_CMD_LICENSING_V3_OUT_LEN))
  return;

 nic_data->licensed_features = MCDI_QWORD(outbuf,
      LICENSING_V3_OUT_LICENSED_FEATURES);
}

static int efx_ef10_get_sysclk_freq(struct efx_nic *efx)
{
 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLOCK_OUT_LEN);
 int rc;

 rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLOCK, NULL, 0,
     outbuf, sizeof(outbuf), NULL);
 if (rc)
  return rc;
 rc = MCDI_DWORD(outbuf, GET_CLOCK_OUT_SYS_FREQ);
 return rc > 0 ? rc : -ERANGE;
}

static int efx_ef10_get_timer_workarounds(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 unsigned int implemented;
 unsigned int enabled;
 int rc;

 nic_data->workaround_35388 = false;
 nic_data->workaround_61265 = false;

 rc = efx_mcdi_get_workarounds(efx, &implemented, &enabled);

 if (rc == -ENOSYS) {
  /* Firmware without GET_WORKAROUNDS - not a problem. */
  rc = 0;
 } else if (rc == 0) {
  /* Bug61265 workaround is always enabled if implemented. */
  if (enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG61265)
   nic_data->workaround_61265 = true;

  if (enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG35388) {
   nic_data->workaround_35388 = true;
  } else if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG35388) {
   /* Workaround is implemented but not enabled.
 * Try to enable it.
 */

   rc = efx_mcdi_set_workaround(efx,
           MC_CMD_WORKAROUND_BUG35388,
           true, NULL);
   if (rc == 0)
    nic_data->workaround_35388 = true;
   /* If we failed to set the workaround just carry on. */
   rc = 0;
  }
 }

 netif_dbg(efx, probe, efx->net_dev,
    "workaround for bug 35388 is %sabled\n",
    nic_data->workaround_35388 ? "en" : "dis");
 netif_dbg(efx, probe, efx->net_dev,
    "workaround for bug 61265 is %sabled\n",
    nic_data->workaround_61265 ? "en" : "dis");

 return rc;
}

static void efx_ef10_process_timer_config(struct efx_nic *efx,
       const efx_dword_t *data)
{
 unsigned int max_count;

 if (EFX_EF10_WORKAROUND_61265(efx)) {
  efx->timer_quantum_ns = MCDI_DWORD(data,
   GET_EVQ_TMR_PROPERTIES_OUT_MCDI_TMR_STEP_NS);
  efx->timer_max_ns = MCDI_DWORD(data,
   GET_EVQ_TMR_PROPERTIES_OUT_MCDI_TMR_MAX_NS);
 } else if (EFX_EF10_WORKAROUND_35388(efx)) {
  efx->timer_quantum_ns = MCDI_DWORD(data,
   GET_EVQ_TMR_PROPERTIES_OUT_BUG35388_TMR_NS_PER_COUNT);
  max_count = MCDI_DWORD(data,
   GET_EVQ_TMR_PROPERTIES_OUT_BUG35388_TMR_MAX_COUNT);
  efx->timer_max_ns = max_count * efx->timer_quantum_ns;
 } else {
  efx->timer_quantum_ns = MCDI_DWORD(data,
   GET_EVQ_TMR_PROPERTIES_OUT_TMR_REG_NS_PER_COUNT);
  max_count = MCDI_DWORD(data,
   GET_EVQ_TMR_PROPERTIES_OUT_TMR_REG_MAX_COUNT);
  efx->timer_max_ns = max_count * efx->timer_quantum_ns;
 }

 netif_dbg(efx, probe, efx->net_dev,
    "got timer properties from MC: quantum %u ns; max %u ns\n",
    efx->timer_quantum_ns, efx->timer_max_ns);
}

static int efx_ef10_get_timer_config(struct efx_nic *efx)
{
 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_EVQ_TMR_PROPERTIES_OUT_LEN);
 int rc;

 rc = efx_ef10_get_timer_workarounds(efx);
 if (rc)
  return rc;

 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_EVQ_TMR_PROPERTIES, NULL, 0,
    outbuf, sizeof(outbuf), NULL);

 if (rc == 0) {
  efx_ef10_process_timer_config(efx, outbuf);
 } else if (rc == -ENOSYS || rc == -EPERM) {
  /* Not available - fall back to Huntington defaults. */
  unsigned int quantum;

  rc = efx_ef10_get_sysclk_freq(efx);
  if (rc < 0)
   return rc;

  quantum = 1536000 / rc; /* 1536 cycles */
  efx->timer_quantum_ns = quantum;
  efx->timer_max_ns = efx->type->timer_period_max * quantum;
  rc = 0;
 } else {
  efx_mcdi_display_error(efx, MC_CMD_GET_EVQ_TMR_PROPERTIES,
           MC_CMD_GET_EVQ_TMR_PROPERTIES_OUT_LEN,
           NULL, 0, rc);
 }

 return rc;
}

static int efx_ef10_get_mac_address_pf(struct efx_nic *efx, u8 *mac_address)
{
 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_MAC_ADDRESSES_OUT_LEN);
 size_t outlen;
 int rc;

 BUILD_BUG_ON(MC_CMD_GET_MAC_ADDRESSES_IN_LEN != 0);

 rc = efx_mcdi_rpc(efx, MC_CMD_GET_MAC_ADDRESSES, NULL, 0,
     outbuf, sizeof(outbuf), &outlen);
 if (rc)
  return rc;
 if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)
  return -EIO;

 ether_addr_copy(mac_address,
   MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE));
 return 0;
}

static int efx_ef10_get_mac_address_vf(struct efx_nic *efx, u8 *mac_address)
{
 MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN);
 MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX);
 size_t outlen;
 int num_addrs, rc;

 MCDI_SET_DWORD(inbuf, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
         EVB_PORT_ID_ASSIGNED);
 rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_GET_MAC_ADDRESSES, inbuf,
     sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);

 if (rc)
  return rc;
 if (outlen < MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN)
  return -EIO;

 num_addrs = MCDI_DWORD(outbuf,
          VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT);

 WARN_ON(num_addrs != 1);

 ether_addr_copy(mac_address,
   MCDI_PTR(outbuf, VPORT_GET_MAC_ADDRESSES_OUT_MACADDR));

 return 0;
}

static ssize_t link_control_flag_show(struct device *dev,
          struct device_attribute *attr,
          char *buf)
{
 struct efx_nic *efx = dev_get_drvdata(dev);

 return sprintf(buf, "%d\n",
         ((efx->mcdi->fn_flags) &
   (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL))
         ? 1 : 0);
}

static ssize_t primary_flag_show(struct device *dev,
     struct device_attribute *attr,
     char *buf)
{
 struct efx_nic *efx = dev_get_drvdata(dev);

 return sprintf(buf, "%d\n",
         ((efx->mcdi->fn_flags) &
   (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY))
         ? 1 : 0);
}

static struct efx_ef10_vlan *efx_ef10_find_vlan(struct efx_nic *efx, u16 vid)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 struct efx_ef10_vlan *vlan;

 WARN_ON(!mutex_is_locked(&nic_data->vlan_lock));

 list_for_each_entry(vlan, &nic_data->vlan_list, list) {
  if (vlan->vid == vid)
   return vlan;
 }

 return NULL;
}

static int efx_ef10_add_vlan(struct efx_nic *efx, u16 vid)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 struct efx_ef10_vlan *vlan;
 int rc;

 mutex_lock(&nic_data->vlan_lock);

 vlan = efx_ef10_find_vlan(efx, vid);
 if (vlan) {
  /* We add VID 0 on init. 8021q adds it on module init
 * for all interfaces with VLAN filtring feature.
 */

  if (vid == 0)
   goto done_unlock;
  netif_warn(efx, drv, efx->net_dev,
      "VLAN %u already added\n", vid);
  rc = -EALREADY;
  goto fail_exist;
 }

 rc = -ENOMEM;
 vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
 if (!vlan)
  goto fail_alloc;

 vlan->vid = vid;

 list_add_tail(&vlan->list, &nic_data->vlan_list);

 if (efx->filter_state) {
  mutex_lock(&efx->mac_lock);
  down_write(&efx->filter_sem);
  rc = efx_mcdi_filter_add_vlan(efx, vlan->vid);
  up_write(&efx->filter_sem);
  mutex_unlock(&efx->mac_lock);
  if (rc)
   goto fail_filter_add_vlan;
 }

done_unlock:
 mutex_unlock(&nic_data->vlan_lock);
 return 0;

fail_filter_add_vlan:
 list_del(&vlan->list);
 kfree(vlan);
fail_alloc:
fail_exist:
 mutex_unlock(&nic_data->vlan_lock);
 return rc;
}

static void efx_ef10_del_vlan_internal(struct efx_nic *efx,
           struct efx_ef10_vlan *vlan)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;

 WARN_ON(!mutex_is_locked(&nic_data->vlan_lock));

 if (efx->filter_state) {
  down_write(&efx->filter_sem);
  efx_mcdi_filter_del_vlan(efx, vlan->vid);
  up_write(&efx->filter_sem);
 }

 list_del(&vlan->list);
 kfree(vlan);
}

static int efx_ef10_del_vlan(struct efx_nic *efx, u16 vid)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 struct efx_ef10_vlan *vlan;
 int rc = 0;

 /* 8021q removes VID 0 on module unload for all interfaces
 * with VLAN filtering feature. We need to keep it to receive
 * untagged traffic.
 */

 if (vid == 0)
  return 0;

 mutex_lock(&nic_data->vlan_lock);

 vlan = efx_ef10_find_vlan(efx, vid);
 if (!vlan) {
  netif_err(efx, drv, efx->net_dev,
     "VLAN %u to be deleted not found\n", vid);
  rc = -ENOENT;
 } else {
  efx_ef10_del_vlan_internal(efx, vlan);
 }

 mutex_unlock(&nic_data->vlan_lock);

 return rc;
}

static void efx_ef10_cleanup_vlans(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 struct efx_ef10_vlan *vlan, *next_vlan;

 mutex_lock(&nic_data->vlan_lock);
 list_for_each_entry_safe(vlan, next_vlan, &nic_data->vlan_list, list)
  efx_ef10_del_vlan_internal(efx, vlan);
 mutex_unlock(&nic_data->vlan_lock);
}

static DEVICE_ATTR_RO(link_control_flag);
static DEVICE_ATTR_RO(primary_flag);

static int efx_ef10_probe(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data;
 int i, rc;

 nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
 if (!nic_data)
  return -ENOMEM;
 efx->nic_data = nic_data;

 /* we assume later that we can copy from this buffer in dwords */
 BUILD_BUG_ON(MCDI_CTL_SDU_LEN_MAX_V2 % 4);

 rc = efx_nic_alloc_buffer(efx, &nic_data->mcdi_buf,
      8 + MCDI_CTL_SDU_LEN_MAX_V2, GFP_KERNEL);
 if (rc)
  goto fail1;

 /* Get the MC's warm boot count.  In case it's rebooting right
 * now, be prepared to retry.
 */

 i = 0;
 for (;;) {
  rc = efx_ef10_get_warm_boot_count(efx);
  if (rc >= 0)
   break;
  if (++i == 5)
   goto fail2;
  ssleep(1);
 }
 nic_data->warm_boot_count = rc;

 /* In case we're recovering from a crash (kexec), we want to
 * cancel any outstanding request by the previous user of this
 * function.  We send a special message using the least
 * significant bits of the 'high' (doorbell) register.
 */

 _efx_writed(efx, cpu_to_le32(1), ER_DZ_MC_DB_HWRD);

 rc = efx_mcdi_init(efx);
 if (rc)
  goto fail2;

 mutex_init(&nic_data->udp_tunnels_lock);
 for (i = 0; i < ARRAY_SIZE(nic_data->udp_tunnels); ++i)
  nic_data->udp_tunnels[i].type =
   TUNNEL_ENCAP_UDP_PORT_ENTRY_INVALID;

 /* Reset (most) configuration for this function */
 rc = efx_mcdi_reset(efx, RESET_TYPE_ALL);
 if (rc)
  goto fail3;

 /* Enable event logging */
 rc = efx_mcdi_log_ctrl(efx, truefalse, 0);
 if (rc)
  goto fail3;

 rc = device_create_file(&efx->pci_dev->dev,
    &dev_attr_link_control_flag);
 if (rc)
  goto fail3;

 rc = device_create_file(&efx->pci_dev->dev, &dev_attr_primary_flag);
 if (rc)
  goto fail4;

 rc = efx_get_pf_index(efx, &nic_data->pf_index);
 if (rc)
  goto fail5;

 rc = efx_ef10_init_datapath_caps(efx);
 if (rc < 0)
  goto fail5;

 efx_ef10_read_licensed_features(efx);

 /* We can have one VI for each vi_stride-byte region.
 * However, until we use TX option descriptors we need up to four
 * TX queues per channel for different checksumming combinations.
 */

 if (nic_data->datapath_caps &
     (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN))
  efx->tx_queues_per_channel = 4;
 else
  efx->tx_queues_per_channel = 2;
 efx->max_vis = efx_ef10_mem_map_size(efx) / efx->vi_stride;
 if (!efx->max_vis) {
  netif_err(efx, drv, efx->net_dev, "error determining max VIs\n");
  rc = -EIO;
  goto fail5;
 }
 efx->max_channels = min_t(unsigned int, EFX_MAX_CHANNELS,
      efx->max_vis / efx->tx_queues_per_channel);
 efx->max_tx_channels = efx->max_channels;
 if (WARN_ON(efx->max_channels == 0)) {
  rc = -EIO;
  goto fail5;
 }

 efx->rx_packet_len_offset =
  ES_DZ_RX_PREFIX_PKTLEN_OFST - ES_DZ_RX_PREFIX_SIZE;

 if (nic_data->datapath_caps &
     (1 << MC_CMD_GET_CAPABILITIES_OUT_RX_INCLUDE_FCS_LBN))
  efx->net_dev->hw_features |= NETIF_F_RXFCS;

 rc = efx_mcdi_port_get_number(efx);
 if (rc < 0)
  goto fail5;
 efx->port_num = rc;

 rc = efx->type->get_mac_address(efx, efx->net_dev->perm_addr);
 if (rc)
  goto fail5;

 rc = efx_ef10_get_timer_config(efx);
 if (rc < 0)
  goto fail5;

 rc = efx_mcdi_mon_probe(efx);
 if (rc && rc != -EPERM)
  goto fail5;

 efx_ptp_defer_probe_with_channel(efx);

#ifdef CONFIG_SFC_SRIOV
 if ((efx->pci_dev->physfn) && (!efx->pci_dev->is_physfn)) {
  struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
  struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);

  efx_pf->type->get_mac_address(efx_pf, nic_data->port_id);
 } else
#endif
  ether_addr_copy(nic_data->port_id, efx->net_dev->perm_addr);

 INIT_LIST_HEAD(&nic_data->vlan_list);
 mutex_init(&nic_data->vlan_lock);

 /* Add unspecified VID to support VLAN filtering being disabled */
 rc = efx_ef10_add_vlan(efx, EFX_FILTER_VID_UNSPEC);
 if (rc)
  goto fail_add_vid_unspec;

 /* If VLAN filtering is enabled, we need VID 0 to get untagged
 * traffic.  It is added automatically if 8021q module is loaded,
 * but we can't rely on it since module may be not loaded.
 */

 rc = efx_ef10_add_vlan(efx, 0);
 if (rc)
  goto fail_add_vid_0;

 if (nic_data->datapath_caps &
     (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN) &&
     efx->mcdi->fn_flags &
     (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED))
  efx->net_dev->udp_tunnel_nic_info = &efx_ef10_udp_tunnels;

 return 0;

fail_add_vid_0:
 efx_ef10_cleanup_vlans(efx);
fail_add_vid_unspec:
 mutex_destroy(&nic_data->vlan_lock);
 efx_ptp_remove(efx);
 efx_mcdi_mon_remove(efx);
fail5:
 device_remove_file(&efx->pci_dev->dev, &dev_attr_primary_flag);
fail4:
 device_remove_file(&efx->pci_dev->dev, &dev_attr_link_control_flag);
fail3:
 efx_mcdi_detach(efx);

 mutex_lock(&nic_data->udp_tunnels_lock);
 memset(nic_data->udp_tunnels, 0, sizeof(nic_data->udp_tunnels));
 (void)efx_ef10_set_udp_tnl_ports(efx, true);
 mutex_unlock(&nic_data->udp_tunnels_lock);
 mutex_destroy(&nic_data->udp_tunnels_lock);

 efx_mcdi_fini(efx);
fail2:
 efx_nic_free_buffer(efx, &nic_data->mcdi_buf);
fail1:
 kfree(nic_data);
 efx->nic_data = NULL;
 return rc;
}

#ifdef EFX_USE_PIO

static void efx_ef10_free_piobufs(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 MCDI_DECLARE_BUF(inbuf, MC_CMD_FREE_PIOBUF_IN_LEN);
 unsigned int i;
 int rc;

 BUILD_BUG_ON(MC_CMD_FREE_PIOBUF_OUT_LEN != 0);

 for (i = 0; i < nic_data->n_piobufs; i++) {
  MCDI_SET_DWORD(inbuf, FREE_PIOBUF_IN_PIOBUF_HANDLE,
          nic_data->piobuf_handle[i]);
  rc = efx_mcdi_rpc(efx, MC_CMD_FREE_PIOBUF, inbuf, sizeof(inbuf),
      NULL, 0, NULL);
  WARN_ON(rc);
 }

 nic_data->n_piobufs = 0;
}

static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 MCDI_DECLARE_BUF(outbuf, MC_CMD_ALLOC_PIOBUF_OUT_LEN);
 unsigned int i;
 size_t outlen;
 int rc = 0;

 BUILD_BUG_ON(MC_CMD_ALLOC_PIOBUF_IN_LEN != 0);

 for (i = 0; i < n; i++) {
  rc = efx_mcdi_rpc_quiet(efx, MC_CMD_ALLOC_PIOBUF, NULL, 0,
     outbuf, sizeof(outbuf), &outlen);
  if (rc) {
   /* Don't display the MC error if we didn't have space
 * for a VF.
 */

   if (!(efx_ef10_is_vf(efx) && rc == -ENOSPC))
    efx_mcdi_display_error(efx, MC_CMD_ALLOC_PIOBUF,
             0, outbuf, outlen, rc);
   break;
  }
  if (outlen < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
   rc = -EIO;
   break;
  }
  nic_data->piobuf_handle[i] =
   MCDI_DWORD(outbuf, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE);
  netif_dbg(efx, probe, efx->net_dev,
     "allocated PIO buffer %u handle %x\n", i,
     nic_data->piobuf_handle[i]);
 }

 nic_data->n_piobufs = i;
 if (rc)
  efx_ef10_free_piobufs(efx);
 return rc;
}

static int efx_ef10_link_piobufs(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_PIOBUF_IN_LEN);
 struct efx_channel *channel;
 struct efx_tx_queue *tx_queue;
 unsigned int offset, index;
 int rc;

 BUILD_BUG_ON(MC_CMD_LINK_PIOBUF_OUT_LEN != 0);
 BUILD_BUG_ON(MC_CMD_UNLINK_PIOBUF_OUT_LEN != 0);

 /* Link a buffer to each VI in the write-combining mapping */
 for (index = 0; index < nic_data->n_piobufs; ++index) {
  MCDI_SET_DWORD(inbuf, LINK_PIOBUF_IN_PIOBUF_HANDLE,
          nic_data->piobuf_handle[index]);
  MCDI_SET_DWORD(inbuf, LINK_PIOBUF_IN_TXQ_INSTANCE,
          nic_data->pio_write_vi_base + index);
  rc = efx_mcdi_rpc(efx, MC_CMD_LINK_PIOBUF,
      inbuf, MC_CMD_LINK_PIOBUF_IN_LEN,
      NULL, 0, NULL);
  if (rc) {
   netif_err(efx, drv, efx->net_dev,
      "failed to link VI %u to PIO buffer %u (%d)\n",
      nic_data->pio_write_vi_base + index, index,
      rc);
   goto fail;
  }
  netif_dbg(efx, probe, efx->net_dev,
     "linked VI %u to PIO buffer %u\n",
     nic_data->pio_write_vi_base + index, index);
 }

 /* Link a buffer to each TX queue */
 efx_for_each_channel(channel, efx) {
  /* Extra channels, even those with TXQs (PTP), do not require
 * PIO resources.
 */

  if (!channel->type->want_pio ||
      channel->channel >= efx->xdp_channel_offset)
   continue;

  efx_for_each_channel_tx_queue(tx_queue, channel) {
   /* We assign the PIO buffers to queues in
 * reverse order to allow for the following
 * special case.
 */

   offset = ((efx->tx_channel_offset + efx->n_tx_channels -
       tx_queue->channel->channel - 1) *
      efx_piobuf_size);
   index = offset / nic_data->piobuf_size;
   offset = offset % nic_data->piobuf_size;

   /* When the host page size is 4K, the first
 * host page in the WC mapping may be within
 * the same VI page as the last TX queue.  We
 * can only link one buffer to each VI.
 */

   if (tx_queue->queue == nic_data->pio_write_vi_base) {
    BUG_ON(index != 0);
    rc = 0;
   } else {
    MCDI_SET_DWORD(inbuf,
            LINK_PIOBUF_IN_PIOBUF_HANDLE,
            nic_data->piobuf_handle[index]);
    MCDI_SET_DWORD(inbuf,
            LINK_PIOBUF_IN_TXQ_INSTANCE,
            tx_queue->queue);
    rc = efx_mcdi_rpc(efx, MC_CMD_LINK_PIOBUF,
        inbuf, MC_CMD_LINK_PIOBUF_IN_LEN,
        NULL, 0, NULL);
   }

   if (rc) {
    /* This is non-fatal; the TX path just
 * won't use PIO for this queue
 */

    netif_err(efx, drv, efx->net_dev,
       "failed to link VI %u to PIO buffer %u (%d)\n",
       tx_queue->queue, index, rc);
    tx_queue->piobuf = NULL;
   } else {
    tx_queue->piobuf =
     nic_data->pio_write_base +
     index * efx->vi_stride + offset;
    tx_queue->piobuf_offset = offset;
    netif_dbg(efx, probe, efx->net_dev,
       "linked VI %u to PIO buffer %u offset %x addr %p\n",
       tx_queue->queue, index,
       tx_queue->piobuf_offset,
       tx_queue->piobuf);
   }
  }
 }

 return 0;

fail:
 /* inbuf was defined for MC_CMD_LINK_PIOBUF.  We can use the same
 * buffer for MC_CMD_UNLINK_PIOBUF because it's shorter.
 */

 BUILD_BUG_ON(MC_CMD_LINK_PIOBUF_IN_LEN < MC_CMD_UNLINK_PIOBUF_IN_LEN);
 while (index--) {
  MCDI_SET_DWORD(inbuf, UNLINK_PIOBUF_IN_TXQ_INSTANCE,
          nic_data->pio_write_vi_base + index);
  efx_mcdi_rpc(efx, MC_CMD_UNLINK_PIOBUF,
        inbuf, MC_CMD_UNLINK_PIOBUF_IN_LEN,
        NULL, 0, NULL);
 }
 return rc;
}

static void efx_ef10_forget_old_piobufs(struct efx_nic *efx)
{
 struct efx_channel *channel;
 struct efx_tx_queue *tx_queue;

 /* All our existing PIO buffers went away */
 efx_for_each_channel(channel, efx)
  efx_for_each_channel_tx_queue(tx_queue, channel)
   tx_queue->piobuf = NULL;
}

#else /* !EFX_USE_PIO */

static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n)
{
 return n == 0 ? 0 : -ENOBUFS;
}

static int efx_ef10_link_piobufs(struct efx_nic *efx)
{
 return 0;
}

static void efx_ef10_free_piobufs(struct efx_nic *efx)
{
}

static void efx_ef10_forget_old_piobufs(struct efx_nic *efx)
{
}

#endif /* EFX_USE_PIO */

static void efx_ef10_remove(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 int rc;

#ifdef CONFIG_SFC_SRIOV
 struct efx_ef10_nic_data *nic_data_pf;
 struct pci_dev *pci_dev_pf;
 struct efx_nic *efx_pf;
 struct ef10_vf *vf;

 if (efx->pci_dev->is_virtfn) {
  pci_dev_pf = efx->pci_dev->physfn;
  if (pci_dev_pf) {
   efx_pf = pci_get_drvdata(pci_dev_pf);
   nic_data_pf = efx_pf->nic_data;
   vf = nic_data_pf->vf + nic_data->vf_index;
   vf->efx = NULL;
  } else
   netif_info(efx, drv, efx->net_dev,
       "Could not get the PF id from VF\n");
 }
#endif

 efx_ef10_cleanup_vlans(efx);
 mutex_destroy(&nic_data->vlan_lock);

 efx_ptp_remove(efx);

 efx_mcdi_mon_remove(efx);

 efx_mcdi_rx_free_indir_table(efx);

 if (nic_data->wc_membase)
  iounmap(nic_data->wc_membase);

 rc = efx_mcdi_free_vis(efx);
 WARN_ON(rc != 0);

 if (!nic_data->must_restore_piobufs)
  efx_ef10_free_piobufs(efx);

 device_remove_file(&efx->pci_dev->dev, &dev_attr_primary_flag);
 device_remove_file(&efx->pci_dev->dev, &dev_attr_link_control_flag);

 efx_mcdi_detach(efx);

 memset(nic_data->udp_tunnels, 0, sizeof(nic_data->udp_tunnels));
 mutex_lock(&nic_data->udp_tunnels_lock);
 (void)efx_ef10_set_udp_tnl_ports(efx, true);
 mutex_unlock(&nic_data->udp_tunnels_lock);

 mutex_destroy(&nic_data->udp_tunnels_lock);

 efx_mcdi_fini(efx);
 efx_nic_free_buffer(efx, &nic_data->mcdi_buf);
 kfree(nic_data);
}

static int efx_ef10_probe_pf(struct efx_nic *efx)
{
 return efx_ef10_probe(efx);
}

int efx_ef10_vadaptor_query(struct efx_nic *efx, unsigned int port_id,
       u32 *port_flags, u32 *vadaptor_flags,
       unsigned int *vlan_tags)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_QUERY_IN_LEN);
 MCDI_DECLARE_BUF(outbuf, MC_CMD_VADAPTOR_QUERY_OUT_LEN);
 size_t outlen;
 int rc;

 if (nic_data->datapath_caps &
     (1 << MC_CMD_GET_CAPABILITIES_OUT_VADAPTOR_QUERY_LBN)) {
  MCDI_SET_DWORD(inbuf, VADAPTOR_QUERY_IN_UPSTREAM_PORT_ID,
          port_id);

  rc = efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_QUERY, inbuf, sizeof(inbuf),
      outbuf, sizeof(outbuf), &outlen);
  if (rc)
   return rc;

  if (outlen < sizeof(outbuf)) {
   rc = -EIO;
   return rc;
  }
 }

 if (port_flags)
  *port_flags = MCDI_DWORD(outbuf, VADAPTOR_QUERY_OUT_PORT_FLAGS);
 if (vadaptor_flags)
  *vadaptor_flags =
   MCDI_DWORD(outbuf, VADAPTOR_QUERY_OUT_VADAPTOR_FLAGS);
 if (vlan_tags)
  *vlan_tags =
   MCDI_DWORD(outbuf,
       VADAPTOR_QUERY_OUT_NUM_AVAILABLE_VLAN_TAGS);

 return 0;
}

int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id)
{
 MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN);

 MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
 return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf),
       NULL, 0, NULL);
}

int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id)
{
 MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN);

 MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
 return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf),
       NULL, 0, NULL);
}

int efx_ef10_vport_add_mac(struct efx_nic *efx,
      unsigned int port_id, const u8 *mac)
{
 MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN);

 MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id);
 ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac);

 return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf,
       sizeof(inbuf), NULL, 0, NULL);
}

int efx_ef10_vport_del_mac(struct efx_nic *efx,
      unsigned int port_id, const u8 *mac)
{
 MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);

 MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
 ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);

 return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
       sizeof(inbuf), NULL, 0, NULL);
}

#ifdef CONFIG_SFC_SRIOV
static int efx_ef10_probe_vf(struct efx_nic *efx)
{
 int rc;
 struct pci_dev *pci_dev_pf;

 /* If the parent PF has no VF data structure, it doesn't know about this
 * VF so fail probe.  The VF needs to be re-created.  This can happen
 * if the PF driver was unloaded while any VF was assigned to a guest
 * (using Xen, only).
 */

 pci_dev_pf = efx->pci_dev->physfn;
 if (pci_dev_pf) {
  struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
  struct efx_ef10_nic_data *nic_data_pf = efx_pf->nic_data;

  if (!nic_data_pf->vf) {
   netif_info(efx, drv, efx->net_dev,
       "The VF cannot link to its parent PF; "
       "please destroy and re-create the VF\n");
   return -EBUSY;
  }
 }

 rc = efx_ef10_probe(efx);
 if (rc)
  return rc;

 rc = efx_ef10_get_vf_index(efx);
 if (rc)
  goto fail;

 if (efx->pci_dev->is_virtfn) {
  if (efx->pci_dev->physfn) {
   struct efx_nic *efx_pf =
    pci_get_drvdata(efx->pci_dev->physfn);
   struct efx_ef10_nic_data *nic_data_p = efx_pf->nic_data;
   struct efx_ef10_nic_data *nic_data = efx->nic_data;

   nic_data_p->vf[nic_data->vf_index].efx = efx;
   nic_data_p->vf[nic_data->vf_index].pci_dev =
    efx->pci_dev;
  } else
   netif_info(efx, drv, efx->net_dev,
       "Could not get the PF id from VF\n");
 }

 return 0;

fail:
 efx_ef10_remove(efx);
 return rc;
}
#else
static int efx_ef10_probe_vf(struct efx_nic *efx __attribute__ ((unused)))
{
 return 0;
}
#endif

static int efx_ef10_alloc_vis(struct efx_nic *efx,
         unsigned int min_vis, unsigned int max_vis)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;

 return efx_mcdi_alloc_vis(efx, min_vis, max_vis, &nic_data->vi_base,
      &nic_data->n_allocated_vis);
}

/* Note that the failure path of this function does not free
 * resources, as this will be done by efx_ef10_remove().
 */

static int efx_ef10_dimension_resources(struct efx_nic *efx)
{
 unsigned int min_vis = max_t(unsigned int, efx->tx_queues_per_channel,
         efx_separate_tx_channels ? 2 : 1);
 unsigned int channel_vis, pio_write_vi_base, max_vis;
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 unsigned int uc_mem_map_size, wc_mem_map_size;
 void __iomem *membase;
 int rc;

 channel_vis = max(efx->n_channels,
     ((efx->n_tx_channels + efx->n_extra_tx_channels) *
      efx->tx_queues_per_channel) +
      efx->n_xdp_channels * efx->xdp_tx_per_channel);
 if (efx->max_vis && efx->max_vis < channel_vis) {
  netif_dbg(efx, drv, efx->net_dev,
     "Reducing channel VIs from %u to %u\n",
     channel_vis, efx->max_vis);
  channel_vis = efx->max_vis;
 }

#ifdef EFX_USE_PIO
 /* Try to allocate PIO buffers if wanted and if the full
 * number of PIO buffers would be sufficient to allocate one
 * copy-buffer per TX channel.  Failure is non-fatal, as there
 * are only a small number of PIO buffers shared between all
 * functions of the controller.
 */

 if (efx_piobuf_size != 0 &&
     nic_data->piobuf_size / efx_piobuf_size * EF10_TX_PIOBUF_COUNT >=
     efx->n_tx_channels) {
  unsigned int n_piobufs =
   DIV_ROUND_UP(efx->n_tx_channels,
         nic_data->piobuf_size / efx_piobuf_size);

  rc = efx_ef10_alloc_piobufs(efx, n_piobufs);
  if (rc == -ENOSPC)
   netif_dbg(efx, probe, efx->net_dev,
      "out of PIO buffers; cannot allocate more\n");
  else if (rc == -EPERM)
   netif_dbg(efx, probe, efx->net_dev,
      "not permitted to allocate PIO buffers\n");
  else if (rc)
   netif_err(efx, probe, efx->net_dev,
      "failed to allocate PIO buffers (%d)\n", rc);
  else
   netif_dbg(efx, probe, efx->net_dev,
      "allocated %u PIO buffers\n", n_piobufs);
 }
#else
 nic_data->n_piobufs = 0;
#endif

 /* PIO buffers should be mapped with write-combining enabled,
 * and we want to make single UC and WC mappings rather than
 * several of each (in fact that's the only option if host
 * page size is >4K).  So we may allocate some extra VIs just
 * for writing PIO buffers through.
 *
 * The UC mapping contains (channel_vis - 1) complete VIs and the
 * first 4K of the next VI.  Then the WC mapping begins with
 * the remainder of this last VI.
 */

 uc_mem_map_size = PAGE_ALIGN((channel_vis - 1) * efx->vi_stride +
         ER_DZ_TX_PIOBUF);
 if (nic_data->n_piobufs) {
  /* pio_write_vi_base rounds down to give the number of complete
 * VIs inside the UC mapping.
 */

  pio_write_vi_base = uc_mem_map_size / efx->vi_stride;
  wc_mem_map_size = (PAGE_ALIGN((pio_write_vi_base +
            nic_data->n_piobufs) *
           efx->vi_stride) -
       uc_mem_map_size);
  max_vis = pio_write_vi_base + nic_data->n_piobufs;
 } else {
  pio_write_vi_base = 0;
  wc_mem_map_size = 0;
  max_vis = channel_vis;
 }

 /* In case the last attached driver failed to free VIs, do it now */
 rc = efx_mcdi_free_vis(efx);
 if (rc != 0)
  return rc;

 rc = efx_ef10_alloc_vis(efx, min_vis, max_vis);
 if (rc != 0)
  return rc;

 if (nic_data->n_allocated_vis < channel_vis) {
  netif_info(efx, drv, efx->net_dev,
      "Could not allocate enough VIs to satisfy RSS"
      " requirements. Performance may not be optimal.\n");
  /* We didn't get the VIs to populate our channels.
 * We could keep what we got but then we'd have more
 * interrupts than we need.
 * Instead calculate new max_channels and restart
 */

  efx->max_channels = nic_data->n_allocated_vis;
  efx->max_tx_channels =
   nic_data->n_allocated_vis / efx->tx_queues_per_channel;

  efx_mcdi_free_vis(efx);
  return -EAGAIN;
 }

 /* If we didn't get enough VIs to map all the PIO buffers, free the
 * PIO buffers
 */

 if (nic_data->n_piobufs &&
     nic_data->n_allocated_vis <
     pio_write_vi_base + nic_data->n_piobufs) {
  netif_dbg(efx, probe, efx->net_dev,
     "%u VIs are not sufficient to map %u PIO buffers\n",
     nic_data->n_allocated_vis, nic_data->n_piobufs);
  efx_ef10_free_piobufs(efx);
 }

 /* Shrink the original UC mapping of the memory BAR */
 membase = ioremap(efx->membase_phys, uc_mem_map_size);
 if (!membase) {
  netif_err(efx, probe, efx->net_dev,
     "could not shrink memory BAR to %x\n",
     uc_mem_map_size);
  return -ENOMEM;
 }
 iounmap(efx->membase);
 efx->membase = membase;

 /* Set up the WC mapping if needed */
 if (wc_mem_map_size) {
  nic_data->wc_membase = ioremap_wc(efx->membase_phys +
        uc_mem_map_size,
        wc_mem_map_size);
  if (!nic_data->wc_membase) {
   netif_err(efx, probe, efx->net_dev,
      "could not allocate WC mapping of size %x\n",
      wc_mem_map_size);
   return -ENOMEM;
  }
  nic_data->pio_write_vi_base = pio_write_vi_base;
  nic_data->pio_write_base =
   nic_data->wc_membase +
   (pio_write_vi_base * efx->vi_stride + ER_DZ_TX_PIOBUF -
    uc_mem_map_size);

  rc = efx_ef10_link_piobufs(efx);
  if (rc)
   efx_ef10_free_piobufs(efx);
 }

 netif_dbg(efx, probe, efx->net_dev,
    "memory BAR at %pa (virtual %p+%x UC, %p+%x WC)\n",
    &efx->membase_phys, efx->membase, uc_mem_map_size,
    nic_data->wc_membase, wc_mem_map_size);

 return 0;
}

static void efx_ef10_fini_nic(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;

 spin_lock_bh(&efx->stats_lock);
 kfree(nic_data->mc_stats);
 nic_data->mc_stats = NULL;
 spin_unlock_bh(&efx->stats_lock);
}

static int efx_ef10_init_nic(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 struct net_device *net_dev = efx->net_dev;
 netdev_features_t tun_feats, tso_feats;
 int rc;

 if (nic_data->must_check_datapath_caps) {
  rc = efx_ef10_init_datapath_caps(efx);
  if (rc)
   return rc;
  nic_data->must_check_datapath_caps = false;
 }

 if (efx->must_realloc_vis) {
  /* We cannot let the number of VIs change now */
  rc = efx_ef10_alloc_vis(efx, nic_data->n_allocated_vis,
     nic_data->n_allocated_vis);
  if (rc)
   return rc;
  efx->must_realloc_vis = false;
 }

 nic_data->mc_stats = kmalloc(efx->num_mac_stats * sizeof(__le64),
         GFP_KERNEL);
 if (!nic_data->mc_stats)
  return -ENOMEM;

 if (nic_data->must_restore_piobufs && nic_data->n_piobufs) {
  rc = efx_ef10_alloc_piobufs(efx, nic_data->n_piobufs);
  if (rc == 0) {
   rc = efx_ef10_link_piobufs(efx);
   if (rc)
    efx_ef10_free_piobufs(efx);
  }

  /* Log an error on failure, but this is non-fatal.
 * Permission errors are less important - we've presumably
 * had the PIO buffer licence removed.
 */

  if (rc == -EPERM)
   netif_dbg(efx, drv, efx->net_dev,
      "not permitted to restore PIO buffers\n");
  else if (rc)
   netif_err(efx, drv, efx->net_dev,
      "failed to restore PIO buffers (%d)\n", rc);
  nic_data->must_restore_piobufs = false;
 }

 /* encap features might change during reset if fw variant changed */
 if (efx_has_cap(efx, VXLAN_NVGRE) && !efx_ef10_is_vf(efx))
  net_dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 else
  net_dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);

 tun_feats = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE |
      NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM;
 tso_feats = NETIF_F_TSO | NETIF_F_TSO6;

 if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) {
  /* If this is first nic_init, or if it is a reset and a new fw
 * variant has added new features, enable them by default.
 * If the features are not new, maintain their current value.
 */

  if (!(net_dev->hw_features & tun_feats))
   net_dev->features |= tun_feats;
  net_dev->hw_enc_features |= tun_feats | tso_feats;
  net_dev->hw_features |= tun_feats;
 } else {
  net_dev->hw_enc_features &= ~(tun_feats | tso_feats);
  net_dev->hw_features &= ~tun_feats;
  net_dev->features &= ~tun_feats;
 }

 /* don't fail init if RSS setup doesn't work */
 rc = efx->type->rx_push_rss_config(efx, false,
        efx->rss_context.rx_indir_table, NULL);

 return 0;
}

static void efx_ef10_table_reset_mc_allocations(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
#ifdef CONFIG_SFC_SRIOV
 unsigned int i;
#endif

 /* All our allocations have been reset */
 efx->must_realloc_vis = true;
 efx_mcdi_filter_table_reset_mc_allocations(efx);
 nic_data->must_restore_piobufs = true;
 efx_ef10_forget_old_piobufs(efx);
 efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;

 /* Driver-created vswitches and vports must be re-created */
 nic_data->must_probe_vswitching = true;
 efx->vport_id = EVB_PORT_ID_ASSIGNED;
#ifdef CONFIG_SFC_SRIOV
 if (nic_data->vf)
  for (i = 0; i < efx->vf_count; i++)
   nic_data->vf[i].vport_id = 0;
#endif
}

static enum reset_type efx_ef10_map_reset_reason(enum reset_type reason)
{
 if (reason == RESET_TYPE_MC_FAILURE)
  return RESET_TYPE_DATAPATH;

 return efx_mcdi_map_reset_reason(reason);
}

static int efx_ef10_map_reset_flags(u32 *flags)
{
 enum {
  EF10_RESET_PORT = ((ETH_RESET_MAC | ETH_RESET_PHY) <<
       ETH_RESET_SHARED_SHIFT),
  EF10_RESET_MC = ((ETH_RESET_DMA | ETH_RESET_FILTER |
      ETH_RESET_OFFLOAD | ETH_RESET_MAC |
      ETH_RESET_PHY | ETH_RESET_MGMT) <<
     ETH_RESET_SHARED_SHIFT)
 };

 /* We assume for now that our PCI function is permitted to
 * reset everything.
 */


 if ((*flags & EF10_RESET_MC) == EF10_RESET_MC) {
  *flags &= ~EF10_RESET_MC;
  return RESET_TYPE_WORLD;
 }

 if ((*flags & EF10_RESET_PORT) == EF10_RESET_PORT) {
  *flags &= ~EF10_RESET_PORT;
  return RESET_TYPE_ALL;
 }

 /* no invisible reset implemented */

 return -EINVAL;
}

static int efx_ef10_reset(struct efx_nic *efx, enum reset_type reset_type)
{
 int rc = efx_mcdi_reset(efx, reset_type);

 /* Unprivileged functions return -EPERM, but need to return success
 * here so that the datapath is brought back up.
 */

 if (reset_type == RESET_TYPE_WORLD && rc == -EPERM)
  rc = 0;

 /* If it was a port reset, trigger reallocation of MC resources.
 * Note that on an MC reset nothing needs to be done now because we'll
 * detect the MC reset later and handle it then.
 * For an FLR, we never get an MC reset event, but the MC has reset all
 * resources assigned to us, so we have to trigger reallocation now.
 */

 if ((reset_type == RESET_TYPE_ALL ||
      reset_type == RESET_TYPE_MCDI_TIMEOUT) && !rc)
  efx_ef10_table_reset_mc_allocations(efx);
 return rc;
}

#define EF10_DMA_STAT(ext_name, mcdi_name)   \
 [EF10_STAT_ ## ext_name] =    \
 { #ext_name, 64, 8 * MC_CMD_MAC_ ## mcdi_name }
#define EF10_DMA_INVIS_STAT(int_name, mcdi_name)  \
 [EF10_STAT_ ## int_name] =    \
 { NULL, 64, 8 * MC_CMD_MAC_ ## mcdi_name }
#define EF10_OTHER_STAT(ext_name)    \
 [EF10_STAT_ ## ext_name] = { #ext_name, 0, 0 }

static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
 EF10_DMA_STAT(port_tx_bytes, TX_BYTES),
 EF10_DMA_STAT(port_tx_packets, TX_PKTS),
 EF10_DMA_STAT(port_tx_pause, TX_PAUSE_PKTS),
 EF10_DMA_STAT(port_tx_control, TX_CONTROL_PKTS),
 EF10_DMA_STAT(port_tx_unicast, TX_UNICAST_PKTS),
 EF10_DMA_STAT(port_tx_multicast, TX_MULTICAST_PKTS),
 EF10_DMA_STAT(port_tx_broadcast, TX_BROADCAST_PKTS),
 EF10_DMA_STAT(port_tx_lt64, TX_LT64_PKTS),
 EF10_DMA_STAT(port_tx_64, TX_64_PKTS),
 EF10_DMA_STAT(port_tx_65_to_127, TX_65_TO_127_PKTS),
 EF10_DMA_STAT(port_tx_128_to_255, TX_128_TO_255_PKTS),
 EF10_DMA_STAT(port_tx_256_to_511, TX_256_TO_511_PKTS),
 EF10_DMA_STAT(port_tx_512_to_1023, TX_512_TO_1023_PKTS),
 EF10_DMA_STAT(port_tx_1024_to_15xx, TX_1024_TO_15XX_PKTS),
 EF10_DMA_STAT(port_tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS),
 EF10_DMA_STAT(port_rx_bytes, RX_BYTES),
 EF10_DMA_INVIS_STAT(port_rx_bytes_minus_good_bytes, RX_BAD_BYTES),
 EF10_OTHER_STAT(port_rx_good_bytes),
 EF10_OTHER_STAT(port_rx_bad_bytes),
 EF10_DMA_STAT(port_rx_packets, RX_PKTS),
 EF10_DMA_STAT(port_rx_good, RX_GOOD_PKTS),
 EF10_DMA_STAT(port_rx_bad, RX_BAD_FCS_PKTS),
 EF10_DMA_STAT(port_rx_pause, RX_PAUSE_PKTS),
 EF10_DMA_STAT(port_rx_control, RX_CONTROL_PKTS),
 EF10_DMA_STAT(port_rx_unicast, RX_UNICAST_PKTS),
 EF10_DMA_STAT(port_rx_multicast, RX_MULTICAST_PKTS),
 EF10_DMA_STAT(port_rx_broadcast, RX_BROADCAST_PKTS),
 EF10_DMA_STAT(port_rx_lt64, RX_UNDERSIZE_PKTS),
 EF10_DMA_STAT(port_rx_64, RX_64_PKTS),
 EF10_DMA_STAT(port_rx_65_to_127, RX_65_TO_127_PKTS),
 EF10_DMA_STAT(port_rx_128_to_255, RX_128_TO_255_PKTS),
 EF10_DMA_STAT(port_rx_256_to_511, RX_256_TO_511_PKTS),
 EF10_DMA_STAT(port_rx_512_to_1023, RX_512_TO_1023_PKTS),
 EF10_DMA_STAT(port_rx_1024_to_15xx, RX_1024_TO_15XX_PKTS),
 EF10_DMA_STAT(port_rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS),
 EF10_DMA_STAT(port_rx_gtjumbo, RX_GTJUMBO_PKTS),
 EF10_DMA_STAT(port_rx_bad_gtjumbo, RX_JABBER_PKTS),
 EF10_DMA_STAT(port_rx_overflow, RX_OVERFLOW_PKTS),
 EF10_DMA_STAT(port_rx_align_error, RX_ALIGN_ERROR_PKTS),
 EF10_DMA_STAT(port_rx_length_error, RX_LENGTH_ERROR_PKTS),
 EF10_DMA_STAT(port_rx_nodesc_drops, RX_NODESC_DROPS),
 EFX_GENERIC_SW_STAT(rx_nodesc_trunc),
 EFX_GENERIC_SW_STAT(rx_noskb_drops),
 EF10_DMA_STAT(port_rx_pm_trunc_bb_overflow, PM_TRUNC_BB_OVERFLOW),
 EF10_DMA_STAT(port_rx_pm_discard_bb_overflow, PM_DISCARD_BB_OVERFLOW),
 EF10_DMA_STAT(port_rx_pm_trunc_vfifo_full, PM_TRUNC_VFIFO_FULL),
 EF10_DMA_STAT(port_rx_pm_discard_vfifo_full, PM_DISCARD_VFIFO_FULL),
 EF10_DMA_STAT(port_rx_pm_trunc_qbb, PM_TRUNC_QBB),
 EF10_DMA_STAT(port_rx_pm_discard_qbb, PM_DISCARD_QBB),
 EF10_DMA_STAT(port_rx_pm_discard_mapping, PM_DISCARD_MAPPING),
 EF10_DMA_STAT(port_rx_dp_q_disabled_packets, RXDP_Q_DISABLED_PKTS),
 EF10_DMA_STAT(port_rx_dp_di_dropped_packets, RXDP_DI_DROPPED_PKTS),
 EF10_DMA_STAT(port_rx_dp_streaming_packets, RXDP_STREAMING_PKTS),
 EF10_DMA_STAT(port_rx_dp_hlb_fetch, RXDP_HLB_FETCH_CONDITIONS),
 EF10_DMA_STAT(port_rx_dp_hlb_wait, RXDP_HLB_WAIT_CONDITIONS),
 EF10_DMA_STAT(rx_unicast, VADAPTER_RX_UNICAST_PACKETS),
 EF10_DMA_STAT(rx_unicast_bytes, VADAPTER_RX_UNICAST_BYTES),
 EF10_DMA_STAT(rx_multicast, VADAPTER_RX_MULTICAST_PACKETS),
 EF10_DMA_STAT(rx_multicast_bytes, VADAPTER_RX_MULTICAST_BYTES),
 EF10_DMA_STAT(rx_broadcast, VADAPTER_RX_BROADCAST_PACKETS),
 EF10_DMA_STAT(rx_broadcast_bytes, VADAPTER_RX_BROADCAST_BYTES),
 EF10_DMA_STAT(rx_bad, VADAPTER_RX_BAD_PACKETS),
 EF10_DMA_STAT(rx_bad_bytes, VADAPTER_RX_BAD_BYTES),
 EF10_DMA_STAT(rx_overflow, VADAPTER_RX_OVERFLOW),
 EF10_DMA_STAT(tx_unicast, VADAPTER_TX_UNICAST_PACKETS),
 EF10_DMA_STAT(tx_unicast_bytes, VADAPTER_TX_UNICAST_BYTES),
 EF10_DMA_STAT(tx_multicast, VADAPTER_TX_MULTICAST_PACKETS),
 EF10_DMA_STAT(tx_multicast_bytes, VADAPTER_TX_MULTICAST_BYTES),
 EF10_DMA_STAT(tx_broadcast, VADAPTER_TX_BROADCAST_PACKETS),
 EF10_DMA_STAT(tx_broadcast_bytes, VADAPTER_TX_BROADCAST_BYTES),
 EF10_DMA_STAT(tx_bad, VADAPTER_TX_BAD_PACKETS),
 EF10_DMA_STAT(tx_bad_bytes, VADAPTER_TX_BAD_BYTES),
 EF10_DMA_STAT(tx_overflow, VADAPTER_TX_OVERFLOW),
 EF10_DMA_STAT(fec_uncorrected_errors, FEC_UNCORRECTED_ERRORS),
 EF10_DMA_STAT(fec_corrected_errors, FEC_CORRECTED_ERRORS),
 EF10_DMA_STAT(fec_corrected_symbols_lane0, FEC_CORRECTED_SYMBOLS_LANE0),
 EF10_DMA_STAT(fec_corrected_symbols_lane1, FEC_CORRECTED_SYMBOLS_LANE1),
 EF10_DMA_STAT(fec_corrected_symbols_lane2, FEC_CORRECTED_SYMBOLS_LANE2),
 EF10_DMA_STAT(fec_corrected_symbols_lane3, FEC_CORRECTED_SYMBOLS_LANE3),
 EF10_DMA_STAT(ctpio_vi_busy_fallback, CTPIO_VI_BUSY_FALLBACK),
 EF10_DMA_STAT(ctpio_long_write_success, CTPIO_LONG_WRITE_SUCCESS),
 EF10_DMA_STAT(ctpio_missing_dbell_fail, CTPIO_MISSING_DBELL_FAIL),
 EF10_DMA_STAT(ctpio_overflow_fail, CTPIO_OVERFLOW_FAIL),
 EF10_DMA_STAT(ctpio_underflow_fail, CTPIO_UNDERFLOW_FAIL),
 EF10_DMA_STAT(ctpio_timeout_fail, CTPIO_TIMEOUT_FAIL),
 EF10_DMA_STAT(ctpio_noncontig_wr_fail, CTPIO_NONCONTIG_WR_FAIL),
 EF10_DMA_STAT(ctpio_frm_clobber_fail, CTPIO_FRM_CLOBBER_FAIL),
 EF10_DMA_STAT(ctpio_invalid_wr_fail, CTPIO_INVALID_WR_FAIL),
 EF10_DMA_STAT(ctpio_vi_clobber_fallback, CTPIO_VI_CLOBBER_FALLBACK),
 EF10_DMA_STAT(ctpio_unqualified_fallback, CTPIO_UNQUALIFIED_FALLBACK),
 EF10_DMA_STAT(ctpio_runt_fallback, CTPIO_RUNT_FALLBACK),
 EF10_DMA_STAT(ctpio_success, CTPIO_SUCCESS),
 EF10_DMA_STAT(ctpio_fallback, CTPIO_FALLBACK),
 EF10_DMA_STAT(ctpio_poison, CTPIO_POISON),
 EF10_DMA_STAT(ctpio_erase, CTPIO_ERASE),
};

#define HUNT_COMMON_STAT_MASK ((1ULL << EF10_STAT_port_tx_bytes) | \
          (1ULL << EF10_STAT_port_tx_packets) | \
          (1ULL << EF10_STAT_port_tx_pause) | \
          (1ULL << EF10_STAT_port_tx_unicast) | \
          (1ULL << EF10_STAT_port_tx_multicast) | \
          (1ULL << EF10_STAT_port_tx_broadcast) | \
          (1ULL << EF10_STAT_port_rx_bytes) | \
          (1ULL <<                                 \
    EF10_STAT_port_rx_bytes_minus_good_bytes) | \
          (1ULL << EF10_STAT_port_rx_good_bytes) | \
          (1ULL << EF10_STAT_port_rx_bad_bytes) | \
          (1ULL << EF10_STAT_port_rx_packets) | \
          (1ULL << EF10_STAT_port_rx_good) | \
          (1ULL << EF10_STAT_port_rx_bad) | \
          (1ULL << EF10_STAT_port_rx_pause) | \
          (1ULL << EF10_STAT_port_rx_control) | \
          (1ULL << EF10_STAT_port_rx_unicast) | \
          (1ULL << EF10_STAT_port_rx_multicast) | \
          (1ULL << EF10_STAT_port_rx_broadcast) | \
          (1ULL << EF10_STAT_port_rx_lt64) | \
          (1ULL << EF10_STAT_port_rx_64) |  \
          (1ULL << EF10_STAT_port_rx_65_to_127) | \
          (1ULL << EF10_STAT_port_rx_128_to_255) | \
          (1ULL << EF10_STAT_port_rx_256_to_511) | \
          (1ULL << EF10_STAT_port_rx_512_to_1023) |\
          (1ULL << EF10_STAT_port_rx_1024_to_15xx) |\
          (1ULL << EF10_STAT_port_rx_15xx_to_jumbo) |\
          (1ULL << EF10_STAT_port_rx_gtjumbo) | \
          (1ULL << EF10_STAT_port_rx_bad_gtjumbo) |\
          (1ULL << EF10_STAT_port_rx_overflow) | \
          (1ULL << EF10_STAT_port_rx_nodesc_drops) |\
          (1ULL << GENERIC_STAT_rx_nodesc_trunc) | \
          (1ULL << GENERIC_STAT_rx_noskb_drops))

/* On 7000 series NICs, these statistics are only provided by the 10G MAC.
 * For a 10G/40G switchable port we do not expose these because they might
 * not include all the packets they should.
 * On 8000 series NICs these statistics are always provided.
 */

#define HUNT_10G_ONLY_STAT_MASK ((1ULL << EF10_STAT_port_tx_control) | \
     (1ULL << EF10_STAT_port_tx_lt64) | \
     (1ULL << EF10_STAT_port_tx_64) | \
     (1ULL << EF10_STAT_port_tx_65_to_127) |\
     (1ULL << EF10_STAT_port_tx_128_to_255) |\
     (1ULL << EF10_STAT_port_tx_256_to_511) |\
     (1ULL << EF10_STAT_port_tx_512_to_1023) |\
     (1ULL << EF10_STAT_port_tx_1024_to_15xx) |\
     (1ULL << EF10_STAT_port_tx_15xx_to_jumbo))

/* These statistics are only provided by the 40G MAC.  For a 10G/40G
 * switchable port we do expose these because the errors will otherwise
 * be silent.
 */

#define HUNT_40G_EXTRA_STAT_MASK ((1ULL << EF10_STAT_port_rx_align_error) |\
      (1ULL << EF10_STAT_port_rx_length_error))

/* These statistics are only provided if the firmware supports the
 * capability PM_AND_RXDP_COUNTERS.
 */

#define HUNT_PM_AND_RXDP_STAT_MASK (     \
 (1ULL << EF10_STAT_port_rx_pm_trunc_bb_overflow) |  \
 (1ULL << EF10_STAT_port_rx_pm_discard_bb_overflow) |  \
 (1ULL << EF10_STAT_port_rx_pm_trunc_vfifo_full) |  \
 (1ULL << EF10_STAT_port_rx_pm_discard_vfifo_full) |  \
 (1ULL << EF10_STAT_port_rx_pm_trunc_qbb) |   \
 (1ULL << EF10_STAT_port_rx_pm_discard_qbb) |   \
 (1ULL << EF10_STAT_port_rx_pm_discard_mapping) |  \
 (1ULL << EF10_STAT_port_rx_dp_q_disabled_packets) |  \
 (1ULL << EF10_STAT_port_rx_dp_di_dropped_packets) |  \
 (1ULL << EF10_STAT_port_rx_dp_streaming_packets) |  \
 (1ULL << EF10_STAT_port_rx_dp_hlb_fetch) |   \
 (1ULL << EF10_STAT_port_rx_dp_hlb_wait))

/* These statistics are only provided if the NIC supports MC_CMD_MAC_STATS_V2,
 * indicated by returning a value >= MC_CMD_MAC_NSTATS_V2 in
 * MC_CMD_GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS.
 * These bits are in the second u64 of the raw mask.
 */

#define EF10_FEC_STAT_MASK (      \
 (1ULL << (EF10_STAT_fec_uncorrected_errors - 64)) |  \
 (1ULL << (EF10_STAT_fec_corrected_errors - 64)) |  \
 (1ULL << (EF10_STAT_fec_corrected_symbols_lane0 - 64)) | \
 (1ULL << (EF10_STAT_fec_corrected_symbols_lane1 - 64)) | \
 (1ULL << (EF10_STAT_fec_corrected_symbols_lane2 - 64)) | \
 (1ULL << (EF10_STAT_fec_corrected_symbols_lane3 - 64)))

/* These statistics are only provided if the NIC supports MC_CMD_MAC_STATS_V3,
 * indicated by returning a value >= MC_CMD_MAC_NSTATS_V3 in
 * MC_CMD_GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS.
 * These bits are in the second u64 of the raw mask.
 */

#define EF10_CTPIO_STAT_MASK (      \
 (1ULL << (EF10_STAT_ctpio_vi_busy_fallback - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_long_write_success - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_missing_dbell_fail - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_overflow_fail - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_underflow_fail - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_timeout_fail - 64)) |   \
 (1ULL << (EF10_STAT_ctpio_noncontig_wr_fail - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_frm_clobber_fail - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_invalid_wr_fail - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_vi_clobber_fallback - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_unqualified_fallback - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_runt_fallback - 64)) |  \
 (1ULL << (EF10_STAT_ctpio_success - 64)) |   \
 (1ULL << (EF10_STAT_ctpio_fallback - 64)) |   \
 (1ULL << (EF10_STAT_ctpio_poison - 64)) |   \
 (1ULL << (EF10_STAT_ctpio_erase - 64)))

static u64 efx_ef10_raw_stat_mask(struct efx_nic *efx)
{
 u64 raw_mask = HUNT_COMMON_STAT_MASK;
 u32 port_caps = efx_mcdi_phy_get_caps(efx);
 struct efx_ef10_nic_data *nic_data = efx->nic_data;

 if (!(efx->mcdi->fn_flags &
       1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL))
  return 0;

 if (port_caps & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) {
  raw_mask |= HUNT_40G_EXTRA_STAT_MASK;
  /* 8000 series have everything even at 40G */
  if (nic_data->datapath_caps2 &
      (1 << MC_CMD_GET_CAPABILITIES_V2_OUT_MAC_STATS_40G_TX_SIZE_BINS_LBN))
   raw_mask |= HUNT_10G_ONLY_STAT_MASK;
 } else {
  raw_mask |= HUNT_10G_ONLY_STAT_MASK;
 }

 if (nic_data->datapath_caps &
     (1 << MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_LBN))
  raw_mask |= HUNT_PM_AND_RXDP_STAT_MASK;

 return raw_mask;
}

static void efx_ef10_get_stat_mask(struct efx_nic *efx, unsigned long *mask)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 u64 raw_mask[2];

 raw_mask[0] = efx_ef10_raw_stat_mask(efx);

 /* Only show vadaptor stats when EVB capability is present */
 if (nic_data->datapath_caps &
     (1 << MC_CMD_GET_CAPABILITIES_OUT_EVB_LBN)) {
  raw_mask[0] |= ~((1ULL << EF10_STAT_rx_unicast) - 1);
  raw_mask[1] = (1ULL << (EF10_STAT_V1_COUNT - 64)) - 1;
 } else {
  raw_mask[1] = 0;
 }
 /* Only show FEC stats when NIC supports MC_CMD_MAC_STATS_V2 */
 if (efx->num_mac_stats >= MC_CMD_MAC_NSTATS_V2)
  raw_mask[1] |= EF10_FEC_STAT_MASK;

 /* CTPIO stats appear in V3. Only show them on devices that actually
 * support CTPIO. Although this driver doesn't use CTPIO others might,
 * and we may be reporting the stats for the underlying port.
 */

 if (efx->num_mac_stats >= MC_CMD_MAC_NSTATS_V3 &&
     (nic_data->datapath_caps2 &
      (1 << MC_CMD_GET_CAPABILITIES_V4_OUT_CTPIO_LBN)))
  raw_mask[1] |= EF10_CTPIO_STAT_MASK;

#if BITS_PER_LONG == 64
 BUILD_BUG_ON(BITS_TO_LONGS(EF10_STAT_COUNT) != 2);
 mask[0] = raw_mask[0];
 mask[1] = raw_mask[1];
#else
 BUILD_BUG_ON(BITS_TO_LONGS(EF10_STAT_COUNT) != 3);
 mask[0] = raw_mask[0] & 0xffffffff;
 mask[1] = raw_mask[0] >> 32;
 mask[2] = raw_mask[1] & 0xffffffff;
#endif
}

static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 **names)
{
 DECLARE_BITMAP(mask, EF10_STAT_COUNT);

 efx_ef10_get_stat_mask(efx, mask);
 return efx_nic_describe_stats(efx_ef10_stat_desc, EF10_STAT_COUNT,
          mask, names);
}

static void efx_ef10_get_fec_stats(struct efx_nic *efx,
       struct ethtool_fec_stats *fec_stats)
{
 DECLARE_BITMAP(mask, EF10_STAT_COUNT);
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 u64 *stats = nic_data->stats;

 efx_ef10_get_stat_mask(efx, mask);
 if (test_bit(EF10_STAT_fec_corrected_errors, mask))
  fec_stats->corrected_blocks.total =
   stats[EF10_STAT_fec_corrected_errors];
 if (test_bit(EF10_STAT_fec_uncorrected_errors, mask))
  fec_stats->uncorrectable_blocks.total =
   stats[EF10_STAT_fec_uncorrected_errors];
}

static size_t efx_ef10_update_stats_common(struct efx_nic *efx, u64 *full_stats,
        struct rtnl_link_stats64 *core_stats)
{
 DECLARE_BITMAP(mask, EF10_STAT_COUNT);
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 u64 *stats = nic_data->stats;
 size_t stats_count = 0, index;

 efx_ef10_get_stat_mask(efx, mask);

 if (full_stats) {
  for_each_set_bit(index, mask, EF10_STAT_COUNT) {
   if (efx_ef10_stat_desc[index].name) {
    *full_stats++ = stats[index];
    ++stats_count;
   }
  }
 }

 if (!core_stats)
  return stats_count;

 if (nic_data->datapath_caps &
   1 << MC_CMD_GET_CAPABILITIES_OUT_EVB_LBN) {
  /* Use vadaptor stats. */
  core_stats->rx_packets = stats[EF10_STAT_rx_unicast] +
      stats[EF10_STAT_rx_multicast] +
      stats[EF10_STAT_rx_broadcast];
  core_stats->tx_packets = stats[EF10_STAT_tx_unicast] +
      stats[EF10_STAT_tx_multicast] +
      stats[EF10_STAT_tx_broadcast];
  core_stats->rx_bytes = stats[EF10_STAT_rx_unicast_bytes] +
           stats[EF10_STAT_rx_multicast_bytes] +
           stats[EF10_STAT_rx_broadcast_bytes];
  core_stats->tx_bytes = stats[EF10_STAT_tx_unicast_bytes] +
           stats[EF10_STAT_tx_multicast_bytes] +
           stats[EF10_STAT_tx_broadcast_bytes];
  core_stats->rx_dropped = stats[GENERIC_STAT_rx_nodesc_trunc] +
      stats[GENERIC_STAT_rx_noskb_drops];
  core_stats->multicast = stats[EF10_STAT_rx_multicast];
  core_stats->rx_crc_errors = stats[EF10_STAT_rx_bad];
  core_stats->rx_fifo_errors = stats[EF10_STAT_rx_overflow];
  core_stats->rx_errors = core_stats->rx_crc_errors;
  core_stats->tx_errors = stats[EF10_STAT_tx_bad];
 } else {
  /* Use port stats. */
  core_stats->rx_packets = stats[EF10_STAT_port_rx_packets];
  core_stats->tx_packets = stats[EF10_STAT_port_tx_packets];
  core_stats->rx_bytes = stats[EF10_STAT_port_rx_bytes];
  core_stats->tx_bytes = stats[EF10_STAT_port_tx_bytes];
  core_stats->rx_dropped = stats[EF10_STAT_port_rx_nodesc_drops] +
      stats[GENERIC_STAT_rx_nodesc_trunc] +
      stats[GENERIC_STAT_rx_noskb_drops];
  core_stats->multicast = stats[EF10_STAT_port_rx_multicast];
  core_stats->rx_length_errors =
    stats[EF10_STAT_port_rx_gtjumbo] +
    stats[EF10_STAT_port_rx_length_error];
  core_stats->rx_crc_errors = stats[EF10_STAT_port_rx_bad];
  core_stats->rx_frame_errors =
    stats[EF10_STAT_port_rx_align_error];
  core_stats->rx_fifo_errors = stats[EF10_STAT_port_rx_overflow];
  core_stats->rx_errors = (core_stats->rx_length_errors +
      core_stats->rx_crc_errors +
      core_stats->rx_frame_errors);
 }

 return stats_count;
}

static size_t efx_ef10_update_stats_pf(struct efx_nic *efx, u64 *full_stats,
           struct rtnl_link_stats64 *core_stats)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 DECLARE_BITMAP(mask, EF10_STAT_COUNT);
 u64 *stats = nic_data->stats;

 efx_ef10_get_stat_mask(efx, mask);

 /* If NIC was fini'd (probably resetting), then we can't read
 * updated stats right now.
 */

 if (nic_data->mc_stats) {
  efx_nic_copy_stats(efx, nic_data->mc_stats);
  efx_nic_update_stats(efx_ef10_stat_desc, EF10_STAT_COUNT,
         mask, stats, nic_data->mc_stats, false);
 }

 /* Update derived statistics */
 efx_nic_fix_nodesc_drop_stat(efx,
         &stats[EF10_STAT_port_rx_nodesc_drops]);
 /* MC Firmware reads RX_BYTES and RX_GOOD_BYTES from the MAC.
 * It then calculates RX_BAD_BYTES and DMAs it to us with RX_BYTES.
 * We report these as port_rx_ stats. We are not given RX_GOOD_BYTES.
 * Here we calculate port_rx_good_bytes.
 */

 stats[EF10_STAT_port_rx_good_bytes] =
  stats[EF10_STAT_port_rx_bytes] -
  stats[EF10_STAT_port_rx_bytes_minus_good_bytes];

 /* The asynchronous reads used to calculate RX_BAD_BYTES in
 * MC Firmware are done such that we should not see an increase in
 * RX_BAD_BYTES when a good packet has arrived. Unfortunately this
 * does mean that the stat can decrease at times. Here we do not
 * update the stat unless it has increased or has gone to zero
 * (In the case of the NIC rebooting).
 * Please see Bug 33781 for a discussion of why things work this way.
 */

 efx_update_diff_stat(&stats[EF10_STAT_port_rx_bad_bytes],
        stats[EF10_STAT_port_rx_bytes_minus_good_bytes]);
 efx_update_sw_stats(efx, stats);

 return efx_ef10_update_stats_common(efx, full_stats, core_stats);
}

static int efx_ef10_try_update_nic_stats_vf(struct efx_nic *efx)
 __must_hold(&efx->stats_lock)
{
 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN);
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 DECLARE_BITMAP(mask, EF10_STAT_COUNT);
 __le64 generation_start, generation_end;
 u64 *stats = nic_data->stats;
 u32 dma_len = efx->num_mac_stats * sizeof(u64);
 struct efx_buffer stats_buf;
 __le64 *dma_stats;
 int rc;

 spin_unlock_bh(&efx->stats_lock);

 efx_ef10_get_stat_mask(efx, mask);

 rc = efx_nic_alloc_buffer(efx, &stats_buf, dma_len, GFP_KERNEL);
 if (rc) {
  spin_lock_bh(&efx->stats_lock);
  return rc;
 }

 dma_stats = stats_buf.addr;
 dma_stats[efx->num_mac_stats - 1] = EFX_MC_STATS_GENERATION_INVALID;

 MCDI_SET_QWORD(inbuf, MAC_STATS_IN_DMA_ADDR, stats_buf.dma_addr);
 MCDI_POPULATE_DWORD_1(inbuf, MAC_STATS_IN_CMD,
         MAC_STATS_IN_DMA, 1);
 MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len);
 MCDI_SET_DWORD(inbuf, MAC_STATS_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);

 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
    NULL, 0, NULL);
 spin_lock_bh(&efx->stats_lock);
 if (rc) {
  /* Expect ENOENT if DMA queues have not been set up */
  if (rc != -ENOENT || atomic_read(&efx->active_queues))
   efx_mcdi_display_error(efx, MC_CMD_MAC_STATS,
            sizeof(inbuf), NULL, 0, rc);
  goto out;
 }

 generation_end = dma_stats[efx->num_mac_stats - 1];
 if (generation_end == EFX_MC_STATS_GENERATION_INVALID) {
  WARN_ON_ONCE(1);
  goto out;
 }
 rmb();
 efx_nic_update_stats(efx_ef10_stat_desc, EF10_STAT_COUNT, mask,
        stats, stats_buf.addr, false);
 rmb();
 generation_start = dma_stats[MC_CMD_MAC_GENERATION_START];
 if (generation_end != generation_start) {
  rc = -EAGAIN;
  goto out;
 }

 efx_update_sw_stats(efx, stats);
out:
 /* releasing a DMA coherent buffer with BH disabled can panic */
 spin_unlock_bh(&efx->stats_lock);
 efx_nic_free_buffer(efx, &stats_buf);
 spin_lock_bh(&efx->stats_lock);
 return rc;
}

static size_t efx_ef10_update_stats_vf(struct efx_nic *efx, u64 *full_stats,
           struct rtnl_link_stats64 *core_stats)
{
 if (efx_ef10_try_update_nic_stats_vf(efx))
  return 0;

 return efx_ef10_update_stats_common(efx, full_stats, core_stats);
}

static size_t efx_ef10_update_stats_atomic_vf(struct efx_nic *efx, u64 *full_stats,
           struct rtnl_link_stats64 *core_stats)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;

 /* In atomic context, cannot update HW stats.  Just update the
 * software stats and return so the caller can continue.
 */

 efx_update_sw_stats(efx, nic_data->stats);
 return efx_ef10_update_stats_common(efx, full_stats, core_stats);
}

static void efx_ef10_push_irq_moderation(struct efx_channel *channel)
{
 struct efx_nic *efx = channel->efx;
 unsigned int mode, usecs;
 efx_dword_t timer_cmd;

 if (channel->irq_moderation_us) {
  mode = 3;
  usecs = channel->irq_moderation_us;
 } else {
  mode = 0;
  usecs = 0;
 }

 if (EFX_EF10_WORKAROUND_61265(efx)) {
  MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_EVQ_TMR_IN_LEN);
  unsigned int ns = usecs * 1000;

  MCDI_SET_DWORD(inbuf, SET_EVQ_TMR_IN_INSTANCE,
          channel->channel);
  MCDI_SET_DWORD(inbuf, SET_EVQ_TMR_IN_TMR_LOAD_REQ_NS, ns);
  MCDI_SET_DWORD(inbuf, SET_EVQ_TMR_IN_TMR_RELOAD_REQ_NS, ns);
  MCDI_SET_DWORD(inbuf, SET_EVQ_TMR_IN_TMR_MODE, mode);

  efx_mcdi_rpc_async(efx, MC_CMD_SET_EVQ_TMR,
       inbuf, sizeof(inbuf), 0, NULL, 0);
 } else if (EFX_EF10_WORKAROUND_35388(efx)) {
  unsigned int ticks = efx_usecs_to_ticks(efx, usecs);

  EFX_POPULATE_DWORD_3(timer_cmd, ERF_DD_EVQ_IND_TIMER_FLAGS,
         EFE_DD_EVQ_IND_TIMER_FLAGS,
         ERF_DD_EVQ_IND_TIMER_MODE, mode,
         ERF_DD_EVQ_IND_TIMER_VAL, ticks);
  efx_writed_page(efx, &timer_cmd, ER_DD_EVQ_INDIRECT,
    channel->channel);
 } else {
  unsigned int ticks = efx_usecs_to_ticks(efx, usecs);

  EFX_POPULATE_DWORD_3(timer_cmd, ERF_DZ_TC_TIMER_MODE, mode,
         ERF_DZ_TC_TIMER_VAL, ticks,
         ERF_FZ_TC_TMR_REL_VAL, ticks);
  efx_writed_page(efx, &timer_cmd, ER_DZ_EVQ_TMR,
    channel->channel);
 }
}

static void efx_ef10_get_wol_vf(struct efx_nic *efx,
    struct ethtool_wolinfo *wol) {}

static int efx_ef10_set_wol_vf(struct efx_nic *efx, u32 type)
{
 return -EOPNOTSUPP;
}

static void efx_ef10_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 efx_ef10_set_wol(struct efx_nic *efx, u32 type)
{
 if (type != 0)
  return -EINVAL;
 return 0;
}

static void efx_ef10_mcdi_request(struct efx_nic *efx,
      const efx_dword_t *hdr, size_t hdr_len,
      const efx_dword_t *sdu, size_t sdu_len)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 u8 *pdu = nic_data->mcdi_buf.addr;

 memcpy(pdu, hdr, hdr_len);
 memcpy(pdu + hdr_len, sdu, sdu_len);
 wmb();

 /* The hardware provides 'low' and 'high' (doorbell) registers
 * for passing the 64-bit address of an MCDI request to
 * firmware.  However the dwords are swapped by firmware.  The
 * least significant bits of the doorbell are then 0 for all
 * MCDI requests due to alignment.
 */

 _efx_writed(efx, cpu_to_le32((u64)nic_data->mcdi_buf.dma_addr >> 32),
      ER_DZ_MC_DB_LWRD);
 _efx_writed(efx, cpu_to_le32((u32)nic_data->mcdi_buf.dma_addr),
      ER_DZ_MC_DB_HWRD);
}

static bool efx_ef10_mcdi_poll_response(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 const efx_dword_t hdr = *(const efx_dword_t *)nic_data->mcdi_buf.addr;

 rmb();
 return EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE);
}

static void
efx_ef10_mcdi_read_response(struct efx_nic *efx, efx_dword_t *outbuf,
       size_t offset, size_t outlen)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 const u8 *pdu = nic_data->mcdi_buf.addr;

 memcpy(outbuf, pdu + offset, outlen);
}

static void efx_ef10_mcdi_reboot_detected(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;

 /* All our allocations have been reset */
 efx_ef10_table_reset_mc_allocations(efx);

 /* The datapath firmware might have been changed */
 nic_data->must_check_datapath_caps = true;

 /* MAC statistics have been cleared on the NIC; clear the local
 * statistic that we update with efx_update_diff_stat().
 */

 nic_data->stats[EF10_STAT_port_rx_bad_bytes] = 0;
}

static int efx_ef10_mcdi_poll_reboot(struct efx_nic *efx)
{
 struct efx_ef10_nic_data *nic_data = efx->nic_data;
 int rc;

 rc = efx_ef10_get_warm_boot_count(efx);
 if (rc < 0) {
  /* The firmware is presumably in the process of
 * rebooting.  However, we are supposed to report each
 * reboot just once, so we must only do that once we
 * can read and store the updated warm boot count.
 */

  return 0;
 }

 if (rc == nic_data->warm_boot_count)
  return 0;

 nic_data->warm_boot_count = rc;
 efx_ef10_mcdi_reboot_detected(efx);

 return -EIO;
}

/* Handle an MSI interrupt
 *
 * Handle an MSI hardware interrupt.  This routine schedules event
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=89 G=93

¤ Dauer der Verarbeitung: 0.9 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge