File Index
Files and directories
Sign in
FILE

ethtool.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/intel/igbvf/ethtool.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright(c) 2009 - 2018 Intel Corporation. */
  3
  4/* ethtool support for igbvf */
  5
  6#include <linux/netdevice.h>
  7#include <linux/ethtool.h>
  8#include <linux/pci.h>
  9#include <linux/vmalloc.h>
 10#include <linux/delay.h>
 11
 12#include "igbvf.h"
 13#include <linux/if_vlan.h>
 14
 15struct igbvf_stats {
 16	char stat_string[ETH_GSTRING_LEN];
 17	int sizeof_stat;
 18	int stat_offset;
 19	int base_stat_offset;
 20};
 21
 22#define IGBVF_STAT(current, base) \
 23		sizeof(((struct igbvf_adapter *)0)->current), \
 24		offsetof(struct igbvf_adapter, current), \
 25		offsetof(struct igbvf_adapter, base)
 26
 27static const struct igbvf_stats igbvf_gstrings_stats[] = {
 28	{ "rx_packets", IGBVF_STAT(stats.gprc, stats.base_gprc) },
 29	{ "tx_packets", IGBVF_STAT(stats.gptc, stats.base_gptc) },
 30	{ "rx_bytes", IGBVF_STAT(stats.gorc, stats.base_gorc) },
 31	{ "tx_bytes", IGBVF_STAT(stats.gotc, stats.base_gotc) },
 32	{ "multicast", IGBVF_STAT(stats.mprc, stats.base_mprc) },
 33	{ "lbrx_packets", IGBVF_STAT(stats.gprlbc, stats.base_gprlbc) },
 34	{ "lbtx_packets", IGBVF_STAT(stats.gptlbc, stats.base_gptlbc) },
 35	{ "lbrx_bytes", IGBVF_STAT(stats.gorlbc, stats.base_gorlbc) },
 36	{ "lbtx_bytes", IGBVF_STAT(stats.gotlbc, stats.base_gotlbc) },
 37	{ "tx_restart_queue", IGBVF_STAT(restart_queue, zero_base) },
 38	{ "tx_timeout_count", IGBVF_STAT(tx_timeout_count, zero_base) },
 39	{ "rx_csum_offload_good", IGBVF_STAT(hw_csum_good, zero_base) },
 40	{ "rx_csum_offload_errors", IGBVF_STAT(hw_csum_err, zero_base) },
 41	{ "rx_header_split", IGBVF_STAT(rx_hdr_split, zero_base) },
 42	{ "alloc_rx_buff_failed", IGBVF_STAT(alloc_rx_buff_failed, zero_base) },
 43};
 44
 45#define IGBVF_GLOBAL_STATS_LEN ARRAY_SIZE(igbvf_gstrings_stats)
 46
 47static const char igbvf_gstrings_test[][ETH_GSTRING_LEN] = {
 48	"Link test   (on/offline)"
 49};
 50
 51#define IGBVF_TEST_LEN ARRAY_SIZE(igbvf_gstrings_test)
 52
 53static int igbvf_get_link_ksettings(struct net_device *netdev,
 54				    struct ethtool_link_ksettings *cmd)
 55{
 56	struct igbvf_adapter *adapter = netdev_priv(netdev);
 57	struct e1000_hw *hw = &adapter->hw;
 58	u32 status;
 59
 60	ethtool_link_ksettings_zero_link_mode(cmd, supported);
 61	ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full);
 62	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
 63	ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
 64
 65	cmd->base.port = -1;
 66
 67	status = er32(STATUS);
 68	if (status & E1000_STATUS_LU) {
 69		if (status & E1000_STATUS_SPEED_1000)
 70			cmd->base.speed = SPEED_1000;
 71		else if (status & E1000_STATUS_SPEED_100)
 72			cmd->base.speed = SPEED_100;
 73		else
 74			cmd->base.speed = SPEED_10;
 75
 76		if (status & E1000_STATUS_FD)
 77			cmd->base.duplex = DUPLEX_FULL;
 78		else
 79			cmd->base.duplex = DUPLEX_HALF;
 80	} else {
 81		cmd->base.speed = SPEED_UNKNOWN;
 82		cmd->base.duplex = DUPLEX_UNKNOWN;
 83	}
 84
 85	cmd->base.autoneg = AUTONEG_DISABLE;
 86
 87	return 0;
 88}
 89
 90static int igbvf_set_link_ksettings(struct net_device *netdev,
 91				    const struct ethtool_link_ksettings *cmd)
 92{
 93	return -EOPNOTSUPP;
 94}
 95
 96static void igbvf_get_pauseparam(struct net_device *netdev,
 97				 struct ethtool_pauseparam *pause)
 98{
 99}
