162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* ethtool support for ixgbe */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/interrupt.h>
762306a36Sopenharmony_ci#include <linux/types.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/pci.h>
1162306a36Sopenharmony_ci#include <linux/netdevice.h>
1262306a36Sopenharmony_ci#include <linux/ethtool.h>
1362306a36Sopenharmony_ci#include <linux/vmalloc.h>
1462306a36Sopenharmony_ci#include <linux/highmem.h>
1562306a36Sopenharmony_ci#include <linux/uaccess.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "ixgbe.h"
1862306a36Sopenharmony_ci#include "ixgbe_phy.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cienum {NETDEV_STATS, IXGBE_STATS};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct ixgbe_stats {
2462306a36Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
2562306a36Sopenharmony_ci	int type;
2662306a36Sopenharmony_ci	int sizeof_stat;
2762306a36Sopenharmony_ci	int stat_offset;
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define IXGBE_STAT(m)		IXGBE_STATS, \
3162306a36Sopenharmony_ci				sizeof(((struct ixgbe_adapter *)0)->m), \
3262306a36Sopenharmony_ci				offsetof(struct ixgbe_adapter, m)
3362306a36Sopenharmony_ci#define IXGBE_NETDEV_STAT(m)	NETDEV_STATS, \
3462306a36Sopenharmony_ci				sizeof(((struct rtnl_link_stats64 *)0)->m), \
3562306a36Sopenharmony_ci				offsetof(struct rtnl_link_stats64, m)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const struct ixgbe_stats ixgbe_gstrings_stats[] = {
3862306a36Sopenharmony_ci	{"rx_packets", IXGBE_NETDEV_STAT(rx_packets)},
3962306a36Sopenharmony_ci	{"tx_packets", IXGBE_NETDEV_STAT(tx_packets)},
4062306a36Sopenharmony_ci	{"rx_bytes", IXGBE_NETDEV_STAT(rx_bytes)},
4162306a36Sopenharmony_ci	{"tx_bytes", IXGBE_NETDEV_STAT(tx_bytes)},
4262306a36Sopenharmony_ci	{"rx_pkts_nic", IXGBE_STAT(stats.gprc)},
4362306a36Sopenharmony_ci	{"tx_pkts_nic", IXGBE_STAT(stats.gptc)},
4462306a36Sopenharmony_ci	{"rx_bytes_nic", IXGBE_STAT(stats.gorc)},
4562306a36Sopenharmony_ci	{"tx_bytes_nic", IXGBE_STAT(stats.gotc)},
4662306a36Sopenharmony_ci	{"lsc_int", IXGBE_STAT(lsc_int)},
4762306a36Sopenharmony_ci	{"tx_busy", IXGBE_STAT(tx_busy)},
4862306a36Sopenharmony_ci	{"non_eop_descs", IXGBE_STAT(non_eop_descs)},
4962306a36Sopenharmony_ci	{"rx_errors", IXGBE_NETDEV_STAT(rx_errors)},
5062306a36Sopenharmony_ci	{"tx_errors", IXGBE_NETDEV_STAT(tx_errors)},
5162306a36Sopenharmony_ci	{"rx_dropped", IXGBE_NETDEV_STAT(rx_dropped)},
5262306a36Sopenharmony_ci	{"tx_dropped", IXGBE_NETDEV_STAT(tx_dropped)},
5362306a36Sopenharmony_ci	{"multicast", IXGBE_NETDEV_STAT(multicast)},
5462306a36Sopenharmony_ci	{"broadcast", IXGBE_STAT(stats.bprc)},
5562306a36Sopenharmony_ci	{"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
5662306a36Sopenharmony_ci	{"collisions", IXGBE_NETDEV_STAT(collisions)},
5762306a36Sopenharmony_ci	{"rx_over_errors", IXGBE_NETDEV_STAT(rx_over_errors)},
5862306a36Sopenharmony_ci	{"rx_crc_errors", IXGBE_NETDEV_STAT(rx_crc_errors)},
5962306a36Sopenharmony_ci	{"rx_frame_errors", IXGBE_NETDEV_STAT(rx_frame_errors)},
6062306a36Sopenharmony_ci	{"hw_rsc_aggregated", IXGBE_STAT(rsc_total_count)},
6162306a36Sopenharmony_ci	{"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)},
6262306a36Sopenharmony_ci	{"fdir_match", IXGBE_STAT(stats.fdirmatch)},
6362306a36Sopenharmony_ci	{"fdir_miss", IXGBE_STAT(stats.fdirmiss)},
6462306a36Sopenharmony_ci	{"fdir_overflow", IXGBE_STAT(fdir_overflow)},
6562306a36Sopenharmony_ci	{"rx_fifo_errors", IXGBE_NETDEV_STAT(rx_fifo_errors)},
6662306a36Sopenharmony_ci	{"rx_missed_errors", IXGBE_NETDEV_STAT(rx_missed_errors)},
6762306a36Sopenharmony_ci	{"tx_aborted_errors", IXGBE_NETDEV_STAT(tx_aborted_errors)},
6862306a36Sopenharmony_ci	{"tx_carrier_errors", IXGBE_NETDEV_STAT(tx_carrier_errors)},
6962306a36Sopenharmony_ci	{"tx_fifo_errors", IXGBE_NETDEV_STAT(tx_fifo_errors)},
7062306a36Sopenharmony_ci	{"tx_heartbeat_errors", IXGBE_NETDEV_STAT(tx_heartbeat_errors)},
7162306a36Sopenharmony_ci	{"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
7262306a36Sopenharmony_ci	{"tx_restart_queue", IXGBE_STAT(restart_queue)},
7362306a36Sopenharmony_ci	{"rx_length_errors", IXGBE_STAT(stats.rlec)},
7462306a36Sopenharmony_ci	{"rx_long_length_errors", IXGBE_STAT(stats.roc)},
7562306a36Sopenharmony_ci	{"rx_short_length_errors", IXGBE_STAT(stats.ruc)},
7662306a36Sopenharmony_ci	{"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)},
7762306a36Sopenharmony_ci	{"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)},
7862306a36Sopenharmony_ci	{"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)},
7962306a36Sopenharmony_ci	{"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)},
8062306a36Sopenharmony_ci	{"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)},
8162306a36Sopenharmony_ci	{"alloc_rx_page", IXGBE_STAT(alloc_rx_page)},
8262306a36Sopenharmony_ci	{"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
8362306a36Sopenharmony_ci	{"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
8462306a36Sopenharmony_ci	{"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)},
8562306a36Sopenharmony_ci	{"os2bmc_rx_by_bmc", IXGBE_STAT(stats.o2bgptc)},
8662306a36Sopenharmony_ci	{"os2bmc_tx_by_bmc", IXGBE_STAT(stats.b2ospc)},
8762306a36Sopenharmony_ci	{"os2bmc_tx_by_host", IXGBE_STAT(stats.o2bspc)},
8862306a36Sopenharmony_ci	{"os2bmc_rx_by_host", IXGBE_STAT(stats.b2ogprc)},
8962306a36Sopenharmony_ci	{"tx_hwtstamp_timeouts", IXGBE_STAT(tx_hwtstamp_timeouts)},
9062306a36Sopenharmony_ci	{"tx_hwtstamp_skipped", IXGBE_STAT(tx_hwtstamp_skipped)},
9162306a36Sopenharmony_ci	{"rx_hwtstamp_cleared", IXGBE_STAT(rx_hwtstamp_cleared)},
9262306a36Sopenharmony_ci	{"tx_ipsec", IXGBE_STAT(tx_ipsec)},
9362306a36Sopenharmony_ci	{"rx_ipsec", IXGBE_STAT(rx_ipsec)},
9462306a36Sopenharmony_ci#ifdef IXGBE_FCOE
9562306a36Sopenharmony_ci	{"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)},
9662306a36Sopenharmony_ci	{"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)},
9762306a36Sopenharmony_ci	{"rx_fcoe_packets", IXGBE_STAT(stats.fcoeprc)},
9862306a36Sopenharmony_ci	{"rx_fcoe_dwords", IXGBE_STAT(stats.fcoedwrc)},
9962306a36Sopenharmony_ci	{"fcoe_noddp", IXGBE_STAT(stats.fcoe_noddp)},
10062306a36Sopenharmony_ci	{"fcoe_noddp_ext_buff", IXGBE_STAT(stats.fcoe_noddp_ext_buff)},
10162306a36Sopenharmony_ci	{"tx_fcoe_packets", IXGBE_STAT(stats.fcoeptc)},
10262306a36Sopenharmony_ci	{"tx_fcoe_dwords", IXGBE_STAT(stats.fcoedwtc)},
10362306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* ixgbe allocates num_tx_queues and num_rx_queues symmetrically so
10762306a36Sopenharmony_ci * we set the num_rx_queues to evaluate to num_tx_queues. This is
10862306a36Sopenharmony_ci * used because we do not have a good way to get the max number of
10962306a36Sopenharmony_ci * rx queues with CONFIG_RPS disabled.
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_ci#define IXGBE_NUM_RX_QUEUES netdev->num_tx_queues
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define IXGBE_QUEUE_STATS_LEN ( \
11462306a36Sopenharmony_ci	(netdev->num_tx_queues + IXGBE_NUM_RX_QUEUES) * \
11562306a36Sopenharmony_ci	(sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
11662306a36Sopenharmony_ci#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats)
11762306a36Sopenharmony_ci#define IXGBE_PB_STATS_LEN ( \
11862306a36Sopenharmony_ci			(sizeof(((struct ixgbe_adapter *)0)->stats.pxonrxc) + \
11962306a36Sopenharmony_ci			 sizeof(((struct ixgbe_adapter *)0)->stats.pxontxc) + \
12062306a36Sopenharmony_ci			 sizeof(((struct ixgbe_adapter *)0)->stats.pxoffrxc) + \
12162306a36Sopenharmony_ci			 sizeof(((struct ixgbe_adapter *)0)->stats.pxofftxc)) \
12262306a36Sopenharmony_ci			/ sizeof(u64))
12362306a36Sopenharmony_ci#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + \
12462306a36Sopenharmony_ci			 IXGBE_PB_STATS_LEN + \
12562306a36Sopenharmony_ci			 IXGBE_QUEUE_STATS_LEN)
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
12862306a36Sopenharmony_ci	"Register test  (offline)", "Eeprom test    (offline)",
12962306a36Sopenharmony_ci	"Interrupt test (offline)", "Loopback test  (offline)",
13062306a36Sopenharmony_ci	"Link test   (on/offline)"
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci#define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic const char ixgbe_priv_flags_strings[][ETH_GSTRING_LEN] = {
13562306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_LEGACY_RX	BIT(0)
13662306a36Sopenharmony_ci	"legacy-rx",
13762306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_VF_IPSEC_EN	BIT(1)
13862306a36Sopenharmony_ci	"vf-ipsec",
13962306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF	BIT(2)
14062306a36Sopenharmony_ci	"mdd-disable-vf",
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbe_priv_flags_strings)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define ixgbe_isbackplane(type) ((type) == ixgbe_media_type_backplane)
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void ixgbe_set_supported_10gtypes(struct ixgbe_hw *hw,
14862306a36Sopenharmony_ci					 struct ethtool_link_ksettings *cmd)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	if (!ixgbe_isbackplane(hw->phy.media_type)) {
15162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported,
15262306a36Sopenharmony_ci						     10000baseT_Full);
15362306a36Sopenharmony_ci		return;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	switch (hw->device_id) {
15762306a36Sopenharmony_ci	case IXGBE_DEV_ID_82598:
15862306a36Sopenharmony_ci	case IXGBE_DEV_ID_82599_KX4:
15962306a36Sopenharmony_ci	case IXGBE_DEV_ID_82599_KX4_MEZZ:
16062306a36Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_X_KX4:
16162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
16262306a36Sopenharmony_ci			(cmd, supported, 10000baseKX4_Full);
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	case IXGBE_DEV_ID_82598_BX:
16562306a36Sopenharmony_ci	case IXGBE_DEV_ID_82599_KR:
16662306a36Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_X_KR:
16762306a36Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_X_XFI:
16862306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
16962306a36Sopenharmony_ci			(cmd, supported, 10000baseKR_Full);
17062306a36Sopenharmony_ci		break;
17162306a36Sopenharmony_ci	default:
17262306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
17362306a36Sopenharmony_ci			(cmd, supported, 10000baseKX4_Full);
17462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
17562306a36Sopenharmony_ci			(cmd, supported, 10000baseKR_Full);
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic void ixgbe_set_advertising_10gtypes(struct ixgbe_hw *hw,
18162306a36Sopenharmony_ci					   struct ethtool_link_ksettings *cmd)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	if (!ixgbe_isbackplane(hw->phy.media_type)) {
18462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
18562306a36Sopenharmony_ci						     10000baseT_Full);
18662306a36Sopenharmony_ci		return;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	switch (hw->device_id) {
19062306a36Sopenharmony_ci	case IXGBE_DEV_ID_82598:
19162306a36Sopenharmony_ci	case IXGBE_DEV_ID_82599_KX4:
19262306a36Sopenharmony_ci	case IXGBE_DEV_ID_82599_KX4_MEZZ:
19362306a36Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_X_KX4:
19462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
19562306a36Sopenharmony_ci			(cmd, advertising, 10000baseKX4_Full);
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci	case IXGBE_DEV_ID_82598_BX:
19862306a36Sopenharmony_ci	case IXGBE_DEV_ID_82599_KR:
19962306a36Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_X_KR:
20062306a36Sopenharmony_ci	case IXGBE_DEV_ID_X550EM_X_XFI:
20162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
20262306a36Sopenharmony_ci			(cmd, advertising, 10000baseKR_Full);
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	default:
20562306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
20662306a36Sopenharmony_ci			(cmd, advertising, 10000baseKX4_Full);
20762306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode
20862306a36Sopenharmony_ci			(cmd, advertising, 10000baseKR_Full);
20962306a36Sopenharmony_ci		break;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int ixgbe_get_link_ksettings(struct net_device *netdev,
21462306a36Sopenharmony_ci				    struct ethtool_link_ksettings *cmd)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
21762306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
21862306a36Sopenharmony_ci	ixgbe_link_speed supported_link;
21962306a36Sopenharmony_ci	bool autoneg = false;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(cmd, supported);
22262306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	hw->mac.ops.get_link_capabilities(hw, &supported_link, &autoneg);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* set the supported link speeds */
22762306a36Sopenharmony_ci	if (supported_link & IXGBE_LINK_SPEED_10GB_FULL) {
22862306a36Sopenharmony_ci		ixgbe_set_supported_10gtypes(hw, cmd);
22962306a36Sopenharmony_ci		ixgbe_set_advertising_10gtypes(hw, cmd);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	if (supported_link & IXGBE_LINK_SPEED_5GB_FULL)
23262306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported,
23362306a36Sopenharmony_ci						     5000baseT_Full);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (supported_link & IXGBE_LINK_SPEED_2_5GB_FULL)
23662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported,
23762306a36Sopenharmony_ci						     2500baseT_Full);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (supported_link & IXGBE_LINK_SPEED_1GB_FULL) {
24062306a36Sopenharmony_ci		if (ixgbe_isbackplane(hw->phy.media_type)) {
24162306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, supported,
24262306a36Sopenharmony_ci							     1000baseKX_Full);
24362306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
24462306a36Sopenharmony_ci							     1000baseKX_Full);
24562306a36Sopenharmony_ci		} else {
24662306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, supported,
24762306a36Sopenharmony_ci							     1000baseT_Full);
24862306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
24962306a36Sopenharmony_ci							     1000baseT_Full);
25062306a36Sopenharmony_ci		}
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci	if (supported_link & IXGBE_LINK_SPEED_100_FULL) {
25362306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported,
25462306a36Sopenharmony_ci						     100baseT_Full);
25562306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
25662306a36Sopenharmony_ci						     100baseT_Full);
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci	if (supported_link & IXGBE_LINK_SPEED_10_FULL) {
25962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported,
26062306a36Sopenharmony_ci						     10baseT_Full);
26162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
26262306a36Sopenharmony_ci						     10baseT_Full);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* set the advertised speeds */
26662306a36Sopenharmony_ci	if (hw->phy.autoneg_advertised) {
26762306a36Sopenharmony_ci		ethtool_link_ksettings_zero_link_mode(cmd, advertising);
26862306a36Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL)
26962306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
27062306a36Sopenharmony_ci							     10baseT_Full);
27162306a36Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
27262306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
27362306a36Sopenharmony_ci							     100baseT_Full);
27462306a36Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
27562306a36Sopenharmony_ci			ixgbe_set_advertising_10gtypes(hw, cmd);
27662306a36Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
27762306a36Sopenharmony_ci			if (ethtool_link_ksettings_test_link_mode
27862306a36Sopenharmony_ci				(cmd, supported, 1000baseKX_Full))
27962306a36Sopenharmony_ci				ethtool_link_ksettings_add_link_mode
28062306a36Sopenharmony_ci					(cmd, advertising, 1000baseKX_Full);
28162306a36Sopenharmony_ci			else
28262306a36Sopenharmony_ci				ethtool_link_ksettings_add_link_mode
28362306a36Sopenharmony_ci					(cmd, advertising, 1000baseT_Full);
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL)
28662306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
28762306a36Sopenharmony_ci							     5000baseT_Full);
28862306a36Sopenharmony_ci		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL)
28962306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
29062306a36Sopenharmony_ci							     2500baseT_Full);
29162306a36Sopenharmony_ci	} else {
29262306a36Sopenharmony_ci		if (hw->phy.multispeed_fiber && !autoneg) {
29362306a36Sopenharmony_ci			if (supported_link & IXGBE_LINK_SPEED_10GB_FULL)
29462306a36Sopenharmony_ci				ethtool_link_ksettings_add_link_mode
29562306a36Sopenharmony_ci					(cmd, advertising, 10000baseT_Full);
29662306a36Sopenharmony_ci		}
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (autoneg) {
30062306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
30162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
30262306a36Sopenharmony_ci		cmd->base.autoneg = AUTONEG_ENABLE;
30362306a36Sopenharmony_ci	} else
30462306a36Sopenharmony_ci		cmd->base.autoneg = AUTONEG_DISABLE;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Determine the remaining settings based on the PHY type. */
30762306a36Sopenharmony_ci	switch (adapter->hw.phy.type) {
30862306a36Sopenharmony_ci	case ixgbe_phy_tn:
30962306a36Sopenharmony_ci	case ixgbe_phy_aq:
31062306a36Sopenharmony_ci	case ixgbe_phy_x550em_ext_t:
31162306a36Sopenharmony_ci	case ixgbe_phy_fw:
31262306a36Sopenharmony_ci	case ixgbe_phy_cu_unknown:
31362306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
31462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
31562306a36Sopenharmony_ci		cmd->base.port = PORT_TP;
31662306a36Sopenharmony_ci		break;
31762306a36Sopenharmony_ci	case ixgbe_phy_qt:
31862306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
31962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
32062306a36Sopenharmony_ci		cmd->base.port = PORT_FIBRE;
32162306a36Sopenharmony_ci		break;
32262306a36Sopenharmony_ci	case ixgbe_phy_nl:
32362306a36Sopenharmony_ci	case ixgbe_phy_sfp_passive_tyco:
32462306a36Sopenharmony_ci	case ixgbe_phy_sfp_passive_unknown:
32562306a36Sopenharmony_ci	case ixgbe_phy_sfp_ftl:
32662306a36Sopenharmony_ci	case ixgbe_phy_sfp_avago:
32762306a36Sopenharmony_ci	case ixgbe_phy_sfp_intel:
32862306a36Sopenharmony_ci	case ixgbe_phy_sfp_unknown:
32962306a36Sopenharmony_ci	case ixgbe_phy_qsfp_passive_unknown:
33062306a36Sopenharmony_ci	case ixgbe_phy_qsfp_active_unknown:
33162306a36Sopenharmony_ci	case ixgbe_phy_qsfp_intel:
33262306a36Sopenharmony_ci	case ixgbe_phy_qsfp_unknown:
33362306a36Sopenharmony_ci		/* SFP+ devices, further checking needed */
33462306a36Sopenharmony_ci		switch (adapter->hw.phy.sfp_type) {
33562306a36Sopenharmony_ci		case ixgbe_sfp_type_da_cu:
33662306a36Sopenharmony_ci		case ixgbe_sfp_type_da_cu_core0:
33762306a36Sopenharmony_ci		case ixgbe_sfp_type_da_cu_core1:
33862306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, supported,
33962306a36Sopenharmony_ci							     FIBRE);
34062306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
34162306a36Sopenharmony_ci							     FIBRE);
34262306a36Sopenharmony_ci			cmd->base.port = PORT_DA;
34362306a36Sopenharmony_ci			break;
34462306a36Sopenharmony_ci		case ixgbe_sfp_type_sr:
34562306a36Sopenharmony_ci		case ixgbe_sfp_type_lr:
34662306a36Sopenharmony_ci		case ixgbe_sfp_type_srlr_core0:
34762306a36Sopenharmony_ci		case ixgbe_sfp_type_srlr_core1:
34862306a36Sopenharmony_ci		case ixgbe_sfp_type_1g_sx_core0:
34962306a36Sopenharmony_ci		case ixgbe_sfp_type_1g_sx_core1:
35062306a36Sopenharmony_ci		case ixgbe_sfp_type_1g_lx_core0:
35162306a36Sopenharmony_ci		case ixgbe_sfp_type_1g_lx_core1:
35262306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, supported,
35362306a36Sopenharmony_ci							     FIBRE);
35462306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
35562306a36Sopenharmony_ci							     FIBRE);
35662306a36Sopenharmony_ci			cmd->base.port = PORT_FIBRE;
35762306a36Sopenharmony_ci			break;
35862306a36Sopenharmony_ci		case ixgbe_sfp_type_not_present:
35962306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, supported,
36062306a36Sopenharmony_ci							     FIBRE);
36162306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
36262306a36Sopenharmony_ci							     FIBRE);
36362306a36Sopenharmony_ci			cmd->base.port = PORT_NONE;
36462306a36Sopenharmony_ci			break;
36562306a36Sopenharmony_ci		case ixgbe_sfp_type_1g_cu_core0:
36662306a36Sopenharmony_ci		case ixgbe_sfp_type_1g_cu_core1:
36762306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, supported,
36862306a36Sopenharmony_ci							     TP);
36962306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
37062306a36Sopenharmony_ci							     TP);
37162306a36Sopenharmony_ci			cmd->base.port = PORT_TP;
37262306a36Sopenharmony_ci			break;
37362306a36Sopenharmony_ci		case ixgbe_sfp_type_unknown:
37462306a36Sopenharmony_ci		default:
37562306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, supported,
37662306a36Sopenharmony_ci							     FIBRE);
37762306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(cmd, advertising,
37862306a36Sopenharmony_ci							     FIBRE);
37962306a36Sopenharmony_ci			cmd->base.port = PORT_OTHER;
38062306a36Sopenharmony_ci			break;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci		break;
38362306a36Sopenharmony_ci	case ixgbe_phy_xaui:
38462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported,
38562306a36Sopenharmony_ci						     FIBRE);
38662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
38762306a36Sopenharmony_ci						     FIBRE);
38862306a36Sopenharmony_ci		cmd->base.port = PORT_NONE;
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci	case ixgbe_phy_unknown:
39162306a36Sopenharmony_ci	case ixgbe_phy_generic:
39262306a36Sopenharmony_ci	case ixgbe_phy_sfp_unsupported:
39362306a36Sopenharmony_ci	default:
39462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported,
39562306a36Sopenharmony_ci						     FIBRE);
39662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
39762306a36Sopenharmony_ci						     FIBRE);
39862306a36Sopenharmony_ci		cmd->base.port = PORT_OTHER;
39962306a36Sopenharmony_ci		break;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Indicate pause support */
40362306a36Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	switch (hw->fc.requested_mode) {
40662306a36Sopenharmony_ci	case ixgbe_fc_full:
40762306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
40862306a36Sopenharmony_ci		break;
40962306a36Sopenharmony_ci	case ixgbe_fc_rx_pause:
41062306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
41162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
41262306a36Sopenharmony_ci						     Asym_Pause);
41362306a36Sopenharmony_ci		break;
41462306a36Sopenharmony_ci	case ixgbe_fc_tx_pause:
41562306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
41662306a36Sopenharmony_ci						     Asym_Pause);
41762306a36Sopenharmony_ci		break;
41862306a36Sopenharmony_ci	default:
41962306a36Sopenharmony_ci		ethtool_link_ksettings_del_link_mode(cmd, advertising, Pause);
42062306a36Sopenharmony_ci		ethtool_link_ksettings_del_link_mode(cmd, advertising,
42162306a36Sopenharmony_ci						     Asym_Pause);
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
42562306a36Sopenharmony_ci		switch (adapter->link_speed) {
42662306a36Sopenharmony_ci		case IXGBE_LINK_SPEED_10GB_FULL:
42762306a36Sopenharmony_ci			cmd->base.speed = SPEED_10000;
42862306a36Sopenharmony_ci			break;
42962306a36Sopenharmony_ci		case IXGBE_LINK_SPEED_5GB_FULL:
43062306a36Sopenharmony_ci			cmd->base.speed = SPEED_5000;
43162306a36Sopenharmony_ci			break;
43262306a36Sopenharmony_ci		case IXGBE_LINK_SPEED_2_5GB_FULL:
43362306a36Sopenharmony_ci			cmd->base.speed = SPEED_2500;
43462306a36Sopenharmony_ci			break;
43562306a36Sopenharmony_ci		case IXGBE_LINK_SPEED_1GB_FULL:
43662306a36Sopenharmony_ci			cmd->base.speed = SPEED_1000;
43762306a36Sopenharmony_ci			break;
43862306a36Sopenharmony_ci		case IXGBE_LINK_SPEED_100_FULL:
43962306a36Sopenharmony_ci			cmd->base.speed = SPEED_100;
44062306a36Sopenharmony_ci			break;
44162306a36Sopenharmony_ci		case IXGBE_LINK_SPEED_10_FULL:
44262306a36Sopenharmony_ci			cmd->base.speed = SPEED_10;
44362306a36Sopenharmony_ci			break;
44462306a36Sopenharmony_ci		default:
44562306a36Sopenharmony_ci			break;
44662306a36Sopenharmony_ci		}
44762306a36Sopenharmony_ci		cmd->base.duplex = DUPLEX_FULL;
44862306a36Sopenharmony_ci	} else {
44962306a36Sopenharmony_ci		cmd->base.speed = SPEED_UNKNOWN;
45062306a36Sopenharmony_ci		cmd->base.duplex = DUPLEX_UNKNOWN;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	return 0;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int ixgbe_set_link_ksettings(struct net_device *netdev,
45762306a36Sopenharmony_ci				    const struct ethtool_link_ksettings *cmd)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
46062306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
46162306a36Sopenharmony_ci	u32 advertised, old;
46262306a36Sopenharmony_ci	s32 err = 0;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if ((hw->phy.media_type == ixgbe_media_type_copper) ||
46562306a36Sopenharmony_ci	    (hw->phy.multispeed_fiber)) {
46662306a36Sopenharmony_ci		/*
46762306a36Sopenharmony_ci		 * this function does not support duplex forcing, but can
46862306a36Sopenharmony_ci		 * limit the advertising of the adapter to the specified speed
46962306a36Sopenharmony_ci		 */
47062306a36Sopenharmony_ci		if (!linkmode_subset(cmd->link_modes.advertising,
47162306a36Sopenharmony_ci				     cmd->link_modes.supported))
47262306a36Sopenharmony_ci			return -EINVAL;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		/* only allow one speed at a time if no autoneg */
47562306a36Sopenharmony_ci		if (!cmd->base.autoneg && hw->phy.multispeed_fiber) {
47662306a36Sopenharmony_ci			if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
47762306a36Sopenharmony_ci								  10000baseT_Full) &&
47862306a36Sopenharmony_ci			    ethtool_link_ksettings_test_link_mode(cmd, advertising,
47962306a36Sopenharmony_ci								  1000baseT_Full))
48062306a36Sopenharmony_ci				return -EINVAL;
48162306a36Sopenharmony_ci		}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		old = hw->phy.autoneg_advertised;
48462306a36Sopenharmony_ci		advertised = 0;
48562306a36Sopenharmony_ci		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
48662306a36Sopenharmony_ci							  10000baseT_Full))
48762306a36Sopenharmony_ci			advertised |= IXGBE_LINK_SPEED_10GB_FULL;
48862306a36Sopenharmony_ci		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
48962306a36Sopenharmony_ci							  5000baseT_Full))
49062306a36Sopenharmony_ci			advertised |= IXGBE_LINK_SPEED_5GB_FULL;
49162306a36Sopenharmony_ci		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
49262306a36Sopenharmony_ci							  2500baseT_Full))
49362306a36Sopenharmony_ci			advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
49462306a36Sopenharmony_ci		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
49562306a36Sopenharmony_ci							  1000baseT_Full))
49662306a36Sopenharmony_ci			advertised |= IXGBE_LINK_SPEED_1GB_FULL;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
49962306a36Sopenharmony_ci							  100baseT_Full))
50062306a36Sopenharmony_ci			advertised |= IXGBE_LINK_SPEED_100_FULL;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
50362306a36Sopenharmony_ci							  10baseT_Full))
50462306a36Sopenharmony_ci			advertised |= IXGBE_LINK_SPEED_10_FULL;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		if (old == advertised)
50762306a36Sopenharmony_ci			return err;
50862306a36Sopenharmony_ci		/* this sets the link speed and restarts auto-neg */
50962306a36Sopenharmony_ci		while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
51062306a36Sopenharmony_ci			usleep_range(1000, 2000);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		hw->mac.autotry_restart = true;
51362306a36Sopenharmony_ci		err = hw->mac.ops.setup_link(hw, advertised, true);
51462306a36Sopenharmony_ci		if (err) {
51562306a36Sopenharmony_ci			e_info(probe, "setup link failed with code %d\n", err);
51662306a36Sopenharmony_ci			hw->mac.ops.setup_link(hw, old, true);
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci		clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
51962306a36Sopenharmony_ci	} else {
52062306a36Sopenharmony_ci		/* in this case we currently only support 10Gb/FULL */
52162306a36Sopenharmony_ci		u32 speed = cmd->base.speed;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		if ((cmd->base.autoneg == AUTONEG_ENABLE) ||
52462306a36Sopenharmony_ci		    (!ethtool_link_ksettings_test_link_mode(cmd, advertising,
52562306a36Sopenharmony_ci							    10000baseT_Full)) ||
52662306a36Sopenharmony_ci		    (speed + cmd->base.duplex != SPEED_10000 + DUPLEX_FULL))
52762306a36Sopenharmony_ci			return -EINVAL;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return err;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic void ixgbe_get_pause_stats(struct net_device *netdev,
53462306a36Sopenharmony_ci				  struct ethtool_pause_stats *stats)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
53762306a36Sopenharmony_ci	struct ixgbe_hw_stats *hwstats = &adapter->stats;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	stats->tx_pause_frames = hwstats->lxontxc + hwstats->lxofftxc;
54062306a36Sopenharmony_ci	stats->rx_pause_frames = hwstats->lxonrxc + hwstats->lxoffrxc;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic void ixgbe_get_pauseparam(struct net_device *netdev,
54462306a36Sopenharmony_ci				 struct ethtool_pauseparam *pause)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
54762306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (ixgbe_device_supports_autoneg_fc(hw) &&
55062306a36Sopenharmony_ci	    !hw->fc.disable_fc_autoneg)
55162306a36Sopenharmony_ci		pause->autoneg = 1;
55262306a36Sopenharmony_ci	else
55362306a36Sopenharmony_ci		pause->autoneg = 0;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (hw->fc.current_mode == ixgbe_fc_rx_pause) {
55662306a36Sopenharmony_ci		pause->rx_pause = 1;
55762306a36Sopenharmony_ci	} else if (hw->fc.current_mode == ixgbe_fc_tx_pause) {
55862306a36Sopenharmony_ci		pause->tx_pause = 1;
55962306a36Sopenharmony_ci	} else if (hw->fc.current_mode == ixgbe_fc_full) {
56062306a36Sopenharmony_ci		pause->rx_pause = 1;
56162306a36Sopenharmony_ci		pause->tx_pause = 1;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic int ixgbe_set_pauseparam(struct net_device *netdev,
56662306a36Sopenharmony_ci				struct ethtool_pauseparam *pause)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
56962306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
57062306a36Sopenharmony_ci	struct ixgbe_fc_info fc = hw->fc;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* 82598 does no support link flow control with DCB enabled */
57362306a36Sopenharmony_ci	if ((hw->mac.type == ixgbe_mac_82598EB) &&
57462306a36Sopenharmony_ci	    (adapter->flags & IXGBE_FLAG_DCB_ENABLED))
57562306a36Sopenharmony_ci		return -EINVAL;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/* some devices do not support autoneg of link flow control */
57862306a36Sopenharmony_ci	if ((pause->autoneg == AUTONEG_ENABLE) &&
57962306a36Sopenharmony_ci	    !ixgbe_device_supports_autoneg_fc(hw))
58062306a36Sopenharmony_ci		return -EINVAL;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	fc.disable_fc_autoneg = (pause->autoneg != AUTONEG_ENABLE);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if ((pause->rx_pause && pause->tx_pause) || pause->autoneg)
58562306a36Sopenharmony_ci		fc.requested_mode = ixgbe_fc_full;
58662306a36Sopenharmony_ci	else if (pause->rx_pause && !pause->tx_pause)
58762306a36Sopenharmony_ci		fc.requested_mode = ixgbe_fc_rx_pause;
58862306a36Sopenharmony_ci	else if (!pause->rx_pause && pause->tx_pause)
58962306a36Sopenharmony_ci		fc.requested_mode = ixgbe_fc_tx_pause;
59062306a36Sopenharmony_ci	else
59162306a36Sopenharmony_ci		fc.requested_mode = ixgbe_fc_none;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* if the thing changed then we'll update and use new autoneg */
59462306a36Sopenharmony_ci	if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) {
59562306a36Sopenharmony_ci		hw->fc = fc;
59662306a36Sopenharmony_ci		if (netif_running(netdev))
59762306a36Sopenharmony_ci			ixgbe_reinit_locked(adapter);
59862306a36Sopenharmony_ci		else
59962306a36Sopenharmony_ci			ixgbe_reset(adapter);
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return 0;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic u32 ixgbe_get_msglevel(struct net_device *netdev)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
60862306a36Sopenharmony_ci	return adapter->msg_enable;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic void ixgbe_set_msglevel(struct net_device *netdev, u32 data)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
61462306a36Sopenharmony_ci	adapter->msg_enable = data;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic int ixgbe_get_regs_len(struct net_device *netdev)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci#define IXGBE_REGS_LEN  1145
62062306a36Sopenharmony_ci	return IXGBE_REGS_LEN * sizeof(u32);
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic void ixgbe_get_regs(struct net_device *netdev,
62662306a36Sopenharmony_ci			   struct ethtool_regs *regs, void *p)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
62962306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
63062306a36Sopenharmony_ci	u32 *regs_buff = p;
63162306a36Sopenharmony_ci	u8 i;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	memset(p, 0, IXGBE_REGS_LEN * sizeof(u32));
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
63662306a36Sopenharmony_ci			hw->device_id;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* General Registers */
63962306a36Sopenharmony_ci	regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL);
64062306a36Sopenharmony_ci	regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS);
64162306a36Sopenharmony_ci	regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
64262306a36Sopenharmony_ci	regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP);
64362306a36Sopenharmony_ci	regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP);
64462306a36Sopenharmony_ci	regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
64562306a36Sopenharmony_ci	regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER);
64662306a36Sopenharmony_ci	regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* NVM Register */
64962306a36Sopenharmony_ci	regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
65062306a36Sopenharmony_ci	regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD);
65162306a36Sopenharmony_ci	regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA(hw));
65262306a36Sopenharmony_ci	regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL);
65362306a36Sopenharmony_ci	regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA);
65462306a36Sopenharmony_ci	regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL);
65562306a36Sopenharmony_ci	regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA);
65662306a36Sopenharmony_ci	regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT);
65762306a36Sopenharmony_ci	regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP);
65862306a36Sopenharmony_ci	regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC(hw));
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* Interrupt */
66162306a36Sopenharmony_ci	/* don't read EICR because it can clear interrupt causes, instead
66262306a36Sopenharmony_ci	 * read EICS which is a shadow but doesn't clear EICR */
66362306a36Sopenharmony_ci	regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICS);
66462306a36Sopenharmony_ci	regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS);
66562306a36Sopenharmony_ci	regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS);
66662306a36Sopenharmony_ci	regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC);
66762306a36Sopenharmony_ci	regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC);
66862306a36Sopenharmony_ci	regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM);
66962306a36Sopenharmony_ci	regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0));
67062306a36Sopenharmony_ci	regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0));
67162306a36Sopenharmony_ci	regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT);
67262306a36Sopenharmony_ci	regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA);
67362306a36Sopenharmony_ci	regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL(0));
67462306a36Sopenharmony_ci	regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	/* Flow Control */
67762306a36Sopenharmony_ci	regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP);
67862306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
67962306a36Sopenharmony_ci		regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_FCTTV(i));
68062306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
68162306a36Sopenharmony_ci		switch (hw->mac.type) {
68262306a36Sopenharmony_ci		case ixgbe_mac_82598EB:
68362306a36Sopenharmony_ci			regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i));
68462306a36Sopenharmony_ci			regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i));
68562306a36Sopenharmony_ci			break;
68662306a36Sopenharmony_ci		case ixgbe_mac_82599EB:
68762306a36Sopenharmony_ci		case ixgbe_mac_X540:
68862306a36Sopenharmony_ci		case ixgbe_mac_X550:
68962306a36Sopenharmony_ci		case ixgbe_mac_X550EM_x:
69062306a36Sopenharmony_ci		case ixgbe_mac_x550em_a:
69162306a36Sopenharmony_ci			regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i));
69262306a36Sopenharmony_ci			regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i));
69362306a36Sopenharmony_ci			break;
69462306a36Sopenharmony_ci		default:
69562306a36Sopenharmony_ci			break;
69662306a36Sopenharmony_ci		}
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci	regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV);
69962306a36Sopenharmony_ci	regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	/* Receive DMA */
70262306a36Sopenharmony_ci	for (i = 0; i < 64; i++)
70362306a36Sopenharmony_ci		regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i));
70462306a36Sopenharmony_ci	for (i = 0; i < 64; i++)
70562306a36Sopenharmony_ci		regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i));
70662306a36Sopenharmony_ci	for (i = 0; i < 64; i++)
70762306a36Sopenharmony_ci		regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i));
70862306a36Sopenharmony_ci	for (i = 0; i < 64; i++)
70962306a36Sopenharmony_ci		regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i));
71062306a36Sopenharmony_ci	for (i = 0; i < 64; i++)
71162306a36Sopenharmony_ci		regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i));
71262306a36Sopenharmony_ci	for (i = 0; i < 64; i++)
71362306a36Sopenharmony_ci		regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
71462306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
71562306a36Sopenharmony_ci		regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
71662306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
71762306a36Sopenharmony_ci		regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
71862306a36Sopenharmony_ci	regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
71962306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
72062306a36Sopenharmony_ci		regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
72162306a36Sopenharmony_ci	regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
72262306a36Sopenharmony_ci	regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* Receive */
72562306a36Sopenharmony_ci	regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
72662306a36Sopenharmony_ci	regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL);
72762306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
72862306a36Sopenharmony_ci		regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i));
72962306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
73062306a36Sopenharmony_ci		regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i));
73162306a36Sopenharmony_ci	regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0));
73262306a36Sopenharmony_ci	regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL);
73362306a36Sopenharmony_ci	regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
73462306a36Sopenharmony_ci	regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL);
73562306a36Sopenharmony_ci	regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC);
73662306a36Sopenharmony_ci	regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL);
73762306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
73862306a36Sopenharmony_ci		regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i));
73962306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
74062306a36Sopenharmony_ci		regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i));
74162306a36Sopenharmony_ci	regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/* Transmit */
74462306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
74562306a36Sopenharmony_ci		regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i));
74662306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
74762306a36Sopenharmony_ci		regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i));
74862306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
74962306a36Sopenharmony_ci		regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i));
75062306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
75162306a36Sopenharmony_ci		regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i));
75262306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
75362306a36Sopenharmony_ci		regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i));
75462306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
75562306a36Sopenharmony_ci		regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
75662306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
75762306a36Sopenharmony_ci		regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i));
75862306a36Sopenharmony_ci	for (i = 0; i < 32; i++)
75962306a36Sopenharmony_ci		regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i));
76062306a36Sopenharmony_ci	regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL);
76162306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
76262306a36Sopenharmony_ci		regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
76362306a36Sopenharmony_ci	regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG);
76462306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
76562306a36Sopenharmony_ci		regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i));
76662306a36Sopenharmony_ci	regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/* Wake Up */
76962306a36Sopenharmony_ci	regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC);
77062306a36Sopenharmony_ci	regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC);
77162306a36Sopenharmony_ci	regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS);
77262306a36Sopenharmony_ci	regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV);
77362306a36Sopenharmony_ci	regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT);
77462306a36Sopenharmony_ci	regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT);
77562306a36Sopenharmony_ci	regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL);
77662306a36Sopenharmony_ci	regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
77762306a36Sopenharmony_ci	regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT(0));
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	/* DCB */
78062306a36Sopenharmony_ci	regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS);   /* same as FCCFG  */
78162306a36Sopenharmony_ci	regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS); /* same as RTTPCS */
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	switch (hw->mac.type) {
78462306a36Sopenharmony_ci	case ixgbe_mac_82598EB:
78562306a36Sopenharmony_ci		regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
78662306a36Sopenharmony_ci		regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR);
78762306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
78862306a36Sopenharmony_ci			regs_buff[833 + i] =
78962306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_RT2CR(i));
79062306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
79162306a36Sopenharmony_ci			regs_buff[841 + i] =
79262306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_RT2SR(i));
79362306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
79462306a36Sopenharmony_ci			regs_buff[849 + i] =
79562306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i));
79662306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
79762306a36Sopenharmony_ci			regs_buff[857 + i] =
79862306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i));
79962306a36Sopenharmony_ci		break;
80062306a36Sopenharmony_ci	case ixgbe_mac_82599EB:
80162306a36Sopenharmony_ci	case ixgbe_mac_X540:
80262306a36Sopenharmony_ci	case ixgbe_mac_X550:
80362306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
80462306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
80562306a36Sopenharmony_ci		regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
80662306a36Sopenharmony_ci		regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RTRPCS);
80762306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
80862306a36Sopenharmony_ci			regs_buff[833 + i] =
80962306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_RTRPT4C(i));
81062306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
81162306a36Sopenharmony_ci			regs_buff[841 + i] =
81262306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_RTRPT4S(i));
81362306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
81462306a36Sopenharmony_ci			regs_buff[849 + i] =
81562306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_RTTDT2C(i));
81662306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
81762306a36Sopenharmony_ci			regs_buff[857 + i] =
81862306a36Sopenharmony_ci				IXGBE_READ_REG(hw, IXGBE_RTTDT2S(i));
81962306a36Sopenharmony_ci		break;
82062306a36Sopenharmony_ci	default:
82162306a36Sopenharmony_ci		break;
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
82562306a36Sopenharmony_ci		regs_buff[865 + i] =
82662306a36Sopenharmony_ci		IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i)); /* same as RTTPT2C */
82762306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
82862306a36Sopenharmony_ci		regs_buff[873 + i] =
82962306a36Sopenharmony_ci		IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i)); /* same as RTTPT2S */
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Statistics */
83262306a36Sopenharmony_ci	regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs);
83362306a36Sopenharmony_ci	regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc);
83462306a36Sopenharmony_ci	regs_buff[883] = IXGBE_GET_STAT(adapter, errbc);
83562306a36Sopenharmony_ci	regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc);
83662306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
83762306a36Sopenharmony_ci		regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]);
83862306a36Sopenharmony_ci	regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc);
83962306a36Sopenharmony_ci	regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc);
84062306a36Sopenharmony_ci	regs_buff[895] = IXGBE_GET_STAT(adapter, rlec);
84162306a36Sopenharmony_ci	regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc);
84262306a36Sopenharmony_ci	regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc);
84362306a36Sopenharmony_ci	regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc);
84462306a36Sopenharmony_ci	regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc);
84562306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
84662306a36Sopenharmony_ci		regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]);
84762306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
84862306a36Sopenharmony_ci		regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]);
84962306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
85062306a36Sopenharmony_ci		regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]);
85162306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
85262306a36Sopenharmony_ci		regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]);
85362306a36Sopenharmony_ci	regs_buff[932] = IXGBE_GET_STAT(adapter, prc64);
85462306a36Sopenharmony_ci	regs_buff[933] = IXGBE_GET_STAT(adapter, prc127);
85562306a36Sopenharmony_ci	regs_buff[934] = IXGBE_GET_STAT(adapter, prc255);
85662306a36Sopenharmony_ci	regs_buff[935] = IXGBE_GET_STAT(adapter, prc511);
85762306a36Sopenharmony_ci	regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023);
85862306a36Sopenharmony_ci	regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522);
85962306a36Sopenharmony_ci	regs_buff[938] = IXGBE_GET_STAT(adapter, gprc);
86062306a36Sopenharmony_ci	regs_buff[939] = IXGBE_GET_STAT(adapter, bprc);
86162306a36Sopenharmony_ci	regs_buff[940] = IXGBE_GET_STAT(adapter, mprc);
86262306a36Sopenharmony_ci	regs_buff[941] = IXGBE_GET_STAT(adapter, gptc);
86362306a36Sopenharmony_ci	regs_buff[942] = (u32)IXGBE_GET_STAT(adapter, gorc);
86462306a36Sopenharmony_ci	regs_buff[943] = (u32)(IXGBE_GET_STAT(adapter, gorc) >> 32);
86562306a36Sopenharmony_ci	regs_buff[944] = (u32)IXGBE_GET_STAT(adapter, gotc);
86662306a36Sopenharmony_ci	regs_buff[945] = (u32)(IXGBE_GET_STAT(adapter, gotc) >> 32);
86762306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
86862306a36Sopenharmony_ci		regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]);
86962306a36Sopenharmony_ci	regs_buff[954] = IXGBE_GET_STAT(adapter, ruc);
87062306a36Sopenharmony_ci	regs_buff[955] = IXGBE_GET_STAT(adapter, rfc);
87162306a36Sopenharmony_ci	regs_buff[956] = IXGBE_GET_STAT(adapter, roc);
87262306a36Sopenharmony_ci	regs_buff[957] = IXGBE_GET_STAT(adapter, rjc);
87362306a36Sopenharmony_ci	regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc);
87462306a36Sopenharmony_ci	regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc);
87562306a36Sopenharmony_ci	regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc);
87662306a36Sopenharmony_ci	regs_buff[961] = (u32)IXGBE_GET_STAT(adapter, tor);
87762306a36Sopenharmony_ci	regs_buff[962] = (u32)(IXGBE_GET_STAT(adapter, tor) >> 32);
87862306a36Sopenharmony_ci	regs_buff[963] = IXGBE_GET_STAT(adapter, tpr);
87962306a36Sopenharmony_ci	regs_buff[964] = IXGBE_GET_STAT(adapter, tpt);
88062306a36Sopenharmony_ci	regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64);
88162306a36Sopenharmony_ci	regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127);
88262306a36Sopenharmony_ci	regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255);
88362306a36Sopenharmony_ci	regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511);
88462306a36Sopenharmony_ci	regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023);
88562306a36Sopenharmony_ci	regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522);
88662306a36Sopenharmony_ci	regs_buff[971] = IXGBE_GET_STAT(adapter, mptc);
88762306a36Sopenharmony_ci	regs_buff[972] = IXGBE_GET_STAT(adapter, bptc);
88862306a36Sopenharmony_ci	regs_buff[973] = IXGBE_GET_STAT(adapter, xec);
88962306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
89062306a36Sopenharmony_ci		regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]);
89162306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
89262306a36Sopenharmony_ci		regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]);
89362306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
89462306a36Sopenharmony_ci		regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]);
89562306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
89662306a36Sopenharmony_ci		regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	/* MAC */
89962306a36Sopenharmony_ci	regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG);
90062306a36Sopenharmony_ci	regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);
90162306a36Sopenharmony_ci	regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
90262306a36Sopenharmony_ci	regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0);
90362306a36Sopenharmony_ci	regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1);
90462306a36Sopenharmony_ci	regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
90562306a36Sopenharmony_ci	regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
90662306a36Sopenharmony_ci	regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP);
90762306a36Sopenharmony_ci	regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP);
90862306a36Sopenharmony_ci	regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0);
90962306a36Sopenharmony_ci	regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1);
91062306a36Sopenharmony_ci	regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP);
91162306a36Sopenharmony_ci	regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA);
91262306a36Sopenharmony_ci	regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE);
91362306a36Sopenharmony_ci	regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD);
91462306a36Sopenharmony_ci	regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS);
91562306a36Sopenharmony_ci	regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA);
91662306a36Sopenharmony_ci	regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD);
91762306a36Sopenharmony_ci	regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD);
91862306a36Sopenharmony_ci	regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD);
91962306a36Sopenharmony_ci	regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG);
92062306a36Sopenharmony_ci	regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1);
92162306a36Sopenharmony_ci	regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2);
92262306a36Sopenharmony_ci	regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS);
92362306a36Sopenharmony_ci	regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC);
92462306a36Sopenharmony_ci	regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS);
92562306a36Sopenharmony_ci	regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC);
92662306a36Sopenharmony_ci	regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS);
92762306a36Sopenharmony_ci	regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
92862306a36Sopenharmony_ci	regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3);
92962306a36Sopenharmony_ci	regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1);
93062306a36Sopenharmony_ci	regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2);
93162306a36Sopenharmony_ci	regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* Diagnostic */
93462306a36Sopenharmony_ci	regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL);
93562306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
93662306a36Sopenharmony_ci		regs_buff[1072 + i] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i));
93762306a36Sopenharmony_ci	regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN);
93862306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
93962306a36Sopenharmony_ci		regs_buff[1081 + i] = IXGBE_READ_REG(hw, IXGBE_RIC_DW(i));
94062306a36Sopenharmony_ci	regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE);
94162306a36Sopenharmony_ci	regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL);
94262306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
94362306a36Sopenharmony_ci		regs_buff[1087 + i] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i));
94462306a36Sopenharmony_ci	regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN);
94562306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
94662306a36Sopenharmony_ci		regs_buff[1096 + i] = IXGBE_READ_REG(hw, IXGBE_TIC_DW(i));
94762306a36Sopenharmony_ci	regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE);
94862306a36Sopenharmony_ci	regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL);
94962306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
95062306a36Sopenharmony_ci		regs_buff[1102 + i] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA(i));
95162306a36Sopenharmony_ci	regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL);
95262306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
95362306a36Sopenharmony_ci		regs_buff[1107 + i] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA(i));
95462306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
95562306a36Sopenharmony_ci		regs_buff[1111 + i] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i));
95662306a36Sopenharmony_ci	regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL);
95762306a36Sopenharmony_ci	regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1);
95862306a36Sopenharmony_ci	regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2);
95962306a36Sopenharmony_ci	regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1);
96062306a36Sopenharmony_ci	regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2);
96162306a36Sopenharmony_ci	regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS);
96262306a36Sopenharmony_ci	regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL);
96362306a36Sopenharmony_ci	regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC);
96462306a36Sopenharmony_ci	regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/* 82599 X540 specific registers  */
96762306a36Sopenharmony_ci	regs_buff[1128] = IXGBE_READ_REG(hw, IXGBE_MFLCN);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	/* 82599 X540 specific DCB registers  */
97062306a36Sopenharmony_ci	regs_buff[1129] = IXGBE_READ_REG(hw, IXGBE_RTRUP2TC);
97162306a36Sopenharmony_ci	regs_buff[1130] = IXGBE_READ_REG(hw, IXGBE_RTTUP2TC);
97262306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
97362306a36Sopenharmony_ci		regs_buff[1131 + i] = IXGBE_READ_REG(hw, IXGBE_TXLLQ(i));
97462306a36Sopenharmony_ci	regs_buff[1135] = IXGBE_READ_REG(hw, IXGBE_RTTBCNRM);
97562306a36Sopenharmony_ci					/* same as RTTQCNRM */
97662306a36Sopenharmony_ci	regs_buff[1136] = IXGBE_READ_REG(hw, IXGBE_RTTBCNRD);
97762306a36Sopenharmony_ci					/* same as RTTQCNRR */
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	/* X540 specific DCB registers  */
98062306a36Sopenharmony_ci	regs_buff[1137] = IXGBE_READ_REG(hw, IXGBE_RTTQCNCR);
98162306a36Sopenharmony_ci	regs_buff[1138] = IXGBE_READ_REG(hw, IXGBE_RTTQCNTG);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* Security config registers */
98462306a36Sopenharmony_ci	regs_buff[1139] = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL);
98562306a36Sopenharmony_ci	regs_buff[1140] = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT);
98662306a36Sopenharmony_ci	regs_buff[1141] = IXGBE_READ_REG(hw, IXGBE_SECTXBUFFAF);
98762306a36Sopenharmony_ci	regs_buff[1142] = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG);
98862306a36Sopenharmony_ci	regs_buff[1143] = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
98962306a36Sopenharmony_ci	regs_buff[1144] = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT);
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic int ixgbe_get_eeprom_len(struct net_device *netdev)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
99562306a36Sopenharmony_ci	return adapter->hw.eeprom.word_size * 2;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int ixgbe_get_eeprom(struct net_device *netdev,
99962306a36Sopenharmony_ci			    struct ethtool_eeprom *eeprom, u8 *bytes)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
100262306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
100362306a36Sopenharmony_ci	u16 *eeprom_buff;
100462306a36Sopenharmony_ci	int first_word, last_word, eeprom_len;
100562306a36Sopenharmony_ci	int ret_val = 0;
100662306a36Sopenharmony_ci	u16 i;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (eeprom->len == 0)
100962306a36Sopenharmony_ci		return -EINVAL;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	first_word = eeprom->offset >> 1;
101462306a36Sopenharmony_ci	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
101562306a36Sopenharmony_ci	eeprom_len = last_word - first_word + 1;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	eeprom_buff = kmalloc_array(eeprom_len, sizeof(u16), GFP_KERNEL);
101862306a36Sopenharmony_ci	if (!eeprom_buff)
101962306a36Sopenharmony_ci		return -ENOMEM;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	ret_val = hw->eeprom.ops.read_buffer(hw, first_word, eeprom_len,
102262306a36Sopenharmony_ci					     eeprom_buff);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	/* Device's eeprom is always little-endian, word addressable */
102562306a36Sopenharmony_ci	for (i = 0; i < eeprom_len; i++)
102662306a36Sopenharmony_ci		le16_to_cpus(&eeprom_buff[i]);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
102962306a36Sopenharmony_ci	kfree(eeprom_buff);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	return ret_val;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic int ixgbe_set_eeprom(struct net_device *netdev,
103562306a36Sopenharmony_ci			    struct ethtool_eeprom *eeprom, u8 *bytes)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
103862306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
103962306a36Sopenharmony_ci	u16 *eeprom_buff;
104062306a36Sopenharmony_ci	void *ptr;
104162306a36Sopenharmony_ci	int max_len, first_word, last_word, ret_val = 0;
104262306a36Sopenharmony_ci	u16 i;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	if (eeprom->len == 0)
104562306a36Sopenharmony_ci		return -EINVAL;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
104862306a36Sopenharmony_ci		return -EINVAL;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	max_len = hw->eeprom.word_size * 2;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	first_word = eeprom->offset >> 1;
105362306a36Sopenharmony_ci	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
105462306a36Sopenharmony_ci	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
105562306a36Sopenharmony_ci	if (!eeprom_buff)
105662306a36Sopenharmony_ci		return -ENOMEM;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	ptr = eeprom_buff;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (eeprom->offset & 1) {
106162306a36Sopenharmony_ci		/*
106262306a36Sopenharmony_ci		 * need read/modify/write of first changed EEPROM word
106362306a36Sopenharmony_ci		 * only the second byte of the word is being modified
106462306a36Sopenharmony_ci		 */
106562306a36Sopenharmony_ci		ret_val = hw->eeprom.ops.read(hw, first_word, &eeprom_buff[0]);
106662306a36Sopenharmony_ci		if (ret_val)
106762306a36Sopenharmony_ci			goto err;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		ptr++;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci	if ((eeprom->offset + eeprom->len) & 1) {
107262306a36Sopenharmony_ci		/*
107362306a36Sopenharmony_ci		 * need read/modify/write of last changed EEPROM word
107462306a36Sopenharmony_ci		 * only the first byte of the word is being modified
107562306a36Sopenharmony_ci		 */
107662306a36Sopenharmony_ci		ret_val = hw->eeprom.ops.read(hw, last_word,
107762306a36Sopenharmony_ci					  &eeprom_buff[last_word - first_word]);
107862306a36Sopenharmony_ci		if (ret_val)
107962306a36Sopenharmony_ci			goto err;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	/* Device's eeprom is always little-endian, word addressable */
108362306a36Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
108462306a36Sopenharmony_ci		le16_to_cpus(&eeprom_buff[i]);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	memcpy(ptr, bytes, eeprom->len);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
108962306a36Sopenharmony_ci		cpu_to_le16s(&eeprom_buff[i]);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	ret_val = hw->eeprom.ops.write_buffer(hw, first_word,
109262306a36Sopenharmony_ci					      last_word - first_word + 1,
109362306a36Sopenharmony_ci					      eeprom_buff);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	/* Update the checksum */
109662306a36Sopenharmony_ci	if (ret_val == 0)
109762306a36Sopenharmony_ci		hw->eeprom.ops.update_checksum(hw);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cierr:
110062306a36Sopenharmony_ci	kfree(eeprom_buff);
110162306a36Sopenharmony_ci	return ret_val;
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cistatic void ixgbe_get_drvinfo(struct net_device *netdev,
110562306a36Sopenharmony_ci			      struct ethtool_drvinfo *drvinfo)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	strscpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	strscpy(drvinfo->fw_version, adapter->eeprom_id,
111262306a36Sopenharmony_ci		sizeof(drvinfo->fw_version));
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	strscpy(drvinfo->bus_info, pci_name(adapter->pdev),
111562306a36Sopenharmony_ci		sizeof(drvinfo->bus_info));
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	drvinfo->n_priv_flags = IXGBE_PRIV_FLAGS_STR_LEN;
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistatic u32 ixgbe_get_max_rxd(struct ixgbe_adapter *adapter)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	switch (adapter->hw.mac.type) {
112362306a36Sopenharmony_ci	case ixgbe_mac_82598EB:
112462306a36Sopenharmony_ci		return IXGBE_MAX_RXD_82598;
112562306a36Sopenharmony_ci	case ixgbe_mac_82599EB:
112662306a36Sopenharmony_ci		return IXGBE_MAX_RXD_82599;
112762306a36Sopenharmony_ci	case ixgbe_mac_X540:
112862306a36Sopenharmony_ci		return IXGBE_MAX_RXD_X540;
112962306a36Sopenharmony_ci	case ixgbe_mac_X550:
113062306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
113162306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
113262306a36Sopenharmony_ci		return IXGBE_MAX_RXD_X550;
113362306a36Sopenharmony_ci	default:
113462306a36Sopenharmony_ci		return IXGBE_MAX_RXD_82598;
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic u32 ixgbe_get_max_txd(struct ixgbe_adapter *adapter)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	switch (adapter->hw.mac.type) {
114162306a36Sopenharmony_ci	case ixgbe_mac_82598EB:
114262306a36Sopenharmony_ci		return IXGBE_MAX_TXD_82598;
114362306a36Sopenharmony_ci	case ixgbe_mac_82599EB:
114462306a36Sopenharmony_ci		return IXGBE_MAX_TXD_82599;
114562306a36Sopenharmony_ci	case ixgbe_mac_X540:
114662306a36Sopenharmony_ci		return IXGBE_MAX_TXD_X540;
114762306a36Sopenharmony_ci	case ixgbe_mac_X550:
114862306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
114962306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
115062306a36Sopenharmony_ci		return IXGBE_MAX_TXD_X550;
115162306a36Sopenharmony_ci	default:
115262306a36Sopenharmony_ci		return IXGBE_MAX_TXD_82598;
115362306a36Sopenharmony_ci	}
115462306a36Sopenharmony_ci}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_cistatic void ixgbe_get_ringparam(struct net_device *netdev,
115762306a36Sopenharmony_ci				struct ethtool_ringparam *ring,
115862306a36Sopenharmony_ci				struct kernel_ethtool_ringparam *kernel_ring,
115962306a36Sopenharmony_ci				struct netlink_ext_ack *extack)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
116262306a36Sopenharmony_ci	struct ixgbe_ring *tx_ring = adapter->tx_ring[0];
116362306a36Sopenharmony_ci	struct ixgbe_ring *rx_ring = adapter->rx_ring[0];
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	ring->rx_max_pending = ixgbe_get_max_rxd(adapter);
116662306a36Sopenharmony_ci	ring->tx_max_pending = ixgbe_get_max_txd(adapter);
116762306a36Sopenharmony_ci	ring->rx_pending = rx_ring->count;
116862306a36Sopenharmony_ci	ring->tx_pending = tx_ring->count;
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic int ixgbe_set_ringparam(struct net_device *netdev,
117262306a36Sopenharmony_ci			       struct ethtool_ringparam *ring,
117362306a36Sopenharmony_ci			       struct kernel_ethtool_ringparam *kernel_ring,
117462306a36Sopenharmony_ci			       struct netlink_ext_ack *extack)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
117762306a36Sopenharmony_ci	struct ixgbe_ring *temp_ring;
117862306a36Sopenharmony_ci	int i, j, err = 0;
117962306a36Sopenharmony_ci	u32 new_rx_count, new_tx_count;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
118262306a36Sopenharmony_ci		return -EINVAL;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	new_tx_count = clamp_t(u32, ring->tx_pending,
118562306a36Sopenharmony_ci			       IXGBE_MIN_TXD, ixgbe_get_max_txd(adapter));
118662306a36Sopenharmony_ci	new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	new_rx_count = clamp_t(u32, ring->rx_pending,
118962306a36Sopenharmony_ci			       IXGBE_MIN_RXD, ixgbe_get_max_rxd(adapter));
119062306a36Sopenharmony_ci	new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if ((new_tx_count == adapter->tx_ring_count) &&
119362306a36Sopenharmony_ci	    (new_rx_count == adapter->rx_ring_count)) {
119462306a36Sopenharmony_ci		/* nothing to do */
119562306a36Sopenharmony_ci		return 0;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
119962306a36Sopenharmony_ci		usleep_range(1000, 2000);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (!netif_running(adapter->netdev)) {
120262306a36Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++)
120362306a36Sopenharmony_ci			adapter->tx_ring[i]->count = new_tx_count;
120462306a36Sopenharmony_ci		for (i = 0; i < adapter->num_xdp_queues; i++)
120562306a36Sopenharmony_ci			adapter->xdp_ring[i]->count = new_tx_count;
120662306a36Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++)
120762306a36Sopenharmony_ci			adapter->rx_ring[i]->count = new_rx_count;
120862306a36Sopenharmony_ci		adapter->tx_ring_count = new_tx_count;
120962306a36Sopenharmony_ci		adapter->xdp_ring_count = new_tx_count;
121062306a36Sopenharmony_ci		adapter->rx_ring_count = new_rx_count;
121162306a36Sopenharmony_ci		goto clear_reset;
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/* allocate temporary buffer to store rings in */
121562306a36Sopenharmony_ci	i = max_t(int, adapter->num_tx_queues + adapter->num_xdp_queues,
121662306a36Sopenharmony_ci		  adapter->num_rx_queues);
121762306a36Sopenharmony_ci	temp_ring = vmalloc(array_size(i, sizeof(struct ixgbe_ring)));
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (!temp_ring) {
122062306a36Sopenharmony_ci		err = -ENOMEM;
122162306a36Sopenharmony_ci		goto clear_reset;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	ixgbe_down(adapter);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	/*
122762306a36Sopenharmony_ci	 * Setup new Tx resources and free the old Tx resources in that order.
122862306a36Sopenharmony_ci	 * We can then assign the new resources to the rings via a memcpy.
122962306a36Sopenharmony_ci	 * The advantage to this approach is that we are guaranteed to still
123062306a36Sopenharmony_ci	 * have resources even in the case of an allocation failure.
123162306a36Sopenharmony_ci	 */
123262306a36Sopenharmony_ci	if (new_tx_count != adapter->tx_ring_count) {
123362306a36Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
123462306a36Sopenharmony_ci			memcpy(&temp_ring[i], adapter->tx_ring[i],
123562306a36Sopenharmony_ci			       sizeof(struct ixgbe_ring));
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci			temp_ring[i].count = new_tx_count;
123862306a36Sopenharmony_ci			err = ixgbe_setup_tx_resources(&temp_ring[i]);
123962306a36Sopenharmony_ci			if (err) {
124062306a36Sopenharmony_ci				while (i) {
124162306a36Sopenharmony_ci					i--;
124262306a36Sopenharmony_ci					ixgbe_free_tx_resources(&temp_ring[i]);
124362306a36Sopenharmony_ci				}
124462306a36Sopenharmony_ci				goto err_setup;
124562306a36Sopenharmony_ci			}
124662306a36Sopenharmony_ci		}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci		for (j = 0; j < adapter->num_xdp_queues; j++, i++) {
124962306a36Sopenharmony_ci			memcpy(&temp_ring[i], adapter->xdp_ring[j],
125062306a36Sopenharmony_ci			       sizeof(struct ixgbe_ring));
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci			temp_ring[i].count = new_tx_count;
125362306a36Sopenharmony_ci			err = ixgbe_setup_tx_resources(&temp_ring[i]);
125462306a36Sopenharmony_ci			if (err) {
125562306a36Sopenharmony_ci				while (i) {
125662306a36Sopenharmony_ci					i--;
125762306a36Sopenharmony_ci					ixgbe_free_tx_resources(&temp_ring[i]);
125862306a36Sopenharmony_ci				}
125962306a36Sopenharmony_ci				goto err_setup;
126062306a36Sopenharmony_ci			}
126162306a36Sopenharmony_ci		}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
126462306a36Sopenharmony_ci			ixgbe_free_tx_resources(adapter->tx_ring[i]);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci			memcpy(adapter->tx_ring[i], &temp_ring[i],
126762306a36Sopenharmony_ci			       sizeof(struct ixgbe_ring));
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci		for (j = 0; j < adapter->num_xdp_queues; j++, i++) {
127062306a36Sopenharmony_ci			ixgbe_free_tx_resources(adapter->xdp_ring[j]);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci			memcpy(adapter->xdp_ring[j], &temp_ring[i],
127362306a36Sopenharmony_ci			       sizeof(struct ixgbe_ring));
127462306a36Sopenharmony_ci		}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci		adapter->tx_ring_count = new_tx_count;
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	/* Repeat the process for the Rx rings if needed */
128062306a36Sopenharmony_ci	if (new_rx_count != adapter->rx_ring_count) {
128162306a36Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
128262306a36Sopenharmony_ci			memcpy(&temp_ring[i], adapter->rx_ring[i],
128362306a36Sopenharmony_ci			       sizeof(struct ixgbe_ring));
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci			/* Clear copied XDP RX-queue info */
128662306a36Sopenharmony_ci			memset(&temp_ring[i].xdp_rxq, 0,
128762306a36Sopenharmony_ci			       sizeof(temp_ring[i].xdp_rxq));
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci			temp_ring[i].count = new_rx_count;
129062306a36Sopenharmony_ci			err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]);
129162306a36Sopenharmony_ci			if (err) {
129262306a36Sopenharmony_ci				while (i) {
129362306a36Sopenharmony_ci					i--;
129462306a36Sopenharmony_ci					ixgbe_free_rx_resources(&temp_ring[i]);
129562306a36Sopenharmony_ci				}
129662306a36Sopenharmony_ci				goto err_setup;
129762306a36Sopenharmony_ci			}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci		}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
130262306a36Sopenharmony_ci			ixgbe_free_rx_resources(adapter->rx_ring[i]);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci			memcpy(adapter->rx_ring[i], &temp_ring[i],
130562306a36Sopenharmony_ci			       sizeof(struct ixgbe_ring));
130662306a36Sopenharmony_ci		}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci		adapter->rx_ring_count = new_rx_count;
130962306a36Sopenharmony_ci	}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cierr_setup:
131262306a36Sopenharmony_ci	ixgbe_up(adapter);
131362306a36Sopenharmony_ci	vfree(temp_ring);
131462306a36Sopenharmony_ciclear_reset:
131562306a36Sopenharmony_ci	clear_bit(__IXGBE_RESETTING, &adapter->state);
131662306a36Sopenharmony_ci	return err;
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic int ixgbe_get_sset_count(struct net_device *netdev, int sset)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	switch (sset) {
132262306a36Sopenharmony_ci	case ETH_SS_TEST:
132362306a36Sopenharmony_ci		return IXGBE_TEST_LEN;
132462306a36Sopenharmony_ci	case ETH_SS_STATS:
132562306a36Sopenharmony_ci		return IXGBE_STATS_LEN;
132662306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
132762306a36Sopenharmony_ci		return IXGBE_PRIV_FLAGS_STR_LEN;
132862306a36Sopenharmony_ci	default:
132962306a36Sopenharmony_ci		return -EOPNOTSUPP;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_cistatic void ixgbe_get_ethtool_stats(struct net_device *netdev,
133462306a36Sopenharmony_ci				    struct ethtool_stats *stats, u64 *data)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
133762306a36Sopenharmony_ci	struct rtnl_link_stats64 temp;
133862306a36Sopenharmony_ci	const struct rtnl_link_stats64 *net_stats;
133962306a36Sopenharmony_ci	unsigned int start;
134062306a36Sopenharmony_ci	struct ixgbe_ring *ring;
134162306a36Sopenharmony_ci	int i, j;
134262306a36Sopenharmony_ci	char *p = NULL;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	ixgbe_update_stats(adapter);
134562306a36Sopenharmony_ci	net_stats = dev_get_stats(netdev, &temp);
134662306a36Sopenharmony_ci	for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
134762306a36Sopenharmony_ci		switch (ixgbe_gstrings_stats[i].type) {
134862306a36Sopenharmony_ci		case NETDEV_STATS:
134962306a36Sopenharmony_ci			p = (char *) net_stats +
135062306a36Sopenharmony_ci					ixgbe_gstrings_stats[i].stat_offset;
135162306a36Sopenharmony_ci			break;
135262306a36Sopenharmony_ci		case IXGBE_STATS:
135362306a36Sopenharmony_ci			p = (char *) adapter +
135462306a36Sopenharmony_ci					ixgbe_gstrings_stats[i].stat_offset;
135562306a36Sopenharmony_ci			break;
135662306a36Sopenharmony_ci		default:
135762306a36Sopenharmony_ci			data[i] = 0;
135862306a36Sopenharmony_ci			continue;
135962306a36Sopenharmony_ci		}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci		data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
136262306a36Sopenharmony_ci			   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci	for (j = 0; j < netdev->num_tx_queues; j++) {
136562306a36Sopenharmony_ci		ring = adapter->tx_ring[j];
136662306a36Sopenharmony_ci		if (!ring) {
136762306a36Sopenharmony_ci			data[i] = 0;
136862306a36Sopenharmony_ci			data[i+1] = 0;
136962306a36Sopenharmony_ci			i += 2;
137062306a36Sopenharmony_ci			continue;
137162306a36Sopenharmony_ci		}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci		do {
137462306a36Sopenharmony_ci			start = u64_stats_fetch_begin(&ring->syncp);
137562306a36Sopenharmony_ci			data[i]   = ring->stats.packets;
137662306a36Sopenharmony_ci			data[i+1] = ring->stats.bytes;
137762306a36Sopenharmony_ci		} while (u64_stats_fetch_retry(&ring->syncp, start));
137862306a36Sopenharmony_ci		i += 2;
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci	for (j = 0; j < IXGBE_NUM_RX_QUEUES; j++) {
138162306a36Sopenharmony_ci		ring = adapter->rx_ring[j];
138262306a36Sopenharmony_ci		if (!ring) {
138362306a36Sopenharmony_ci			data[i] = 0;
138462306a36Sopenharmony_ci			data[i+1] = 0;
138562306a36Sopenharmony_ci			i += 2;
138662306a36Sopenharmony_ci			continue;
138762306a36Sopenharmony_ci		}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci		do {
139062306a36Sopenharmony_ci			start = u64_stats_fetch_begin(&ring->syncp);
139162306a36Sopenharmony_ci			data[i]   = ring->stats.packets;
139262306a36Sopenharmony_ci			data[i+1] = ring->stats.bytes;
139362306a36Sopenharmony_ci		} while (u64_stats_fetch_retry(&ring->syncp, start));
139462306a36Sopenharmony_ci		i += 2;
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	for (j = 0; j < IXGBE_MAX_PACKET_BUFFERS; j++) {
139862306a36Sopenharmony_ci		data[i++] = adapter->stats.pxontxc[j];
139962306a36Sopenharmony_ci		data[i++] = adapter->stats.pxofftxc[j];
140062306a36Sopenharmony_ci	}
140162306a36Sopenharmony_ci	for (j = 0; j < IXGBE_MAX_PACKET_BUFFERS; j++) {
140262306a36Sopenharmony_ci		data[i++] = adapter->stats.pxonrxc[j];
140362306a36Sopenharmony_ci		data[i++] = adapter->stats.pxoffrxc[j];
140462306a36Sopenharmony_ci	}
140562306a36Sopenharmony_ci}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_cistatic void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
140862306a36Sopenharmony_ci			      u8 *data)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	unsigned int i;
141162306a36Sopenharmony_ci	u8 *p = data;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	switch (stringset) {
141462306a36Sopenharmony_ci	case ETH_SS_TEST:
141562306a36Sopenharmony_ci		for (i = 0; i < IXGBE_TEST_LEN; i++)
141662306a36Sopenharmony_ci			ethtool_sprintf(&p, ixgbe_gstrings_test[i]);
141762306a36Sopenharmony_ci		break;
141862306a36Sopenharmony_ci	case ETH_SS_STATS:
141962306a36Sopenharmony_ci		for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++)
142062306a36Sopenharmony_ci			ethtool_sprintf(&p,
142162306a36Sopenharmony_ci					ixgbe_gstrings_stats[i].stat_string);
142262306a36Sopenharmony_ci		for (i = 0; i < netdev->num_tx_queues; i++) {
142362306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_queue_%u_packets", i);
142462306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci		for (i = 0; i < IXGBE_NUM_RX_QUEUES; i++) {
142762306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_queue_%u_packets", i);
142862306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_queue_%u_bytes", i);
142962306a36Sopenharmony_ci		}
143062306a36Sopenharmony_ci		for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) {
143162306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_pb_%u_pxon", i);
143262306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_pb_%u_pxoff", i);
143362306a36Sopenharmony_ci		}
143462306a36Sopenharmony_ci		for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) {
143562306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_pb_%u_pxon", i);
143662306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_pb_%u_pxoff", i);
143762306a36Sopenharmony_ci		}
143862306a36Sopenharmony_ci		/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
143962306a36Sopenharmony_ci		break;
144062306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
144162306a36Sopenharmony_ci		memcpy(data, ixgbe_priv_flags_strings,
144262306a36Sopenharmony_ci		       IXGBE_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN);
144362306a36Sopenharmony_ci	}
144462306a36Sopenharmony_ci}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_cistatic int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data)
144762306a36Sopenharmony_ci{
144862306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
144962306a36Sopenharmony_ci	bool link_up;
145062306a36Sopenharmony_ci	u32 link_speed = 0;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	if (ixgbe_removed(hw->hw_addr)) {
145362306a36Sopenharmony_ci		*data = 1;
145462306a36Sopenharmony_ci		return 1;
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci	*data = 0;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	hw->mac.ops.check_link(hw, &link_speed, &link_up, true);
145962306a36Sopenharmony_ci	if (link_up)
146062306a36Sopenharmony_ci		return *data;
146162306a36Sopenharmony_ci	else
146262306a36Sopenharmony_ci		*data = 1;
146362306a36Sopenharmony_ci	return *data;
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci/* ethtool register test data */
146762306a36Sopenharmony_cistruct ixgbe_reg_test {
146862306a36Sopenharmony_ci	u16 reg;
146962306a36Sopenharmony_ci	u8  array_len;
147062306a36Sopenharmony_ci	u8  test_type;
147162306a36Sopenharmony_ci	u32 mask;
147262306a36Sopenharmony_ci	u32 write;
147362306a36Sopenharmony_ci};
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci/* In the hardware, registers are laid out either singly, in arrays
147662306a36Sopenharmony_ci * spaced 0x40 bytes apart, or in contiguous tables.  We assume
147762306a36Sopenharmony_ci * most tests take place on arrays or single registers (handled
147862306a36Sopenharmony_ci * as a single-element array) and special-case the tables.
147962306a36Sopenharmony_ci * Table tests are always pattern tests.
148062306a36Sopenharmony_ci *
148162306a36Sopenharmony_ci * We also make provision for some required setup steps by specifying
148262306a36Sopenharmony_ci * registers to be written without any read-back testing.
148362306a36Sopenharmony_ci */
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci#define PATTERN_TEST	1
148662306a36Sopenharmony_ci#define SET_READ_TEST	2
148762306a36Sopenharmony_ci#define WRITE_NO_TEST	3
148862306a36Sopenharmony_ci#define TABLE32_TEST	4
148962306a36Sopenharmony_ci#define TABLE64_TEST_LO	5
149062306a36Sopenharmony_ci#define TABLE64_TEST_HI	6
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci/* default 82599 register test */
149362306a36Sopenharmony_cistatic const struct ixgbe_reg_test reg_test_82599[] = {
149462306a36Sopenharmony_ci	{ IXGBE_FCRTL_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
149562306a36Sopenharmony_ci	{ IXGBE_FCRTH_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
149662306a36Sopenharmony_ci	{ IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
149762306a36Sopenharmony_ci	{ IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 },
149862306a36Sopenharmony_ci	{ IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
149962306a36Sopenharmony_ci	{ IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
150062306a36Sopenharmony_ci	{ IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
150162306a36Sopenharmony_ci	{ IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE },
150262306a36Sopenharmony_ci	{ IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
150362306a36Sopenharmony_ci	{ IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 },
150462306a36Sopenharmony_ci	{ IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
150562306a36Sopenharmony_ci	{ IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
150662306a36Sopenharmony_ci	{ IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
150762306a36Sopenharmony_ci	{ IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
150862306a36Sopenharmony_ci	{ IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFF80 },
150962306a36Sopenharmony_ci	{ IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000001, 0x00000001 },
151062306a36Sopenharmony_ci	{ IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
151162306a36Sopenharmony_ci	{ IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x8001FFFF, 0x800CFFFF },
151262306a36Sopenharmony_ci	{ IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
151362306a36Sopenharmony_ci	{ .reg = 0 }
151462306a36Sopenharmony_ci};
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci/* default 82598 register test */
151762306a36Sopenharmony_cistatic const struct ixgbe_reg_test reg_test_82598[] = {
151862306a36Sopenharmony_ci	{ IXGBE_FCRTL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
151962306a36Sopenharmony_ci	{ IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
152062306a36Sopenharmony_ci	{ IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
152162306a36Sopenharmony_ci	{ IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 },
152262306a36Sopenharmony_ci	{ IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
152362306a36Sopenharmony_ci	{ IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
152462306a36Sopenharmony_ci	{ IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
152562306a36Sopenharmony_ci	/* Enable all four RX queues before testing. */
152662306a36Sopenharmony_ci	{ IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE },
152762306a36Sopenharmony_ci	/* RDH is read-only for 82598, only test RDT. */
152862306a36Sopenharmony_ci	{ IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
152962306a36Sopenharmony_ci	{ IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 },
153062306a36Sopenharmony_ci	{ IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
153162306a36Sopenharmony_ci	{ IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
153262306a36Sopenharmony_ci	{ IXGBE_TIPG, 1, PATTERN_TEST, 0x000000FF, 0x000000FF },
153362306a36Sopenharmony_ci	{ IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
153462306a36Sopenharmony_ci	{ IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
153562306a36Sopenharmony_ci	{ IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
153662306a36Sopenharmony_ci	{ IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000003, 0x00000003 },
153762306a36Sopenharmony_ci	{ IXGBE_DTXCTL, 1, SET_READ_TEST, 0x00000005, 0x00000005 },
153862306a36Sopenharmony_ci	{ IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
153962306a36Sopenharmony_ci	{ IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x800CFFFF, 0x800CFFFF },
154062306a36Sopenharmony_ci	{ IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
154162306a36Sopenharmony_ci	{ .reg = 0 }
154262306a36Sopenharmony_ci};
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg,
154562306a36Sopenharmony_ci			     u32 mask, u32 write)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	u32 pat, val, before;
154862306a36Sopenharmony_ci	static const u32 test_pattern[] = {
154962306a36Sopenharmony_ci		0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	if (ixgbe_removed(adapter->hw.hw_addr)) {
155262306a36Sopenharmony_ci		*data = 1;
155362306a36Sopenharmony_ci		return true;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci	for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
155662306a36Sopenharmony_ci		before = ixgbe_read_reg(&adapter->hw, reg);
155762306a36Sopenharmony_ci		ixgbe_write_reg(&adapter->hw, reg, test_pattern[pat] & write);
155862306a36Sopenharmony_ci		val = ixgbe_read_reg(&adapter->hw, reg);
155962306a36Sopenharmony_ci		if (val != (test_pattern[pat] & write & mask)) {
156062306a36Sopenharmony_ci			e_err(drv, "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
156162306a36Sopenharmony_ci			      reg, val, (test_pattern[pat] & write & mask));
156262306a36Sopenharmony_ci			*data = reg;
156362306a36Sopenharmony_ci			ixgbe_write_reg(&adapter->hw, reg, before);
156462306a36Sopenharmony_ci			return true;
156562306a36Sopenharmony_ci		}
156662306a36Sopenharmony_ci		ixgbe_write_reg(&adapter->hw, reg, before);
156762306a36Sopenharmony_ci	}
156862306a36Sopenharmony_ci	return false;
156962306a36Sopenharmony_ci}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg,
157262306a36Sopenharmony_ci			      u32 mask, u32 write)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	u32 val, before;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (ixgbe_removed(adapter->hw.hw_addr)) {
157762306a36Sopenharmony_ci		*data = 1;
157862306a36Sopenharmony_ci		return true;
157962306a36Sopenharmony_ci	}
158062306a36Sopenharmony_ci	before = ixgbe_read_reg(&adapter->hw, reg);
158162306a36Sopenharmony_ci	ixgbe_write_reg(&adapter->hw, reg, write & mask);
158262306a36Sopenharmony_ci	val = ixgbe_read_reg(&adapter->hw, reg);
158362306a36Sopenharmony_ci	if ((write & mask) != (val & mask)) {
158462306a36Sopenharmony_ci		e_err(drv, "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
158562306a36Sopenharmony_ci		      reg, (val & mask), (write & mask));
158662306a36Sopenharmony_ci		*data = reg;
158762306a36Sopenharmony_ci		ixgbe_write_reg(&adapter->hw, reg, before);
158862306a36Sopenharmony_ci		return true;
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci	ixgbe_write_reg(&adapter->hw, reg, before);
159162306a36Sopenharmony_ci	return false;
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	const struct ixgbe_reg_test *test;
159762306a36Sopenharmony_ci	u32 value, before, after;
159862306a36Sopenharmony_ci	u32 i, toggle;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	if (ixgbe_removed(adapter->hw.hw_addr)) {
160162306a36Sopenharmony_ci		e_err(drv, "Adapter removed - register test blocked\n");
160262306a36Sopenharmony_ci		*data = 1;
160362306a36Sopenharmony_ci		return 1;
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci	switch (adapter->hw.mac.type) {
160662306a36Sopenharmony_ci	case ixgbe_mac_82598EB:
160762306a36Sopenharmony_ci		toggle = 0x7FFFF3FF;
160862306a36Sopenharmony_ci		test = reg_test_82598;
160962306a36Sopenharmony_ci		break;
161062306a36Sopenharmony_ci	case ixgbe_mac_82599EB:
161162306a36Sopenharmony_ci	case ixgbe_mac_X540:
161262306a36Sopenharmony_ci	case ixgbe_mac_X550:
161362306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
161462306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
161562306a36Sopenharmony_ci		toggle = 0x7FFFF30F;
161662306a36Sopenharmony_ci		test = reg_test_82599;
161762306a36Sopenharmony_ci		break;
161862306a36Sopenharmony_ci	default:
161962306a36Sopenharmony_ci		*data = 1;
162062306a36Sopenharmony_ci		return 1;
162162306a36Sopenharmony_ci	}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	/*
162462306a36Sopenharmony_ci	 * Because the status register is such a special case,
162562306a36Sopenharmony_ci	 * we handle it separately from the rest of the register
162662306a36Sopenharmony_ci	 * tests.  Some bits are read-only, some toggle, and some
162762306a36Sopenharmony_ci	 * are writeable on newer MACs.
162862306a36Sopenharmony_ci	 */
162962306a36Sopenharmony_ci	before = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS);
163062306a36Sopenharmony_ci	value = (ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle);
163162306a36Sopenharmony_ci	ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, toggle);
163262306a36Sopenharmony_ci	after = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle;
163362306a36Sopenharmony_ci	if (value != after) {
163462306a36Sopenharmony_ci		e_err(drv, "failed STATUS register test got: 0x%08X expected: 0x%08X\n",
163562306a36Sopenharmony_ci		      after, value);
163662306a36Sopenharmony_ci		*data = 1;
163762306a36Sopenharmony_ci		return 1;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci	/* restore previous status */
164062306a36Sopenharmony_ci	ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, before);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	/*
164362306a36Sopenharmony_ci	 * Perform the remainder of the register test, looping through
164462306a36Sopenharmony_ci	 * the test table until we either fail or reach the null entry.
164562306a36Sopenharmony_ci	 */
164662306a36Sopenharmony_ci	while (test->reg) {
164762306a36Sopenharmony_ci		for (i = 0; i < test->array_len; i++) {
164862306a36Sopenharmony_ci			bool b = false;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci			switch (test->test_type) {
165162306a36Sopenharmony_ci			case PATTERN_TEST:
165262306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
165362306a36Sopenharmony_ci						     test->reg + (i * 0x40),
165462306a36Sopenharmony_ci						     test->mask,
165562306a36Sopenharmony_ci						     test->write);
165662306a36Sopenharmony_ci				break;
165762306a36Sopenharmony_ci			case SET_READ_TEST:
165862306a36Sopenharmony_ci				b = reg_set_and_check(adapter, data,
165962306a36Sopenharmony_ci						      test->reg + (i * 0x40),
166062306a36Sopenharmony_ci						      test->mask,
166162306a36Sopenharmony_ci						      test->write);
166262306a36Sopenharmony_ci				break;
166362306a36Sopenharmony_ci			case WRITE_NO_TEST:
166462306a36Sopenharmony_ci				ixgbe_write_reg(&adapter->hw,
166562306a36Sopenharmony_ci						test->reg + (i * 0x40),
166662306a36Sopenharmony_ci						test->write);
166762306a36Sopenharmony_ci				break;
166862306a36Sopenharmony_ci			case TABLE32_TEST:
166962306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
167062306a36Sopenharmony_ci						     test->reg + (i * 4),
167162306a36Sopenharmony_ci						     test->mask,
167262306a36Sopenharmony_ci						     test->write);
167362306a36Sopenharmony_ci				break;
167462306a36Sopenharmony_ci			case TABLE64_TEST_LO:
167562306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
167662306a36Sopenharmony_ci						     test->reg + (i * 8),
167762306a36Sopenharmony_ci						     test->mask,
167862306a36Sopenharmony_ci						     test->write);
167962306a36Sopenharmony_ci				break;
168062306a36Sopenharmony_ci			case TABLE64_TEST_HI:
168162306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
168262306a36Sopenharmony_ci						     (test->reg + 4) + (i * 8),
168362306a36Sopenharmony_ci						     test->mask,
168462306a36Sopenharmony_ci						     test->write);
168562306a36Sopenharmony_ci				break;
168662306a36Sopenharmony_ci			}
168762306a36Sopenharmony_ci			if (b)
168862306a36Sopenharmony_ci				return 1;
168962306a36Sopenharmony_ci		}
169062306a36Sopenharmony_ci		test++;
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	*data = 0;
169462306a36Sopenharmony_ci	return 0;
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_cistatic int ixgbe_eeprom_test(struct ixgbe_adapter *adapter, u64 *data)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
170062306a36Sopenharmony_ci	if (hw->eeprom.ops.validate_checksum(hw, NULL))
170162306a36Sopenharmony_ci		*data = 1;
170262306a36Sopenharmony_ci	else
170362306a36Sopenharmony_ci		*data = 0;
170462306a36Sopenharmony_ci	return *data;
170562306a36Sopenharmony_ci}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic irqreturn_t ixgbe_test_intr(int irq, void *data)
170862306a36Sopenharmony_ci{
170962306a36Sopenharmony_ci	struct net_device *netdev = (struct net_device *) data;
171062306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	adapter->test_icr |= IXGBE_READ_REG(&adapter->hw, IXGBE_EICR);
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	return IRQ_HANDLED;
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_cistatic int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
171862306a36Sopenharmony_ci{
171962306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
172062306a36Sopenharmony_ci	u32 mask, i = 0, shared_int = true;
172162306a36Sopenharmony_ci	u32 irq = adapter->pdev->irq;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	*data = 0;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	/* Hook up test interrupt handler just for this test */
172662306a36Sopenharmony_ci	if (adapter->msix_entries) {
172762306a36Sopenharmony_ci		/* NOTE: we don't test MSI-X interrupts here, yet */
172862306a36Sopenharmony_ci		return 0;
172962306a36Sopenharmony_ci	} else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
173062306a36Sopenharmony_ci		shared_int = false;
173162306a36Sopenharmony_ci		if (request_irq(irq, ixgbe_test_intr, 0, netdev->name,
173262306a36Sopenharmony_ci				netdev)) {
173362306a36Sopenharmony_ci			*data = 1;
173462306a36Sopenharmony_ci			return -1;
173562306a36Sopenharmony_ci		}
173662306a36Sopenharmony_ci	} else if (!request_irq(irq, ixgbe_test_intr, IRQF_PROBE_SHARED,
173762306a36Sopenharmony_ci				netdev->name, netdev)) {
173862306a36Sopenharmony_ci		shared_int = false;
173962306a36Sopenharmony_ci	} else if (request_irq(irq, ixgbe_test_intr, IRQF_SHARED,
174062306a36Sopenharmony_ci			       netdev->name, netdev)) {
174162306a36Sopenharmony_ci		*data = 1;
174262306a36Sopenharmony_ci		return -1;
174362306a36Sopenharmony_ci	}
174462306a36Sopenharmony_ci	e_info(hw, "testing %s interrupt\n", shared_int ?
174562306a36Sopenharmony_ci	       "shared" : "unshared");
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	/* Disable all the interrupts */
174862306a36Sopenharmony_ci	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
174962306a36Sopenharmony_ci	IXGBE_WRITE_FLUSH(&adapter->hw);
175062306a36Sopenharmony_ci	usleep_range(10000, 20000);
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	/* Test each interrupt */
175362306a36Sopenharmony_ci	for (; i < 10; i++) {
175462306a36Sopenharmony_ci		/* Interrupt to test */
175562306a36Sopenharmony_ci		mask = BIT(i);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci		if (!shared_int) {
175862306a36Sopenharmony_ci			/*
175962306a36Sopenharmony_ci			 * Disable the interrupts to be reported in
176062306a36Sopenharmony_ci			 * the cause register and then force the same
176162306a36Sopenharmony_ci			 * interrupt and see if one gets posted.  If
176262306a36Sopenharmony_ci			 * an interrupt was posted to the bus, the
176362306a36Sopenharmony_ci			 * test failed.
176462306a36Sopenharmony_ci			 */
176562306a36Sopenharmony_ci			adapter->test_icr = 0;
176662306a36Sopenharmony_ci			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC,
176762306a36Sopenharmony_ci					~mask & 0x00007FFF);
176862306a36Sopenharmony_ci			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
176962306a36Sopenharmony_ci					~mask & 0x00007FFF);
177062306a36Sopenharmony_ci			IXGBE_WRITE_FLUSH(&adapter->hw);
177162306a36Sopenharmony_ci			usleep_range(10000, 20000);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci			if (adapter->test_icr & mask) {
177462306a36Sopenharmony_ci				*data = 3;
177562306a36Sopenharmony_ci				break;
177662306a36Sopenharmony_ci			}
177762306a36Sopenharmony_ci		}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci		/*
178062306a36Sopenharmony_ci		 * Enable the interrupt to be reported in the cause
178162306a36Sopenharmony_ci		 * register and then force the same interrupt and see
178262306a36Sopenharmony_ci		 * if one gets posted.  If an interrupt was not posted
178362306a36Sopenharmony_ci		 * to the bus, the test failed.
178462306a36Sopenharmony_ci		 */
178562306a36Sopenharmony_ci		adapter->test_icr = 0;
178662306a36Sopenharmony_ci		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
178762306a36Sopenharmony_ci		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
178862306a36Sopenharmony_ci		IXGBE_WRITE_FLUSH(&adapter->hw);
178962306a36Sopenharmony_ci		usleep_range(10000, 20000);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci		if (!(adapter->test_icr & mask)) {
179262306a36Sopenharmony_ci			*data = 4;
179362306a36Sopenharmony_ci			break;
179462306a36Sopenharmony_ci		}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci		if (!shared_int) {
179762306a36Sopenharmony_ci			/*
179862306a36Sopenharmony_ci			 * Disable the other interrupts to be reported in
179962306a36Sopenharmony_ci			 * the cause register and then force the other
180062306a36Sopenharmony_ci			 * interrupts and see if any get posted.  If
180162306a36Sopenharmony_ci			 * an interrupt was posted to the bus, the
180262306a36Sopenharmony_ci			 * test failed.
180362306a36Sopenharmony_ci			 */
180462306a36Sopenharmony_ci			adapter->test_icr = 0;
180562306a36Sopenharmony_ci			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC,
180662306a36Sopenharmony_ci					~mask & 0x00007FFF);
180762306a36Sopenharmony_ci			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
180862306a36Sopenharmony_ci					~mask & 0x00007FFF);
180962306a36Sopenharmony_ci			IXGBE_WRITE_FLUSH(&adapter->hw);
181062306a36Sopenharmony_ci			usleep_range(10000, 20000);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci			if (adapter->test_icr) {
181362306a36Sopenharmony_ci				*data = 5;
181462306a36Sopenharmony_ci				break;
181562306a36Sopenharmony_ci			}
181662306a36Sopenharmony_ci		}
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	/* Disable all the interrupts */
182062306a36Sopenharmony_ci	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
182162306a36Sopenharmony_ci	IXGBE_WRITE_FLUSH(&adapter->hw);
182262306a36Sopenharmony_ci	usleep_range(10000, 20000);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/* Unhook test interrupt handler */
182562306a36Sopenharmony_ci	free_irq(irq, netdev);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	return *data;
182862306a36Sopenharmony_ci}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_cistatic void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
183162306a36Sopenharmony_ci{
183262306a36Sopenharmony_ci	/* Shut down the DMA engines now so they can be reinitialized later,
183362306a36Sopenharmony_ci	 * since the test rings and normally used rings should overlap on
183462306a36Sopenharmony_ci	 * queue 0 we can just use the standard disable Rx/Tx calls and they
183562306a36Sopenharmony_ci	 * will take care of disabling the test rings for us.
183662306a36Sopenharmony_ci	 */
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/* first Rx */
183962306a36Sopenharmony_ci	ixgbe_disable_rx(adapter);
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/* now Tx */
184262306a36Sopenharmony_ci	ixgbe_disable_tx(adapter);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	ixgbe_reset(adapter);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	ixgbe_free_tx_resources(&adapter->test_tx_ring);
184762306a36Sopenharmony_ci	ixgbe_free_rx_resources(&adapter->test_rx_ring);
184862306a36Sopenharmony_ci}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
185162306a36Sopenharmony_ci{
185262306a36Sopenharmony_ci	struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
185362306a36Sopenharmony_ci	struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
185462306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
185562306a36Sopenharmony_ci	u32 rctl, reg_data;
185662306a36Sopenharmony_ci	int ret_val;
185762306a36Sopenharmony_ci	int err;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	/* Setup Tx descriptor ring and Tx buffers */
186062306a36Sopenharmony_ci	tx_ring->count = IXGBE_DEFAULT_TXD;
186162306a36Sopenharmony_ci	tx_ring->queue_index = 0;
186262306a36Sopenharmony_ci	tx_ring->dev = &adapter->pdev->dev;
186362306a36Sopenharmony_ci	tx_ring->netdev = adapter->netdev;
186462306a36Sopenharmony_ci	tx_ring->reg_idx = adapter->tx_ring[0]->reg_idx;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	err = ixgbe_setup_tx_resources(tx_ring);
186762306a36Sopenharmony_ci	if (err)
186862306a36Sopenharmony_ci		return 1;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	switch (adapter->hw.mac.type) {
187162306a36Sopenharmony_ci	case ixgbe_mac_82599EB:
187262306a36Sopenharmony_ci	case ixgbe_mac_X540:
187362306a36Sopenharmony_ci	case ixgbe_mac_X550:
187462306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
187562306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
187662306a36Sopenharmony_ci		reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
187762306a36Sopenharmony_ci		reg_data |= IXGBE_DMATXCTL_TE;
187862306a36Sopenharmony_ci		IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
187962306a36Sopenharmony_ci		break;
188062306a36Sopenharmony_ci	default:
188162306a36Sopenharmony_ci		break;
188262306a36Sopenharmony_ci	}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	ixgbe_configure_tx_ring(adapter, tx_ring);
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	/* Setup Rx Descriptor ring and Rx buffers */
188762306a36Sopenharmony_ci	rx_ring->count = IXGBE_DEFAULT_RXD;
188862306a36Sopenharmony_ci	rx_ring->queue_index = 0;
188962306a36Sopenharmony_ci	rx_ring->dev = &adapter->pdev->dev;
189062306a36Sopenharmony_ci	rx_ring->netdev = adapter->netdev;
189162306a36Sopenharmony_ci	rx_ring->reg_idx = adapter->rx_ring[0]->reg_idx;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	err = ixgbe_setup_rx_resources(adapter, rx_ring);
189462306a36Sopenharmony_ci	if (err) {
189562306a36Sopenharmony_ci		ret_val = 4;
189662306a36Sopenharmony_ci		goto err_nomem;
189762306a36Sopenharmony_ci	}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	hw->mac.ops.disable_rx(hw);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	ixgbe_configure_rx_ring(adapter, rx_ring);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
190462306a36Sopenharmony_ci	rctl |= IXGBE_RXCTRL_DMBYPS;
190562306a36Sopenharmony_ci	IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	hw->mac.ops.enable_rx(hw);
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	return 0;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_cierr_nomem:
191262306a36Sopenharmony_ci	ixgbe_free_desc_rings(adapter);
191362306a36Sopenharmony_ci	return ret_val;
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_cistatic int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
191962306a36Sopenharmony_ci	u32 reg_data;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/* Setup MAC loopback */
192362306a36Sopenharmony_ci	reg_data = IXGBE_READ_REG(hw, IXGBE_HLREG0);
192462306a36Sopenharmony_ci	reg_data |= IXGBE_HLREG0_LPBK;
192562306a36Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_data);
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	reg_data = IXGBE_READ_REG(hw, IXGBE_FCTRL);
192862306a36Sopenharmony_ci	reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
192962306a36Sopenharmony_ci	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_data);
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	/* X540 and X550 needs to set the MACC.FLU bit to force link up */
193262306a36Sopenharmony_ci	switch (adapter->hw.mac.type) {
193362306a36Sopenharmony_ci	case ixgbe_mac_X540:
193462306a36Sopenharmony_ci	case ixgbe_mac_X550:
193562306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
193662306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
193762306a36Sopenharmony_ci		reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
193862306a36Sopenharmony_ci		reg_data |= IXGBE_MACC_FLU;
193962306a36Sopenharmony_ci		IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data);
194062306a36Sopenharmony_ci		break;
194162306a36Sopenharmony_ci	default:
194262306a36Sopenharmony_ci		if (hw->mac.orig_autoc) {
194362306a36Sopenharmony_ci			reg_data = hw->mac.orig_autoc | IXGBE_AUTOC_FLU;
194462306a36Sopenharmony_ci			IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_data);
194562306a36Sopenharmony_ci		} else {
194662306a36Sopenharmony_ci			return 10;
194762306a36Sopenharmony_ci		}
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci	IXGBE_WRITE_FLUSH(hw);
195062306a36Sopenharmony_ci	usleep_range(10000, 20000);
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	/* Disable Atlas Tx lanes; re-enabled in reset path */
195362306a36Sopenharmony_ci	if (hw->mac.type == ixgbe_mac_82598EB) {
195462306a36Sopenharmony_ci		u8 atlas;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &atlas);
195762306a36Sopenharmony_ci		atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
195862306a36Sopenharmony_ci		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, atlas);
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &atlas);
196162306a36Sopenharmony_ci		atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
196262306a36Sopenharmony_ci		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, atlas);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &atlas);
196562306a36Sopenharmony_ci		atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
196662306a36Sopenharmony_ci		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, atlas);
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci		hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &atlas);
196962306a36Sopenharmony_ci		atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
197062306a36Sopenharmony_ci		hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, atlas);
197162306a36Sopenharmony_ci	}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	return 0;
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_cistatic void ixgbe_loopback_cleanup(struct ixgbe_adapter *adapter)
197762306a36Sopenharmony_ci{
197862306a36Sopenharmony_ci	u32 reg_data;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
198162306a36Sopenharmony_ci	reg_data &= ~IXGBE_HLREG0_LPBK;
198262306a36Sopenharmony_ci	IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_cistatic void ixgbe_create_lbtest_frame(struct sk_buff *skb,
198662306a36Sopenharmony_ci				      unsigned int frame_size)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	memset(skb->data, 0xFF, frame_size);
198962306a36Sopenharmony_ci	frame_size >>= 1;
199062306a36Sopenharmony_ci	memset(&skb->data[frame_size], 0xAA, frame_size / 2 - 1);
199162306a36Sopenharmony_ci	skb->data[frame_size + 10] = 0xBE;
199262306a36Sopenharmony_ci	skb->data[frame_size + 12] = 0xAF;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_cistatic bool ixgbe_check_lbtest_frame(struct ixgbe_rx_buffer *rx_buffer,
199662306a36Sopenharmony_ci				     unsigned int frame_size)
199762306a36Sopenharmony_ci{
199862306a36Sopenharmony_ci	unsigned char *data;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	frame_size >>= 1;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	data = page_address(rx_buffer->page) + rx_buffer->page_offset;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	return data[3] == 0xFF && data[frame_size + 10] == 0xBE &&
200562306a36Sopenharmony_ci		data[frame_size + 12] == 0xAF;
200662306a36Sopenharmony_ci}
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_cistatic u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring,
200962306a36Sopenharmony_ci				  struct ixgbe_ring *tx_ring,
201062306a36Sopenharmony_ci				  unsigned int size)
201162306a36Sopenharmony_ci{
201262306a36Sopenharmony_ci	union ixgbe_adv_rx_desc *rx_desc;
201362306a36Sopenharmony_ci	u16 rx_ntc, tx_ntc, count = 0;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/* initialize next to clean and descriptor values */
201662306a36Sopenharmony_ci	rx_ntc = rx_ring->next_to_clean;
201762306a36Sopenharmony_ci	tx_ntc = tx_ring->next_to_clean;
201862306a36Sopenharmony_ci	rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	while (tx_ntc != tx_ring->next_to_use) {
202162306a36Sopenharmony_ci		union ixgbe_adv_tx_desc *tx_desc;
202262306a36Sopenharmony_ci		struct ixgbe_tx_buffer *tx_buffer;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci		tx_desc = IXGBE_TX_DESC(tx_ring, tx_ntc);
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci		/* if DD is not set transmit has not completed */
202762306a36Sopenharmony_ci		if (!(tx_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
202862306a36Sopenharmony_ci			return count;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci		/* unmap buffer on Tx side */
203162306a36Sopenharmony_ci		tx_buffer = &tx_ring->tx_buffer_info[tx_ntc];
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci		/* Free all the Tx ring sk_buffs */
203462306a36Sopenharmony_ci		dev_kfree_skb_any(tx_buffer->skb);
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci		/* unmap skb header data */
203762306a36Sopenharmony_ci		dma_unmap_single(tx_ring->dev,
203862306a36Sopenharmony_ci				 dma_unmap_addr(tx_buffer, dma),
203962306a36Sopenharmony_ci				 dma_unmap_len(tx_buffer, len),
204062306a36Sopenharmony_ci				 DMA_TO_DEVICE);
204162306a36Sopenharmony_ci		dma_unmap_len_set(tx_buffer, len, 0);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci		/* increment Tx next to clean counter */
204462306a36Sopenharmony_ci		tx_ntc++;
204562306a36Sopenharmony_ci		if (tx_ntc == tx_ring->count)
204662306a36Sopenharmony_ci			tx_ntc = 0;
204762306a36Sopenharmony_ci	}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	while (rx_desc->wb.upper.length) {
205062306a36Sopenharmony_ci		struct ixgbe_rx_buffer *rx_buffer;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci		/* check Rx buffer */
205362306a36Sopenharmony_ci		rx_buffer = &rx_ring->rx_buffer_info[rx_ntc];
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci		/* sync Rx buffer for CPU read */
205662306a36Sopenharmony_ci		dma_sync_single_for_cpu(rx_ring->dev,
205762306a36Sopenharmony_ci					rx_buffer->dma,
205862306a36Sopenharmony_ci					ixgbe_rx_bufsz(rx_ring),
205962306a36Sopenharmony_ci					DMA_FROM_DEVICE);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci		/* verify contents of skb */
206262306a36Sopenharmony_ci		if (ixgbe_check_lbtest_frame(rx_buffer, size))
206362306a36Sopenharmony_ci			count++;
206462306a36Sopenharmony_ci		else
206562306a36Sopenharmony_ci			break;
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci		/* sync Rx buffer for device write */
206862306a36Sopenharmony_ci		dma_sync_single_for_device(rx_ring->dev,
206962306a36Sopenharmony_ci					   rx_buffer->dma,
207062306a36Sopenharmony_ci					   ixgbe_rx_bufsz(rx_ring),
207162306a36Sopenharmony_ci					   DMA_FROM_DEVICE);
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci		/* increment Rx next to clean counter */
207462306a36Sopenharmony_ci		rx_ntc++;
207562306a36Sopenharmony_ci		if (rx_ntc == rx_ring->count)
207662306a36Sopenharmony_ci			rx_ntc = 0;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci		/* fetch next descriptor */
207962306a36Sopenharmony_ci		rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc);
208062306a36Sopenharmony_ci	}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	netdev_tx_reset_queue(txring_txq(tx_ring));
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	/* re-map buffers to ring, store next to clean values */
208562306a36Sopenharmony_ci	ixgbe_alloc_rx_buffers(rx_ring, count);
208662306a36Sopenharmony_ci	rx_ring->next_to_clean = rx_ntc;
208762306a36Sopenharmony_ci	tx_ring->next_to_clean = tx_ntc;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	return count;
209062306a36Sopenharmony_ci}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_cistatic int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
209362306a36Sopenharmony_ci{
209462306a36Sopenharmony_ci	struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
209562306a36Sopenharmony_ci	struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
209662306a36Sopenharmony_ci	int i, j, lc, good_cnt, ret_val = 0;
209762306a36Sopenharmony_ci	unsigned int size = 1024;
209862306a36Sopenharmony_ci	netdev_tx_t tx_ret_val;
209962306a36Sopenharmony_ci	struct sk_buff *skb;
210062306a36Sopenharmony_ci	u32 flags_orig = adapter->flags;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	/* DCB can modify the frames on Tx */
210362306a36Sopenharmony_ci	adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	/* allocate test skb */
210662306a36Sopenharmony_ci	skb = alloc_skb(size, GFP_KERNEL);
210762306a36Sopenharmony_ci	if (!skb)
210862306a36Sopenharmony_ci		return 11;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	/* place data into test skb */
211162306a36Sopenharmony_ci	ixgbe_create_lbtest_frame(skb, size);
211262306a36Sopenharmony_ci	skb_put(skb, size);
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	/*
211562306a36Sopenharmony_ci	 * Calculate the loop count based on the largest descriptor ring
211662306a36Sopenharmony_ci	 * The idea is to wrap the largest ring a number of times using 64
211762306a36Sopenharmony_ci	 * send/receive pairs during each loop
211862306a36Sopenharmony_ci	 */
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	if (rx_ring->count <= tx_ring->count)
212162306a36Sopenharmony_ci		lc = ((tx_ring->count / 64) * 2) + 1;
212262306a36Sopenharmony_ci	else
212362306a36Sopenharmony_ci		lc = ((rx_ring->count / 64) * 2) + 1;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	for (j = 0; j <= lc; j++) {
212662306a36Sopenharmony_ci		/* reset count of good packets */
212762306a36Sopenharmony_ci		good_cnt = 0;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci		/* place 64 packets on the transmit queue*/
213062306a36Sopenharmony_ci		for (i = 0; i < 64; i++) {
213162306a36Sopenharmony_ci			skb_get(skb);
213262306a36Sopenharmony_ci			tx_ret_val = ixgbe_xmit_frame_ring(skb,
213362306a36Sopenharmony_ci							   adapter,
213462306a36Sopenharmony_ci							   tx_ring);
213562306a36Sopenharmony_ci			if (tx_ret_val == NETDEV_TX_OK)
213662306a36Sopenharmony_ci				good_cnt++;
213762306a36Sopenharmony_ci		}
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci		if (good_cnt != 64) {
214062306a36Sopenharmony_ci			ret_val = 12;
214162306a36Sopenharmony_ci			break;
214262306a36Sopenharmony_ci		}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		/* allow 200 milliseconds for packets to go from Tx to Rx */
214562306a36Sopenharmony_ci		msleep(200);
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci		good_cnt = ixgbe_clean_test_rings(rx_ring, tx_ring, size);
214862306a36Sopenharmony_ci		if (good_cnt != 64) {
214962306a36Sopenharmony_ci			ret_val = 13;
215062306a36Sopenharmony_ci			break;
215162306a36Sopenharmony_ci		}
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	/* free the original skb */
215562306a36Sopenharmony_ci	kfree_skb(skb);
215662306a36Sopenharmony_ci	adapter->flags = flags_orig;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	return ret_val;
215962306a36Sopenharmony_ci}
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_cistatic int ixgbe_loopback_test(struct ixgbe_adapter *adapter, u64 *data)
216262306a36Sopenharmony_ci{
216362306a36Sopenharmony_ci	*data = ixgbe_setup_desc_rings(adapter);
216462306a36Sopenharmony_ci	if (*data)
216562306a36Sopenharmony_ci		goto out;
216662306a36Sopenharmony_ci	*data = ixgbe_setup_loopback_test(adapter);
216762306a36Sopenharmony_ci	if (*data)
216862306a36Sopenharmony_ci		goto err_loopback;
216962306a36Sopenharmony_ci	*data = ixgbe_run_loopback_test(adapter);
217062306a36Sopenharmony_ci	ixgbe_loopback_cleanup(adapter);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_cierr_loopback:
217362306a36Sopenharmony_ci	ixgbe_free_desc_rings(adapter);
217462306a36Sopenharmony_ciout:
217562306a36Sopenharmony_ci	return *data;
217662306a36Sopenharmony_ci}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_cistatic void ixgbe_diag_test(struct net_device *netdev,
217962306a36Sopenharmony_ci			    struct ethtool_test *eth_test, u64 *data)
218062306a36Sopenharmony_ci{
218162306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
218262306a36Sopenharmony_ci	bool if_running = netif_running(netdev);
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	if (ixgbe_removed(adapter->hw.hw_addr)) {
218562306a36Sopenharmony_ci		e_err(hw, "Adapter removed - test blocked\n");
218662306a36Sopenharmony_ci		data[0] = 1;
218762306a36Sopenharmony_ci		data[1] = 1;
218862306a36Sopenharmony_ci		data[2] = 1;
218962306a36Sopenharmony_ci		data[3] = 1;
219062306a36Sopenharmony_ci		data[4] = 1;
219162306a36Sopenharmony_ci		eth_test->flags |= ETH_TEST_FL_FAILED;
219262306a36Sopenharmony_ci		return;
219362306a36Sopenharmony_ci	}
219462306a36Sopenharmony_ci	set_bit(__IXGBE_TESTING, &adapter->state);
219562306a36Sopenharmony_ci	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
219662306a36Sopenharmony_ci		struct ixgbe_hw *hw = &adapter->hw;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci		if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
219962306a36Sopenharmony_ci			int i;
220062306a36Sopenharmony_ci			for (i = 0; i < adapter->num_vfs; i++) {
220162306a36Sopenharmony_ci				if (adapter->vfinfo[i].clear_to_send) {
220262306a36Sopenharmony_ci					netdev_warn(netdev, "offline diagnostic is not supported when VFs are present\n");
220362306a36Sopenharmony_ci					data[0] = 1;
220462306a36Sopenharmony_ci					data[1] = 1;
220562306a36Sopenharmony_ci					data[2] = 1;
220662306a36Sopenharmony_ci					data[3] = 1;
220762306a36Sopenharmony_ci					data[4] = 1;
220862306a36Sopenharmony_ci					eth_test->flags |= ETH_TEST_FL_FAILED;
220962306a36Sopenharmony_ci					clear_bit(__IXGBE_TESTING,
221062306a36Sopenharmony_ci						  &adapter->state);
221162306a36Sopenharmony_ci					return;
221262306a36Sopenharmony_ci				}
221362306a36Sopenharmony_ci			}
221462306a36Sopenharmony_ci		}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci		/* Offline tests */
221762306a36Sopenharmony_ci		e_info(hw, "offline testing starting\n");
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci		/* Link test performed before hardware reset so autoneg doesn't
222062306a36Sopenharmony_ci		 * interfere with test result
222162306a36Sopenharmony_ci		 */
222262306a36Sopenharmony_ci		if (ixgbe_link_test(adapter, &data[4]))
222362306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci		if (if_running)
222662306a36Sopenharmony_ci			/* indicate we're in test mode */
222762306a36Sopenharmony_ci			ixgbe_close(netdev);
222862306a36Sopenharmony_ci		else
222962306a36Sopenharmony_ci			ixgbe_reset(adapter);
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci		e_info(hw, "register testing starting\n");
223262306a36Sopenharmony_ci		if (ixgbe_reg_test(adapter, &data[0]))
223362306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci		ixgbe_reset(adapter);
223662306a36Sopenharmony_ci		e_info(hw, "eeprom testing starting\n");
223762306a36Sopenharmony_ci		if (ixgbe_eeprom_test(adapter, &data[1]))
223862306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci		ixgbe_reset(adapter);
224162306a36Sopenharmony_ci		e_info(hw, "interrupt testing starting\n");
224262306a36Sopenharmony_ci		if (ixgbe_intr_test(adapter, &data[2]))
224362306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci		/* If SRIOV or VMDq is enabled then skip MAC
224662306a36Sopenharmony_ci		 * loopback diagnostic. */
224762306a36Sopenharmony_ci		if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
224862306a36Sopenharmony_ci				      IXGBE_FLAG_VMDQ_ENABLED)) {
224962306a36Sopenharmony_ci			e_info(hw, "Skip MAC loopback diagnostic in VT mode\n");
225062306a36Sopenharmony_ci			data[3] = 0;
225162306a36Sopenharmony_ci			goto skip_loopback;
225262306a36Sopenharmony_ci		}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci		ixgbe_reset(adapter);
225562306a36Sopenharmony_ci		e_info(hw, "loopback testing starting\n");
225662306a36Sopenharmony_ci		if (ixgbe_loopback_test(adapter, &data[3]))
225762306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ciskip_loopback:
226062306a36Sopenharmony_ci		ixgbe_reset(adapter);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci		/* clear testing bit and return adapter to previous state */
226362306a36Sopenharmony_ci		clear_bit(__IXGBE_TESTING, &adapter->state);
226462306a36Sopenharmony_ci		if (if_running)
226562306a36Sopenharmony_ci			ixgbe_open(netdev);
226662306a36Sopenharmony_ci		else if (hw->mac.ops.disable_tx_laser)
226762306a36Sopenharmony_ci			hw->mac.ops.disable_tx_laser(hw);
226862306a36Sopenharmony_ci	} else {
226962306a36Sopenharmony_ci		e_info(hw, "online testing starting\n");
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci		/* Online tests */
227262306a36Sopenharmony_ci		if (ixgbe_link_test(adapter, &data[4]))
227362306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci		/* Offline tests aren't run; pass by default */
227662306a36Sopenharmony_ci		data[0] = 0;
227762306a36Sopenharmony_ci		data[1] = 0;
227862306a36Sopenharmony_ci		data[2] = 0;
227962306a36Sopenharmony_ci		data[3] = 0;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci		clear_bit(__IXGBE_TESTING, &adapter->state);
228262306a36Sopenharmony_ci	}
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_cistatic int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter,
228662306a36Sopenharmony_ci			       struct ethtool_wolinfo *wol)
228762306a36Sopenharmony_ci{
228862306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
228962306a36Sopenharmony_ci	int retval = 0;
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	/* WOL not supported for all devices */
229262306a36Sopenharmony_ci	if (!ixgbe_wol_supported(adapter, hw->device_id,
229362306a36Sopenharmony_ci				 hw->subsystem_device_id)) {
229462306a36Sopenharmony_ci		retval = 1;
229562306a36Sopenharmony_ci		wol->supported = 0;
229662306a36Sopenharmony_ci	}
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	return retval;
229962306a36Sopenharmony_ci}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_cistatic void ixgbe_get_wol(struct net_device *netdev,
230262306a36Sopenharmony_ci			  struct ethtool_wolinfo *wol)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	wol->supported = WAKE_UCAST | WAKE_MCAST |
230762306a36Sopenharmony_ci			 WAKE_BCAST | WAKE_MAGIC;
230862306a36Sopenharmony_ci	wol->wolopts = 0;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	if (ixgbe_wol_exclusion(adapter, wol) ||
231162306a36Sopenharmony_ci	    !device_can_wakeup(&adapter->pdev->dev))
231262306a36Sopenharmony_ci		return;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	if (adapter->wol & IXGBE_WUFC_EX)
231562306a36Sopenharmony_ci		wol->wolopts |= WAKE_UCAST;
231662306a36Sopenharmony_ci	if (adapter->wol & IXGBE_WUFC_MC)
231762306a36Sopenharmony_ci		wol->wolopts |= WAKE_MCAST;
231862306a36Sopenharmony_ci	if (adapter->wol & IXGBE_WUFC_BC)
231962306a36Sopenharmony_ci		wol->wolopts |= WAKE_BCAST;
232062306a36Sopenharmony_ci	if (adapter->wol & IXGBE_WUFC_MAG)
232162306a36Sopenharmony_ci		wol->wolopts |= WAKE_MAGIC;
232262306a36Sopenharmony_ci}
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_cistatic int ixgbe_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
232562306a36Sopenharmony_ci{
232662306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE |
232962306a36Sopenharmony_ci			    WAKE_FILTER))
233062306a36Sopenharmony_ci		return -EOPNOTSUPP;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	if (ixgbe_wol_exclusion(adapter, wol))
233362306a36Sopenharmony_ci		return wol->wolopts ? -EOPNOTSUPP : 0;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	adapter->wol = 0;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	if (wol->wolopts & WAKE_UCAST)
233862306a36Sopenharmony_ci		adapter->wol |= IXGBE_WUFC_EX;
233962306a36Sopenharmony_ci	if (wol->wolopts & WAKE_MCAST)
234062306a36Sopenharmony_ci		adapter->wol |= IXGBE_WUFC_MC;
234162306a36Sopenharmony_ci	if (wol->wolopts & WAKE_BCAST)
234262306a36Sopenharmony_ci		adapter->wol |= IXGBE_WUFC_BC;
234362306a36Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC)
234462306a36Sopenharmony_ci		adapter->wol |= IXGBE_WUFC_MAG;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	return 0;
234962306a36Sopenharmony_ci}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_cistatic int ixgbe_nway_reset(struct net_device *netdev)
235262306a36Sopenharmony_ci{
235362306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	if (netif_running(netdev))
235662306a36Sopenharmony_ci		ixgbe_reinit_locked(adapter);
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	return 0;
235962306a36Sopenharmony_ci}
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_cistatic int ixgbe_set_phys_id(struct net_device *netdev,
236262306a36Sopenharmony_ci			     enum ethtool_phys_id_state state)
236362306a36Sopenharmony_ci{
236462306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
236562306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	if (!hw->mac.ops.led_on || !hw->mac.ops.led_off)
236862306a36Sopenharmony_ci		return -EOPNOTSUPP;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	switch (state) {
237162306a36Sopenharmony_ci	case ETHTOOL_ID_ACTIVE:
237262306a36Sopenharmony_ci		adapter->led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
237362306a36Sopenharmony_ci		return 2;
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	case ETHTOOL_ID_ON:
237662306a36Sopenharmony_ci		hw->mac.ops.led_on(hw, hw->mac.led_link_act);
237762306a36Sopenharmony_ci		break;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	case ETHTOOL_ID_OFF:
238062306a36Sopenharmony_ci		hw->mac.ops.led_off(hw, hw->mac.led_link_act);
238162306a36Sopenharmony_ci		break;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	case ETHTOOL_ID_INACTIVE:
238462306a36Sopenharmony_ci		/* Restore LED settings */
238562306a36Sopenharmony_ci		IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, adapter->led_reg);
238662306a36Sopenharmony_ci		break;
238762306a36Sopenharmony_ci	}
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	return 0;
239062306a36Sopenharmony_ci}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_cistatic int ixgbe_get_coalesce(struct net_device *netdev,
239362306a36Sopenharmony_ci			      struct ethtool_coalesce *ec,
239462306a36Sopenharmony_ci			      struct kernel_ethtool_coalesce *kernel_coal,
239562306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
239662306a36Sopenharmony_ci{
239762306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	/* only valid if in constant ITR mode */
240062306a36Sopenharmony_ci	if (adapter->rx_itr_setting <= 1)
240162306a36Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->rx_itr_setting;
240262306a36Sopenharmony_ci	else
240362306a36Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	/* if in mixed tx/rx queues per vector mode, report only rx settings */
240662306a36Sopenharmony_ci	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count)
240762306a36Sopenharmony_ci		return 0;
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	/* only valid if in constant ITR mode */
241062306a36Sopenharmony_ci	if (adapter->tx_itr_setting <= 1)
241162306a36Sopenharmony_ci		ec->tx_coalesce_usecs = adapter->tx_itr_setting;
241262306a36Sopenharmony_ci	else
241362306a36Sopenharmony_ci		ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	return 0;
241662306a36Sopenharmony_ci}
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci/*
241962306a36Sopenharmony_ci * this function must be called before setting the new value of
242062306a36Sopenharmony_ci * rx_itr_setting
242162306a36Sopenharmony_ci */
242262306a36Sopenharmony_cistatic bool ixgbe_update_rsc(struct ixgbe_adapter *adapter)
242362306a36Sopenharmony_ci{
242462306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	/* nothing to do if LRO or RSC are not enabled */
242762306a36Sopenharmony_ci	if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) ||
242862306a36Sopenharmony_ci	    !(netdev->features & NETIF_F_LRO))
242962306a36Sopenharmony_ci		return false;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	/* check the feature flag value and enable RSC if necessary */
243262306a36Sopenharmony_ci	if (adapter->rx_itr_setting == 1 ||
243362306a36Sopenharmony_ci	    adapter->rx_itr_setting > IXGBE_MIN_RSC_ITR) {
243462306a36Sopenharmony_ci		if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)) {
243562306a36Sopenharmony_ci			adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
243662306a36Sopenharmony_ci			e_info(probe, "rx-usecs value high enough to re-enable RSC\n");
243762306a36Sopenharmony_ci			return true;
243862306a36Sopenharmony_ci		}
243962306a36Sopenharmony_ci	/* if interrupt rate is too high then disable RSC */
244062306a36Sopenharmony_ci	} else if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
244162306a36Sopenharmony_ci		adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
244262306a36Sopenharmony_ci		e_info(probe, "rx-usecs set too low, disabling RSC\n");
244362306a36Sopenharmony_ci		return true;
244462306a36Sopenharmony_ci	}
244562306a36Sopenharmony_ci	return false;
244662306a36Sopenharmony_ci}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cistatic int ixgbe_set_coalesce(struct net_device *netdev,
244962306a36Sopenharmony_ci			      struct ethtool_coalesce *ec,
245062306a36Sopenharmony_ci			      struct kernel_ethtool_coalesce *kernel_coal,
245162306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
245262306a36Sopenharmony_ci{
245362306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
245462306a36Sopenharmony_ci	struct ixgbe_q_vector *q_vector;
245562306a36Sopenharmony_ci	int i;
245662306a36Sopenharmony_ci	u16 tx_itr_param, rx_itr_param, tx_itr_prev;
245762306a36Sopenharmony_ci	bool need_reset = false;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) {
246062306a36Sopenharmony_ci		/* reject Tx specific changes in case of mixed RxTx vectors */
246162306a36Sopenharmony_ci		if (ec->tx_coalesce_usecs)
246262306a36Sopenharmony_ci			return -EINVAL;
246362306a36Sopenharmony_ci		tx_itr_prev = adapter->rx_itr_setting;
246462306a36Sopenharmony_ci	} else {
246562306a36Sopenharmony_ci		tx_itr_prev = adapter->tx_itr_setting;
246662306a36Sopenharmony_ci	}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	if ((ec->rx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)) ||
246962306a36Sopenharmony_ci	    (ec->tx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)))
247062306a36Sopenharmony_ci		return -EINVAL;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	if (ec->rx_coalesce_usecs > 1)
247362306a36Sopenharmony_ci		adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2;
247462306a36Sopenharmony_ci	else
247562306a36Sopenharmony_ci		adapter->rx_itr_setting = ec->rx_coalesce_usecs;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	if (adapter->rx_itr_setting == 1)
247862306a36Sopenharmony_ci		rx_itr_param = IXGBE_20K_ITR;
247962306a36Sopenharmony_ci	else
248062306a36Sopenharmony_ci		rx_itr_param = adapter->rx_itr_setting;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	if (ec->tx_coalesce_usecs > 1)
248362306a36Sopenharmony_ci		adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2;
248462306a36Sopenharmony_ci	else
248562306a36Sopenharmony_ci		adapter->tx_itr_setting = ec->tx_coalesce_usecs;
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	if (adapter->tx_itr_setting == 1)
248862306a36Sopenharmony_ci		tx_itr_param = IXGBE_12K_ITR;
248962306a36Sopenharmony_ci	else
249062306a36Sopenharmony_ci		tx_itr_param = adapter->tx_itr_setting;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	/* mixed Rx/Tx */
249362306a36Sopenharmony_ci	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count)
249462306a36Sopenharmony_ci		adapter->tx_itr_setting = adapter->rx_itr_setting;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	/* detect ITR changes that require update of TXDCTL.WTHRESH */
249762306a36Sopenharmony_ci	if ((adapter->tx_itr_setting != 1) &&
249862306a36Sopenharmony_ci	    (adapter->tx_itr_setting < IXGBE_100K_ITR)) {
249962306a36Sopenharmony_ci		if ((tx_itr_prev == 1) ||
250062306a36Sopenharmony_ci		    (tx_itr_prev >= IXGBE_100K_ITR))
250162306a36Sopenharmony_ci			need_reset = true;
250262306a36Sopenharmony_ci	} else {
250362306a36Sopenharmony_ci		if ((tx_itr_prev != 1) &&
250462306a36Sopenharmony_ci		    (tx_itr_prev < IXGBE_100K_ITR))
250562306a36Sopenharmony_ci			need_reset = true;
250662306a36Sopenharmony_ci	}
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	/* check the old value and enable RSC if necessary */
250962306a36Sopenharmony_ci	need_reset |= ixgbe_update_rsc(adapter);
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	for (i = 0; i < adapter->num_q_vectors; i++) {
251262306a36Sopenharmony_ci		q_vector = adapter->q_vector[i];
251362306a36Sopenharmony_ci		if (q_vector->tx.count && !q_vector->rx.count)
251462306a36Sopenharmony_ci			/* tx only */
251562306a36Sopenharmony_ci			q_vector->itr = tx_itr_param;
251662306a36Sopenharmony_ci		else
251762306a36Sopenharmony_ci			/* rx only or mixed */
251862306a36Sopenharmony_ci			q_vector->itr = rx_itr_param;
251962306a36Sopenharmony_ci		ixgbe_write_eitr(q_vector);
252062306a36Sopenharmony_ci	}
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	/*
252362306a36Sopenharmony_ci	 * do reset here at the end to make sure EITR==0 case is handled
252462306a36Sopenharmony_ci	 * correctly w.r.t stopping tx, and changing TXDCTL.WTHRESH settings
252562306a36Sopenharmony_ci	 * also locks in RSC enable/disable which requires reset
252662306a36Sopenharmony_ci	 */
252762306a36Sopenharmony_ci	if (need_reset)
252862306a36Sopenharmony_ci		ixgbe_do_reset(netdev);
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	return 0;
253162306a36Sopenharmony_ci}
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_cistatic int ixgbe_get_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
253462306a36Sopenharmony_ci					struct ethtool_rxnfc *cmd)
253562306a36Sopenharmony_ci{
253662306a36Sopenharmony_ci	union ixgbe_atr_input *mask = &adapter->fdir_mask;
253762306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp =
253862306a36Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
253962306a36Sopenharmony_ci	struct hlist_node *node2;
254062306a36Sopenharmony_ci	struct ixgbe_fdir_filter *rule = NULL;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	/* report total rule count */
254362306a36Sopenharmony_ci	cmd->data = (1024 << adapter->fdir_pballoc) - 2;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	hlist_for_each_entry_safe(rule, node2,
254662306a36Sopenharmony_ci				  &adapter->fdir_filter_list, fdir_node) {
254762306a36Sopenharmony_ci		if (fsp->location <= rule->sw_idx)
254862306a36Sopenharmony_ci			break;
254962306a36Sopenharmony_ci	}
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	if (!rule || fsp->location != rule->sw_idx)
255262306a36Sopenharmony_ci		return -EINVAL;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	/* fill out the flow spec entry */
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	/* set flow type field */
255762306a36Sopenharmony_ci	switch (rule->filter.formatted.flow_type) {
255862306a36Sopenharmony_ci	case IXGBE_ATR_FLOW_TYPE_TCPV4:
255962306a36Sopenharmony_ci		fsp->flow_type = TCP_V4_FLOW;
256062306a36Sopenharmony_ci		break;
256162306a36Sopenharmony_ci	case IXGBE_ATR_FLOW_TYPE_UDPV4:
256262306a36Sopenharmony_ci		fsp->flow_type = UDP_V4_FLOW;
256362306a36Sopenharmony_ci		break;
256462306a36Sopenharmony_ci	case IXGBE_ATR_FLOW_TYPE_SCTPV4:
256562306a36Sopenharmony_ci		fsp->flow_type = SCTP_V4_FLOW;
256662306a36Sopenharmony_ci		break;
256762306a36Sopenharmony_ci	case IXGBE_ATR_FLOW_TYPE_IPV4:
256862306a36Sopenharmony_ci		fsp->flow_type = IP_USER_FLOW;
256962306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
257062306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.proto = 0;
257162306a36Sopenharmony_ci		fsp->m_u.usr_ip4_spec.proto = 0;
257262306a36Sopenharmony_ci		break;
257362306a36Sopenharmony_ci	default:
257462306a36Sopenharmony_ci		return -EINVAL;
257562306a36Sopenharmony_ci	}
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	fsp->h_u.tcp_ip4_spec.psrc = rule->filter.formatted.src_port;
257862306a36Sopenharmony_ci	fsp->m_u.tcp_ip4_spec.psrc = mask->formatted.src_port;
257962306a36Sopenharmony_ci	fsp->h_u.tcp_ip4_spec.pdst = rule->filter.formatted.dst_port;
258062306a36Sopenharmony_ci	fsp->m_u.tcp_ip4_spec.pdst = mask->formatted.dst_port;
258162306a36Sopenharmony_ci	fsp->h_u.tcp_ip4_spec.ip4src = rule->filter.formatted.src_ip[0];
258262306a36Sopenharmony_ci	fsp->m_u.tcp_ip4_spec.ip4src = mask->formatted.src_ip[0];
258362306a36Sopenharmony_ci	fsp->h_u.tcp_ip4_spec.ip4dst = rule->filter.formatted.dst_ip[0];
258462306a36Sopenharmony_ci	fsp->m_u.tcp_ip4_spec.ip4dst = mask->formatted.dst_ip[0];
258562306a36Sopenharmony_ci	fsp->h_ext.vlan_tci = rule->filter.formatted.vlan_id;
258662306a36Sopenharmony_ci	fsp->m_ext.vlan_tci = mask->formatted.vlan_id;
258762306a36Sopenharmony_ci	fsp->h_ext.vlan_etype = rule->filter.formatted.flex_bytes;
258862306a36Sopenharmony_ci	fsp->m_ext.vlan_etype = mask->formatted.flex_bytes;
258962306a36Sopenharmony_ci	fsp->h_ext.data[1] = htonl(rule->filter.formatted.vm_pool);
259062306a36Sopenharmony_ci	fsp->m_ext.data[1] = htonl(mask->formatted.vm_pool);
259162306a36Sopenharmony_ci	fsp->flow_type |= FLOW_EXT;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	/* record action */
259462306a36Sopenharmony_ci	if (rule->action == IXGBE_FDIR_DROP_QUEUE)
259562306a36Sopenharmony_ci		fsp->ring_cookie = RX_CLS_FLOW_DISC;
259662306a36Sopenharmony_ci	else
259762306a36Sopenharmony_ci		fsp->ring_cookie = rule->action;
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	return 0;
260062306a36Sopenharmony_ci}
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_cistatic int ixgbe_get_ethtool_fdir_all(struct ixgbe_adapter *adapter,
260362306a36Sopenharmony_ci				      struct ethtool_rxnfc *cmd,
260462306a36Sopenharmony_ci				      u32 *rule_locs)
260562306a36Sopenharmony_ci{
260662306a36Sopenharmony_ci	struct hlist_node *node2;
260762306a36Sopenharmony_ci	struct ixgbe_fdir_filter *rule;
260862306a36Sopenharmony_ci	int cnt = 0;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	/* report total rule count */
261162306a36Sopenharmony_ci	cmd->data = (1024 << adapter->fdir_pballoc) - 2;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	hlist_for_each_entry_safe(rule, node2,
261462306a36Sopenharmony_ci				  &adapter->fdir_filter_list, fdir_node) {
261562306a36Sopenharmony_ci		if (cnt == cmd->rule_cnt)
261662306a36Sopenharmony_ci			return -EMSGSIZE;
261762306a36Sopenharmony_ci		rule_locs[cnt] = rule->sw_idx;
261862306a36Sopenharmony_ci		cnt++;
261962306a36Sopenharmony_ci	}
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	cmd->rule_cnt = cnt;
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	return 0;
262462306a36Sopenharmony_ci}
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_cistatic int ixgbe_get_rss_hash_opts(struct ixgbe_adapter *adapter,
262762306a36Sopenharmony_ci				   struct ethtool_rxnfc *cmd)
262862306a36Sopenharmony_ci{
262962306a36Sopenharmony_ci	cmd->data = 0;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	/* Report default options for RSS on ixgbe */
263262306a36Sopenharmony_ci	switch (cmd->flow_type) {
263362306a36Sopenharmony_ci	case TCP_V4_FLOW:
263462306a36Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
263562306a36Sopenharmony_ci		fallthrough;
263662306a36Sopenharmony_ci	case UDP_V4_FLOW:
263762306a36Sopenharmony_ci		if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
263862306a36Sopenharmony_ci			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
263962306a36Sopenharmony_ci		fallthrough;
264062306a36Sopenharmony_ci	case SCTP_V4_FLOW:
264162306a36Sopenharmony_ci	case AH_ESP_V4_FLOW:
264262306a36Sopenharmony_ci	case AH_V4_FLOW:
264362306a36Sopenharmony_ci	case ESP_V4_FLOW:
264462306a36Sopenharmony_ci	case IPV4_FLOW:
264562306a36Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
264662306a36Sopenharmony_ci		break;
264762306a36Sopenharmony_ci	case TCP_V6_FLOW:
264862306a36Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
264962306a36Sopenharmony_ci		fallthrough;
265062306a36Sopenharmony_ci	case UDP_V6_FLOW:
265162306a36Sopenharmony_ci		if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
265262306a36Sopenharmony_ci			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
265362306a36Sopenharmony_ci		fallthrough;
265462306a36Sopenharmony_ci	case SCTP_V6_FLOW:
265562306a36Sopenharmony_ci	case AH_ESP_V6_FLOW:
265662306a36Sopenharmony_ci	case AH_V6_FLOW:
265762306a36Sopenharmony_ci	case ESP_V6_FLOW:
265862306a36Sopenharmony_ci	case IPV6_FLOW:
265962306a36Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
266062306a36Sopenharmony_ci		break;
266162306a36Sopenharmony_ci	default:
266262306a36Sopenharmony_ci		return -EINVAL;
266362306a36Sopenharmony_ci	}
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	return 0;
266662306a36Sopenharmony_ci}
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_cistatic int ixgbe_rss_indir_tbl_max(struct ixgbe_adapter *adapter)
266962306a36Sopenharmony_ci{
267062306a36Sopenharmony_ci	if (adapter->hw.mac.type < ixgbe_mac_X550)
267162306a36Sopenharmony_ci		return 16;
267262306a36Sopenharmony_ci	else
267362306a36Sopenharmony_ci		return 64;
267462306a36Sopenharmony_ci}
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_cistatic int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
267762306a36Sopenharmony_ci			   u32 *rule_locs)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(dev);
268062306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	switch (cmd->cmd) {
268362306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
268462306a36Sopenharmony_ci		cmd->data = min_t(int, adapter->num_rx_queues,
268562306a36Sopenharmony_ci				  ixgbe_rss_indir_tbl_max(adapter));
268662306a36Sopenharmony_ci		ret = 0;
268762306a36Sopenharmony_ci		break;
268862306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
268962306a36Sopenharmony_ci		cmd->rule_cnt = adapter->fdir_filter_count;
269062306a36Sopenharmony_ci		ret = 0;
269162306a36Sopenharmony_ci		break;
269262306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
269362306a36Sopenharmony_ci		ret = ixgbe_get_ethtool_fdir_entry(adapter, cmd);
269462306a36Sopenharmony_ci		break;
269562306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
269662306a36Sopenharmony_ci		ret = ixgbe_get_ethtool_fdir_all(adapter, cmd, rule_locs);
269762306a36Sopenharmony_ci		break;
269862306a36Sopenharmony_ci	case ETHTOOL_GRXFH:
269962306a36Sopenharmony_ci		ret = ixgbe_get_rss_hash_opts(adapter, cmd);
270062306a36Sopenharmony_ci		break;
270162306a36Sopenharmony_ci	default:
270262306a36Sopenharmony_ci		break;
270362306a36Sopenharmony_ci	}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	return ret;
270662306a36Sopenharmony_ci}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ciint ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
270962306a36Sopenharmony_ci				    struct ixgbe_fdir_filter *input,
271062306a36Sopenharmony_ci				    u16 sw_idx)
271162306a36Sopenharmony_ci{
271262306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
271362306a36Sopenharmony_ci	struct hlist_node *node2;
271462306a36Sopenharmony_ci	struct ixgbe_fdir_filter *rule, *parent;
271562306a36Sopenharmony_ci	int err = -EINVAL;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	parent = NULL;
271862306a36Sopenharmony_ci	rule = NULL;
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	hlist_for_each_entry_safe(rule, node2,
272162306a36Sopenharmony_ci				  &adapter->fdir_filter_list, fdir_node) {
272262306a36Sopenharmony_ci		/* hash found, or no matching entry */
272362306a36Sopenharmony_ci		if (rule->sw_idx >= sw_idx)
272462306a36Sopenharmony_ci			break;
272562306a36Sopenharmony_ci		parent = rule;
272662306a36Sopenharmony_ci	}
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	/* if there is an old rule occupying our place remove it */
272962306a36Sopenharmony_ci	if (rule && (rule->sw_idx == sw_idx)) {
273062306a36Sopenharmony_ci		if (!input || (rule->filter.formatted.bkt_hash !=
273162306a36Sopenharmony_ci			       input->filter.formatted.bkt_hash)) {
273262306a36Sopenharmony_ci			err = ixgbe_fdir_erase_perfect_filter_82599(hw,
273362306a36Sopenharmony_ci								&rule->filter,
273462306a36Sopenharmony_ci								sw_idx);
273562306a36Sopenharmony_ci		}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci		hlist_del(&rule->fdir_node);
273862306a36Sopenharmony_ci		kfree(rule);
273962306a36Sopenharmony_ci		adapter->fdir_filter_count--;
274062306a36Sopenharmony_ci	}
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	/*
274362306a36Sopenharmony_ci	 * If no input this was a delete, err should be 0 if a rule was
274462306a36Sopenharmony_ci	 * successfully found and removed from the list else -EINVAL
274562306a36Sopenharmony_ci	 */
274662306a36Sopenharmony_ci	if (!input)
274762306a36Sopenharmony_ci		return err;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	/* initialize node and set software index */
275062306a36Sopenharmony_ci	INIT_HLIST_NODE(&input->fdir_node);
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	/* add filter to the list */
275362306a36Sopenharmony_ci	if (parent)
275462306a36Sopenharmony_ci		hlist_add_behind(&input->fdir_node, &parent->fdir_node);
275562306a36Sopenharmony_ci	else
275662306a36Sopenharmony_ci		hlist_add_head(&input->fdir_node,
275762306a36Sopenharmony_ci			       &adapter->fdir_filter_list);
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	/* update counts */
276062306a36Sopenharmony_ci	adapter->fdir_filter_count++;
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	return 0;
276362306a36Sopenharmony_ci}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_cistatic int ixgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp,
276662306a36Sopenharmony_ci				       u8 *flow_type)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci	switch (fsp->flow_type & ~FLOW_EXT) {
276962306a36Sopenharmony_ci	case TCP_V4_FLOW:
277062306a36Sopenharmony_ci		*flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
277162306a36Sopenharmony_ci		break;
277262306a36Sopenharmony_ci	case UDP_V4_FLOW:
277362306a36Sopenharmony_ci		*flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4;
277462306a36Sopenharmony_ci		break;
277562306a36Sopenharmony_ci	case SCTP_V4_FLOW:
277662306a36Sopenharmony_ci		*flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4;
277762306a36Sopenharmony_ci		break;
277862306a36Sopenharmony_ci	case IP_USER_FLOW:
277962306a36Sopenharmony_ci		switch (fsp->h_u.usr_ip4_spec.proto) {
278062306a36Sopenharmony_ci		case IPPROTO_TCP:
278162306a36Sopenharmony_ci			*flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
278262306a36Sopenharmony_ci			break;
278362306a36Sopenharmony_ci		case IPPROTO_UDP:
278462306a36Sopenharmony_ci			*flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4;
278562306a36Sopenharmony_ci			break;
278662306a36Sopenharmony_ci		case IPPROTO_SCTP:
278762306a36Sopenharmony_ci			*flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4;
278862306a36Sopenharmony_ci			break;
278962306a36Sopenharmony_ci		case 0:
279062306a36Sopenharmony_ci			if (!fsp->m_u.usr_ip4_spec.proto) {
279162306a36Sopenharmony_ci				*flow_type = IXGBE_ATR_FLOW_TYPE_IPV4;
279262306a36Sopenharmony_ci				break;
279362306a36Sopenharmony_ci			}
279462306a36Sopenharmony_ci			fallthrough;
279562306a36Sopenharmony_ci		default:
279662306a36Sopenharmony_ci			return 0;
279762306a36Sopenharmony_ci		}
279862306a36Sopenharmony_ci		break;
279962306a36Sopenharmony_ci	default:
280062306a36Sopenharmony_ci		return 0;
280162306a36Sopenharmony_ci	}
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	return 1;
280462306a36Sopenharmony_ci}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_cistatic int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
280762306a36Sopenharmony_ci					struct ethtool_rxnfc *cmd)
280862306a36Sopenharmony_ci{
280962306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp =
281062306a36Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
281162306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
281262306a36Sopenharmony_ci	struct ixgbe_fdir_filter *input;
281362306a36Sopenharmony_ci	union ixgbe_atr_input mask;
281462306a36Sopenharmony_ci	u8 queue;
281562306a36Sopenharmony_ci	int err;
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
281862306a36Sopenharmony_ci		return -EOPNOTSUPP;
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	/* ring_cookie is a masked into a set of queues and ixgbe pools or
282162306a36Sopenharmony_ci	 * we use the drop index.
282262306a36Sopenharmony_ci	 */
282362306a36Sopenharmony_ci	if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
282462306a36Sopenharmony_ci		queue = IXGBE_FDIR_DROP_QUEUE;
282562306a36Sopenharmony_ci	} else {
282662306a36Sopenharmony_ci		u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
282762306a36Sopenharmony_ci		u8 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci		if (!vf && (ring >= adapter->num_rx_queues))
283062306a36Sopenharmony_ci			return -EINVAL;
283162306a36Sopenharmony_ci		else if (vf &&
283262306a36Sopenharmony_ci			 ((vf > adapter->num_vfs) ||
283362306a36Sopenharmony_ci			   ring >= adapter->num_rx_queues_per_pool))
283462306a36Sopenharmony_ci			return -EINVAL;
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci		/* Map the ring onto the absolute queue index */
283762306a36Sopenharmony_ci		if (!vf)
283862306a36Sopenharmony_ci			queue = adapter->rx_ring[ring]->reg_idx;
283962306a36Sopenharmony_ci		else
284062306a36Sopenharmony_ci			queue = ((vf - 1) *
284162306a36Sopenharmony_ci				adapter->num_rx_queues_per_pool) + ring;
284262306a36Sopenharmony_ci	}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	/* Don't allow indexes to exist outside of available space */
284562306a36Sopenharmony_ci	if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2)) {
284662306a36Sopenharmony_ci		e_err(drv, "Location out of range\n");
284762306a36Sopenharmony_ci		return -EINVAL;
284862306a36Sopenharmony_ci	}
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	input = kzalloc(sizeof(*input), GFP_ATOMIC);
285162306a36Sopenharmony_ci	if (!input)
285262306a36Sopenharmony_ci		return -ENOMEM;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	memset(&mask, 0, sizeof(union ixgbe_atr_input));
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	/* set SW index */
285762306a36Sopenharmony_ci	input->sw_idx = fsp->location;
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	/* record flow type */
286062306a36Sopenharmony_ci	if (!ixgbe_flowspec_to_flow_type(fsp,
286162306a36Sopenharmony_ci					 &input->filter.formatted.flow_type)) {
286262306a36Sopenharmony_ci		e_err(drv, "Unrecognized flow type\n");
286362306a36Sopenharmony_ci		goto err_out;
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	mask.formatted.flow_type = IXGBE_ATR_L4TYPE_IPV6_MASK |
286762306a36Sopenharmony_ci				   IXGBE_ATR_L4TYPE_MASK;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	if (input->filter.formatted.flow_type == IXGBE_ATR_FLOW_TYPE_IPV4)
287062306a36Sopenharmony_ci		mask.formatted.flow_type &= IXGBE_ATR_L4TYPE_IPV6_MASK;
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci	/* Copy input into formatted structures */
287362306a36Sopenharmony_ci	input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
287462306a36Sopenharmony_ci	mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
287562306a36Sopenharmony_ci	input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
287662306a36Sopenharmony_ci	mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
287762306a36Sopenharmony_ci	input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc;
287862306a36Sopenharmony_ci	mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc;
287962306a36Sopenharmony_ci	input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
288062306a36Sopenharmony_ci	mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	if (fsp->flow_type & FLOW_EXT) {
288362306a36Sopenharmony_ci		input->filter.formatted.vm_pool =
288462306a36Sopenharmony_ci				(unsigned char)ntohl(fsp->h_ext.data[1]);
288562306a36Sopenharmony_ci		mask.formatted.vm_pool =
288662306a36Sopenharmony_ci				(unsigned char)ntohl(fsp->m_ext.data[1]);
288762306a36Sopenharmony_ci		input->filter.formatted.vlan_id = fsp->h_ext.vlan_tci;
288862306a36Sopenharmony_ci		mask.formatted.vlan_id = fsp->m_ext.vlan_tci;
288962306a36Sopenharmony_ci		input->filter.formatted.flex_bytes =
289062306a36Sopenharmony_ci						fsp->h_ext.vlan_etype;
289162306a36Sopenharmony_ci		mask.formatted.flex_bytes = fsp->m_ext.vlan_etype;
289262306a36Sopenharmony_ci	}
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci	/* determine if we need to drop or route the packet */
289562306a36Sopenharmony_ci	if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
289662306a36Sopenharmony_ci		input->action = IXGBE_FDIR_DROP_QUEUE;
289762306a36Sopenharmony_ci	else
289862306a36Sopenharmony_ci		input->action = fsp->ring_cookie;
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	spin_lock(&adapter->fdir_perfect_lock);
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	if (hlist_empty(&adapter->fdir_filter_list)) {
290362306a36Sopenharmony_ci		/* save mask and program input mask into HW */
290462306a36Sopenharmony_ci		memcpy(&adapter->fdir_mask, &mask, sizeof(mask));
290562306a36Sopenharmony_ci		err = ixgbe_fdir_set_input_mask_82599(hw, &mask);
290662306a36Sopenharmony_ci		if (err) {
290762306a36Sopenharmony_ci			e_err(drv, "Error writing mask\n");
290862306a36Sopenharmony_ci			goto err_out_w_lock;
290962306a36Sopenharmony_ci		}
291062306a36Sopenharmony_ci	} else if (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) {
291162306a36Sopenharmony_ci		e_err(drv, "Only one mask supported per port\n");
291262306a36Sopenharmony_ci		goto err_out_w_lock;
291362306a36Sopenharmony_ci	}
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	/* apply mask and compute/store hash */
291662306a36Sopenharmony_ci	ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask);
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci	/* program filters to filter memory */
291962306a36Sopenharmony_ci	err = ixgbe_fdir_write_perfect_filter_82599(hw,
292062306a36Sopenharmony_ci				&input->filter, input->sw_idx, queue);
292162306a36Sopenharmony_ci	if (err)
292262306a36Sopenharmony_ci		goto err_out_w_lock;
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	spin_unlock(&adapter->fdir_perfect_lock);
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	return err;
292962306a36Sopenharmony_cierr_out_w_lock:
293062306a36Sopenharmony_ci	spin_unlock(&adapter->fdir_perfect_lock);
293162306a36Sopenharmony_cierr_out:
293262306a36Sopenharmony_ci	kfree(input);
293362306a36Sopenharmony_ci	return -EINVAL;
293462306a36Sopenharmony_ci}
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_cistatic int ixgbe_del_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
293762306a36Sopenharmony_ci					struct ethtool_rxnfc *cmd)
293862306a36Sopenharmony_ci{
293962306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp =
294062306a36Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
294162306a36Sopenharmony_ci	int err;
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	spin_lock(&adapter->fdir_perfect_lock);
294462306a36Sopenharmony_ci	err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, fsp->location);
294562306a36Sopenharmony_ci	spin_unlock(&adapter->fdir_perfect_lock);
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	return err;
294862306a36Sopenharmony_ci}
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci#define UDP_RSS_FLAGS (IXGBE_FLAG2_RSS_FIELD_IPV4_UDP | \
295162306a36Sopenharmony_ci		       IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
295262306a36Sopenharmony_cistatic int ixgbe_set_rss_hash_opt(struct ixgbe_adapter *adapter,
295362306a36Sopenharmony_ci				  struct ethtool_rxnfc *nfc)
295462306a36Sopenharmony_ci{
295562306a36Sopenharmony_ci	u32 flags2 = adapter->flags2;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	/*
295862306a36Sopenharmony_ci	 * RSS does not support anything other than hashing
295962306a36Sopenharmony_ci	 * to queues on src and dst IPs and ports
296062306a36Sopenharmony_ci	 */
296162306a36Sopenharmony_ci	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
296262306a36Sopenharmony_ci			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
296362306a36Sopenharmony_ci		return -EINVAL;
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	switch (nfc->flow_type) {
296662306a36Sopenharmony_ci	case TCP_V4_FLOW:
296762306a36Sopenharmony_ci	case TCP_V6_FLOW:
296862306a36Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
296962306a36Sopenharmony_ci		    !(nfc->data & RXH_IP_DST) ||
297062306a36Sopenharmony_ci		    !(nfc->data & RXH_L4_B_0_1) ||
297162306a36Sopenharmony_ci		    !(nfc->data & RXH_L4_B_2_3))
297262306a36Sopenharmony_ci			return -EINVAL;
297362306a36Sopenharmony_ci		break;
297462306a36Sopenharmony_ci	case UDP_V4_FLOW:
297562306a36Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
297662306a36Sopenharmony_ci		    !(nfc->data & RXH_IP_DST))
297762306a36Sopenharmony_ci			return -EINVAL;
297862306a36Sopenharmony_ci		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
297962306a36Sopenharmony_ci		case 0:
298062306a36Sopenharmony_ci			flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV4_UDP;
298162306a36Sopenharmony_ci			break;
298262306a36Sopenharmony_ci		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
298362306a36Sopenharmony_ci			flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV4_UDP;
298462306a36Sopenharmony_ci			break;
298562306a36Sopenharmony_ci		default:
298662306a36Sopenharmony_ci			return -EINVAL;
298762306a36Sopenharmony_ci		}
298862306a36Sopenharmony_ci		break;
298962306a36Sopenharmony_ci	case UDP_V6_FLOW:
299062306a36Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
299162306a36Sopenharmony_ci		    !(nfc->data & RXH_IP_DST))
299262306a36Sopenharmony_ci			return -EINVAL;
299362306a36Sopenharmony_ci		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
299462306a36Sopenharmony_ci		case 0:
299562306a36Sopenharmony_ci			flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV6_UDP;
299662306a36Sopenharmony_ci			break;
299762306a36Sopenharmony_ci		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
299862306a36Sopenharmony_ci			flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV6_UDP;
299962306a36Sopenharmony_ci			break;
300062306a36Sopenharmony_ci		default:
300162306a36Sopenharmony_ci			return -EINVAL;
300262306a36Sopenharmony_ci		}
300362306a36Sopenharmony_ci		break;
300462306a36Sopenharmony_ci	case AH_ESP_V4_FLOW:
300562306a36Sopenharmony_ci	case AH_V4_FLOW:
300662306a36Sopenharmony_ci	case ESP_V4_FLOW:
300762306a36Sopenharmony_ci	case SCTP_V4_FLOW:
300862306a36Sopenharmony_ci	case AH_ESP_V6_FLOW:
300962306a36Sopenharmony_ci	case AH_V6_FLOW:
301062306a36Sopenharmony_ci	case ESP_V6_FLOW:
301162306a36Sopenharmony_ci	case SCTP_V6_FLOW:
301262306a36Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
301362306a36Sopenharmony_ci		    !(nfc->data & RXH_IP_DST) ||
301462306a36Sopenharmony_ci		    (nfc->data & RXH_L4_B_0_1) ||
301562306a36Sopenharmony_ci		    (nfc->data & RXH_L4_B_2_3))
301662306a36Sopenharmony_ci			return -EINVAL;
301762306a36Sopenharmony_ci		break;
301862306a36Sopenharmony_ci	default:
301962306a36Sopenharmony_ci		return -EINVAL;
302062306a36Sopenharmony_ci	}
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	/* if we changed something we need to update flags */
302362306a36Sopenharmony_ci	if (flags2 != adapter->flags2) {
302462306a36Sopenharmony_ci		struct ixgbe_hw *hw = &adapter->hw;
302562306a36Sopenharmony_ci		u32 mrqc;
302662306a36Sopenharmony_ci		unsigned int pf_pool = adapter->num_vfs;
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci		if ((hw->mac.type >= ixgbe_mac_X550) &&
302962306a36Sopenharmony_ci		    (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
303062306a36Sopenharmony_ci			mrqc = IXGBE_READ_REG(hw, IXGBE_PFVFMRQC(pf_pool));
303162306a36Sopenharmony_ci		else
303262306a36Sopenharmony_ci			mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC);
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci		if ((flags2 & UDP_RSS_FLAGS) &&
303562306a36Sopenharmony_ci		    !(adapter->flags2 & UDP_RSS_FLAGS))
303662306a36Sopenharmony_ci			e_warn(drv, "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci		adapter->flags2 = flags2;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci		/* Perform hash on these packet types */
304162306a36Sopenharmony_ci		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
304262306a36Sopenharmony_ci		      | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
304362306a36Sopenharmony_ci		      | IXGBE_MRQC_RSS_FIELD_IPV6
304462306a36Sopenharmony_ci		      | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci		mrqc &= ~(IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
304762306a36Sopenharmony_ci			  IXGBE_MRQC_RSS_FIELD_IPV6_UDP);
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci		if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
305062306a36Sopenharmony_ci			mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci		if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
305362306a36Sopenharmony_ci			mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci		if ((hw->mac.type >= ixgbe_mac_X550) &&
305662306a36Sopenharmony_ci		    (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
305762306a36Sopenharmony_ci			IXGBE_WRITE_REG(hw, IXGBE_PFVFMRQC(pf_pool), mrqc);
305862306a36Sopenharmony_ci		else
305962306a36Sopenharmony_ci			IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
306062306a36Sopenharmony_ci	}
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	return 0;
306362306a36Sopenharmony_ci}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_cistatic int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
306662306a36Sopenharmony_ci{
306762306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(dev);
306862306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	switch (cmd->cmd) {
307162306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
307262306a36Sopenharmony_ci		ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd);
307362306a36Sopenharmony_ci		break;
307462306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
307562306a36Sopenharmony_ci		ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd);
307662306a36Sopenharmony_ci		break;
307762306a36Sopenharmony_ci	case ETHTOOL_SRXFH:
307862306a36Sopenharmony_ci		ret = ixgbe_set_rss_hash_opt(adapter, cmd);
307962306a36Sopenharmony_ci		break;
308062306a36Sopenharmony_ci	default:
308162306a36Sopenharmony_ci		break;
308262306a36Sopenharmony_ci	}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	return ret;
308562306a36Sopenharmony_ci}
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_cistatic u32 ixgbe_get_rxfh_key_size(struct net_device *netdev)
308862306a36Sopenharmony_ci{
308962306a36Sopenharmony_ci	return IXGBE_RSS_KEY_SIZE;
309062306a36Sopenharmony_ci}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_cistatic u32 ixgbe_rss_indir_size(struct net_device *netdev)
309362306a36Sopenharmony_ci{
309462306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	return ixgbe_rss_indir_tbl_entries(adapter);
309762306a36Sopenharmony_ci}
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_cistatic void ixgbe_get_reta(struct ixgbe_adapter *adapter, u32 *indir)
310062306a36Sopenharmony_ci{
310162306a36Sopenharmony_ci	int i, reta_size = ixgbe_rss_indir_tbl_entries(adapter);
310262306a36Sopenharmony_ci	u16 rss_m = adapter->ring_feature[RING_F_RSS].mask;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
310562306a36Sopenharmony_ci		rss_m = adapter->ring_feature[RING_F_RSS].indices - 1;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	for (i = 0; i < reta_size; i++)
310862306a36Sopenharmony_ci		indir[i] = adapter->rss_indir_tbl[i] & rss_m;
310962306a36Sopenharmony_ci}
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_cistatic int ixgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
311262306a36Sopenharmony_ci			  u8 *hfunc)
311362306a36Sopenharmony_ci{
311462306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ci	if (hfunc)
311762306a36Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	if (indir)
312062306a36Sopenharmony_ci		ixgbe_get_reta(adapter, indir);
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	if (key)
312362306a36Sopenharmony_ci		memcpy(key, adapter->rss_key, ixgbe_get_rxfh_key_size(netdev));
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	return 0;
312662306a36Sopenharmony_ci}
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_cistatic int ixgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
312962306a36Sopenharmony_ci			  const u8 *key, const u8 hfunc)
313062306a36Sopenharmony_ci{
313162306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
313262306a36Sopenharmony_ci	int i;
313362306a36Sopenharmony_ci	u32 reta_entries = ixgbe_rss_indir_tbl_entries(adapter);
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
313662306a36Sopenharmony_ci		return -EOPNOTSUPP;
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	/* Fill out the redirection table */
313962306a36Sopenharmony_ci	if (indir) {
314062306a36Sopenharmony_ci		int max_queues = min_t(int, adapter->num_rx_queues,
314162306a36Sopenharmony_ci				       ixgbe_rss_indir_tbl_max(adapter));
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ci		/*Allow at least 2 queues w/ SR-IOV.*/
314462306a36Sopenharmony_ci		if ((adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) &&
314562306a36Sopenharmony_ci		    (max_queues < 2))
314662306a36Sopenharmony_ci			max_queues = 2;
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci		/* Verify user input. */
314962306a36Sopenharmony_ci		for (i = 0; i < reta_entries; i++)
315062306a36Sopenharmony_ci			if (indir[i] >= max_queues)
315162306a36Sopenharmony_ci				return -EINVAL;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci		for (i = 0; i < reta_entries; i++)
315462306a36Sopenharmony_ci			adapter->rss_indir_tbl[i] = indir[i];
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci		ixgbe_store_reta(adapter);
315762306a36Sopenharmony_ci	}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	/* Fill out the rss hash key */
316062306a36Sopenharmony_ci	if (key) {
316162306a36Sopenharmony_ci		memcpy(adapter->rss_key, key, ixgbe_get_rxfh_key_size(netdev));
316262306a36Sopenharmony_ci		ixgbe_store_key(adapter);
316362306a36Sopenharmony_ci	}
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	return 0;
316662306a36Sopenharmony_ci}
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_cistatic int ixgbe_get_ts_info(struct net_device *dev,
316962306a36Sopenharmony_ci			     struct ethtool_ts_info *info)
317062306a36Sopenharmony_ci{
317162306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(dev);
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci	/* we always support timestamping disabled */
317462306a36Sopenharmony_ci	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	switch (adapter->hw.mac.type) {
317762306a36Sopenharmony_ci	case ixgbe_mac_X550:
317862306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
317962306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
318062306a36Sopenharmony_ci		info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL);
318162306a36Sopenharmony_ci		break;
318262306a36Sopenharmony_ci	case ixgbe_mac_X540:
318362306a36Sopenharmony_ci	case ixgbe_mac_82599EB:
318462306a36Sopenharmony_ci		info->rx_filters |=
318562306a36Sopenharmony_ci			BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
318662306a36Sopenharmony_ci			BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
318762306a36Sopenharmony_ci			BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
318862306a36Sopenharmony_ci		break;
318962306a36Sopenharmony_ci	default:
319062306a36Sopenharmony_ci		return ethtool_op_get_ts_info(dev, info);
319162306a36Sopenharmony_ci	}
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	info->so_timestamping =
319462306a36Sopenharmony_ci		SOF_TIMESTAMPING_TX_SOFTWARE |
319562306a36Sopenharmony_ci		SOF_TIMESTAMPING_RX_SOFTWARE |
319662306a36Sopenharmony_ci		SOF_TIMESTAMPING_SOFTWARE |
319762306a36Sopenharmony_ci		SOF_TIMESTAMPING_TX_HARDWARE |
319862306a36Sopenharmony_ci		SOF_TIMESTAMPING_RX_HARDWARE |
319962306a36Sopenharmony_ci		SOF_TIMESTAMPING_RAW_HARDWARE;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	if (adapter->ptp_clock)
320262306a36Sopenharmony_ci		info->phc_index = ptp_clock_index(adapter->ptp_clock);
320362306a36Sopenharmony_ci	else
320462306a36Sopenharmony_ci		info->phc_index = -1;
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	info->tx_types =
320762306a36Sopenharmony_ci		BIT(HWTSTAMP_TX_OFF) |
320862306a36Sopenharmony_ci		BIT(HWTSTAMP_TX_ON);
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	return 0;
321162306a36Sopenharmony_ci}
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_cistatic unsigned int ixgbe_max_channels(struct ixgbe_adapter *adapter)
321462306a36Sopenharmony_ci{
321562306a36Sopenharmony_ci	unsigned int max_combined;
321662306a36Sopenharmony_ci	u8 tcs = adapter->hw_tcs;
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
321962306a36Sopenharmony_ci		/* We only support one q_vector without MSI-X */
322062306a36Sopenharmony_ci		max_combined = 1;
322162306a36Sopenharmony_ci	} else if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
322262306a36Sopenharmony_ci		/* Limit value based on the queue mask */
322362306a36Sopenharmony_ci		max_combined = adapter->ring_feature[RING_F_RSS].mask + 1;
322462306a36Sopenharmony_ci	} else if (tcs > 1) {
322562306a36Sopenharmony_ci		/* For DCB report channels per traffic class */
322662306a36Sopenharmony_ci		if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
322762306a36Sopenharmony_ci			/* 8 TC w/ 4 queues per TC */
322862306a36Sopenharmony_ci			max_combined = 4;
322962306a36Sopenharmony_ci		} else if (tcs > 4) {
323062306a36Sopenharmony_ci			/* 8 TC w/ 8 queues per TC */
323162306a36Sopenharmony_ci			max_combined = 8;
323262306a36Sopenharmony_ci		} else {
323362306a36Sopenharmony_ci			/* 4 TC w/ 16 queues per TC */
323462306a36Sopenharmony_ci			max_combined = 16;
323562306a36Sopenharmony_ci		}
323662306a36Sopenharmony_ci	} else if (adapter->atr_sample_rate) {
323762306a36Sopenharmony_ci		/* support up to 64 queues with ATR */
323862306a36Sopenharmony_ci		max_combined = IXGBE_MAX_FDIR_INDICES;
323962306a36Sopenharmony_ci	} else {
324062306a36Sopenharmony_ci		/* support up to 16 queues with RSS */
324162306a36Sopenharmony_ci		max_combined = ixgbe_max_rss_indices(adapter);
324262306a36Sopenharmony_ci	}
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	return min_t(int, max_combined, num_online_cpus());
324562306a36Sopenharmony_ci}
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_cistatic void ixgbe_get_channels(struct net_device *dev,
324862306a36Sopenharmony_ci			       struct ethtool_channels *ch)
324962306a36Sopenharmony_ci{
325062306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(dev);
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_ci	/* report maximum channels */
325362306a36Sopenharmony_ci	ch->max_combined = ixgbe_max_channels(adapter);
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	/* report info for other vector */
325662306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
325762306a36Sopenharmony_ci		ch->max_other = NON_Q_VECTORS;
325862306a36Sopenharmony_ci		ch->other_count = NON_Q_VECTORS;
325962306a36Sopenharmony_ci	}
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	/* record RSS queues */
326262306a36Sopenharmony_ci	ch->combined_count = adapter->ring_feature[RING_F_RSS].indices;
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci	/* nothing else to report if RSS is disabled */
326562306a36Sopenharmony_ci	if (ch->combined_count == 1)
326662306a36Sopenharmony_ci		return;
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	/* we do not support ATR queueing if SR-IOV is enabled */
326962306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
327062306a36Sopenharmony_ci		return;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	/* same thing goes for being DCB enabled */
327362306a36Sopenharmony_ci	if (adapter->hw_tcs > 1)
327462306a36Sopenharmony_ci		return;
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	/* if ATR is disabled we can exit */
327762306a36Sopenharmony_ci	if (!adapter->atr_sample_rate)
327862306a36Sopenharmony_ci		return;
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	/* report flow director queues as maximum channels */
328162306a36Sopenharmony_ci	ch->combined_count = adapter->ring_feature[RING_F_FDIR].indices;
328262306a36Sopenharmony_ci}
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_cistatic int ixgbe_set_channels(struct net_device *dev,
328562306a36Sopenharmony_ci			      struct ethtool_channels *ch)
328662306a36Sopenharmony_ci{
328762306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(dev);
328862306a36Sopenharmony_ci	unsigned int count = ch->combined_count;
328962306a36Sopenharmony_ci	u8 max_rss_indices = ixgbe_max_rss_indices(adapter);
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci	/* verify they are not requesting separate vectors */
329262306a36Sopenharmony_ci	if (!count || ch->rx_count || ch->tx_count)
329362306a36Sopenharmony_ci		return -EINVAL;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	/* verify other_count has not changed */
329662306a36Sopenharmony_ci	if (ch->other_count != NON_Q_VECTORS)
329762306a36Sopenharmony_ci		return -EINVAL;
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	/* verify the number of channels does not exceed hardware limits */
330062306a36Sopenharmony_ci	if (count > ixgbe_max_channels(adapter))
330162306a36Sopenharmony_ci		return -EINVAL;
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci	/* update feature limits from largest to smallest supported values */
330462306a36Sopenharmony_ci	adapter->ring_feature[RING_F_FDIR].limit = count;
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	/* cap RSS limit */
330762306a36Sopenharmony_ci	if (count > max_rss_indices)
330862306a36Sopenharmony_ci		count = max_rss_indices;
330962306a36Sopenharmony_ci	adapter->ring_feature[RING_F_RSS].limit = count;
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci#ifdef IXGBE_FCOE
331262306a36Sopenharmony_ci	/* cap FCoE limit at 8 */
331362306a36Sopenharmony_ci	if (count > IXGBE_FCRETA_SIZE)
331462306a36Sopenharmony_ci		count = IXGBE_FCRETA_SIZE;
331562306a36Sopenharmony_ci	adapter->ring_feature[RING_F_FCOE].limit = count;
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci#endif
331862306a36Sopenharmony_ci	/* use setup TC to update any traffic class queue mapping */
331962306a36Sopenharmony_ci	return ixgbe_setup_tc(dev, adapter->hw_tcs);
332062306a36Sopenharmony_ci}
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_cistatic int ixgbe_get_module_info(struct net_device *dev,
332362306a36Sopenharmony_ci				       struct ethtool_modinfo *modinfo)
332462306a36Sopenharmony_ci{
332562306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(dev);
332662306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
332762306a36Sopenharmony_ci	s32 status;
332862306a36Sopenharmony_ci	u8 sff8472_rev, addr_mode;
332962306a36Sopenharmony_ci	bool page_swap = false;
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	if (hw->phy.type == ixgbe_phy_fw)
333262306a36Sopenharmony_ci		return -ENXIO;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	/* Check whether we support SFF-8472 or not */
333562306a36Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw,
333662306a36Sopenharmony_ci					     IXGBE_SFF_SFF_8472_COMP,
333762306a36Sopenharmony_ci					     &sff8472_rev);
333862306a36Sopenharmony_ci	if (status)
333962306a36Sopenharmony_ci		return -EIO;
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	/* addressing mode is not supported */
334262306a36Sopenharmony_ci	status = hw->phy.ops.read_i2c_eeprom(hw,
334362306a36Sopenharmony_ci					     IXGBE_SFF_SFF_8472_SWAP,
334462306a36Sopenharmony_ci					     &addr_mode);
334562306a36Sopenharmony_ci	if (status)
334662306a36Sopenharmony_ci		return -EIO;
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
334962306a36Sopenharmony_ci		e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
335062306a36Sopenharmony_ci		page_swap = true;
335162306a36Sopenharmony_ci	}
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci	if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap ||
335462306a36Sopenharmony_ci	    !(addr_mode & IXGBE_SFF_DDM_IMPLEMENTED)) {
335562306a36Sopenharmony_ci		/* We have a SFP, but it does not support SFF-8472 */
335662306a36Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8079;
335762306a36Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
335862306a36Sopenharmony_ci	} else {
335962306a36Sopenharmony_ci		/* We have a SFP which supports a revision of SFF-8472. */
336062306a36Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8472;
336162306a36Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
336262306a36Sopenharmony_ci	}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	return 0;
336562306a36Sopenharmony_ci}
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_cistatic int ixgbe_get_module_eeprom(struct net_device *dev,
336862306a36Sopenharmony_ci					 struct ethtool_eeprom *ee,
336962306a36Sopenharmony_ci					 u8 *data)
337062306a36Sopenharmony_ci{
337162306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(dev);
337262306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
337362306a36Sopenharmony_ci	s32 status = -EFAULT;
337462306a36Sopenharmony_ci	u8 databyte = 0xFF;
337562306a36Sopenharmony_ci	int i = 0;
337662306a36Sopenharmony_ci
337762306a36Sopenharmony_ci	if (ee->len == 0)
337862306a36Sopenharmony_ci		return -EINVAL;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	if (hw->phy.type == ixgbe_phy_fw)
338162306a36Sopenharmony_ci		return -ENXIO;
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	for (i = ee->offset; i < ee->offset + ee->len; i++) {
338462306a36Sopenharmony_ci		/* I2C reads can take long time */
338562306a36Sopenharmony_ci		if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
338662306a36Sopenharmony_ci			return -EBUSY;
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci		if (i < ETH_MODULE_SFF_8079_LEN)
338962306a36Sopenharmony_ci			status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
339062306a36Sopenharmony_ci		else
339162306a36Sopenharmony_ci			status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte);
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci		if (status)
339462306a36Sopenharmony_ci			return -EIO;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci		data[i - ee->offset] = databyte;
339762306a36Sopenharmony_ci	}
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	return 0;
340062306a36Sopenharmony_ci}
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_cistatic const struct {
340362306a36Sopenharmony_ci	ixgbe_link_speed mac_speed;
340462306a36Sopenharmony_ci	u32 supported;
340562306a36Sopenharmony_ci} ixgbe_ls_map[] = {
340662306a36Sopenharmony_ci	{ IXGBE_LINK_SPEED_10_FULL, SUPPORTED_10baseT_Full },
340762306a36Sopenharmony_ci	{ IXGBE_LINK_SPEED_100_FULL, SUPPORTED_100baseT_Full },
340862306a36Sopenharmony_ci	{ IXGBE_LINK_SPEED_1GB_FULL, SUPPORTED_1000baseT_Full },
340962306a36Sopenharmony_ci	{ IXGBE_LINK_SPEED_2_5GB_FULL, SUPPORTED_2500baseX_Full },
341062306a36Sopenharmony_ci	{ IXGBE_LINK_SPEED_10GB_FULL, SUPPORTED_10000baseT_Full },
341162306a36Sopenharmony_ci};
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_cistatic const struct {
341462306a36Sopenharmony_ci	u32 lp_advertised;
341562306a36Sopenharmony_ci	u32 mac_speed;
341662306a36Sopenharmony_ci} ixgbe_lp_map[] = {
341762306a36Sopenharmony_ci	{ FW_PHY_ACT_UD_2_100M_TX_EEE, SUPPORTED_100baseT_Full },
341862306a36Sopenharmony_ci	{ FW_PHY_ACT_UD_2_1G_T_EEE, SUPPORTED_1000baseT_Full },
341962306a36Sopenharmony_ci	{ FW_PHY_ACT_UD_2_10G_T_EEE, SUPPORTED_10000baseT_Full },
342062306a36Sopenharmony_ci	{ FW_PHY_ACT_UD_2_1G_KX_EEE, SUPPORTED_1000baseKX_Full },
342162306a36Sopenharmony_ci	{ FW_PHY_ACT_UD_2_10G_KX4_EEE, SUPPORTED_10000baseKX4_Full },
342262306a36Sopenharmony_ci	{ FW_PHY_ACT_UD_2_10G_KR_EEE, SUPPORTED_10000baseKR_Full},
342362306a36Sopenharmony_ci};
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_cistatic int
342662306a36Sopenharmony_ciixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_eee *edata)
342762306a36Sopenharmony_ci{
342862306a36Sopenharmony_ci	u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 };
342962306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
343062306a36Sopenharmony_ci	s32 rc;
343162306a36Sopenharmony_ci	u16 i;
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_UD_2, &info);
343462306a36Sopenharmony_ci	if (rc)
343562306a36Sopenharmony_ci		return rc;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	edata->lp_advertised = 0;
343862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ixgbe_lp_map); ++i) {
343962306a36Sopenharmony_ci		if (info[0] & ixgbe_lp_map[i].lp_advertised)
344062306a36Sopenharmony_ci			edata->lp_advertised |= ixgbe_lp_map[i].mac_speed;
344162306a36Sopenharmony_ci	}
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_ci	edata->supported = 0;
344462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) {
344562306a36Sopenharmony_ci		if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed)
344662306a36Sopenharmony_ci			edata->supported |= ixgbe_ls_map[i].supported;
344762306a36Sopenharmony_ci	}
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	edata->advertised = 0;
345062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) {
345162306a36Sopenharmony_ci		if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed)
345262306a36Sopenharmony_ci			edata->advertised |= ixgbe_ls_map[i].supported;
345362306a36Sopenharmony_ci	}
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_ci	edata->eee_enabled = !!edata->advertised;
345662306a36Sopenharmony_ci	edata->tx_lpi_enabled = edata->eee_enabled;
345762306a36Sopenharmony_ci	if (edata->advertised & edata->lp_advertised)
345862306a36Sopenharmony_ci		edata->eee_active = true;
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	return 0;
346162306a36Sopenharmony_ci}
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_cistatic int ixgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
346462306a36Sopenharmony_ci{
346562306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
346662306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE))
346962306a36Sopenharmony_ci		return -EOPNOTSUPP;
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ci	if (hw->phy.eee_speeds_supported && hw->phy.type == ixgbe_phy_fw)
347262306a36Sopenharmony_ci		return ixgbe_get_eee_fw(adapter, edata);
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	return -EOPNOTSUPP;
347562306a36Sopenharmony_ci}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_cistatic int ixgbe_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
347862306a36Sopenharmony_ci{
347962306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
348062306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
348162306a36Sopenharmony_ci	struct ethtool_eee eee_data;
348262306a36Sopenharmony_ci	s32 ret_val;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE))
348562306a36Sopenharmony_ci		return -EOPNOTSUPP;
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci	memset(&eee_data, 0, sizeof(struct ethtool_eee));
348862306a36Sopenharmony_ci
348962306a36Sopenharmony_ci	ret_val = ixgbe_get_eee(netdev, &eee_data);
349062306a36Sopenharmony_ci	if (ret_val)
349162306a36Sopenharmony_ci		return ret_val;
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	if (eee_data.eee_enabled && !edata->eee_enabled) {
349462306a36Sopenharmony_ci		if (eee_data.tx_lpi_enabled != edata->tx_lpi_enabled) {
349562306a36Sopenharmony_ci			e_err(drv, "Setting EEE tx-lpi is not supported\n");
349662306a36Sopenharmony_ci			return -EINVAL;
349762306a36Sopenharmony_ci		}
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci		if (eee_data.tx_lpi_timer != edata->tx_lpi_timer) {
350062306a36Sopenharmony_ci			e_err(drv,
350162306a36Sopenharmony_ci			      "Setting EEE Tx LPI timer is not supported\n");
350262306a36Sopenharmony_ci			return -EINVAL;
350362306a36Sopenharmony_ci		}
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci		if (eee_data.advertised != edata->advertised) {
350662306a36Sopenharmony_ci			e_err(drv,
350762306a36Sopenharmony_ci			      "Setting EEE advertised speeds is not supported\n");
350862306a36Sopenharmony_ci			return -EINVAL;
350962306a36Sopenharmony_ci		}
351062306a36Sopenharmony_ci	}
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	if (eee_data.eee_enabled != edata->eee_enabled) {
351362306a36Sopenharmony_ci		if (edata->eee_enabled) {
351462306a36Sopenharmony_ci			adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
351562306a36Sopenharmony_ci			hw->phy.eee_speeds_advertised =
351662306a36Sopenharmony_ci						   hw->phy.eee_speeds_supported;
351762306a36Sopenharmony_ci		} else {
351862306a36Sopenharmony_ci			adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
351962306a36Sopenharmony_ci			hw->phy.eee_speeds_advertised = 0;
352062306a36Sopenharmony_ci		}
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci		/* reset link */
352362306a36Sopenharmony_ci		if (netif_running(netdev))
352462306a36Sopenharmony_ci			ixgbe_reinit_locked(adapter);
352562306a36Sopenharmony_ci		else
352662306a36Sopenharmony_ci			ixgbe_reset(adapter);
352762306a36Sopenharmony_ci	}
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci	return 0;
353062306a36Sopenharmony_ci}
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_cistatic u32 ixgbe_get_priv_flags(struct net_device *netdev)
353362306a36Sopenharmony_ci{
353462306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
353562306a36Sopenharmony_ci	u32 priv_flags = 0;
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	if (adapter->flags2 & IXGBE_FLAG2_RX_LEGACY)
353862306a36Sopenharmony_ci		priv_flags |= IXGBE_PRIV_FLAGS_LEGACY_RX;
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	if (adapter->flags2 & IXGBE_FLAG2_VF_IPSEC_ENABLED)
354162306a36Sopenharmony_ci		priv_flags |= IXGBE_PRIV_FLAGS_VF_IPSEC_EN;
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	if (adapter->flags2 & IXGBE_FLAG2_AUTO_DISABLE_VF)
354462306a36Sopenharmony_ci		priv_flags |= IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	return priv_flags;
354762306a36Sopenharmony_ci}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_cistatic int ixgbe_set_priv_flags(struct net_device *netdev, u32 priv_flags)
355062306a36Sopenharmony_ci{
355162306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = netdev_priv(netdev);
355262306a36Sopenharmony_ci	unsigned int flags2 = adapter->flags2;
355362306a36Sopenharmony_ci	unsigned int i;
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	flags2 &= ~IXGBE_FLAG2_RX_LEGACY;
355662306a36Sopenharmony_ci	if (priv_flags & IXGBE_PRIV_FLAGS_LEGACY_RX)
355762306a36Sopenharmony_ci		flags2 |= IXGBE_FLAG2_RX_LEGACY;
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci	flags2 &= ~IXGBE_FLAG2_VF_IPSEC_ENABLED;
356062306a36Sopenharmony_ci	if (priv_flags & IXGBE_PRIV_FLAGS_VF_IPSEC_EN)
356162306a36Sopenharmony_ci		flags2 |= IXGBE_FLAG2_VF_IPSEC_ENABLED;
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	flags2 &= ~IXGBE_FLAG2_AUTO_DISABLE_VF;
356462306a36Sopenharmony_ci	if (priv_flags & IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF) {
356562306a36Sopenharmony_ci		if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
356662306a36Sopenharmony_ci			/* Reset primary abort counter */
356762306a36Sopenharmony_ci			for (i = 0; i < adapter->num_vfs; i++)
356862306a36Sopenharmony_ci				adapter->vfinfo[i].primary_abort_count = 0;
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci			flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF;
357162306a36Sopenharmony_ci		} else {
357262306a36Sopenharmony_ci			e_info(probe,
357362306a36Sopenharmony_ci			       "Cannot set private flags: Operation not supported\n");
357462306a36Sopenharmony_ci			return -EOPNOTSUPP;
357562306a36Sopenharmony_ci		}
357662306a36Sopenharmony_ci	}
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci	if (flags2 != adapter->flags2) {
357962306a36Sopenharmony_ci		adapter->flags2 = flags2;
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci		/* reset interface to repopulate queues */
358262306a36Sopenharmony_ci		if (netif_running(netdev))
358362306a36Sopenharmony_ci			ixgbe_reinit_locked(adapter);
358462306a36Sopenharmony_ci	}
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	return 0;
358762306a36Sopenharmony_ci}
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_cistatic const struct ethtool_ops ixgbe_ethtool_ops = {
359062306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
359162306a36Sopenharmony_ci	.get_drvinfo            = ixgbe_get_drvinfo,
359262306a36Sopenharmony_ci	.get_regs_len           = ixgbe_get_regs_len,
359362306a36Sopenharmony_ci	.get_regs               = ixgbe_get_regs,
359462306a36Sopenharmony_ci	.get_wol                = ixgbe_get_wol,
359562306a36Sopenharmony_ci	.set_wol                = ixgbe_set_wol,
359662306a36Sopenharmony_ci	.nway_reset             = ixgbe_nway_reset,
359762306a36Sopenharmony_ci	.get_link               = ethtool_op_get_link,
359862306a36Sopenharmony_ci	.get_eeprom_len         = ixgbe_get_eeprom_len,
359962306a36Sopenharmony_ci	.get_eeprom             = ixgbe_get_eeprom,
360062306a36Sopenharmony_ci	.set_eeprom             = ixgbe_set_eeprom,
360162306a36Sopenharmony_ci	.get_ringparam          = ixgbe_get_ringparam,
360262306a36Sopenharmony_ci	.set_ringparam          = ixgbe_set_ringparam,
360362306a36Sopenharmony_ci	.get_pause_stats	= ixgbe_get_pause_stats,
360462306a36Sopenharmony_ci	.get_pauseparam         = ixgbe_get_pauseparam,
360562306a36Sopenharmony_ci	.set_pauseparam         = ixgbe_set_pauseparam,
360662306a36Sopenharmony_ci	.get_msglevel           = ixgbe_get_msglevel,
360762306a36Sopenharmony_ci	.set_msglevel           = ixgbe_set_msglevel,
360862306a36Sopenharmony_ci	.self_test              = ixgbe_diag_test,
360962306a36Sopenharmony_ci	.get_strings            = ixgbe_get_strings,
361062306a36Sopenharmony_ci	.set_phys_id            = ixgbe_set_phys_id,
361162306a36Sopenharmony_ci	.get_sset_count         = ixgbe_get_sset_count,
361262306a36Sopenharmony_ci	.get_ethtool_stats      = ixgbe_get_ethtool_stats,
361362306a36Sopenharmony_ci	.get_coalesce           = ixgbe_get_coalesce,
361462306a36Sopenharmony_ci	.set_coalesce           = ixgbe_set_coalesce,
361562306a36Sopenharmony_ci	.get_rxnfc		= ixgbe_get_rxnfc,
361662306a36Sopenharmony_ci	.set_rxnfc		= ixgbe_set_rxnfc,
361762306a36Sopenharmony_ci	.get_rxfh_indir_size	= ixgbe_rss_indir_size,
361862306a36Sopenharmony_ci	.get_rxfh_key_size	= ixgbe_get_rxfh_key_size,
361962306a36Sopenharmony_ci	.get_rxfh		= ixgbe_get_rxfh,
362062306a36Sopenharmony_ci	.set_rxfh		= ixgbe_set_rxfh,
362162306a36Sopenharmony_ci	.get_eee		= ixgbe_get_eee,
362262306a36Sopenharmony_ci	.set_eee		= ixgbe_set_eee,
362362306a36Sopenharmony_ci	.get_channels		= ixgbe_get_channels,
362462306a36Sopenharmony_ci	.set_channels		= ixgbe_set_channels,
362562306a36Sopenharmony_ci	.get_priv_flags		= ixgbe_get_priv_flags,
362662306a36Sopenharmony_ci	.set_priv_flags		= ixgbe_set_priv_flags,
362762306a36Sopenharmony_ci	.get_ts_info		= ixgbe_get_ts_info,
362862306a36Sopenharmony_ci	.get_module_info	= ixgbe_get_module_info,
362962306a36Sopenharmony_ci	.get_module_eeprom	= ixgbe_get_module_eeprom,
363062306a36Sopenharmony_ci	.get_link_ksettings     = ixgbe_get_link_ksettings,
363162306a36Sopenharmony_ci	.set_link_ksettings     = ixgbe_set_link_ksettings,
363262306a36Sopenharmony_ci};
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_civoid ixgbe_set_ethtool_ops(struct net_device *netdev)
363562306a36Sopenharmony_ci{
363662306a36Sopenharmony_ci	netdev->ethtool_ops = &ixgbe_ethtool_ops;
363762306a36Sopenharmony_ci}
3638