brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · bb19308 Raw
281 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/****************************************************************************3 * Driver for Solarflare network controllers and boards4 * Copyright 2005-2006 Fen Systems Ltd.5 * Copyright 2006-2013 Solarflare Communications Inc.6 */7 8#include <linux/netdevice.h>9#include <linux/ethtool.h>10#include <linux/rtnetlink.h>11#include <linux/in.h>12#include "net_driver.h"13#include "workarounds.h"14#include "selftest.h"15#include "efx.h"16#include "efx_channels.h"17#include "rx_common.h"18#include "tx_common.h"19#include "ethtool_common.h"20#include "filter.h"21#include "nic.h"22 23#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB24 25/**************************************************************************26 *27 * Ethtool operations28 *29 **************************************************************************30 */31 32/* Identify device by flashing LEDs */33static int efx_ethtool_phys_id(struct net_device *net_dev,34			       enum ethtool_phys_id_state state)35{36	struct efx_nic *efx = efx_netdev_priv(net_dev);37	enum efx_led_mode mode = EFX_LED_DEFAULT;38 39	switch (state) {40	case ETHTOOL_ID_ON:41		mode = EFX_LED_ON;42		break;43	case ETHTOOL_ID_OFF:44		mode = EFX_LED_OFF;45		break;46	case ETHTOOL_ID_INACTIVE:47		mode = EFX_LED_DEFAULT;48		break;49	case ETHTOOL_ID_ACTIVE:50		return 1;	/* cycle on/off once per second */51	}52 53	return efx_mcdi_set_id_led(efx, mode);54}55 56static int efx_ethtool_get_regs_len(struct net_device *net_dev)57{58	return efx_nic_get_regs_len(efx_netdev_priv(net_dev));59}60 61static void efx_ethtool_get_regs(struct net_device *net_dev,62				 struct ethtool_regs *regs, void *buf)63{64	struct efx_nic *efx = efx_netdev_priv(net_dev);65 66	regs->version = efx->type->revision;67	efx_nic_get_regs(efx, buf);68}69 70/*71 * Each channel has a single IRQ and moderation timer, started by any72 * completion (or other event).  Unless the module parameter73 * separate_tx_channels is set, IRQs and moderation are therefore74 * shared between RX and TX completions.  In this case, when RX IRQ75 * moderation is explicitly changed then TX IRQ moderation is76 * automatically changed too, but otherwise we fail if the two values77 * are requested to be different.78 *79 * The hardware does not support a limit on the number of completions80 * before an IRQ, so we do not use the max_frames fields.  We should81 * report and require that max_frames == (usecs != 0), but this would82 * invalidate existing user documentation.83 *84 * The hardware does not have distinct settings for interrupt85 * moderation while the previous IRQ is being handled, so we should86 * not use the 'irq' fields.  However, an earlier developer87 * misunderstood the meaning of the 'irq' fields and the driver did88 * not support the standard fields.  To avoid invalidating existing89 * user documentation, we report and accept changes through either the90 * standard or 'irq' fields.  If both are changed at the same time, we91 * prefer the standard field.92 *93 * We implement adaptive IRQ moderation, but use a different algorithm94 * from that assumed in the definition of struct ethtool_coalesce.95 * Therefore we do not use any of the adaptive moderation parameters96 * in it.97 */98 99static int efx_ethtool_get_coalesce(struct net_device *net_dev,100				    struct ethtool_coalesce *coalesce,101				    struct kernel_ethtool_coalesce *kernel_coal,102				    struct netlink_ext_ack *extack)103{104	struct efx_nic *efx = efx_netdev_priv(net_dev);105	unsigned int tx_usecs, rx_usecs;106	bool rx_adaptive;107 108	efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive);109 110	coalesce->tx_coalesce_usecs = tx_usecs;111	coalesce->tx_coalesce_usecs_irq = tx_usecs;112	coalesce->rx_coalesce_usecs = rx_usecs;113	coalesce->rx_coalesce_usecs_irq = rx_usecs;114	coalesce->use_adaptive_rx_coalesce = rx_adaptive;115 116	return 0;117}118 119static int efx_ethtool_set_coalesce(struct net_device *net_dev,120				    struct ethtool_coalesce *coalesce,121				    struct kernel_ethtool_coalesce *kernel_coal,122				    struct netlink_ext_ack *extack)123{124	struct efx_nic *efx = efx_netdev_priv(net_dev);125	struct efx_channel *channel;126	unsigned int tx_usecs, rx_usecs;127	bool adaptive, rx_may_override_tx;128	int rc;129 130	efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);131 132	if (coalesce->rx_coalesce_usecs != rx_usecs)133		rx_usecs = coalesce->rx_coalesce_usecs;134	else135		rx_usecs = coalesce->rx_coalesce_usecs_irq;136 137	adaptive = coalesce->use_adaptive_rx_coalesce;138 139	/* If channels are shared, TX IRQ moderation can be quietly140	 * overridden unless it is changed from its old value.141	 */142	rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs &&143			      coalesce->tx_coalesce_usecs_irq == tx_usecs);144	if (coalesce->tx_coalesce_usecs != tx_usecs)145		tx_usecs = coalesce->tx_coalesce_usecs;146	else147		tx_usecs = coalesce->tx_coalesce_usecs_irq;148 149	rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive,150				     rx_may_override_tx);151	if (rc != 0)152		return rc;153 154	efx_for_each_channel(channel, efx)155		efx->type->push_irq_moderation(channel);156 157	return 0;158}159 160static void161efx_ethtool_get_ringparam(struct net_device *net_dev,162			  struct ethtool_ringparam *ring,163			  struct kernel_ethtool_ringparam *kernel_ring,164			  struct netlink_ext_ack *extack)165{166	struct efx_nic *efx = efx_netdev_priv(net_dev);167 168	ring->rx_max_pending = EFX_MAX_DMAQ_SIZE;169	ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx);170	ring->rx_pending = efx->rxq_entries;171	ring->tx_pending = efx->txq_entries;172}173 174static int175efx_ethtool_set_ringparam(struct net_device *net_dev,176			  struct ethtool_ringparam *ring,177			  struct kernel_ethtool_ringparam *kernel_ring,178			  struct netlink_ext_ack *extack)179{180	struct efx_nic *efx = efx_netdev_priv(net_dev);181	u32 txq_entries;182 183	if (ring->rx_mini_pending || ring->rx_jumbo_pending ||184	    ring->rx_pending > EFX_MAX_DMAQ_SIZE ||185	    ring->tx_pending > EFX_TXQ_MAX_ENT(efx))186		return -EINVAL;187 188	if (ring->rx_pending < EFX_RXQ_MIN_ENT) {189		netif_err(efx, drv, efx->net_dev,190			  "RX queues cannot be smaller than %u\n",191			  EFX_RXQ_MIN_ENT);192		return -EINVAL;193	}194 195	txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));196	if (txq_entries != ring->tx_pending)197		netif_warn(efx, drv, efx->net_dev,198			   "increasing TX queue size to minimum of %u\n",199			   txq_entries);200 201	return efx_realloc_channels(efx, ring->rx_pending, txq_entries);202}203 204static void efx_ethtool_get_wol(struct net_device *net_dev,205				struct ethtool_wolinfo *wol)206{207	struct efx_nic *efx = efx_netdev_priv(net_dev);208	return efx->type->get_wol(efx, wol);209}210 211 212static int efx_ethtool_set_wol(struct net_device *net_dev,213			       struct ethtool_wolinfo *wol)214{215	struct efx_nic *efx = efx_netdev_priv(net_dev);216	return efx->type->set_wol(efx, wol->wolopts);217}218 219static void efx_ethtool_get_fec_stats(struct net_device *net_dev,220				      struct ethtool_fec_stats *fec_stats)221{222	struct efx_nic *efx = efx_netdev_priv(net_dev);223 224	if (efx->type->get_fec_stats)225		efx->type->get_fec_stats(efx, fec_stats);226}227 228static int efx_ethtool_get_ts_info(struct net_device *net_dev,229				   struct kernel_ethtool_ts_info *ts_info)230{231	struct efx_nic *efx = efx_netdev_priv(net_dev);232 233	efx_ptp_get_ts_info(efx, ts_info);234	return 0;235}236 237const struct ethtool_ops efx_ethtool_ops = {238	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |239				     ETHTOOL_COALESCE_USECS_IRQ |240				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,241	.get_drvinfo		= efx_ethtool_get_drvinfo,242	.get_regs_len		= efx_ethtool_get_regs_len,243	.get_regs		= efx_ethtool_get_regs,244	.get_msglevel		= efx_ethtool_get_msglevel,245	.set_msglevel		= efx_ethtool_set_msglevel,246	.get_link		= ethtool_op_get_link,247	.get_coalesce		= efx_ethtool_get_coalesce,248	.set_coalesce		= efx_ethtool_set_coalesce,249	.get_ringparam		= efx_ethtool_get_ringparam,250	.set_ringparam		= efx_ethtool_set_ringparam,251	.get_pauseparam         = efx_ethtool_get_pauseparam,252	.set_pauseparam         = efx_ethtool_set_pauseparam,253	.get_sset_count		= efx_ethtool_get_sset_count,254	.self_test		= efx_ethtool_self_test,255	.get_strings		= efx_ethtool_get_strings,256	.set_phys_id		= efx_ethtool_phys_id,257	.get_ethtool_stats	= efx_ethtool_get_stats,258	.get_wol                = efx_ethtool_get_wol,259	.set_wol                = efx_ethtool_set_wol,260	.reset			= efx_ethtool_reset,261	.get_rxnfc		= efx_ethtool_get_rxnfc,262	.set_rxnfc		= efx_ethtool_set_rxnfc,263	.get_rxfh_indir_size	= efx_ethtool_get_rxfh_indir_size,264	.get_rxfh_key_size	= efx_ethtool_get_rxfh_key_size,265	.rxfh_per_ctx_key	= true,266	.rxfh_priv_size		= sizeof(struct efx_rss_context_priv),267	.get_rxfh		= efx_ethtool_get_rxfh,268	.set_rxfh		= efx_ethtool_set_rxfh,269	.create_rxfh_context	= efx_ethtool_create_rxfh_context,270	.modify_rxfh_context	= efx_ethtool_modify_rxfh_context,271	.remove_rxfh_context	= efx_ethtool_remove_rxfh_context,272	.get_ts_info		= efx_ethtool_get_ts_info,273	.get_module_info	= efx_ethtool_get_module_info,274	.get_module_eeprom	= efx_ethtool_get_module_eeprom,275	.get_link_ksettings	= efx_ethtool_get_link_ksettings,276	.set_link_ksettings	= efx_ethtool_set_link_ksettings,277	.get_fec_stats		= efx_ethtool_get_fec_stats,278	.get_fecparam		= efx_ethtool_get_fecparam,279	.set_fecparam		= efx_ethtool_set_fecparam,280};281