Commit 86f968a0 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sfc-driver-for-EF100-family-NICs-part-1'



Edward Cree says:

====================
sfc: driver for EF100 family NICs, part 1

EF100 is a new NIC architecture under development at Xilinx, based
 partly on existing Solarflare technology.  As many of the hardware
 interfaces resemble EF10, support is implemented within the 'sfc'
 driver, which previous patch series "commonised" for this purpose.

In order to maintain bisectability while splitting into patches of a
 reasonable size, I had to do a certain amount of back-and-forth with
 stubs for things that the common code may try to call, mainly because
 we can't do them until we've set up MCDI, but we can't set up MCDI
 without probing the event queues, at which point a lot of the common
 machinery becomes reachable from event handlers.
Consequently, this first series doesn't get as far as actually sending
 and receiving packets.  I have a second series ready to follow it
 which implements the datapath (and a few other things like ethtool).

Changes from v4:
 * Fix build on CONFIG_RETPOLINE=n by using plain prototypes instead
   of INDIRECT_CALLABLE_DECLARE.

Changes from v3:
 * combine both drivers (sfc_ef100 and sfc) into a single module, to
   make non-modular builds work.  Patch #4 now adds a few indirections
   to support this; the ones in the RX and TX path use indirect-call-
   wrappers to minimise the performance impact.

Changes from v2:
 * remove MODULE_VERSION.
 * call efx_destroy_reset_workqueue() from ef100_exit_module().
 * correct uint32_ts to u32s.  While I was at it, I fixed a bunch of
   other style issues in the function-control-window code.
All in patch #4.

Changes from v1:
 * kernel test robot spotted a link error when sfc_ef100 was built
   without mdio.  It turns out the thing we were trying to link to
   was a bogus thing to do on anything but Falcon, so new patch #1
   removes it from this driver.
 * fix undeclared symbols in patch #4 by shuffling around prototypes
   and #includes and adding 'static' where appropriate.
 * fix uninitialised variable 'rc2' in patch #7.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 65ccbbda 1c748843
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ config NET_VENDOR_SOLARFLARE
if NET_VENDOR_SOLARFLARE

config SFC
	tristate "Solarflare SFC9000/SFC9100-family support"
	tristate "Solarflare SFC9000/SFC9100/EF100-family support"
	depends on PCI
	select MDIO
	select CRC32
@@ -26,6 +26,9 @@ config SFC
	  This driver supports 10/40-gigabit Ethernet cards based on
	  the Solarflare SFC9000-family and SFC9100-family controllers.

	  It also supports 10/25/40/100-gigabit Ethernet cards based
	  on the Solarflare EF100 networking IP in Xilinx FPGAs.

	  To compile this driver as a module, choose M here.  The module
	  will be called sfc.
config SFC_MTD
+3 −1
Original line number Diff line number Diff line
@@ -4,7 +4,9 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \
			   tx.o tx_common.o tx_tso.o rx.o rx_common.o \
			   selftest.o ethtool.o ethtool_common.o ptp.o \
			   mcdi.o mcdi_port.o mcdi_port_common.o \
			   mcdi_functions.o mcdi_filters.o mcdi_mon.o
			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
			   ef100.o ef100_nic.o ef100_netdev.o \
			   ef100_ethtool.o ef100_rx.o ef100_tx.o
sfc-$(CONFIG_SFC_MTD)	+= mtd.o
sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o siena_sriov.o ef10_sriov.o

+7 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include "net_driver.h"
#include "rx_common.h"
#include "tx_common.h"
#include "ef10_regs.h"
#include "io.h"
#include "mcdi.h"
@@ -3977,6 +3978,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
	.tx_remove = efx_mcdi_tx_remove,
	.tx_write = efx_ef10_tx_write,
	.tx_limit_len = efx_ef10_tx_limit_len,
	.tx_enqueue = __efx_enqueue_skb,
	.rx_push_rss_config = efx_mcdi_vf_rx_push_rss_config,
	.rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
	.rx_probe = efx_mcdi_rx_probe,
