// 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_addr_t)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_addr_t)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_addr_t)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"); 
 | 
        rc = -EIO; 
 | 
        goto fail; 
 | 
    } 
 | 
  
 | 
    /* Set up basic I/O (BAR mappings etc) */ 
 | 
    rc = efx_init_io(efx, fcw.bar, 
 | 
             (dma_addr_t)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 }, 
 | 
    {PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x1100),  /* Riverhead VF */ 
 | 
        .driver_data = (unsigned long) &ef100_vf_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); 
 |