diff mbox series

[net-next,03/15] sfc_ef100: skeleton EF100 PF driver

Message ID b9ccfacc-93c8-5f60-d3a5-ecd87fcef5ee@solarflare.com
State Changes Requested
Delegated to: David Miller
Headers show
Series sfc_ef100: driver for EF100 family NICs, part 1 | expand

Commit Message

Edward Cree July 3, 2020, 3:31 p.m. UTC
No TX or RX path, no MCDI, not even an ifup/down handler.
Besides stubs, the bulk of the patch deals with reading the Xilinx
 extended PCIe capability, which tells us where to find our BAR.

Signed-off-by: Edward Cree <ecree@solarflare.com>
---
 drivers/net/ethernet/sfc/Kconfig         |  10 +
 drivers/net/ethernet/sfc/Makefile        |   8 +
 drivers/net/ethernet/sfc/ef100.c         | 583 +++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_ethtool.c |  26 +
 drivers/net/ethernet/sfc/ef100_ethtool.h |  12 +
 drivers/net/ethernet/sfc/ef100_netdev.c  | 135 ++++++
 drivers/net/ethernet/sfc/ef100_netdev.h  |  17 +
 drivers/net/ethernet/sfc/ef100_nic.c     | 177 +++++++
 drivers/net/ethernet/sfc/ef100_nic.h     |  26 +
 drivers/net/ethernet/sfc/ef100_rx.c      |  24 +
 drivers/net/ethernet/sfc/ef100_rx.h      |  17 +
 drivers/net/ethernet/sfc/ef100_tx.c      |  43 ++
 drivers/net/ethernet/sfc/ef100_tx.h      |  18 +
 drivers/net/ethernet/sfc/net_driver.h    |  12 +-
 14 files changed, 1107 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/sfc/ef100.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_ethtool.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_ethtool.h
 create mode 100644 drivers/net/ethernet/sfc/ef100_netdev.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_netdev.h
 create mode 100644 drivers/net/ethernet/sfc/ef100_nic.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_nic.h
 create mode 100644 drivers/net/ethernet/sfc/ef100_rx.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_rx.h
 create mode 100644 drivers/net/ethernet/sfc/ef100_tx.c
 create mode 100644 drivers/net/ethernet/sfc/ef100_tx.h

Comments

Jakub Kicinski July 3, 2020, 5:43 p.m. UTC | #1
On Fri, 3 Jul 2020 16:31:33 +0100 Edward Cree wrote:
> No TX or RX path, no MCDI, not even an ifup/down handler.
> Besides stubs, the bulk of the patch deals with reading the Xilinx
>  extended PCIe capability, which tells us where to find our BAR.
> 
> Signed-off-by: Edward Cree <ecree@solarflare.com>

Warnings:

drivers/net/ethernet/sfc/ef100_netdev.c:31:6: warning: symbol 'efx_separate_tx_channels' was not declared. Should it be static?
drivers/net/ethernet/sfc/ef100_netdev.c:45:13: warning: symbol 'ef100_hard_start_xmit' was not declared. Should it be static?
28a27,41
drivers/net/ethernet/sfc/ef100_rx.c:15:6: warning: symbol '__efx_rx_packet' was not declared. Should it be static?
drivers/net/ethernet/sfc/ef100_tx.c:16:5: warning: symbol 'efx_enqueue_skb_tso' was not declared. Should it be static?
drivers/net/ethernet/sfc/ef100_netdev.c:45:13: warning: no previous prototype for ‘ef100_hard_start_xmit’ [-Wmissing-prototypes]
   45 | netdev_tx_t ef100_hard_start_xmit(struct sk_buff *skb,
      |             ^~~~~~~~~~~~~~~~~~~~~
drivers/net/ethernet/sfc/ef100_rx.c:15:6: warning: no previous prototype for ‘__efx_rx_packet’ [-Wmissing-prototypes]
   15 | void __efx_rx_packet(struct efx_channel *channel)
      |      ^~~~~~~~~~~~~~~
drivers/net/ethernet/sfc/ef100_tx.c:16:5: warning: no previous prototype for ‘efx_enqueue_skb_tso’ [-Wmissing-prototypes]
   16 | int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
      |     ^~~~~~~~~~~~~~~~~~~
kernel test robot July 3, 2020, 5:46 p.m. UTC | #2
Hi Edward,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Edward-Cree/sfc_ef100-driver-for-EF100-family-NICs-part-1/20200703-233750
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 8c8278a5b1a81e099ba883d8a0f9e3df9bdb1a74
config: i386-randconfig-s002-20200702 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-14) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.2-3-gfa153962-dirty
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from include/linux/skbuff.h:31,
                    from include/linux/if_ether.h:19,
                    from include/uapi/linux/ethtool.h:19,
                    from include/linux/ethtool.h:18,
                    from include/linux/netdevice.h:37,
                    from drivers/net/ethernet/sfc/net_driver.h:13,
                    from drivers/net/ethernet/sfc/ef100.c:12:
   drivers/net/ethernet/sfc/ef100.c: In function 'ef100_pci_parse_continue_entry':
>> include/linux/dma-mapping.h:139:25: warning: conversion from 'long long unsigned int' to 'dma_addr_t' {aka 'unsigned int'} changes value from '18446744073709551615' to '4294967295' [-Woverflow]
     139 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/net/ethernet/sfc/ef100.c:144:6: note: in expansion of macro 'DMA_BIT_MASK'
     144 |      DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
         |      ^~~~~~~~~~~~
>> include/linux/dma-mapping.h:139:25: warning: conversion from 'long long unsigned int' to 'dma_addr_t' {aka 'unsigned int'} changes value from '18446744073709551615' to '4294967295' [-Woverflow]
     139 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/net/ethernet/sfc/ef100.c:162:6: note: in expansion of macro 'DMA_BIT_MASK'
     162 |      DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
         |      ^~~~~~~~~~~~
   drivers/net/ethernet/sfc/ef100.c: In function 'ef100_pci_parse_xilinx_cap':
>> include/linux/dma-mapping.h:139:25: warning: conversion from 'long long unsigned int' to 'dma_addr_t' {aka 'unsigned int'} changes value from '18446744073709551615' to '4294967295' [-Woverflow]
     139 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/net/ethernet/sfc/ef100.c:339:5: note: in expansion of macro 'DMA_BIT_MASK'
     339 |     DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
         |     ^~~~~~~~~~~~
   drivers/net/ethernet/sfc/ef100.c: In function 'ef100_pci_probe':
