summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/sfc/ef10.c76
-rw-r--r--drivers/net/ethernet/sfc/efx.c14
-rw-r--r--drivers/net/ethernet/sfc/efx_channels.c66
-rw-r--r--drivers/net/ethernet/sfc/efx_channels.h3
-rw-r--r--drivers/net/ethernet/sfc/efx_common.c14
-rw-r--r--drivers/net/ethernet/sfc/efx_common.h2
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c2
-rw-r--r--drivers/net/ethernet/sfc/ethtool_common.c11
-rw-r--r--drivers/net/ethernet/sfc/ethtool_common.h2
-rw-r--r--drivers/net/ethernet/sfc/farch.c6
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c62
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h1
-rw-r--r--drivers/net/ethernet/sfc/mcdi_filters.c58
-rw-r--r--drivers/net/ethernet/sfc/mcdi_filters.h3
-rw-r--r--drivers/net/ethernet/sfc/mcdi_functions.c57
-rw-r--r--drivers/net/ethernet/sfc/mcdi_functions.h1
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h44
-rw-r--r--drivers/net/ethernet/sfc/nic_common.h3
-rw-r--r--drivers/net/ethernet/sfc/selftest.c18
-rw-r--r--drivers/net/ethernet/sfc/siena.c4
-rw-r--r--drivers/net/ethernet/sfc/tx.c50
-rw-r--r--drivers/net/ethernet/sfc/tx_common.c6
22 files changed, 292 insertions, 211 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 5faf2f0e4d62..cb7b634a1150 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -552,8 +552,6 @@ static int efx_ef10_probe(struct efx_nic *efx)
}
nic_data->warm_boot_count = rc;
- efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
-
/* 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
@@ -600,6 +598,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
* However, until we use TX option descriptors we need two TX queues
* per channel.
*/
+ efx->tx_queues_per_channel = 2;
efx->max_vis = efx_ef10_mem_map_size(efx) / efx->vi_stride;
if (!efx->max_vis) {
netif_err(efx, drv, efx->net_dev, "error determining max VIs\n");
@@ -607,7 +606,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
goto fail5;
}
efx->max_channels = min_t(unsigned int, EFX_MAX_CHANNELS,
- efx->max_vis / EFX_TXQ_TYPES);
+ efx->max_vis / efx->tx_queues_per_channel);
efx->max_tx_channels = efx->max_channels;
if (WARN_ON(efx->max_channels == 0)) {
rc = -EIO;
@@ -1120,17 +1119,17 @@ static int efx_ef10_alloc_vis(struct efx_nic *efx,
*/
static int efx_ef10_dimension_resources(struct efx_nic *efx)
{
+ unsigned int min_vis = max_t(unsigned int, efx->tx_queues_per_channel,
+ efx_separate_tx_channels ? 2 : 1);
+ unsigned int channel_vis, pio_write_vi_base, max_vis;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
unsigned int uc_mem_map_size, wc_mem_map_size;
- unsigned int min_vis = max(EFX_TXQ_TYPES,
- efx_separate_tx_channels ? 2 : 1);
- unsigned int channel_vis, pio_write_vi_base, max_vis;
void __iomem *membase;
int rc;
channel_vis = max(efx->n_channels,
((efx->n_tx_channels + efx->n_extra_tx_channels) *
- EFX_TXQ_TYPES) +
+ efx->tx_queues_per_channel) +
efx->n_xdp_channels * efx->xdp_tx_per_channel);
if (efx->max_vis && efx->max_vis < channel_vis) {
netif_dbg(efx, drv, efx->net_dev,
@@ -1219,7 +1218,7 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
*/
efx->max_channels = nic_data->n_allocated_vis;
efx->max_tx_channels =
- nic_data->n_allocated_vis / EFX_TXQ_TYPES;
+ nic_data->n_allocated_vis / efx->tx_queues_per_channel;
efx_mcdi_free_vis(efx);
return -EAGAIN;
@@ -2243,7 +2242,7 @@ static u32 efx_ef10_tso_versions(struct efx_nic *efx)
static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
{
- bool csum_offload = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
+ bool csum_offload = tx_queue->label & EFX_TXQ_TYPE_OFFLOAD;
struct efx_channel *channel = tx_queue->channel;
struct efx_nic *efx = tx_queue->efx;
struct efx_ef10_nic_data *nic_data;
@@ -3116,44 +3115,6 @@ fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
}
-static int efx_ef10_fini_dmaq(struct efx_nic *efx)
-{
- struct efx_tx_queue *tx_queue;
- struct efx_rx_queue *rx_queue;
- struct efx_channel *channel;
- int pending;
-
- /* If the MC has just rebooted, the TX/RX queues will have already been
- * torn down, but efx->active_queues needs to be set to zero.
- */
- if (efx->must_realloc_vis) {
- atomic_set(&efx->active_queues, 0);
- return 0;
- }
-
- /* Do not attempt to write to the NIC during EEH recovery */
- if (efx->state != STATE_RECOVERY) {
- efx_for_each_channel(channel, efx) {
- efx_for_each_channel_rx_queue(rx_queue, channel)
- efx_mcdi_rx_fini(rx_queue);
- efx_for_each_channel_tx_queue(tx_queue, channel)
- efx_mcdi_tx_fini(tx_queue);
- }
-
- wait_event_timeout(efx->flush_wq,
- atomic_read(&efx->active_queues) == 0,
- msecs_to_jiffies(EFX_MAX_FLUSH_TIME));
- pending = atomic_read(&efx->active_queues);
- if (pending) {
- netif_err(efx, hw, efx->net_dev, "failed to flush %d queues\n",
- pending);
- return -ETIMEDOUT;
- }
- }
-
- return 0;
-}
-
static void efx_ef10_prepare_flr(struct efx_nic *efx)
{
atomic_set(&efx->active_queues, 0);
@@ -3306,18 +3267,15 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
return rc;
}
-static int efx_ef10_mac_reconfigure(struct efx_nic *efx)
+static int efx_ef10_mac_reconfigure(struct efx_nic *efx, bool mtu_only)
{
- efx_mcdi_filter_sync_rx_mode(efx);
+ WARN_ON(!mutex_is_locked(&efx->mac_lock));
- return efx_mcdi_set_mac(efx);
-}
-
-static int efx_ef10_mac_reconfigure_vf(struct efx_nic *efx)
-{
efx_mcdi_filter_sync_rx_mode(efx);
- return 0;
+ if (mtu_only && efx_has_cap(efx, SET_MAC_ENHANCED))
+ return efx_mcdi_set_mtu(efx);
+ return efx_mcdi_set_mac(efx);
}
static int efx_ef10_start_bist(struct efx_nic *efx, u32 bist_type)
@@ -4028,7 +3986,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.reset = efx_ef10_reset,
.probe_port = efx_mcdi_port_probe,
.remove_port = efx_mcdi_port_remove,
- .fini_dmaq = efx_ef10_fini_dmaq,
+ .fini_dmaq = efx_fini_dmaq,
.prepare_flr = efx_ef10_prepare_flr,
.finish_flr = efx_port_dummy_op_void,
.describe_stats = efx_ef10_describe_stats,
@@ -4038,7 +3996,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.stop_stats = efx_port_dummy_op_void,
.set_id_led = efx_mcdi_set_id_led,
.push_irq_moderation = efx_ef10_push_irq_moderation,
- .reconfigure_mac = efx_ef10_mac_reconfigure_vf,
+ .reconfigure_mac = efx_ef10_mac_reconfigure,
.check_mac_fault = efx_mcdi_mac_check_fault,
.reconfigure_port = efx_mcdi_port_reconfigure,
.get_wol = efx_ef10_get_wol_vf,
@@ -4111,7 +4069,6 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.can_rx_scatter = true,
.always_rx_scatter = true,
.min_interrupt_mode = EFX_INT_MODE_MSIX,
- .max_interrupt_mode = EFX_INT_MODE_MSIX,
.timer_period_max = 1 << ERF_DD_EVQ_IND_TIMER_VAL_WIDTH,
.offload_features = EF10_OFFLOAD_FEATURES,
.mcdi_max_ver = 2,
@@ -4137,7 +4094,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.reset = efx_ef10_reset,
.probe_port = efx_mcdi_port_probe,
.remove_port = efx_mcdi_port_remove,
- .fini_dmaq = efx_ef10_fini_dmaq,
+ .fini_dmaq = efx_fini_dmaq,
.prepare_flr = efx_ef10_prepare_flr,
.finish_flr = efx_port_dummy_op_void,
.describe_stats = efx_ef10_describe_stats,
@@ -4248,7 +4205,6 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.always_rx_scatter = true,
.option_descriptors = true,
.min_interrupt_mode = EFX_INT_MODE_LEGACY,
- .max_interrupt_mode = EFX_INT_MODE_MSIX,
.timer_period_max = 1 << ERF_DD_EVQ_IND_TIMER_VAL_WIDTH,
.offload_features = EF10_OFFLOAD_FEATURES,
.mcdi_max_ver = 2,
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 028d826ab147..befd253af918 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -64,6 +64,13 @@ void efx_get_udp_tunnel_type_name(u16 type, char *buf, size_t buflen)
*
*************************************************************************/
+module_param_named(interrupt_mode, efx_interrupt_mode, uint, 0444);
+MODULE_PARM_DESC(interrupt_mode,
+ "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
+
+module_param(rss_cpus, uint, 0444);
+MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
+
/*
* Use separate channels for TX and RX events
*
@@ -169,10 +176,6 @@ static int efx_init_port(struct efx_nic *efx)
efx->port_initialized = true;
- /* Reconfigure the MAC before creating dma queues (required for
- * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */
- efx_mac_reconfigure(efx);
-
/* Ensure the PHY advertises the correct flow control settings */
rc = efx->phy_op->reconfigure(efx);
if (rc && rc != -EPERM)
@@ -333,9 +336,6 @@ static int efx_probe_nic(struct efx_nic *efx)
sizeof(efx->rss_context.rx_hash_key));
efx_set_default_rx_indir_table(efx, &efx->rss_context);
- netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
- netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
-
/* Initialise the interrupt moderation settings */
efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000);
efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true,
diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c
index 2f9db219513a..dd4f30ea48a8 100644
--- a/drivers/net/ethernet/sfc/efx_channels.c
+++ b/drivers/net/ethernet/sfc/efx_channels.c
@@ -23,10 +23,7 @@
* 1 => MSI
* 2 => legacy
*/
-static unsigned int interrupt_mode;
-module_param(interrupt_mode, uint, 0444);
-MODULE_PARM_DESC(interrupt_mode,
- "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
+unsigned int efx_interrupt_mode = EFX_INT_MODE_MSIX;
/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
* i.e. the number of CPUs among which we may distribute simultaneous
@@ -35,9 +32,7 @@ MODULE_PARM_DESC(interrupt_mode,
* Cards without MSI-X will only target one CPU via legacy or MSI interrupt.
* The default (0) means to assign an interrupt to each core.
*/
-static unsigned int rss_cpus;
-module_param(rss_cpus, uint, 0444);
-MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
+unsigned int rss_cpus;
static unsigned int irq_adapt_low_thresh = 8000;
module_param(irq_adapt_low_thresh, uint, 0644);
@@ -529,7 +524,8 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
for (j = 0; j < EFX_TXQ_TYPES; j++) {
tx_queue = &channel->tx_queue[j];
tx_queue->efx = efx;
- tx_queue->queue = i * EFX_TXQ_TYPES + j;
+ tx_queue->queue = -1;
+ tx_queue->label = j;
tx_queue->channel = channel;
}
@@ -557,14 +553,8 @@ int efx_init_channels(struct efx_nic *efx)
}
/* Higher numbered interrupt modes are less capable! */
- if (WARN_ON_ONCE(efx->type->max_interrupt_mode >
- efx->type->min_interrupt_mode)) {
- return -EIO;
- }
- efx->interrupt_mode = max(efx->type->max_interrupt_mode,
- interrupt_mode);
efx->interrupt_mode = min(efx->type->min_interrupt_mode,
- interrupt_mode);
+ efx_interrupt_mode);
efx->max_channels = EFX_MAX_CHANNELS;
efx->max_tx_channels = EFX_MAX_CHANNELS;
@@ -737,7 +727,7 @@ void efx_remove_channel(struct efx_channel *channel)
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_remove_rx_queue(rx_queue);
- efx_for_each_possible_channel_tx_queue(tx_queue, channel)
+ efx_for_each_channel_tx_queue(tx_queue, channel)
efx_remove_tx_queue(tx_queue);
efx_remove_eventq(channel);
channel->type->post_remove(channel);
@@ -864,9 +854,11 @@ rollback:
int efx_set_channels(struct efx_nic *efx)
{
- struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
+ struct efx_channel *channel;
+ unsigned int next_queue = 0;
int xdp_queue_number;
+ int rc;
efx->tx_channel_offset =
efx_separate_tx_channels ?
@@ -894,18 +886,38 @@ int efx_set_channels(struct efx_nic *efx)
else
channel->rx_queue.core_index = -1;
- efx_for_each_channel_tx_queue(tx_queue, channel) {
- tx_queue->queue -= (efx->tx_channel_offset *
- EFX_TXQ_TYPES);
-
- if (efx_channel_is_xdp_tx(channel) &&
- xdp_queue_number < efx->xdp_tx_queue_count) {
- efx->xdp_tx_queues[xdp_queue_number] = tx_queue;
- xdp_queue_number++;
+ if (channel->channel >= efx->tx_channel_offset) {
+ if (efx_channel_is_xdp_tx(channel)) {
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ tx_queue->queue = next_queue++;
+ netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n",
+ channel->channel, tx_queue->label,
+ xdp_queue_number, tx_queue->queue);
+ /* We may have a few left-over XDP TX
+ * queues owing to xdp_tx_queue_count
+ * not dividing evenly by EFX_TXQ_TYPES.
+ * We still allocate and probe those
+ * TXQs, but never use them.
+ */
+ if (xdp_queue_number < efx->xdp_tx_queue_count)
+ efx->xdp_tx_queues[xdp_queue_number] = tx_queue;
+ xdp_queue_number++;
+ }
+ } else {
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ tx_queue->queue = next_queue++;
+ netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is HW %u\n",
+ channel->channel, tx_queue->label,
+ tx_queue->queue);
+ }
}
}
}
- return 0;
+
+ rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
+ if (rc)
+ return rc;
+ return netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
}
bool efx_default_channel_want_txqs(struct efx_channel *channel)
@@ -1101,7 +1113,7 @@ void efx_stop_channels(struct efx_nic *efx)
efx_for_each_channel(channel, efx) {
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_fini_rx_queue(rx_queue);
- efx_for_each_possible_channel_tx_queue(tx_queue, channel)
+ efx_for_each_channel_tx_queue(tx_queue, channel)
efx_fini_tx_queue(tx_queue);
}
}
diff --git a/drivers/net/ethernet/sfc/efx_channels.h b/drivers/net/ethernet/sfc/efx_channels.h
index 8d7b8c4142d7..2d71dc9a33dd 100644
--- a/drivers/net/ethernet/sfc/efx_channels.h
+++ b/drivers/net/ethernet/sfc/efx_channels.h
@@ -11,6 +11,9 @@
#ifndef EFX_CHANNELS_H
#define EFX_CHANNELS_H
+extern unsigned int efx_interrupt_mode;
+extern unsigned int rss_cpus;
+
int efx_probe_interrupts(struct efx_nic *efx);
void efx_remove_interrupts(struct efx_nic *efx);
int efx_soft_enable_interrupts(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c
index a2f744377aaa..5667694c6514 100644
--- a/drivers/net/ethernet/sfc/efx_common.c
+++ b/drivers/net/ethernet/sfc/efx_common.c
@@ -139,11 +139,11 @@ void efx_destroy_reset_workqueue(void)
/* We assume that efx->type->reconfigure_mac will always try to sync RX
* filters and therefore needs to read-lock the filter table against freeing
*/
-void efx_mac_reconfigure(struct efx_nic *efx)
+void efx_mac_reconfigure(struct efx_nic *efx, bool mtu_only)
{
if (efx->type->reconfigure_mac) {
down_read(&efx->filter_sem);
- efx->type->reconfigure_mac(efx);
+ efx->type->reconfigure_mac(efx, mtu_only);
up_read(&efx->filter_sem);
}
}
@@ -158,7 +158,7 @@ static void efx_mac_work(struct work_struct *data)
mutex_lock(&efx->mac_lock);
if (efx->port_enabled)
- efx_mac_reconfigure(efx);
+ efx_mac_reconfigure(efx, false);
mutex_unlock(&efx->mac_lock);
}
@@ -190,7 +190,7 @@ int efx_set_mac_address(struct net_device *net_dev, void *data)
/* Reconfigure the MAC */
mutex_lock(&efx->mac_lock);
- efx_mac_reconfigure(efx);
+ efx_mac_reconfigure(efx, false);
mutex_unlock(&efx->mac_lock);
return 0;
@@ -304,7 +304,7 @@ int efx_change_mtu(struct net_device *net_dev, int new_mtu)
mutex_lock(&efx->mac_lock);
net_dev->mtu = new_mtu;
- efx_mac_reconfigure(efx);
+ efx_mac_reconfigure(efx, true);
mutex_unlock(&efx->mac_lock);
efx_start_all(efx);
@@ -486,7 +486,7 @@ static void efx_start_port(struct efx_nic *efx)
efx->port_enabled = true;
/* Ensure MAC ingress/egress is enabled */
- efx_mac_reconfigure(efx);
+ efx_mac_reconfigure(efx, false);
mutex_unlock(&efx->mac_lock);
}
@@ -1017,6 +1017,7 @@ int efx_init_struct(struct efx_nic *efx,
efx->rx_packet_ts_offset =
efx->type->rx_ts_offset - efx->type->rx_prefix_size;
INIT_LIST_HEAD(&efx->rss_context.list);
+ efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
mutex_init(&efx->rss_lock);
efx->vport_id = EVB_PORT_ID_ASSIGNED;
spin_lock_init(&efx->stats_lock);
@@ -1036,6 +1037,7 @@ int efx_init_struct(struct efx_nic *efx,
INIT_WORK(&efx->mac_work, efx_mac_work);
init_waitqueue_head(&efx->flush_wq);
+ efx->tx_queues_per_channel = 1;
efx->rxq_entries = EFX_DEFAULT_DMAQ_SIZE;
efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
diff --git a/drivers/net/ethernet/sfc/efx_common.h b/drivers/net/ethernet/sfc/efx_common.h
index 73c355fc2590..4056f68f04e5 100644
--- a/drivers/net/ethernet/sfc/efx_common.h
+++ b/drivers/net/ethernet/sfc/efx_common.h
@@ -95,7 +95,7 @@ static inline void efx_init_mcdi_logging(struct efx_nic *efx) {}
static inline void efx_fini_mcdi_logging(struct efx_nic *efx) {}
#endif
-void efx_mac_reconfigure(struct efx_nic *efx);
+void efx_mac_reconfigure(struct efx_nic *efx, bool mtu_only);
int efx_set_mac_address(struct net_device *net_dev, void *data);
void efx_set_rx_mode(struct net_device *net_dev);
int efx_set_features(struct net_device *net_dev, netdev_features_t data);
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 48a96ed6b7d0..9828516bd82d 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -221,6 +221,8 @@ static int efx_ethtool_get_ts_info(struct net_device *net_dev,
return 0;
}
+const char *efx_driver_name = KBUILD_MODNAME;
+
const struct ethtool_ops efx_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USECS_IRQ |
diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c
index c96595e50234..e9a5a66529bf 100644
--- a/drivers/net/ethernet/sfc/ethtool_common.c
+++ b/drivers/net/ethernet/sfc/ethtool_common.c
@@ -104,7 +104,7 @@ void efx_ethtool_get_drvinfo(struct net_device *net_dev,
{
struct efx_nic *efx = netdev_priv(net_dev);
- strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->driver, efx_driver_name, sizeof(info->driver));
strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
efx_mcdi_print_fwver(efx, info->fw_version,
sizeof(info->fw_version));
@@ -241,7 +241,7 @@ int efx_ethtool_set_pauseparam(struct net_device *net_dev,
/* Reconfigure the MAC. The PHY *may* generate a link state change event
* if the user just changed the advertised capabilities, but there's no
* harm doing this twice */
- efx_mac_reconfigure(efx);
+ efx_mac_reconfigure(efx, false);
out:
mutex_unlock(&efx->mac_lock);
@@ -287,8 +287,7 @@ static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data,
}
#define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel
-#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue
-#define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue
+#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->label
#define EFX_LOOPBACK_NAME(_mode, _counter) \
"loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode)
@@ -316,11 +315,11 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
efx_for_each_channel_tx_queue(tx_queue, channel) {
efx_fill_test(test_index++, strings, data,
- &lb_tests->tx_sent[tx_queue->queue],
+ &lb_tests->tx_sent[tx_queue->label],
EFX_TX_QUEUE_NAME(tx_queue),
EFX_LOOPBACK_NAME(mode, "tx_sent"));
efx_fill_test(test_index++, strings, data,
- &lb_tests->tx_done[tx_queue->queue],
+ &lb_tests->tx_done[tx_queue->label],
EFX_TX_QUEUE_NAME(tx_queue),
EFX_LOOPBACK_NAME(mode, "tx_done"));
}
diff --git a/drivers/net/ethernet/sfc/ethtool_common.h b/drivers/net/ethernet/sfc/ethtool_common.h
index 7bfbbd08a1ef..3f3aaa92fbb5 100644
--- a/drivers/net/ethernet/sfc/ethtool_common.h
+++ b/drivers/net/ethernet/sfc/ethtool_common.h
@@ -11,6 +11,8 @@
#ifndef 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,
struct ethtool_drvinfo *info);
u32 efx_ethtool_get_msglevel(struct net_device *net_dev);
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index dbbb898adddb..d07eeaad9bdf 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -379,7 +379,7 @@ int efx_farch_tx_probe(struct efx_tx_queue *tx_queue)
void efx_farch_tx_init(struct efx_tx_queue *tx_queue)
{
- int csum = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
+ int csum = tx_queue->label & EFX_TXQ_TYPE_OFFLOAD;
struct efx_nic *efx = tx_queue->efx;
efx_oword_t reg;
@@ -395,7 +395,7 @@ void efx_farch_tx_init(struct efx_tx_queue *tx_queue)
FRF_AZ_TX_DESCQ_EVQ_ID,
tx_queue->channel->channel,
FRF_AZ_TX_DESCQ_OWNER_ID, 0,
- FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue,
+ FRF_AZ_TX_DESCQ_LABEL, tx_queue->label,
FRF_AZ_TX_DESCQ_SIZE,
__ffs(tx_queue->txd.entries),
FRF_AZ_TX_DESCQ_TYPE, 0,
@@ -409,7 +409,7 @@ void efx_farch_tx_init(struct efx_tx_queue *tx_queue)
EFX_POPULATE_OWORD_1(reg,
FRF_BZ_TX_PACE,
- (tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ?
+ (tx_queue->label & EFX_TXQ_TYPE_HIGHPRI) ?
FFE_BZ_TX_PACE_OFF :
FFE_BZ_TX_PACE_RESERVED);
efx_writeo_table(efx, &reg, FR_BZ_TX_PACE_TBL, tx_queue->queue);
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 244fb621d17b..6c49740a178e 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -1621,6 +1621,35 @@ fail:
return rc;
}
+/* This function finds types using the new NVRAM_PARTITIONS mcdi. */
+static int efx_new_mcdi_nvram_types(struct efx_nic *efx, u32 *number,
+ u32 *nvram_types)
+{
+ efx_dword_t *outbuf = kzalloc(MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2,
+ GFP_KERNEL);
+ size_t outlen;
+ int rc;
+
+ if (!outbuf)
+ return -ENOMEM;
+
+ BUILD_BUG_ON(MC_CMD_NVRAM_PARTITIONS_IN_LEN != 0);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_PARTITIONS, NULL, 0,
+ outbuf, MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2, &outlen);
+ if (rc)
+ goto fail;
+
+ *number = MCDI_DWORD(outbuf, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
+
+ memcpy(nvram_types, MCDI_PTR(outbuf, NVRAM_PARTITIONS_OUT_TYPE_ID),
+ *number * sizeof(u32));
+
+fail:
+ kfree(outbuf);
+ return rc;
+}
+
int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
size_t *size_out, size_t *erase_size_out,
bool *protected_out)
@@ -1674,6 +1703,39 @@ static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
}
}
+/* This function tests nvram partitions using the new mcdi partition lookup scheme */
+int efx_new_mcdi_nvram_test_all(struct efx_nic *efx)
+{
+ u32 *nvram_types = kzalloc(MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2,
+ GFP_KERNEL);
+ unsigned int number;
+ int rc, i;
+
+ if (!nvram_types)
+ return -ENOMEM;
+
+ rc = efx_new_mcdi_nvram_types(efx, &number, nvram_types);
+ if (rc)
+ goto fail;
+
+ /* Require at least one check */
+ rc = -EAGAIN;
+
+ for (i = 0; i < number; i++) {
+ if (nvram_types[i] == NVRAM_PARTITION_TYPE_PARTITION_MAP ||
+ nvram_types[i] == NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG)
+ continue;
+
+ rc = efx_mcdi_nvram_test(efx, nvram_types[i]);
+ if (rc)
+ goto fail;
+ }
+
+fail:
+ kfree(nvram_types);
+ return rc;
+}
+
int efx_mcdi_nvram_test_all(struct efx_nic *efx)
{
u32 nvram_types;
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 10f064f761a5..e053adfe82b0 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -345,6 +345,7 @@ int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out);
int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
size_t *size_out, size_t *erase_size_out,
bool *protected_out);
+int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
int efx_mcdi_nvram_test_all(struct efx_nic *efx);
int efx_mcdi_handle_assertion(struct efx_nic *efx);
void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
diff --git a/drivers/net/ethernet/sfc/mcdi_filters.c b/drivers/net/ethernet/sfc/mcdi_filters.c
index 74ee06fe0996..5a74d880b733 100644
--- a/drivers/net/ethernet/sfc/mcdi_filters.c
+++ b/drivers/net/ethernet/sfc/mcdi_filters.c
@@ -1459,7 +1459,7 @@ not_restored:
table->must_restore_filters = false;
}
-void efx_mcdi_filter_table_remove(struct efx_nic *efx)
+void efx_mcdi_filter_table_down(struct efx_nic *efx)
{
struct efx_mcdi_filter_table *table = efx->filter_state;
MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
@@ -1467,21 +1467,11 @@ void efx_mcdi_filter_table_remove(struct efx_nic *efx)
unsigned int filter_idx;
int rc;
- efx_mcdi_filter_cleanup_vlans(efx);
- efx->filter_state = NULL;
- /*
- * If we were called without locking, then it's not safe to free
- * the table as others might be using it. So we just WARN, leak
- * the memory, and potentially get an inconsistent filter table
- * state.
- * This should never actually happen.
- */
- if (!efx_rwsem_assert_write_locked(&efx->filter_sem))
- return;
-
if (!table)
return;
+ efx_mcdi_filter_cleanup_vlans(efx);
+
for (filter_idx = 0; filter_idx < EFX_MCDI_FILTER_TBL_ROWS; filter_idx++) {
spec = efx_mcdi_filter_entry_spec(table, filter_idx);
if (!spec)
@@ -1501,6 +1491,27 @@ void efx_mcdi_filter_table_remove(struct efx_nic *efx)
__func__, filter_idx);
kfree(spec);
}
+}
+
+void efx_mcdi_filter_table_remove(struct efx_nic *efx)
+{
+ struct efx_mcdi_filter_table *table = efx->filter_state;
+
+ efx_mcdi_filter_table_down(efx);
+
+ efx->filter_state = NULL;
+ /*
+ * If we were called without locking, then it's not safe to free
+ * the table as others might be using it. So we just WARN, leak
+ * the memory, and potentially get an inconsistent filter table
+ * state.
+ * This should never actually happen.
+ */
+ if (!efx_rwsem_assert_write_locked(&efx->filter_sem))
+ return;
+
+ if (!table)
+ return;
vfree(table->entry);
kfree(table);
@@ -2265,3 +2276,24 @@ int efx_mcdi_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
return 0;
return efx_mcdi_filter_rx_push_shared_rss_config(efx, NULL);
}
+
+int efx_mcdi_push_default_indir_table(struct efx_nic *efx,
+ unsigned int rss_spread)
+{
+ int rc = 0;
+
+ if (efx->rss_spread == rss_spread)
+ return 0;
+
+ efx->rss_spread = rss_spread;
+ if (!efx->filter_state)
+ return 0;
+
+ efx_mcdi_rx_free_indir_table(efx);
+ if (rss_spread > 1) {
+ efx_set_default_rx_indir_table(efx, &efx->rss_context);
+ rc = efx->type->rx_push_rss_config(efx, false,
+ efx->rss_context.rx_indir_table, NULL);
+ }
+ return rc;
+}
diff --git a/drivers/net/ethernet/sfc/mcdi_filters.h b/drivers/net/ethernet/sfc/mcdi_filters.h
index 03a8bf74c733..06426aa9f2f3 100644
--- a/drivers/net/ethernet/sfc/mcdi_filters.h
+++ b/drivers/net/ethernet/sfc/mcdi_filters.h
@@ -93,6 +93,7 @@ struct efx_mcdi_filter_table {
};
int efx_mcdi_filter_table_probe(struct efx_nic *efx, bool multicast_chaining);
+void efx_mcdi_filter_table_down(struct efx_nic *efx);
void efx_mcdi_filter_table_remove(struct efx_nic *efx);
void efx_mcdi_filter_table_restore(struct efx_nic *efx);
@@ -154,6 +155,8 @@ int efx_mcdi_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
__attribute__ ((unused)),
const u8 *key
__attribute__ ((unused)));
+int efx_mcdi_push_default_indir_table(struct efx_nic *efx,
+ unsigned int rss_spread);
int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx);
int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
struct efx_rss_context *ctx);
diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c
index 962d8395d958..d8a3af86ef78 100644
--- a/drivers/net/ethernet/sfc/mcdi_functions.c
+++ b/drivers/net/ethernet/sfc/mcdi_functions.c
@@ -164,7 +164,7 @@ int efx_mcdi_tx_init(struct efx_tx_queue *tx_queue, bool tso_v2)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_INIT_TXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
EFX_BUF_SIZE));
- bool csum_offload = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
+ bool csum_offload = tx_queue->label & EFX_TXQ_TYPE_OFFLOAD;
size_t entries = tx_queue->txd.buf.len / EFX_BUF_SIZE;
struct efx_channel *channel = tx_queue->channel;
struct efx_nic *efx = tx_queue->efx;
@@ -176,7 +176,7 @@ int efx_mcdi_tx_init(struct efx_tx_queue *tx_queue, bool tso_v2)
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_SIZE, tx_queue->ptr_mask + 1);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_TARGET_EVQ, channel->channel);
- MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_LABEL, tx_queue->queue);
+ MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_LABEL, tx_queue->label);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_INSTANCE, tx_queue->queue);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_OWNER_ID, 0);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_PORT_ID, efx->vport_id);
@@ -267,20 +267,22 @@ int efx_mcdi_rx_probe(struct efx_rx_queue *rx_queue)
void efx_mcdi_rx_init(struct efx_rx_queue *rx_queue)
{
- MCDI_DECLARE_BUF(inbuf,
- MC_CMD_INIT_RXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
- EFX_BUF_SIZE));
struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
size_t entries = rx_queue->rxd.buf.len / EFX_BUF_SIZE;
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_INIT_RXQ_V4_IN_LEN);
struct efx_nic *efx = rx_queue->efx;
+ unsigned int buffer_size;
dma_addr_t dma_addr;
- size_t inlen;
int rc;
int i;
BUILD_BUG_ON(MC_CMD_INIT_RXQ_OUT_LEN != 0);
rx_queue->scatter_n = 0;
rx_queue->scatter_len = 0;
+ if (efx->type->revision == EFX_REV_EF100)
+ buffer_size = efx->rx_page_buf_step;
+ else
+ buffer_size = 0;
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_SIZE, rx_queue->ptr_mask + 1);
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_TARGET_EVQ, channel->channel);
@@ -292,6 +294,7 @@ void efx_mcdi_rx_init(struct efx_rx_queue *rx_queue)
INIT_RXQ_IN_FLAG_TIMESTAMP, 1);
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_OWNER_ID, 0);
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, efx->vport_id);
+ MCDI_SET_DWORD(inbuf, INIT_RXQ_V4_IN_BUFFER_SIZE_BYTES, buffer_size);
dma_addr = rx_queue->rxd.buf.dma_addr;
@@ -303,9 +306,7 @@ void efx_mcdi_rx_init(struct efx_rx_queue *rx_queue)
dma_addr += EFX_BUF_SIZE;
}
- inlen = MC_CMD_INIT_RXQ_IN_LEN(entries);
-
- rc = efx_mcdi_rpc(efx, MC_CMD_INIT_RXQ, inbuf, inlen,
+ rc = efx_mcdi_rpc(efx, MC_CMD_INIT_RXQ, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
netdev_WARN(efx->net_dev, "failed to initialise RXQ %d\n",
@@ -341,6 +342,44 @@ fail:
outbuf, outlen, rc);
}
+int efx_fini_dmaq(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
+ int pending;
+
+ /* If the MC has just rebooted, the TX/RX queues will have already been
+ * torn down, but efx->active_queues needs to be set to zero.
+ */
+ if (efx->must_realloc_vis) {
+ atomic_set(&efx->active_queues, 0);
+ return 0;
+ }
+
+ /* Do not attempt to write to the NIC during EEH recovery */
+ if (efx->state != STATE_RECOVERY) {
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_mcdi_rx_fini(rx_queue);
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_mcdi_tx_fini(tx_queue);
+ }
+
+ wait_event_timeout(efx->flush_wq,
+ atomic_read(&efx->active_queues) == 0,
+ msecs_to_jiffies(EFX_MAX_FLUSH_TIME));
+ pending = atomic_read(&efx->active_queues);
+ if (pending) {
+ netif_err(efx, hw, efx->net_dev, "failed to flush %d queues\n",
+ pending);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode)
{
switch (vi_window_mode) {
diff --git a/drivers/net/ethernet/sfc/mcdi_functions.h b/drivers/net/ethernet/sfc/mcdi_functions.h
index ca4a5ac1a66b..687be8b00cd8 100644
--- a/drivers/net/ethernet/sfc/mcdi_functions.h
+++ b/drivers/net/ethernet/sfc/mcdi_functions.h
@@ -26,6 +26,7 @@ int efx_mcdi_rx_probe(struct efx_rx_queue *rx_queue);
void efx_mcdi_rx_init(struct efx_rx_queue *rx_queue);
void efx_mcdi_rx_remove(struct efx_rx_queue *rx_queue);
void efx_mcdi_rx_fini(struct efx_rx_queue *rx_queue);
+int efx_fini_dmaq(struct efx_nic *efx);
int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode);
int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index);
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index e0b84b2e3bd2..0bf11ebb03cf 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -189,6 +189,8 @@ struct efx_tx_buffer {
*
* @efx: The associated Efx NIC
* @queue: DMA queue number
+ * @label: Label for TX completion events.
+ * Is our index within @channel->tx_queue array.
* @tso_version: Version of TSO in use for this queue.
* @channel: The associated channel
* @core_txq: The networking core TX queue structure
@@ -250,7 +252,8 @@ struct efx_tx_buffer {
struct efx_tx_queue {
/* Members which don't change on the fast path */
struct efx_nic *efx ____cacheline_aligned_in_smp;
- unsigned queue;
+ unsigned int queue;
+ unsigned int label;
unsigned int tso_version;
struct efx_channel *channel;
struct netdev_queue *core_txq;
@@ -867,6 +870,7 @@ struct efx_async_filter_insertion {
* @n_rx_channels: Number of channels used for RX (= number of RX queues)
* @n_tx_channels: Number of channels used for TX
* @n_extra_tx_channels: Number of extra channels with TX queues
+ * @tx_queues_per_channel: number of TX queues probed on each channel
* @n_xdp_channels: Number of channels used for XDP TX
* @xdp_channel_offset: Offset of zeroth channel used for XPD TX.
* @xdp_tx_per_channel: Max number of TX queues on an XDP TX channel.
@@ -1031,6 +1035,7 @@ struct efx_nic {
unsigned tx_channel_offset;
unsigned n_tx_channels;
unsigned n_extra_tx_channels;
+ unsigned int tx_queues_per_channel;
unsigned int n_xdp_channels;
unsigned int xdp_channel_offset;
unsigned int xdp_tx_per_channel;
@@ -1317,8 +1322,6 @@ struct efx_udp_tunnel {
* @option_descriptors: NIC supports TX option descriptors
* @min_interrupt_mode: Lowest capability interrupt mode supported
* from &enum efx_int_mode.
- * @max_interrupt_mode: Highest capability interrupt mode supported
- * from &enum efx_int_mode.
* @timer_period_max: Maximum period of interrupt timer (in ticks)
* @offload_features: net_device feature flags for protocol offload
* features implemented in hardware
@@ -1356,7 +1359,7 @@ struct efx_nic_type {
void (*push_irq_moderation)(struct efx_channel *channel);
int (*reconfigure_port)(struct efx_nic *efx);
void (*prepare_enable_fc_tx)(struct efx_nic *efx);
- int (*reconfigure_mac)(struct efx_nic *efx);
+ int (*reconfigure_mac)(struct efx_nic *efx, bool mtu_only);
bool (*check_mac_fault)(struct efx_nic *efx);
void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol);
int (*set_wol)(struct efx_nic *efx, u32 type);
@@ -1492,7 +1495,6 @@ struct efx_nic_type {
bool always_rx_scatter;
bool option_descriptors;
unsigned int min_interrupt_mode;
- unsigned int max_interrupt_mode;
unsigned int timer_period_max;
netdev_features_t offload_features;
int mcdi_max_ver;
@@ -1532,7 +1534,7 @@ static inline struct efx_tx_queue *
efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
{
EFX_WARN_ON_ONCE_PARANOID(index >= efx->n_tx_channels ||
- type >= EFX_TXQ_TYPES);
+ type >= efx->tx_queues_per_channel);
return &efx->channel[efx->tx_channel_offset + index]->tx_queue[type];
}
@@ -1554,18 +1556,18 @@ static inline bool efx_channel_has_tx_queues(struct efx_channel *channel)
return true;
}
-static inline struct efx_tx_queue *
-efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
+static inline unsigned int efx_channel_num_tx_queues(struct efx_channel *channel)
{
- EFX_WARN_ON_ONCE_PARANOID(!efx_channel_has_tx_queues(channel) ||
- type >= EFX_TXQ_TYPES);
- return &channel->tx_queue[type];
+ if (efx_channel_is_xdp_tx(channel))
+ return channel->efx->xdp_tx_per_channel;
+ return channel->efx->tx_queues_per_channel;
}
-static inline bool efx_tx_queue_used(struct efx_tx_queue *tx_queue)
+static inline struct efx_tx_queue *
+efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
{
- return !(tx_queue->efx->net_dev->num_tc < 2 &&
- tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI);
+ EFX_WARN_ON_ONCE_PARANOID(type >= efx_channel_num_tx_queues(channel));
+ return &channel->tx_queue[type];
}
/* Iterate over all TX queues belonging to a channel */
@@ -1574,18 +1576,8 @@ static inline bool efx_tx_queue_used(struct efx_tx_queue *tx_queue)
; \
else \
for (_tx_queue = (_channel)->tx_queue; \
- _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES && \
- (efx_tx_queue_used(_tx_queue) || \
- efx_channel_is_xdp_tx(_channel)); \
- _tx_queue++)
-
-/* Iterate over all possible TX queues belonging to a channel */
-#define efx_for_each_possible_channel_tx_queue(_tx_queue, _channel) \
- if (!efx_channel_has_tx_queues(_channel)) \
- ; \
- else \
- for (_tx_queue = (_channel)->tx_queue; \
- _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \
+ _tx_queue < (_channel)->tx_queue + \
+ efx_channel_num_tx_queues(_channel); \
_tx_queue++)
static inline bool efx_channel_has_rx_queue(struct efx_channel *channel)
diff --git a/drivers/net/ethernet/sfc/nic_common.h b/drivers/net/ethernet/sfc/nic_common.h
index fd474d9e55e4..e04b6817cde3 100644
--- a/drivers/net/ethernet/sfc/nic_common.h
+++ b/drivers/net/ethernet/sfc/nic_common.h
@@ -21,6 +21,7 @@ enum {
*/
EFX_REV_SIENA_A0 = 3,
EFX_REV_HUNT_A0 = 4,
+ EFX_REV_EF100 = 5,
};
static inline int efx_nic_rev(struct efx_nic *efx)
@@ -90,7 +91,7 @@ static inline bool efx_nic_tx_is_empty(struct efx_tx_queue *tx_queue)
/* XXX is this a thing on EF100? */
static inline struct efx_tx_queue *efx_tx_queue_partner(struct efx_tx_queue *tx_queue)
{
- if (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD)
+ if (tx_queue->label & EFX_TXQ_TYPE_OFFLOAD)
return tx_queue - EFX_TXQ_TYPE_OFFLOAD;
else
return tx_queue + EFX_TXQ_TYPE_OFFLOAD;
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index 1ae369022d7d..e71d6d37a317 100644
--- a/drivers/net/ethernet/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
@@ -445,7 +445,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
if (rc != NETDEV_TX_OK) {
netif_err(efx, drv, efx->net_dev,
"TX queue %d could not transmit packet %d of "
- "%d in %s loopback test\n", tx_queue->queue,
+ "%d in %s loopback test\n", tx_queue->label,
i + 1, state->packet_count,
LOOPBACK_MODE(efx));
@@ -497,7 +497,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue,
netif_err(efx, drv, efx->net_dev,
"TX queue %d saw only %d out of an expected %d "
"TX completion events in %s loopback test\n",
- tx_queue->queue, tx_done, state->packet_count,
+ tx_queue->label, tx_done, state->packet_count,
LOOPBACK_MODE(efx));
rc = -ETIMEDOUT;
/* Allow to fall through so we see the RX errors as well */
@@ -508,15 +508,15 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue,
netif_dbg(efx, drv, efx->net_dev,
"TX queue %d saw only %d out of an expected %d "
"received packets in %s loopback test\n",
- tx_queue->queue, rx_good, state->packet_count,
+ tx_queue->label, rx_good, state->packet_count,
LOOPBACK_MODE(efx));
rc = -ETIMEDOUT;
/* Fall through */
}
/* Update loopback test structure */
- lb_tests->tx_sent[tx_queue->queue] += state->packet_count;
- lb_tests->tx_done[tx_queue->queue] += tx_done;
+ lb_tests->tx_sent[tx_queue->label] += state->packet_count;
+ lb_tests->tx_done[tx_queue->label] += tx_done;
lb_tests->rx_good += rx_good;
lb_tests->rx_bad += rx_bad;
@@ -542,8 +542,8 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
state->flush = false;
netif_dbg(efx, drv, efx->net_dev,
- "TX queue %d testing %s loopback with %d packets\n",
- tx_queue->queue, LOOPBACK_MODE(efx),
+ "TX queue %d (hw %d) testing %s loopback with %d packets\n",
+ tx_queue->label, tx_queue->queue, LOOPBACK_MODE(efx),
state->packet_count);
efx_iterate_state(efx);
@@ -570,7 +570,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
netif_dbg(efx, drv, efx->net_dev,
"TX queue %d passed %s loopback test with a burst length "
- "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+ "of %d packets\n", tx_queue->label, LOOPBACK_MODE(efx),
state->packet_count);
return 0;
@@ -660,7 +660,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
/* Test all enabled types of TX queue */
efx_for_each_channel_tx_queue(tx_queue, channel) {
- state->offload_csum = (tx_queue->queue &
+ state->offload_csum = (tx_queue->label &
EFX_TXQ_TYPE_OFFLOAD);
rc = efx_test_loopback(tx_queue,
&tests->loopback[mode]);
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index ffe193f03352..219fb3a0c9d0 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -279,6 +279,7 @@ static int siena_probe_nic(struct efx_nic *efx)
efx->max_channels = EFX_MAX_CHANNELS;
efx->max_vis = EFX_MAX_CHANNELS;
efx->max_tx_channels = EFX_MAX_CHANNELS;
+ efx->tx_queues_per_channel = 4;
efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
@@ -633,7 +634,7 @@ static size_t siena_update_nic_stats(struct efx_nic *efx, u64 *full_stats,
return SIENA_STAT_COUNT;
}
-static int siena_mac_reconfigure(struct efx_nic *efx)
+static int siena_mac_reconfigure(struct efx_nic *efx, bool mtu_only __always_unused)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_MCAST_HASH_IN_LEN);
int rc;
@@ -1085,7 +1086,6 @@ const struct efx_nic_type siena_a0_nic_type = {
.can_rx_scatter = true,
.option_descriptors = false,
.min_interrupt_mode = EFX_INT_MODE_LEGACY,
- .max_interrupt_mode = EFX_INT_MODE_MSIX,
.timer_period_max = 1 << FRF_CZ_TC_TIMER_VAL_WIDTH,
.offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXHASH | NETIF_F_NTUPLE),
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index ed20f6aef435..1bcf50ab95d9 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -551,8 +551,8 @@ void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue)
/* Must be inverse of queue lookup in efx_hard_start_xmit() */
tx_queue->core_txq =
netdev_get_tx_queue(efx->net_dev,
- tx_queue->queue / EFX_TXQ_TYPES +
- ((tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ?
+ tx_queue->channel->channel +
+ ((tx_queue->label & EFX_TXQ_TYPE_HIGHPRI) ?
efx->n_tx_channels : 0));
}
@@ -561,14 +561,15 @@ int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
{
struct efx_nic *efx = netdev_priv(net_dev);
struct tc_mqprio_qopt *mqprio = type_data;
- struct efx_channel *channel;
- struct efx_tx_queue *tx_queue;
unsigned tc, num_tc;
- int rc;
if (type != TC_SETUP_QDISC_MQPRIO)
return -EOPNOTSUPP;
+ /* Only Siena supported highpri queues */
+ if (efx_nic_rev(efx) > EFX_REV_SIENA_A0)
+ return -EOPNOTSUPP;
+
num_tc = mqprio->num_tc;
if (num_tc > EFX_MAX_TX_TC)
@@ -584,40 +585,9 @@ int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
net_dev->tc_to_txq[tc].count = efx->n_tx_channels;
}
- if (num_tc > net_dev->num_tc) {
- /* Initialise high-priority queues as necessary */
- efx_for_each_channel(channel, efx) {
- efx_for_each_possible_channel_tx_queue(tx_queue,
- channel) {
- if (!(tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI))
- continue;
- if (!tx_queue->buffer) {
- rc = efx_probe_tx_queue(tx_queue);
- if (rc)
- return rc;
- }
- if (!tx_queue->initialised)
- efx_init_tx_queue(tx_queue);
- efx_init_tx_queue_core_txq(tx_queue);
- }
- }
- } else {
- /* Reduce number of classes before number of queues */
- net_dev->num_tc = num_tc;
- }
-
- rc = netif_set_real_num_tx_queues(net_dev,
- max_t(int, num_tc, 1) *
- efx->n_tx_channels);
- if (rc)
- return rc;
-
- /* Do not destroy high-priority queues when they become
- * unused. We would have to flush them first, and it is
- * fairly difficult to flush a subset of TX queues. Leave
- * it to efx_fini_channels().
- */
-
net_dev->num_tc = num_tc;
- return 0;
+
+ return netif_set_real_num_tx_queues(net_dev,
+ max_t(int, num_tc, 1) *
+ efx->n_tx_channels);
}
diff --git a/drivers/net/ethernet/sfc/tx_common.c b/drivers/net/ethernet/sfc/tx_common.c
index 2a058b76d1f0..11b64c609550 100644
--- a/drivers/net/ethernet/sfc/tx_common.c
+++ b/drivers/net/ethernet/sfc/tx_common.c
@@ -298,7 +298,11 @@ struct efx_tx_buffer *efx_tx_map_chunk(struct efx_tx_queue *tx_queue,
/* Map the fragment taking account of NIC-dependent DMA limits. */
do {
buffer = efx_tx_queue_get_insert_buffer(tx_queue);
- dma_len = nic_type->tx_limit_len(tx_queue, dma_addr, len);
+
+ if (nic_type->tx_limit_len)
+ dma_len = nic_type->tx_limit_len(tx_queue, dma_addr, len);
+ else
+ dma_len = len;
buffer->len = dma_len;
buffer->dma_addr = dma_addr;