Commit 51b35a45 authored by Edward Cree's avatar Edward Cree Committed by David S. Miller

sfc: skeleton EF100 PF driver

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.

Though in the same module, EF100 has its own struct pci_driver,
 which is named sfc_ef100.

A small number of additional nic_type methods are added; those in the
 TX (tx_enqueue) and RX (rx_packet) paths are called through indirect
 call wrappers to minimise the performance impact.
Signed-off-by: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 61060c5d
...@@ -17,7 +17,7 @@ config NET_VENDOR_SOLARFLARE ...@@ -17,7 +17,7 @@ config NET_VENDOR_SOLARFLARE
if NET_VENDOR_SOLARFLARE if NET_VENDOR_SOLARFLARE
config SFC config SFC
tristate "Solarflare SFC9000/SFC9100-family support" tristate "Solarflare SFC9000/SFC9100/EF100-family support"
depends on PCI depends on PCI
select MDIO select MDIO
select CRC32 select CRC32
...@@ -26,6 +26,9 @@ config SFC ...@@ -26,6 +26,9 @@ config SFC
This driver supports 10/40-gigabit Ethernet cards based on This driver supports 10/40-gigabit Ethernet cards based on
the Solarflare SFC9000-family and SFC9100-family controllers. 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 To compile this driver as a module, choose M here. The module
will be called sfc. will be called sfc.
config SFC_MTD config SFC_MTD
......
...@@ -4,7 +4,9 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \ ...@@ -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 \ tx.o tx_common.o tx_tso.o rx.o rx_common.o \
selftest.o ethtool.o ethtool_common.o ptp.o \ selftest.o ethtool.o ethtool_common.o ptp.o \
mcdi.o mcdi_port.o mcdi_port_common.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_MTD) += mtd.o
sfc-$(CONFIG_SFC_SRIOV) += sriov.o siena_sriov.o ef10_sriov.o sfc-$(CONFIG_SFC_SRIOV) += sriov.o siena_sriov.o ef10_sriov.o
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "net_driver.h" #include "net_driver.h"
#include "rx_common.h" #include "rx_common.h"
#include "tx_common.h"
#include "ef10_regs.h" #include "ef10_regs.h"
#include "io.h" #include "io.h"
#include "mcdi.h" #include "mcdi.h"
...@@ -3977,6 +3978,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { ...@@ -3977,6 +3978,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.tx_remove = efx_mcdi_tx_remove, .tx_remove = efx_mcdi_tx_remove,
.tx_write = efx_ef10_tx_write, .tx_write = efx_ef10_tx_write,
.tx_limit_len = efx_ef10_tx_limit_len, .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_push_rss_config = efx_mcdi_vf_rx_push_rss_config,
.rx_pull_rss_config = efx_mcdi_rx_pull_rss_config, .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
.rx_probe = efx_mcdi_rx_probe, .rx_probe = efx_mcdi_rx_probe,
...@@ -3984,6 +3986,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { ...@@ -3984,6 +3986,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.rx_remove = efx_mcdi_rx_remove, .rx_remove = efx_mcdi_rx_remove,
.rx_write = efx_ef10_rx_write, .rx_write = efx_ef10_rx_write,
.rx_defer_refill = efx_ef10_rx_defer_refill, .rx_defer_refill = efx_ef10_rx_defer_refill,
.rx_packet = __efx_rx_packet,
.ev_probe = efx_mcdi_ev_probe, .ev_probe = efx_mcdi_ev_probe,
.ev_init = efx_ef10_ev_init, .ev_init = efx_ef10_ev_init,
.ev_fini = efx_mcdi_ev_fini, .ev_fini = efx_mcdi_ev_fini,
...@@ -4038,6 +4041,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { ...@@ -4038,6 +4041,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.rx_hash_key_size = 40, .rx_hash_key_size = 40,
.check_caps = ef10_check_caps, .check_caps = ef10_check_caps,
.print_additional_fwver = efx_ef10_print_additional_fwver, .print_additional_fwver = efx_ef10_print_additional_fwver,
.sensor_event = efx_mcdi_sensor_event,
}; };
const struct efx_nic_type efx_hunt_a0_nic_type = { const struct efx_nic_type efx_hunt_a0_nic_type = {
...@@ -4087,6 +4091,7 @@ 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_remove = efx_mcdi_tx_remove,
.tx_write = efx_ef10_tx_write, .tx_write = efx_ef10_tx_write,
.tx_limit_len = efx_ef10_tx_limit_len, .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_push_rss_config = efx_mcdi_pf_rx_push_rss_config,
.rx_pull_rss_config = efx_mcdi_rx_pull_rss_config, .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
.rx_push_rss_context_config = efx_mcdi_rx_push_rss_context_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 = { ...@@ -4097,6 +4102,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.rx_remove = efx_mcdi_rx_remove, .rx_remove = efx_mcdi_rx_remove,
.rx_write = efx_ef10_rx_write, .rx_write = efx_ef10_rx_write,
.rx_defer_refill = efx_ef10_rx_defer_refill, .rx_defer_refill = efx_ef10_rx_defer_refill,
.rx_packet = __efx_rx_packet,
.ev_probe = efx_mcdi_ev_probe, .ev_probe = efx_mcdi_ev_probe,
.ev_init = efx_ef10_ev_init, .ev_init = efx_ef10_ev_init,
.ev_fini = efx_mcdi_ev_fini, .ev_fini = efx_mcdi_ev_fini,
...@@ -4172,4 +4178,5 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { ...@@ -4172,4 +4178,5 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.rx_hash_key_size = 40, .rx_hash_key_size = 40,
.check_caps = ef10_check_caps, .check_caps = ef10_check_caps,
.print_additional_fwver = efx_ef10_print_additional_fwver, .print_additional_fwver = efx_ef10_print_additional_fwver,
.sensor_event = efx_mcdi_sensor_event,
}; };
This diff is collapsed.
/* 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;
// 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"
/* Ethtool options available
*/
const struct ethtool_ops ef100_ethtool_ops = {
.get_drvinfo = efx_ethtool_get_drvinfo,
};
/* 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;
// 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"
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.
*/
static 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 = ef100_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);
}
}
/* 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);
// 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);
}
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;
}
/* 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)))
// 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"
#include "efx.h"
void __ef100_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;
}
/* 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"
void __ef100_rx_packet(struct efx_channel *channel);
#endif
// 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 "nic_common.h"
#include "ef100_tx.h"
/* 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 ef100_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;
}
/* 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"
netdev_tx_t ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
#endif
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "efx.h" #include "efx.h"
#include "efx_common.h" #include "efx_common.h"
#include "efx_channels.h" #include "efx_channels.h"
#include "ef100.h"
#include "rx_common.h" #include "rx_common.h"
#include "tx_common.h" #include "tx_common.h"
#include "nic.h" #include "nic.h"
...@@ -1360,8 +1361,14 @@ static int __init efx_init_module(void) ...@@ -1360,8 +1361,14 @@ static int __init efx_init_module(void)
if (rc < 0) if (rc < 0)
goto err_pci; goto err_pci;
rc = pci_register_driver(&ef100_pci_driver);
if (rc < 0)
goto err_pci_ef100;
return 0; return 0;
err_pci_ef100:
pci_unregister_driver(&efx_pci_driver);
err_pci: err_pci:
efx_destroy_reset_workqueue(); efx_destroy_reset_workqueue();
err_reset: err_reset:
...@@ -1378,6 +1385,7 @@ static void __exit efx_exit_module(void) ...@@ -1378,6 +1385,7 @@ static void __exit efx_exit_module(void)
{ {
printk(KERN_INFO "Solarflare NET driver unloading\n"); printk(KERN_INFO "Solarflare NET driver unloading\n");
pci_unregister_driver(&ef100_pci_driver);
pci_unregister_driver(&efx_pci_driver); pci_unregister_driver(&efx_pci_driver);
efx_destroy_reset_workqueue(); efx_destroy_reset_workqueue();
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
#ifndef EFX_EFX_H #ifndef EFX_EFX_H
#define EFX_EFX_H #define EFX_EFX_H
#include <linux/indirect_call_wrapper.h>
#include "net_driver.h" #include "net_driver.h"
#include "ef100_rx.h"
#include "ef100_tx.h"
#include "filter.h" #include "filter.h"
int efx_net_open(struct net_device *net_dev); int efx_net_open(struct net_device *net_dev);
...@@ -18,13 +21,18 @@ int efx_net_stop(struct net_device *net_dev); ...@@ -18,13 +21,18 @@ int efx_net_stop(struct net_device *net_dev);
void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue); void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue);
netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
struct net_device *net_dev); struct net_device *net_dev);
netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); netdev_tx_t __efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
static inline netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
{
return INDIRECT_CALL_2(tx_queue->efx->type->tx_enqueue,
ef100_enqueue_skb, __efx_enqueue_skb,
tx_queue, skb);
}
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
void efx_xmit_done_single(struct efx_tx_queue *tx_queue); void efx_xmit_done_single(struct efx_tx_queue *tx_queue);
int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type, int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
void *type_data); void *type_data);
extern unsigned int efx_piobuf_size; extern unsigned int efx_piobuf_size;
extern bool efx_separate_tx_channels;
/* RX */ /* RX */
void __efx_rx_packet(struct efx_channel *channel); void __efx_rx_packet(struct efx_channel *channel);
...@@ -33,7 +41,9 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, ...@@ -33,7 +41,9 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
static inline void efx_rx_flush_packet(struct efx_channel *channel) static inline void efx_rx_flush_packet(struct efx_channel *channel)
{ {
if (channel->rx_pkt_n_frags) if (channel->rx_pkt_n_frags)
__efx_rx_packet(channel); INDIRECT_CALL_2(channel->efx->type->rx_packet,
__ef100_rx_packet, __efx_rx_packet,
channel);
} }
/* Maximum number of TCP segments we support for soft-TSO */ /* Maximum number of TCP segments we support for soft-TSO */
......
...@@ -221,8 +221,6 @@ static int efx_ethtool_get_ts_info(struct net_device *net_dev, ...@@ -221,8 +221,6 @@ static int efx_ethtool_get_ts_info(struct net_device *net_dev,
return 0; return 0;
} }
const char *efx_driver_name = KBUILD_MODNAME;
const struct ethtool_ops efx_ethtool_ops = { const struct ethtool_ops efx_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS | .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USECS_IRQ | ETHTOOL_COALESCE_USECS_IRQ |
......
...@@ -104,7 +104,7 @@ void efx_ethtool_get_drvinfo(struct net_device *net_dev, ...@@ -104,7 +104,7 @@ void efx_ethtool_get_drvinfo(struct net_device *net_dev,
{ {
struct efx_nic *efx = netdev_priv(net_dev); struct efx_nic *efx = netdev_priv(net_dev);
strlcpy(info->driver, efx_driver_name, sizeof(info->driver)); strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
efx_mcdi_print_fwver(efx, info->fw_version, efx_mcdi_print_fwver(efx, info->fw_version,
sizeof(info->fw_version)); sizeof(info->fw_version));
......
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
#ifndef EFX_ETHTOOL_COMMON_H #ifndef EFX_ETHTOOL_COMMON_H
#define EFX_ETHTOOL_COMMON_H #define EFX_ETHTOOL_COMMON_H
extern const char *efx_driver_name;
void efx_ethtool_get_drvinfo(struct net_device *net_dev, void efx_ethtool_get_drvinfo(struct net_device *net_dev,
struct ethtool_drvinfo *info); struct ethtool_drvinfo *info);
u32 efx_ethtool_get_msglevel(struct net_device *net_dev); u32 efx_ethtool_get_msglevel(struct net_device *net_dev);
......
...@@ -1337,7 +1337,7 @@ void efx_mcdi_process_event(struct efx_channel *channel, ...@@ -1337,7 +1337,7 @@ void efx_mcdi_process_event(struct efx_channel *channel,
efx_mcdi_process_link_change(efx, event); efx_mcdi_process_link_change(efx, event);
break; break;
case MCDI_EVENT_CODE_SENSOREVT: case MCDI_EVENT_CODE_SENSOREVT:
efx_mcdi_sensor_event(efx, event); efx_sensor_event(efx, event);
break; break;
case MCDI_EVENT_CODE_SCHEDERR: case MCDI_EVENT_CODE_SCHEDERR:
netif_dbg(efx, hw, efx->net_dev, netif_dbg(efx, hw, efx->net_dev,
......
...@@ -963,6 +963,7 @@ struct efx_async_filter_insertion { ...@@ -963,6 +963,7 @@ struct efx_async_filter_insertion {
* @vpd_sn: Serial number read from VPD * @vpd_sn: Serial number read from VPD
* @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their * @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their
* xdp_rxq_info structures? * xdp_rxq_info structures?
* @netdev_notifier: Netdevice notifier.
* @mem_bar: The BAR that is mapped into membase. * @mem_bar: The BAR that is mapped into membase.
* @reg_base: Offset from the start of the bar to the function control window. * @reg_base: Offset from the start of the bar to the function control window.
* @monitor_work: Hardware monitor workitem * @monitor_work: Hardware monitor workitem
...@@ -1142,6 +1143,8 @@ struct efx_nic { ...@@ -1142,6 +1143,8 @@ struct efx_nic {
char *vpd_sn; char *vpd_sn;
bool xdp_rxq_info_failed; bool xdp_rxq_info_failed;
struct notifier_block netdev_notifier;
unsigned int mem_bar; unsigned int mem_bar;
u32 reg_base; u32 reg_base;
...@@ -1246,6 +1249,7 @@ struct efx_udp_tunnel { ...@@ -1246,6 +1249,7 @@ struct efx_udp_tunnel {
* @tx_init: Initialise TX queue on the NIC * @tx_init: Initialise TX queue on the NIC
* @tx_remove: Free resources for TX queue * @tx_remove: Free resources for TX queue
* @tx_write: Write TX descriptors and doorbell * @tx_write: Write TX descriptors and doorbell
* @tx_enqueue: Add an SKB to TX queue
* @rx_push_rss_config: Write RSS hash key and indirection table to the NIC * @rx_push_rss_config: Write RSS hash key and indirection table to the NIC
* @rx_pull_rss_config: Read RSS hash key and indirection table back from the NIC * @rx_pull_rss_config: Read RSS hash key and indirection table back from the NIC
* @rx_push_rss_context_config: Write RSS hash key and indirection table for * @rx_push_rss_context_config: Write RSS hash key and indirection table for
...@@ -1257,6 +1261,7 @@ struct efx_udp_tunnel { ...@@ -1257,6 +1261,7 @@ struct efx_udp_tunnel {
* @rx_remove: Free resources for RX queue * @rx_remove: Free resources for RX queue
* @rx_write: Write RX descriptors and doorbell * @rx_write: Write RX descriptors and doorbell
* @rx_defer_refill: Generate a refill reminder event * @rx_defer_refill: Generate a refill reminder event
* @rx_packet: Receive the queued RX buffer on a channel
* @ev_probe: Allocate resources for event queue * @ev_probe: Allocate resources for event queue
* @ev_init: Initialise event queue on the NIC * @ev_init: Initialise event queue on the NIC
* @ev_fini: Deinitialise event queue on the NIC * @ev_fini: Deinitialise event queue on the NIC
...@@ -1301,6 +1306,7 @@ struct efx_udp_tunnel { ...@@ -1301,6 +1306,7 @@ struct efx_udp_tunnel {
* @udp_tnl_push_ports: Push the list of UDP tunnel ports to the NIC if required. * @udp_tnl_push_ports: Push the list of UDP tunnel ports to the NIC if required.
* @udp_tnl_has_port: Check if a port has been added as UDP tunnel * @udp_tnl_has_port: Check if a port has been added as UDP tunnel
* @print_additional_fwver: Dump NIC-specific additional FW version info * @print_additional_fwver: Dump NIC-specific additional FW version info
* @sensor_event: Handle a sensor event from MCDI
* @revision: Hardware architecture revision * @revision: Hardware architecture revision
* @txd_ptr_tbl_base: TX descriptor ring base address * @txd_ptr_tbl_base: TX descriptor ring base address
* @rxd_ptr_tbl_base: RX descriptor ring base address * @rxd_ptr_tbl_base: RX descriptor ring base address
...@@ -1381,6 +1387,7 @@ struct efx_nic_type { ...@@ -1381,6 +1387,7 @@ struct efx_nic_type {
void (*tx_init)(struct efx_tx_queue *tx_queue); void (*tx_init)(struct efx_tx_queue *tx_queue);
void (*tx_remove)(struct efx_tx_queue *tx_queue); void (*tx_remove)(struct efx_tx_queue *tx_queue);
void (*tx_write)(struct efx_tx_queue *tx_queue); void (*tx_write)(struct efx_tx_queue *tx_queue);
netdev_tx_t (*tx_enqueue)(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
unsigned int (*tx_limit_len)(struct efx_tx_queue *tx_queue, unsigned int (*tx_limit_len)(struct efx_tx_queue *tx_queue,
dma_addr_t dma_addr, unsigned int len); dma_addr_t dma_addr, unsigned int len);
int (*rx_push_rss_config)(struct efx_nic *efx, bool user, int (*rx_push_rss_config)(struct efx_nic *efx, bool user,
...@@ -1398,6 +1405,7 @@ struct efx_nic_type { ...@@ -1398,6 +1405,7 @@ struct efx_nic_type {
void (*rx_remove)(struct efx_rx_queue *rx_queue); void (*rx_remove)(struct efx_rx_queue *rx_queue);
void (*rx_write)(struct efx_rx_queue *rx_queue); void (*rx_write)(struct efx_rx_queue *rx_queue);
void (*rx_defer_refill)(struct efx_rx_queue *rx_queue); void (*rx_defer_refill)(struct efx_rx_queue *rx_queue);
void (*rx_packet)(struct efx_channel *channel);
int (*ev_probe)(struct efx_channel *channel); int (*ev_probe)(struct efx_channel *channel);
int (*ev_init)(struct efx_channel *channel); int (*ev_init)(struct efx_channel *channel);
void (*ev_fini)(struct efx_channel *channel); void (*ev_fini)(struct efx_channel *channel);
...@@ -1472,6 +1480,7 @@ struct efx_nic_type { ...@@ -1472,6 +1480,7 @@ struct efx_nic_type {
bool (*udp_tnl_has_port)(struct efx_nic *efx, __be16 port); bool (*udp_tnl_has_port)(struct efx_nic *efx, __be16 port);
size_t (*print_additional_fwver)(struct efx_nic *efx, char *buf, size_t (*print_additional_fwver)(struct efx_nic *efx, char *buf,
size_t len); size_t len);
void (*sensor_event)(struct efx_nic *efx, efx_qword_t *ev);
int revision; int revision;
unsigned int txd_ptr_tbl_base; unsigned int txd_ptr_tbl_base;
...@@ -1523,6 +1532,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index) ...@@ -1523,6 +1532,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index)
_channel = _channel->channel ? \ _channel = _channel->channel ? \
(_efx)->channel[_channel->channel - 1] : NULL) (_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 * static inline struct efx_tx_queue *
efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type) efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
{ {
......
...@@ -225,6 +225,12 @@ void efx_nic_event_test_start(struct efx_channel *channel); ...@@ -225,6 +225,12 @@ void efx_nic_event_test_start(struct efx_channel *channel);
bool efx_nic_event_present(struct efx_channel *channel); bool efx_nic_event_present(struct efx_channel *channel);
static inline void efx_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
{
if (efx->type->sensor_event)
efx->type->sensor_event(efx, ev);
}
/* Some statistics are computed as A - B where A and B each increase /* Some statistics are computed as A - B where A and B each increase
* linearly with some hardware counter(s) and the counters are read * linearly with some hardware counter(s) and the counters are read
* asynchronously. If the counters contributing to B are always read * asynchronously. If the counters contributing to B are always read
......
...@@ -1018,6 +1018,7 @@ const struct efx_nic_type siena_a0_nic_type = { ...@@ -1018,6 +1018,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.tx_remove = efx_farch_tx_remove, .tx_remove = efx_farch_tx_remove,
.tx_write = efx_farch_tx_write, .tx_write = efx_farch_tx_write,
.tx_limit_len = efx_farch_tx_limit_len, .tx_limit_len = efx_farch_tx_limit_len,
.tx_enqueue = __efx_enqueue_skb,
.rx_push_rss_config = siena_rx_push_rss_config, .rx_push_rss_config = siena_rx_push_rss_config,
.rx_pull_rss_config = siena_rx_pull_rss_config, .rx_pull_rss_config = siena_rx_pull_rss_config,
.rx_probe = efx_farch_rx_probe, .rx_probe = efx_farch_rx_probe,
...@@ -1025,6 +1026,7 @@ const struct efx_nic_type siena_a0_nic_type = { ...@@ -1025,6 +1026,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.rx_remove = efx_farch_rx_remove, .rx_remove = efx_farch_rx_remove,
.rx_write = efx_farch_rx_write, .rx_write = efx_farch_rx_write,
.rx_defer_refill = efx_farch_rx_defer_refill, .rx_defer_refill = efx_farch_rx_defer_refill,
.rx_packet = __efx_rx_packet,
.ev_probe = efx_farch_ev_probe, .ev_probe = efx_farch_ev_probe,
.ev_init = efx_farch_ev_init, .ev_init = efx_farch_ev_init,
.ev_fini = efx_farch_ev_fini, .ev_fini = efx_farch_ev_fini,
...@@ -1096,4 +1098,5 @@ const struct efx_nic_type siena_a0_nic_type = { ...@@ -1096,4 +1098,5 @@ const struct efx_nic_type siena_a0_nic_type = {
1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT), 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT),
.rx_hash_key_size = 16, .rx_hash_key_size = 16,
.check_caps = siena_check_caps, .check_caps = siena_check_caps,
.sensor_event = efx_mcdi_sensor_event,
}; };
...@@ -284,7 +284,7 @@ static int efx_enqueue_skb_pio(struct efx_tx_queue *tx_queue, ...@@ -284,7 +284,7 @@ static int efx_enqueue_skb_pio(struct efx_tx_queue *tx_queue,
* Returns NETDEV_TX_OK. * Returns NETDEV_TX_OK.
* You must hold netif_tx_lock() to call this function. * You must hold netif_tx_lock() to call this function.
*/ */
netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) netdev_tx_t __efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
{ {
unsigned int old_insert_count = tx_queue->insert_count; unsigned int old_insert_count = tx_queue->insert_count;
bool xmit_more = netdev_xmit_more(); bool xmit_more = netdev_xmit_more();
...@@ -503,7 +503,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, ...@@ -503,7 +503,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
} }
tx_queue = efx_get_tx_queue(efx, index, type); tx_queue = efx_get_tx_queue(efx, index, type);
return efx_enqueue_skb(tx_queue, skb); return __efx_enqueue_skb(tx_queue, skb);
} }
void efx_xmit_done_single(struct efx_tx_queue *tx_queue) void efx_xmit_done_single(struct efx_tx_queue *tx_queue)
......
...@@ -40,4 +40,6 @@ int efx_tx_map_data(struct efx_tx_queue *tx_queue, struct sk_buff *skb, ...@@ -40,4 +40,6 @@ int efx_tx_map_data(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
unsigned int efx_tx_max_skb_descs(struct efx_nic *efx); unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
int efx_tx_tso_fallback(struct efx_tx_queue *tx_queue, struct sk_buff *skb); int efx_tx_tso_fallback(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
extern bool efx_separate_tx_channels;
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment