From af3c38d3fb7c3003842974b1de454ecebbd8bc83 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:27:35 +0100 Subject: [PATCH 01/16] sfc: support setting MTU even if not privileged to configure MAC fully Unprivileged functions (such as VFs) may set their MTU by use of the 'control' field of MC_CMD_SET_MAC_EXT, as used in efx_mcdi_set_mtu(). If calling efx_ef10_mac_reconfigure() from efx_change_mtu(), and the NIC supports the above (SET_MAC_ENHANCED capability), use it rather than efx_mcdi_set_mac(). Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 15 ++++++--------- drivers/net/ethernet/sfc/efx.c | 4 ---- drivers/net/ethernet/sfc/efx_common.c | 12 ++++++------ drivers/net/ethernet/sfc/efx_common.h | 2 +- drivers/net/ethernet/sfc/ethtool_common.c | 2 +- drivers/net/ethernet/sfc/net_driver.h | 2 +- drivers/net/ethernet/sfc/siena.c | 2 +- 7 files changed, 16 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 5faf2f0e4d62a..a51925b45fc75 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3306,18 +3306,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); - - return efx_mcdi_set_mac(efx); -} + WARN_ON(!mutex_is_locked(&efx->mac_lock)); -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) @@ -4038,7 +4035,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, diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 028d826ab147b..418676aba43a3 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -169,10 +169,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) diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c index a2f744377aaa2..26dca2f9a3631 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); } diff --git a/drivers/net/ethernet/sfc/efx_common.h b/drivers/net/ethernet/sfc/efx_common.h index 73c355fc2590e..4056f68f04e52 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_common.c b/drivers/net/ethernet/sfc/ethtool_common.c index c96595e502343..738d9be868997 100644 --- a/drivers/net/ethernet/sfc/ethtool_common.c +++ b/drivers/net/ethernet/sfc/ethtool_common.c @@ -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); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index e0b84b2e3bd23..65a1068781867 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1356,7 +1356,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); diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index ffe193f033520..a7dcd2d3c09b3 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -633,7 +633,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; From bc32442176d7289a71a2e940e5e8ea63cd0a23bb Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:27:51 +0100 Subject: [PATCH 02/16] sfc: remove max_interrupt_mode All NICs supported by this driver are capable of MSI-X interrupts (only Falcon A1 wasn't, and that's now hived off into its own driver), so no need for a nic-type parameter. Besides, the code that checked it was buggy anyway (the following assignment that checked min_interrupt_mode overrode it). Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 2 -- drivers/net/ethernet/sfc/efx_channels.c | 6 ------ drivers/net/ethernet/sfc/net_driver.h | 3 --- drivers/net/ethernet/sfc/siena.c | 1 - 4 files changed, 12 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index a51925b45fc75..88522b683cc7e 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -4108,7 +4108,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, @@ -4245,7 +4244,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_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index 2f9db219513a2..2220b95073361 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -557,12 +557,6 @@ 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); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 65a1068781867..e536c1e12f86d 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1317,8 +1317,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 @@ -1492,7 +1490,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; diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index a7dcd2d3c09b3..e438853f64a38 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -1085,7 +1085,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), From e4ff3232102080e8491f2fecb83446e1cbf5b87c Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:28:13 +0100 Subject: [PATCH 03/16] sfc: move modparam 'interrupt_mode' out of common channel code EF100 only supports MSI-X, so there's no need for the new driver to expose this old module parameter. Since it's now visible to the linker, we have to rename it internally to efx_interrupt_mode to avoid symbol collisions in non-modular builds. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 4 ++++ drivers/net/ethernet/sfc/efx_channels.c | 7 ++----- drivers/net/ethernet/sfc/efx_channels.h | 2 ++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 418676aba43a3..2725d1d62d253 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -64,6 +64,10 @@ 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)"); + /* * Use separate channels for TX and RX events * diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index 2220b95073361..50356db39ae50 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 @@ -558,7 +555,7 @@ int efx_init_channels(struct efx_nic *efx) /* Higher numbered interrupt modes are less capable! */ 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; diff --git a/drivers/net/ethernet/sfc/efx_channels.h b/drivers/net/ethernet/sfc/efx_channels.h index 8d7b8c4142d71..86dd058d40f37 100644 --- a/drivers/net/ethernet/sfc/efx_channels.h +++ b/drivers/net/ethernet/sfc/efx_channels.h @@ -11,6 +11,8 @@ #ifndef EFX_CHANNELS_H #define EFX_CHANNELS_H +extern unsigned int efx_interrupt_mode; + 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); From 67e6398e2e058d0ec126f47ac123cca590c7a2ba Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:29:09 +0100 Subject: [PATCH 04/16] sfc: move modparam 'rss_cpus' out of common channel code Instead of exposing this old module parameter on the new driver (thus having to keep it forever after for compatibility), let's confine it to the old one; if we find later that we need the feature, we ought to support it properly, with ethtool set-channels. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 3 +++ drivers/net/ethernet/sfc/efx_channels.c | 4 +--- drivers/net/ethernet/sfc/efx_channels.h | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 2725d1d62d253..6094f59d49a7e 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -68,6 +68,9 @@ 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 * diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index 50356db39ae50..466257b9abbf1 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -32,9 +32,7 @@ unsigned int efx_interrupt_mode = EFX_INT_MODE_MSIX; * 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); diff --git a/drivers/net/ethernet/sfc/efx_channels.h b/drivers/net/ethernet/sfc/efx_channels.h index 86dd058d40f37..2d71dc9a33dd3 100644 --- a/drivers/net/ethernet/sfc/efx_channels.h +++ b/drivers/net/ethernet/sfc/efx_channels.h @@ -12,6 +12,7 @@ #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); From f9cac93e5b3eefc5c6340ba4efd3628f2347e1ef Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:29:24 +0100 Subject: [PATCH 05/16] sfc: make tx_queues_per_channel variable at runtime Siena needs four TX queues (csum * highpri), EF10 needs two (csum), and EF100 only needs one (as checksumming is controlled entirely by the transmit descriptor). Rather than having various bits of ad-hoc code to decide which queues to set up etc., put the knowledge of how many TXQs a channel has in one place. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 13 +++++----- drivers/net/ethernet/sfc/efx_channels.c | 4 +-- drivers/net/ethernet/sfc/efx_common.c | 1 + drivers/net/ethernet/sfc/net_driver.h | 34 ++++++++++--------------- drivers/net/ethernet/sfc/siena.c | 1 + drivers/net/ethernet/sfc/tx.c | 8 ++++-- 6 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 88522b683cc7e..be15640c160a3 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -600,6 +600,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 +608,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 +1121,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 +1220,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; diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index 466257b9abbf1..c3edebf523b6c 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -726,7 +726,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); @@ -1090,7 +1090,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_common.c b/drivers/net/ethernet/sfc/efx_common.c index 26dca2f9a3631..c84123456c017 100644 --- a/drivers/net/ethernet/sfc/efx_common.c +++ b/drivers/net/ethernet/sfc/efx_common.c @@ -1036,6 +1036,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/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index e536c1e12f86d..4ded155b12e91 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -867,6 +867,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 +1032,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; @@ -1529,7 +1531,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]; } @@ -1551,18 +1553,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 */ @@ -1571,18 +1573,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/siena.c b/drivers/net/ethernet/sfc/siena.c index e438853f64a38..4c5881a3bfe4f 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 = 2; efx_reado(efx, ®, FR_AZ_CS_DEBUG); efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index ed20f6aef435b..76ff394f5b58c 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -569,6 +569,10 @@ int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type, 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) @@ -585,10 +589,10 @@ int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type, } if (num_tc > net_dev->num_tc) { + efx->tx_queues_per_channel = 4; /* Initialise high-priority queues as necessary */ efx_for_each_channel(channel, efx) { - efx_for_each_possible_channel_tx_queue(tx_queue, - channel) { + efx_for_each_channel_tx_queue(tx_queue, channel) { if (!(tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI)) continue; if (!tx_queue->buffer) { From 69a704962e8cab43bd62301e104c222e7d23e361 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:29:40 +0100 Subject: [PATCH 06/16] sfc: commonise netif_set_real_num[tr]x_queues calls While we're at it, also check them for failure. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 3 --- drivers/net/ethernet/sfc/efx_channels.c | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 6094f59d49a7e..befd253af9182 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -336,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 c3edebf523b6c..30358f3f48ca6 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -856,6 +856,7 @@ int efx_set_channels(struct efx_nic *efx) struct efx_channel *channel; struct efx_tx_queue *tx_queue; int xdp_queue_number; + int rc; efx->tx_channel_offset = efx_separate_tx_channels ? @@ -894,7 +895,11 @@ int efx_set_channels(struct efx_nic *efx) } } } - 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) From a81dcd85a7c1bc548ce8fb635623970fdee5887d Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:29:58 +0100 Subject: [PATCH 07/16] sfc: assign TXQs without gaps Since we only allocate VIs for the number of TXQs we actually need, we cannot naively use "channel * TXQ_TYPES + txq" for the TXQ number, as this has gaps (when efx->tx_queues_per_channel < EFX_TXQ_TYPES) and thus overruns the driver's VI allocations, causing the firmware to reject the MC_CMD_INIT_TXQ based on INSTANCE. Thus, we distinguish INSTANCE (stored in tx_queue->queue) from LABEL (tx_queue->label); the former is allocated starting from 0 in efx_set_channels(), while the latter is simply the txq type (index in channel->tx_queue array). To simplify things, rather than changing tx_queues_per_channel after setting up TXQs, make Siena always probe its HIGHPRI queues at start of day, rather than deferring it until tc mqprio enables them. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 2 +- drivers/net/ethernet/sfc/efx_channels.c | 38 ++++++++++++++----- drivers/net/ethernet/sfc/ethtool_common.c | 7 ++-- drivers/net/ethernet/sfc/farch.c | 6 +-- drivers/net/ethernet/sfc/mcdi_functions.c | 4 +- drivers/net/ethernet/sfc/net_driver.h | 5 ++- drivers/net/ethernet/sfc/nic_common.h | 2 +- drivers/net/ethernet/sfc/selftest.c | 18 ++++----- drivers/net/ethernet/sfc/siena.c | 2 +- drivers/net/ethernet/sfc/tx.c | 46 +++-------------------- 10 files changed, 58 insertions(+), 72 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index be15640c160a3..311a2d2a906dd 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2244,7 +2244,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; diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index 30358f3f48ca6..dd4f30ea48a8e 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -524,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; } @@ -853,8 +854,9 @@ int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) 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; @@ -884,14 +886,30 @@ 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); + } } } } diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c index 738d9be868997..37a4409e759e8 100644 --- a/drivers/net/ethernet/sfc/ethtool_common.c +++ b/drivers/net/ethernet/sfc/ethtool_common.c @@ -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/farch.c b/drivers/net/ethernet/sfc/farch.c index dbbb898adddb1..d07eeaad9bdff 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, ®, FR_BZ_TX_PACE_TBL, tx_queue->queue); diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c index 962d8395d958d..b3a8aa88db062 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); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 4ded155b12e91..0bf11ebb03cfc 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; diff --git a/drivers/net/ethernet/sfc/nic_common.h b/drivers/net/ethernet/sfc/nic_common.h index fd474d9e55e4d..813f288ab3fe2 100644 --- a/drivers/net/ethernet/sfc/nic_common.h +++ b/drivers/net/ethernet/sfc/nic_common.h @@ -90,7 +90,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 1ae369022d7d9..e71d6d37a317f 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 4c5881a3bfe4f..219fb3a0c9d0d 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -279,7 +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 = 2; + efx->tx_queues_per_channel = 4; efx_reado(efx, ®, FR_AZ_CS_DEBUG); efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 76ff394f5b58c..1bcf50ab95d9d 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,10 +561,7 @@ 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; @@ -588,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) { - efx->tx_queues_per_channel = 4; - /* Initialise high-priority queues as necessary */ - efx_for_each_channel(channel, efx) { - efx_for_each_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); } From 79de6e7cb8ac9bd0c98be663d414f85ef90c1196 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:30:23 +0100 Subject: [PATCH 08/16] sfc: don't call tx_limit_len if NIC type doesn't have one EF100 doesn't need to split up large DMAs. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/tx_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/sfc/tx_common.c b/drivers/net/ethernet/sfc/tx_common.c index 2a058b76d1f07..11b64c609550a 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; From 965470ee76988af234e23d559f5915747fe1b073 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:30:39 +0100 Subject: [PATCH 09/16] sfc: factor out efx_mcdi_filter_table_down() from _remove() _down() merely removes all our filters and VLANs, it doesn't free efx->filter_state itself. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi_filters.c | 37 ++++++++++++++++--------- drivers/net/ethernet/sfc/mcdi_filters.h | 1 + 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/sfc/mcdi_filters.c b/drivers/net/ethernet/sfc/mcdi_filters.c index 74ee06fe09962..283f68264b661 100644 --- a/drivers/net/ethernet/sfc/mcdi_filters.c +++ b/drivers/net/ethernet/sfc/mcdi_filters.c @@ -1459,7 +1459,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx) 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); diff --git a/drivers/net/ethernet/sfc/mcdi_filters.h b/drivers/net/ethernet/sfc/mcdi_filters.h index 03a8bf74c7337..23f9d08d071dc 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); From d700fe014ec13cf96df8df4de6ee46034008ff85 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:30:56 +0100 Subject: [PATCH 10/16] sfc: commonise efx_fini_dmaq Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 42 ++--------------------- drivers/net/ethernet/sfc/mcdi_functions.c | 38 ++++++++++++++++++++ drivers/net/ethernet/sfc/mcdi_functions.h | 1 + 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 311a2d2a906dd..d2101d2a55bef 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3117,44 +3117,6 @@ static void efx_ef10_ev_test_generate(struct efx_channel *channel) 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); @@ -4026,7 +3988,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, @@ -4134,7 +4096,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, diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c index b3a8aa88db062..92b9a741c286f 100644 --- a/drivers/net/ethernet/sfc/mcdi_functions.c +++ b/drivers/net/ethernet/sfc/mcdi_functions.c @@ -341,6 +341,44 @@ void efx_mcdi_rx_fini(struct efx_rx_queue *rx_queue) 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 ca4a5ac1a66bb..687be8b00cd8b 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); From 31f4cbd4014360ec45ddb19fa1bf5ae97e42ec5b Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:31:19 +0100 Subject: [PATCH 11/16] sfc: initialise RSS context ID to 'no RSS context' in efx_init_struct() Previously this was only happening in ef10-specific code. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 2 -- drivers/net/ethernet/sfc/efx_common.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index d2101d2a55bef..cb7b634a11508 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 diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c index c84123456c017..5667694c65149 100644 --- a/drivers/net/ethernet/sfc/efx_common.c +++ b/drivers/net/ethernet/sfc/efx_common.c @@ -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); From bcacac7a8cd9939a991fd20acb1b9f57251363b9 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:31:43 +0100 Subject: [PATCH 12/16] sfc: get drvinfo driver name from outside the common code Since ethtool_common.o will be built into both sfc and sfc_ef100 drivers, it can't use KBUILD_MODNAME directly. Instead, make it reference a string provided by the individual driver code. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ethtool.c | 2 ++ drivers/net/ethernet/sfc/ethtool_common.c | 2 +- drivers/net/ethernet/sfc/ethtool_common.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 48a96ed6b7d06..9828516bd82d6 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 37a4409e759e8..e9a5a66529bfe 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)); diff --git a/drivers/net/ethernet/sfc/ethtool_common.h b/drivers/net/ethernet/sfc/ethtool_common.h index 7bfbbd08a1ef4..3f3aaa92fbb59 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); From 805d22bf92f1541cbb5b5544f628864610e2c9a2 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:32:04 +0100 Subject: [PATCH 13/16] sfc_ef100: add EF100 to NIC-revision enumeration Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/nic_common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/sfc/nic_common.h b/drivers/net/ethernet/sfc/nic_common.h index 813f288ab3fe2..e04b6817cde3d 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) From 39c965f4e663fa53955f77435068748448514da1 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:32:24 +0100 Subject: [PATCH 14/16] sfc_ef100: populate BUFFER_SIZE_BYTES in INIT_RXQ The QDMA subsystem on EF100 needs this information. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi_functions.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c index 92b9a741c286f..d8a3af86ef781 100644 --- a/drivers/net/ethernet/sfc/mcdi_functions.c +++ b/drivers/net/ethernet/sfc/mcdi_functions.c @@ -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", From b3007dfd5b059cc873a8b4c24a1e337cdcec9011 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:34:27 +0100 Subject: [PATCH 15/16] sfc_ef100: NVRAM selftest support code We have yet another new scheme for NVRAM, and a corresponding new MCDI. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi.c | 62 +++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/mcdi.h | 1 + 2 files changed, 63 insertions(+) diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 244fb621d17bc..6c49740a178eb 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1621,6 +1621,35 @@ int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out) 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 10f064f761a53..e053adfe82b08 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); From b6d02dd2ffd4ac9b08a963762eb3d1ee0502ffc6 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 2 Jul 2020 17:34:43 +0100 Subject: [PATCH 16/16] sfc_ef100: helper function to set default RSS table of given size Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi_filters.c | 21 +++++++++++++++++++++ drivers/net/ethernet/sfc/mcdi_filters.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/drivers/net/ethernet/sfc/mcdi_filters.c b/drivers/net/ethernet/sfc/mcdi_filters.c index 283f68264b661..5a74d880b7338 100644 --- a/drivers/net/ethernet/sfc/mcdi_filters.c +++ b/drivers/net/ethernet/sfc/mcdi_filters.c @@ -2276,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 23f9d08d071dc..06426aa9f2f37 100644 --- a/drivers/net/ethernet/sfc/mcdi_filters.h +++ b/drivers/net/ethernet/sfc/mcdi_filters.h @@ -155,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);