@@ -3984,6 +3986,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
	.rx_remove = efx_mcdi_rx_remove,
	.rx_write = efx_ef10_rx_write,
	.rx_defer_refill = efx_ef10_rx_defer_refill,
	.rx_packet = __efx_rx_packet,
	.ev_probe = efx_mcdi_ev_probe,
	.ev_init = efx_ef10_ev_init,
	.ev_fini = efx_mcdi_ev_fini,
@@ -4038,6 +4041,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
	.rx_hash_key_size = 40,
	.check_caps = ef10_check_caps,
	.print_additional_fwver = efx_ef10_print_additional_fwver,
	.sensor_event = efx_mcdi_sensor_event,
};

const struct efx_nic_type efx_hunt_a0_nic_type = {
@@ -4087,6 +4091,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
	.tx_remove = efx_mcdi_tx_remove,
	.tx_write = efx_ef10_tx_write,
	.tx_limit_len = efx_ef10_tx_limit_len,
	.tx_enqueue = __efx_enqueue_skb,
	.rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config,
	.rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
	.rx_push_rss_context_config = efx_mcdi_rx_push_rss_context_config,
@@ -4097,6 +4102,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
	.rx_remove = efx_mcdi_rx_remove,
	.rx_write = efx_ef10_rx_write,
	.rx_defer_refill = efx_ef10_rx_defer_refill,
	.rx_packet = __efx_rx_packet,
	.ev_probe = efx_mcdi_ev_probe,
	.ev_init = efx_ef10_ev_init,
	.ev_fini = efx_mcdi_ev_fini,
@@ -4172,4 +4178,5 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
	.rx_hash_key_size = 40,
	.check_caps = ef10_check_caps,
	.print_additional_fwver = efx_ef10_print_additional_fwver,
	.sensor_event = efx_mcdi_sensor_event,
};
+541 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
 * Driver for Solarflare network controllers and boards
 * Copyright 2005-2018 Solarflare Communications Inc.
 * Copyright 2019-2020 Xilinx 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 "net_driver.h"
#include <linux/module.h>
#include <linux/aer.h>
#include "efx_common.h"
#include "efx_channels.h"
#include "io.h"
#include "ef100_nic.h"
#include "ef100_netdev.h"
#include "ef100_regs.h"
#include "ef100.h"

#define EFX_EF100_PCI_DEFAULT_BAR	2

/* Number of bytes at start of vendor specified extended capability that indicate
 * that the capability is vendor specified. i.e. offset from value returned by
 * pci_find_next_ext_capability() to beginning of vendor specified capability
 * header.
 */
#define PCI_EXT_CAP_HDR_LENGTH  4

/* Expected size of a Xilinx continuation address table entry. */
#define ESE_GZ_CFGBAR_CONT_CAP_MIN_LENGTH      16

struct ef100_func_ctl_window {
	bool valid;
	unsigned int bar;
	u64 offset;
};

static int ef100_pci_walk_xilinx_table(struct efx_nic *efx, u64 offset,
				       struct ef100_func_ctl_window *result);

/* Number of bytes to offset when reading bit position x with dword accessors. */
#define ROUND_DOWN_TO_DWORD(x) (((x) & (~31)) >> 3)

#define EXTRACT_BITS(x, lbn, width) \
	(((x) >> ((lbn) & 31)) & ((1ull << (width)) - 1))

static u32 _ef100_pci_get_bar_bits_with_width(struct efx_nic *efx,
					      int structure_start,
					      int lbn, int width)
{
	efx_dword_t dword;

	efx_readd(efx, &dword, structure_start + ROUND_DOWN_TO_DWORD(lbn));

	return EXTRACT_BITS(le32_to_cpu(dword.u32[0]), lbn, width);
}

