162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2009 - 2018 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* ethtool support for igbvf */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/netdevice.h>
762306a36Sopenharmony_ci#include <linux/ethtool.h>
862306a36Sopenharmony_ci#include <linux/pci.h>
962306a36Sopenharmony_ci#include <linux/vmalloc.h>
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "igbvf.h"
1362306a36Sopenharmony_ci#include <linux/if_vlan.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct igbvf_stats {
1662306a36Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
1762306a36Sopenharmony_ci	int sizeof_stat;
1862306a36Sopenharmony_ci	int stat_offset;
1962306a36Sopenharmony_ci	int base_stat_offset;
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define IGBVF_STAT(current, base) \
2362306a36Sopenharmony_ci		sizeof(((struct igbvf_adapter *)0)->current), \
2462306a36Sopenharmony_ci		offsetof(struct igbvf_adapter, current), \
2562306a36Sopenharmony_ci		offsetof(struct igbvf_adapter, base)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const struct igbvf_stats igbvf_gstrings_stats[] = {
2862306a36Sopenharmony_ci	{ "rx_packets", IGBVF_STAT(stats.gprc, stats.base_gprc) },
2962306a36Sopenharmony_ci	{ "tx_packets", IGBVF_STAT(stats.gptc, stats.base_gptc) },
3062306a36Sopenharmony_ci	{ "rx_bytes", IGBVF_STAT(stats.gorc, stats.base_gorc) },
3162306a36Sopenharmony_ci	{ "tx_bytes", IGBVF_STAT(stats.gotc, stats.base_gotc) },
3262306a36Sopenharmony_ci	{ "multicast", IGBVF_STAT(stats.mprc, stats.base_mprc) },
3362306a36Sopenharmony_ci	{ "lbrx_bytes", IGBVF_STAT(stats.gorlbc, stats.base_gorlbc) },
3462306a36Sopenharmony_ci	{ "lbrx_packets", IGBVF_STAT(stats.gprlbc, stats.base_gprlbc) },
3562306a36Sopenharmony_ci	{ "tx_restart_queue", IGBVF_STAT(restart_queue, zero_base) },
3662306a36Sopenharmony_ci	{ "rx_long_byte_count", IGBVF_STAT(stats.gorc, stats.base_gorc) },
3762306a36Sopenharmony_ci	{ "rx_csum_offload_good", IGBVF_STAT(hw_csum_good, zero_base) },
3862306a36Sopenharmony_ci	{ "rx_csum_offload_errors", IGBVF_STAT(hw_csum_err, zero_base) },
3962306a36Sopenharmony_ci	{ "rx_header_split", IGBVF_STAT(rx_hdr_split, zero_base) },
4062306a36Sopenharmony_ci	{ "alloc_rx_buff_failed", IGBVF_STAT(alloc_rx_buff_failed, zero_base) },
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define IGBVF_GLOBAL_STATS_LEN ARRAY_SIZE(igbvf_gstrings_stats)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const char igbvf_gstrings_test[][ETH_GSTRING_LEN] = {
4662306a36Sopenharmony_ci	"Link test   (on/offline)"
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define IGBVF_TEST_LEN ARRAY_SIZE(igbvf_gstrings_test)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int igbvf_get_link_ksettings(struct net_device *netdev,
5262306a36Sopenharmony_ci				    struct ethtool_link_ksettings *cmd)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
5562306a36Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
5662306a36Sopenharmony_ci	u32 status;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(cmd, supported);
5962306a36Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full);
6062306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
6162306a36Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	cmd->base.port = -1;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	status = er32(STATUS);
6662306a36Sopenharmony_ci	if (status & E1000_STATUS_LU) {
6762306a36Sopenharmony_ci		if (status & E1000_STATUS_SPEED_1000)
6862306a36Sopenharmony_ci			cmd->base.speed = SPEED_1000;
6962306a36Sopenharmony_ci		else if (status & E1000_STATUS_SPEED_100)
7062306a36Sopenharmony_ci			cmd->base.speed = SPEED_100;
7162306a36Sopenharmony_ci		else
7262306a36Sopenharmony_ci			cmd->base.speed = SPEED_10;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		if (status & E1000_STATUS_FD)
7562306a36Sopenharmony_ci			cmd->base.duplex = DUPLEX_FULL;
7662306a36Sopenharmony_ci		else
7762306a36Sopenharmony_ci			cmd->base.duplex = DUPLEX_HALF;
7862306a36Sopenharmony_ci	} else {
7962306a36Sopenharmony_ci		cmd->base.speed = SPEED_UNKNOWN;
8062306a36Sopenharmony_ci		cmd->base.duplex = DUPLEX_UNKNOWN;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	cmd->base.autoneg = AUTONEG_DISABLE;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int igbvf_set_link_ksettings(struct net_device *netdev,
8962306a36Sopenharmony_ci				    const struct ethtool_link_ksettings *cmd)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	return -EOPNOTSUPP;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void igbvf_get_pauseparam(struct net_device *netdev,
9562306a36Sopenharmony_ci				 struct ethtool_pauseparam *pause)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int igbvf_set_pauseparam(struct net_device *netdev,
10062306a36Sopenharmony_ci				struct ethtool_pauseparam *pause)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	return -EOPNOTSUPP;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic u32 igbvf_get_msglevel(struct net_device *netdev)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return adapter->msg_enable;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void igbvf_set_msglevel(struct net_device *netdev, u32 data)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	adapter->msg_enable = data;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic int igbvf_get_regs_len(struct net_device *netdev)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci#define IGBVF_REGS_LEN 8
12262306a36Sopenharmony_ci	return IGBVF_REGS_LEN * sizeof(u32);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic void igbvf_get_regs(struct net_device *netdev,
12662306a36Sopenharmony_ci			   struct ethtool_regs *regs, void *p)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
12962306a36Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
13062306a36Sopenharmony_ci	u32 *regs_buff = p;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	memset(p, 0, IGBVF_REGS_LEN * sizeof(u32));
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	regs->version = (1u << 24) |
13562306a36Sopenharmony_ci			(adapter->pdev->revision << 16) |
13662306a36Sopenharmony_ci			adapter->pdev->device;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	regs_buff[0] = er32(CTRL);
13962306a36Sopenharmony_ci	regs_buff[1] = er32(STATUS);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	regs_buff[2] = er32(RDLEN(0));
14262306a36Sopenharmony_ci	regs_buff[3] = er32(RDH(0));
14362306a36Sopenharmony_ci	regs_buff[4] = er32(RDT(0));
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	regs_buff[5] = er32(TDLEN(0));
14662306a36Sopenharmony_ci	regs_buff[6] = er32(TDH(0));
14762306a36Sopenharmony_ci	regs_buff[7] = er32(TDT(0));
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int igbvf_get_eeprom_len(struct net_device *netdev)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int igbvf_get_eeprom(struct net_device *netdev,
15662306a36Sopenharmony_ci			    struct ethtool_eeprom *eeprom, u8 *bytes)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	return -EOPNOTSUPP;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int igbvf_set_eeprom(struct net_device *netdev,
16262306a36Sopenharmony_ci			    struct ethtool_eeprom *eeprom, u8 *bytes)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	return -EOPNOTSUPP;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic void igbvf_get_drvinfo(struct net_device *netdev,
16862306a36Sopenharmony_ci			      struct ethtool_drvinfo *drvinfo)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	strscpy(drvinfo->driver,  igbvf_driver_name, sizeof(drvinfo->driver));
17362306a36Sopenharmony_ci	strscpy(drvinfo->bus_info, pci_name(adapter->pdev),
17462306a36Sopenharmony_ci		sizeof(drvinfo->bus_info));
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void igbvf_get_ringparam(struct net_device *netdev,
17862306a36Sopenharmony_ci				struct ethtool_ringparam *ring,
17962306a36Sopenharmony_ci				struct kernel_ethtool_ringparam *kernel_ring,
18062306a36Sopenharmony_ci				struct netlink_ext_ack *extack)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
18362306a36Sopenharmony_ci	struct igbvf_ring *tx_ring = adapter->tx_ring;
18462306a36Sopenharmony_ci	struct igbvf_ring *rx_ring = adapter->rx_ring;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	ring->rx_max_pending = IGBVF_MAX_RXD;
18762306a36Sopenharmony_ci	ring->tx_max_pending = IGBVF_MAX_TXD;
18862306a36Sopenharmony_ci	ring->rx_pending = rx_ring->count;
18962306a36Sopenharmony_ci	ring->tx_pending = tx_ring->count;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int igbvf_set_ringparam(struct net_device *netdev,
19362306a36Sopenharmony_ci			       struct ethtool_ringparam *ring,
19462306a36Sopenharmony_ci			       struct kernel_ethtool_ringparam *kernel_ring,
19562306a36Sopenharmony_ci			       struct netlink_ext_ack *extack)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
19862306a36Sopenharmony_ci	struct igbvf_ring *temp_ring;
19962306a36Sopenharmony_ci	int err = 0;
20062306a36Sopenharmony_ci	u32 new_rx_count, new_tx_count;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
20362306a36Sopenharmony_ci		return -EINVAL;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	new_rx_count = max_t(u32, ring->rx_pending, IGBVF_MIN_RXD);
20662306a36Sopenharmony_ci	new_rx_count = min_t(u32, new_rx_count, IGBVF_MAX_RXD);
20762306a36Sopenharmony_ci	new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	new_tx_count = max_t(u32, ring->tx_pending, IGBVF_MIN_TXD);
21062306a36Sopenharmony_ci	new_tx_count = min_t(u32, new_tx_count, IGBVF_MAX_TXD);
21162306a36Sopenharmony_ci	new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if ((new_tx_count == adapter->tx_ring->count) &&
21462306a36Sopenharmony_ci	    (new_rx_count == adapter->rx_ring->count)) {
21562306a36Sopenharmony_ci		/* nothing to do */
21662306a36Sopenharmony_ci		return 0;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	while (test_and_set_bit(__IGBVF_RESETTING, &adapter->state))
22062306a36Sopenharmony_ci		usleep_range(1000, 2000);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (!netif_running(adapter->netdev)) {
22362306a36Sopenharmony_ci		adapter->tx_ring->count = new_tx_count;
22462306a36Sopenharmony_ci		adapter->rx_ring->count = new_rx_count;
22562306a36Sopenharmony_ci		goto clear_reset;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	temp_ring = vmalloc(sizeof(struct igbvf_ring));
22962306a36Sopenharmony_ci	if (!temp_ring) {
23062306a36Sopenharmony_ci		err = -ENOMEM;
23162306a36Sopenharmony_ci		goto clear_reset;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	igbvf_down(adapter);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* We can't just free everything and then setup again,
23762306a36Sopenharmony_ci	 * because the ISRs in MSI-X mode get passed pointers
23862306a36Sopenharmony_ci	 * to the Tx and Rx ring structs.
23962306a36Sopenharmony_ci	 */
24062306a36Sopenharmony_ci	if (new_tx_count != adapter->tx_ring->count) {
24162306a36Sopenharmony_ci		memcpy(temp_ring, adapter->tx_ring, sizeof(struct igbvf_ring));
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		temp_ring->count = new_tx_count;
24462306a36Sopenharmony_ci		err = igbvf_setup_tx_resources(adapter, temp_ring);
24562306a36Sopenharmony_ci		if (err)
24662306a36Sopenharmony_ci			goto err_setup;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		igbvf_free_tx_resources(adapter->tx_ring);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		memcpy(adapter->tx_ring, temp_ring, sizeof(struct igbvf_ring));
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (new_rx_count != adapter->rx_ring->count) {
25462306a36Sopenharmony_ci		memcpy(temp_ring, adapter->rx_ring, sizeof(struct igbvf_ring));
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		temp_ring->count = new_rx_count;
25762306a36Sopenharmony_ci		err = igbvf_setup_rx_resources(adapter, temp_ring);
25862306a36Sopenharmony_ci		if (err)
25962306a36Sopenharmony_ci			goto err_setup;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		igbvf_free_rx_resources(adapter->rx_ring);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		memcpy(adapter->rx_ring, temp_ring, sizeof(struct igbvf_ring));
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_cierr_setup:
26662306a36Sopenharmony_ci	igbvf_up(adapter);
26762306a36Sopenharmony_ci	vfree(temp_ring);
26862306a36Sopenharmony_ciclear_reset:
26962306a36Sopenharmony_ci	clear_bit(__IGBVF_RESETTING, &adapter->state);
27062306a36Sopenharmony_ci	return err;
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic int igbvf_link_test(struct igbvf_adapter *adapter, u64 *data)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
27662306a36Sopenharmony_ci	*data = 0;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	spin_lock_bh(&hw->mbx_lock);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	hw->mac.ops.check_for_link(hw);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	spin_unlock_bh(&hw->mbx_lock);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (!(er32(STATUS) & E1000_STATUS_LU))
28562306a36Sopenharmony_ci		*data = 1;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return *data;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic void igbvf_diag_test(struct net_device *netdev,
29162306a36Sopenharmony_ci			    struct ethtool_test *eth_test, u64 *data)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	set_bit(__IGBVF_TESTING, &adapter->state);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* Link test performed before hardware reset so autoneg doesn't
29862306a36Sopenharmony_ci	 * interfere with test result
29962306a36Sopenharmony_ci	 */
30062306a36Sopenharmony_ci	if (igbvf_link_test(adapter, &data[0]))
30162306a36Sopenharmony_ci		eth_test->flags |= ETH_TEST_FL_FAILED;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	clear_bit(__IGBVF_TESTING, &adapter->state);
30462306a36Sopenharmony_ci	msleep_interruptible(4 * 1000);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic void igbvf_get_wol(struct net_device *netdev,
30862306a36Sopenharmony_ci			  struct ethtool_wolinfo *wol)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	wol->supported = 0;
31162306a36Sopenharmony_ci	wol->wolopts = 0;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int igbvf_set_wol(struct net_device *netdev,
31562306a36Sopenharmony_ci			 struct ethtool_wolinfo *wol)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	return -EOPNOTSUPP;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int igbvf_get_coalesce(struct net_device *netdev,
32162306a36Sopenharmony_ci			      struct ethtool_coalesce *ec,
32262306a36Sopenharmony_ci			      struct kernel_ethtool_coalesce *kernel_coal,
32362306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (adapter->requested_itr <= 3)
32862306a36Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->requested_itr;
32962306a36Sopenharmony_ci	else
33062306a36Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->current_itr >> 2;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int igbvf_set_coalesce(struct net_device *netdev,
33662306a36Sopenharmony_ci			      struct ethtool_coalesce *ec,
33762306a36Sopenharmony_ci			      struct kernel_ethtool_coalesce *kernel_coal,
33862306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
34162306a36Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if ((ec->rx_coalesce_usecs >= IGBVF_MIN_ITR_USECS) &&
34462306a36Sopenharmony_ci	    (ec->rx_coalesce_usecs <= IGBVF_MAX_ITR_USECS)) {
34562306a36Sopenharmony_ci		adapter->current_itr = ec->rx_coalesce_usecs << 2;
34662306a36Sopenharmony_ci		adapter->requested_itr = 1000000000 /
34762306a36Sopenharmony_ci					(adapter->current_itr * 256);
34862306a36Sopenharmony_ci	} else if ((ec->rx_coalesce_usecs == 3) ||
34962306a36Sopenharmony_ci		   (ec->rx_coalesce_usecs == 2)) {
35062306a36Sopenharmony_ci		adapter->current_itr = IGBVF_START_ITR;
35162306a36Sopenharmony_ci		adapter->requested_itr = ec->rx_coalesce_usecs;
35262306a36Sopenharmony_ci	} else if (ec->rx_coalesce_usecs == 0) {
35362306a36Sopenharmony_ci		/* The user's desire is to turn off interrupt throttling
35462306a36Sopenharmony_ci		 * altogether, but due to HW limitations, we can't do that.
35562306a36Sopenharmony_ci		 * Instead we set a very small value in EITR, which would
35662306a36Sopenharmony_ci		 * allow ~967k interrupts per second, but allow the adapter's
35762306a36Sopenharmony_ci		 * internal clocking to still function properly.
35862306a36Sopenharmony_ci		 */
35962306a36Sopenharmony_ci		adapter->current_itr = 4;
36062306a36Sopenharmony_ci		adapter->requested_itr = 1000000000 /
36162306a36Sopenharmony_ci					(adapter->current_itr * 256);
36262306a36Sopenharmony_ci	} else {
36362306a36Sopenharmony_ci		return -EINVAL;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	writel(adapter->current_itr,
36762306a36Sopenharmony_ci	       hw->hw_addr + adapter->rx_ring->itr_register);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return 0;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int igbvf_nway_reset(struct net_device *netdev)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (netif_running(netdev))
37762306a36Sopenharmony_ci		igbvf_reinit_locked(adapter);
37862306a36Sopenharmony_ci	return 0;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic void igbvf_get_ethtool_stats(struct net_device *netdev,
38262306a36Sopenharmony_ci				    struct ethtool_stats *stats,
38362306a36Sopenharmony_ci				    u64 *data)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct igbvf_adapter *adapter = netdev_priv(netdev);
38662306a36Sopenharmony_ci	int i;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	igbvf_update_stats(adapter);
38962306a36Sopenharmony_ci	for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) {
39062306a36Sopenharmony_ci		char *p = (char *)adapter +
39162306a36Sopenharmony_ci			  igbvf_gstrings_stats[i].stat_offset;
39262306a36Sopenharmony_ci		char *b = (char *)adapter +
39362306a36Sopenharmony_ci			  igbvf_gstrings_stats[i].base_stat_offset;
39462306a36Sopenharmony_ci		data[i] = ((igbvf_gstrings_stats[i].sizeof_stat ==
39562306a36Sopenharmony_ci			    sizeof(u64)) ? (*(u64 *)p - *(u64 *)b) :
39662306a36Sopenharmony_ci			    (*(u32 *)p - *(u32 *)b));
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic int igbvf_get_sset_count(struct net_device *dev, int stringset)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	switch (stringset) {
40362306a36Sopenharmony_ci	case ETH_SS_TEST:
40462306a36Sopenharmony_ci		return IGBVF_TEST_LEN;
40562306a36Sopenharmony_ci	case ETH_SS_STATS:
40662306a36Sopenharmony_ci		return IGBVF_GLOBAL_STATS_LEN;
40762306a36Sopenharmony_ci	default:
40862306a36Sopenharmony_ci		return -EINVAL;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic void igbvf_get_strings(struct net_device *netdev, u32 stringset,
41362306a36Sopenharmony_ci			      u8 *data)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	u8 *p = data;
41662306a36Sopenharmony_ci	int i;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	switch (stringset) {
41962306a36Sopenharmony_ci	case ETH_SS_TEST:
42062306a36Sopenharmony_ci		memcpy(data, *igbvf_gstrings_test, sizeof(igbvf_gstrings_test));
42162306a36Sopenharmony_ci		break;
42262306a36Sopenharmony_ci	case ETH_SS_STATS:
42362306a36Sopenharmony_ci		for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) {
42462306a36Sopenharmony_ci			memcpy(p, igbvf_gstrings_stats[i].stat_string,
42562306a36Sopenharmony_ci			       ETH_GSTRING_LEN);
42662306a36Sopenharmony_ci			p += ETH_GSTRING_LEN;
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci		break;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic const struct ethtool_ops igbvf_ethtool_ops = {
43362306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS,
43462306a36Sopenharmony_ci	.get_drvinfo		= igbvf_get_drvinfo,
43562306a36Sopenharmony_ci	.get_regs_len		= igbvf_get_regs_len,
43662306a36Sopenharmony_ci	.get_regs		= igbvf_get_regs,
43762306a36Sopenharmony_ci	.get_wol		= igbvf_get_wol,
43862306a36Sopenharmony_ci	.set_wol		= igbvf_set_wol,
43962306a36Sopenharmony_ci	.get_msglevel		= igbvf_get_msglevel,
44062306a36Sopenharmony_ci	.set_msglevel		= igbvf_set_msglevel,
44162306a36Sopenharmony_ci	.nway_reset		= igbvf_nway_reset,
44262306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
44362306a36Sopenharmony_ci	.get_eeprom_len		= igbvf_get_eeprom_len,
44462306a36Sopenharmony_ci	.get_eeprom		= igbvf_get_eeprom,
44562306a36Sopenharmony_ci	.set_eeprom		= igbvf_set_eeprom,
44662306a36Sopenharmony_ci	.get_ringparam		= igbvf_get_ringparam,
44762306a36Sopenharmony_ci	.set_ringparam		= igbvf_set_ringparam,
44862306a36Sopenharmony_ci	.get_pauseparam		= igbvf_get_pauseparam,
44962306a36Sopenharmony_ci	.set_pauseparam		= igbvf_set_pauseparam,
45062306a36Sopenharmony_ci	.self_test		= igbvf_diag_test,
45162306a36Sopenharmony_ci	.get_sset_count		= igbvf_get_sset_count,
45262306a36Sopenharmony_ci	.get_strings		= igbvf_get_strings,
45362306a36Sopenharmony_ci	.get_ethtool_stats	= igbvf_get_ethtool_stats,
45462306a36Sopenharmony_ci	.get_coalesce		= igbvf_get_coalesce,
45562306a36Sopenharmony_ci	.set_coalesce		= igbvf_set_coalesce,
45662306a36Sopenharmony_ci	.get_link_ksettings	= igbvf_get_link_ksettings,
45762306a36Sopenharmony_ci	.set_link_ksettings	= igbvf_set_link_ksettings,
45862306a36Sopenharmony_ci};
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_civoid igbvf_set_ethtool_ops(struct net_device *netdev)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	netdev->ethtool_ops = &igbvf_ethtool_ops;
46362306a36Sopenharmony_ci}
464