>> include/linux/dma-mapping.h:139:25: warning: conversion from 'long long unsigned int' to 'dma_addr_t' {aka 'unsigned int'} changes value from '18446744073709551615' to '4294967295' [-Woverflow]
     139 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/net/ethernet/sfc/ef100.c:503:5: note: in expansion of macro 'DMA_BIT_MASK'
     503 |     DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
         |     ^~~~~~~~~~~~
--
>> drivers/net/ethernet/sfc/ef100_netdev.c:45:13: warning: no previous prototype for 'ef100_hard_start_xmit' [-Wmissing-prototypes]
      45 | netdev_tx_t ef100_hard_start_xmit(struct sk_buff *skb,
         |             ^~~~~~~~~~~~~~~~~~~~~
--
>> drivers/net/ethernet/sfc/ef100_rx.c:15:6: warning: no previous prototype for '__efx_rx_packet' [-Wmissing-prototypes]
      15 | void __efx_rx_packet(struct efx_channel *channel)
         |      ^~~~~~~~~~~~~~~
--
>> drivers/net/ethernet/sfc/ef100_tx.c:16:5: warning: no previous prototype for 'efx_enqueue_skb_tso' [-Wmissing-prototypes]
      16 | int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
         |     ^~~~~~~~~~~~~~~~~~~

sparse warnings: (new ones prefixed by >>)

>> drivers/net/ethernet/sfc/ef100_netdev.c:45:13: sparse: sparse: symbol 'ef100_hard_start_xmit' was not declared. Should it be static?

Please review and possibly fold the followup patch.

vim +/DMA_BIT_MASK +144 drivers/net/ethernet/sfc/ef100.c

  > 12	#include "net_driver.h"
    13	#include <linux/module.h>
    14	#include <linux/aer.h>
    15	#include "efx_common.h"
    16	#include "efx_channels.h"
    17	#include "io.h"
    18	#include "ef100_nic.h"
    19	#include "ef100_netdev.h"
    20	#include "ef100_regs.h"
    21	
    22	#define EFX_EF100_PCI_DEFAULT_BAR	2
    23	
    24	/* Number of bytes at start of vendor specified extended capability that indicate
    25	 * that the capability is vendor specified. i.e. offset from value returned by
    26	 * pci_find_next_ext_capability() to beginning of vendor specified capability
    27	 * header.
    28	 */
    29	#define PCI_EXT_CAP_HDR_LENGTH  4
    30	
    31	/* Expected size of a Xilinx continuation address table entry. */
    32	#define ESE_GZ_CFGBAR_CONT_CAP_MIN_LENGTH      16
    33	
    34	struct ef100_func_ctl_window {
    35		bool valid;
    36		unsigned int bar;
    37		u64 offset;
    38	};
    39	
    40	static int ef100_pci_walk_xilinx_table(struct efx_nic *efx, u64 offset,
    41					       struct ef100_func_ctl_window *result);
    42	
    43	/* Number of bytes to offset when reading bit position x with dword accessors. */
    44	#define ROUND_DOWN_TO_DWORD(x) (((x) & (~31)) >> 3)
    45	
    46	#define EXTRACT_BITS(x, lbn, width) \
    47		((x) >> ((lbn) & 31)) & ((1ull << (width)) - 1)
    48	
    49	static u32 _ef100_pci_get_bar_bits_with_width(struct efx_nic *efx,
    50						      int structure_start,
    51						      int lbn, int width)
    52	{
    53		efx_dword_t dword;
    54	
    55		efx_readd(efx, &dword, structure_start + ROUND_DOWN_TO_DWORD(lbn));
    56	
    57		return EXTRACT_BITS(le32_to_cpu(dword.u32[0]), lbn, width);
    58	}
    59	
    60	#define ef100_pci_get_bar_bits(efx, entry_location, bitdef) \
    61		_ef100_pci_get_bar_bits_with_width(efx, entry_location, \
    62			bitdef ## _LBN, bitdef ## _WIDTH)
    63	
    64	static int ef100_pci_parse_ef100_entry(struct efx_nic *efx, int entry_location,
    65					       struct ef100_func_ctl_window *result)
    66	{
    67		u32 bar = ef100_pci_get_bar_bits(efx, entry_location,
    68						 ESF_GZ_CFGBAR_EF100_BAR);
    69		u64 offset = ef100_pci_get_bar_bits(efx, entry_location,
    70						    ESF_GZ_CFGBAR_EF100_FUNC_CTL_WIN_OFF) << ESE_GZ_EF100_FUNC_CTL_WIN_OFF_SHIFT;
    71	
    72		netif_dbg(efx, probe, efx->net_dev,
    73			  "Found EF100 function control window bar=%d offset=0x%llx\n",
    74			  bar, offset);
    75	
    76		if (result->valid) {
    77			netif_err(efx, probe, efx->net_dev,
    78				  "Duplicated EF100 table entry.\n");
    79			return -EINVAL;
    80		}
    81	
    82		if ((bar == ESE_GZ_CFGBAR_EF100_BAR_NUM_EXPANSION_ROM) ||
    83		    (bar == ESE_GZ_CFGBAR_EF100_BAR_NUM_INVALID)) {
    84			netif_err(efx, probe, efx->net_dev,
    85				  "Bad BAR value of %d in Xilinx capabilities EF100 entry.\n",
    86				  bar);
    87			return -EINVAL;
    88		}
    89	
    90		result->bar = bar;
    91		result->offset = offset;
    92		result->valid = true;
    93		return 0;
    94	}
    95	
    96	static bool ef100_pci_does_bar_overflow(struct efx_nic *efx, int bar,
    97						u64 next_entry)
    98	{
    99		return next_entry + ESE_GZ_CFGBAR_ENTRY_HEADER_SIZE >
   100			pci_resource_len(efx->pci_dev, bar);
   101	}
   102	
   103	/* Parse a Xilinx capabilities table entry describing a continuation to a new
   104	 * sub-table.
   105	 */
   106	static int ef100_pci_parse_continue_entry(struct efx_nic *efx, int entry_location,
   107						  struct ef100_func_ctl_window *result)
   108	{
   109		unsigned int previous_bar;
   110		efx_oword_t entry;
   111		u64 offset;
   112		int rc = 0;
   113		u32 bar;
   114	
   115		efx_reado(efx, &entry, entry_location);
   116	
   117		bar = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_CONT_CAP_BAR);
   118	
   119		offset = EFX_OWORD_FIELD64(entry, ESF_GZ_CFGBAR_CONT_CAP_OFFSET) <<
   120			ESE_GZ_CONT_CAP_OFFSET_BYTES_SHIFT;
   121	
   122		previous_bar = efx->mem_bar;
   123	
   124		if ((bar == ESE_GZ_VSEC_BAR_NUM_EXPANSION_ROM) ||
   125		    (bar == ESE_GZ_VSEC_BAR_NUM_INVALID)) {
   126			netif_err(efx, probe, efx->net_dev,
   127				  "Bad BAR value of %d in Xilinx capabilities sub-table.\n",
   128				  bar);
   129			return -EINVAL;
   130		}
   131	
   132		if (bar != previous_bar) {
   133			efx_fini_io(efx);
   134	
   135			if (ef100_pci_does_bar_overflow(efx, bar, offset)) {
   136				netif_err(efx, probe, efx->net_dev,
   137					  "Xilinx table will overrun BAR[%d] offset=0x%llx\n",
   138					  bar, offset);
   139				return -EINVAL;
   140			}
   141	
   142			/* Temporarily map new BAR. */
   143			rc = efx_init_io(efx, bar,
 > 144					 DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
   145					 pci_resource_len(efx->pci_dev, bar));
   146			if (rc) {
   147				netif_err(efx, probe, efx->net_dev,
   148					  "Mapping new BAR for Xilinx table failed, rc=%d\n", rc);
   149				return rc;
   150			}
   151		}
   152	
   153		rc = ef100_pci_walk_xilinx_table(efx, offset, result);
   154		if (rc)
   155			return rc;
   156	
   157		if (bar != previous_bar) {
   158			efx_fini_io(efx);
   159	
   160			/* Put old BAR back. */
   161			rc = efx_init_io(efx, previous_bar,
   162					 DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
   163					 pci_resource_len(efx->pci_dev, previous_bar));
   164			if (rc) {
   165				netif_err(efx, probe, efx->net_dev,
   166					  "Putting old BAR back failed, rc=%d\n", rc);
   167				return rc;
   168			}
   169		}
   170	
   171		return 0;
   172	}
   173	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot July 3, 2020, 7:41 p.m. UTC | #3
Hi Edward,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Edward-Cree/sfc_ef100-driver-for-EF100-family-NICs-part-1/20200703-233750
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 8c8278a5b1a81e099ba883d8a0f9e3df9bdb1a74
config: parisc-generic-64bit_defconfig (attached as .config)
compiler: hppa64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=parisc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "mdio45_nway_restart" [drivers/net/ethernet/sfc/sfc_ef100.ko] undefined!

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot July 4, 2020, 4:16 a.m. UTC | #4
Hi Edward,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Edward-Cree/sfc_ef100-driver-for-EF100-family-NICs-part-1/20200703-233750
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 8c8278a5b1a81e099ba883d8a0f9e3df9bdb1a74
config: m68k-randconfig-c003-20200701 (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


coccinelle warnings: (new ones prefixed by >>)

>> drivers/net/ethernet/sfc/ptp.c:1442:1-4: alloc with no test, possible model on line 1457

vim +1442 drivers/net/ethernet/sfc/ptp.c

5d0dab01175bff0 Ben Hutchings   2013-10-16  1434  
ac36baf817c39fc Ben Hutchings   2013-10-15  1435  /* Initialise PTP state. */
ac36baf817c39fc Ben Hutchings   2013-10-15  1436  int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
7c236c43b838221 Stuart Hodgson  2012-09-03  1437  {
7c236c43b838221 Stuart Hodgson  2012-09-03  1438  	struct efx_ptp_data *ptp;
7c236c43b838221 Stuart Hodgson  2012-09-03  1439  	int rc = 0;
7c236c43b838221 Stuart Hodgson  2012-09-03  1440  	unsigned int pos;
7c236c43b838221 Stuart Hodgson  2012-09-03  1441  
7c236c43b838221 Stuart Hodgson  2012-09-03 @1442  	ptp = kzalloc(sizeof(struct efx_ptp_data), GFP_KERNEL);
7c236c43b838221 Stuart Hodgson  2012-09-03  1443  	efx->ptp_data = ptp;
7c236c43b838221 Stuart Hodgson  2012-09-03  1444  	if (!efx->ptp_data)
7c236c43b838221 Stuart Hodgson  2012-09-03  1445  		return -ENOMEM;
7c236c43b838221 Stuart Hodgson  2012-09-03  1446  
ac36baf817c39fc Ben Hutchings   2013-10-15  1447  	ptp->efx = efx;
ac36baf817c39fc Ben Hutchings   2013-10-15  1448  	ptp->channel = channel;
bd9a265db26cdbf Jon Cooper      2013-11-18  1449  	ptp->rx_ts_inline = efx_nic_rev(efx) >= EFX_REV_HUNT_A0;
ac36baf817c39fc Ben Hutchings   2013-10-15  1450  
0d19a540beb7849 Ben Hutchings   2012-09-18  1451  	rc = efx_nic_alloc_buffer(efx, &ptp->start, sizeof(int), GFP_KERNEL);
7c236c43b838221 Stuart Hodgson  2012-09-03  1452  	if (rc != 0)
7c236c43b838221 Stuart Hodgson  2012-09-03  1453  		goto fail1;
7c236c43b838221 Stuart Hodgson  2012-09-03  1454  
7c236c43b838221 Stuart Hodgson  2012-09-03  1455  	skb_queue_head_init(&ptp->rxq);
7c236c43b838221 Stuart Hodgson  2012-09-03  1456  	skb_queue_head_init(&ptp->txq);
7c236c43b838221 Stuart Hodgson  2012-09-03 @1457  	ptp->workwq = create_singlethread_workqueue("sfc_ptp");
7c236c43b838221 Stuart Hodgson  2012-09-03  1458  	if (!ptp->workwq) {
7c236c43b838221 Stuart Hodgson  2012-09-03  1459  		rc = -ENOMEM;
7c236c43b838221 Stuart Hodgson  2012-09-03  1460  		goto fail2;
7c236c43b838221 Stuart Hodgson  2012-09-03  1461  	}
7c236c43b838221 Stuart Hodgson  2012-09-03  1462  
2935e3c38228ad9 Edward Cree     2018-01-25  1463  	if (efx_ptp_use_mac_tx_timestamps(efx)) {
23418dc131464ff Martin Habets   2018-01-25  1464  		ptp->xmit_skb = efx_ptp_xmit_skb_queue;
2935e3c38228ad9 Edward Cree     2018-01-25  1465  		/* Request sync events on this channel. */
2935e3c38228ad9 Edward Cree     2018-01-25  1466  		channel->sync_events_state = SYNC_EVENTS_QUIESCENT;
2935e3c38228ad9 Edward Cree     2018-01-25  1467  	} else {
23418dc131464ff Martin Habets   2018-01-25  1468  		ptp->xmit_skb = efx_ptp_xmit_skb_mc;
2935e3c38228ad9 Edward Cree     2018-01-25  1469  	}
23418dc131464ff Martin Habets   2018-01-25  1470  
7c236c43b838221 Stuart Hodgson  2012-09-03  1471  	INIT_WORK(&ptp->work, efx_ptp_worker);
7c236c43b838221 Stuart Hodgson  2012-09-03  1472  	ptp->config.flags = 0;
7c236c43b838221 Stuart Hodgson  2012-09-03  1473  	ptp->config.tx_type = HWTSTAMP_TX_OFF;
7c236c43b838221 Stuart Hodgson  2012-09-03  1474  	ptp->config.rx_filter = HWTSTAMP_FILTER_NONE;
7c236c43b838221 Stuart Hodgson  2012-09-03  1475  	INIT_LIST_HEAD(&ptp->evt_list);
7c236c43b838221 Stuart Hodgson  2012-09-03  1476  	INIT_LIST_HEAD(&ptp->evt_free_list);
7c236c43b838221 Stuart Hodgson  2012-09-03  1477  	spin_lock_init(&ptp->evt_lock);
7c236c43b838221 Stuart Hodgson  2012-09-03  1478  	for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++)
7c236c43b838221 Stuart Hodgson  2012-09-03  1479  		list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list);
7c236c43b838221 Stuart Hodgson  2012-09-03  1480  
a6f73460b592404 Laurence Evans  2013-12-04  1481  	/* Get the NIC PTP attributes and set up time conversions */
a6f73460b592404 Laurence Evans  2013-12-04  1482  	rc = efx_ptp_get_attributes(efx);
a6f73460b592404 Laurence Evans  2013-12-04  1483  	if (rc < 0)
a6f73460b592404 Laurence Evans  2013-12-04  1484  		goto fail3;
a6f73460b592404 Laurence Evans  2013-12-04  1485  
a6f73460b592404 Laurence Evans  2013-12-04  1486  	/* Get the timestamp corrections */
a6f73460b592404 Laurence Evans  2013-12-04  1487  	rc = efx_ptp_get_timestamp_corrections(efx);
a6f73460b592404 Laurence Evans  2013-12-04  1488  	if (rc < 0)
a6f73460b592404 Laurence Evans  2013-12-04  1489  		goto fail3;
a6f73460b592404 Laurence Evans  2013-12-04  1490  
9aecda95d0a2865 Ben Hutchings   2013-12-05  1491  	if (efx->mcdi->fn_flags &
9aecda95d0a2865 Ben Hutchings   2013-12-05  1492  	    (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY)) {
5d0dab01175bff0 Ben Hutchings   2013-10-16  1493  		ptp->phc_clock_info = efx_phc_clock_info;
1ef761582c07444 Richard Cochran 2012-09-22  1494  		ptp->phc_clock = ptp_clock_register(&ptp->phc_clock_info,
1ef761582c07444 Richard Cochran 2012-09-22  1495  						    &efx->pci_dev->dev);
155d940a78fd076 Wei Yongjun     2013-05-07  1496  		if (IS_ERR(ptp->phc_clock)) {
155d940a78fd076 Wei Yongjun     2013-05-07  1497  			rc = PTR_ERR(ptp->phc_clock);
7c236c43b838221 Stuart Hodgson  2012-09-03  1498  			goto fail3;
efee95f42b5ddde Nicolas Pitre   2016-09-20  1499  		} else if (ptp->phc_clock) {
7c236c43b838221 Stuart Hodgson  2012-09-03  1500  			INIT_WORK(&ptp->pps_work, efx_ptp_pps_worker);
7c236c43b838221 Stuart Hodgson  2012-09-03  1501  			ptp->pps_workwq = create_singlethread_workqueue("sfc_pps");
7c236c43b838221 Stuart Hodgson  2012-09-03  1502  			if (!ptp->pps_workwq) {
7c236c43b838221 Stuart Hodgson  2012-09-03  1503  				rc = -ENOMEM;
7c236c43b838221 Stuart Hodgson  2012-09-03  1504  				goto fail4;
7c236c43b838221 Stuart Hodgson  2012-09-03  1505  			}
9aecda95d0a2865 Ben Hutchings   2013-12-05  1506  		}
efee95f42b5ddde Nicolas Pitre   2016-09-20  1507  	}
7c236c43b838221 Stuart Hodgson  2012-09-03  1508  	ptp->nic_ts_enabled = false;
7c236c43b838221 Stuart Hodgson  2012-09-03  1509  
7c236c43b838221 Stuart Hodgson  2012-09-03  1510  	return 0;
7c236c43b838221 Stuart Hodgson  2012-09-03  1511  fail4:
7c236c43b838221 Stuart Hodgson  2012-09-03  1512  	ptp_clock_unregister(efx->ptp_data->phc_clock);
7c236c43b838221 Stuart Hodgson  2012-09-03  1513  
7c236c43b838221 Stuart Hodgson  2012-09-03  1514  fail3:
7c236c43b838221 Stuart Hodgson  2012-09-03  1515  	destroy_workqueue(efx->ptp_data->workwq);
7c236c43b838221 Stuart Hodgson  2012-09-03  1516  
7c236c43b838221 Stuart Hodgson  2012-09-03  1517  fail2:
7c236c43b838221 Stuart Hodgson  2012-09-03  1518  	efx_nic_free_buffer(efx, &ptp->start);
7c236c43b838221 Stuart Hodgson  2012-09-03  1519  
7c236c43b838221 Stuart Hodgson  2012-09-03  1520  fail1:
7c236c43b838221 Stuart Hodgson  2012-09-03  1521  	kfree(efx->ptp_data);
7c236c43b838221 Stuart Hodgson  2012-09-03  1522  	efx->ptp_data = NULL;
7c236c43b838221 Stuart Hodgson  2012-09-03  1523  
7c236c43b838221 Stuart Hodgson  2012-09-03  1524  	return rc;
7c236c43b838221 Stuart Hodgson  2012-09-03  1525  }
7c236c43b838221 Stuart Hodgson  2012-09-03  1526  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Edward Cree July 7, 2020, 6:34 p.m. UTC | #5
On 04/07/2020 05:16, kernel test robot wrote:
>>> drivers/net/ethernet/sfc/ptp.c:1442:1-4: alloc with no test, possible model on line 1457
This one's a false positive, see below:
> vim +1442 drivers/net/ethernet/sfc/ptp.c
>
> 5d0dab01175bff0 Ben Hutchings   2013-10-16  1434  
> ac36baf817c39fc Ben Hutchings   2013-10-15  1435  /* Initialise PTP state. */
> ac36baf817c39fc Ben Hutchings   2013-10-15  1436  int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1437  {
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1438  	struct efx_ptp_data *ptp;
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1439  	int rc = 0;
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1440  	unsigned int pos;
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1441  
> 7c236c43b838221 Stuart Hodgson  2012-09-03 @1442  	ptp = kzalloc(sizeof(struct efx_ptp_data), GFP_KERNEL);
We allocate ptp...
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1443  	efx->ptp_data = ptp;
... assign it to efx->ptp_data...
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1444  	if (!efx->ptp_data)
> 7c236c43b838221 Stuart Hodgson  2012-09-03  1445  		return -ENOMEM;
... which we then test.

So by here...
> 7c236c43b838221 Stuart Hodgson  2012-09-03 @1457  	ptp->workwq = create_singlethread_workqueue("sfc_ptp");
... we know ptp is non-NULL.

-ed
Xia, Hui July 8, 2020, 3:15 a.m. UTC | #6
>-----Original Message-----
>From: Edward Cree <ecree@solarflare.com>
>Sent: 2020年7月8日 2:35
>To: lkp <lkp@intel.com>; linux-net-drivers@solarflare.com;
>davem@davemloft.net
>Cc: kbuild-all@lists.01.org; netdev@vger.kernel.org
>Subject: [kbuild-all] Re: [PATCH net-next 03/15] sfc_ef100: skeleton EF100 PF
>driver
>
>On 04/07/2020 05:16, kernel test robot wrote:
>>>> drivers/net/ethernet/sfc/ptp.c:1442:1-4: alloc with no test,
>>>> possible model on line 1457
>This one's a false positive, see below:
Sorry for inconvenient. Please ignore this warning.
We will double check for this type of warning. Thanks.

>> vim +1442 drivers/net/ethernet/sfc/ptp.c
>>
>> 5d0dab01175bff0 Ben Hutchings   2013-10-16  1434
>> ac36baf817c39fc Ben Hutchings   2013-10-15  1435  /* Initialise PTP state. */
>> ac36baf817c39fc Ben Hutchings   2013-10-15  1436  int efx_ptp_probe(struct
>efx_nic *efx, struct efx_channel *channel)
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1437  {
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1438  	struct efx_ptp_data
>*ptp;
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1439  	int rc = 0;
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1440  	unsigned int pos;
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1441
>> 7c236c43b838221 Stuart Hodgson  2012-09-03 @1442  	ptp =
>kzalloc(sizeof(struct efx_ptp_data), GFP_KERNEL);
>We allocate ptp...
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1443  	efx->ptp_data = ptp;
>... assign it to efx->ptp_data...
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1444  	if (!efx->ptp_data)
>> 7c236c43b838221 Stuart Hodgson  2012-09-03  1445  		return -
>ENOMEM;
>... which we then test.
>
>So by here...
>> 7c236c43b838221 Stuart Hodgson  2012-09-03 @1457  	ptp->workwq =
>create_singlethread_workqueue("sfc_ptp");
>... we know ptp is non-NULL.
>
>-ed
>_______________________________________________
>kbuild-all mailing list -- kbuild-all@lists.01.org To unsubscribe send an email to
>kbuild-all-leave@lists.01.org
Edward Cree July 8, 2020, 7:16 p.m. UTC | #7
On 03/07/2020 18:46, kernel test robot wrote:
>    In file included from include/linux/skbuff.h:31,
>                     from include/linux/if_ether.h:19,
>                     from include/uapi/linux/ethtool.h:19,
>                     from include/linux/ethtool.h:18,
>                     from include/linux/netdevice.h:37,
>                     from drivers/net/ethernet/sfc/net_driver.h:13,
>                     from drivers/net/ethernet/sfc/ef100.c:12:
>    drivers/net/ethernet/sfc/ef100.c: In function 'ef100_pci_parse_continue_entry':
>>> include/linux/dma-mapping.h:139:25: warning: conversion from 'long long unsigned int' to 'dma_addr_t' {aka 'unsigned int'} changes value from '18446744073709551615' to '4294967295' [-Woverflow]
>      139 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
>          |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> drivers/net/ethernet/sfc/ef100.c:144:6: note: in expansion of macro 'DMA_BIT_MASK'
>      144 |      DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
>          |      ^~~~~~~~~~~~
I think this is spurious?  DMA_BIT_MASK() looks likeit's intended to
 return a dma_addr_t, and the conversion does the right thing (truncate
 to 32 bits), so maybe all that's needed is some suitable annotation to
 make the compiler happy.  Would casting explicitly to dma_addr_t do it?

-ed
diff mbox series

Patch

diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index 81b0f7d3a025..2d37d1bc008c 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -28,6 +28,16 @@  config SFC
 
 	  To compile this driver as a module, choose M here.  The module
 	  will be called sfc.
+config SFC_EF100
+	tristate "Solarflare EF100 (Riverhead) support"
+	depends on PCI
+	default m
+	help
+          This driver 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_ef100.
 config SFC_MTD
 	bool "Solarflare SFC9000/SFC9100-family MTD support"
 	depends on SFC && MTD && !(SFC=y && MTD=m)
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index 87d093da22ca..90992a1c404d 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -10,4 +10,12 @@  sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o siena_sriov.o ef10_sriov.o
 
 obj-$(CONFIG_SFC)	+= sfc.o
 
+sfc_ef100-y             += mcdi.o ef100.o efx_common.o efx_channels.o \
+                           ef100_nic.o nic.o ef100_netdev.o ef100_ethtool.o \
+                           ef100_rx.o rx_common.o ef100_tx.o tx_common.o \
+			   ethtool_common.o mcdi_port_common.o mcdi_functions.o \
+			   mcdi_filters.o selftest.o ptp.o
+
+obj-$(CONFIG_SFC_EF100) += sfc_ef100.o
+
 obj-$(CONFIG_SFC_FALCON) += falcon/
diff --git a/drivers/net/ethernet/sfc/ef100.c b/drivers/net/ethernet/sfc/ef100.c
new file mode 100644
index 000000000000..a2a816f691ee
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100.c
@@ -0,0 +1,583 @@ 
+// 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"
+
+#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, \
+		bitdef ## _LBN, bitdef ## _WIDTH)
+
+static int ef100_pci_parse_ef100_entry(struct efx_nic *efx, int entry_location,
+				       struct ef100_func_ctl_window *result)
+{
+	u32 bar = ef100_pci_get_bar_bits(efx, entry_location,
+					 ESF_GZ_CFGBAR_EF100_BAR);
+	u64 offset = ef100_pci_get_bar_bits(efx, entry_location,
+					    ESF_GZ_CFGBAR_EF100_FUNC_CTL_WIN_OFF) << ESE_GZ_EF100_FUNC_CTL_WIN_OFF_SHIFT;
+
+	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,
+						ESF_GZ_CFGBAR_ENTRY_FORMAT);
+		u32 last = ef100_pci_get_bar_bits(efx, current_entry,
+						  ESF_GZ_CFGBAR_ENTRY_LAST);
+		u32 rev = ef100_pci_get_bar_bits(efx, current_entry,
+						 ESF_GZ_CFGBAR_ENTRY_REV);
+		u32 entry_size;
+
+		if (id == ESE_GZ_CFGBAR_ENTRY_LAST)
+			return 0;
+
+		entry_size = ef100_pci_get_bar_bits(efx, current_entry,
+						    ESF_GZ_CFGBAR_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(uint32_t) * 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,  \
+		bitdef ## _LBN, 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, ESF_GZ_VSEC_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, ESF_GZ_VSEC_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, ESF_GZ_VSEC_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(uint32_t) * 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, ESF_GZ_VSEC_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, ESF_GZ_VSEC_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, ESF_GZ_VSEC_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 */
+};
+
+static struct pci_driver ef100_pci_driver = {
+	.name           = KBUILD_MODNAME,
+	.id_table       = ef100_pci_table,
+	.probe          = ef100_pci_probe,
+	.remove         = ef100_pci_remove,
+	.err_handler    = &efx_err_handlers,
+};
+
+static int __init ef100_init_module(void)
+{
+	int rc;
+
+	pr_info("Solarflare EF100 NET driver v" EFX_DRIVER_VERSION "\n");
+
+	rc = efx_create_reset_workqueue();
+	if (rc)
+		goto err_reset;
+
+	rc = pci_register_driver(&ef100_pci_driver);
+	if (rc < 0) {
+		pr_err("pci_register_driver failed, rc=%d\n", rc);
+		goto err_pci;
+	}
+
+	return 0;
+
+err_pci:
+	efx_destroy_reset_workqueue();
+err_reset:
+	return rc;
+}
+
+static void __exit ef100_exit_module(void)
+{
+	pr_info("Solarflare EF100 NET driver unloading\n");
+
+	pci_unregister_driver(&ef100_pci_driver);
+}
+
+module_init(ef100_init_module);
+module_exit(ef100_exit_module);
+
+MODULE_DESCRIPTION("Solarflare EF100 network driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ef100_pci_table);
+MODULE_VERSION(EFX_DRIVER_VERSION);
diff --git a/drivers/net/ethernet/sfc/ef100_ethtool.c b/drivers/net/ethernet/sfc/ef100_ethtool.c
new file mode 100644
index 000000000000..af3f385b828b
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_ethtool.c
@@ -0,0 +1,26 @@ 
+// 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.
+ */
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include "net_driver.h"
+#include "efx.h"
+#include "mcdi_port_common.h"
+#include "ethtool_common.h"
+#include "ef100_ethtool.h"
+#include "mcdi_functions.h"
+
+const char *efx_driver_name = KBUILD_MODNAME;
+
+/*	Ethtool options available
+ */
+const struct ethtool_ops ef100_ethtool_ops = {
+	.get_drvinfo		= efx_ethtool_get_drvinfo,
+};
diff --git a/drivers/net/ethernet/sfc/ef100_ethtool.h b/drivers/net/ethernet/sfc/ef100_ethtool.h
new file mode 100644
index 000000000000..6efda72dfc6c
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_ethtool.h
@@ -0,0 +1,12 @@ 
+/* 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 const struct ethtool_ops ef100_ethtool_ops;
diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
new file mode 100644
index 000000000000..356938104cb2
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_netdev.c
@@ -0,0 +1,135 @@ 
+// 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.
+ */
+#include "net_driver.h"
+#include "mcdi_port_common.h"
+#include "mcdi_functions.h"
+#include "efx_common.h"
+#include "efx_channels.h"
+#include "tx_common.h"
+#include "ef100_netdev.h"
+#include "ef100_ethtool.h"
+#include "efx_common.h"
+#include "nic_common.h"
+#include "ef100_nic.h"
+#include "ef100_tx.h"
+#include "ef100_regs.h"
+#include "mcdi_filters.h"
+#include "rx_common.h"
+
+/* In EF10 this was a module parameter.  Since EF100 is a new module, we
+ * don't have to be compatible with the old module parameters, so we can
+ * get rid of it.
+ */
+bool efx_separate_tx_channels = false;
+
+static void ef100_update_name(struct efx_nic *efx)
+{
+	strcpy(efx->name, efx->net_dev->name);
+}
+
+/* Initiate a packet transmission.  We use one channel per CPU
+ * (sharing when we have more CPUs than channels).
+ *
+ * Context: non-blocking.
+ * Note that returning anything other than NETDEV_TX_OK will cause the
+ * OS to free the skb.
+ */
+netdev_tx_t ef100_hard_start_xmit(struct sk_buff *skb,
+				  struct net_device *net_dev)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	struct efx_tx_queue *tx_queue;
+	struct efx_channel *channel;
+	int rc;
+
+	channel = efx_get_tx_channel(efx, skb_get_queue_mapping(skb));
+	netif_vdbg(efx, tx_queued, efx->net_dev,
+		   "%s len %d data %d channel %d\n", __func__,
+		   skb->len, skb->data_len, channel->channel);
+	if (!efx->n_channels || !efx->n_tx_channels || !channel) {
+		netif_stop_queue(net_dev);
+		goto err;
+	}
+
+	tx_queue = &channel->tx_queue[0];
+	rc = efx_enqueue_skb(tx_queue, skb);
+	if (rc == 0)
+		return NETDEV_TX_OK;
+
+err:
+	net_dev->stats.tx_dropped++;
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops ef100_netdev_ops = {
+	.ndo_start_xmit         = ef100_hard_start_xmit,
+};
+
+/*	Netdev registration
+ */
+int ef100_netdev_event(struct notifier_block *this,
+		       unsigned long event, void *ptr)
+{
+	struct efx_nic *efx = container_of(this, struct efx_nic, netdev_notifier);
+	struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
+
+	if (netdev_priv(net_dev) == efx && event == NETDEV_CHANGENAME)
+		ef100_update_name(efx);
+
+	return NOTIFY_DONE;
+}
+
+int ef100_register_netdev(struct efx_nic *efx)
+{
+	struct net_device *net_dev = efx->net_dev;
+	int rc;
+
+	net_dev->watchdog_timeo = 5 * HZ;
+	net_dev->irq = efx->pci_dev->irq;
+	net_dev->netdev_ops = &ef100_netdev_ops;
+	net_dev->min_mtu = EFX_MIN_MTU;
+	net_dev->max_mtu = EFX_MAX_MTU;
+	net_dev->ethtool_ops = &ef100_ethtool_ops;
+
+	rtnl_lock();
+
+	rc = dev_alloc_name(net_dev, net_dev->name);
+	if (rc < 0)
+		goto fail_locked;
+	ef100_update_name(efx);
+
+	rc = register_netdevice(net_dev);
+	if (rc)
+		goto fail_locked;
+
+	/* Always start with carrier off; PHY events will detect the link */
+	netif_carrier_off(net_dev);
+
+	efx->state = STATE_READY;
+	rtnl_unlock();
+	efx_init_mcdi_logging(efx);
+
+	return 0;
+
+fail_locked:
+	rtnl_unlock();
+	netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
+	return rc;
+}
+
+void ef100_unregister_netdev(struct efx_nic *efx)
+{
+	if (efx_dev_registered(efx)) {
+		efx_fini_mcdi_logging(efx);
+		efx->state = STATE_UNINIT;
+		unregister_netdev(efx->net_dev);
+	}
+}
diff --git a/drivers/net/ethernet/sfc/ef100_netdev.h b/drivers/net/ethernet/sfc/ef100_netdev.h
new file mode 100644
index 000000000000..d40abb7cc086
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_netdev.h
@@ -0,0 +1,17 @@ 
+/* 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.
+ */
+
+#include <linux/netdevice.h>
+
+int ef100_netdev_event(struct notifier_block *this,
+		       unsigned long event, void *ptr);
+int ef100_register_netdev(struct efx_nic *efx);
+void ef100_unregister_netdev(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
new file mode 100644
index 000000000000..20b6f4bb35ad
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -0,0 +1,177 @@ 
+// 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.
+ */
+
+#include "ef100_nic.h"
+#include "efx_common.h"
+#include "efx_channels.h"
+#include "io.h"
+#include "selftest.h"
+#include "ef100_regs.h"
+#include "mcdi.h"
+#include "mcdi_pcol.h"
+#include "mcdi_port_common.h"
+#include "mcdi_functions.h"
+#include "mcdi_filters.h"
+#include "ef100_rx.h"
+#include "ef100_tx.h"
+#include "ef100_netdev.h"
+
+#define EF100_MAX_VIS 4096
+
+/*	MCDI
+ */
+static int ef100_get_warm_boot_count(struct efx_nic *efx)
+{
+	efx_dword_t reg;
+
+	efx_readd(efx, &reg, efx_reg(efx, ER_GZ_MC_SFT_STATUS));
+
+	if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) == 0xffffffff) {
+		netif_err(efx, hw, efx->net_dev, "Hardware unavailable\n");
+		efx->state = STATE_DISABLED;
+		return -ENETDOWN;
+	} else {
+		return EFX_DWORD_FIELD(reg, EFX_WORD_1) == 0xb007 ?
+			EFX_DWORD_FIELD(reg, EFX_WORD_0) : -EIO;
+	}
+}
+
+/*	Event handling
+ */
+static int ef100_ev_probe(struct efx_channel *channel)
+{
+	/* Allocate an extra descriptor for the QMDA status completion entry */
+	return efx_nic_alloc_buffer(channel->efx, &channel->eventq.buf,
+				    (channel->eventq_mask + 2) *
+				    sizeof(efx_qword_t),
+				    GFP_KERNEL);
+}
+
+/* efx_mcdi_process_event() may call this */
+void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev) {}
+
+static irqreturn_t ef100_msi_interrupt(int irq, void *dev_id)
+{
+	struct efx_msi_context *context = dev_id;
+	struct efx_nic *efx = context->efx;
+
+	netif_vdbg(efx, intr, efx->net_dev,
+		   "IRQ %d on CPU %d\n", irq, raw_smp_processor_id());
+
+	if (likely(READ_ONCE(efx->irq_soft_enabled))) {
+		/* Note test interrupts */
+		if (context->index == efx->irq_level)
+			efx->last_irq_cpu = raw_smp_processor_id();
+
+		/* Schedule processing of the channel */
+		efx_schedule_channel_irq(efx->channel[context->index]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*	NIC level access functions
+ */
+const struct efx_nic_type ef100_pf_nic_type = {
+	.revision = EFX_REV_EF100,
+	.is_vf = false,
+	.probe = ef100_probe_pf,
+	.mcdi_max_ver = 2,
+	.irq_enable_master = efx_port_dummy_op_void,
+	.irq_disable_non_ev = efx_port_dummy_op_void,
+	.push_irq_moderation = efx_channel_dummy_op_void,
+	.min_interrupt_mode = EFX_INT_MODE_MSIX,
+
+	.ev_probe = ef100_ev_probe,
+	.irq_handle_msi = ef100_msi_interrupt,
+
+	/* Per-type bar/size configuration not used on ef100. Location of
+	 * registers is defined by extended capabilities.
+	 */
+	.mem_bar = NULL,
+	.mem_map_size = NULL,
+
+};
+
+/*	NIC probe and remove
+ */
+static int ef100_probe_main(struct efx_nic *efx)
+{
+	unsigned int bar_size = resource_size(&efx->pci_dev->resource[efx->mem_bar]);
+	struct net_device *net_dev = efx->net_dev;
+	struct ef100_nic_data *nic_data;
+	int i, rc;
+
+	if (WARN_ON(bar_size == 0))
+		return -EIO;
+
+	nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
+	if (!nic_data)
+		return -ENOMEM;
+	efx->nic_data = nic_data;
+	nic_data->efx = efx;
+	net_dev->features |= efx->type->offload_features;
+	net_dev->hw_features |= efx->type->offload_features;
+
+	/* Get the MC's warm boot count.  In case it's rebooting right
+	 * now, be prepared to retry.
+	 */
+	i = 0;
+	for (;;) {
+		rc = ef100_get_warm_boot_count(efx);
+		if (rc >= 0)
+			break;
+		if (++i == 5)
+			goto fail;
+		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), efx_reg(efx, ER_GZ_MC_DB_HWRD));
+
+	/* Post-IO section. */
+
+	efx->max_vis = EF100_MAX_VIS;
+
+	rc = efx_init_channels(efx);
+	if (rc)
+		goto fail;
+
+	rc = ef100_register_netdev(efx);
+	if (rc)
+		goto fail;
+
+	return 0;
+fail:
+	return rc;
+}
+
+int ef100_probe_pf(struct efx_nic *efx)
+{
+	return ef100_probe_main(efx);
+}
+
+void ef100_remove(struct efx_nic *efx)
+{
+	struct ef100_nic_data *nic_data = efx->nic_data;
+
+	ef100_unregister_netdev(efx);
+	efx_fini_channels(efx);
+	kfree(efx->phy_data);
+	efx->phy_data = NULL;
+	kfree(nic_data);
+	efx->nic_data = NULL;
+}
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
new file mode 100644
index 000000000000..643111aebba5
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -0,0 +1,26 @@ 
+/* 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.
+ */
+
+#include "net_driver.h"
+#include "nic_common.h"
+
+extern const struct efx_nic_type ef100_pf_nic_type;
+
+int ef100_probe_pf(struct efx_nic *efx);
+void ef100_remove(struct efx_nic *efx);
+
+struct ef100_nic_data {
+	struct efx_nic *efx;
+	u16 warm_boot_count;
+};
+
+#define efx_ef100_has_cap(caps, flag) \
+	(!!((caps) & BIT_ULL(MC_CMD_GET_CAPABILITIES_V4_OUT_ ## flag ## _LBN)))
diff --git a/drivers/net/ethernet/sfc/ef100_rx.c b/drivers/net/ethernet/sfc/ef100_rx.c
new file mode 100644
index 000000000000..f06aa302e9c9
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_rx.c
@@ -0,0 +1,24 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2005-2019 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 "net_driver.h"
+#include "ef100_rx.h"
+#include "rx_common.h"
+
+void __efx_rx_packet(struct efx_channel *channel)
+{
+	/* Stub.  No RX path yet.  Discard the buffer. */
+	struct efx_rx_buffer *rx_buf = efx_rx_buffer(&channel->rx_queue,
+						     channel->rx_pkt_index);
+	struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
+
+	efx_free_rx_buffers(rx_queue, rx_buf, 1);
+	channel->rx_pkt_n_frags = 0;
+}
diff --git a/drivers/net/ethernet/sfc/ef100_rx.h b/drivers/net/ethernet/sfc/ef100_rx.h
new file mode 100644
index 000000000000..9de9c2ab9014
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_rx.h
@@ -0,0 +1,17 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2019 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.
+ */
+
+#ifndef EFX_EF100_RX_H
+#define EFX_EF100_RX_H
+
+#include "net_driver.h"
+
+#endif
diff --git a/drivers/net/ethernet/sfc/ef100_tx.c b/drivers/net/ethernet/sfc/ef100_tx.c
new file mode 100644
index 000000000000..0272f99b3115
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_tx.c
@@ -0,0 +1,43 @@ 
+// 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.
+ */
+
+#include "net_driver.h"
+#include "tx_common.h"
+#include "ef100_tx.h"
+
+int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
+			bool *data_mapped)
+{
+	/* This should never be called; it's just a stub callback for some
+	 * infrastructure that's shared with the EF10 driver
+	 * (tx_queue->handle_tso, only called from tx.c which isn't linked
+	 * into sfc_ef100.ko).
+	 */
+	WARN_ON_ONCE(1);
+	return -EOPNOTSUPP;
+}
+
+/* Add a socket buffer to a TX queue
+ *
+ * You must hold netif_tx_lock() to call this function.
+ *
+ * Returns 0 on success, error code otherwise. In case of an error this
+ * function will free the SKB.
+ */
+int efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
+{
+	/* Stub.  No TX path yet. */
+	struct efx_nic *efx = tx_queue->efx;
+
+	netif_stop_queue(efx->net_dev);
+	dev_kfree_skb_any(skb);
+	return -ENODEV;
+}
diff --git a/drivers/net/ethernet/sfc/ef100_tx.h b/drivers/net/ethernet/sfc/ef100_tx.h
new file mode 100644
index 000000000000..dedfed5d3e53
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_tx.h
@@ -0,0 +1,18 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2019 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.
+ */
+
+#ifndef EFX_EF100_TX_H
+#define EFX_EF100_TX_H
+
+#include "net_driver.h"
+
+int efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
+#endif
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 5b3b3a976114..bf78c2faf999 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -38,7 +38,7 @@ 
  *
  **************************************************************************/
 
-#define EFX_DRIVER_VERSION	"4.1"
+#define EFX_DRIVER_VERSION	"4.2"
 
 #ifdef DEBUG
 #define EFX_WARN_ON_ONCE_PARANOID(x) WARN_ON_ONCE(x)
@@ -965,6 +965,7 @@  struct efx_async_filter_insertion {
  * @vpd_sn: Serial number read from VPD
  * @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their
  *      xdp_rxq_info structures?
+ * @netdev_notifier: Netdevice notifier.
  * @mem_bar: The BAR that is mapped into membase.
  * @reg_base: Offset from the start of the bar to the function control window.
  * @monitor_work: Hardware monitor workitem
@@ -1144,6 +1145,8 @@  struct efx_nic {
 	char *vpd_sn;
 	bool xdp_rxq_info_failed;
 
+	struct notifier_block netdev_notifier;
+
 	unsigned int mem_bar;
 	u32 reg_base;
 
@@ -1532,6 +1535,13 @@  efx_get_channel(struct efx_nic *efx, unsigned index)
 	     _channel = _channel->channel ?				\
 		     (_efx)->channel[_channel->channel - 1] : NULL)
 
+static inline struct efx_channel *
+efx_get_tx_channel(struct efx_nic *efx, unsigned int index)
+{
+	EFX_WARN_ON_ONCE_PARANOID(index >= efx->n_tx_channels);
+	return efx->channel[efx->tx_channel_offset + index];
+}
+
 static inline struct efx_tx_queue *
 efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
 {