100
101static int igbvf_set_pauseparam(struct net_device *netdev,
102				struct ethtool_pauseparam *pause)
103{
104	return -EOPNOTSUPP;
105}
106
107static u32 igbvf_get_msglevel(struct net_device *netdev)
108{
109	struct igbvf_adapter *adapter = netdev_priv(netdev);
110
111	return adapter->msg_enable;
112}
113
114static void igbvf_set_msglevel(struct net_device *netdev, u32 data)
115{
116	struct igbvf_adapter *adapter = netdev_priv(netdev);
117
118	adapter->msg_enable = data;
119}
120
121static int igbvf_get_regs_len(struct net_device *netdev)
122{
123#define IGBVF_REGS_LEN 8
124	return IGBVF_REGS_LEN * sizeof(u32);
125}
126
127static void igbvf_get_regs(struct net_device *netdev,
128			   struct ethtool_regs *regs, void *p)
129{
130	struct igbvf_adapter *adapter = netdev_priv(netdev);
131	struct e1000_hw *hw = &adapter->hw;
132	u32 *regs_buff = p;
133
134	memset(p, 0, IGBVF_REGS_LEN * sizeof(u32));
135
136	regs->version = (1u << 24) |
137			(adapter->pdev->revision << 16) |
138			adapter->pdev->device;
139
140	regs_buff[0] = er32(CTRL);
141	regs_buff[1] = er32(STATUS);
142
143	regs_buff[2] = er32(RDLEN(0));
144	regs_buff[3] = er32(RDH(0));
145	regs_buff[4] = er32(RDT(0));
146
147	regs_buff[5] = er32(TDLEN(0));
148	regs_buff[6] = er32(TDH(0));
149	regs_buff[7] = er32(TDT(0));
150}
151
152static int igbvf_get_eeprom_len(struct net_device *netdev)
153{
154	return 0;
155}
156
157static int igbvf_get_eeprom(struct net_device *netdev,
158			    struct ethtool_eeprom *eeprom, u8 *bytes)
159{
160	return -EOPNOTSUPP;
161}
162
163static int igbvf_set_eeprom(struct net_device *netdev,
164			    struct ethtool_eeprom *eeprom, u8 *bytes)
165{
166	return -EOPNOTSUPP;
167}
168
169static void igbvf_get_drvinfo(struct net_device *netdev,
170			      struct ethtool_drvinfo *drvinfo)
171{
172	struct igbvf_adapter *adapter = netdev_priv(netdev);
173
174	strscpy(drvinfo->driver,  igbvf_driver_name, sizeof(drvinfo->driver));
175	strscpy(drvinfo->bus_info, pci_name(adapter->pdev),
176		sizeof(drvinfo->bus_info));
177}
178
179static void igbvf_get_ringparam(struct net_device *netdev,
180				struct ethtool_ringparam *ring,
181				struct kernel_ethtool_ringparam *kernel_ring,
182				struct netlink_ext_ack *extack)
183{
184	struct igbvf_adapter *adapter = netdev_priv(netdev);
185	struct igbvf_ring *tx_ring = adapter->tx_ring;
186	struct igbvf_ring *rx_ring = adapter->rx_ring;
187
188	ring->rx_max_pending = IGBVF_MAX_RXD;
189	ring->tx_max_pending = IGBVF_MAX_TXD;
190	ring->rx_pending = rx_ring->count;
191	ring->tx_pending = tx_ring->count;
192}
193
194static int igbvf_set_ringparam(struct net_device *netdev,
195			       struct ethtool_ringparam *ring,
196			       struct kernel_ethtool_ringparam *kernel_ring,
197			       struct netlink_ext_ack *extack)
198{
199	struct igbvf_adapter *adapter = netdev_priv(netdev);
200	struct igbvf_ring *temp_ring;
201	int err = 0;
202	u32 new_rx_count, new_tx_count;
203
204	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
205		return -EINVAL;
206
207	new_rx_count = max_t(u32, ring->rx_pending, IGBVF_MIN_RXD);
208	new_rx_count = min_t(u32, new_rx_count, IGBVF_MAX_RXD);
209	new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE);
210
211	new_tx_count = max_t(u32, ring->tx_pending, IGBVF_MIN_TXD);
212	new_tx_count = min_t(u32, new_tx_count, IGBVF_MAX_TXD);
213	new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
214
215	if ((new_tx_count == adapter->tx_ring->count) &&
216	    (new_rx_count == adapter->rx_ring->count)) {
217		/* nothing to do */
218		return 0;
219	}
220
221	while (test_and_set_bit(__IGBVF_RESETTING, &adapter->state))
222		usleep_range(1000, 2000);
223
224	if (!netif_running(adapter->netdev)) {
225		adapter->tx_ring->count = new_tx_count;
226		adapter->rx_ring->count = new_rx_count;
227		goto clear_reset;
228	}
229
230	temp_ring = vmalloc(sizeof(struct igbvf_ring));
231	if (!temp_ring) {
232		err = -ENOMEM;
233		goto clear_reset;
234	}
235
236	igbvf_down(adapter);
237
238	/* We can't just free everything and then setup again,
239	 * because the ISRs in MSI-X mode get passed pointers
240	 * to the Tx and Rx ring structs.
241	 */
242	if (new_tx_count != adapter->tx_ring->count) {
243		memcpy(temp_ring, adapter->tx_ring, sizeof(struct igbvf_ring));
244
245		temp_ring->count = new_tx_count;
246		err = igbvf_setup_tx_resources(adapter, temp_ring);
247		if (err)
248			goto err_setup;
249
250		igbvf_free_tx_resources(adapter->tx_ring);
251
252		memcpy(adapter->tx_ring, temp_ring, sizeof(struct igbvf_ring));
253	}
254
255	if (new_rx_count != adapter->rx_ring->count) {
256		memcpy(temp_ring, adapter->rx_ring, sizeof(struct igbvf_ring));
257
258		temp_ring->count = new_rx_count;
259		err = igbvf_setup_rx_resources(adapter, temp_ring);
260		if (err)
261			goto err_setup;
262
263		igbvf_free_rx_resources(adapter->rx_ring);
264
265		memcpy(adapter->rx_ring, temp_ring, sizeof(struct igbvf_ring));
266	}
267err_setup:
268	igbvf_up(adapter);
269	vfree(temp_ring);
270clear_reset:
271	clear_bit(__IGBVF_RESETTING, &adapter->state);
272	return err;
273}
274
275static int igbvf_link_test(struct igbvf_adapter *adapter, u64 *data)
276{
277	struct e1000_hw *hw = &adapter->hw;
278	*data = 0;
279
280	spin_lock_bh(&hw->mbx_lock);
281
282	hw->mac.ops.check_for_link(hw);
283
284	spin_unlock_bh(&hw->mbx_lock);
285
286	if (!(er32(STATUS) & E1000_STATUS_LU))
287		*data = 1;
288
289	return *data;
290}
291
292static void igbvf_diag_test(struct net_device *netdev,
293			    struct ethtool_test *eth_test, u64 *data)
294{
295	struct igbvf_adapter *adapter = netdev_priv(netdev);
296
297	set_bit(__IGBVF_TESTING, &adapter->state);
298
299	/* Link test performed before hardware reset so autoneg doesn't
300	 * interfere with test result
301	 */
302	if (igbvf_link_test(adapter, &data[0]))
303		eth_test->flags |= ETH_TEST_FL_FAILED;
304
305	clear_bit(__IGBVF_TESTING, &adapter->state);
306	msleep_interruptible(4 * 1000);
307}
308
309static void igbvf_get_wol(struct net_device *netdev,
310			  struct ethtool_wolinfo *wol)
311{
312	wol->supported = 0;
313	wol->wolopts = 0;
314}
315
316static int igbvf_set_wol(struct net_device *netdev,
317			 struct ethtool_wolinfo *wol)
318{
319	return -EOPNOTSUPP;
320}
321
322static int igbvf_get_coalesce(struct net_device *netdev,
323			      struct ethtool_coalesce *ec,
324			      struct kernel_ethtool_coalesce *kernel_coal,
325			      struct netlink_ext_ack *extack)
326{
327	struct igbvf_adapter *adapter = netdev_priv(netdev);
328
329	if (adapter->requested_itr <= 3)
330		ec->rx_coalesce_usecs = adapter->requested_itr;
331	else
332		ec->rx_coalesce_usecs = adapter->current_itr >> 2;
333
334	return 0;
335}
336
337static int igbvf_set_coalesce(struct net_device *netdev,
338			      struct ethtool_coalesce *ec,
339			      struct kernel_ethtool_coalesce *kernel_coal,
340			      struct netlink_ext_ack *extack)
341{
342	struct igbvf_adapter *adapter = netdev_priv(netdev);
343	struct e1000_hw *hw = &adapter->hw;
344
345	if ((ec->rx_coalesce_usecs >= IGBVF_MIN_ITR_USECS) &&
346	    (ec->rx_coalesce_usecs <= IGBVF_MAX_ITR_USECS)) {
347		adapter->current_itr = ec->rx_coalesce_usecs << 2;
348		adapter->requested_itr = 1000000000 /
349					(adapter->current_itr * 256);
350	} else if ((ec->rx_coalesce_usecs == 3) ||
351		   (ec->rx_coalesce_usecs == 2)) {
352		adapter->current_itr = IGBVF_START_ITR;
353		adapter->requested_itr = ec->rx_coalesce_usecs;
354	} else if (ec->rx_coalesce_usecs == 0) {
355		/* The user's desire is to turn off interrupt throttling
356		 * altogether, but due to HW limitations, we can't do that.
357		 * Instead we set a very small value in EITR, which would
358		 * allow ~967k interrupts per second, but allow the adapter's
359		 * internal clocking to still function properly.
360		 */
361		adapter->current_itr = 4;
362		adapter->requested_itr = 1000000000 /
363					(adapter->current_itr * 256);
364	} else {
365		return -EINVAL;
366	}
367
368	writel(adapter->current_itr,
369	       hw->hw_addr + adapter->rx_ring->itr_register);
370
371	return 0;
372}
373
374static int igbvf_nway_reset(struct net_device *netdev)
375{
376	struct igbvf_adapter *adapter = netdev_priv(netdev);
377
378	if (netif_running(netdev))
379		igbvf_reinit_locked(adapter);
380	return 0;
381}
382
383static void igbvf_get_ethtool_stats(struct net_device *netdev,
384				    struct ethtool_stats *stats,
385				    u64 *data)
386{
387	struct igbvf_adapter *adapter = netdev_priv(netdev);
388	int i;
389
390	igbvf_update_stats(adapter);
391	for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) {
392		char *p = (char *)adapter +
393			  igbvf_gstrings_stats[i].stat_offset;
394		char *b = (char *)adapter +
395			  igbvf_gstrings_stats[i].base_stat_offset;
396		data[i] = ((igbvf_gstrings_stats[i].sizeof_stat ==
397			    sizeof(u64)) ? (*(u64 *)p - *(u64 *)b) :
398			    (*(u32 *)p - *(u32 *)b));
399	}
400}
401
402static int igbvf_get_sset_count(struct net_device *dev, int stringset)
403{
404	switch (stringset) {
405	case ETH_SS_TEST:
406		return IGBVF_TEST_LEN;
407	case ETH_SS_STATS:
408		return IGBVF_GLOBAL_STATS_LEN;
409	default:
410		return -EINVAL;
411	}
412}
413
414static void igbvf_get_strings(struct net_device *netdev, u32 stringset,
415			      u8 *data)
416{
417	u8 *p = data;
418	int i;
419
420	switch (stringset) {
421	case ETH_SS_TEST:
422		memcpy(data, *igbvf_gstrings_test, sizeof(igbvf_gstrings_test));
423		break;
424	case ETH_SS_STATS:
425		for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) {
426			memcpy(p, igbvf_gstrings_stats[i].stat_string,
427			       ETH_GSTRING_LEN);
428			p += ETH_GSTRING_LEN;
429		}
430		break;
431	}
432}
433
434static const struct ethtool_ops igbvf_ethtool_ops = {
435	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS,
436	.get_drvinfo		= igbvf_get_drvinfo,
437	.get_regs_len		= igbvf_get_regs_len,
438	.get_regs		= igbvf_get_regs,
439	.get_wol		= igbvf_get_wol,
440	.set_wol		= igbvf_set_wol,
441	.get_msglevel		= igbvf_get_msglevel,
442	.set_msglevel		= igbvf_set_msglevel,
443	.nway_reset		= igbvf_nway_reset,
444	.get_link		= ethtool_op_get_link,
445	.get_eeprom_len		= igbvf_get_eeprom_len,
446	.get_eeprom		= igbvf_get_eeprom,
447	.set_eeprom		= igbvf_set_eeprom,
448	.get_ringparam		= igbvf_get_ringparam,
449	.set_ringparam		= igbvf_set_ringparam,
450	.get_pauseparam		= igbvf_get_pauseparam,
451	.set_pauseparam		= igbvf_set_pauseparam,
452	.self_test		= igbvf_diag_test,
453	.get_sset_count		= igbvf_get_sset_count,
454	.get_strings		= igbvf_get_strings,
455	.get_ethtool_stats	= igbvf_get_ethtool_stats,
456	.get_coalesce		= igbvf_get_coalesce,
457	.set_coalesce		= igbvf_set_coalesce,
458	.get_link_ksettings	= igbvf_get_link_ksettings,
459	.set_link_ksettings	= igbvf_set_link_ksettings,
460};
461
462void igbvf_set_ethtool_ops(struct net_device *netdev)
463{
464	netdev->ethtool_ops = &igbvf_ethtool_ops;
465}
~/ Read-only file preview.