ethtool.c 8.8 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
2
/****************************************************************************
B
Ben Hutchings 已提交
3
 * Driver for Solarflare network controllers and boards
4
 * Copyright 2005-2006 Fen Systems Ltd.
B
Ben Hutchings 已提交
5
 * Copyright 2006-2013 Solarflare Communications Inc.
6 7 8 9 10
 */

#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
11
#include <linux/in.h>
12
#include "net_driver.h"
B
Ben Hutchings 已提交
13
#include "workarounds.h"
14
#include "selftest.h"
15
#include "efx.h"
16 17 18
#include "efx_channels.h"
#include "rx_common.h"
#include "tx_common.h"
19
#include "ethtool_common.h"
20
#include "filter.h"
B
Ben Hutchings 已提交
21
#include "nic.h"
22

23 24
#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB

25 26 27 28 29 30 31 32
/**************************************************************************
 *
 * Ethtool operations
 *
 **************************************************************************
 */

/* Identify device by flashing LEDs */
33 34
static int efx_ethtool_phys_id(struct net_device *net_dev,
			       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 40 41 42 43 44 45 46 47 48
	switch (state) {
	case ETHTOOL_ID_ON:
		mode = EFX_LED_ON;
		break;
	case ETHTOOL_ID_OFF:
		mode = EFX_LED_OFF;
		break;
	case ETHTOOL_ID_INACTIVE:
		mode = EFX_LED_DEFAULT;
		break;
49 50
	case ETHTOOL_ID_ACTIVE:
		return 1;	/* cycle on/off once per second */
51
	}
52

53
	return efx_mcdi_set_id_led(efx, mode);
54 55
}

56 57
static int efx_ethtool_get_regs_len(struct net_device *net_dev)
{
58
	return efx_nic_get_regs_len(efx_netdev_priv(net_dev));
59 60 61 62 63
}

static void efx_ethtool_get_regs(struct net_device *net_dev,
				 struct ethtool_regs *regs, void *buf)
{
64
	struct efx_nic *efx = efx_netdev_priv(net_dev);
65 66 67 68 69

	regs->version = efx->type->revision;
	efx_nic_get_regs(efx, buf);
}

70 71 72 73 74 75 76 77 78
/*
 * Each channel has a single IRQ and moderation timer, started by any
 * completion (or other event).  Unless the module parameter
 * separate_tx_channels is set, IRQs and moderation are therefore
 * shared between RX and TX completions.  In this case, when RX IRQ
 * moderation is explicitly changed then TX IRQ moderation is
 * automatically changed too, but otherwise we fail if the two values
 * are requested to be different.
 *
79 80 81 82 83 84 85 86 87 88 89 90 91 92
 * The hardware does not support a limit on the number of completions
 * before an IRQ, so we do not use the max_frames fields.  We should
 * report and require that max_frames == (usecs != 0), but this would
 * invalidate existing user documentation.
 *
 * The hardware does not have distinct settings for interrupt
 * moderation while the previous IRQ is being handled, so we should
 * not use the 'irq' fields.  However, an earlier developer
 * misunderstood the meaning of the 'irq' fields and the driver did
 * not support the standard fields.  To avoid invalidating existing
 * user documentation, we report and accept changes through either the
 * standard or 'irq' fields.  If both are changed at the same time, we
 * prefer the standard field.
 *
93 94 95 96 97 98
 * We implement adaptive IRQ moderation, but use a different algorithm
 * from that assumed in the definition of struct ethtool_coalesce.
 * Therefore we do not use any of the adaptive moderation parameters
 * in it.
 */

99
static int efx_ethtool_get_coalesce(struct net_device *net_dev,
100 101 102
				    struct ethtool_coalesce *coalesce,
				    struct kernel_ethtool_coalesce *kernel_coal,
				    struct netlink_ext_ack *extack)
103
{
104
	struct efx_nic *efx = efx_netdev_priv(net_dev);
105 106
	unsigned int tx_usecs, rx_usecs;
	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 114
	coalesce->rx_coalesce_usecs_irq = rx_usecs;
	coalesce->use_adaptive_rx_coalesce = rx_adaptive;
115

116 117 118 119
	return 0;
}

static int efx_ethtool_set_coalesce(struct net_device *net_dev,
120 121 122
				    struct ethtool_coalesce *coalesce,
				    struct kernel_ethtool_coalesce *kernel_coal,
				    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 128
	bool adaptive, rx_may_override_tx;
	int rc;
129

130 131
	efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);

132 133 134 135 136
	if (coalesce->rx_coalesce_usecs != rx_usecs)
		rx_usecs = coalesce->rx_coalesce_usecs;
	else
		rx_usecs = coalesce->rx_coalesce_usecs_irq;

137
	adaptive = coalesce->use_adaptive_rx_coalesce;
138

139 140 141
	/* If channels are shared, TX IRQ moderation can be quietly
	 * overridden unless it is changed from its old value.
	 */
142 143 144 145 146 147
	rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs &&
			      coalesce->tx_coalesce_usecs_irq == tx_usecs);
	if (coalesce->tx_coalesce_usecs != tx_usecs)
		tx_usecs = coalesce->tx_coalesce_usecs;
	else
		tx_usecs = coalesce->tx_coalesce_usecs_irq;
148

149 150 151 152 153
	rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive,
				     rx_may_override_tx);
	if (rc != 0)
		return rc;

154
	efx_for_each_channel(channel, efx)
155
		efx->type->push_irq_moderation(channel);
156 157 158 159

	return 0;
}