#define ef100_pci_get_bar_bits(efx, entry_location, bitdef)	\
	_ef100_pci_get_bar_bits_with_width(efx, entry_location,	\
		ESF_GZ_CFGBAR_ ## bitdef ## _LBN,		\
		ESF_GZ_CFGBAR_ ## bitdef ## _WIDTH)

static int ef100_pci_parse_ef100_entry(struct efx_nic *efx, int entry_location,
				       struct ef100_func_ctl_window *result)
{
	u64 offset = ef100_pci_get_bar_bits(efx, entry_location, EF100_FUNC_CTL_WIN_OFF) <<
					ESE_GZ_EF100_FUNC_CTL_WIN_OFF_SHIFT;
	u32 bar = ef100_pci_get_bar_bits(efx, entry_location, EF100_BAR);

	netif_dbg(efx, probe, efx->net_dev,
		  "Found EF100 function control window bar=%d offset=0x%llx\n",
		  bar, offset);

	if (result->valid) {
		netif_err(efx, probe, efx->net_dev,
			  "Duplicated EF100 table entry.\n");
		return -EINVAL;
	}

	if (bar == ESE_GZ_CFGBAR_EF100_BAR_NUM_EXPANSION_ROM ||
	    bar == ESE_GZ_CFGBAR_EF100_BAR_NUM_INVALID) {
		netif_err(efx, probe, efx->net_dev,
			  "Bad BAR value of %d in Xilinx capabilities EF100 entry.\n",
			  bar);
		return -EINVAL;
	}

	result->bar = bar;
	result->offset = offset;
	result->valid = true;
	return 0;
}

static bool ef100_pci_does_bar_overflow(struct efx_nic *efx, int bar,
					u64 next_entry)
{
	return next_entry + ESE_GZ_CFGBAR_ENTRY_HEADER_SIZE >
					pci_resource_len(efx->pci_dev, bar);
}

/* Parse a Xilinx capabilities table entry describing a continuation to a new
 * sub-table.
 */
static int ef100_pci_parse_continue_entry(struct efx_nic *efx, int entry_location,
					  struct ef100_func_ctl_window *result)
{
	unsigned int previous_bar;
	efx_oword_t entry;
	u64 offset;
	int rc = 0;
	u32 bar;

	efx_reado(efx, &entry, entry_location);

	bar = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_CONT_CAP_BAR);

	offset = EFX_OWORD_FIELD64(entry, ESF_GZ_CFGBAR_CONT_CAP_OFFSET) <<
		ESE_GZ_CONT_CAP_OFFSET_BYTES_SHIFT;

	previous_bar = efx->mem_bar;

	if (bar == ESE_GZ_VSEC_BAR_NUM_EXPANSION_ROM ||
	    bar == ESE_GZ_VSEC_BAR_NUM_INVALID) {
		netif_err(efx, probe, efx->net_dev,
			  "Bad BAR value of %d in Xilinx capabilities sub-table.\n",
			  bar);
		return -EINVAL;
	}

	if (bar != previous_bar) {
		efx_fini_io(efx);

		if (ef100_pci_does_bar_overflow(efx, bar, offset)) {
			netif_err(efx, probe, efx->net_dev,
				  "Xilinx table will overrun BAR[%d] offset=0x%llx\n",
				  bar, offset);
			return -EINVAL;
		}

		/* Temporarily map new BAR. */
		rc = efx_init_io(efx, bar,
				 DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
				 pci_resource_len(efx->pci_dev, bar));
		if (rc) {
			netif_err(efx, probe, efx->net_dev,
				  "Mapping new BAR for Xilinx table failed, rc=%d\n", rc);
			return rc;
		}
	}

	rc = ef100_pci_walk_xilinx_table(efx, offset, result);
	if (rc)
		return rc;

	if (bar != previous_bar) {
		efx_fini_io(efx);

		/* Put old BAR back. */
		rc = efx_init_io(efx, previous_bar,
				 DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
				 pci_resource_len(efx->pci_dev, previous_bar));
		if (rc) {
			netif_err(efx, probe, efx->net_dev,
				  "Putting old BAR back failed, rc=%d\n", rc);
			return rc;
		}
	}

	return 0;
}

/* Iterate over the Xilinx capabilities table in the currently mapped BAR and
 * call ef100_pci_parse_ef100_entry() on any EF100 entries and
 * ef100_pci_parse_continue_entry() on any table continuations.
 */
static int ef100_pci_walk_xilinx_table(struct efx_nic *efx, u64 offset,
				       struct ef100_func_ctl_window *result)
{
	u64 current_entry = offset;
	int rc = 0;

