Commit bca56ea6 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'move-siena-into-a-separate-subdirectory'

Martin Habets says:

====================
Move Siena into a separate subdirectory

The Siena NICs (SFN5000 and SFN6000 series) went EOL in November 2021.
Most of these adapters have been remove from our test labs, and testing
has been reduced to a minimum.

This patch series creates a separate kernel module for the Siena architecture,
analogous to what was done for Falcon some years ago.
This reduces our maintenance for the sfc.ko module, and allows us to
enhance the EF10 and EF100 drivers without the risk of breaking Siena NICs.

After this series further enhancements are needed to differentiate the
new kernel module from sfc.ko, and the Siena code can be removed from sfc.ko.
Thes will be posted as a small follow-up series.
The Siena module is not built by default, but can be enabled
using Kconfig option SFC_SIENA. This will create module sfc-siena.ko.

	Patches

Patches 1-3 establish the code base for the Siena driver.
Patches 4-10 ensure the allyesconfig build succeeds.
Patch 11 adds the basic Siena module.

I do not expect patch 1 through 3 to be reviewed, they are FYI only.
No checkpatch issues were resolved as part of these, but they
were fixed in the subsequent patches.

	Testing

Various build tests were done such as allyesconfig, W=1 and sparse.
The new sfc-siena.ko and sfc.ko modules were tested on a machine with both
these NICs in them, and several tests were run on both drivers.
====================

Link: https://lore.kernel.org/r/165211018297.5289.9658523545298485394.stgit@palantir17.mph.netSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 61004d1d c5a13c31
...@@ -65,5 +65,6 @@ config SFC_MCDI_LOGGING ...@@ -65,5 +65,6 @@ config SFC_MCDI_LOGGING
a sysfs file 'mcdi_logging' under the PCI device. a sysfs file 'mcdi_logging' under the PCI device.
source "drivers/net/ethernet/sfc/falcon/Kconfig" source "drivers/net/ethernet/sfc/falcon/Kconfig"
source "drivers/net/ethernet/sfc/siena/Kconfig"
endif # NET_VENDOR_SOLARFLARE endif # NET_VENDOR_SOLARFLARE
...@@ -13,3 +13,4 @@ sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ...@@ -13,3 +13,4 @@ sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o
obj-$(CONFIG_SFC) += sfc.o obj-$(CONFIG_SFC) += sfc.o
obj-$(CONFIG_SFC_FALCON) += falcon/ obj-$(CONFIG_SFC_FALCON) += falcon/
obj-$(CONFIG_SFC_SIENA) += siena/
# SPDX-License-Identifier: GPL-2.0-only
config SFC_SIENA
tristate "Solarflare SFC9000 support"
depends on PCI
select MDIO
select CRC32
help
This driver supports 10-gigabit Ethernet cards based on
the Solarflare SFC9000 controller.
To compile this driver as a module, choose M here. The module
will be called sfc-siena.
# SPDX-License-Identifier: GPL-2.0
sfc-siena-y += farch.o siena.o \
efx.o efx_common.o efx_channels.o nic.o \
tx.o tx_common.o rx.o rx_common.o \
selftest.o ethtool.o ethtool_common.o ptp.o \
mcdi.o mcdi_port.o mcdi_port_common.o \
mcdi_mon.o
sfc-siena-$(CONFIG_SFC_MTD) += mtd.o
sfc-siena-$(CONFIG_SFC_SRIOV) += siena_sriov.o
obj-$(CONFIG_SFC_SIENA) += sfc-siena.o
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications Inc.
*/
#ifndef EFX_EFX_H
#define EFX_EFX_H
#include <linux/indirect_call_wrapper.h>
#include "net_driver.h"
#include "filter.h"
/* TX */
void efx_siena_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue);
netdev_tx_t efx_siena_hard_start_xmit(struct sk_buff *skb,
struct net_device *net_dev);
netdev_tx_t __efx_siena_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_1(tx_queue->efx->type->tx_enqueue,
__efx_siena_enqueue_skb, tx_queue, skb);
}
int efx_siena_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
void *type_data);
/* RX */
void __efx_siena_rx_packet(struct efx_channel *channel);
void efx_siena_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int n_frags, unsigned int len, u16 flags);
static inline void efx_rx_flush_packet(struct efx_channel *channel)
{
if (channel->rx_pkt_n_frags)
__efx_siena_rx_packet(channel);
}
/* Maximum number of TCP segments we support for soft-TSO */
#define EFX_TSO_MAX_SEGS 100
/* The smallest [rt]xq_entries that the driver supports. RX minimum
* is a bit arbitrary. For TX, we must have space for at least 2
* TSO skbs.
*/
#define EFX_RXQ_MIN_ENT 128U
#define EFX_TXQ_MIN_ENT(efx) (2 * efx_siena_tx_max_skb_descs(efx))
/* All EF10 architecture NICs steal one bit of the DMAQ size for various
* other purposes when counting TxQ entries, so we halve the queue size.
*/
#define EFX_TXQ_MAX_ENT(efx) (EFX_WORKAROUND_EF10(efx) ? \
EFX_MAX_DMAQ_SIZE / 2 : EFX_MAX_DMAQ_SIZE)
static inline bool efx_rss_enabled(struct efx_nic *efx)
{
return efx->rss_spread > 1;
}
/* Filters */
/**
* efx_filter_insert_filter - add or replace a filter
* @efx: NIC in which to insert the filter
* @spec: Specification for the filter
* @replace_equal: Flag for whether the specified filter may replace an
* existing filter with equal priority
*
* On success, return the filter ID.
* On failure, return a negative error code.
*
* If existing filters have equal match values to the new filter spec,
* then the new filter might replace them or the function might fail,
* as follows.
*
* 1. If the existing filters have lower priority, or @replace_equal
* is set and they have equal priority, replace them.
*
* 2. If the existing filters have higher priority, return -%EPERM.
*
* 3. If !efx_siena_filter_is_mc_recipient(@spec), or the NIC does not
* support delivery to multiple recipients, return -%EEXIST.
*
* This implies that filters for multiple multicast recipients must
* all be inserted with the same priority and @replace_equal = %false.
*/
static inline s32 efx_filter_insert_filter(struct efx_nic *efx,
struct efx_filter_spec *spec,
bool replace_equal)
{
return efx->type->filter_insert(efx, spec, replace_equal);
}
/**
* efx_filter_remove_id_safe - remove a filter by ID, carefully
* @efx: NIC from which to remove the filter
* @priority: Priority of filter, as passed to @efx_filter_insert_filter
* @filter_id: ID of filter, as returned by @efx_filter_insert_filter
*
* This function will range-check @filter_id, so it is safe to call
* with a value passed from userland.
*/
static inline int efx_filter_remove_id_safe(struct efx_nic *efx,
enum efx_filter_priority priority,
u32 filter_id)
{
return efx->type->filter_remove_safe(efx, priority, filter_id);
}
/**
* efx_filter_get_filter_safe - retrieve a filter by ID, carefully
* @efx: NIC from which to remove the filter
* @priority: Priority of filter, as passed to @efx_filter_insert_filter
* @filter_id: ID of filter, as returned by @efx_filter_insert_filter
* @spec: Buffer in which to store filter specification
*
* This function will range-check @filter_id, so it is safe to call
* with a value passed from userland.
*/
static inline int
efx_filter_get_filter_safe(struct efx_nic *efx,
enum efx_filter_priority priority,
u32 filter_id, struct efx_filter_spec *spec)
{
return efx->type->filter_get_safe(efx, priority, filter_id, spec);
}
static inline u32 efx_filter_count_rx_used(struct efx_nic *efx,
enum efx_filter_priority priority)
{
return efx->type->filter_count_rx_used(efx, priority);
}
static inline u32 efx_filter_get_rx_id_limit(struct efx_nic *efx)
{
return efx->type->filter_get_rx_id_limit(efx);
}
static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx,
enum efx_filter_priority priority,
u32 *buf, u32 size)
{
return efx->type->filter_get_rx_ids(efx, priority, buf, size);
}
/* RSS contexts */
static inline bool efx_rss_active(struct efx_rss_context *ctx)
{
return ctx->context_id != EFX_MCDI_RSS_CONTEXT_INVALID;
}
/* Ethtool support */
extern const struct ethtool_ops efx_siena_ethtool_ops;
/* Global */
unsigned int efx_siena_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs);
int efx_siena_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
unsigned int rx_usecs, bool rx_adaptive,
bool rx_may_override_tx);
void efx_siena_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
unsigned int *rx_usecs, bool *rx_adaptive);
/* Update the generic software stats in the passed stats array */
void efx_siena_update_sw_stats(struct efx_nic *efx, u64 *stats);
/* MTD */
#ifdef CONFIG_SFC_MTD
int efx_siena_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts,
size_t n_parts, size_t sizeof_part);
static inline int efx_mtd_probe(struct efx_nic *efx)
{
return efx->type->mtd_probe(efx);
}
void efx_siena_mtd_rename(struct efx_nic *efx);
void efx_siena_mtd_remove(struct efx_nic *efx);
#else
static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; }
static inline void efx_siena_mtd_rename(struct efx_nic *efx) {}
static inline void efx_siena_mtd_remove(struct efx_nic *efx) {}
#endif
#ifdef CONFIG_SFC_SRIOV
static inline unsigned int efx_vf_size(struct efx_nic *efx)
{
return 1 << efx->vi_scale;
}
#endif
static inline void efx_device_detach_sync(struct efx_nic *efx)
{
struct net_device *dev = efx->net_dev;
/* Lock/freeze all TX queues so that we can be sure the
* TX scheduler is stopped when we're done and before
* netif_device_present() becomes false.
*/
netif_tx_lock_bh(dev);
netif_device_detach(dev);
netif_tx_unlock_bh(dev);
}
static inline void efx_device_attach_if_not_resetting(struct efx_nic *efx)
{
if ((efx->state != STATE_DISABLED) && !efx->reset_pending)
netif_device_attach(efx->net_dev);
}
static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem)
{
if (WARN_ON(down_read_trylock(sem))) {
up_read(sem);
return false;
}
return true;
}
int efx_siena_xdp_tx_buffers(struct efx_nic *efx, int n,
struct xdp_frame **xdpfs, bool flush);
#endif /* EFX_EFX_H */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2018 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.
*/
#ifndef EFX_CHANNELS_H
#define EFX_CHANNELS_H
extern unsigned int efx_siena_interrupt_mode;
extern unsigned int efx_siena_rss_cpus;
int efx_siena_probe_interrupts(struct efx_nic *efx);
void efx_siena_remove_interrupts(struct efx_nic *efx);
int efx_siena_enable_interrupts(struct efx_nic *efx);
void efx_siena_disable_interrupts(struct efx_nic *efx);
void efx_siena_set_interrupt_affinity(struct efx_nic *efx);
void efx_siena_clear_interrupt_affinity(struct efx_nic *efx);
void efx_siena_start_eventq(struct efx_channel *channel);
void efx_siena_stop_eventq(struct efx_channel *channel);
int efx_siena_realloc_channels(struct efx_nic *efx, u32 rxq_entries,
u32 txq_entries);
void efx_siena_set_channel_names(struct efx_nic *efx);
int efx_siena_init_channels(struct efx_nic *efx);
int efx_siena_probe_channels(struct efx_nic *efx);
int efx_siena_set_channels(struct efx_nic *efx);
void efx_siena_remove_channel(struct efx_channel *channel);
void efx_siena_remove_channels(struct efx_nic *efx);
void efx_siena_fini_channels(struct efx_nic *efx);
void efx_siena_start_channels(struct efx_nic *efx);
void efx_siena_stop_channels(struct efx_nic *efx);
void efx_siena_init_napi(struct efx_nic *efx);
void efx_siena_fini_napi(struct efx_nic *efx);
void efx_siena_channel_dummy_op_void(struct efx_channel *channel);
#endif
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2018 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.
*/
#ifndef EFX_COMMON_H
#define EFX_COMMON_H
int efx_siena_init_io(struct efx_nic *efx, int bar, dma_addr_t dma_mask,
unsigned int mem_map_size);
void efx_siena_fini_io(struct efx_nic *efx);
int efx_siena_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev,
struct net_device *net_dev);
void efx_siena_fini_struct(struct efx_nic *efx);
#define EFX_MAX_DMAQ_SIZE 4096UL
#define EFX_DEFAULT_DMAQ_SIZE 1024UL
#define EFX_MIN_DMAQ_SIZE 512UL
#define EFX_MAX_EVQ_SIZE 16384UL
#define EFX_MIN_EVQ_SIZE 512UL
void efx_siena_link_clear_advertising(struct efx_nic *efx);
void efx_siena_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc);
void efx_siena_start_all(struct efx_nic *efx);
void efx_siena_stop_all(struct efx_nic *efx);
void efx_siena_net_stats(struct net_device *net_dev,
struct rtnl_link_stats64 *stats);
int efx_siena_create_reset_workqueue(void);
void efx_siena_queue_reset_work(struct efx_nic *efx);
void efx_siena_flush_reset_workqueue(struct efx_nic *efx);
void efx_siena_destroy_reset_workqueue(void);
void efx_siena_start_monitor(struct efx_nic *efx);
int __efx_siena_reconfigure_port(struct efx_nic *efx);
int efx_siena_reconfigure_port(struct efx_nic *efx);
#define EFX_ASSERT_RESET_SERIALISED(efx) \
do { \
if ((efx->state == STATE_READY) || \
(efx->state == STATE_RECOVERY) || \
(efx->state == STATE_DISABLED)) \
ASSERT_RTNL(); \
} while (0)
int efx_siena_try_recovery(struct efx_nic *efx);
void efx_siena_reset_down(struct efx_nic *efx, enum reset_type method);
void efx_siena_watchdog(struct net_device *net_dev, unsigned int txqueue);
int efx_siena_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
int efx_siena_reset(struct efx_nic *efx, enum reset_type method);
void efx_siena_schedule_reset(struct efx_nic *efx, enum reset_type type);
/* Dummy PHY ops for PHY drivers */
int efx_siena_port_dummy_op_int(struct efx_nic *efx);
void efx_siena_port_dummy_op_void(struct efx_nic *efx);
static inline int efx_check_disabled(struct efx_nic *efx)
{
if (efx->state == STATE_DISABLED || efx->state == STATE_RECOVERY) {
netif_err(efx, drv, efx->net_dev,
"device is disabled due to earlier errors\n");
return -EIO;
}
return 0;
}
static inline void efx_schedule_channel(struct efx_channel *channel)
{
netif_vdbg(channel->efx, intr, channel->efx->net_dev,
"channel %d scheduling NAPI poll on CPU%d\n",
channel->channel, raw_smp_processor_id());
napi_schedule(&channel->napi_str);
}
static inline void efx_schedule_channel_irq(struct efx_channel *channel)
{
channel->event_test_cpu = raw_smp_processor_id();
efx_schedule_channel(channel);
}
#ifdef CONFIG_SFC_MCDI_LOGGING
void efx_siena_init_mcdi_logging(struct efx_nic *efx);
void efx_siena_fini_mcdi_logging(struct efx_nic *efx);
#else
static inline void efx_siena_init_mcdi_logging(struct efx_nic *efx) {}
static inline void efx_siena_fini_mcdi_logging(struct efx_nic *efx) {}
#endif
void efx_siena_mac_reconfigure(struct efx_nic *efx, bool mtu_only);
int efx_siena_set_mac_address(struct net_device *net_dev, void *data);
void efx_siena_set_rx_mode(struct net_device *net_dev);
int efx_siena_set_features(struct net_device *net_dev, netdev_features_t data);
void efx_siena_link_status_changed(struct efx_nic *efx);
unsigned int efx_siena_xdp_max_mtu(struct efx_nic *efx);
int efx_siena_change_mtu(struct net_device *net_dev, int new_mtu);
extern const struct pci_error_handlers efx_siena_err_handlers;
netdev_features_t efx_siena_features_check(struct sk_buff *skb,
struct net_device *dev,
netdev_features_t features);
int efx_siena_get_phys_port_id(struct net_device *net_dev,
struct netdev_phys_item_id *ppid);
int efx_siena_get_phys_port_name(struct net_device *net_dev,
char *name, size_t len);
#endif
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2007-2013 Solarflare Communications Inc.
*/
#ifndef EFX_ENUM_H
#define EFX_ENUM_H
/**
* enum efx_loopback_mode - loopback modes
* @LOOPBACK_NONE: no loopback
* @LOOPBACK_DATA: data path loopback
* @LOOPBACK_GMAC: loopback within GMAC
* @LOOPBACK_XGMII: loopback after XMAC
* @LOOPBACK_XGXS: loopback within BPX after XGXS
* @LOOPBACK_XAUI: loopback within BPX before XAUI serdes
* @LOOPBACK_GMII: loopback within BPX after GMAC
* @LOOPBACK_SGMII: loopback within BPX within SGMII
* @LOOPBACK_XGBR: loopback within BPX within XGBR
* @LOOPBACK_XFI: loopback within BPX before XFI serdes
* @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes
* @LOOPBACK_GMII_FAR: loopback within BPX before SGMII
* @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII
* @LOOPBACK_XFI_FAR: loopback after XFI serdes
* @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level
* @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level
* @LOOPBACK_PCS: loopback within 10G PHY at PCS level
* @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level
* @LOOPBACK_XPORT: cross port loopback
* @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC
* @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes
* @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes
* @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes
* @LOOPBACK_GMII_WS: wireside loopback excluding GMAC
* @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes
* @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes
* @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level
*/
/* Please keep up-to-date w.r.t the following two #defines */
enum efx_loopback_mode {
LOOPBACK_NONE = 0,
LOOPBACK_DATA = 1,
LOOPBACK_GMAC = 2,
LOOPBACK_XGMII = 3,
LOOPBACK_XGXS = 4,
LOOPBACK_XAUI = 5,
LOOPBACK_GMII = 6,
LOOPBACK_SGMII = 7,
LOOPBACK_XGBR = 8,
LOOPBACK_XFI = 9,
LOOPBACK_XAUI_FAR = 10,
LOOPBACK_GMII_FAR = 11,
LOOPBACK_SGMII_FAR = 12,
LOOPBACK_XFI_FAR = 13,
LOOPBACK_GPHY = 14,
LOOPBACK_PHYXS = 15,
LOOPBACK_PCS = 16,
LOOPBACK_PMAPMD = 17,
LOOPBACK_XPORT = 18,
LOOPBACK_XGMII_WS = 19,
LOOPBACK_XAUI_WS = 20,
LOOPBACK_XAUI_WS_FAR = 21,
LOOPBACK_XAUI_WS_NEAR = 22,
LOOPBACK_GMII_WS = 23,
LOOPBACK_XFI_WS = 24,
LOOPBACK_XFI_WS_FAR = 25,
LOOPBACK_PHYXS_WS = 26,
LOOPBACK_MAX
};
#define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD
/* These loopbacks occur within the controller */
#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) | \
(1 << LOOPBACK_GMAC) | \
(1 << LOOPBACK_XGMII)| \
(1 << LOOPBACK_XGXS) | \
(1 << LOOPBACK_XAUI) | \
(1 << LOOPBACK_GMII) | \
(1 << LOOPBACK_SGMII) | \
(1 << LOOPBACK_XGBR) | \
(1 << LOOPBACK_XFI) | \
(1 << LOOPBACK_XAUI_FAR) | \
(1 << LOOPBACK_GMII_FAR) | \
(1 << LOOPBACK_SGMII_FAR) | \
(1 << LOOPBACK_XFI_FAR) | \
(1 << LOOPBACK_XGMII_WS) | \
(1 << LOOPBACK_XAUI_WS) | \
(1 << LOOPBACK_XAUI_WS_FAR) | \
(1 << LOOPBACK_XAUI_WS_NEAR) | \
(1 << LOOPBACK_GMII_WS) | \
(1 << LOOPBACK_XFI_WS) | \
(1 << LOOPBACK_XFI_WS_FAR))
#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) | \
(1 << LOOPBACK_XAUI_WS) | \
(1 << LOOPBACK_XAUI_WS_FAR) | \
(1 << LOOPBACK_XAUI_WS_NEAR) | \
(1 << LOOPBACK_GMII_WS) | \
(1 << LOOPBACK_XFI_WS) | \
(1 << LOOPBACK_XFI_WS_FAR) | \
(1 << LOOPBACK_PHYXS_WS))
#define LOOPBACKS_EXTERNAL(_efx) \
((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL & \
~(1 << LOOPBACK_NONE))
#define LOOPBACK_MASK(_efx) \
(1 << (_efx)->loopback_mode)
#define LOOPBACK_INTERNAL(_efx) \
(!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx)))
#define LOOPBACK_EXTERNAL(_efx) \
(!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx)))
#define LOOPBACK_CHANGED(_from, _to, _mask) \
(!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask)))
#define LOOPBACK_OUT_OF(_from, _to, _mask) \
((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask)))
/*****************************************************************************/
/**
* enum reset_type - reset types
*
* %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and
* %RESET_TYPE_DISABLE specify the method/scope of the reset. The
* other valuesspecify reasons, which efx_siena_schedule_reset() will choose
* a method for.
*
* Reset methods are numbered in order of increasing scope.
*
* @RESET_TYPE_INVISIBLE: Reset datapath and MAC (Falcon only)
* @RESET_TYPE_RECOVER_OR_ALL: Try to recover. Apply RESET_TYPE_ALL
* if unsuccessful.
* @RESET_TYPE_ALL: Reset datapath, MAC and PHY
* @RESET_TYPE_WORLD: Reset as much as possible
* @RESET_TYPE_RECOVER_OR_DISABLE: Try to recover. Apply RESET_TYPE_DISABLE if
* unsuccessful.
* @RESET_TYPE_DATAPATH: Reset datapath only.
* @RESET_TYPE_MC_BIST: MC entering BIST mode.
* @RESET_TYPE_DISABLE: Reset datapath, MAC and PHY; leave NIC disabled
* @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
* @RESET_TYPE_INT_ERROR: reset due to internal error
* @RESET_TYPE_DMA_ERROR: DMA error
* @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
* @RESET_TYPE_MC_FAILURE: MC reboot/assertion
* @RESET_TYPE_MCDI_TIMEOUT: MCDI timeout.
*/
enum reset_type {
RESET_TYPE_INVISIBLE,
RESET_TYPE_RECOVER_OR_ALL,
RESET_TYPE_ALL,
RESET_TYPE_WORLD,
RESET_TYPE_RECOVER_OR_DISABLE,
RESET_TYPE_DATAPATH,
RESET_TYPE_MC_BIST,
RESET_TYPE_DISABLE,
RESET_TYPE_MAX_METHOD,
RESET_TYPE_TX_WATCHDOG,
RESET_TYPE_INT_ERROR,
RESET_TYPE_DMA_ERROR,
RESET_TYPE_TX_SKIP,
RESET_TYPE_MC_FAILURE,
/* RESET_TYPE_MCDI_TIMEOUT is actually a method, not just a reason, but
* it doesn't fit the scope hierarchy (not well-ordered by inclusion).
* We encode this by having its enum value be greater than
* RESET_TYPE_MAX_METHOD.
*/
RESET_TYPE_MCDI_TIMEOUT,
RESET_TYPE_MAX,
};
#endif /* EFX_ENUM_H */
// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications Inc.
*/
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include <linux/in.h>
#include "net_driver.h"
#include "workarounds.h"
#include "selftest.h"
#include "efx.h"
#include "efx_channels.h"
#include "rx_common.h"
#include "tx_common.h"
#include "ethtool_common.h"
#include "filter.h"
#include "nic.h"
#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
/**************************************************************************
*
* Ethtool operations
*
**************************************************************************
*/
/* Identify device by flashing LEDs */
static int efx_ethtool_phys_id(struct net_device *net_dev,
enum ethtool_phys_id_state state)
{
struct efx_nic *efx = netdev_priv(net_dev);
enum efx_led_mode mode = EFX_LED_DEFAULT;
switch (state) {
case ETHTOOL_ID_ON:
mode = EFX_LED_ON;
break;
case ETHTOOL_ID_OFF:
mode = EFX_LED_OFF;
break;
case ETHTOOL_ID_INACTIVE:
mode = EFX_LED_DEFAULT;
break;
case ETHTOOL_ID_ACTIVE:
return 1; /* cycle on/off once per second */
}
return efx_siena_mcdi_set_id_led(efx, mode);
}
static int efx_ethtool_get_regs_len(struct net_device *net_dev)
{
return efx_siena_get_regs_len(netdev_priv(net_dev));
}
static void efx_ethtool_get_regs(struct net_device *net_dev,
struct ethtool_regs *regs, void *buf)
{
struct efx_nic *efx = netdev_priv(net_dev);
regs->version = efx->type->revision;
efx_siena_get_regs(efx, buf);
}
/*
* Each channel has a single IRQ and moderation timer, started by any
* completion (or other event). Unless the module parameter
* separate_tx_channels is set, IRQs and moderation are therefore
* shared between RX and TX completions. In this case, when RX IRQ
* moderation is explicitly changed then TX IRQ moderation is
* automatically changed too, but otherwise we fail if the two values
* are requested to be different.
*
* The hardware does not support a limit on the number of completions
* before an IRQ, so we do not use the max_frames fields. We should
* report and require that max_frames == (usecs != 0), but this would
* invalidate existing user documentation.
*
* The hardware does not have distinct settings for interrupt
* moderation while the previous IRQ is being handled, so we should
* not use the 'irq' fields. However, an earlier developer
* misunderstood the meaning of the 'irq' fields and the driver did
* not support the standard fields. To avoid invalidating existing
* user documentation, we report and accept changes through either the
* standard or 'irq' fields. If both are changed at the same time, we
* prefer the standard field.
*
* We implement adaptive IRQ moderation, but use a different algorithm
* from that assumed in the definition of struct ethtool_coalesce.
* Therefore we do not use any of the adaptive moderation parameters
* in it.
*/
static int efx_ethtool_get_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce,
struct kernel_ethtool_coalesce *kernel_coal,
struct netlink_ext_ack *extack)
{
struct efx_nic *efx = netdev_priv(net_dev);
unsigned int tx_usecs, rx_usecs;
bool rx_adaptive;
efx_siena_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive);
coalesce->tx_coalesce_usecs = tx_usecs;
coalesce->tx_coalesce_usecs_irq = tx_usecs;
coalesce->rx_coalesce_usecs = rx_usecs;
coalesce->rx_coalesce_usecs_irq = rx_usecs;
coalesce->use_adaptive_rx_coalesce = rx_adaptive;
return 0;
}
static int efx_ethtool_set_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce,
struct kernel_ethtool_coalesce *kernel_coal,
struct netlink_ext_ack *extack)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_channel *channel;
unsigned int tx_usecs, rx_usecs;
bool adaptive, rx_may_override_tx;
int rc;
efx_siena_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);
if (coalesce->rx_coalesce_usecs != rx_usecs)
rx_usecs = coalesce->rx_coalesce_usecs;
else
rx_usecs = coalesce->rx_coalesce_usecs_irq;
adaptive = coalesce->use_adaptive_rx_coalesce;
/* If channels are shared, TX IRQ moderation can be quietly
* overridden unless it is changed from its old value.
*/
rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs &&
coalesce->tx_coalesce_usecs_irq == tx_usecs);
if (coalesce->tx_coalesce_usecs != tx_usecs)
tx_usecs = coalesce->tx_coalesce_usecs;
else
tx_usecs = coalesce->tx_coalesce_usecs_irq;
rc = efx_siena_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive,
rx_may_override_tx);
if (rc != 0)
return rc;
efx_for_each_channel(channel, efx)
efx->type->push_irq_moderation(channel);
return 0;
}
static void
efx_ethtool_get_ringparam(struct net_device *net_dev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
struct netlink_ext_ack *extack)
{
struct efx_nic *efx = netdev_priv(net_dev);
ring->rx_max_pending = EFX_MAX_DMAQ_SIZE;
ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx);
ring->rx_pending = efx->rxq_entries;
ring->tx_pending = efx->txq_entries;
}
static int
efx_ethtool_set_ringparam(struct net_device *net_dev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
struct netlink_ext_ack *extack)
{
struct efx_nic *efx = netdev_priv(net_dev);
u32 txq_entries;
if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
ring->tx_pending > EFX_TXQ_MAX_ENT(efx))
return -EINVAL;
if (ring->rx_pending < EFX_RXQ_MIN_ENT) {
netif_err(efx, drv, efx->net_dev,
"RX queues cannot be smaller than %u\n",
EFX_RXQ_MIN_ENT);
return -EINVAL;
}
txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));
if (txq_entries != ring->tx_pending)
netif_warn(efx, drv, efx->net_dev,
"increasing TX queue size to minimum of %u\n",
txq_entries);
return efx_siena_realloc_channels(efx, ring->rx_pending, txq_entries);
}
static void efx_ethtool_get_wol(struct net_device *net_dev,
struct ethtool_wolinfo *wol)
{
struct efx_nic *efx = netdev_priv(net_dev);
return efx->type->get_wol(efx, wol);
}
static int efx_ethtool_set_wol(struct net_device *net_dev,
struct ethtool_wolinfo *wol)
{
struct efx_nic *efx = netdev_priv(net_dev);
return efx->type->set_wol(efx, wol->wolopts);
}
static void efx_ethtool_get_fec_stats(struct net_device *net_dev,
struct ethtool_fec_stats *fec_stats)
{
struct efx_nic *efx = netdev_priv(net_dev);
if (efx->type->get_fec_stats)
efx->type->get_fec_stats(efx, fec_stats);
}
static int efx_ethtool_get_ts_info(struct net_device *net_dev,
struct ethtool_ts_info *ts_info)
{
struct efx_nic *efx = netdev_priv(net_dev);
/* Software capabilities */
ts_info->so_timestamping = (SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE);
ts_info->phc_index = -1;
efx_siena_ptp_get_ts_info(efx, ts_info);
return 0;
}
const struct ethtool_ops efx_siena_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USECS_IRQ |
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
.get_drvinfo = efx_siena_ethtool_get_drvinfo,
.get_regs_len = efx_ethtool_get_regs_len,
.get_regs = efx_ethtool_get_regs,
.get_msglevel = efx_siena_ethtool_get_msglevel,
.set_msglevel = efx_siena_ethtool_set_msglevel,
.get_link = ethtool_op_get_link,
.get_coalesce = efx_ethtool_get_coalesce,
.set_coalesce = efx_ethtool_set_coalesce,
.get_ringparam = efx_ethtool_get_ringparam,
.set_ringparam = efx_ethtool_set_ringparam,
.get_pauseparam = efx_siena_ethtool_get_pauseparam,
.set_pauseparam = efx_siena_ethtool_set_pauseparam,
.get_sset_count = efx_siena_ethtool_get_sset_count,
.self_test = efx_siena_ethtool_self_test,
.get_strings = efx_siena_ethtool_get_strings,
.set_phys_id = efx_ethtool_phys_id,
.get_ethtool_stats = efx_siena_ethtool_get_stats,
.get_wol = efx_ethtool_get_wol,
.set_wol = efx_ethtool_set_wol,
.reset = efx_siena_ethtool_reset,
.get_rxnfc = efx_siena_ethtool_get_rxnfc,
.set_rxnfc = efx_siena_ethtool_set_rxnfc,
.get_rxfh_indir_size = efx_siena_ethtool_get_rxfh_indir_size,
.get_rxfh_key_size = efx_siena_ethtool_get_rxfh_key_size,
.get_rxfh = efx_siena_ethtool_get_rxfh,
.set_rxfh = efx_siena_ethtool_set_rxfh,
.get_rxfh_context = efx_siena_ethtool_get_rxfh_context,
.set_rxfh_context = efx_siena_ethtool_set_rxfh_context,
.get_ts_info = efx_ethtool_get_ts_info,
.get_module_info = efx_siena_ethtool_get_module_info,
.get_module_eeprom = efx_siena_ethtool_get_module_eeprom,
.get_link_ksettings = efx_siena_ethtool_get_link_ksettings,
.set_link_ksettings = efx_siena_ethtool_set_link_ksettings,
.get_fec_stats = efx_ethtool_get_fec_stats,
.get_fecparam = efx_siena_ethtool_get_fecparam,
.set_fecparam = efx_siena_ethtool_set_fecparam,
};
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 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.
*/
#ifndef EFX_ETHTOOL_COMMON_H
#define EFX_ETHTOOL_COMMON_H
void efx_siena_ethtool_get_drvinfo(struct net_device *net_dev,
struct ethtool_drvinfo *info);
u32 efx_siena_ethtool_get_msglevel(struct net_device *net_dev);
void efx_siena_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable);
void efx_siena_ethtool_self_test(struct net_device *net_dev,
struct ethtool_test *test, u64 *data);
void efx_siena_ethtool_get_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause);
int efx_siena_ethtool_set_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause);
int efx_siena_ethtool_get_sset_count(struct net_device *net_dev, int string_set);
void efx_siena_ethtool_get_strings(struct net_device *net_dev, u32 string_set,
u8 *strings);
void efx_siena_ethtool_get_stats(struct net_device *net_dev,
struct ethtool_stats *stats __always_unused,
u64 *data);
int efx_siena_ethtool_get_link_ksettings(struct net_device *net_dev,
struct ethtool_link_ksettings *out);
int efx_siena_ethtool_set_link_ksettings(struct net_device *net_dev,
const struct ethtool_link_ksettings *settings);
int efx_siena_ethtool_get_fecparam(struct net_device *net_dev,
struct ethtool_fecparam *fecparam);
int efx_siena_ethtool_set_fecparam(struct net_device *net_dev,
struct ethtool_fecparam *fecparam);
int efx_siena_ethtool_get_rxnfc(struct net_device *net_dev,
struct ethtool_rxnfc *info, u32 *rule_locs);
int efx_siena_ethtool_set_rxnfc(struct net_device *net_dev,
struct ethtool_rxnfc *info);
u32 efx_siena_ethtool_get_rxfh_indir_size(struct net_device *net_dev);
u32 efx_siena_ethtool_get_rxfh_key_size(struct net_device *net_dev);
int efx_siena_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
u8 *hfunc);
int efx_siena_ethtool_set_rxfh(struct net_device *net_dev,
const u32 *indir, const u8 *key, const u8 hfunc);
int efx_siena_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
u8 *key, u8 *hfunc, u32 rss_context);
int efx_siena_ethtool_set_rxfh_context(struct net_device *net_dev,
const u32 *indir, const u8 *key,
const u8 hfunc, u32 *rss_context,
bool delete);
int efx_siena_ethtool_reset(struct net_device *net_dev, u32 *flags);
int efx_siena_ethtool_get_module_eeprom(struct net_device *net_dev,
struct ethtool_eeprom *ee,
u8 *data);
int efx_siena_ethtool_get_module_info(struct net_device *net_dev,
struct ethtool_modinfo *modinfo);
#endif
...@@ -233,7 +233,7 @@ static int efx_alloc_special_buffer(struct efx_nic *efx, ...@@ -233,7 +233,7 @@ static int efx_alloc_special_buffer(struct efx_nic *efx,
#endif #endif
len = ALIGN(len, EFX_BUF_SIZE); len = ALIGN(len, EFX_BUF_SIZE);
if (efx_nic_alloc_buffer(efx, &buffer->buf, len, GFP_KERNEL)) if (efx_siena_alloc_buffer(efx, &buffer->buf, len, GFP_KERNEL))
return -ENOMEM; return -ENOMEM;
buffer->entries = len / EFX_BUF_SIZE; buffer->entries = len / EFX_BUF_SIZE;
BUG_ON(buffer->buf.dma_addr & (EFX_BUF_SIZE - 1)); BUG_ON(buffer->buf.dma_addr & (EFX_BUF_SIZE - 1));
...@@ -269,7 +269,7 @@ efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) ...@@ -269,7 +269,7 @@ efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
(u64)buffer->buf.dma_addr, buffer->buf.len, (u64)buffer->buf.dma_addr, buffer->buf.len,
buffer->buf.addr, (u64)virt_to_phys(buffer->buf.addr)); buffer->buf.addr, (u64)virt_to_phys(buffer->buf.addr));
efx_nic_free_buffer(efx, &buffer->buf); efx_siena_free_buffer(efx, &buffer->buf);
buffer->entries = 0; buffer->entries = 0;
} }
...@@ -667,7 +667,7 @@ static int efx_farch_do_flush(struct efx_nic *efx) ...@@ -667,7 +667,7 @@ static int efx_farch_do_flush(struct efx_nic *efx)
* completion). If that fails, fall back to the old scheme. * completion). If that fails, fall back to the old scheme.
*/ */
if (efx_siena_sriov_enabled(efx)) { if (efx_siena_sriov_enabled(efx)) {
rc = efx_mcdi_flush_rxqs(efx); rc = efx_siena_mcdi_flush_rxqs(efx);
if (!rc) if (!rc)
goto wait; goto wait;
} }
...@@ -747,12 +747,13 @@ int efx_farch_fini_dmaq(struct efx_nic *efx) ...@@ -747,12 +747,13 @@ int efx_farch_fini_dmaq(struct efx_nic *efx)
* completion events. This means that efx->rxq_flush_outstanding remained at 4 * completion events. This means that efx->rxq_flush_outstanding remained at 4
* after the FLR; also, efx->active_queues was non-zero (as no flush completion * after the FLR; also, efx->active_queues was non-zero (as no flush completion
* events were received, and we didn't go through efx_check_tx_flush_complete()) * events were received, and we didn't go through efx_check_tx_flush_complete())
* If we don't fix this up, on the next call to efx_realloc_channels() we won't * If we don't fix this up, on the next call to efx_siena_realloc_channels() we
* flush any RX queues because efx->rxq_flush_outstanding is at the limit of 4 * won't flush any RX queues because efx->rxq_flush_outstanding is at the limit
* for batched flush requests; and the efx->active_queues gets messed up because * of 4 for batched flush requests; and the efx->active_queues gets messed up
* we keep incrementing for the newly initialised queues, but it never went to * because we keep incrementing for the newly initialised queues, but it never
* zero previously. Then we get a timeout every time we try to restart the * went to zero previously. Then we get a timeout every time we try to restart
* queues, as it doesn't go back to zero when we should be flushing the queues. * the queues, as it doesn't go back to zero when we should be flushing the
* queues.
*/ */
void efx_farch_finish_flr(struct efx_nic *efx) void efx_farch_finish_flr(struct efx_nic *efx)
{ {
...@@ -838,7 +839,7 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) ...@@ -838,7 +839,7 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
tx_queue = channel->tx_queue + tx_queue = channel->tx_queue +
(tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL); (tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL);
efx_xmit_done(tx_queue, tx_ev_desc_ptr); efx_siena_xmit_done(tx_queue, tx_ev_desc_ptr);
} else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) {
/* Rewrite the FIFO write pointer */ /* Rewrite the FIFO write pointer */
tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
...@@ -849,7 +850,7 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) ...@@ -849,7 +850,7 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
efx_farch_notify_tx_desc(tx_queue); efx_farch_notify_tx_desc(tx_queue);
netif_tx_unlock(efx->net_dev); netif_tx_unlock(efx->net_dev);
} else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR)) { } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR)) {
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR); efx_siena_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
} else { } else {
netif_err(efx, tx_err, efx->net_dev, netif_err(efx, tx_err, efx->net_dev,
"channel %d unexpected TX event " "channel %d unexpected TX event "
...@@ -956,7 +957,7 @@ efx_farch_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index) ...@@ -956,7 +957,7 @@ efx_farch_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index)
"dropped %d events (index=%d expected=%d)\n", "dropped %d events (index=%d expected=%d)\n",
dropped, index, expected); dropped, index, expected);
efx_schedule_reset(efx, RESET_TYPE_DISABLE); efx_siena_schedule_reset(efx, RESET_TYPE_DISABLE);
return false; return false;
} }
...@@ -1001,7 +1002,7 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) ...@@ -1001,7 +1002,7 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
/* Discard all pending fragments */ /* Discard all pending fragments */
if (rx_queue->scatter_n) { if (rx_queue->scatter_n) {
efx_rx_packet( efx_siena_rx_packet(
rx_queue, rx_queue,
rx_queue->removed_count & rx_queue->ptr_mask, rx_queue->removed_count & rx_queue->ptr_mask,
rx_queue->scatter_n, 0, EFX_RX_PKT_DISCARD); rx_queue->scatter_n, 0, EFX_RX_PKT_DISCARD);
...@@ -1015,7 +1016,7 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) ...@@ -1015,7 +1016,7 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
/* Discard new fragment if not SOP */ /* Discard new fragment if not SOP */
if (!rx_ev_sop) { if (!rx_ev_sop) {
efx_rx_packet( efx_siena_rx_packet(
rx_queue, rx_queue,
rx_queue->removed_count & rx_queue->ptr_mask, rx_queue->removed_count & rx_queue->ptr_mask,
1, 0, EFX_RX_PKT_DISCARD); 1, 0, EFX_RX_PKT_DISCARD);
...@@ -1067,7 +1068,7 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) ...@@ -1067,7 +1068,7 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
channel->irq_mod_score += 2; channel->irq_mod_score += 2;
/* Handle received packet */ /* Handle received packet */
efx_rx_packet(rx_queue, efx_siena_rx_packet(rx_queue,
rx_queue->removed_count & rx_queue->ptr_mask, rx_queue->removed_count & rx_queue->ptr_mask,
rx_queue->scatter_n, rx_ev_byte_cnt, flags); rx_queue->scatter_n, rx_ev_byte_cnt, flags);
rx_queue->removed_count += rx_queue->scatter_n; rx_queue->removed_count += rx_queue->scatter_n;
...@@ -1159,7 +1160,7 @@ static void efx_farch_handle_generated_event(struct efx_channel *channel, ...@@ -1159,7 +1160,7 @@ static void efx_farch_handle_generated_event(struct efx_channel *channel,
/* The queue must be empty, so we won't receive any rx /* The queue must be empty, so we won't receive any rx
* events, so efx_process_channel() won't refill the * events, so efx_process_channel() won't refill the
* queue. Refill it here */ * queue. Refill it here */
efx_fast_push_rx_descriptors(rx_queue, true); efx_siena_fast_push_rx_descriptors(rx_queue, true);
} else if (rx_queue && magic == EFX_CHANNEL_MAGIC_RX_DRAIN(rx_queue)) { } else if (rx_queue && magic == EFX_CHANNEL_MAGIC_RX_DRAIN(rx_queue)) {
efx_farch_handle_drain_event(channel); efx_farch_handle_drain_event(channel);
} else if (code == _EFX_CHANNEL_MAGIC_TX_DRAIN) { } else if (code == _EFX_CHANNEL_MAGIC_TX_DRAIN) {
...@@ -1222,7 +1223,7 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) ...@@ -1222,7 +1223,7 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
"channel %d seen DRIVER RX_RESET event. " "channel %d seen DRIVER RX_RESET event. "
"Resetting.\n", channel->channel); "Resetting.\n", channel->channel);
atomic_inc(&efx->rx_reset); atomic_inc(&efx->rx_reset);
efx_schedule_reset(efx, RESET_TYPE_DISABLE); efx_siena_schedule_reset(efx, RESET_TYPE_DISABLE);
break; break;
case FSE_BZ_RX_DSC_ERROR_EV: case FSE_BZ_RX_DSC_ERROR_EV:
if (ev_sub_data < EFX_VI_BASE) { if (ev_sub_data < EFX_VI_BASE) {
...@@ -1230,7 +1231,7 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) ...@@ -1230,7 +1231,7 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
"RX DMA Q %d reports descriptor fetch error." "RX DMA Q %d reports descriptor fetch error."
" RX Q %d is disabled.\n", ev_sub_data, " RX Q %d is disabled.\n", ev_sub_data,
ev_sub_data); ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR); efx_siena_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
} }
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
else else
...@@ -1243,7 +1244,7 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) ...@@ -1243,7 +1244,7 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
"TX DMA Q %d reports descriptor fetch error." "TX DMA Q %d reports descriptor fetch error."
" TX Q %d is disabled.\n", ev_sub_data, " TX Q %d is disabled.\n", ev_sub_data,
ev_sub_data); ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR); efx_siena_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
} }
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
else else
...@@ -1312,7 +1313,7 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget) ...@@ -1312,7 +1313,7 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
break; break;
#endif #endif
case FSE_CZ_EV_CODE_MCDI_EV: case FSE_CZ_EV_CODE_MCDI_EV:
efx_mcdi_process_event(channel, &event); efx_siena_mcdi_process_event(channel, &event);
break; break;
case FSE_AZ_EV_CODE_GLOBAL_EV: case FSE_AZ_EV_CODE_GLOBAL_EV:
if (efx->type->handle_global_event && if (efx->type->handle_global_event &&
...@@ -1496,12 +1497,12 @@ irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx) ...@@ -1496,12 +1497,12 @@ irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx)
if (++efx->int_error_count < EFX_MAX_INT_ERRORS) { if (++efx->int_error_count < EFX_MAX_INT_ERRORS) {
netif_err(efx, hw, efx->net_dev, netif_err(efx, hw, efx->net_dev,
"SYSTEM ERROR - reset scheduled\n"); "SYSTEM ERROR - reset scheduled\n");
efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); efx_siena_schedule_reset(efx, RESET_TYPE_INT_ERROR);
} else { } else {
netif_err(efx, hw, efx->net_dev, netif_err(efx, hw, efx->net_dev,
"SYSTEM ERROR - max number of errors seen." "SYSTEM ERROR - max number of errors seen."
"NIC will be disabled\n"); "NIC will be disabled\n");
efx_schedule_reset(efx, RESET_TYPE_DISABLE); efx_siena_schedule_reset(efx, RESET_TYPE_DISABLE);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -1529,7 +1530,7 @@ irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id) ...@@ -1529,7 +1530,7 @@ irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id)
* code. Disable them earlier. * code. Disable them earlier.
* If an EEH error occurred, the read will have returned all ones. * If an EEH error occurred, the read will have returned all ones.
*/ */
if (EFX_DWORD_IS_ALL_ONES(reg) && efx_try_recovery(efx) && if (EFX_DWORD_IS_ALL_ONES(reg) && efx_siena_try_recovery(efx) &&
!efx->eeh_disabled_legacy_irq) { !efx->eeh_disabled_legacy_irq) {
disable_irq_nosync(efx->legacy_irq); disable_irq_nosync(efx->legacy_irq);
efx->eeh_disabled_legacy_irq = true; efx->eeh_disabled_legacy_irq = true;
...@@ -2924,13 +2925,14 @@ bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id, ...@@ -2924,13 +2925,14 @@ bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
*/ */
arfs_id = 0; arfs_id = 0;
} else { } else {
rule = efx_rps_hash_find(efx, &spec); rule = efx_siena_rps_hash_find(efx, &spec);
if (!rule) { if (!rule) {
/* ARFS table doesn't know of this filter, remove it */ /* ARFS table doesn't know of this filter, remove it */
force = true; force = true;
} else { } else {
arfs_id = rule->arfs_id; arfs_id = rule->arfs_id;
if (!efx_rps_check_rule(rule, index, &force)) if (!efx_siena_rps_check_rule(rule, index,
&force))
goto out_unlock; goto out_unlock;
} }
} }
...@@ -2938,7 +2940,7 @@ bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id, ...@@ -2938,7 +2940,7 @@ bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
flow_id, arfs_id)) { flow_id, arfs_id)) {
if (rule) if (rule)
rule->filter_id = EFX_ARFS_FILTER_ID_REMOVING; rule->filter_id = EFX_ARFS_FILTER_ID_REMOVING;
efx_rps_hash_del(efx, &spec); efx_siena_rps_hash_del(efx, &spec);
efx_farch_filter_table_clear_entry(efx, table, index); efx_farch_filter_table_clear_entry(efx, table, index);
ret = true; ret = true;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2009-2013 Solarflare Communications Inc.
*/
/*
* Driver for PHY related operations via MCDI.
*/
#include <linux/slab.h>
#include "efx.h"
#include "mcdi_port.h"
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "nic.h"
#include "selftest.h"
#include "mcdi_port_common.h"
static int efx_mcdi_mdio_read(struct net_device *net_dev,
int prtad, int devad, u16 addr)
{
struct efx_nic *efx = netdev_priv(net_dev);
MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_READ_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_READ_OUT_LEN);
size_t outlen;
int rc;
MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, efx->mdio_bus);
MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad);
MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad);
MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr);
rc = efx_siena_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
return rc;
if (MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS) !=
MC_CMD_MDIO_STATUS_GOOD)
return -EIO;
return (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE);
}
static int efx_mcdi_mdio_write(struct net_device *net_dev,
int prtad, int devad, u16 addr, u16 value)
{
struct efx_nic *efx = netdev_priv(net_dev);
MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_WRITE_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_WRITE_OUT_LEN);
size_t outlen;
int rc;
MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, efx->mdio_bus);
MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad);
MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad);
MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr);
MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value);
rc = efx_siena_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
return rc;
if (MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS) !=
MC_CMD_MDIO_STATUS_GOOD)
return -EIO;
return 0;
}
bool efx_siena_mcdi_mac_check_fault(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
size_t outlength;
int rc;
BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
outbuf, sizeof(outbuf), &outlength);
if (rc)
return true;
return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0;
}
int efx_siena_mcdi_port_probe(struct efx_nic *efx)
{
int rc;
/* Set up MDIO structure for PHY */
efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
efx->mdio.mdio_read = efx_mcdi_mdio_read;
efx->mdio.mdio_write = efx_mcdi_mdio_write;
/* Fill out MDIO structure, loopback modes, and initial link state */
rc = efx_siena_mcdi_phy_probe(efx);
if (rc != 0)
return rc;
return efx_siena_mcdi_mac_init_stats(efx);
}
void efx_siena_mcdi_port_remove(struct efx_nic *efx)
{
efx_siena_mcdi_phy_remove(efx);
efx_siena_mcdi_mac_fini_stats(efx);
}
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2008-2013 Solarflare Communications Inc.
* Copyright 2019-2020 Xilinx Inc.
*/
#ifndef EFX_MCDI_PORT_H
#define EFX_MCDI_PORT_H
#include "net_driver.h"
bool efx_siena_mcdi_mac_check_fault(struct efx_nic *efx);
int efx_siena_mcdi_port_probe(struct efx_nic *efx);
void efx_siena_mcdi_port_remove(struct efx_nic *efx);
#endif /* EFX_MCDI_PORT_H */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2018 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.
*/
#ifndef EFX_MCDI_PORT_COMMON_H
#define EFX_MCDI_PORT_COMMON_H
#include "net_driver.h"
#include "mcdi.h"
#include "mcdi_pcol.h"
struct efx_mcdi_phy_data {
u32 flags;
u32 type;
u32 supported_cap;
u32 channel;
u32 port;
u32 stats_mask;
u8 name[20];
u32 media;
u32 mmd_mask;
u8 revision[20];
u32 forced_cap;
};
void efx_siena_link_set_advertising(struct efx_nic *efx,
const unsigned long *advertising);
bool efx_siena_mcdi_phy_poll(struct efx_nic *efx);
int efx_siena_mcdi_phy_probe(struct efx_nic *efx);
void efx_siena_mcdi_phy_remove(struct efx_nic *efx);
void efx_siena_mcdi_phy_get_link_ksettings(struct efx_nic *efx,
struct ethtool_link_ksettings *cmd);
int efx_siena_mcdi_phy_set_link_ksettings(struct efx_nic *efx,
const struct ethtool_link_ksettings *cmd);
int efx_siena_mcdi_phy_get_fecparam(struct efx_nic *efx,
struct ethtool_fecparam *fec);
int efx_siena_mcdi_phy_set_fecparam(struct efx_nic *efx,
const struct ethtool_fecparam *fec);
int efx_siena_mcdi_phy_test_alive(struct efx_nic *efx);
int efx_siena_mcdi_port_reconfigure(struct efx_nic *efx);
int efx_siena_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
unsigned int flags);
const char *efx_siena_mcdi_phy_test_name(struct efx_nic *efx,
unsigned int index);
int efx_siena_mcdi_phy_get_module_eeprom(struct efx_nic *efx,
struct ethtool_eeprom *ee, u8 *data);
int efx_siena_mcdi_phy_get_module_info(struct efx_nic *efx,
struct ethtool_modinfo *modinfo);
int efx_siena_mcdi_set_mac(struct efx_nic *efx);
int efx_siena_mcdi_mac_init_stats(struct efx_nic *efx);
void efx_siena_mcdi_mac_fini_stats(struct efx_nic *efx);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications Inc.
* Copyright 2019-2020 Xilinx Inc.
*/
#ifndef EFX_PTP_H
#define EFX_PTP_H
#include <linux/net_tstamp.h>
#include "net_driver.h"
struct ethtool_ts_info;
void efx_siena_ptp_defer_probe_with_channel(struct efx_nic *efx);
struct efx_channel *efx_siena_ptp_channel(struct efx_nic *efx);
int efx_siena_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
int efx_siena_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);
void efx_siena_ptp_get_ts_info(struct efx_nic *efx,
struct ethtool_ts_info *ts_info);
bool efx_siena_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
int efx_siena_ptp_get_mode(struct efx_nic *efx);
int efx_siena_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
unsigned int new_mode);
int efx_siena_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
void efx_siena_ptp_event(struct efx_nic *efx, efx_qword_t *ev);
size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 *strings);
size_t efx_siena_ptp_update_stats(struct efx_nic *efx, u64 *stats);
void efx_siena_time_sync_event(struct efx_channel *channel, efx_qword_t *ev);
void __efx_siena_rx_skb_attach_timestamp(struct efx_channel *channel,
struct sk_buff *skb);
static inline void efx_rx_skb_attach_timestamp(struct efx_channel *channel,
struct sk_buff *skb)
{
if (channel->sync_events_state == SYNC_EVENTS_VALID)
__efx_siena_rx_skb_attach_timestamp(channel, skb);
}
void efx_siena_ptp_start_datapath(struct efx_nic *efx);
void efx_siena_ptp_stop_datapath(struct efx_nic *efx);
bool efx_siena_ptp_use_mac_tx_timestamps(struct efx_nic *efx);
ktime_t efx_siena_ptp_nic_to_kernel_time(struct efx_tx_queue *tx_queue);
#endif /* EFX_PTP_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2012 Solarflare Communications Inc.
*/
#ifndef EFX_SELFTEST_H
#define EFX_SELFTEST_H
#include "net_driver.h"
/*
* Self tests
*/
struct efx_loopback_self_tests {
int tx_sent[EFX_MAX_TXQ_PER_CHANNEL];
int tx_done[EFX_MAX_TXQ_PER_CHANNEL];
int rx_good;
int rx_bad;
};
#define EFX_MAX_PHY_TESTS 20
/* Efx self test results
* For fields which are not counters, 1 indicates success and -1
* indicates failure; 0 indicates test could not be run.
*/
struct efx_self_tests {
/* online tests */
int phy_alive;
int nvram;
int interrupt;
int eventq_dma[EFX_MAX_CHANNELS];
int eventq_int[EFX_MAX_CHANNELS];
/* offline tests */
int memory;
int registers;
int phy_ext[EFX_MAX_PHY_TESTS];
struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
};
void efx_siena_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr,
int pkt_len);
int efx_siena_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
unsigned int flags);
void efx_siena_selftest_async_init(struct efx_nic *efx);
void efx_siena_selftest_async_start(struct efx_nic *efx);
void efx_siena_selftest_async_cancel(struct efx_nic *efx);
#endif /* EFX_SELFTEST_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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