160 161 162 163 164
static void
efx_ethtool_get_ringparam(struct net_device *net_dev,
			  struct ethtool_ringparam *ring,
			  struct kernel_ethtool_ringparam *kernel_ring,
			  struct netlink_ext_ack *extack)
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 171 172 173
	ring->rx_pending = efx->rxq_entries;
	ring->tx_pending = efx->txq_entries;
}

174 175 176 177 178
static int
efx_ethtool_set_ringparam(struct net_device *net_dev,
			  struct ethtool_ringparam *ring,
			  struct kernel_ethtool_ringparam *kernel_ring,
			  struct netlink_ext_ack *extack)
179
{
180
	struct efx_nic *efx = efx_netdev_priv(net_dev);
181
	u32 txq_entries;
182 183 184

	if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
	    ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
185
	    ring->tx_pending > EFX_TXQ_MAX_ENT(efx))
186 187
		return -EINVAL;

188
	if (ring->rx_pending < EFX_RXQ_MIN_ENT) {
189
		netif_err(efx, drv, efx->net_dev,
190 191
			  "RX queues cannot be smaller than %u\n",
			  EFX_RXQ_MIN_ENT);
192 193 194
		return -EINVAL;
	}

195 196 197 198 199 200 201
	txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));
	if (txq_entries != ring->tx_pending)
		netif_warn(efx, drv, efx->net_dev,
			   "increasing TX queue size to minimum of %u\n",
			   txq_entries);

	return efx_realloc_channels(efx, ring->rx_pending, txq_entries);
202 203
}

204 205 206
static void efx_ethtool_get_wol(struct net_device *net_dev,
				struct ethtool_wolinfo *wol)
{
207
	struct efx_nic *efx = efx_netdev_priv(net_dev);
208 209 210 211 212 213 214
	return efx->type->get_wol(efx, wol);
}


static int efx_ethtool_set_wol(struct net_device *net_dev,
			       struct ethtool_wolinfo *wol)
{
215
	struct efx_nic *efx = efx_netdev_priv(net_dev);
216 217 218
	return efx->type->set_wol(efx, wol->wolopts);
}

219 220 221
static void efx_ethtool_get_fec_stats(struct net_device *net_dev,
				      struct ethtool_fec_stats *fec_stats)
{
222
	struct efx_nic *efx = efx_netdev_priv(net_dev);
223 224 225 226 227

	if (efx->type->get_fec_stats)
		efx->type->get_fec_stats(efx, fec_stats);
}

228 229
static int efx_ethtool_get_ts_info(struct net_device *net_dev,
				   struct ethtool_ts_info *ts_info)
230
{
231
	struct efx_nic *efx = efx_netdev_priv(net_dev);
232 233 234 235 236 237 238 239 240 241

	/* Software capabilities */
	ts_info->so_timestamping = (SOF_TIMESTAMPING_RX_SOFTWARE |
				    SOF_TIMESTAMPING_SOFTWARE);
	ts_info->phc_index = -1;

	efx_ptp_get_ts_info(efx, ts_info);
	return 0;
}

242
const struct ethtool_ops efx_ethtool_ops = {
243 244 245
	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
				     ETHTOOL_COALESCE_USECS_IRQ |
				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
246
	.get_drvinfo		= efx_ethtool_get_drvinfo,
247 248
	.get_regs_len		= efx_ethtool_get_regs_len,
	.get_regs		= efx_ethtool_get_regs,
249 250
	.get_msglevel		= efx_ethtool_get_msglevel,
	.set_msglevel		= efx_ethtool_set_msglevel,
251
	.get_link		= ethtool_op_get_link,
252 253
	.get_coalesce		= efx_ethtool_get_coalesce,
	.set_coalesce		= efx_ethtool_set_coalesce,
254 255
	.get_ringparam		= efx_ethtool_get_ringparam,
	.set_ringparam		= efx_ethtool_set_ringparam,
256 257
	.get_pauseparam         = efx_ethtool_get_pauseparam,
	.set_pauseparam         = efx_ethtool_set_pauseparam,
258
	.get_sset_count		= efx_ethtool_get_sset_count,
259
	.self_test		= efx_ethtool_self_test,
260
	.get_strings		= efx_ethtool_get_strings,
261
	.set_phys_id		= efx_ethtool_phys_id,
262
	.get_ethtool_stats	= efx_ethtool_get_stats,
263 264
	.get_wol                = efx_ethtool_get_wol,
	.set_wol                = efx_ethtool_set_wol,
265
	.reset			= efx_ethtool_reset,
266
	.get_rxnfc		= efx_ethtool_get_rxnfc,
267
	.set_rxnfc		= efx_ethtool_set_rxnfc,
268
	.get_rxfh_indir_size	= efx_ethtool_get_rxfh_indir_size,
269
	.get_rxfh_key_size	= efx_ethtool_get_rxfh_key_size,
270 271
	.get_rxfh		= efx_ethtool_get_rxfh,
	.set_rxfh		= efx_ethtool_set_rxfh,
272 273
	.get_rxfh_context	= efx_ethtool_get_rxfh_context,
	.set_rxfh_context	= efx_ethtool_set_rxfh_context,
274
	.get_ts_info		= efx_ethtool_get_ts_info,
275 276
	.get_module_info	= efx_ethtool_get_module_info,
	.get_module_eeprom	= efx_ethtool_get_module_eeprom,
277 278
	.get_link_ksettings	= efx_ethtool_get_link_ksettings,
	.set_link_ksettings	= efx_ethtool_set_link_ksettings,
279
	.get_fec_stats		= efx_ethtool_get_fec_stats,
280 281
	.get_fecparam		= efx_ethtool_get_fecparam,
	.set_fecparam		= efx_ethtool_set_fecparam,
282
};