	while (true) {
		u32 id = ef100_pci_get_bar_bits(efx, current_entry, ENTRY_FORMAT);
		u32 last = ef100_pci_get_bar_bits(efx, current_entry, ENTRY_LAST);
		u32 rev = ef100_pci_get_bar_bits(efx, current_entry, ENTRY_REV);
		u32 entry_size;

		if (id == ESE_GZ_CFGBAR_ENTRY_LAST)
			return 0;

		entry_size = ef100_pci_get_bar_bits(efx, current_entry, ENTRY_SIZE);

		netif_dbg(efx, probe, efx->net_dev,
			  "Seen Xilinx table entry 0x%x size 0x%x at 0x%llx in BAR[%d]\n",
			  id, entry_size, current_entry, efx->mem_bar);

		if (entry_size < sizeof(u32) * 2) {
			netif_err(efx, probe, efx->net_dev,
				  "Xilinx table entry too short len=0x%x\n", entry_size);
			return -EINVAL;
		}

		switch (id) {
		case ESE_GZ_CFGBAR_ENTRY_EF100:
			if (rev != ESE_GZ_CFGBAR_ENTRY_REV_EF100 ||
			    entry_size < ESE_GZ_CFGBAR_ENTRY_SIZE_EF100) {
				netif_err(efx, probe, efx->net_dev,
					  "Bad length or rev for EF100 entry in Xilinx capabilities table. entry_size=%d rev=%d.\n",
					  entry_size, rev);
				return -EINVAL;
			}

			rc = ef100_pci_parse_ef100_entry(efx, current_entry,
							 result);
			if (rc)
				return rc;
			break;
		case ESE_GZ_CFGBAR_ENTRY_CONT_CAP_ADDR:
			if (rev != 0 || entry_size < ESE_GZ_CFGBAR_CONT_CAP_MIN_LENGTH) {
				netif_err(efx, probe, efx->net_dev,
					  "Bad length or rev for continue entry in Xilinx capabilities table. entry_size=%d rev=%d.\n",
					  entry_size, rev);
				return -EINVAL;
			}

			rc = ef100_pci_parse_continue_entry(efx, current_entry, result);
			if (rc)
				return rc;
			break;
		default:
			/* Ignore unknown table entries. */
			break;
		}

		if (last)
			return 0;

		current_entry += entry_size;

		if (ef100_pci_does_bar_overflow(efx, efx->mem_bar, current_entry)) {
			netif_err(efx, probe, efx->net_dev,
				  "Xilinx table overrun at position=0x%llx.\n",
				  current_entry);
			return -EINVAL;
		}
	}
}

static int _ef100_pci_get_config_bits_with_width(struct efx_nic *efx,
						 int structure_start, int lbn,
						 int width, u32 *result)
{
	int rc, pos = structure_start + ROUND_DOWN_TO_DWORD(lbn);
	u32 temp;

	rc = pci_read_config_dword(efx->pci_dev, pos, &temp);
	if (rc) {
		netif_err(efx, probe, efx->net_dev,
			  "Failed to read PCI config dword at %d\n",
			  pos);
		return rc;
	}

	*result = EXTRACT_BITS(temp, lbn, width);

	return 0;
}

#define ef100_pci_get_config_bits(efx, entry_location, bitdef, result)	\
	_ef100_pci_get_config_bits_with_width(efx, entry_location,	\
		 ESF_GZ_VSEC_ ## bitdef ## _LBN,			\
		 ESF_GZ_VSEC_ ## bitdef ## _WIDTH, result)

/* Call ef100_pci_walk_xilinx_table() for the Xilinx capabilities table pointed
 * to by this PCI_EXT_CAP_ID_VNDR.
 */
static int ef100_pci_parse_xilinx_cap(struct efx_nic *efx, int vndr_cap,
				      bool has_offset_hi,
				      struct ef100_func_ctl_window *result)
{
	u32 offset_high = 0;
	u32 offset_lo = 0;
	u64 offset = 0;
	u32 bar = 0;
	int rc = 0;

	rc = ef100_pci_get_config_bits(efx, vndr_cap, TBL_BAR, &bar);
	if (rc) {
		netif_err(efx, probe, efx->net_dev,
			  "Failed to read ESF_GZ_VSEC_TBL_BAR, rc=%d\n",
			  rc);
		return rc;
	}

	if (bar == ESE_GZ_CFGBAR_CONT_CAP_BAR_NUM_EXPANSION_ROM ||
	    bar == ESE_GZ_CFGBAR_CONT_CAP_BAR_NUM_INVALID) {
		netif_err(efx, probe, efx->net_dev,
			  "Bad BAR value of %d in Xilinx capabilities sub-table.\n",
			  bar);
		return -EINVAL;
	}

	rc = ef100_pci_get_config_bits(efx, vndr_cap, TBL_OFF_LO, &offset_lo);
	if (rc) {
		netif_err(efx, probe, efx->net_dev,
			  "Failed to read ESF_GZ_VSEC_TBL_OFF_LO, rc=%d\n",
			  rc);
		return rc;
	}

	/* Get optional extension to 64bit offset. */
	if (has_offset_hi) {
		rc = ef100_pci_get_config_bits(efx, vndr_cap, TBL_OFF_HI, &offset_high);
		if (rc) {
			netif_err(efx, probe, efx->net_dev,
				  "Failed to read ESF_GZ_VSEC_TBL_OFF_HI, rc=%d\n",
				  rc);
			return rc;
		}
	}

	offset = (((u64)offset_lo) << ESE_GZ_VSEC_TBL_OFF_LO_BYTES_SHIFT) |
		 (((u64)offset_high) << ESE_GZ_VSEC_TBL_OFF_HI_BYTES_SHIFT);

	if (offset > pci_resource_len(efx->pci_dev, bar) - sizeof(u32) * 2) {
		netif_err(efx, probe, efx->net_dev,
			  "Xilinx table will overrun BAR[%d] offset=0x%llx\n",
			  bar, offset);
		return -EINVAL;
	}

	/* Temporarily map BAR. */
	rc = efx_init_io(efx, bar,
			 DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
			 pci_resource_len(efx->pci_dev, bar));
	if (rc) {
		netif_err(efx, probe, efx->net_dev,
			  "efx_init_io failed, rc=%d\n", rc);
		return rc;
	}

	rc = ef100_pci_walk_xilinx_table(efx, offset, result);

	/* Unmap temporarily mapped BAR. */
	efx_fini_io(efx);
	return rc;
}

/* Call ef100_pci_parse_ef100_entry() for each Xilinx PCI_EXT_CAP_ID_VNDR
 * capability.
 */
static int ef100_pci_find_func_ctrl_window(struct efx_nic *efx,
					   struct ef100_func_ctl_window *result)
{
	int num_xilinx_caps = 0;
	int cap = 0;

	result->valid = false;

	while ((cap = pci_find_next_ext_capability(efx->pci_dev, cap, PCI_EXT_CAP_ID_VNDR)) != 0) {
		int vndr_cap = cap + PCI_EXT_CAP_HDR_LENGTH;
		u32 vsec_ver = 0;
		u32 vsec_len = 0;
		u32 vsec_id = 0;
		int rc = 0;

		num_xilinx_caps++;

		rc = ef100_pci_get_config_bits(efx, vndr_cap, ID, &vsec_id);
		if (rc) {
			netif_err(efx, probe, efx->net_dev,
				  "Failed to read ESF_GZ_VSEC_ID, rc=%d\n",
				  rc);
			return rc;
		}

		rc = ef100_pci_get_config_bits(efx, vndr_cap, VER, &vsec_ver);
		if (rc) {
			netif_err(efx, probe, efx->net_dev,
				  "Failed to read ESF_GZ_VSEC_VER, rc=%d\n",
				  rc);
			return rc;
		}

		/* Get length of whole capability - i.e. starting at cap */
		rc = ef100_pci_get_config_bits(efx, vndr_cap, LEN, &vsec_len);
		if (rc) {
			netif_err(efx, probe, efx->net_dev,
				  "Failed to read ESF_GZ_VSEC_LEN, rc=%d\n",
				  rc);
			return rc;
		}

		if (vsec_id == ESE_GZ_XILINX_VSEC_ID &&
		    vsec_ver == ESE_GZ_VSEC_VER_XIL_CFGBAR &&
		    vsec_len >= ESE_GZ_VSEC_LEN_MIN) {
			bool has_offset_hi = (vsec_len >= ESE_GZ_VSEC_LEN_HIGH_OFFT);

			rc = ef100_pci_parse_xilinx_cap(efx, vndr_cap,
							has_offset_hi, result);
			if (rc)
				return rc;
		}
	}

	if (num_xilinx_caps && !result->valid) {
		netif_err(efx, probe, efx->net_dev,
			  "Seen %d Xilinx tables, but no EF100 entry.\n",
			  num_xilinx_caps);
		return -EINVAL;
	}

	return 0;
}

/* Final NIC shutdown
 * This is called only at module unload (or hotplug removal).  A PF can call
 * this on its VFs to ensure they are unbound first.
 */
static void ef100_pci_remove(struct pci_dev *pci_dev)
{
	struct efx_nic *efx;

	efx = pci_get_drvdata(pci_dev);
	if (!efx)
		return;

	rtnl_lock();
	dev_close(efx->net_dev);
	rtnl_unlock();

	/* Unregistering our netdev notifier triggers unbinding of TC indirect
	 * blocks, so we have to do it before PCI removal.
	 */
	unregister_netdevice_notifier(&efx->netdev_notifier);
	ef100_remove(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);

	pci_disable_pcie_error_reporting(pci_dev);
};

static int ef100_pci_probe(struct pci_dev *pci_dev,
			   const struct pci_device_id *entry)
{
	struct ef100_func_ctl_window fcw = { 0 };
	struct net_device *net_dev;
	struct efx_nic *efx;
	int rc;

	/* Allocate and initialise a struct net_device and struct efx_nic */
	net_dev = alloc_etherdev_mq(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES);
	if (!net_dev)
		return -ENOMEM;
	efx = netdev_priv(net_dev);
	efx->type = (const struct efx_nic_type *)entry->driver_data;

	pci_set_drvdata(pci_dev, efx);
	SET_NETDEV_DEV(net_dev, &pci_dev->dev);
	rc = efx_init_struct(efx, pci_dev, net_dev);
	if (rc)
		goto fail;

	efx->vi_stride = EF100_DEFAULT_VI_STRIDE;
	netif_info(efx, probe, efx->net_dev,
		   "Solarflare EF100 NIC detected\n");

	rc = ef100_pci_find_func_ctrl_window(efx, &fcw);
	if (rc) {
		netif_err(efx, probe, efx->net_dev,
			  "Error looking for ef100 function control window, rc=%d\n",
			  rc);
		goto fail;
	}

	if (!fcw.valid) {
		/* Extended capability not found - use defaults. */
		fcw.bar = EFX_EF100_PCI_DEFAULT_BAR;
		fcw.offset = 0;
		fcw.valid = true;
	}

	if (fcw.offset > pci_resource_len(efx->pci_dev, fcw.bar) - ESE_GZ_FCW_LEN) {
		netif_err(efx, probe, efx->net_dev,
			  "Func control window overruns BAR\n");
		goto fail;
	}

	/* Set up basic I/O (BAR mappings etc) */
	rc = efx_init_io(efx, fcw.bar,
			 DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
			 pci_resource_len(efx->pci_dev, fcw.bar));
	if (rc)
		goto fail;

	efx->reg_base = fcw.offset;

	efx->netdev_notifier.notifier_call = ef100_netdev_event;
	rc = register_netdevice_notifier(&efx->netdev_notifier);
	if (rc) {
		netif_err(efx, probe, efx->net_dev,
			  "Failed to register netdevice notifier, rc=%d\n", rc);
		goto fail;
	}

	rc = efx->type->probe(efx);
	if (rc)
		goto fail;

	netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");

	return 0;

fail:
	ef100_pci_remove(pci_dev);
	return rc;
}

/* PCI device ID table */
static const struct pci_device_id ef100_pci_table[] = {
	{PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x0100),  /* Riverhead PF */
		.driver_data = (unsigned long) &ef100_pf_nic_type },
	{0}                     /* end of list */
};

struct pci_driver ef100_pci_driver = {
	.name           = "sfc_ef100",
	.id_table       = ef100_pci_table,
	.probe          = ef100_pci_probe,
	.remove         = ef100_pci_remove,
	.err_handler    = &efx_err_handlers,
};

MODULE_DEVICE_TABLE(pci, ef100_pci_table);
+12 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
 * Driver for Solarflare network controllers and boards
 * Copyright 2018 Solarflare Communications Inc.
 * Copyright 2019-2020 Xilinx 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.
 */

extern struct pci_driver ef100_pci_driver;
Loading