18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 2007 - 2018 Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci/* ethtool support for igb */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
78c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
88c2ecf20Sopenharmony_ci#include <linux/pci.h>
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
128c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
138c2ecf20Sopenharmony_ci#include <linux/sched.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
168c2ecf20Sopenharmony_ci#include <linux/highmem.h>
178c2ecf20Sopenharmony_ci#include <linux/mdio.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "igb.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct igb_stats {
228c2ecf20Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
238c2ecf20Sopenharmony_ci	int sizeof_stat;
248c2ecf20Sopenharmony_ci	int stat_offset;
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define IGB_STAT(_name, _stat) { \
288c2ecf20Sopenharmony_ci	.stat_string = _name, \
298c2ecf20Sopenharmony_ci	.sizeof_stat = sizeof_field(struct igb_adapter, _stat), \
308c2ecf20Sopenharmony_ci	.stat_offset = offsetof(struct igb_adapter, _stat) \
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_cistatic const struct igb_stats igb_gstrings_stats[] = {
338c2ecf20Sopenharmony_ci	IGB_STAT("rx_packets", stats.gprc),
348c2ecf20Sopenharmony_ci	IGB_STAT("tx_packets", stats.gptc),
358c2ecf20Sopenharmony_ci	IGB_STAT("rx_bytes", stats.gorc),
368c2ecf20Sopenharmony_ci	IGB_STAT("tx_bytes", stats.gotc),
378c2ecf20Sopenharmony_ci	IGB_STAT("rx_broadcast", stats.bprc),
388c2ecf20Sopenharmony_ci	IGB_STAT("tx_broadcast", stats.bptc),
398c2ecf20Sopenharmony_ci	IGB_STAT("rx_multicast", stats.mprc),
408c2ecf20Sopenharmony_ci	IGB_STAT("tx_multicast", stats.mptc),
418c2ecf20Sopenharmony_ci	IGB_STAT("multicast", stats.mprc),
428c2ecf20Sopenharmony_ci	IGB_STAT("collisions", stats.colc),
438c2ecf20Sopenharmony_ci	IGB_STAT("rx_crc_errors", stats.crcerrs),
448c2ecf20Sopenharmony_ci	IGB_STAT("rx_no_buffer_count", stats.rnbc),
458c2ecf20Sopenharmony_ci	IGB_STAT("rx_missed_errors", stats.mpc),
468c2ecf20Sopenharmony_ci	IGB_STAT("tx_aborted_errors", stats.ecol),
478c2ecf20Sopenharmony_ci	IGB_STAT("tx_carrier_errors", stats.tncrs),
488c2ecf20Sopenharmony_ci	IGB_STAT("tx_window_errors", stats.latecol),
498c2ecf20Sopenharmony_ci	IGB_STAT("tx_abort_late_coll", stats.latecol),
508c2ecf20Sopenharmony_ci	IGB_STAT("tx_deferred_ok", stats.dc),
518c2ecf20Sopenharmony_ci	IGB_STAT("tx_single_coll_ok", stats.scc),
528c2ecf20Sopenharmony_ci	IGB_STAT("tx_multi_coll_ok", stats.mcc),
538c2ecf20Sopenharmony_ci	IGB_STAT("tx_timeout_count", tx_timeout_count),
548c2ecf20Sopenharmony_ci	IGB_STAT("rx_long_length_errors", stats.roc),
558c2ecf20Sopenharmony_ci	IGB_STAT("rx_short_length_errors", stats.ruc),
568c2ecf20Sopenharmony_ci	IGB_STAT("rx_align_errors", stats.algnerrc),
578c2ecf20Sopenharmony_ci	IGB_STAT("tx_tcp_seg_good", stats.tsctc),
588c2ecf20Sopenharmony_ci	IGB_STAT("tx_tcp_seg_failed", stats.tsctfc),
598c2ecf20Sopenharmony_ci	IGB_STAT("rx_flow_control_xon", stats.xonrxc),
608c2ecf20Sopenharmony_ci	IGB_STAT("rx_flow_control_xoff", stats.xoffrxc),
618c2ecf20Sopenharmony_ci	IGB_STAT("tx_flow_control_xon", stats.xontxc),
628c2ecf20Sopenharmony_ci	IGB_STAT("tx_flow_control_xoff", stats.xofftxc),
638c2ecf20Sopenharmony_ci	IGB_STAT("rx_long_byte_count", stats.gorc),
648c2ecf20Sopenharmony_ci	IGB_STAT("tx_dma_out_of_sync", stats.doosync),
658c2ecf20Sopenharmony_ci	IGB_STAT("tx_smbus", stats.mgptc),
668c2ecf20Sopenharmony_ci	IGB_STAT("rx_smbus", stats.mgprc),
678c2ecf20Sopenharmony_ci	IGB_STAT("dropped_smbus", stats.mgpdc),
688c2ecf20Sopenharmony_ci	IGB_STAT("os2bmc_rx_by_bmc", stats.o2bgptc),
698c2ecf20Sopenharmony_ci	IGB_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
708c2ecf20Sopenharmony_ci	IGB_STAT("os2bmc_tx_by_host", stats.o2bspc),
718c2ecf20Sopenharmony_ci	IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc),
728c2ecf20Sopenharmony_ci	IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
738c2ecf20Sopenharmony_ci	IGB_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
748c2ecf20Sopenharmony_ci	IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define IGB_NETDEV_STAT(_net_stat) { \
788c2ecf20Sopenharmony_ci	.stat_string = __stringify(_net_stat), \
798c2ecf20Sopenharmony_ci	.sizeof_stat = sizeof_field(struct rtnl_link_stats64, _net_stat), \
808c2ecf20Sopenharmony_ci	.stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_cistatic const struct igb_stats igb_gstrings_net_stats[] = {
838c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(rx_errors),
848c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(tx_errors),
858c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(tx_dropped),
868c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(rx_length_errors),
878c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(rx_over_errors),
888c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(rx_frame_errors),
898c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(rx_fifo_errors),
908c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(tx_fifo_errors),
918c2ecf20Sopenharmony_ci	IGB_NETDEV_STAT(tx_heartbeat_errors)
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci#define IGB_GLOBAL_STATS_LEN	\
958c2ecf20Sopenharmony_ci	(sizeof(igb_gstrings_stats) / sizeof(struct igb_stats))
968c2ecf20Sopenharmony_ci#define IGB_NETDEV_STATS_LEN	\
978c2ecf20Sopenharmony_ci	(sizeof(igb_gstrings_net_stats) / sizeof(struct igb_stats))
988c2ecf20Sopenharmony_ci#define IGB_RX_QUEUE_STATS_LEN \
998c2ecf20Sopenharmony_ci	(sizeof(struct igb_rx_queue_stats) / sizeof(u64))
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define IGB_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define IGB_QUEUE_STATS_LEN \
1048c2ecf20Sopenharmony_ci	((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues * \
1058c2ecf20Sopenharmony_ci	  IGB_RX_QUEUE_STATS_LEN) + \
1068c2ecf20Sopenharmony_ci	 (((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues * \
1078c2ecf20Sopenharmony_ci	  IGB_TX_QUEUE_STATS_LEN))
1088c2ecf20Sopenharmony_ci#define IGB_STATS_LEN \
1098c2ecf20Sopenharmony_ci	(IGB_GLOBAL_STATS_LEN + IGB_NETDEV_STATS_LEN + IGB_QUEUE_STATS_LEN)
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cienum igb_diagnostics_results {
1128c2ecf20Sopenharmony_ci	TEST_REG = 0,
1138c2ecf20Sopenharmony_ci	TEST_EEP,
1148c2ecf20Sopenharmony_ci	TEST_IRQ,
1158c2ecf20Sopenharmony_ci	TEST_LOOP,
1168c2ecf20Sopenharmony_ci	TEST_LINK
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic const char igb_gstrings_test[][ETH_GSTRING_LEN] = {
1208c2ecf20Sopenharmony_ci	[TEST_REG]  = "Register test  (offline)",
1218c2ecf20Sopenharmony_ci	[TEST_EEP]  = "Eeprom test    (offline)",
1228c2ecf20Sopenharmony_ci	[TEST_IRQ]  = "Interrupt test (offline)",
1238c2ecf20Sopenharmony_ci	[TEST_LOOP] = "Loopback test  (offline)",
1248c2ecf20Sopenharmony_ci	[TEST_LINK] = "Link test   (on/offline)"
1258c2ecf20Sopenharmony_ci};
1268c2ecf20Sopenharmony_ci#define IGB_TEST_LEN (sizeof(igb_gstrings_test) / ETH_GSTRING_LEN)
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const char igb_priv_flags_strings[][ETH_GSTRING_LEN] = {
1298c2ecf20Sopenharmony_ci#define IGB_PRIV_FLAGS_LEGACY_RX	BIT(0)
1308c2ecf20Sopenharmony_ci	"legacy-rx",
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#define IGB_PRIV_FLAGS_STR_LEN ARRAY_SIZE(igb_priv_flags_strings)
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int igb_get_link_ksettings(struct net_device *netdev,
1368c2ecf20Sopenharmony_ci				  struct ethtool_link_ksettings *cmd)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
1398c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
1408c2ecf20Sopenharmony_ci	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
1418c2ecf20Sopenharmony_ci	struct e1000_sfp_flags *eth_flags = &dev_spec->eth_flags;
1428c2ecf20Sopenharmony_ci	u32 status;
1438c2ecf20Sopenharmony_ci	u32 speed;
1448c2ecf20Sopenharmony_ci	u32 supported, advertising;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	status = pm_runtime_suspended(&adapter->pdev->dev) ?
1478c2ecf20Sopenharmony_ci		 0 : rd32(E1000_STATUS);
1488c2ecf20Sopenharmony_ci	if (hw->phy.media_type == e1000_media_type_copper) {
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		supported = (SUPPORTED_10baseT_Half |
1518c2ecf20Sopenharmony_ci			     SUPPORTED_10baseT_Full |
1528c2ecf20Sopenharmony_ci			     SUPPORTED_100baseT_Half |
1538c2ecf20Sopenharmony_ci			     SUPPORTED_100baseT_Full |
1548c2ecf20Sopenharmony_ci			     SUPPORTED_1000baseT_Full|
1558c2ecf20Sopenharmony_ci			     SUPPORTED_Autoneg |
1568c2ecf20Sopenharmony_ci			     SUPPORTED_TP |
1578c2ecf20Sopenharmony_ci			     SUPPORTED_Pause);
1588c2ecf20Sopenharmony_ci		advertising = ADVERTISED_TP;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		if (hw->mac.autoneg == 1) {
1618c2ecf20Sopenharmony_ci			advertising |= ADVERTISED_Autoneg;
1628c2ecf20Sopenharmony_ci			/* the e1000 autoneg seems to match ethtool nicely */
1638c2ecf20Sopenharmony_ci			advertising |= hw->phy.autoneg_advertised;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci		cmd->base.port = PORT_TP;
1678c2ecf20Sopenharmony_ci		cmd->base.phy_address = hw->phy.addr;
1688c2ecf20Sopenharmony_ci	} else {
1698c2ecf20Sopenharmony_ci		supported = (SUPPORTED_FIBRE |
1708c2ecf20Sopenharmony_ci			     SUPPORTED_1000baseKX_Full |
1718c2ecf20Sopenharmony_ci			     SUPPORTED_Autoneg |
1728c2ecf20Sopenharmony_ci			     SUPPORTED_Pause);
1738c2ecf20Sopenharmony_ci		advertising = (ADVERTISED_FIBRE |
1748c2ecf20Sopenharmony_ci			       ADVERTISED_1000baseKX_Full);
1758c2ecf20Sopenharmony_ci		if (hw->mac.type == e1000_i354) {
1768c2ecf20Sopenharmony_ci			if ((hw->device_id ==
1778c2ecf20Sopenharmony_ci			     E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) &&
1788c2ecf20Sopenharmony_ci			    !(status & E1000_STATUS_2P5_SKU_OVER)) {
1798c2ecf20Sopenharmony_ci				supported |= SUPPORTED_2500baseX_Full;
1808c2ecf20Sopenharmony_ci				supported &= ~SUPPORTED_1000baseKX_Full;
1818c2ecf20Sopenharmony_ci				advertising |= ADVERTISED_2500baseX_Full;
1828c2ecf20Sopenharmony_ci				advertising &= ~ADVERTISED_1000baseKX_Full;
1838c2ecf20Sopenharmony_ci			}
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci		if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) {
1868c2ecf20Sopenharmony_ci			supported |= SUPPORTED_100baseT_Full;
1878c2ecf20Sopenharmony_ci			advertising |= ADVERTISED_100baseT_Full;
1888c2ecf20Sopenharmony_ci		}
1898c2ecf20Sopenharmony_ci		if (hw->mac.autoneg == 1)
1908c2ecf20Sopenharmony_ci			advertising |= ADVERTISED_Autoneg;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		cmd->base.port = PORT_FIBRE;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci	if (hw->mac.autoneg != 1)
1958c2ecf20Sopenharmony_ci		advertising &= ~(ADVERTISED_Pause |
1968c2ecf20Sopenharmony_ci				 ADVERTISED_Asym_Pause);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	switch (hw->fc.requested_mode) {
1998c2ecf20Sopenharmony_ci	case e1000_fc_full:
2008c2ecf20Sopenharmony_ci		advertising |= ADVERTISED_Pause;
2018c2ecf20Sopenharmony_ci		break;
2028c2ecf20Sopenharmony_ci	case e1000_fc_rx_pause:
2038c2ecf20Sopenharmony_ci		advertising |= (ADVERTISED_Pause |
2048c2ecf20Sopenharmony_ci				ADVERTISED_Asym_Pause);
2058c2ecf20Sopenharmony_ci		break;
2068c2ecf20Sopenharmony_ci	case e1000_fc_tx_pause:
2078c2ecf20Sopenharmony_ci		advertising |=  ADVERTISED_Asym_Pause;
2088c2ecf20Sopenharmony_ci		break;
2098c2ecf20Sopenharmony_ci	default:
2108c2ecf20Sopenharmony_ci		advertising &= ~(ADVERTISED_Pause |
2118c2ecf20Sopenharmony_ci				 ADVERTISED_Asym_Pause);
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci	if (status & E1000_STATUS_LU) {
2148c2ecf20Sopenharmony_ci		if ((status & E1000_STATUS_2P5_SKU) &&
2158c2ecf20Sopenharmony_ci		    !(status & E1000_STATUS_2P5_SKU_OVER)) {
2168c2ecf20Sopenharmony_ci			speed = SPEED_2500;
2178c2ecf20Sopenharmony_ci		} else if (status & E1000_STATUS_SPEED_1000) {
2188c2ecf20Sopenharmony_ci			speed = SPEED_1000;
2198c2ecf20Sopenharmony_ci		} else if (status & E1000_STATUS_SPEED_100) {
2208c2ecf20Sopenharmony_ci			speed = SPEED_100;
2218c2ecf20Sopenharmony_ci		} else {
2228c2ecf20Sopenharmony_ci			speed = SPEED_10;
2238c2ecf20Sopenharmony_ci		}
2248c2ecf20Sopenharmony_ci		if ((status & E1000_STATUS_FD) ||
2258c2ecf20Sopenharmony_ci		    hw->phy.media_type != e1000_media_type_copper)
2268c2ecf20Sopenharmony_ci			cmd->base.duplex = DUPLEX_FULL;
2278c2ecf20Sopenharmony_ci		else
2288c2ecf20Sopenharmony_ci			cmd->base.duplex = DUPLEX_HALF;
2298c2ecf20Sopenharmony_ci	} else {
2308c2ecf20Sopenharmony_ci		speed = SPEED_UNKNOWN;
2318c2ecf20Sopenharmony_ci		cmd->base.duplex = DUPLEX_UNKNOWN;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	cmd->base.speed = speed;
2348c2ecf20Sopenharmony_ci	if ((hw->phy.media_type == e1000_media_type_fiber) ||
2358c2ecf20Sopenharmony_ci	    hw->mac.autoneg)
2368c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_ENABLE;
2378c2ecf20Sopenharmony_ci	else
2388c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_DISABLE;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* MDI-X => 2; MDI =>1; Invalid =>0 */
2418c2ecf20Sopenharmony_ci	if (hw->phy.media_type == e1000_media_type_copper)
2428c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
2438c2ecf20Sopenharmony_ci						      ETH_TP_MDI;
2448c2ecf20Sopenharmony_ci	else
2458c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (hw->phy.mdix == AUTO_ALL_MODES)
2488c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
2498c2ecf20Sopenharmony_ci	else
2508c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = hw->phy.mdix;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
2538c2ecf20Sopenharmony_ci						supported);
2548c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
2558c2ecf20Sopenharmony_ci						advertising);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return 0;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int igb_set_link_ksettings(struct net_device *netdev,
2618c2ecf20Sopenharmony_ci				  const struct ethtool_link_ksettings *cmd)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
2648c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
2658c2ecf20Sopenharmony_ci	u32 advertising;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* When SoL/IDER sessions are active, autoneg/speed/duplex
2688c2ecf20Sopenharmony_ci	 * cannot be changed
2698c2ecf20Sopenharmony_ci	 */
2708c2ecf20Sopenharmony_ci	if (igb_check_reset_block(hw)) {
2718c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
2728c2ecf20Sopenharmony_ci			"Cannot change link characteristics when SoL/IDER is active.\n");
2738c2ecf20Sopenharmony_ci		return -EINVAL;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* MDI setting is only allowed when autoneg enabled because
2778c2ecf20Sopenharmony_ci	 * some hardware doesn't allow MDI setting when speed or
2788c2ecf20Sopenharmony_ci	 * duplex is forced.
2798c2ecf20Sopenharmony_ci	 */
2808c2ecf20Sopenharmony_ci	if (cmd->base.eth_tp_mdix_ctrl) {
2818c2ecf20Sopenharmony_ci		if (hw->phy.media_type != e1000_media_type_copper)
2828c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		if ((cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) &&
2858c2ecf20Sopenharmony_ci		    (cmd->base.autoneg != AUTONEG_ENABLE)) {
2868c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev, "forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
2878c2ecf20Sopenharmony_ci			return -EINVAL;
2888c2ecf20Sopenharmony_ci		}
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
2928c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	ethtool_convert_link_mode_to_legacy_u32(&advertising,
2958c2ecf20Sopenharmony_ci						cmd->link_modes.advertising);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (cmd->base.autoneg == AUTONEG_ENABLE) {
2988c2ecf20Sopenharmony_ci		hw->mac.autoneg = 1;
2998c2ecf20Sopenharmony_ci		if (hw->phy.media_type == e1000_media_type_fiber) {
3008c2ecf20Sopenharmony_ci			hw->phy.autoneg_advertised = advertising |
3018c2ecf20Sopenharmony_ci						     ADVERTISED_FIBRE |
3028c2ecf20Sopenharmony_ci						     ADVERTISED_Autoneg;
3038c2ecf20Sopenharmony_ci			switch (adapter->link_speed) {
3048c2ecf20Sopenharmony_ci			case SPEED_2500:
3058c2ecf20Sopenharmony_ci				hw->phy.autoneg_advertised =
3068c2ecf20Sopenharmony_ci					ADVERTISED_2500baseX_Full;
3078c2ecf20Sopenharmony_ci				break;
3088c2ecf20Sopenharmony_ci			case SPEED_1000:
3098c2ecf20Sopenharmony_ci				hw->phy.autoneg_advertised =
3108c2ecf20Sopenharmony_ci					ADVERTISED_1000baseT_Full;
3118c2ecf20Sopenharmony_ci				break;
3128c2ecf20Sopenharmony_ci			case SPEED_100:
3138c2ecf20Sopenharmony_ci				hw->phy.autoneg_advertised =
3148c2ecf20Sopenharmony_ci					ADVERTISED_100baseT_Full;
3158c2ecf20Sopenharmony_ci				break;
3168c2ecf20Sopenharmony_ci			default:
3178c2ecf20Sopenharmony_ci				break;
3188c2ecf20Sopenharmony_ci			}
3198c2ecf20Sopenharmony_ci		} else {
3208c2ecf20Sopenharmony_ci			hw->phy.autoneg_advertised = advertising |
3218c2ecf20Sopenharmony_ci						     ADVERTISED_TP |
3228c2ecf20Sopenharmony_ci						     ADVERTISED_Autoneg;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci		advertising = hw->phy.autoneg_advertised;
3258c2ecf20Sopenharmony_ci		if (adapter->fc_autoneg)
3268c2ecf20Sopenharmony_ci			hw->fc.requested_mode = e1000_fc_default;
3278c2ecf20Sopenharmony_ci	} else {
3288c2ecf20Sopenharmony_ci		u32 speed = cmd->base.speed;
3298c2ecf20Sopenharmony_ci		/* calling this overrides forced MDI setting */
3308c2ecf20Sopenharmony_ci		if (igb_set_spd_dplx(adapter, speed, cmd->base.duplex)) {
3318c2ecf20Sopenharmony_ci			clear_bit(__IGB_RESETTING, &adapter->state);
3328c2ecf20Sopenharmony_ci			return -EINVAL;
3338c2ecf20Sopenharmony_ci		}
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	/* MDI-X => 2; MDI => 1; Auto => 3 */
3378c2ecf20Sopenharmony_ci	if (cmd->base.eth_tp_mdix_ctrl) {
3388c2ecf20Sopenharmony_ci		/* fix up the value for auto (3 => 0) as zero is mapped
3398c2ecf20Sopenharmony_ci		 * internally to auto
3408c2ecf20Sopenharmony_ci		 */
3418c2ecf20Sopenharmony_ci		if (cmd->base.eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO)
3428c2ecf20Sopenharmony_ci			hw->phy.mdix = AUTO_ALL_MODES;
3438c2ecf20Sopenharmony_ci		else
3448c2ecf20Sopenharmony_ci			hw->phy.mdix = cmd->base.eth_tp_mdix_ctrl;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* reset the link */
3488c2ecf20Sopenharmony_ci	if (netif_running(adapter->netdev)) {
3498c2ecf20Sopenharmony_ci		igb_down(adapter);
3508c2ecf20Sopenharmony_ci		igb_up(adapter);
3518c2ecf20Sopenharmony_ci	} else
3528c2ecf20Sopenharmony_ci		igb_reset(adapter);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	clear_bit(__IGB_RESETTING, &adapter->state);
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic u32 igb_get_link(struct net_device *netdev)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
3618c2ecf20Sopenharmony_ci	struct e1000_mac_info *mac = &adapter->hw.mac;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* If the link is not reported up to netdev, interrupts are disabled,
3648c2ecf20Sopenharmony_ci	 * and so the physical link state may have changed since we last
3658c2ecf20Sopenharmony_ci	 * looked. Set get_link_status to make sure that the true link
3668c2ecf20Sopenharmony_ci	 * state is interrogated, rather than pulling a cached and possibly
3678c2ecf20Sopenharmony_ci	 * stale link state from the driver.
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci	if (!netif_carrier_ok(netdev))
3708c2ecf20Sopenharmony_ci		mac->get_link_status = 1;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	return igb_has_link(adapter);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic void igb_get_pauseparam(struct net_device *netdev,
3768c2ecf20Sopenharmony_ci			       struct ethtool_pauseparam *pause)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
3798c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	pause->autoneg =
3828c2ecf20Sopenharmony_ci		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (hw->fc.current_mode == e1000_fc_rx_pause)
3858c2ecf20Sopenharmony_ci		pause->rx_pause = 1;
3868c2ecf20Sopenharmony_ci	else if (hw->fc.current_mode == e1000_fc_tx_pause)
3878c2ecf20Sopenharmony_ci		pause->tx_pause = 1;
3888c2ecf20Sopenharmony_ci	else if (hw->fc.current_mode == e1000_fc_full) {
3898c2ecf20Sopenharmony_ci		pause->rx_pause = 1;
3908c2ecf20Sopenharmony_ci		pause->tx_pause = 1;
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic int igb_set_pauseparam(struct net_device *netdev,
3958c2ecf20Sopenharmony_ci			      struct ethtool_pauseparam *pause)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
3988c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
3998c2ecf20Sopenharmony_ci	int retval = 0;
4008c2ecf20Sopenharmony_ci	int i;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/* 100basefx does not support setting link flow control */
4038c2ecf20Sopenharmony_ci	if (hw->dev_spec._82575.eth_flags.e100_base_fx)
4048c2ecf20Sopenharmony_ci		return -EINVAL;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	adapter->fc_autoneg = pause->autoneg;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
4098c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
4128c2ecf20Sopenharmony_ci		hw->fc.requested_mode = e1000_fc_default;
4138c2ecf20Sopenharmony_ci		if (netif_running(adapter->netdev)) {
4148c2ecf20Sopenharmony_ci			igb_down(adapter);
4158c2ecf20Sopenharmony_ci			igb_up(adapter);
4168c2ecf20Sopenharmony_ci		} else {
4178c2ecf20Sopenharmony_ci			igb_reset(adapter);
4188c2ecf20Sopenharmony_ci		}
4198c2ecf20Sopenharmony_ci	} else {
4208c2ecf20Sopenharmony_ci		if (pause->rx_pause && pause->tx_pause)
4218c2ecf20Sopenharmony_ci			hw->fc.requested_mode = e1000_fc_full;
4228c2ecf20Sopenharmony_ci		else if (pause->rx_pause && !pause->tx_pause)
4238c2ecf20Sopenharmony_ci			hw->fc.requested_mode = e1000_fc_rx_pause;
4248c2ecf20Sopenharmony_ci		else if (!pause->rx_pause && pause->tx_pause)
4258c2ecf20Sopenharmony_ci			hw->fc.requested_mode = e1000_fc_tx_pause;
4268c2ecf20Sopenharmony_ci		else if (!pause->rx_pause && !pause->tx_pause)
4278c2ecf20Sopenharmony_ci			hw->fc.requested_mode = e1000_fc_none;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		hw->fc.current_mode = hw->fc.requested_mode;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		retval = ((hw->phy.media_type == e1000_media_type_copper) ?
4328c2ecf20Sopenharmony_ci			  igb_force_mac_fc(hw) : igb_setup_link(hw));
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		/* Make sure SRRCTL considers new fc settings for each ring */
4358c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
4368c2ecf20Sopenharmony_ci			struct igb_ring *ring = adapter->rx_ring[i];
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci			igb_setup_srrctl(adapter, ring);
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	clear_bit(__IGB_RESETTING, &adapter->state);
4438c2ecf20Sopenharmony_ci	return retval;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic u32 igb_get_msglevel(struct net_device *netdev)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
4498c2ecf20Sopenharmony_ci	return adapter->msg_enable;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic void igb_set_msglevel(struct net_device *netdev, u32 data)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
4558c2ecf20Sopenharmony_ci	adapter->msg_enable = data;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int igb_get_regs_len(struct net_device *netdev)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci#define IGB_REGS_LEN 740
4618c2ecf20Sopenharmony_ci	return IGB_REGS_LEN * sizeof(u32);
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic void igb_get_regs(struct net_device *netdev,
4658c2ecf20Sopenharmony_ci			 struct ethtool_regs *regs, void *p)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
4688c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
4698c2ecf20Sopenharmony_ci	u32 *regs_buff = p;
4708c2ecf20Sopenharmony_ci	u8 i;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	memset(p, 0, IGB_REGS_LEN * sizeof(u32));
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	regs->version = (1u << 24) | (hw->revision_id << 16) | hw->device_id;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/* General Registers */
4778c2ecf20Sopenharmony_ci	regs_buff[0] = rd32(E1000_CTRL);
4788c2ecf20Sopenharmony_ci	regs_buff[1] = rd32(E1000_STATUS);
4798c2ecf20Sopenharmony_ci	regs_buff[2] = rd32(E1000_CTRL_EXT);
4808c2ecf20Sopenharmony_ci	regs_buff[3] = rd32(E1000_MDIC);
4818c2ecf20Sopenharmony_ci	regs_buff[4] = rd32(E1000_SCTL);
4828c2ecf20Sopenharmony_ci	regs_buff[5] = rd32(E1000_CONNSW);
4838c2ecf20Sopenharmony_ci	regs_buff[6] = rd32(E1000_VET);
4848c2ecf20Sopenharmony_ci	regs_buff[7] = rd32(E1000_LEDCTL);
4858c2ecf20Sopenharmony_ci	regs_buff[8] = rd32(E1000_PBA);
4868c2ecf20Sopenharmony_ci	regs_buff[9] = rd32(E1000_PBS);
4878c2ecf20Sopenharmony_ci	regs_buff[10] = rd32(E1000_FRTIMER);
4888c2ecf20Sopenharmony_ci	regs_buff[11] = rd32(E1000_TCPTIMER);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	/* NVM Register */
4918c2ecf20Sopenharmony_ci	regs_buff[12] = rd32(E1000_EECD);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	/* Interrupt */
4948c2ecf20Sopenharmony_ci	/* Reading EICS for EICR because they read the
4958c2ecf20Sopenharmony_ci	 * same but EICS does not clear on read
4968c2ecf20Sopenharmony_ci	 */
4978c2ecf20Sopenharmony_ci	regs_buff[13] = rd32(E1000_EICS);
4988c2ecf20Sopenharmony_ci	regs_buff[14] = rd32(E1000_EICS);
4998c2ecf20Sopenharmony_ci	regs_buff[15] = rd32(E1000_EIMS);
5008c2ecf20Sopenharmony_ci	regs_buff[16] = rd32(E1000_EIMC);
5018c2ecf20Sopenharmony_ci	regs_buff[17] = rd32(E1000_EIAC);
5028c2ecf20Sopenharmony_ci	regs_buff[18] = rd32(E1000_EIAM);
5038c2ecf20Sopenharmony_ci	/* Reading ICS for ICR because they read the
5048c2ecf20Sopenharmony_ci	 * same but ICS does not clear on read
5058c2ecf20Sopenharmony_ci	 */
5068c2ecf20Sopenharmony_ci	regs_buff[19] = rd32(E1000_ICS);
5078c2ecf20Sopenharmony_ci	regs_buff[20] = rd32(E1000_ICS);
5088c2ecf20Sopenharmony_ci	regs_buff[21] = rd32(E1000_IMS);
5098c2ecf20Sopenharmony_ci	regs_buff[22] = rd32(E1000_IMC);
5108c2ecf20Sopenharmony_ci	regs_buff[23] = rd32(E1000_IAC);
5118c2ecf20Sopenharmony_ci	regs_buff[24] = rd32(E1000_IAM);
5128c2ecf20Sopenharmony_ci	regs_buff[25] = rd32(E1000_IMIRVP);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* Flow Control */
5158c2ecf20Sopenharmony_ci	regs_buff[26] = rd32(E1000_FCAL);
5168c2ecf20Sopenharmony_ci	regs_buff[27] = rd32(E1000_FCAH);
5178c2ecf20Sopenharmony_ci	regs_buff[28] = rd32(E1000_FCTTV);
5188c2ecf20Sopenharmony_ci	regs_buff[29] = rd32(E1000_FCRTL);
5198c2ecf20Sopenharmony_ci	regs_buff[30] = rd32(E1000_FCRTH);
5208c2ecf20Sopenharmony_ci	regs_buff[31] = rd32(E1000_FCRTV);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* Receive */
5238c2ecf20Sopenharmony_ci	regs_buff[32] = rd32(E1000_RCTL);
5248c2ecf20Sopenharmony_ci	regs_buff[33] = rd32(E1000_RXCSUM);
5258c2ecf20Sopenharmony_ci	regs_buff[34] = rd32(E1000_RLPML);
5268c2ecf20Sopenharmony_ci	regs_buff[35] = rd32(E1000_RFCTL);
5278c2ecf20Sopenharmony_ci	regs_buff[36] = rd32(E1000_MRQC);
5288c2ecf20Sopenharmony_ci	regs_buff[37] = rd32(E1000_VT_CTL);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	/* Transmit */
5318c2ecf20Sopenharmony_ci	regs_buff[38] = rd32(E1000_TCTL);
5328c2ecf20Sopenharmony_ci	regs_buff[39] = rd32(E1000_TCTL_EXT);
5338c2ecf20Sopenharmony_ci	regs_buff[40] = rd32(E1000_TIPG);
5348c2ecf20Sopenharmony_ci	regs_buff[41] = rd32(E1000_DTXCTL);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/* Wake Up */
5378c2ecf20Sopenharmony_ci	regs_buff[42] = rd32(E1000_WUC);
5388c2ecf20Sopenharmony_ci	regs_buff[43] = rd32(E1000_WUFC);
5398c2ecf20Sopenharmony_ci	regs_buff[44] = rd32(E1000_WUS);
5408c2ecf20Sopenharmony_ci	regs_buff[45] = rd32(E1000_IPAV);
5418c2ecf20Sopenharmony_ci	regs_buff[46] = rd32(E1000_WUPL);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* MAC */
5448c2ecf20Sopenharmony_ci	regs_buff[47] = rd32(E1000_PCS_CFG0);
5458c2ecf20Sopenharmony_ci	regs_buff[48] = rd32(E1000_PCS_LCTL);
5468c2ecf20Sopenharmony_ci	regs_buff[49] = rd32(E1000_PCS_LSTAT);
5478c2ecf20Sopenharmony_ci	regs_buff[50] = rd32(E1000_PCS_ANADV);
5488c2ecf20Sopenharmony_ci	regs_buff[51] = rd32(E1000_PCS_LPAB);
5498c2ecf20Sopenharmony_ci	regs_buff[52] = rd32(E1000_PCS_NPTX);
5508c2ecf20Sopenharmony_ci	regs_buff[53] = rd32(E1000_PCS_LPABNP);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	/* Statistics */
5538c2ecf20Sopenharmony_ci	regs_buff[54] = adapter->stats.crcerrs;
5548c2ecf20Sopenharmony_ci	regs_buff[55] = adapter->stats.algnerrc;
5558c2ecf20Sopenharmony_ci	regs_buff[56] = adapter->stats.symerrs;
5568c2ecf20Sopenharmony_ci	regs_buff[57] = adapter->stats.rxerrc;
5578c2ecf20Sopenharmony_ci	regs_buff[58] = adapter->stats.mpc;
5588c2ecf20Sopenharmony_ci	regs_buff[59] = adapter->stats.scc;
5598c2ecf20Sopenharmony_ci	regs_buff[60] = adapter->stats.ecol;
5608c2ecf20Sopenharmony_ci	regs_buff[61] = adapter->stats.mcc;
5618c2ecf20Sopenharmony_ci	regs_buff[62] = adapter->stats.latecol;
5628c2ecf20Sopenharmony_ci	regs_buff[63] = adapter->stats.colc;
5638c2ecf20Sopenharmony_ci	regs_buff[64] = adapter->stats.dc;
5648c2ecf20Sopenharmony_ci	regs_buff[65] = adapter->stats.tncrs;
5658c2ecf20Sopenharmony_ci	regs_buff[66] = adapter->stats.sec;
5668c2ecf20Sopenharmony_ci	regs_buff[67] = adapter->stats.htdpmc;
5678c2ecf20Sopenharmony_ci	regs_buff[68] = adapter->stats.rlec;
5688c2ecf20Sopenharmony_ci	regs_buff[69] = adapter->stats.xonrxc;
5698c2ecf20Sopenharmony_ci	regs_buff[70] = adapter->stats.xontxc;
5708c2ecf20Sopenharmony_ci	regs_buff[71] = adapter->stats.xoffrxc;
5718c2ecf20Sopenharmony_ci	regs_buff[72] = adapter->stats.xofftxc;
5728c2ecf20Sopenharmony_ci	regs_buff[73] = adapter->stats.fcruc;
5738c2ecf20Sopenharmony_ci	regs_buff[74] = adapter->stats.prc64;
5748c2ecf20Sopenharmony_ci	regs_buff[75] = adapter->stats.prc127;
5758c2ecf20Sopenharmony_ci	regs_buff[76] = adapter->stats.prc255;
5768c2ecf20Sopenharmony_ci	regs_buff[77] = adapter->stats.prc511;
5778c2ecf20Sopenharmony_ci	regs_buff[78] = adapter->stats.prc1023;
5788c2ecf20Sopenharmony_ci	regs_buff[79] = adapter->stats.prc1522;
5798c2ecf20Sopenharmony_ci	regs_buff[80] = adapter->stats.gprc;
5808c2ecf20Sopenharmony_ci	regs_buff[81] = adapter->stats.bprc;
5818c2ecf20Sopenharmony_ci	regs_buff[82] = adapter->stats.mprc;
5828c2ecf20Sopenharmony_ci	regs_buff[83] = adapter->stats.gptc;
5838c2ecf20Sopenharmony_ci	regs_buff[84] = adapter->stats.gorc;
5848c2ecf20Sopenharmony_ci	regs_buff[86] = adapter->stats.gotc;
5858c2ecf20Sopenharmony_ci	regs_buff[88] = adapter->stats.rnbc;
5868c2ecf20Sopenharmony_ci	regs_buff[89] = adapter->stats.ruc;
5878c2ecf20Sopenharmony_ci	regs_buff[90] = adapter->stats.rfc;
5888c2ecf20Sopenharmony_ci	regs_buff[91] = adapter->stats.roc;
5898c2ecf20Sopenharmony_ci	regs_buff[92] = adapter->stats.rjc;
5908c2ecf20Sopenharmony_ci	regs_buff[93] = adapter->stats.mgprc;
5918c2ecf20Sopenharmony_ci	regs_buff[94] = adapter->stats.mgpdc;
5928c2ecf20Sopenharmony_ci	regs_buff[95] = adapter->stats.mgptc;
5938c2ecf20Sopenharmony_ci	regs_buff[96] = adapter->stats.tor;
5948c2ecf20Sopenharmony_ci	regs_buff[98] = adapter->stats.tot;
5958c2ecf20Sopenharmony_ci	regs_buff[100] = adapter->stats.tpr;
5968c2ecf20Sopenharmony_ci	regs_buff[101] = adapter->stats.tpt;
5978c2ecf20Sopenharmony_ci	regs_buff[102] = adapter->stats.ptc64;
5988c2ecf20Sopenharmony_ci	regs_buff[103] = adapter->stats.ptc127;
5998c2ecf20Sopenharmony_ci	regs_buff[104] = adapter->stats.ptc255;
6008c2ecf20Sopenharmony_ci	regs_buff[105] = adapter->stats.ptc511;
6018c2ecf20Sopenharmony_ci	regs_buff[106] = adapter->stats.ptc1023;
6028c2ecf20Sopenharmony_ci	regs_buff[107] = adapter->stats.ptc1522;
6038c2ecf20Sopenharmony_ci	regs_buff[108] = adapter->stats.mptc;
6048c2ecf20Sopenharmony_ci	regs_buff[109] = adapter->stats.bptc;
6058c2ecf20Sopenharmony_ci	regs_buff[110] = adapter->stats.tsctc;
6068c2ecf20Sopenharmony_ci	regs_buff[111] = adapter->stats.iac;
6078c2ecf20Sopenharmony_ci	regs_buff[112] = adapter->stats.rpthc;
6088c2ecf20Sopenharmony_ci	regs_buff[113] = adapter->stats.hgptc;
6098c2ecf20Sopenharmony_ci	regs_buff[114] = adapter->stats.hgorc;
6108c2ecf20Sopenharmony_ci	regs_buff[116] = adapter->stats.hgotc;
6118c2ecf20Sopenharmony_ci	regs_buff[118] = adapter->stats.lenerrs;
6128c2ecf20Sopenharmony_ci	regs_buff[119] = adapter->stats.scvpc;
6138c2ecf20Sopenharmony_ci	regs_buff[120] = adapter->stats.hrmpc;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6168c2ecf20Sopenharmony_ci		regs_buff[121 + i] = rd32(E1000_SRRCTL(i));
6178c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6188c2ecf20Sopenharmony_ci		regs_buff[125 + i] = rd32(E1000_PSRTYPE(i));
6198c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6208c2ecf20Sopenharmony_ci		regs_buff[129 + i] = rd32(E1000_RDBAL(i));
6218c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6228c2ecf20Sopenharmony_ci		regs_buff[133 + i] = rd32(E1000_RDBAH(i));
6238c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6248c2ecf20Sopenharmony_ci		regs_buff[137 + i] = rd32(E1000_RDLEN(i));
6258c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6268c2ecf20Sopenharmony_ci		regs_buff[141 + i] = rd32(E1000_RDH(i));
6278c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6288c2ecf20Sopenharmony_ci		regs_buff[145 + i] = rd32(E1000_RDT(i));
6298c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6308c2ecf20Sopenharmony_ci		regs_buff[149 + i] = rd32(E1000_RXDCTL(i));
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++)
6338c2ecf20Sopenharmony_ci		regs_buff[153 + i] = rd32(E1000_EITR(i));
6348c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
6358c2ecf20Sopenharmony_ci		regs_buff[163 + i] = rd32(E1000_IMIR(i));
6368c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
6378c2ecf20Sopenharmony_ci		regs_buff[171 + i] = rd32(E1000_IMIREXT(i));
6388c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
6398c2ecf20Sopenharmony_ci		regs_buff[179 + i] = rd32(E1000_RAL(i));
6408c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
6418c2ecf20Sopenharmony_ci		regs_buff[195 + i] = rd32(E1000_RAH(i));
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6448c2ecf20Sopenharmony_ci		regs_buff[211 + i] = rd32(E1000_TDBAL(i));
6458c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6468c2ecf20Sopenharmony_ci		regs_buff[215 + i] = rd32(E1000_TDBAH(i));
6478c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6488c2ecf20Sopenharmony_ci		regs_buff[219 + i] = rd32(E1000_TDLEN(i));
6498c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6508c2ecf20Sopenharmony_ci		regs_buff[223 + i] = rd32(E1000_TDH(i));
6518c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6528c2ecf20Sopenharmony_ci		regs_buff[227 + i] = rd32(E1000_TDT(i));
6538c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6548c2ecf20Sopenharmony_ci		regs_buff[231 + i] = rd32(E1000_TXDCTL(i));
6558c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6568c2ecf20Sopenharmony_ci		regs_buff[235 + i] = rd32(E1000_TDWBAL(i));
6578c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6588c2ecf20Sopenharmony_ci		regs_buff[239 + i] = rd32(E1000_TDWBAH(i));
6598c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6608c2ecf20Sopenharmony_ci		regs_buff[243 + i] = rd32(E1000_DCA_TXCTRL(i));
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6638c2ecf20Sopenharmony_ci		regs_buff[247 + i] = rd32(E1000_IP4AT_REG(i));
6648c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6658c2ecf20Sopenharmony_ci		regs_buff[251 + i] = rd32(E1000_IP6AT_REG(i));
6668c2ecf20Sopenharmony_ci	for (i = 0; i < 32; i++)
6678c2ecf20Sopenharmony_ci		regs_buff[255 + i] = rd32(E1000_WUPM_REG(i));
6688c2ecf20Sopenharmony_ci	for (i = 0; i < 128; i++)
6698c2ecf20Sopenharmony_ci		regs_buff[287 + i] = rd32(E1000_FFMT_REG(i));
6708c2ecf20Sopenharmony_ci	for (i = 0; i < 128; i++)
6718c2ecf20Sopenharmony_ci		regs_buff[415 + i] = rd32(E1000_FFVT_REG(i));
6728c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
6738c2ecf20Sopenharmony_ci		regs_buff[543 + i] = rd32(E1000_FFLT_REG(i));
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	regs_buff[547] = rd32(E1000_TDFH);
6768c2ecf20Sopenharmony_ci	regs_buff[548] = rd32(E1000_TDFT);
6778c2ecf20Sopenharmony_ci	regs_buff[549] = rd32(E1000_TDFHS);
6788c2ecf20Sopenharmony_ci	regs_buff[550] = rd32(E1000_TDFPC);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	if (hw->mac.type > e1000_82580) {
6818c2ecf20Sopenharmony_ci		regs_buff[551] = adapter->stats.o2bgptc;
6828c2ecf20Sopenharmony_ci		regs_buff[552] = adapter->stats.b2ospc;
6838c2ecf20Sopenharmony_ci		regs_buff[553] = adapter->stats.o2bspc;
6848c2ecf20Sopenharmony_ci		regs_buff[554] = adapter->stats.b2ogprc;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (hw->mac.type == e1000_82576) {
6888c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
6898c2ecf20Sopenharmony_ci			regs_buff[555 + i] = rd32(E1000_SRRCTL(i + 4));
6908c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
6918c2ecf20Sopenharmony_ci			regs_buff[567 + i] = rd32(E1000_PSRTYPE(i + 4));
6928c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
6938c2ecf20Sopenharmony_ci			regs_buff[571 + i] = rd32(E1000_RDBAL(i + 4));
6948c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
6958c2ecf20Sopenharmony_ci			regs_buff[583 + i] = rd32(E1000_RDBAH(i + 4));
6968c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
6978c2ecf20Sopenharmony_ci			regs_buff[595 + i] = rd32(E1000_RDLEN(i + 4));
6988c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
6998c2ecf20Sopenharmony_ci			regs_buff[607 + i] = rd32(E1000_RDH(i + 4));
7008c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7018c2ecf20Sopenharmony_ci			regs_buff[619 + i] = rd32(E1000_RDT(i + 4));
7028c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7038c2ecf20Sopenharmony_ci			regs_buff[631 + i] = rd32(E1000_RXDCTL(i + 4));
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7068c2ecf20Sopenharmony_ci			regs_buff[643 + i] = rd32(E1000_TDBAL(i + 4));
7078c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7088c2ecf20Sopenharmony_ci			regs_buff[655 + i] = rd32(E1000_TDBAH(i + 4));
7098c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7108c2ecf20Sopenharmony_ci			regs_buff[667 + i] = rd32(E1000_TDLEN(i + 4));
7118c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7128c2ecf20Sopenharmony_ci			regs_buff[679 + i] = rd32(E1000_TDH(i + 4));
7138c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7148c2ecf20Sopenharmony_ci			regs_buff[691 + i] = rd32(E1000_TDT(i + 4));
7158c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7168c2ecf20Sopenharmony_ci			regs_buff[703 + i] = rd32(E1000_TXDCTL(i + 4));
7178c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7188c2ecf20Sopenharmony_ci			regs_buff[715 + i] = rd32(E1000_TDWBAL(i + 4));
7198c2ecf20Sopenharmony_ci		for (i = 0; i < 12; i++)
7208c2ecf20Sopenharmony_ci			regs_buff[727 + i] = rd32(E1000_TDWBAH(i + 4));
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211)
7248c2ecf20Sopenharmony_ci		regs_buff[739] = rd32(E1000_I210_RR2DCDELAY);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic int igb_get_eeprom_len(struct net_device *netdev)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
7308c2ecf20Sopenharmony_ci	return adapter->hw.nvm.word_size * 2;
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic int igb_get_eeprom(struct net_device *netdev,
7348c2ecf20Sopenharmony_ci			  struct ethtool_eeprom *eeprom, u8 *bytes)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
7378c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
7388c2ecf20Sopenharmony_ci	u16 *eeprom_buff;
7398c2ecf20Sopenharmony_ci	int first_word, last_word;
7408c2ecf20Sopenharmony_ci	int ret_val = 0;
7418c2ecf20Sopenharmony_ci	u16 i;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	if (eeprom->len == 0)
7448c2ecf20Sopenharmony_ci		return -EINVAL;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	first_word = eeprom->offset >> 1;
7498c2ecf20Sopenharmony_ci	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16),
7528c2ecf20Sopenharmony_ci				    GFP_KERNEL);
7538c2ecf20Sopenharmony_ci	if (!eeprom_buff)
7548c2ecf20Sopenharmony_ci		return -ENOMEM;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (hw->nvm.type == e1000_nvm_eeprom_spi)
7578c2ecf20Sopenharmony_ci		ret_val = hw->nvm.ops.read(hw, first_word,
7588c2ecf20Sopenharmony_ci					   last_word - first_word + 1,
7598c2ecf20Sopenharmony_ci					   eeprom_buff);
7608c2ecf20Sopenharmony_ci	else {
7618c2ecf20Sopenharmony_ci		for (i = 0; i < last_word - first_word + 1; i++) {
7628c2ecf20Sopenharmony_ci			ret_val = hw->nvm.ops.read(hw, first_word + i, 1,
7638c2ecf20Sopenharmony_ci						   &eeprom_buff[i]);
7648c2ecf20Sopenharmony_ci			if (ret_val)
7658c2ecf20Sopenharmony_ci				break;
7668c2ecf20Sopenharmony_ci		}
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	/* Device's eeprom is always little-endian, word addressable */
7708c2ecf20Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
7718c2ecf20Sopenharmony_ci		le16_to_cpus(&eeprom_buff[i]);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1),
7748c2ecf20Sopenharmony_ci			eeprom->len);
7758c2ecf20Sopenharmony_ci	kfree(eeprom_buff);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	return ret_val;
7788c2ecf20Sopenharmony_ci}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistatic int igb_set_eeprom(struct net_device *netdev,
7818c2ecf20Sopenharmony_ci			  struct ethtool_eeprom *eeprom, u8 *bytes)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
7848c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
7858c2ecf20Sopenharmony_ci	u16 *eeprom_buff;
7868c2ecf20Sopenharmony_ci	void *ptr;
7878c2ecf20Sopenharmony_ci	int max_len, first_word, last_word, ret_val = 0;
7888c2ecf20Sopenharmony_ci	u16 i;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	if (eeprom->len == 0)
7918c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if ((hw->mac.type >= e1000_i210) &&
7948c2ecf20Sopenharmony_ci	    !igb_get_flash_presence_i210(hw)) {
7958c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
7968c2ecf20Sopenharmony_ci	}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
7998c2ecf20Sopenharmony_ci		return -EFAULT;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	max_len = hw->nvm.word_size * 2;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	first_word = eeprom->offset >> 1;
8048c2ecf20Sopenharmony_ci	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
8058c2ecf20Sopenharmony_ci	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
8068c2ecf20Sopenharmony_ci	if (!eeprom_buff)
8078c2ecf20Sopenharmony_ci		return -ENOMEM;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	ptr = (void *)eeprom_buff;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (eeprom->offset & 1) {
8128c2ecf20Sopenharmony_ci		/* need read/modify/write of first changed EEPROM word
8138c2ecf20Sopenharmony_ci		 * only the second byte of the word is being modified
8148c2ecf20Sopenharmony_ci		 */
8158c2ecf20Sopenharmony_ci		ret_val = hw->nvm.ops.read(hw, first_word, 1,
8168c2ecf20Sopenharmony_ci					    &eeprom_buff[0]);
8178c2ecf20Sopenharmony_ci		ptr++;
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci	if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
8208c2ecf20Sopenharmony_ci		/* need read/modify/write of last changed EEPROM word
8218c2ecf20Sopenharmony_ci		 * only the first byte of the word is being modified
8228c2ecf20Sopenharmony_ci		 */
8238c2ecf20Sopenharmony_ci		ret_val = hw->nvm.ops.read(hw, last_word, 1,
8248c2ecf20Sopenharmony_ci				   &eeprom_buff[last_word - first_word]);
8258c2ecf20Sopenharmony_ci		if (ret_val)
8268c2ecf20Sopenharmony_ci			goto out;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/* Device's eeprom is always little-endian, word addressable */
8308c2ecf20Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
8318c2ecf20Sopenharmony_ci		le16_to_cpus(&eeprom_buff[i]);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	memcpy(ptr, bytes, eeprom->len);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
8368c2ecf20Sopenharmony_ci		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	ret_val = hw->nvm.ops.write(hw, first_word,
8398c2ecf20Sopenharmony_ci				    last_word - first_word + 1, eeprom_buff);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/* Update the checksum if nvm write succeeded */
8428c2ecf20Sopenharmony_ci	if (ret_val == 0)
8438c2ecf20Sopenharmony_ci		hw->nvm.ops.update(hw);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	igb_set_fw_version(adapter);
8468c2ecf20Sopenharmony_ciout:
8478c2ecf20Sopenharmony_ci	kfree(eeprom_buff);
8488c2ecf20Sopenharmony_ci	return ret_val;
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_cistatic void igb_get_drvinfo(struct net_device *netdev,
8528c2ecf20Sopenharmony_ci			    struct ethtool_drvinfo *drvinfo)
8538c2ecf20Sopenharmony_ci{
8548c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	strlcpy(drvinfo->driver,  igb_driver_name, sizeof(drvinfo->driver));
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	/* EEPROM image version # is reported as firmware version # for
8598c2ecf20Sopenharmony_ci	 * 82575 controllers
8608c2ecf20Sopenharmony_ci	 */
8618c2ecf20Sopenharmony_ci	strlcpy(drvinfo->fw_version, adapter->fw_version,
8628c2ecf20Sopenharmony_ci		sizeof(drvinfo->fw_version));
8638c2ecf20Sopenharmony_ci	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
8648c2ecf20Sopenharmony_ci		sizeof(drvinfo->bus_info));
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	drvinfo->n_priv_flags = IGB_PRIV_FLAGS_STR_LEN;
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic void igb_get_ringparam(struct net_device *netdev,
8708c2ecf20Sopenharmony_ci			      struct ethtool_ringparam *ring)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	ring->rx_max_pending = IGB_MAX_RXD;
8758c2ecf20Sopenharmony_ci	ring->tx_max_pending = IGB_MAX_TXD;
8768c2ecf20Sopenharmony_ci	ring->rx_pending = adapter->rx_ring_count;
8778c2ecf20Sopenharmony_ci	ring->tx_pending = adapter->tx_ring_count;
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cistatic int igb_set_ringparam(struct net_device *netdev,
8818c2ecf20Sopenharmony_ci			     struct ethtool_ringparam *ring)
8828c2ecf20Sopenharmony_ci{
8838c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
8848c2ecf20Sopenharmony_ci	struct igb_ring *temp_ring;
8858c2ecf20Sopenharmony_ci	int i, err = 0;
8868c2ecf20Sopenharmony_ci	u16 new_rx_count, new_tx_count;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
8898c2ecf20Sopenharmony_ci		return -EINVAL;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	new_rx_count = min_t(u32, ring->rx_pending, IGB_MAX_RXD);
8928c2ecf20Sopenharmony_ci	new_rx_count = max_t(u16, new_rx_count, IGB_MIN_RXD);
8938c2ecf20Sopenharmony_ci	new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	new_tx_count = min_t(u32, ring->tx_pending, IGB_MAX_TXD);
8968c2ecf20Sopenharmony_ci	new_tx_count = max_t(u16, new_tx_count, IGB_MIN_TXD);
8978c2ecf20Sopenharmony_ci	new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	if ((new_tx_count == adapter->tx_ring_count) &&
9008c2ecf20Sopenharmony_ci	    (new_rx_count == adapter->rx_ring_count)) {
9018c2ecf20Sopenharmony_ci		/* nothing to do */
9028c2ecf20Sopenharmony_ci		return 0;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
9068c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (!netif_running(adapter->netdev)) {
9098c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++)
9108c2ecf20Sopenharmony_ci			adapter->tx_ring[i]->count = new_tx_count;
9118c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++)
9128c2ecf20Sopenharmony_ci			adapter->rx_ring[i]->count = new_rx_count;
9138c2ecf20Sopenharmony_ci		adapter->tx_ring_count = new_tx_count;
9148c2ecf20Sopenharmony_ci		adapter->rx_ring_count = new_rx_count;
9158c2ecf20Sopenharmony_ci		goto clear_reset;
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (adapter->num_tx_queues > adapter->num_rx_queues)
9198c2ecf20Sopenharmony_ci		temp_ring = vmalloc(array_size(sizeof(struct igb_ring),
9208c2ecf20Sopenharmony_ci					       adapter->num_tx_queues));
9218c2ecf20Sopenharmony_ci	else
9228c2ecf20Sopenharmony_ci		temp_ring = vmalloc(array_size(sizeof(struct igb_ring),
9238c2ecf20Sopenharmony_ci					       adapter->num_rx_queues));
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	if (!temp_ring) {
9268c2ecf20Sopenharmony_ci		err = -ENOMEM;
9278c2ecf20Sopenharmony_ci		goto clear_reset;
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	igb_down(adapter);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/* We can't just free everything and then setup again,
9338c2ecf20Sopenharmony_ci	 * because the ISRs in MSI-X mode get passed pointers
9348c2ecf20Sopenharmony_ci	 * to the Tx and Rx ring structs.
9358c2ecf20Sopenharmony_ci	 */
9368c2ecf20Sopenharmony_ci	if (new_tx_count != adapter->tx_ring_count) {
9378c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
9388c2ecf20Sopenharmony_ci			memcpy(&temp_ring[i], adapter->tx_ring[i],
9398c2ecf20Sopenharmony_ci			       sizeof(struct igb_ring));
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci			temp_ring[i].count = new_tx_count;
9428c2ecf20Sopenharmony_ci			err = igb_setup_tx_resources(&temp_ring[i]);
9438c2ecf20Sopenharmony_ci			if (err) {
9448c2ecf20Sopenharmony_ci				while (i) {
9458c2ecf20Sopenharmony_ci					i--;
9468c2ecf20Sopenharmony_ci					igb_free_tx_resources(&temp_ring[i]);
9478c2ecf20Sopenharmony_ci				}
9488c2ecf20Sopenharmony_ci				goto err_setup;
9498c2ecf20Sopenharmony_ci			}
9508c2ecf20Sopenharmony_ci		}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
9538c2ecf20Sopenharmony_ci			igb_free_tx_resources(adapter->tx_ring[i]);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci			memcpy(adapter->tx_ring[i], &temp_ring[i],
9568c2ecf20Sopenharmony_ci			       sizeof(struct igb_ring));
9578c2ecf20Sopenharmony_ci		}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci		adapter->tx_ring_count = new_tx_count;
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	if (new_rx_count != adapter->rx_ring_count) {
9638c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
9648c2ecf20Sopenharmony_ci			memcpy(&temp_ring[i], adapter->rx_ring[i],
9658c2ecf20Sopenharmony_ci			       sizeof(struct igb_ring));
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci			/* Clear copied XDP RX-queue info */
9688c2ecf20Sopenharmony_ci			memset(&temp_ring[i].xdp_rxq, 0,
9698c2ecf20Sopenharmony_ci			       sizeof(temp_ring[i].xdp_rxq));
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci			temp_ring[i].count = new_rx_count;
9728c2ecf20Sopenharmony_ci			err = igb_setup_rx_resources(&temp_ring[i]);
9738c2ecf20Sopenharmony_ci			if (err) {
9748c2ecf20Sopenharmony_ci				while (i) {
9758c2ecf20Sopenharmony_ci					i--;
9768c2ecf20Sopenharmony_ci					igb_free_rx_resources(&temp_ring[i]);
9778c2ecf20Sopenharmony_ci				}
9788c2ecf20Sopenharmony_ci				goto err_setup;
9798c2ecf20Sopenharmony_ci			}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
9848c2ecf20Sopenharmony_ci			igb_free_rx_resources(adapter->rx_ring[i]);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci			memcpy(adapter->rx_ring[i], &temp_ring[i],
9878c2ecf20Sopenharmony_ci			       sizeof(struct igb_ring));
9888c2ecf20Sopenharmony_ci		}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		adapter->rx_ring_count = new_rx_count;
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_cierr_setup:
9938c2ecf20Sopenharmony_ci	igb_up(adapter);
9948c2ecf20Sopenharmony_ci	vfree(temp_ring);
9958c2ecf20Sopenharmony_ciclear_reset:
9968c2ecf20Sopenharmony_ci	clear_bit(__IGB_RESETTING, &adapter->state);
9978c2ecf20Sopenharmony_ci	return err;
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci/* ethtool register test data */
10018c2ecf20Sopenharmony_cistruct igb_reg_test {
10028c2ecf20Sopenharmony_ci	u16 reg;
10038c2ecf20Sopenharmony_ci	u16 reg_offset;
10048c2ecf20Sopenharmony_ci	u16 array_len;
10058c2ecf20Sopenharmony_ci	u16 test_type;
10068c2ecf20Sopenharmony_ci	u32 mask;
10078c2ecf20Sopenharmony_ci	u32 write;
10088c2ecf20Sopenharmony_ci};
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci/* In the hardware, registers are laid out either singly, in arrays
10118c2ecf20Sopenharmony_ci * spaced 0x100 bytes apart, or in contiguous tables.  We assume
10128c2ecf20Sopenharmony_ci * most tests take place on arrays or single registers (handled
10138c2ecf20Sopenharmony_ci * as a single-element array) and special-case the tables.
10148c2ecf20Sopenharmony_ci * Table tests are always pattern tests.
10158c2ecf20Sopenharmony_ci *
10168c2ecf20Sopenharmony_ci * We also make provision for some required setup steps by specifying
10178c2ecf20Sopenharmony_ci * registers to be written without any read-back testing.
10188c2ecf20Sopenharmony_ci */
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci#define PATTERN_TEST	1
10218c2ecf20Sopenharmony_ci#define SET_READ_TEST	2
10228c2ecf20Sopenharmony_ci#define WRITE_NO_TEST	3
10238c2ecf20Sopenharmony_ci#define TABLE32_TEST	4
10248c2ecf20Sopenharmony_ci#define TABLE64_TEST_LO	5
10258c2ecf20Sopenharmony_ci#define TABLE64_TEST_HI	6
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci/* i210 reg test */
10288c2ecf20Sopenharmony_cistatic struct igb_reg_test reg_test_i210[] = {
10298c2ecf20Sopenharmony_ci	{ E1000_FCAL,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10308c2ecf20Sopenharmony_ci	{ E1000_FCAH,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
10318c2ecf20Sopenharmony_ci	{ E1000_FCT,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
10328c2ecf20Sopenharmony_ci	{ E1000_RDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
10338c2ecf20Sopenharmony_ci	{ E1000_RDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10348c2ecf20Sopenharmony_ci	{ E1000_RDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
10358c2ecf20Sopenharmony_ci	/* RDH is read-only for i210, only test RDT. */
10368c2ecf20Sopenharmony_ci	{ E1000_RDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10378c2ecf20Sopenharmony_ci	{ E1000_FCRTH,	   0x100, 1,  PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
10388c2ecf20Sopenharmony_ci	{ E1000_FCTTV,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10398c2ecf20Sopenharmony_ci	{ E1000_TIPG,	   0x100, 1,  PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
10408c2ecf20Sopenharmony_ci	{ E1000_TDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
10418c2ecf20Sopenharmony_ci	{ E1000_TDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10428c2ecf20Sopenharmony_ci	{ E1000_TDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
10438c2ecf20Sopenharmony_ci	{ E1000_TDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10448c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
10458c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
10468c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
10478c2ecf20Sopenharmony_ci	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
10488c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_LO,
10498c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
10508c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_HI,
10518c2ecf20Sopenharmony_ci						0x900FFFFF, 0xFFFFFFFF },
10528c2ecf20Sopenharmony_ci	{ E1000_MTA,	   0, 128, TABLE32_TEST,
10538c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
10548c2ecf20Sopenharmony_ci	{ 0, 0, 0, 0, 0 }
10558c2ecf20Sopenharmony_ci};
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci/* i350 reg test */
10588c2ecf20Sopenharmony_cistatic struct igb_reg_test reg_test_i350[] = {
10598c2ecf20Sopenharmony_ci	{ E1000_FCAL,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10608c2ecf20Sopenharmony_ci	{ E1000_FCAH,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
10618c2ecf20Sopenharmony_ci	{ E1000_FCT,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
10628c2ecf20Sopenharmony_ci	{ E1000_VET,	   0x100, 1,  PATTERN_TEST, 0xFFFF0000, 0xFFFF0000 },
10638c2ecf20Sopenharmony_ci	{ E1000_RDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
10648c2ecf20Sopenharmony_ci	{ E1000_RDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10658c2ecf20Sopenharmony_ci	{ E1000_RDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
10668c2ecf20Sopenharmony_ci	{ E1000_RDBAL(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
10678c2ecf20Sopenharmony_ci	{ E1000_RDBAH(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10688c2ecf20Sopenharmony_ci	{ E1000_RDLEN(4),  0x40,  4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
10698c2ecf20Sopenharmony_ci	/* RDH is read-only for i350, only test RDT. */
10708c2ecf20Sopenharmony_ci	{ E1000_RDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10718c2ecf20Sopenharmony_ci	{ E1000_RDT(4),	   0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10728c2ecf20Sopenharmony_ci	{ E1000_FCRTH,	   0x100, 1,  PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
10738c2ecf20Sopenharmony_ci	{ E1000_FCTTV,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10748c2ecf20Sopenharmony_ci	{ E1000_TIPG,	   0x100, 1,  PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
10758c2ecf20Sopenharmony_ci	{ E1000_TDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
10768c2ecf20Sopenharmony_ci	{ E1000_TDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10778c2ecf20Sopenharmony_ci	{ E1000_TDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
10788c2ecf20Sopenharmony_ci	{ E1000_TDBAL(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
10798c2ecf20Sopenharmony_ci	{ E1000_TDBAH(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
10808c2ecf20Sopenharmony_ci	{ E1000_TDLEN(4),  0x40,  4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
10818c2ecf20Sopenharmony_ci	{ E1000_TDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10828c2ecf20Sopenharmony_ci	{ E1000_TDT(4),	   0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
10838c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
10848c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
10858c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
10868c2ecf20Sopenharmony_ci	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
10878c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_LO,
10888c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
10898c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_HI,
10908c2ecf20Sopenharmony_ci						0xC3FFFFFF, 0xFFFFFFFF },
10918c2ecf20Sopenharmony_ci	{ E1000_RA2,	   0, 16, TABLE64_TEST_LO,
10928c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
10938c2ecf20Sopenharmony_ci	{ E1000_RA2,	   0, 16, TABLE64_TEST_HI,
10948c2ecf20Sopenharmony_ci						0xC3FFFFFF, 0xFFFFFFFF },
10958c2ecf20Sopenharmony_ci	{ E1000_MTA,	   0, 128, TABLE32_TEST,
10968c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
10978c2ecf20Sopenharmony_ci	{ 0, 0, 0, 0 }
10988c2ecf20Sopenharmony_ci};
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci/* 82580 reg test */
11018c2ecf20Sopenharmony_cistatic struct igb_reg_test reg_test_82580[] = {
11028c2ecf20Sopenharmony_ci	{ E1000_FCAL,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11038c2ecf20Sopenharmony_ci	{ E1000_FCAH,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
11048c2ecf20Sopenharmony_ci	{ E1000_FCT,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
11058c2ecf20Sopenharmony_ci	{ E1000_VET,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11068c2ecf20Sopenharmony_ci	{ E1000_RDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11078c2ecf20Sopenharmony_ci	{ E1000_RDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11088c2ecf20Sopenharmony_ci	{ E1000_RDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11098c2ecf20Sopenharmony_ci	{ E1000_RDBAL(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11108c2ecf20Sopenharmony_ci	{ E1000_RDBAH(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11118c2ecf20Sopenharmony_ci	{ E1000_RDLEN(4),  0x40,  4,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11128c2ecf20Sopenharmony_ci	/* RDH is read-only for 82580, only test RDT. */
11138c2ecf20Sopenharmony_ci	{ E1000_RDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11148c2ecf20Sopenharmony_ci	{ E1000_RDT(4),	   0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11158c2ecf20Sopenharmony_ci	{ E1000_FCRTH,	   0x100, 1,  PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
11168c2ecf20Sopenharmony_ci	{ E1000_FCTTV,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11178c2ecf20Sopenharmony_ci	{ E1000_TIPG,	   0x100, 1,  PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
11188c2ecf20Sopenharmony_ci	{ E1000_TDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11198c2ecf20Sopenharmony_ci	{ E1000_TDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11208c2ecf20Sopenharmony_ci	{ E1000_TDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11218c2ecf20Sopenharmony_ci	{ E1000_TDBAL(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11228c2ecf20Sopenharmony_ci	{ E1000_TDBAH(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11238c2ecf20Sopenharmony_ci	{ E1000_TDLEN(4),  0x40,  4,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11248c2ecf20Sopenharmony_ci	{ E1000_TDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11258c2ecf20Sopenharmony_ci	{ E1000_TDT(4),	   0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11268c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
11278c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
11288c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
11298c2ecf20Sopenharmony_ci	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
11308c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_LO,
11318c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
11328c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_HI,
11338c2ecf20Sopenharmony_ci						0x83FFFFFF, 0xFFFFFFFF },
11348c2ecf20Sopenharmony_ci	{ E1000_RA2,	   0, 8, TABLE64_TEST_LO,
11358c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
11368c2ecf20Sopenharmony_ci	{ E1000_RA2,	   0, 8, TABLE64_TEST_HI,
11378c2ecf20Sopenharmony_ci						0x83FFFFFF, 0xFFFFFFFF },
11388c2ecf20Sopenharmony_ci	{ E1000_MTA,	   0, 128, TABLE32_TEST,
11398c2ecf20Sopenharmony_ci						0xFFFFFFFF, 0xFFFFFFFF },
11408c2ecf20Sopenharmony_ci	{ 0, 0, 0, 0 }
11418c2ecf20Sopenharmony_ci};
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci/* 82576 reg test */
11448c2ecf20Sopenharmony_cistatic struct igb_reg_test reg_test_82576[] = {
11458c2ecf20Sopenharmony_ci	{ E1000_FCAL,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11468c2ecf20Sopenharmony_ci	{ E1000_FCAH,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
11478c2ecf20Sopenharmony_ci	{ E1000_FCT,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
11488c2ecf20Sopenharmony_ci	{ E1000_VET,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11498c2ecf20Sopenharmony_ci	{ E1000_RDBAL(0),  0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11508c2ecf20Sopenharmony_ci	{ E1000_RDBAH(0),  0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11518c2ecf20Sopenharmony_ci	{ E1000_RDLEN(0),  0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11528c2ecf20Sopenharmony_ci	{ E1000_RDBAL(4),  0x40, 12, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11538c2ecf20Sopenharmony_ci	{ E1000_RDBAH(4),  0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11548c2ecf20Sopenharmony_ci	{ E1000_RDLEN(4),  0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11558c2ecf20Sopenharmony_ci	/* Enable all RX queues before testing. */
11568c2ecf20Sopenharmony_ci	{ E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0,
11578c2ecf20Sopenharmony_ci	  E1000_RXDCTL_QUEUE_ENABLE },
11588c2ecf20Sopenharmony_ci	{ E1000_RXDCTL(4), 0x40, 12, WRITE_NO_TEST, 0,
11598c2ecf20Sopenharmony_ci	  E1000_RXDCTL_QUEUE_ENABLE },
11608c2ecf20Sopenharmony_ci	/* RDH is read-only for 82576, only test RDT. */
11618c2ecf20Sopenharmony_ci	{ E1000_RDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11628c2ecf20Sopenharmony_ci	{ E1000_RDT(4),	   0x40, 12,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11638c2ecf20Sopenharmony_ci	{ E1000_RXDCTL(0), 0x100, 4,  WRITE_NO_TEST, 0, 0 },
11648c2ecf20Sopenharmony_ci	{ E1000_RXDCTL(4), 0x40, 12,  WRITE_NO_TEST, 0, 0 },
11658c2ecf20Sopenharmony_ci	{ E1000_FCRTH,	   0x100, 1,  PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
11668c2ecf20Sopenharmony_ci	{ E1000_FCTTV,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
11678c2ecf20Sopenharmony_ci	{ E1000_TIPG,	   0x100, 1,  PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
11688c2ecf20Sopenharmony_ci	{ E1000_TDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11698c2ecf20Sopenharmony_ci	{ E1000_TDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11708c2ecf20Sopenharmony_ci	{ E1000_TDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11718c2ecf20Sopenharmony_ci	{ E1000_TDBAL(4),  0x40, 12,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11728c2ecf20Sopenharmony_ci	{ E1000_TDBAH(4),  0x40, 12,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11738c2ecf20Sopenharmony_ci	{ E1000_TDLEN(4),  0x40, 12,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
11748c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
11758c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
11768c2ecf20Sopenharmony_ci	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
11778c2ecf20Sopenharmony_ci	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
11788c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
11798c2ecf20Sopenharmony_ci	{ E1000_RA,	   0, 16, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF },
11808c2ecf20Sopenharmony_ci	{ E1000_RA2,	   0, 8, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
11818c2ecf20Sopenharmony_ci	{ E1000_RA2,	   0, 8, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF },
11828c2ecf20Sopenharmony_ci	{ E1000_MTA,	   0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11838c2ecf20Sopenharmony_ci	{ 0, 0, 0, 0 }
11848c2ecf20Sopenharmony_ci};
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci/* 82575 register test */
11878c2ecf20Sopenharmony_cistatic struct igb_reg_test reg_test_82575[] = {
11888c2ecf20Sopenharmony_ci	{ E1000_FCAL,      0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11898c2ecf20Sopenharmony_ci	{ E1000_FCAH,      0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
11908c2ecf20Sopenharmony_ci	{ E1000_FCT,       0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
11918c2ecf20Sopenharmony_ci	{ E1000_VET,       0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11928c2ecf20Sopenharmony_ci	{ E1000_RDBAL(0),  0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
11938c2ecf20Sopenharmony_ci	{ E1000_RDBAH(0),  0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
11948c2ecf20Sopenharmony_ci	{ E1000_RDLEN(0),  0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
11958c2ecf20Sopenharmony_ci	/* Enable all four RX queues before testing. */
11968c2ecf20Sopenharmony_ci	{ E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0,
11978c2ecf20Sopenharmony_ci	  E1000_RXDCTL_QUEUE_ENABLE },
11988c2ecf20Sopenharmony_ci	/* RDH is read-only for 82575, only test RDT. */
11998c2ecf20Sopenharmony_ci	{ E1000_RDT(0),    0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
12008c2ecf20Sopenharmony_ci	{ E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 },
12018c2ecf20Sopenharmony_ci	{ E1000_FCRTH,     0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
12028c2ecf20Sopenharmony_ci	{ E1000_FCTTV,     0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
12038c2ecf20Sopenharmony_ci	{ E1000_TIPG,      0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
12048c2ecf20Sopenharmony_ci	{ E1000_TDBAL(0),  0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
12058c2ecf20Sopenharmony_ci	{ E1000_TDBAH(0),  0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
12068c2ecf20Sopenharmony_ci	{ E1000_TDLEN(0),  0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
12078c2ecf20Sopenharmony_ci	{ E1000_RCTL,      0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
12088c2ecf20Sopenharmony_ci	{ E1000_RCTL,      0x100, 1, SET_READ_TEST, 0x04CFB3FE, 0x003FFFFB },
12098c2ecf20Sopenharmony_ci	{ E1000_RCTL,      0x100, 1, SET_READ_TEST, 0x04CFB3FE, 0xFFFFFFFF },
12108c2ecf20Sopenharmony_ci	{ E1000_TCTL,      0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
12118c2ecf20Sopenharmony_ci	{ E1000_TXCW,      0x100, 1, PATTERN_TEST, 0xC000FFFF, 0x0000FFFF },
12128c2ecf20Sopenharmony_ci	{ E1000_RA,        0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
12138c2ecf20Sopenharmony_ci	{ E1000_RA,        0, 16, TABLE64_TEST_HI, 0x800FFFFF, 0xFFFFFFFF },
12148c2ecf20Sopenharmony_ci	{ E1000_MTA,       0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
12158c2ecf20Sopenharmony_ci	{ 0, 0, 0, 0 }
12168c2ecf20Sopenharmony_ci};
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_cistatic bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
12198c2ecf20Sopenharmony_ci			     int reg, u32 mask, u32 write)
12208c2ecf20Sopenharmony_ci{
12218c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
12228c2ecf20Sopenharmony_ci	u32 pat, val;
12238c2ecf20Sopenharmony_ci	static const u32 _test[] = {
12248c2ecf20Sopenharmony_ci		0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
12258c2ecf20Sopenharmony_ci	for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {
12268c2ecf20Sopenharmony_ci		wr32(reg, (_test[pat] & write));
12278c2ecf20Sopenharmony_ci		val = rd32(reg) & mask;
12288c2ecf20Sopenharmony_ci		if (val != (_test[pat] & write & mask)) {
12298c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
12308c2ecf20Sopenharmony_ci				"pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
12318c2ecf20Sopenharmony_ci				reg, val, (_test[pat] & write & mask));
12328c2ecf20Sopenharmony_ci			*data = reg;
12338c2ecf20Sopenharmony_ci			return true;
12348c2ecf20Sopenharmony_ci		}
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	return false;
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_cistatic bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
12418c2ecf20Sopenharmony_ci			      int reg, u32 mask, u32 write)
12428c2ecf20Sopenharmony_ci{
12438c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
12448c2ecf20Sopenharmony_ci	u32 val;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	wr32(reg, write & mask);
12478c2ecf20Sopenharmony_ci	val = rd32(reg);
12488c2ecf20Sopenharmony_ci	if ((write & mask) != (val & mask)) {
12498c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
12508c2ecf20Sopenharmony_ci			"set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
12518c2ecf20Sopenharmony_ci			reg, (val & mask), (write & mask));
12528c2ecf20Sopenharmony_ci		*data = reg;
12538c2ecf20Sopenharmony_ci		return true;
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	return false;
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci#define REG_PATTERN_TEST(reg, mask, write) \
12608c2ecf20Sopenharmony_ci	do { \
12618c2ecf20Sopenharmony_ci		if (reg_pattern_test(adapter, data, reg, mask, write)) \
12628c2ecf20Sopenharmony_ci			return 1; \
12638c2ecf20Sopenharmony_ci	} while (0)
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci#define REG_SET_AND_CHECK(reg, mask, write) \
12668c2ecf20Sopenharmony_ci	do { \
12678c2ecf20Sopenharmony_ci		if (reg_set_and_check(adapter, data, reg, mask, write)) \
12688c2ecf20Sopenharmony_ci			return 1; \
12698c2ecf20Sopenharmony_ci	} while (0)
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_cistatic int igb_reg_test(struct igb_adapter *adapter, u64 *data)
12728c2ecf20Sopenharmony_ci{
12738c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
12748c2ecf20Sopenharmony_ci	struct igb_reg_test *test;
12758c2ecf20Sopenharmony_ci	u32 value, before, after;
12768c2ecf20Sopenharmony_ci	u32 i, toggle;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	switch (adapter->hw.mac.type) {
12798c2ecf20Sopenharmony_ci	case e1000_i350:
12808c2ecf20Sopenharmony_ci	case e1000_i354:
12818c2ecf20Sopenharmony_ci		test = reg_test_i350;
12828c2ecf20Sopenharmony_ci		toggle = 0x7FEFF3FF;
12838c2ecf20Sopenharmony_ci		break;
12848c2ecf20Sopenharmony_ci	case e1000_i210:
12858c2ecf20Sopenharmony_ci	case e1000_i211:
12868c2ecf20Sopenharmony_ci		test = reg_test_i210;
12878c2ecf20Sopenharmony_ci		toggle = 0x7FEFF3FF;
12888c2ecf20Sopenharmony_ci		break;
12898c2ecf20Sopenharmony_ci	case e1000_82580:
12908c2ecf20Sopenharmony_ci		test = reg_test_82580;
12918c2ecf20Sopenharmony_ci		toggle = 0x7FEFF3FF;
12928c2ecf20Sopenharmony_ci		break;
12938c2ecf20Sopenharmony_ci	case e1000_82576:
12948c2ecf20Sopenharmony_ci		test = reg_test_82576;
12958c2ecf20Sopenharmony_ci		toggle = 0x7FFFF3FF;
12968c2ecf20Sopenharmony_ci		break;
12978c2ecf20Sopenharmony_ci	default:
12988c2ecf20Sopenharmony_ci		test = reg_test_82575;
12998c2ecf20Sopenharmony_ci		toggle = 0x7FFFF3FF;
13008c2ecf20Sopenharmony_ci		break;
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	/* Because the status register is such a special case,
13048c2ecf20Sopenharmony_ci	 * we handle it separately from the rest of the register
13058c2ecf20Sopenharmony_ci	 * tests.  Some bits are read-only, some toggle, and some
13068c2ecf20Sopenharmony_ci	 * are writable on newer MACs.
13078c2ecf20Sopenharmony_ci	 */
13088c2ecf20Sopenharmony_ci	before = rd32(E1000_STATUS);
13098c2ecf20Sopenharmony_ci	value = (rd32(E1000_STATUS) & toggle);
13108c2ecf20Sopenharmony_ci	wr32(E1000_STATUS, toggle);
13118c2ecf20Sopenharmony_ci	after = rd32(E1000_STATUS) & toggle;
13128c2ecf20Sopenharmony_ci	if (value != after) {
13138c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
13148c2ecf20Sopenharmony_ci			"failed STATUS register test got: 0x%08X expected: 0x%08X\n",
13158c2ecf20Sopenharmony_ci			after, value);
13168c2ecf20Sopenharmony_ci		*data = 1;
13178c2ecf20Sopenharmony_ci		return 1;
13188c2ecf20Sopenharmony_ci	}
13198c2ecf20Sopenharmony_ci	/* restore previous status */
13208c2ecf20Sopenharmony_ci	wr32(E1000_STATUS, before);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	/* Perform the remainder of the register test, looping through
13238c2ecf20Sopenharmony_ci	 * the test table until we either fail or reach the null entry.
13248c2ecf20Sopenharmony_ci	 */
13258c2ecf20Sopenharmony_ci	while (test->reg) {
13268c2ecf20Sopenharmony_ci		for (i = 0; i < test->array_len; i++) {
13278c2ecf20Sopenharmony_ci			switch (test->test_type) {
13288c2ecf20Sopenharmony_ci			case PATTERN_TEST:
13298c2ecf20Sopenharmony_ci				REG_PATTERN_TEST(test->reg +
13308c2ecf20Sopenharmony_ci						(i * test->reg_offset),
13318c2ecf20Sopenharmony_ci						test->mask,
13328c2ecf20Sopenharmony_ci						test->write);
13338c2ecf20Sopenharmony_ci				break;
13348c2ecf20Sopenharmony_ci			case SET_READ_TEST:
13358c2ecf20Sopenharmony_ci				REG_SET_AND_CHECK(test->reg +
13368c2ecf20Sopenharmony_ci						(i * test->reg_offset),
13378c2ecf20Sopenharmony_ci						test->mask,
13388c2ecf20Sopenharmony_ci						test->write);
13398c2ecf20Sopenharmony_ci				break;
13408c2ecf20Sopenharmony_ci			case WRITE_NO_TEST:
13418c2ecf20Sopenharmony_ci				writel(test->write,
13428c2ecf20Sopenharmony_ci				    (adapter->hw.hw_addr + test->reg)
13438c2ecf20Sopenharmony_ci					+ (i * test->reg_offset));
13448c2ecf20Sopenharmony_ci				break;
13458c2ecf20Sopenharmony_ci			case TABLE32_TEST:
13468c2ecf20Sopenharmony_ci				REG_PATTERN_TEST(test->reg + (i * 4),
13478c2ecf20Sopenharmony_ci						test->mask,
13488c2ecf20Sopenharmony_ci						test->write);
13498c2ecf20Sopenharmony_ci				break;
13508c2ecf20Sopenharmony_ci			case TABLE64_TEST_LO:
13518c2ecf20Sopenharmony_ci				REG_PATTERN_TEST(test->reg + (i * 8),
13528c2ecf20Sopenharmony_ci						test->mask,
13538c2ecf20Sopenharmony_ci						test->write);
13548c2ecf20Sopenharmony_ci				break;
13558c2ecf20Sopenharmony_ci			case TABLE64_TEST_HI:
13568c2ecf20Sopenharmony_ci				REG_PATTERN_TEST((test->reg + 4) + (i * 8),
13578c2ecf20Sopenharmony_ci						test->mask,
13588c2ecf20Sopenharmony_ci						test->write);
13598c2ecf20Sopenharmony_ci				break;
13608c2ecf20Sopenharmony_ci			}
13618c2ecf20Sopenharmony_ci		}
13628c2ecf20Sopenharmony_ci		test++;
13638c2ecf20Sopenharmony_ci	}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	*data = 0;
13668c2ecf20Sopenharmony_ci	return 0;
13678c2ecf20Sopenharmony_ci}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cistatic int igb_eeprom_test(struct igb_adapter *adapter, u64 *data)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	*data = 0;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	/* Validate eeprom on all parts but flashless */
13768c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
13778c2ecf20Sopenharmony_ci	case e1000_i210:
13788c2ecf20Sopenharmony_ci	case e1000_i211:
13798c2ecf20Sopenharmony_ci		if (igb_get_flash_presence_i210(hw)) {
13808c2ecf20Sopenharmony_ci			if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0)
13818c2ecf20Sopenharmony_ci				*data = 2;
13828c2ecf20Sopenharmony_ci		}
13838c2ecf20Sopenharmony_ci		break;
13848c2ecf20Sopenharmony_ci	default:
13858c2ecf20Sopenharmony_ci		if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0)
13868c2ecf20Sopenharmony_ci			*data = 2;
13878c2ecf20Sopenharmony_ci		break;
13888c2ecf20Sopenharmony_ci	}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	return *data;
13918c2ecf20Sopenharmony_ci}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_cistatic irqreturn_t igb_test_intr(int irq, void *data)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = (struct igb_adapter *) data;
13968c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	adapter->test_icr |= rd32(E1000_ICR);
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
14018c2ecf20Sopenharmony_ci}
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_cistatic int igb_intr_test(struct igb_adapter *adapter, u64 *data)
14048c2ecf20Sopenharmony_ci{
14058c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
14068c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
14078c2ecf20Sopenharmony_ci	u32 mask, ics_mask, i = 0, shared_int = true;
14088c2ecf20Sopenharmony_ci	u32 irq = adapter->pdev->irq;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	*data = 0;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	/* Hook up test interrupt handler just for this test */
14138c2ecf20Sopenharmony_ci	if (adapter->flags & IGB_FLAG_HAS_MSIX) {
14148c2ecf20Sopenharmony_ci		if (request_irq(adapter->msix_entries[0].vector,
14158c2ecf20Sopenharmony_ci				igb_test_intr, 0, netdev->name, adapter)) {
14168c2ecf20Sopenharmony_ci			*data = 1;
14178c2ecf20Sopenharmony_ci			return -1;
14188c2ecf20Sopenharmony_ci		}
14198c2ecf20Sopenharmony_ci		wr32(E1000_IVAR_MISC, E1000_IVAR_VALID << 8);
14208c2ecf20Sopenharmony_ci		wr32(E1000_EIMS, BIT(0));
14218c2ecf20Sopenharmony_ci	} else if (adapter->flags & IGB_FLAG_HAS_MSI) {
14228c2ecf20Sopenharmony_ci		shared_int = false;
14238c2ecf20Sopenharmony_ci		if (request_irq(irq,
14248c2ecf20Sopenharmony_ci				igb_test_intr, 0, netdev->name, adapter)) {
14258c2ecf20Sopenharmony_ci			*data = 1;
14268c2ecf20Sopenharmony_ci			return -1;
14278c2ecf20Sopenharmony_ci		}
14288c2ecf20Sopenharmony_ci	} else if (!request_irq(irq, igb_test_intr, IRQF_PROBE_SHARED,
14298c2ecf20Sopenharmony_ci				netdev->name, adapter)) {
14308c2ecf20Sopenharmony_ci		shared_int = false;
14318c2ecf20Sopenharmony_ci	} else if (request_irq(irq, igb_test_intr, IRQF_SHARED,
14328c2ecf20Sopenharmony_ci		 netdev->name, adapter)) {
14338c2ecf20Sopenharmony_ci		*data = 1;
14348c2ecf20Sopenharmony_ci		return -1;
14358c2ecf20Sopenharmony_ci	}
14368c2ecf20Sopenharmony_ci	dev_info(&adapter->pdev->dev, "testing %s interrupt\n",
14378c2ecf20Sopenharmony_ci		(shared_int ? "shared" : "unshared"));
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	/* Disable all the interrupts */
14408c2ecf20Sopenharmony_ci	wr32(E1000_IMC, ~0);
14418c2ecf20Sopenharmony_ci	wrfl();
14428c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	/* Define all writable bits for ICS */
14458c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
14468c2ecf20Sopenharmony_ci	case e1000_82575:
14478c2ecf20Sopenharmony_ci		ics_mask = 0x37F47EDD;
14488c2ecf20Sopenharmony_ci		break;
14498c2ecf20Sopenharmony_ci	case e1000_82576:
14508c2ecf20Sopenharmony_ci		ics_mask = 0x77D4FBFD;
14518c2ecf20Sopenharmony_ci		break;
14528c2ecf20Sopenharmony_ci	case e1000_82580:
14538c2ecf20Sopenharmony_ci		ics_mask = 0x77DCFED5;
14548c2ecf20Sopenharmony_ci		break;
14558c2ecf20Sopenharmony_ci	case e1000_i350:
14568c2ecf20Sopenharmony_ci	case e1000_i354:
14578c2ecf20Sopenharmony_ci	case e1000_i210:
14588c2ecf20Sopenharmony_ci	case e1000_i211:
14598c2ecf20Sopenharmony_ci		ics_mask = 0x77DCFED5;
14608c2ecf20Sopenharmony_ci		break;
14618c2ecf20Sopenharmony_ci	default:
14628c2ecf20Sopenharmony_ci		ics_mask = 0x7FFFFFFF;
14638c2ecf20Sopenharmony_ci		break;
14648c2ecf20Sopenharmony_ci	}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	/* Test each interrupt */
14678c2ecf20Sopenharmony_ci	for (; i < 31; i++) {
14688c2ecf20Sopenharmony_ci		/* Interrupt to test */
14698c2ecf20Sopenharmony_ci		mask = BIT(i);
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci		if (!(mask & ics_mask))
14728c2ecf20Sopenharmony_ci			continue;
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci		if (!shared_int) {
14758c2ecf20Sopenharmony_ci			/* Disable the interrupt to be reported in
14768c2ecf20Sopenharmony_ci			 * the cause register and then force the same
14778c2ecf20Sopenharmony_ci			 * interrupt and see if one gets posted.  If
14788c2ecf20Sopenharmony_ci			 * an interrupt was posted to the bus, the
14798c2ecf20Sopenharmony_ci			 * test failed.
14808c2ecf20Sopenharmony_ci			 */
14818c2ecf20Sopenharmony_ci			adapter->test_icr = 0;
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci			/* Flush any pending interrupts */
14848c2ecf20Sopenharmony_ci			wr32(E1000_ICR, ~0);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci			wr32(E1000_IMC, mask);
14878c2ecf20Sopenharmony_ci			wr32(E1000_ICS, mask);
14888c2ecf20Sopenharmony_ci			wrfl();
14898c2ecf20Sopenharmony_ci			usleep_range(10000, 11000);
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci			if (adapter->test_icr & mask) {
14928c2ecf20Sopenharmony_ci				*data = 3;
14938c2ecf20Sopenharmony_ci				break;
14948c2ecf20Sopenharmony_ci			}
14958c2ecf20Sopenharmony_ci		}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci		/* Enable the interrupt to be reported in
14988c2ecf20Sopenharmony_ci		 * the cause register and then force the same
14998c2ecf20Sopenharmony_ci		 * interrupt and see if one gets posted.  If
15008c2ecf20Sopenharmony_ci		 * an interrupt was not posted to the bus, the
15018c2ecf20Sopenharmony_ci		 * test failed.
15028c2ecf20Sopenharmony_ci		 */
15038c2ecf20Sopenharmony_ci		adapter->test_icr = 0;
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci		/* Flush any pending interrupts */
15068c2ecf20Sopenharmony_ci		wr32(E1000_ICR, ~0);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci		wr32(E1000_IMS, mask);
15098c2ecf20Sopenharmony_ci		wr32(E1000_ICS, mask);
15108c2ecf20Sopenharmony_ci		wrfl();
15118c2ecf20Sopenharmony_ci		usleep_range(10000, 11000);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci		if (!(adapter->test_icr & mask)) {
15148c2ecf20Sopenharmony_ci			*data = 4;
15158c2ecf20Sopenharmony_ci			break;
15168c2ecf20Sopenharmony_ci		}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		if (!shared_int) {
15198c2ecf20Sopenharmony_ci			/* Disable the other interrupts to be reported in
15208c2ecf20Sopenharmony_ci			 * the cause register and then force the other
15218c2ecf20Sopenharmony_ci			 * interrupts and see if any get posted.  If
15228c2ecf20Sopenharmony_ci			 * an interrupt was posted to the bus, the
15238c2ecf20Sopenharmony_ci			 * test failed.
15248c2ecf20Sopenharmony_ci			 */
15258c2ecf20Sopenharmony_ci			adapter->test_icr = 0;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci			/* Flush any pending interrupts */
15288c2ecf20Sopenharmony_ci			wr32(E1000_ICR, ~0);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci			wr32(E1000_IMC, ~mask);
15318c2ecf20Sopenharmony_ci			wr32(E1000_ICS, ~mask);
15328c2ecf20Sopenharmony_ci			wrfl();
15338c2ecf20Sopenharmony_ci			usleep_range(10000, 11000);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci			if (adapter->test_icr & mask) {
15368c2ecf20Sopenharmony_ci				*data = 5;
15378c2ecf20Sopenharmony_ci				break;
15388c2ecf20Sopenharmony_ci			}
15398c2ecf20Sopenharmony_ci		}
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	/* Disable all the interrupts */
15438c2ecf20Sopenharmony_ci	wr32(E1000_IMC, ~0);
15448c2ecf20Sopenharmony_ci	wrfl();
15458c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	/* Unhook test interrupt handler */
15488c2ecf20Sopenharmony_ci	if (adapter->flags & IGB_FLAG_HAS_MSIX)
15498c2ecf20Sopenharmony_ci		free_irq(adapter->msix_entries[0].vector, adapter);
15508c2ecf20Sopenharmony_ci	else
15518c2ecf20Sopenharmony_ci		free_irq(irq, adapter);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	return *data;
15548c2ecf20Sopenharmony_ci}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_cistatic void igb_free_desc_rings(struct igb_adapter *adapter)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	igb_free_tx_resources(&adapter->test_tx_ring);
15598c2ecf20Sopenharmony_ci	igb_free_rx_resources(&adapter->test_rx_ring);
15608c2ecf20Sopenharmony_ci}
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_cistatic int igb_setup_desc_rings(struct igb_adapter *adapter)
15638c2ecf20Sopenharmony_ci{
15648c2ecf20Sopenharmony_ci	struct igb_ring *tx_ring = &adapter->test_tx_ring;
15658c2ecf20Sopenharmony_ci	struct igb_ring *rx_ring = &adapter->test_rx_ring;
15668c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
15678c2ecf20Sopenharmony_ci	int ret_val;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	/* Setup Tx descriptor ring and Tx buffers */
15708c2ecf20Sopenharmony_ci	tx_ring->count = IGB_DEFAULT_TXD;
15718c2ecf20Sopenharmony_ci	tx_ring->dev = &adapter->pdev->dev;
15728c2ecf20Sopenharmony_ci	tx_ring->netdev = adapter->netdev;
15738c2ecf20Sopenharmony_ci	tx_ring->reg_idx = adapter->vfs_allocated_count;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	if (igb_setup_tx_resources(tx_ring)) {
15768c2ecf20Sopenharmony_ci		ret_val = 1;
15778c2ecf20Sopenharmony_ci		goto err_nomem;
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	igb_setup_tctl(adapter);
15818c2ecf20Sopenharmony_ci	igb_configure_tx_ring(adapter, tx_ring);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	/* Setup Rx descriptor ring and Rx buffers */
15848c2ecf20Sopenharmony_ci	rx_ring->count = IGB_DEFAULT_RXD;
15858c2ecf20Sopenharmony_ci	rx_ring->dev = &adapter->pdev->dev;
15868c2ecf20Sopenharmony_ci	rx_ring->netdev = adapter->netdev;
15878c2ecf20Sopenharmony_ci	rx_ring->reg_idx = adapter->vfs_allocated_count;
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	if (igb_setup_rx_resources(rx_ring)) {
15908c2ecf20Sopenharmony_ci		ret_val = 3;
15918c2ecf20Sopenharmony_ci		goto err_nomem;
15928c2ecf20Sopenharmony_ci	}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	/* set the default queue to queue 0 of PF */
15958c2ecf20Sopenharmony_ci	wr32(E1000_MRQC, adapter->vfs_allocated_count << 3);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	/* enable receive ring */
15988c2ecf20Sopenharmony_ci	igb_setup_rctl(adapter);
15998c2ecf20Sopenharmony_ci	igb_configure_rx_ring(adapter, rx_ring);
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	igb_alloc_rx_buffers(rx_ring, igb_desc_unused(rx_ring));
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	return 0;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_cierr_nomem:
16068c2ecf20Sopenharmony_ci	igb_free_desc_rings(adapter);
16078c2ecf20Sopenharmony_ci	return ret_val;
16088c2ecf20Sopenharmony_ci}
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_cistatic void igb_phy_disable_receiver(struct igb_adapter *adapter)
16118c2ecf20Sopenharmony_ci{
16128c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	/* Write out to PHY registers 29 and 30 to disable the Receiver. */
16158c2ecf20Sopenharmony_ci	igb_write_phy_reg(hw, 29, 0x001F);
16168c2ecf20Sopenharmony_ci	igb_write_phy_reg(hw, 30, 0x8FFC);
16178c2ecf20Sopenharmony_ci	igb_write_phy_reg(hw, 29, 0x001A);
16188c2ecf20Sopenharmony_ci	igb_write_phy_reg(hw, 30, 0x8FF0);
16198c2ecf20Sopenharmony_ci}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_cistatic int igb_integrated_phy_loopback(struct igb_adapter *adapter)
16228c2ecf20Sopenharmony_ci{
16238c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
16248c2ecf20Sopenharmony_ci	u32 ctrl_reg = 0;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	hw->mac.autoneg = false;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if (hw->phy.type == e1000_phy_m88) {
16298c2ecf20Sopenharmony_ci		if (hw->phy.id != I210_I_PHY_ID) {
16308c2ecf20Sopenharmony_ci			/* Auto-MDI/MDIX Off */
16318c2ecf20Sopenharmony_ci			igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
16328c2ecf20Sopenharmony_ci			/* reset to update Auto-MDI/MDIX */
16338c2ecf20Sopenharmony_ci			igb_write_phy_reg(hw, PHY_CONTROL, 0x9140);
16348c2ecf20Sopenharmony_ci			/* autoneg off */
16358c2ecf20Sopenharmony_ci			igb_write_phy_reg(hw, PHY_CONTROL, 0x8140);
16368c2ecf20Sopenharmony_ci		} else {
16378c2ecf20Sopenharmony_ci			/* force 1000, set loopback  */
16388c2ecf20Sopenharmony_ci			igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0);
16398c2ecf20Sopenharmony_ci			igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
16408c2ecf20Sopenharmony_ci		}
16418c2ecf20Sopenharmony_ci	} else if (hw->phy.type == e1000_phy_82580) {
16428c2ecf20Sopenharmony_ci		/* enable MII loopback */
16438c2ecf20Sopenharmony_ci		igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041);
16448c2ecf20Sopenharmony_ci	}
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	/* add small delay to avoid loopback test failure */
16478c2ecf20Sopenharmony_ci	msleep(50);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	/* force 1000, set loopback */
16508c2ecf20Sopenharmony_ci	igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	/* Now set up the MAC to the same speed/duplex as the PHY. */
16538c2ecf20Sopenharmony_ci	ctrl_reg = rd32(E1000_CTRL);
16548c2ecf20Sopenharmony_ci	ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
16558c2ecf20Sopenharmony_ci	ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
16568c2ecf20Sopenharmony_ci		     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
16578c2ecf20Sopenharmony_ci		     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
16588c2ecf20Sopenharmony_ci		     E1000_CTRL_FD |	 /* Force Duplex to FULL */
16598c2ecf20Sopenharmony_ci		     E1000_CTRL_SLU);	 /* Set link up enable bit */
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (hw->phy.type == e1000_phy_m88)
16628c2ecf20Sopenharmony_ci		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	wr32(E1000_CTRL, ctrl_reg);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	/* Disable the receiver on the PHY so when a cable is plugged in, the
16678c2ecf20Sopenharmony_ci	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.
16688c2ecf20Sopenharmony_ci	 */
16698c2ecf20Sopenharmony_ci	if (hw->phy.type == e1000_phy_m88)
16708c2ecf20Sopenharmony_ci		igb_phy_disable_receiver(adapter);
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	msleep(500);
16738c2ecf20Sopenharmony_ci	return 0;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_cistatic int igb_set_phy_loopback(struct igb_adapter *adapter)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	return igb_integrated_phy_loopback(adapter);
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_cistatic int igb_setup_loopback_test(struct igb_adapter *adapter)
16828c2ecf20Sopenharmony_ci{
16838c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
16848c2ecf20Sopenharmony_ci	u32 reg;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	reg = rd32(E1000_CTRL_EXT);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	/* use CTRL_EXT to identify link type as SGMII can appear as copper */
16898c2ecf20Sopenharmony_ci	if (reg & E1000_CTRL_EXT_LINK_MODE_MASK) {
16908c2ecf20Sopenharmony_ci		if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) ||
16918c2ecf20Sopenharmony_ci		(hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) ||
16928c2ecf20Sopenharmony_ci		(hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) ||
16938c2ecf20Sopenharmony_ci		(hw->device_id == E1000_DEV_ID_DH89XXCC_SFP) ||
16948c2ecf20Sopenharmony_ci		(hw->device_id == E1000_DEV_ID_I354_SGMII) ||
16958c2ecf20Sopenharmony_ci		(hw->device_id == E1000_DEV_ID_I354_BACKPLANE_2_5GBPS)) {
16968c2ecf20Sopenharmony_ci			/* Enable DH89xxCC MPHY for near end loopback */
16978c2ecf20Sopenharmony_ci			reg = rd32(E1000_MPHY_ADDR_CTL);
16988c2ecf20Sopenharmony_ci			reg = (reg & E1000_MPHY_ADDR_CTL_OFFSET_MASK) |
16998c2ecf20Sopenharmony_ci			E1000_MPHY_PCS_CLK_REG_OFFSET;
17008c2ecf20Sopenharmony_ci			wr32(E1000_MPHY_ADDR_CTL, reg);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci			reg = rd32(E1000_MPHY_DATA);
17038c2ecf20Sopenharmony_ci			reg |= E1000_MPHY_PCS_CLK_REG_DIGINELBEN;
17048c2ecf20Sopenharmony_ci			wr32(E1000_MPHY_DATA, reg);
17058c2ecf20Sopenharmony_ci		}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci		reg = rd32(E1000_RCTL);
17088c2ecf20Sopenharmony_ci		reg |= E1000_RCTL_LBM_TCVR;
17098c2ecf20Sopenharmony_ci		wr32(E1000_RCTL, reg);
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci		wr32(E1000_SCTL, E1000_ENABLE_SERDES_LOOPBACK);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci		reg = rd32(E1000_CTRL);
17148c2ecf20Sopenharmony_ci		reg &= ~(E1000_CTRL_RFCE |
17158c2ecf20Sopenharmony_ci			 E1000_CTRL_TFCE |
17168c2ecf20Sopenharmony_ci			 E1000_CTRL_LRST);
17178c2ecf20Sopenharmony_ci		reg |= E1000_CTRL_SLU |
17188c2ecf20Sopenharmony_ci		       E1000_CTRL_FD;
17198c2ecf20Sopenharmony_ci		wr32(E1000_CTRL, reg);
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci		/* Unset switch control to serdes energy detect */
17228c2ecf20Sopenharmony_ci		reg = rd32(E1000_CONNSW);
17238c2ecf20Sopenharmony_ci		reg &= ~E1000_CONNSW_ENRGSRC;
17248c2ecf20Sopenharmony_ci		wr32(E1000_CONNSW, reg);
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci		/* Unset sigdetect for SERDES loopback on
17278c2ecf20Sopenharmony_ci		 * 82580 and newer devices.
17288c2ecf20Sopenharmony_ci		 */
17298c2ecf20Sopenharmony_ci		if (hw->mac.type >= e1000_82580) {
17308c2ecf20Sopenharmony_ci			reg = rd32(E1000_PCS_CFG0);
17318c2ecf20Sopenharmony_ci			reg |= E1000_PCS_CFG_IGN_SD;
17328c2ecf20Sopenharmony_ci			wr32(E1000_PCS_CFG0, reg);
17338c2ecf20Sopenharmony_ci		}
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci		/* Set PCS register for forced speed */
17368c2ecf20Sopenharmony_ci		reg = rd32(E1000_PCS_LCTL);
17378c2ecf20Sopenharmony_ci		reg &= ~E1000_PCS_LCTL_AN_ENABLE;     /* Disable Autoneg*/
17388c2ecf20Sopenharmony_ci		reg |= E1000_PCS_LCTL_FLV_LINK_UP |   /* Force link up */
17398c2ecf20Sopenharmony_ci		       E1000_PCS_LCTL_FSV_1000 |      /* Force 1000    */
17408c2ecf20Sopenharmony_ci		       E1000_PCS_LCTL_FDV_FULL |      /* SerDes Full duplex */
17418c2ecf20Sopenharmony_ci		       E1000_PCS_LCTL_FSD |           /* Force Speed */
17428c2ecf20Sopenharmony_ci		       E1000_PCS_LCTL_FORCE_LINK;     /* Force Link */
17438c2ecf20Sopenharmony_ci		wr32(E1000_PCS_LCTL, reg);
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci		return 0;
17468c2ecf20Sopenharmony_ci	}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	return igb_set_phy_loopback(adapter);
17498c2ecf20Sopenharmony_ci}
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_cistatic void igb_loopback_cleanup(struct igb_adapter *adapter)
17528c2ecf20Sopenharmony_ci{
17538c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
17548c2ecf20Sopenharmony_ci	u32 rctl;
17558c2ecf20Sopenharmony_ci	u16 phy_reg;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) ||
17588c2ecf20Sopenharmony_ci	(hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) ||
17598c2ecf20Sopenharmony_ci	(hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) ||
17608c2ecf20Sopenharmony_ci	(hw->device_id == E1000_DEV_ID_DH89XXCC_SFP) ||
17618c2ecf20Sopenharmony_ci	(hw->device_id == E1000_DEV_ID_I354_SGMII)) {
17628c2ecf20Sopenharmony_ci		u32 reg;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci		/* Disable near end loopback on DH89xxCC */
17658c2ecf20Sopenharmony_ci		reg = rd32(E1000_MPHY_ADDR_CTL);
17668c2ecf20Sopenharmony_ci		reg = (reg & E1000_MPHY_ADDR_CTL_OFFSET_MASK) |
17678c2ecf20Sopenharmony_ci		E1000_MPHY_PCS_CLK_REG_OFFSET;
17688c2ecf20Sopenharmony_ci		wr32(E1000_MPHY_ADDR_CTL, reg);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci		reg = rd32(E1000_MPHY_DATA);
17718c2ecf20Sopenharmony_ci		reg &= ~E1000_MPHY_PCS_CLK_REG_DIGINELBEN;
17728c2ecf20Sopenharmony_ci		wr32(E1000_MPHY_DATA, reg);
17738c2ecf20Sopenharmony_ci	}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	rctl = rd32(E1000_RCTL);
17768c2ecf20Sopenharmony_ci	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
17778c2ecf20Sopenharmony_ci	wr32(E1000_RCTL, rctl);
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	hw->mac.autoneg = true;
17808c2ecf20Sopenharmony_ci	igb_read_phy_reg(hw, PHY_CONTROL, &phy_reg);
17818c2ecf20Sopenharmony_ci	if (phy_reg & MII_CR_LOOPBACK) {
17828c2ecf20Sopenharmony_ci		phy_reg &= ~MII_CR_LOOPBACK;
17838c2ecf20Sopenharmony_ci		igb_write_phy_reg(hw, PHY_CONTROL, phy_reg);
17848c2ecf20Sopenharmony_ci		igb_phy_sw_reset(hw);
17858c2ecf20Sopenharmony_ci	}
17868c2ecf20Sopenharmony_ci}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_cistatic void igb_create_lbtest_frame(struct sk_buff *skb,
17898c2ecf20Sopenharmony_ci				    unsigned int frame_size)
17908c2ecf20Sopenharmony_ci{
17918c2ecf20Sopenharmony_ci	memset(skb->data, 0xFF, frame_size);
17928c2ecf20Sopenharmony_ci	frame_size /= 2;
17938c2ecf20Sopenharmony_ci	memset(&skb->data[frame_size], 0xAA, frame_size - 1);
17948c2ecf20Sopenharmony_ci	skb->data[frame_size + 10] = 0xBE;
17958c2ecf20Sopenharmony_ci	skb->data[frame_size + 12] = 0xAF;
17968c2ecf20Sopenharmony_ci}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_cistatic int igb_check_lbtest_frame(struct igb_rx_buffer *rx_buffer,
17998c2ecf20Sopenharmony_ci				  unsigned int frame_size)
18008c2ecf20Sopenharmony_ci{
18018c2ecf20Sopenharmony_ci	unsigned char *data;
18028c2ecf20Sopenharmony_ci	bool match = true;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	frame_size >>= 1;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	data = kmap(rx_buffer->page);
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	if (data[3] != 0xFF ||
18098c2ecf20Sopenharmony_ci	    data[frame_size + 10] != 0xBE ||
18108c2ecf20Sopenharmony_ci	    data[frame_size + 12] != 0xAF)
18118c2ecf20Sopenharmony_ci		match = false;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	kunmap(rx_buffer->page);
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	return match;
18168c2ecf20Sopenharmony_ci}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_cistatic int igb_clean_test_rings(struct igb_ring *rx_ring,
18198c2ecf20Sopenharmony_ci				struct igb_ring *tx_ring,
18208c2ecf20Sopenharmony_ci				unsigned int size)
18218c2ecf20Sopenharmony_ci{
18228c2ecf20Sopenharmony_ci	union e1000_adv_rx_desc *rx_desc;
18238c2ecf20Sopenharmony_ci	struct igb_rx_buffer *rx_buffer_info;
18248c2ecf20Sopenharmony_ci	struct igb_tx_buffer *tx_buffer_info;
18258c2ecf20Sopenharmony_ci	u16 rx_ntc, tx_ntc, count = 0;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	/* initialize next to clean and descriptor values */
18288c2ecf20Sopenharmony_ci	rx_ntc = rx_ring->next_to_clean;
18298c2ecf20Sopenharmony_ci	tx_ntc = tx_ring->next_to_clean;
18308c2ecf20Sopenharmony_ci	rx_desc = IGB_RX_DESC(rx_ring, rx_ntc);
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	while (rx_desc->wb.upper.length) {
18338c2ecf20Sopenharmony_ci		/* check Rx buffer */
18348c2ecf20Sopenharmony_ci		rx_buffer_info = &rx_ring->rx_buffer_info[rx_ntc];
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci		/* sync Rx buffer for CPU read */
18378c2ecf20Sopenharmony_ci		dma_sync_single_for_cpu(rx_ring->dev,
18388c2ecf20Sopenharmony_ci					rx_buffer_info->dma,
18398c2ecf20Sopenharmony_ci					size,
18408c2ecf20Sopenharmony_ci					DMA_FROM_DEVICE);
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci		/* verify contents of skb */
18438c2ecf20Sopenharmony_ci		if (igb_check_lbtest_frame(rx_buffer_info, size))
18448c2ecf20Sopenharmony_ci			count++;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci		/* sync Rx buffer for device write */
18478c2ecf20Sopenharmony_ci		dma_sync_single_for_device(rx_ring->dev,
18488c2ecf20Sopenharmony_ci					   rx_buffer_info->dma,
18498c2ecf20Sopenharmony_ci					   size,
18508c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE);
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci		/* unmap buffer on Tx side */
18538c2ecf20Sopenharmony_ci		tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc];
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci		/* Free all the Tx ring sk_buffs */
18568c2ecf20Sopenharmony_ci		dev_kfree_skb_any(tx_buffer_info->skb);
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci		/* unmap skb header data */
18598c2ecf20Sopenharmony_ci		dma_unmap_single(tx_ring->dev,
18608c2ecf20Sopenharmony_ci				 dma_unmap_addr(tx_buffer_info, dma),
18618c2ecf20Sopenharmony_ci				 dma_unmap_len(tx_buffer_info, len),
18628c2ecf20Sopenharmony_ci				 DMA_TO_DEVICE);
18638c2ecf20Sopenharmony_ci		dma_unmap_len_set(tx_buffer_info, len, 0);
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci		/* increment Rx/Tx next to clean counters */
18668c2ecf20Sopenharmony_ci		rx_ntc++;
18678c2ecf20Sopenharmony_ci		if (rx_ntc == rx_ring->count)
18688c2ecf20Sopenharmony_ci			rx_ntc = 0;
18698c2ecf20Sopenharmony_ci		tx_ntc++;
18708c2ecf20Sopenharmony_ci		if (tx_ntc == tx_ring->count)
18718c2ecf20Sopenharmony_ci			tx_ntc = 0;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci		/* fetch next descriptor */
18748c2ecf20Sopenharmony_ci		rx_desc = IGB_RX_DESC(rx_ring, rx_ntc);
18758c2ecf20Sopenharmony_ci	}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	netdev_tx_reset_queue(txring_txq(tx_ring));
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	/* re-map buffers to ring, store next to clean values */
18808c2ecf20Sopenharmony_ci	igb_alloc_rx_buffers(rx_ring, count);
18818c2ecf20Sopenharmony_ci	rx_ring->next_to_clean = rx_ntc;
18828c2ecf20Sopenharmony_ci	tx_ring->next_to_clean = tx_ntc;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	return count;
18858c2ecf20Sopenharmony_ci}
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_cistatic int igb_run_loopback_test(struct igb_adapter *adapter)
18888c2ecf20Sopenharmony_ci{
18898c2ecf20Sopenharmony_ci	struct igb_ring *tx_ring = &adapter->test_tx_ring;
18908c2ecf20Sopenharmony_ci	struct igb_ring *rx_ring = &adapter->test_rx_ring;
18918c2ecf20Sopenharmony_ci	u16 i, j, lc, good_cnt;
18928c2ecf20Sopenharmony_ci	int ret_val = 0;
18938c2ecf20Sopenharmony_ci	unsigned int size = IGB_RX_HDR_LEN;
18948c2ecf20Sopenharmony_ci	netdev_tx_t tx_ret_val;
18958c2ecf20Sopenharmony_ci	struct sk_buff *skb;
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	/* allocate test skb */
18988c2ecf20Sopenharmony_ci	skb = alloc_skb(size, GFP_KERNEL);
18998c2ecf20Sopenharmony_ci	if (!skb)
19008c2ecf20Sopenharmony_ci		return 11;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	/* place data into test skb */
19038c2ecf20Sopenharmony_ci	igb_create_lbtest_frame(skb, size);
19048c2ecf20Sopenharmony_ci	skb_put(skb, size);
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	/* Calculate the loop count based on the largest descriptor ring
19078c2ecf20Sopenharmony_ci	 * The idea is to wrap the largest ring a number of times using 64
19088c2ecf20Sopenharmony_ci	 * send/receive pairs during each loop
19098c2ecf20Sopenharmony_ci	 */
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	if (rx_ring->count <= tx_ring->count)
19128c2ecf20Sopenharmony_ci		lc = ((tx_ring->count / 64) * 2) + 1;
19138c2ecf20Sopenharmony_ci	else
19148c2ecf20Sopenharmony_ci		lc = ((rx_ring->count / 64) * 2) + 1;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	for (j = 0; j <= lc; j++) { /* loop count loop */
19178c2ecf20Sopenharmony_ci		/* reset count of good packets */
19188c2ecf20Sopenharmony_ci		good_cnt = 0;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci		/* place 64 packets on the transmit queue*/
19218c2ecf20Sopenharmony_ci		for (i = 0; i < 64; i++) {
19228c2ecf20Sopenharmony_ci			skb_get(skb);
19238c2ecf20Sopenharmony_ci			tx_ret_val = igb_xmit_frame_ring(skb, tx_ring);
19248c2ecf20Sopenharmony_ci			if (tx_ret_val == NETDEV_TX_OK)
19258c2ecf20Sopenharmony_ci				good_cnt++;
19268c2ecf20Sopenharmony_ci		}
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci		if (good_cnt != 64) {
19298c2ecf20Sopenharmony_ci			ret_val = 12;
19308c2ecf20Sopenharmony_ci			break;
19318c2ecf20Sopenharmony_ci		}
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci		/* allow 200 milliseconds for packets to go from Tx to Rx */
19348c2ecf20Sopenharmony_ci		msleep(200);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci		good_cnt = igb_clean_test_rings(rx_ring, tx_ring, size);
19378c2ecf20Sopenharmony_ci		if (good_cnt != 64) {
19388c2ecf20Sopenharmony_ci			ret_val = 13;
19398c2ecf20Sopenharmony_ci			break;
19408c2ecf20Sopenharmony_ci		}
19418c2ecf20Sopenharmony_ci	} /* end loop count loop */
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	/* free the original skb */
19448c2ecf20Sopenharmony_ci	kfree_skb(skb);
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	return ret_val;
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic int igb_loopback_test(struct igb_adapter *adapter, u64 *data)
19508c2ecf20Sopenharmony_ci{
19518c2ecf20Sopenharmony_ci	/* PHY loopback cannot be performed if SoL/IDER
19528c2ecf20Sopenharmony_ci	 * sessions are active
19538c2ecf20Sopenharmony_ci	 */
19548c2ecf20Sopenharmony_ci	if (igb_check_reset_block(&adapter->hw)) {
19558c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
19568c2ecf20Sopenharmony_ci			"Cannot do PHY loopback test when SoL/IDER is active.\n");
19578c2ecf20Sopenharmony_ci		*data = 0;
19588c2ecf20Sopenharmony_ci		goto out;
19598c2ecf20Sopenharmony_ci	}
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	if (adapter->hw.mac.type == e1000_i354) {
19628c2ecf20Sopenharmony_ci		dev_info(&adapter->pdev->dev,
19638c2ecf20Sopenharmony_ci			"Loopback test not supported on i354.\n");
19648c2ecf20Sopenharmony_ci		*data = 0;
19658c2ecf20Sopenharmony_ci		goto out;
19668c2ecf20Sopenharmony_ci	}
19678c2ecf20Sopenharmony_ci	*data = igb_setup_desc_rings(adapter);
19688c2ecf20Sopenharmony_ci	if (*data)
19698c2ecf20Sopenharmony_ci		goto out;
19708c2ecf20Sopenharmony_ci	*data = igb_setup_loopback_test(adapter);
19718c2ecf20Sopenharmony_ci	if (*data)
19728c2ecf20Sopenharmony_ci		goto err_loopback;
19738c2ecf20Sopenharmony_ci	*data = igb_run_loopback_test(adapter);
19748c2ecf20Sopenharmony_ci	igb_loopback_cleanup(adapter);
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_cierr_loopback:
19778c2ecf20Sopenharmony_ci	igb_free_desc_rings(adapter);
19788c2ecf20Sopenharmony_ciout:
19798c2ecf20Sopenharmony_ci	return *data;
19808c2ecf20Sopenharmony_ci}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_cistatic int igb_link_test(struct igb_adapter *adapter, u64 *data)
19838c2ecf20Sopenharmony_ci{
19848c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
19858c2ecf20Sopenharmony_ci	*data = 0;
19868c2ecf20Sopenharmony_ci	if (hw->phy.media_type == e1000_media_type_internal_serdes) {
19878c2ecf20Sopenharmony_ci		int i = 0;
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci		hw->mac.serdes_has_link = false;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci		/* On some blade server designs, link establishment
19928c2ecf20Sopenharmony_ci		 * could take as long as 2-3 minutes
19938c2ecf20Sopenharmony_ci		 */
19948c2ecf20Sopenharmony_ci		do {
19958c2ecf20Sopenharmony_ci			hw->mac.ops.check_for_link(&adapter->hw);
19968c2ecf20Sopenharmony_ci			if (hw->mac.serdes_has_link)
19978c2ecf20Sopenharmony_ci				return *data;
19988c2ecf20Sopenharmony_ci			msleep(20);
19998c2ecf20Sopenharmony_ci		} while (i++ < 3750);
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci		*data = 1;
20028c2ecf20Sopenharmony_ci	} else {
20038c2ecf20Sopenharmony_ci		hw->mac.ops.check_for_link(&adapter->hw);
20048c2ecf20Sopenharmony_ci		if (hw->mac.autoneg)
20058c2ecf20Sopenharmony_ci			msleep(5000);
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci		if (!(rd32(E1000_STATUS) & E1000_STATUS_LU))
20088c2ecf20Sopenharmony_ci			*data = 1;
20098c2ecf20Sopenharmony_ci	}
20108c2ecf20Sopenharmony_ci	return *data;
20118c2ecf20Sopenharmony_ci}
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_cistatic void igb_diag_test(struct net_device *netdev,
20148c2ecf20Sopenharmony_ci			  struct ethtool_test *eth_test, u64 *data)
20158c2ecf20Sopenharmony_ci{
20168c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
20178c2ecf20Sopenharmony_ci	u16 autoneg_advertised;
20188c2ecf20Sopenharmony_ci	u8 forced_speed_duplex, autoneg;
20198c2ecf20Sopenharmony_ci	bool if_running = netif_running(netdev);
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	set_bit(__IGB_TESTING, &adapter->state);
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	/* can't do offline tests on media switching devices */
20248c2ecf20Sopenharmony_ci	if (adapter->hw.dev_spec._82575.mas_capable)
20258c2ecf20Sopenharmony_ci		eth_test->flags &= ~ETH_TEST_FL_OFFLINE;
20268c2ecf20Sopenharmony_ci	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
20278c2ecf20Sopenharmony_ci		/* Offline tests */
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci		/* save speed, duplex, autoneg settings */
20308c2ecf20Sopenharmony_ci		autoneg_advertised = adapter->hw.phy.autoneg_advertised;
20318c2ecf20Sopenharmony_ci		forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
20328c2ecf20Sopenharmony_ci		autoneg = adapter->hw.mac.autoneg;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci		dev_info(&adapter->pdev->dev, "offline testing starting\n");
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci		/* power up link for link test */
20378c2ecf20Sopenharmony_ci		igb_power_up_link(adapter);
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci		/* Link test performed before hardware reset so autoneg doesn't
20408c2ecf20Sopenharmony_ci		 * interfere with test result
20418c2ecf20Sopenharmony_ci		 */
20428c2ecf20Sopenharmony_ci		if (igb_link_test(adapter, &data[TEST_LINK]))
20438c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci		if (if_running)
20468c2ecf20Sopenharmony_ci			/* indicate we're in test mode */
20478c2ecf20Sopenharmony_ci			igb_close(netdev);
20488c2ecf20Sopenharmony_ci		else
20498c2ecf20Sopenharmony_ci			igb_reset(adapter);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci		if (igb_reg_test(adapter, &data[TEST_REG]))
20528c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci		igb_reset(adapter);
20558c2ecf20Sopenharmony_ci		if (igb_eeprom_test(adapter, &data[TEST_EEP]))
20568c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci		igb_reset(adapter);
20598c2ecf20Sopenharmony_ci		if (igb_intr_test(adapter, &data[TEST_IRQ]))
20608c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci		igb_reset(adapter);
20638c2ecf20Sopenharmony_ci		/* power up link for loopback test */
20648c2ecf20Sopenharmony_ci		igb_power_up_link(adapter);
20658c2ecf20Sopenharmony_ci		if (igb_loopback_test(adapter, &data[TEST_LOOP]))
20668c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci		/* restore speed, duplex, autoneg settings */
20698c2ecf20Sopenharmony_ci		adapter->hw.phy.autoneg_advertised = autoneg_advertised;
20708c2ecf20Sopenharmony_ci		adapter->hw.mac.forced_speed_duplex = forced_speed_duplex;
20718c2ecf20Sopenharmony_ci		adapter->hw.mac.autoneg = autoneg;
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci		/* force this routine to wait until autoneg complete/timeout */
20748c2ecf20Sopenharmony_ci		adapter->hw.phy.autoneg_wait_to_complete = true;
20758c2ecf20Sopenharmony_ci		igb_reset(adapter);
20768c2ecf20Sopenharmony_ci		adapter->hw.phy.autoneg_wait_to_complete = false;
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci		clear_bit(__IGB_TESTING, &adapter->state);
20798c2ecf20Sopenharmony_ci		if (if_running)
20808c2ecf20Sopenharmony_ci			igb_open(netdev);
20818c2ecf20Sopenharmony_ci	} else {
20828c2ecf20Sopenharmony_ci		dev_info(&adapter->pdev->dev, "online testing starting\n");
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci		/* PHY is powered down when interface is down */
20858c2ecf20Sopenharmony_ci		if (if_running && igb_link_test(adapter, &data[TEST_LINK]))
20868c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
20878c2ecf20Sopenharmony_ci		else
20888c2ecf20Sopenharmony_ci			data[TEST_LINK] = 0;
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci		/* Online tests aren't run; pass by default */
20918c2ecf20Sopenharmony_ci		data[TEST_REG] = 0;
20928c2ecf20Sopenharmony_ci		data[TEST_EEP] = 0;
20938c2ecf20Sopenharmony_ci		data[TEST_IRQ] = 0;
20948c2ecf20Sopenharmony_ci		data[TEST_LOOP] = 0;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci		clear_bit(__IGB_TESTING, &adapter->state);
20978c2ecf20Sopenharmony_ci	}
20988c2ecf20Sopenharmony_ci	msleep_interruptible(4 * 1000);
20998c2ecf20Sopenharmony_ci}
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_cistatic void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	wol->wolopts = 0;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	if (!(adapter->flags & IGB_FLAG_WOL_SUPPORTED))
21088c2ecf20Sopenharmony_ci		return;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	wol->supported = WAKE_UCAST | WAKE_MCAST |
21118c2ecf20Sopenharmony_ci			 WAKE_BCAST | WAKE_MAGIC |
21128c2ecf20Sopenharmony_ci			 WAKE_PHY;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	/* apply any specific unsupported masks here */
21158c2ecf20Sopenharmony_ci	switch (adapter->hw.device_id) {
21168c2ecf20Sopenharmony_ci	default:
21178c2ecf20Sopenharmony_ci		break;
21188c2ecf20Sopenharmony_ci	}
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	if (adapter->wol & E1000_WUFC_EX)
21218c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_UCAST;
21228c2ecf20Sopenharmony_ci	if (adapter->wol & E1000_WUFC_MC)
21238c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_MCAST;
21248c2ecf20Sopenharmony_ci	if (adapter->wol & E1000_WUFC_BC)
21258c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_BCAST;
21268c2ecf20Sopenharmony_ci	if (adapter->wol & E1000_WUFC_MAG)
21278c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_MAGIC;
21288c2ecf20Sopenharmony_ci	if (adapter->wol & E1000_WUFC_LNKC)
21298c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_PHY;
21308c2ecf20Sopenharmony_ci}
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_cistatic int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
21338c2ecf20Sopenharmony_ci{
21348c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER))
21378c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	if (!(adapter->flags & IGB_FLAG_WOL_SUPPORTED))
21408c2ecf20Sopenharmony_ci		return wol->wolopts ? -EOPNOTSUPP : 0;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	/* these settings will always override what we currently have */
21438c2ecf20Sopenharmony_ci	adapter->wol = 0;
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_UCAST)
21468c2ecf20Sopenharmony_ci		adapter->wol |= E1000_WUFC_EX;
21478c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MCAST)
21488c2ecf20Sopenharmony_ci		adapter->wol |= E1000_WUFC_MC;
21498c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_BCAST)
21508c2ecf20Sopenharmony_ci		adapter->wol |= E1000_WUFC_BC;
21518c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC)
21528c2ecf20Sopenharmony_ci		adapter->wol |= E1000_WUFC_MAG;
21538c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_PHY)
21548c2ecf20Sopenharmony_ci		adapter->wol |= E1000_WUFC_LNKC;
21558c2ecf20Sopenharmony_ci	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	return 0;
21588c2ecf20Sopenharmony_ci}
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci/* bit defines for adapter->led_status */
21618c2ecf20Sopenharmony_ci#define IGB_LED_ON		0
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_cistatic int igb_set_phys_id(struct net_device *netdev,
21648c2ecf20Sopenharmony_ci			   enum ethtool_phys_id_state state)
21658c2ecf20Sopenharmony_ci{
21668c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
21678c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	switch (state) {
21708c2ecf20Sopenharmony_ci	case ETHTOOL_ID_ACTIVE:
21718c2ecf20Sopenharmony_ci		igb_blink_led(hw);
21728c2ecf20Sopenharmony_ci		return 2;
21738c2ecf20Sopenharmony_ci	case ETHTOOL_ID_ON:
21748c2ecf20Sopenharmony_ci		igb_blink_led(hw);
21758c2ecf20Sopenharmony_ci		break;
21768c2ecf20Sopenharmony_ci	case ETHTOOL_ID_OFF:
21778c2ecf20Sopenharmony_ci		igb_led_off(hw);
21788c2ecf20Sopenharmony_ci		break;
21798c2ecf20Sopenharmony_ci	case ETHTOOL_ID_INACTIVE:
21808c2ecf20Sopenharmony_ci		igb_led_off(hw);
21818c2ecf20Sopenharmony_ci		clear_bit(IGB_LED_ON, &adapter->led_status);
21828c2ecf20Sopenharmony_ci		igb_cleanup_led(hw);
21838c2ecf20Sopenharmony_ci		break;
21848c2ecf20Sopenharmony_ci	}
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	return 0;
21878c2ecf20Sopenharmony_ci}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_cistatic int igb_set_coalesce(struct net_device *netdev,
21908c2ecf20Sopenharmony_ci			    struct ethtool_coalesce *ec)
21918c2ecf20Sopenharmony_ci{
21928c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
21938c2ecf20Sopenharmony_ci	int i;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) ||
21968c2ecf20Sopenharmony_ci	    ((ec->rx_coalesce_usecs > 3) &&
21978c2ecf20Sopenharmony_ci	     (ec->rx_coalesce_usecs < IGB_MIN_ITR_USECS)) ||
21988c2ecf20Sopenharmony_ci	    (ec->rx_coalesce_usecs == 2))
21998c2ecf20Sopenharmony_ci		return -EINVAL;
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	if ((ec->tx_coalesce_usecs > IGB_MAX_ITR_USECS) ||
22028c2ecf20Sopenharmony_ci	    ((ec->tx_coalesce_usecs > 3) &&
22038c2ecf20Sopenharmony_ci	     (ec->tx_coalesce_usecs < IGB_MIN_ITR_USECS)) ||
22048c2ecf20Sopenharmony_ci	    (ec->tx_coalesce_usecs == 2))
22058c2ecf20Sopenharmony_ci		return -EINVAL;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	if ((adapter->flags & IGB_FLAG_QUEUE_PAIRS) && ec->tx_coalesce_usecs)
22088c2ecf20Sopenharmony_ci		return -EINVAL;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	/* If ITR is disabled, disable DMAC */
22118c2ecf20Sopenharmony_ci	if (ec->rx_coalesce_usecs == 0) {
22128c2ecf20Sopenharmony_ci		if (adapter->flags & IGB_FLAG_DMAC)
22138c2ecf20Sopenharmony_ci			adapter->flags &= ~IGB_FLAG_DMAC;
22148c2ecf20Sopenharmony_ci	}
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	/* convert to rate of irq's per second */
22178c2ecf20Sopenharmony_ci	if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3)
22188c2ecf20Sopenharmony_ci		adapter->rx_itr_setting = ec->rx_coalesce_usecs;
22198c2ecf20Sopenharmony_ci	else
22208c2ecf20Sopenharmony_ci		adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2;
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	/* convert to rate of irq's per second */
22238c2ecf20Sopenharmony_ci	if (adapter->flags & IGB_FLAG_QUEUE_PAIRS)
22248c2ecf20Sopenharmony_ci		adapter->tx_itr_setting = adapter->rx_itr_setting;
22258c2ecf20Sopenharmony_ci	else if (ec->tx_coalesce_usecs && ec->tx_coalesce_usecs <= 3)
22268c2ecf20Sopenharmony_ci		adapter->tx_itr_setting = ec->tx_coalesce_usecs;
22278c2ecf20Sopenharmony_ci	else
22288c2ecf20Sopenharmony_ci		adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2;
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->num_q_vectors; i++) {
22318c2ecf20Sopenharmony_ci		struct igb_q_vector *q_vector = adapter->q_vector[i];
22328c2ecf20Sopenharmony_ci		q_vector->tx.work_limit = adapter->tx_work_limit;
22338c2ecf20Sopenharmony_ci		if (q_vector->rx.ring)
22348c2ecf20Sopenharmony_ci			q_vector->itr_val = adapter->rx_itr_setting;
22358c2ecf20Sopenharmony_ci		else
22368c2ecf20Sopenharmony_ci			q_vector->itr_val = adapter->tx_itr_setting;
22378c2ecf20Sopenharmony_ci		if (q_vector->itr_val && q_vector->itr_val <= 3)
22388c2ecf20Sopenharmony_ci			q_vector->itr_val = IGB_START_ITR;
22398c2ecf20Sopenharmony_ci		q_vector->set_itr = 1;
22408c2ecf20Sopenharmony_ci	}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	return 0;
22438c2ecf20Sopenharmony_ci}
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_cistatic int igb_get_coalesce(struct net_device *netdev,
22468c2ecf20Sopenharmony_ci			    struct ethtool_coalesce *ec)
22478c2ecf20Sopenharmony_ci{
22488c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	if (adapter->rx_itr_setting <= 3)
22518c2ecf20Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->rx_itr_setting;
22528c2ecf20Sopenharmony_ci	else
22538c2ecf20Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2;
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS)) {
22568c2ecf20Sopenharmony_ci		if (adapter->tx_itr_setting <= 3)
22578c2ecf20Sopenharmony_ci			ec->tx_coalesce_usecs = adapter->tx_itr_setting;
22588c2ecf20Sopenharmony_ci		else
22598c2ecf20Sopenharmony_ci			ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2;
22608c2ecf20Sopenharmony_ci	}
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci	return 0;
22638c2ecf20Sopenharmony_ci}
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_cistatic int igb_nway_reset(struct net_device *netdev)
22668c2ecf20Sopenharmony_ci{
22678c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
22688c2ecf20Sopenharmony_ci	if (netif_running(netdev))
22698c2ecf20Sopenharmony_ci		igb_reinit_locked(adapter);
22708c2ecf20Sopenharmony_ci	return 0;
22718c2ecf20Sopenharmony_ci}
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_cistatic int igb_get_sset_count(struct net_device *netdev, int sset)
22748c2ecf20Sopenharmony_ci{
22758c2ecf20Sopenharmony_ci	switch (sset) {
22768c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
22778c2ecf20Sopenharmony_ci		return IGB_STATS_LEN;
22788c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
22798c2ecf20Sopenharmony_ci		return IGB_TEST_LEN;
22808c2ecf20Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
22818c2ecf20Sopenharmony_ci		return IGB_PRIV_FLAGS_STR_LEN;
22828c2ecf20Sopenharmony_ci	default:
22838c2ecf20Sopenharmony_ci		return -ENOTSUPP;
22848c2ecf20Sopenharmony_ci	}
22858c2ecf20Sopenharmony_ci}
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_cistatic void igb_get_ethtool_stats(struct net_device *netdev,
22888c2ecf20Sopenharmony_ci				  struct ethtool_stats *stats, u64 *data)
22898c2ecf20Sopenharmony_ci{
22908c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
22918c2ecf20Sopenharmony_ci	struct rtnl_link_stats64 *net_stats = &adapter->stats64;
22928c2ecf20Sopenharmony_ci	unsigned int start;
22938c2ecf20Sopenharmony_ci	struct igb_ring *ring;
22948c2ecf20Sopenharmony_ci	int i, j;
22958c2ecf20Sopenharmony_ci	char *p;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	spin_lock(&adapter->stats64_lock);
22988c2ecf20Sopenharmony_ci	igb_update_stats(adapter);
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci	for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
23018c2ecf20Sopenharmony_ci		p = (char *)adapter + igb_gstrings_stats[i].stat_offset;
23028c2ecf20Sopenharmony_ci		data[i] = (igb_gstrings_stats[i].sizeof_stat ==
23038c2ecf20Sopenharmony_ci			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
23048c2ecf20Sopenharmony_ci	}
23058c2ecf20Sopenharmony_ci	for (j = 0; j < IGB_NETDEV_STATS_LEN; j++, i++) {
23068c2ecf20Sopenharmony_ci		p = (char *)net_stats + igb_gstrings_net_stats[j].stat_offset;
23078c2ecf20Sopenharmony_ci		data[i] = (igb_gstrings_net_stats[j].sizeof_stat ==
23088c2ecf20Sopenharmony_ci			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
23098c2ecf20Sopenharmony_ci	}
23108c2ecf20Sopenharmony_ci	for (j = 0; j < adapter->num_tx_queues; j++) {
23118c2ecf20Sopenharmony_ci		u64	restart2;
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci		ring = adapter->tx_ring[j];
23148c2ecf20Sopenharmony_ci		do {
23158c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
23168c2ecf20Sopenharmony_ci			data[i]   = ring->tx_stats.packets;
23178c2ecf20Sopenharmony_ci			data[i+1] = ring->tx_stats.bytes;
23188c2ecf20Sopenharmony_ci			data[i+2] = ring->tx_stats.restart_queue;
23198c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
23208c2ecf20Sopenharmony_ci		do {
23218c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&ring->tx_syncp2);
23228c2ecf20Sopenharmony_ci			restart2  = ring->tx_stats.restart_queue2;
23238c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start));
23248c2ecf20Sopenharmony_ci		data[i+2] += restart2;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci		i += IGB_TX_QUEUE_STATS_LEN;
23278c2ecf20Sopenharmony_ci	}
23288c2ecf20Sopenharmony_ci	for (j = 0; j < adapter->num_rx_queues; j++) {
23298c2ecf20Sopenharmony_ci		ring = adapter->rx_ring[j];
23308c2ecf20Sopenharmony_ci		do {
23318c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
23328c2ecf20Sopenharmony_ci			data[i]   = ring->rx_stats.packets;
23338c2ecf20Sopenharmony_ci			data[i+1] = ring->rx_stats.bytes;
23348c2ecf20Sopenharmony_ci			data[i+2] = ring->rx_stats.drops;
23358c2ecf20Sopenharmony_ci			data[i+3] = ring->rx_stats.csum_err;
23368c2ecf20Sopenharmony_ci			data[i+4] = ring->rx_stats.alloc_failed;
23378c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
23388c2ecf20Sopenharmony_ci		i += IGB_RX_QUEUE_STATS_LEN;
23398c2ecf20Sopenharmony_ci	}
23408c2ecf20Sopenharmony_ci	spin_unlock(&adapter->stats64_lock);
23418c2ecf20Sopenharmony_ci}
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_cistatic void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
23448c2ecf20Sopenharmony_ci{
23458c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
23468c2ecf20Sopenharmony_ci	u8 *p = data;
23478c2ecf20Sopenharmony_ci	int i;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	switch (stringset) {
23508c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
23518c2ecf20Sopenharmony_ci		memcpy(data, *igb_gstrings_test,
23528c2ecf20Sopenharmony_ci			IGB_TEST_LEN*ETH_GSTRING_LEN);
23538c2ecf20Sopenharmony_ci		break;
23548c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
23558c2ecf20Sopenharmony_ci		for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
23568c2ecf20Sopenharmony_ci			memcpy(p, igb_gstrings_stats[i].stat_string,
23578c2ecf20Sopenharmony_ci			       ETH_GSTRING_LEN);
23588c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23598c2ecf20Sopenharmony_ci		}
23608c2ecf20Sopenharmony_ci		for (i = 0; i < IGB_NETDEV_STATS_LEN; i++) {
23618c2ecf20Sopenharmony_ci			memcpy(p, igb_gstrings_net_stats[i].stat_string,
23628c2ecf20Sopenharmony_ci			       ETH_GSTRING_LEN);
23638c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23648c2ecf20Sopenharmony_ci		}
23658c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
23668c2ecf20Sopenharmony_ci			sprintf(p, "tx_queue_%u_packets", i);
23678c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23688c2ecf20Sopenharmony_ci			sprintf(p, "tx_queue_%u_bytes", i);
23698c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23708c2ecf20Sopenharmony_ci			sprintf(p, "tx_queue_%u_restart", i);
23718c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23728c2ecf20Sopenharmony_ci		}
23738c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
23748c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_packets", i);
23758c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23768c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_bytes", i);
23778c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23788c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_drops", i);
23798c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23808c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_csum_err", i);
23818c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23828c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_alloc_failed", i);
23838c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
23848c2ecf20Sopenharmony_ci		}
23858c2ecf20Sopenharmony_ci		/* BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */
23868c2ecf20Sopenharmony_ci		break;
23878c2ecf20Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
23888c2ecf20Sopenharmony_ci		memcpy(data, igb_priv_flags_strings,
23898c2ecf20Sopenharmony_ci		       IGB_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN);
23908c2ecf20Sopenharmony_ci		break;
23918c2ecf20Sopenharmony_ci	}
23928c2ecf20Sopenharmony_ci}
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_cistatic int igb_get_ts_info(struct net_device *dev,
23958c2ecf20Sopenharmony_ci			   struct ethtool_ts_info *info)
23968c2ecf20Sopenharmony_ci{
23978c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(dev);
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	if (adapter->ptp_clock)
24008c2ecf20Sopenharmony_ci		info->phc_index = ptp_clock_index(adapter->ptp_clock);
24018c2ecf20Sopenharmony_ci	else
24028c2ecf20Sopenharmony_ci		info->phc_index = -1;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	switch (adapter->hw.mac.type) {
24058c2ecf20Sopenharmony_ci	case e1000_82575:
24068c2ecf20Sopenharmony_ci		info->so_timestamping =
24078c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_TX_SOFTWARE |
24088c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_RX_SOFTWARE |
24098c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_SOFTWARE;
24108c2ecf20Sopenharmony_ci		return 0;
24118c2ecf20Sopenharmony_ci	case e1000_82576:
24128c2ecf20Sopenharmony_ci	case e1000_82580:
24138c2ecf20Sopenharmony_ci	case e1000_i350:
24148c2ecf20Sopenharmony_ci	case e1000_i354:
24158c2ecf20Sopenharmony_ci	case e1000_i210:
24168c2ecf20Sopenharmony_ci	case e1000_i211:
24178c2ecf20Sopenharmony_ci		info->so_timestamping =
24188c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_TX_SOFTWARE |
24198c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_RX_SOFTWARE |
24208c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_SOFTWARE |
24218c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_TX_HARDWARE |
24228c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_RX_HARDWARE |
24238c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_RAW_HARDWARE;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci		info->tx_types =
24268c2ecf20Sopenharmony_ci			BIT(HWTSTAMP_TX_OFF) |
24278c2ecf20Sopenharmony_ci			BIT(HWTSTAMP_TX_ON);
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci		info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci		/* 82576 does not support timestamping all packets. */
24328c2ecf20Sopenharmony_ci		if (adapter->hw.mac.type >= e1000_82580)
24338c2ecf20Sopenharmony_ci			info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL);
24348c2ecf20Sopenharmony_ci		else
24358c2ecf20Sopenharmony_ci			info->rx_filters |=
24368c2ecf20Sopenharmony_ci				BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
24378c2ecf20Sopenharmony_ci				BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
24388c2ecf20Sopenharmony_ci				BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci		return 0;
24418c2ecf20Sopenharmony_ci	default:
24428c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci}
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
24478c2ecf20Sopenharmony_cistatic int igb_get_ethtool_nfc_entry(struct igb_adapter *adapter,
24488c2ecf20Sopenharmony_ci				     struct ethtool_rxnfc *cmd)
24498c2ecf20Sopenharmony_ci{
24508c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp = &cmd->fs;
24518c2ecf20Sopenharmony_ci	struct igb_nfc_filter *rule = NULL;
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	/* report total rule count */
24548c2ecf20Sopenharmony_ci	cmd->data = IGB_MAX_RXNFC_FILTERS;
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
24578c2ecf20Sopenharmony_ci		if (fsp->location <= rule->sw_idx)
24588c2ecf20Sopenharmony_ci			break;
24598c2ecf20Sopenharmony_ci	}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	if (!rule || fsp->location != rule->sw_idx)
24628c2ecf20Sopenharmony_ci		return -EINVAL;
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci	if (rule->filter.match_flags) {
24658c2ecf20Sopenharmony_ci		fsp->flow_type = ETHER_FLOW;
24668c2ecf20Sopenharmony_ci		fsp->ring_cookie = rule->action;
24678c2ecf20Sopenharmony_ci		if (rule->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE) {
24688c2ecf20Sopenharmony_ci			fsp->h_u.ether_spec.h_proto = rule->filter.etype;
24698c2ecf20Sopenharmony_ci			fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK;
24708c2ecf20Sopenharmony_ci		}
24718c2ecf20Sopenharmony_ci		if (rule->filter.match_flags & IGB_FILTER_FLAG_VLAN_TCI) {
24728c2ecf20Sopenharmony_ci			fsp->flow_type |= FLOW_EXT;
24738c2ecf20Sopenharmony_ci			fsp->h_ext.vlan_tci = rule->filter.vlan_tci;
24748c2ecf20Sopenharmony_ci			fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK);
24758c2ecf20Sopenharmony_ci		}
24768c2ecf20Sopenharmony_ci		if (rule->filter.match_flags & IGB_FILTER_FLAG_DST_MAC_ADDR) {
24778c2ecf20Sopenharmony_ci			ether_addr_copy(fsp->h_u.ether_spec.h_dest,
24788c2ecf20Sopenharmony_ci					rule->filter.dst_addr);
24798c2ecf20Sopenharmony_ci			/* As we only support matching by the full
24808c2ecf20Sopenharmony_ci			 * mask, return the mask to userspace
24818c2ecf20Sopenharmony_ci			 */
24828c2ecf20Sopenharmony_ci			eth_broadcast_addr(fsp->m_u.ether_spec.h_dest);
24838c2ecf20Sopenharmony_ci		}
24848c2ecf20Sopenharmony_ci		if (rule->filter.match_flags & IGB_FILTER_FLAG_SRC_MAC_ADDR) {
24858c2ecf20Sopenharmony_ci			ether_addr_copy(fsp->h_u.ether_spec.h_source,
24868c2ecf20Sopenharmony_ci					rule->filter.src_addr);
24878c2ecf20Sopenharmony_ci			/* As we only support matching by the full
24888c2ecf20Sopenharmony_ci			 * mask, return the mask to userspace
24898c2ecf20Sopenharmony_ci			 */
24908c2ecf20Sopenharmony_ci			eth_broadcast_addr(fsp->m_u.ether_spec.h_source);
24918c2ecf20Sopenharmony_ci		}
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci		return 0;
24948c2ecf20Sopenharmony_ci	}
24958c2ecf20Sopenharmony_ci	return -EINVAL;
24968c2ecf20Sopenharmony_ci}
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_cistatic int igb_get_ethtool_nfc_all(struct igb_adapter *adapter,
24998c2ecf20Sopenharmony_ci				   struct ethtool_rxnfc *cmd,
25008c2ecf20Sopenharmony_ci				   u32 *rule_locs)
25018c2ecf20Sopenharmony_ci{
25028c2ecf20Sopenharmony_ci	struct igb_nfc_filter *rule;
25038c2ecf20Sopenharmony_ci	int cnt = 0;
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	/* report total rule count */
25068c2ecf20Sopenharmony_ci	cmd->data = IGB_MAX_RXNFC_FILTERS;
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
25098c2ecf20Sopenharmony_ci		if (cnt == cmd->rule_cnt)
25108c2ecf20Sopenharmony_ci			return -EMSGSIZE;
25118c2ecf20Sopenharmony_ci		rule_locs[cnt] = rule->sw_idx;
25128c2ecf20Sopenharmony_ci		cnt++;
25138c2ecf20Sopenharmony_ci	}
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	cmd->rule_cnt = cnt;
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	return 0;
25188c2ecf20Sopenharmony_ci}
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_cistatic int igb_get_rss_hash_opts(struct igb_adapter *adapter,
25218c2ecf20Sopenharmony_ci				 struct ethtool_rxnfc *cmd)
25228c2ecf20Sopenharmony_ci{
25238c2ecf20Sopenharmony_ci	cmd->data = 0;
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci	/* Report default options for RSS on igb */
25268c2ecf20Sopenharmony_ci	switch (cmd->flow_type) {
25278c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
25288c2ecf20Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
25298c2ecf20Sopenharmony_ci		fallthrough;
25308c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
25318c2ecf20Sopenharmony_ci		if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV4_UDP)
25328c2ecf20Sopenharmony_ci			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
25338c2ecf20Sopenharmony_ci		fallthrough;
25348c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
25358c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
25368c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
25378c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
25388c2ecf20Sopenharmony_ci	case IPV4_FLOW:
25398c2ecf20Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
25408c2ecf20Sopenharmony_ci		break;
25418c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
25428c2ecf20Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
25438c2ecf20Sopenharmony_ci		fallthrough;
25448c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
25458c2ecf20Sopenharmony_ci		if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV6_UDP)
25468c2ecf20Sopenharmony_ci			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
25478c2ecf20Sopenharmony_ci		fallthrough;
25488c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
25498c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
25508c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
25518c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
25528c2ecf20Sopenharmony_ci	case IPV6_FLOW:
25538c2ecf20Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
25548c2ecf20Sopenharmony_ci		break;
25558c2ecf20Sopenharmony_ci	default:
25568c2ecf20Sopenharmony_ci		return -EINVAL;
25578c2ecf20Sopenharmony_ci	}
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci	return 0;
25608c2ecf20Sopenharmony_ci}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_cistatic int igb_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
25638c2ecf20Sopenharmony_ci			 u32 *rule_locs)
25648c2ecf20Sopenharmony_ci{
25658c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(dev);
25668c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
25698c2ecf20Sopenharmony_ci	case ETHTOOL_GRXRINGS:
25708c2ecf20Sopenharmony_ci		cmd->data = adapter->num_rx_queues;
25718c2ecf20Sopenharmony_ci		ret = 0;
25728c2ecf20Sopenharmony_ci		break;
25738c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
25748c2ecf20Sopenharmony_ci		cmd->rule_cnt = adapter->nfc_filter_count;
25758c2ecf20Sopenharmony_ci		ret = 0;
25768c2ecf20Sopenharmony_ci		break;
25778c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
25788c2ecf20Sopenharmony_ci		ret = igb_get_ethtool_nfc_entry(adapter, cmd);
25798c2ecf20Sopenharmony_ci		break;
25808c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
25818c2ecf20Sopenharmony_ci		ret = igb_get_ethtool_nfc_all(adapter, cmd, rule_locs);
25828c2ecf20Sopenharmony_ci		break;
25838c2ecf20Sopenharmony_ci	case ETHTOOL_GRXFH:
25848c2ecf20Sopenharmony_ci		ret = igb_get_rss_hash_opts(adapter, cmd);
25858c2ecf20Sopenharmony_ci		break;
25868c2ecf20Sopenharmony_ci	default:
25878c2ecf20Sopenharmony_ci		break;
25888c2ecf20Sopenharmony_ci	}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci	return ret;
25918c2ecf20Sopenharmony_ci}
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci#define UDP_RSS_FLAGS (IGB_FLAG_RSS_FIELD_IPV4_UDP | \
25948c2ecf20Sopenharmony_ci		       IGB_FLAG_RSS_FIELD_IPV6_UDP)
25958c2ecf20Sopenharmony_cistatic int igb_set_rss_hash_opt(struct igb_adapter *adapter,
25968c2ecf20Sopenharmony_ci				struct ethtool_rxnfc *nfc)
25978c2ecf20Sopenharmony_ci{
25988c2ecf20Sopenharmony_ci	u32 flags = adapter->flags;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	/* RSS does not support anything other than hashing
26018c2ecf20Sopenharmony_ci	 * to queues on src and dst IPs and ports
26028c2ecf20Sopenharmony_ci	 */
26038c2ecf20Sopenharmony_ci	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
26048c2ecf20Sopenharmony_ci			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
26058c2ecf20Sopenharmony_ci		return -EINVAL;
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	switch (nfc->flow_type) {
26088c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
26098c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
26108c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
26118c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST) ||
26128c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_L4_B_0_1) ||
26138c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_L4_B_2_3))
26148c2ecf20Sopenharmony_ci			return -EINVAL;
26158c2ecf20Sopenharmony_ci		break;
26168c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
26178c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
26188c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST))
26198c2ecf20Sopenharmony_ci			return -EINVAL;
26208c2ecf20Sopenharmony_ci		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
26218c2ecf20Sopenharmony_ci		case 0:
26228c2ecf20Sopenharmony_ci			flags &= ~IGB_FLAG_RSS_FIELD_IPV4_UDP;
26238c2ecf20Sopenharmony_ci			break;
26248c2ecf20Sopenharmony_ci		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
26258c2ecf20Sopenharmony_ci			flags |= IGB_FLAG_RSS_FIELD_IPV4_UDP;
26268c2ecf20Sopenharmony_ci			break;
26278c2ecf20Sopenharmony_ci		default:
26288c2ecf20Sopenharmony_ci			return -EINVAL;
26298c2ecf20Sopenharmony_ci		}
26308c2ecf20Sopenharmony_ci		break;
26318c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
26328c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
26338c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST))
26348c2ecf20Sopenharmony_ci			return -EINVAL;
26358c2ecf20Sopenharmony_ci		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
26368c2ecf20Sopenharmony_ci		case 0:
26378c2ecf20Sopenharmony_ci			flags &= ~IGB_FLAG_RSS_FIELD_IPV6_UDP;
26388c2ecf20Sopenharmony_ci			break;
26398c2ecf20Sopenharmony_ci		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
26408c2ecf20Sopenharmony_ci			flags |= IGB_FLAG_RSS_FIELD_IPV6_UDP;
26418c2ecf20Sopenharmony_ci			break;
26428c2ecf20Sopenharmony_ci		default:
26438c2ecf20Sopenharmony_ci			return -EINVAL;
26448c2ecf20Sopenharmony_ci		}
26458c2ecf20Sopenharmony_ci		break;
26468c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
26478c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
26488c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
26498c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
26508c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
26518c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
26528c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
26538c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
26548c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
26558c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST) ||
26568c2ecf20Sopenharmony_ci		    (nfc->data & RXH_L4_B_0_1) ||
26578c2ecf20Sopenharmony_ci		    (nfc->data & RXH_L4_B_2_3))
26588c2ecf20Sopenharmony_ci			return -EINVAL;
26598c2ecf20Sopenharmony_ci		break;
26608c2ecf20Sopenharmony_ci	default:
26618c2ecf20Sopenharmony_ci		return -EINVAL;
26628c2ecf20Sopenharmony_ci	}
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci	/* if we changed something we need to update flags */
26658c2ecf20Sopenharmony_ci	if (flags != adapter->flags) {
26668c2ecf20Sopenharmony_ci		struct e1000_hw *hw = &adapter->hw;
26678c2ecf20Sopenharmony_ci		u32 mrqc = rd32(E1000_MRQC);
26688c2ecf20Sopenharmony_ci
26698c2ecf20Sopenharmony_ci		if ((flags & UDP_RSS_FLAGS) &&
26708c2ecf20Sopenharmony_ci		    !(adapter->flags & UDP_RSS_FLAGS))
26718c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
26728c2ecf20Sopenharmony_ci				"enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci		adapter->flags = flags;
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci		/* Perform hash on these packet types */
26778c2ecf20Sopenharmony_ci		mrqc |= E1000_MRQC_RSS_FIELD_IPV4 |
26788c2ecf20Sopenharmony_ci			E1000_MRQC_RSS_FIELD_IPV4_TCP |
26798c2ecf20Sopenharmony_ci			E1000_MRQC_RSS_FIELD_IPV6 |
26808c2ecf20Sopenharmony_ci			E1000_MRQC_RSS_FIELD_IPV6_TCP;
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci		mrqc &= ~(E1000_MRQC_RSS_FIELD_IPV4_UDP |
26838c2ecf20Sopenharmony_ci			  E1000_MRQC_RSS_FIELD_IPV6_UDP);
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci		if (flags & IGB_FLAG_RSS_FIELD_IPV4_UDP)
26868c2ecf20Sopenharmony_ci			mrqc |= E1000_MRQC_RSS_FIELD_IPV4_UDP;
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci		if (flags & IGB_FLAG_RSS_FIELD_IPV6_UDP)
26898c2ecf20Sopenharmony_ci			mrqc |= E1000_MRQC_RSS_FIELD_IPV6_UDP;
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci		wr32(E1000_MRQC, mrqc);
26928c2ecf20Sopenharmony_ci	}
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	return 0;
26958c2ecf20Sopenharmony_ci}
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_cistatic int igb_rxnfc_write_etype_filter(struct igb_adapter *adapter,
26988c2ecf20Sopenharmony_ci					struct igb_nfc_filter *input)
26998c2ecf20Sopenharmony_ci{
27008c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
27018c2ecf20Sopenharmony_ci	u8 i;
27028c2ecf20Sopenharmony_ci	u32 etqf;
27038c2ecf20Sopenharmony_ci	u16 etype;
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci	/* find an empty etype filter register */
27068c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_ETYPE_FILTER; ++i) {
27078c2ecf20Sopenharmony_ci		if (!adapter->etype_bitmap[i])
27088c2ecf20Sopenharmony_ci			break;
27098c2ecf20Sopenharmony_ci	}
27108c2ecf20Sopenharmony_ci	if (i == MAX_ETYPE_FILTER) {
27118c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "ethtool -N: etype filters are all used.\n");
27128c2ecf20Sopenharmony_ci		return -EINVAL;
27138c2ecf20Sopenharmony_ci	}
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	adapter->etype_bitmap[i] = true;
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci	etqf = rd32(E1000_ETQF(i));
27188c2ecf20Sopenharmony_ci	etype = ntohs(input->filter.etype & ETHER_TYPE_FULL_MASK);
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_ci	etqf |= E1000_ETQF_FILTER_ENABLE;
27218c2ecf20Sopenharmony_ci	etqf &= ~E1000_ETQF_ETYPE_MASK;
27228c2ecf20Sopenharmony_ci	etqf |= (etype & E1000_ETQF_ETYPE_MASK);
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	etqf &= ~E1000_ETQF_QUEUE_MASK;
27258c2ecf20Sopenharmony_ci	etqf |= ((input->action << E1000_ETQF_QUEUE_SHIFT)
27268c2ecf20Sopenharmony_ci		& E1000_ETQF_QUEUE_MASK);
27278c2ecf20Sopenharmony_ci	etqf |= E1000_ETQF_QUEUE_ENABLE;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	wr32(E1000_ETQF(i), etqf);
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	input->etype_reg_index = i;
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	return 0;
27348c2ecf20Sopenharmony_ci}
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_cistatic int igb_rxnfc_write_vlan_prio_filter(struct igb_adapter *adapter,
27378c2ecf20Sopenharmony_ci					    struct igb_nfc_filter *input)
27388c2ecf20Sopenharmony_ci{
27398c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
27408c2ecf20Sopenharmony_ci	u8 vlan_priority;
27418c2ecf20Sopenharmony_ci	u16 queue_index;
27428c2ecf20Sopenharmony_ci	u32 vlapqf;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	vlapqf = rd32(E1000_VLAPQF);
27458c2ecf20Sopenharmony_ci	vlan_priority = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK)
27468c2ecf20Sopenharmony_ci				>> VLAN_PRIO_SHIFT;
27478c2ecf20Sopenharmony_ci	queue_index = (vlapqf >> (vlan_priority * 4)) & E1000_VLAPQF_QUEUE_MASK;
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	/* check whether this vlan prio is already set */
27508c2ecf20Sopenharmony_ci	if ((vlapqf & E1000_VLAPQF_P_VALID(vlan_priority)) &&
27518c2ecf20Sopenharmony_ci	    (queue_index != input->action)) {
27528c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "ethtool rxnfc set vlan prio filter failed.\n");
27538c2ecf20Sopenharmony_ci		return -EEXIST;
27548c2ecf20Sopenharmony_ci	}
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	vlapqf |= E1000_VLAPQF_P_VALID(vlan_priority);
27578c2ecf20Sopenharmony_ci	vlapqf |= E1000_VLAPQF_QUEUE_SEL(vlan_priority, input->action);
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	wr32(E1000_VLAPQF, vlapqf);
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	return 0;
27628c2ecf20Sopenharmony_ci}
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ciint igb_add_filter(struct igb_adapter *adapter, struct igb_nfc_filter *input)
27658c2ecf20Sopenharmony_ci{
27668c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
27678c2ecf20Sopenharmony_ci	int err = -EINVAL;
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci	if (hw->mac.type == e1000_i210 &&
27708c2ecf20Sopenharmony_ci	    !(input->filter.match_flags & ~IGB_FILTER_FLAG_SRC_MAC_ADDR)) {
27718c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
27728c2ecf20Sopenharmony_ci			"i210 doesn't support flow classification rules specifying only source addresses.\n");
27738c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
27748c2ecf20Sopenharmony_ci	}
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE) {
27778c2ecf20Sopenharmony_ci		err = igb_rxnfc_write_etype_filter(adapter, input);
27788c2ecf20Sopenharmony_ci		if (err)
27798c2ecf20Sopenharmony_ci			return err;
27808c2ecf20Sopenharmony_ci	}
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_DST_MAC_ADDR) {
27838c2ecf20Sopenharmony_ci		err = igb_add_mac_steering_filter(adapter,
27848c2ecf20Sopenharmony_ci						  input->filter.dst_addr,
27858c2ecf20Sopenharmony_ci						  input->action, 0);
27868c2ecf20Sopenharmony_ci		err = min_t(int, err, 0);
27878c2ecf20Sopenharmony_ci		if (err)
27888c2ecf20Sopenharmony_ci			return err;
27898c2ecf20Sopenharmony_ci	}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_SRC_MAC_ADDR) {
27928c2ecf20Sopenharmony_ci		err = igb_add_mac_steering_filter(adapter,
27938c2ecf20Sopenharmony_ci						  input->filter.src_addr,
27948c2ecf20Sopenharmony_ci						  input->action,
27958c2ecf20Sopenharmony_ci						  IGB_MAC_STATE_SRC_ADDR);
27968c2ecf20Sopenharmony_ci		err = min_t(int, err, 0);
27978c2ecf20Sopenharmony_ci		if (err)
27988c2ecf20Sopenharmony_ci			return err;
27998c2ecf20Sopenharmony_ci	}
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_VLAN_TCI)
28028c2ecf20Sopenharmony_ci		err = igb_rxnfc_write_vlan_prio_filter(adapter, input);
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ci	return err;
28058c2ecf20Sopenharmony_ci}
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_cistatic void igb_clear_etype_filter_regs(struct igb_adapter *adapter,
28088c2ecf20Sopenharmony_ci					u16 reg_index)
28098c2ecf20Sopenharmony_ci{
28108c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
28118c2ecf20Sopenharmony_ci	u32 etqf = rd32(E1000_ETQF(reg_index));
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	etqf &= ~E1000_ETQF_QUEUE_ENABLE;
28148c2ecf20Sopenharmony_ci	etqf &= ~E1000_ETQF_QUEUE_MASK;
28158c2ecf20Sopenharmony_ci	etqf &= ~E1000_ETQF_FILTER_ENABLE;
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	wr32(E1000_ETQF(reg_index), etqf);
28188c2ecf20Sopenharmony_ci
28198c2ecf20Sopenharmony_ci	adapter->etype_bitmap[reg_index] = false;
28208c2ecf20Sopenharmony_ci}
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_cistatic void igb_clear_vlan_prio_filter(struct igb_adapter *adapter,
28238c2ecf20Sopenharmony_ci				       u16 vlan_tci)
28248c2ecf20Sopenharmony_ci{
28258c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
28268c2ecf20Sopenharmony_ci	u8 vlan_priority;
28278c2ecf20Sopenharmony_ci	u32 vlapqf;
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	vlan_priority = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
28308c2ecf20Sopenharmony_ci
28318c2ecf20Sopenharmony_ci	vlapqf = rd32(E1000_VLAPQF);
28328c2ecf20Sopenharmony_ci	vlapqf &= ~E1000_VLAPQF_P_VALID(vlan_priority);
28338c2ecf20Sopenharmony_ci	vlapqf &= ~E1000_VLAPQF_QUEUE_SEL(vlan_priority,
28348c2ecf20Sopenharmony_ci						E1000_VLAPQF_QUEUE_MASK);
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	wr32(E1000_VLAPQF, vlapqf);
28378c2ecf20Sopenharmony_ci}
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ciint igb_erase_filter(struct igb_adapter *adapter, struct igb_nfc_filter *input)
28408c2ecf20Sopenharmony_ci{
28418c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE)
28428c2ecf20Sopenharmony_ci		igb_clear_etype_filter_regs(adapter,
28438c2ecf20Sopenharmony_ci					    input->etype_reg_index);
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_VLAN_TCI)
28468c2ecf20Sopenharmony_ci		igb_clear_vlan_prio_filter(adapter,
28478c2ecf20Sopenharmony_ci					   ntohs(input->filter.vlan_tci));
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_SRC_MAC_ADDR)
28508c2ecf20Sopenharmony_ci		igb_del_mac_steering_filter(adapter, input->filter.src_addr,
28518c2ecf20Sopenharmony_ci					    input->action,
28528c2ecf20Sopenharmony_ci					    IGB_MAC_STATE_SRC_ADDR);
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	if (input->filter.match_flags & IGB_FILTER_FLAG_DST_MAC_ADDR)
28558c2ecf20Sopenharmony_ci		igb_del_mac_steering_filter(adapter, input->filter.dst_addr,
28568c2ecf20Sopenharmony_ci					    input->action, 0);
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci	return 0;
28598c2ecf20Sopenharmony_ci}
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_cistatic int igb_update_ethtool_nfc_entry(struct igb_adapter *adapter,
28628c2ecf20Sopenharmony_ci					struct igb_nfc_filter *input,
28638c2ecf20Sopenharmony_ci					u16 sw_idx)
28648c2ecf20Sopenharmony_ci{
28658c2ecf20Sopenharmony_ci	struct igb_nfc_filter *rule, *parent;
28668c2ecf20Sopenharmony_ci	int err = -EINVAL;
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci	parent = NULL;
28698c2ecf20Sopenharmony_ci	rule = NULL;
28708c2ecf20Sopenharmony_ci
28718c2ecf20Sopenharmony_ci	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
28728c2ecf20Sopenharmony_ci		/* hash found, or no matching entry */
28738c2ecf20Sopenharmony_ci		if (rule->sw_idx >= sw_idx)
28748c2ecf20Sopenharmony_ci			break;
28758c2ecf20Sopenharmony_ci		parent = rule;
28768c2ecf20Sopenharmony_ci	}
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci	/* if there is an old rule occupying our place remove it */
28798c2ecf20Sopenharmony_ci	if (rule && (rule->sw_idx == sw_idx)) {
28808c2ecf20Sopenharmony_ci		if (!input)
28818c2ecf20Sopenharmony_ci			err = igb_erase_filter(adapter, rule);
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci		hlist_del(&rule->nfc_node);
28848c2ecf20Sopenharmony_ci		kfree(rule);
28858c2ecf20Sopenharmony_ci		adapter->nfc_filter_count--;
28868c2ecf20Sopenharmony_ci	}
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci	/* If no input this was a delete, err should be 0 if a rule was
28898c2ecf20Sopenharmony_ci	 * successfully found and removed from the list else -EINVAL
28908c2ecf20Sopenharmony_ci	 */
28918c2ecf20Sopenharmony_ci	if (!input)
28928c2ecf20Sopenharmony_ci		return err;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci	/* initialize node */
28958c2ecf20Sopenharmony_ci	INIT_HLIST_NODE(&input->nfc_node);
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci	/* add filter to the list */
28988c2ecf20Sopenharmony_ci	if (parent)
28998c2ecf20Sopenharmony_ci		hlist_add_behind(&input->nfc_node, &parent->nfc_node);
29008c2ecf20Sopenharmony_ci	else
29018c2ecf20Sopenharmony_ci		hlist_add_head(&input->nfc_node, &adapter->nfc_filter_list);
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	/* update counts */
29048c2ecf20Sopenharmony_ci	adapter->nfc_filter_count++;
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci	return 0;
29078c2ecf20Sopenharmony_ci}
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_cistatic int igb_add_ethtool_nfc_entry(struct igb_adapter *adapter,
29108c2ecf20Sopenharmony_ci				     struct ethtool_rxnfc *cmd)
29118c2ecf20Sopenharmony_ci{
29128c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
29138c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp =
29148c2ecf20Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
29158c2ecf20Sopenharmony_ci	struct igb_nfc_filter *input, *rule;
29168c2ecf20Sopenharmony_ci	int err = 0;
29178c2ecf20Sopenharmony_ci
29188c2ecf20Sopenharmony_ci	if (!(netdev->hw_features & NETIF_F_NTUPLE))
29198c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci	/* Don't allow programming if the action is a queue greater than
29228c2ecf20Sopenharmony_ci	 * the number of online Rx queues.
29238c2ecf20Sopenharmony_ci	 */
29248c2ecf20Sopenharmony_ci	if ((fsp->ring_cookie == RX_CLS_FLOW_DISC) ||
29258c2ecf20Sopenharmony_ci	    (fsp->ring_cookie >= adapter->num_rx_queues)) {
29268c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "ethtool -N: The specified action is invalid\n");
29278c2ecf20Sopenharmony_ci		return -EINVAL;
29288c2ecf20Sopenharmony_ci	}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci	/* Don't allow indexes to exist outside of available space */
29318c2ecf20Sopenharmony_ci	if (fsp->location >= IGB_MAX_RXNFC_FILTERS) {
29328c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Location out of range\n");
29338c2ecf20Sopenharmony_ci		return -EINVAL;
29348c2ecf20Sopenharmony_ci	}
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW)
29378c2ecf20Sopenharmony_ci		return -EINVAL;
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_ci	input = kzalloc(sizeof(*input), GFP_KERNEL);
29408c2ecf20Sopenharmony_ci	if (!input)
29418c2ecf20Sopenharmony_ci		return -ENOMEM;
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_ci	if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) {
29448c2ecf20Sopenharmony_ci		input->filter.etype = fsp->h_u.ether_spec.h_proto;
29458c2ecf20Sopenharmony_ci		input->filter.match_flags = IGB_FILTER_FLAG_ETHER_TYPE;
29468c2ecf20Sopenharmony_ci	}
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_ci	/* Only support matching addresses by the full mask */
29498c2ecf20Sopenharmony_ci	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) {
29508c2ecf20Sopenharmony_ci		input->filter.match_flags |= IGB_FILTER_FLAG_SRC_MAC_ADDR;
29518c2ecf20Sopenharmony_ci		ether_addr_copy(input->filter.src_addr,
29528c2ecf20Sopenharmony_ci				fsp->h_u.ether_spec.h_source);
29538c2ecf20Sopenharmony_ci	}
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci	/* Only support matching addresses by the full mask */
29568c2ecf20Sopenharmony_ci	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) {
29578c2ecf20Sopenharmony_ci		input->filter.match_flags |= IGB_FILTER_FLAG_DST_MAC_ADDR;
29588c2ecf20Sopenharmony_ci		ether_addr_copy(input->filter.dst_addr,
29598c2ecf20Sopenharmony_ci				fsp->h_u.ether_spec.h_dest);
29608c2ecf20Sopenharmony_ci	}
29618c2ecf20Sopenharmony_ci
29628c2ecf20Sopenharmony_ci	if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) {
29638c2ecf20Sopenharmony_ci		if (fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) {
29648c2ecf20Sopenharmony_ci			err = -EINVAL;
29658c2ecf20Sopenharmony_ci			goto err_out;
29668c2ecf20Sopenharmony_ci		}
29678c2ecf20Sopenharmony_ci		input->filter.vlan_tci = fsp->h_ext.vlan_tci;
29688c2ecf20Sopenharmony_ci		input->filter.match_flags |= IGB_FILTER_FLAG_VLAN_TCI;
29698c2ecf20Sopenharmony_ci	}
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	input->action = fsp->ring_cookie;
29728c2ecf20Sopenharmony_ci	input->sw_idx = fsp->location;
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	spin_lock(&adapter->nfc_lock);
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_ci	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
29778c2ecf20Sopenharmony_ci		if (!memcmp(&input->filter, &rule->filter,
29788c2ecf20Sopenharmony_ci			    sizeof(input->filter))) {
29798c2ecf20Sopenharmony_ci			err = -EEXIST;
29808c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
29818c2ecf20Sopenharmony_ci				"ethtool: this filter is already set\n");
29828c2ecf20Sopenharmony_ci			goto err_out_w_lock;
29838c2ecf20Sopenharmony_ci		}
29848c2ecf20Sopenharmony_ci	}
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	err = igb_add_filter(adapter, input);
29878c2ecf20Sopenharmony_ci	if (err)
29888c2ecf20Sopenharmony_ci		goto err_out_w_lock;
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci	err = igb_update_ethtool_nfc_entry(adapter, input, input->sw_idx);
29918c2ecf20Sopenharmony_ci	if (err)
29928c2ecf20Sopenharmony_ci		goto err_out_input_filter;
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_ci	spin_unlock(&adapter->nfc_lock);
29958c2ecf20Sopenharmony_ci	return 0;
29968c2ecf20Sopenharmony_ci
29978c2ecf20Sopenharmony_cierr_out_input_filter:
29988c2ecf20Sopenharmony_ci	igb_erase_filter(adapter, input);
29998c2ecf20Sopenharmony_cierr_out_w_lock:
30008c2ecf20Sopenharmony_ci	spin_unlock(&adapter->nfc_lock);
30018c2ecf20Sopenharmony_cierr_out:
30028c2ecf20Sopenharmony_ci	kfree(input);
30038c2ecf20Sopenharmony_ci	return err;
30048c2ecf20Sopenharmony_ci}
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_cistatic int igb_del_ethtool_nfc_entry(struct igb_adapter *adapter,
30078c2ecf20Sopenharmony_ci				     struct ethtool_rxnfc *cmd)
30088c2ecf20Sopenharmony_ci{
30098c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp =
30108c2ecf20Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
30118c2ecf20Sopenharmony_ci	int err;
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_ci	spin_lock(&adapter->nfc_lock);
30148c2ecf20Sopenharmony_ci	err = igb_update_ethtool_nfc_entry(adapter, NULL, fsp->location);
30158c2ecf20Sopenharmony_ci	spin_unlock(&adapter->nfc_lock);
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci	return err;
30188c2ecf20Sopenharmony_ci}
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_cistatic int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
30218c2ecf20Sopenharmony_ci{
30228c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(dev);
30238c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
30268c2ecf20Sopenharmony_ci	case ETHTOOL_SRXFH:
30278c2ecf20Sopenharmony_ci		ret = igb_set_rss_hash_opt(adapter, cmd);
30288c2ecf20Sopenharmony_ci		break;
30298c2ecf20Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
30308c2ecf20Sopenharmony_ci		ret = igb_add_ethtool_nfc_entry(adapter, cmd);
30318c2ecf20Sopenharmony_ci		break;
30328c2ecf20Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
30338c2ecf20Sopenharmony_ci		ret = igb_del_ethtool_nfc_entry(adapter, cmd);
30348c2ecf20Sopenharmony_ci	default:
30358c2ecf20Sopenharmony_ci		break;
30368c2ecf20Sopenharmony_ci	}
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	return ret;
30398c2ecf20Sopenharmony_ci}
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_cistatic int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
30428c2ecf20Sopenharmony_ci{
30438c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
30448c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
30458c2ecf20Sopenharmony_ci	u32 ret_val;
30468c2ecf20Sopenharmony_ci	u16 phy_data;
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci	if ((hw->mac.type < e1000_i350) ||
30498c2ecf20Sopenharmony_ci	    (hw->phy.media_type != e1000_media_type_copper))
30508c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
30518c2ecf20Sopenharmony_ci
30528c2ecf20Sopenharmony_ci	edata->supported = (SUPPORTED_1000baseT_Full |
30538c2ecf20Sopenharmony_ci			    SUPPORTED_100baseT_Full);
30548c2ecf20Sopenharmony_ci	if (!hw->dev_spec._82575.eee_disable)
30558c2ecf20Sopenharmony_ci		edata->advertised =
30568c2ecf20Sopenharmony_ci			mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	/* The IPCNFG and EEER registers are not supported on I354. */
30598c2ecf20Sopenharmony_ci	if (hw->mac.type == e1000_i354) {
30608c2ecf20Sopenharmony_ci		igb_get_eee_status_i354(hw, (bool *)&edata->eee_active);
30618c2ecf20Sopenharmony_ci	} else {
30628c2ecf20Sopenharmony_ci		u32 eeer;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci		eeer = rd32(E1000_EEER);
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci		/* EEE status on negotiated link */
30678c2ecf20Sopenharmony_ci		if (eeer & E1000_EEER_EEE_NEG)
30688c2ecf20Sopenharmony_ci			edata->eee_active = true;
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci		if (eeer & E1000_EEER_TX_LPI_EN)
30718c2ecf20Sopenharmony_ci			edata->tx_lpi_enabled = true;
30728c2ecf20Sopenharmony_ci	}
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci	/* EEE Link Partner Advertised */
30758c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
30768c2ecf20Sopenharmony_ci	case e1000_i350:
30778c2ecf20Sopenharmony_ci		ret_val = igb_read_emi_reg(hw, E1000_EEE_LP_ADV_ADDR_I350,
30788c2ecf20Sopenharmony_ci					   &phy_data);
30798c2ecf20Sopenharmony_ci		if (ret_val)
30808c2ecf20Sopenharmony_ci			return -ENODATA;
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci		edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
30838c2ecf20Sopenharmony_ci		break;
30848c2ecf20Sopenharmony_ci	case e1000_i354:
30858c2ecf20Sopenharmony_ci	case e1000_i210:
30868c2ecf20Sopenharmony_ci	case e1000_i211:
30878c2ecf20Sopenharmony_ci		ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210,
30888c2ecf20Sopenharmony_ci					     E1000_EEE_LP_ADV_DEV_I210,
30898c2ecf20Sopenharmony_ci					     &phy_data);
30908c2ecf20Sopenharmony_ci		if (ret_val)
30918c2ecf20Sopenharmony_ci			return -ENODATA;
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci		edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci		break;
30968c2ecf20Sopenharmony_ci	default:
30978c2ecf20Sopenharmony_ci		break;
30988c2ecf20Sopenharmony_ci	}
30998c2ecf20Sopenharmony_ci
31008c2ecf20Sopenharmony_ci	edata->eee_enabled = !hw->dev_spec._82575.eee_disable;
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	if ((hw->mac.type == e1000_i354) &&
31038c2ecf20Sopenharmony_ci	    (edata->eee_enabled))
31048c2ecf20Sopenharmony_ci		edata->tx_lpi_enabled = true;
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	/* Report correct negotiated EEE status for devices that
31078c2ecf20Sopenharmony_ci	 * wrongly report EEE at half-duplex
31088c2ecf20Sopenharmony_ci	 */
31098c2ecf20Sopenharmony_ci	if (adapter->link_duplex == HALF_DUPLEX) {
31108c2ecf20Sopenharmony_ci		edata->eee_enabled = false;
31118c2ecf20Sopenharmony_ci		edata->eee_active = false;
31128c2ecf20Sopenharmony_ci		edata->tx_lpi_enabled = false;
31138c2ecf20Sopenharmony_ci		edata->advertised &= ~edata->advertised;
31148c2ecf20Sopenharmony_ci	}
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	return 0;
31178c2ecf20Sopenharmony_ci}
31188c2ecf20Sopenharmony_ci
31198c2ecf20Sopenharmony_cistatic int igb_set_eee(struct net_device *netdev,
31208c2ecf20Sopenharmony_ci		       struct ethtool_eee *edata)
31218c2ecf20Sopenharmony_ci{
31228c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
31238c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
31248c2ecf20Sopenharmony_ci	struct ethtool_eee eee_curr;
31258c2ecf20Sopenharmony_ci	bool adv1g_eee = true, adv100m_eee = true;
31268c2ecf20Sopenharmony_ci	s32 ret_val;
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_ci	if ((hw->mac.type < e1000_i350) ||
31298c2ecf20Sopenharmony_ci	    (hw->phy.media_type != e1000_media_type_copper))
31308c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci	memset(&eee_curr, 0, sizeof(struct ethtool_eee));
31338c2ecf20Sopenharmony_ci
31348c2ecf20Sopenharmony_ci	ret_val = igb_get_eee(netdev, &eee_curr);
31358c2ecf20Sopenharmony_ci	if (ret_val)
31368c2ecf20Sopenharmony_ci		return ret_val;
31378c2ecf20Sopenharmony_ci
31388c2ecf20Sopenharmony_ci	if (eee_curr.eee_enabled) {
31398c2ecf20Sopenharmony_ci		if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
31408c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
31418c2ecf20Sopenharmony_ci				"Setting EEE tx-lpi is not supported\n");
31428c2ecf20Sopenharmony_ci			return -EINVAL;
31438c2ecf20Sopenharmony_ci		}
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci		/* Tx LPI timer is not implemented currently */
31468c2ecf20Sopenharmony_ci		if (edata->tx_lpi_timer) {
31478c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
31488c2ecf20Sopenharmony_ci				"Setting EEE Tx LPI timer is not supported\n");
31498c2ecf20Sopenharmony_ci			return -EINVAL;
31508c2ecf20Sopenharmony_ci		}
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_ci		if (!edata->advertised || (edata->advertised &
31538c2ecf20Sopenharmony_ci		    ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) {
31548c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
31558c2ecf20Sopenharmony_ci				"EEE Advertisement supports only 100Tx and/or 100T full duplex\n");
31568c2ecf20Sopenharmony_ci			return -EINVAL;
31578c2ecf20Sopenharmony_ci		}
31588c2ecf20Sopenharmony_ci		adv100m_eee = !!(edata->advertised & ADVERTISE_100_FULL);
31598c2ecf20Sopenharmony_ci		adv1g_eee = !!(edata->advertised & ADVERTISE_1000_FULL);
31608c2ecf20Sopenharmony_ci
31618c2ecf20Sopenharmony_ci	} else if (!edata->eee_enabled) {
31628c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
31638c2ecf20Sopenharmony_ci			"Setting EEE options are not supported with EEE disabled\n");
31648c2ecf20Sopenharmony_ci		return -EINVAL;
31658c2ecf20Sopenharmony_ci	}
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci	adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
31688c2ecf20Sopenharmony_ci	if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
31698c2ecf20Sopenharmony_ci		hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
31708c2ecf20Sopenharmony_ci		adapter->flags |= IGB_FLAG_EEE;
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci		/* reset link */
31738c2ecf20Sopenharmony_ci		if (netif_running(netdev))
31748c2ecf20Sopenharmony_ci			igb_reinit_locked(adapter);
31758c2ecf20Sopenharmony_ci		else
31768c2ecf20Sopenharmony_ci			igb_reset(adapter);
31778c2ecf20Sopenharmony_ci	}
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_ci	if (hw->mac.type == e1000_i354)
31808c2ecf20Sopenharmony_ci		ret_val = igb_set_eee_i354(hw, adv1g_eee, adv100m_eee);
31818c2ecf20Sopenharmony_ci	else
31828c2ecf20Sopenharmony_ci		ret_val = igb_set_eee_i350(hw, adv1g_eee, adv100m_eee);
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci	if (ret_val) {
31858c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
31868c2ecf20Sopenharmony_ci			"Problem setting EEE advertisement options\n");
31878c2ecf20Sopenharmony_ci		return -EINVAL;
31888c2ecf20Sopenharmony_ci	}
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	return 0;
31918c2ecf20Sopenharmony_ci}
31928c2ecf20Sopenharmony_ci
31938c2ecf20Sopenharmony_cistatic int igb_get_module_info(struct net_device *netdev,
31948c2ecf20Sopenharmony_ci			       struct ethtool_modinfo *modinfo)
31958c2ecf20Sopenharmony_ci{
31968c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
31978c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
31988c2ecf20Sopenharmony_ci	u32 status = 0;
31998c2ecf20Sopenharmony_ci	u16 sff8472_rev, addr_mode;
32008c2ecf20Sopenharmony_ci	bool page_swap = false;
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci	if ((hw->phy.media_type == e1000_media_type_copper) ||
32038c2ecf20Sopenharmony_ci	    (hw->phy.media_type == e1000_media_type_unknown))
32048c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	/* Check whether we support SFF-8472 or not */
32078c2ecf20Sopenharmony_ci	status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_COMP, &sff8472_rev);
32088c2ecf20Sopenharmony_ci	if (status)
32098c2ecf20Sopenharmony_ci		return -EIO;
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	/* addressing mode is not supported */
32128c2ecf20Sopenharmony_ci	status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_SWAP, &addr_mode);
32138c2ecf20Sopenharmony_ci	if (status)
32148c2ecf20Sopenharmony_ci		return -EIO;
32158c2ecf20Sopenharmony_ci
32168c2ecf20Sopenharmony_ci	/* addressing mode is not supported */
32178c2ecf20Sopenharmony_ci	if ((addr_mode & 0xFF) & IGB_SFF_ADDRESSING_MODE) {
32188c2ecf20Sopenharmony_ci		hw_dbg("Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
32198c2ecf20Sopenharmony_ci		page_swap = true;
32208c2ecf20Sopenharmony_ci	}
32218c2ecf20Sopenharmony_ci
32228c2ecf20Sopenharmony_ci	if ((sff8472_rev & 0xFF) == IGB_SFF_8472_UNSUP || page_swap) {
32238c2ecf20Sopenharmony_ci		/* We have an SFP, but it does not support SFF-8472 */
32248c2ecf20Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8079;
32258c2ecf20Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
32268c2ecf20Sopenharmony_ci	} else {
32278c2ecf20Sopenharmony_ci		/* We have an SFP which supports a revision of SFF-8472 */
32288c2ecf20Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8472;
32298c2ecf20Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
32308c2ecf20Sopenharmony_ci	}
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	return 0;
32338c2ecf20Sopenharmony_ci}
32348c2ecf20Sopenharmony_ci
32358c2ecf20Sopenharmony_cistatic int igb_get_module_eeprom(struct net_device *netdev,
32368c2ecf20Sopenharmony_ci				 struct ethtool_eeprom *ee, u8 *data)
32378c2ecf20Sopenharmony_ci{
32388c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
32398c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
32408c2ecf20Sopenharmony_ci	u32 status = 0;
32418c2ecf20Sopenharmony_ci	u16 *dataword;
32428c2ecf20Sopenharmony_ci	u16 first_word, last_word;
32438c2ecf20Sopenharmony_ci	int i = 0;
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci	if (ee->len == 0)
32468c2ecf20Sopenharmony_ci		return -EINVAL;
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci	first_word = ee->offset >> 1;
32498c2ecf20Sopenharmony_ci	last_word = (ee->offset + ee->len - 1) >> 1;
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci	dataword = kmalloc_array(last_word - first_word + 1, sizeof(u16),
32528c2ecf20Sopenharmony_ci				 GFP_KERNEL);
32538c2ecf20Sopenharmony_ci	if (!dataword)
32548c2ecf20Sopenharmony_ci		return -ENOMEM;
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci	/* Read EEPROM block, SFF-8079/SFF-8472, word at a time */
32578c2ecf20Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++) {
32588c2ecf20Sopenharmony_ci		status = igb_read_phy_reg_i2c(hw, (first_word + i) * 2,
32598c2ecf20Sopenharmony_ci					      &dataword[i]);
32608c2ecf20Sopenharmony_ci		if (status) {
32618c2ecf20Sopenharmony_ci			/* Error occurred while reading module */
32628c2ecf20Sopenharmony_ci			kfree(dataword);
32638c2ecf20Sopenharmony_ci			return -EIO;
32648c2ecf20Sopenharmony_ci		}
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci		be16_to_cpus(&dataword[i]);
32678c2ecf20Sopenharmony_ci	}
32688c2ecf20Sopenharmony_ci
32698c2ecf20Sopenharmony_ci	memcpy(data, (u8 *)dataword + (ee->offset & 1), ee->len);
32708c2ecf20Sopenharmony_ci	kfree(dataword);
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci	return 0;
32738c2ecf20Sopenharmony_ci}
32748c2ecf20Sopenharmony_ci
32758c2ecf20Sopenharmony_cistatic int igb_ethtool_begin(struct net_device *netdev)
32768c2ecf20Sopenharmony_ci{
32778c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
32788c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&adapter->pdev->dev);
32798c2ecf20Sopenharmony_ci	return 0;
32808c2ecf20Sopenharmony_ci}
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_cistatic void igb_ethtool_complete(struct net_device *netdev)
32838c2ecf20Sopenharmony_ci{
32848c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
32858c2ecf20Sopenharmony_ci	pm_runtime_put(&adapter->pdev->dev);
32868c2ecf20Sopenharmony_ci}
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_cistatic u32 igb_get_rxfh_indir_size(struct net_device *netdev)
32898c2ecf20Sopenharmony_ci{
32908c2ecf20Sopenharmony_ci	return IGB_RETA_SIZE;
32918c2ecf20Sopenharmony_ci}
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_cistatic int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
32948c2ecf20Sopenharmony_ci			u8 *hfunc)
32958c2ecf20Sopenharmony_ci{
32968c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
32978c2ecf20Sopenharmony_ci	int i;
32988c2ecf20Sopenharmony_ci
32998c2ecf20Sopenharmony_ci	if (hfunc)
33008c2ecf20Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
33018c2ecf20Sopenharmony_ci	if (!indir)
33028c2ecf20Sopenharmony_ci		return 0;
33038c2ecf20Sopenharmony_ci	for (i = 0; i < IGB_RETA_SIZE; i++)
33048c2ecf20Sopenharmony_ci		indir[i] = adapter->rss_indir_tbl[i];
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	return 0;
33078c2ecf20Sopenharmony_ci}
33088c2ecf20Sopenharmony_ci
33098c2ecf20Sopenharmony_civoid igb_write_rss_indir_tbl(struct igb_adapter *adapter)
33108c2ecf20Sopenharmony_ci{
33118c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
33128c2ecf20Sopenharmony_ci	u32 reg = E1000_RETA(0);
33138c2ecf20Sopenharmony_ci	u32 shift = 0;
33148c2ecf20Sopenharmony_ci	int i = 0;
33158c2ecf20Sopenharmony_ci
33168c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
33178c2ecf20Sopenharmony_ci	case e1000_82575:
33188c2ecf20Sopenharmony_ci		shift = 6;
33198c2ecf20Sopenharmony_ci		break;
33208c2ecf20Sopenharmony_ci	case e1000_82576:
33218c2ecf20Sopenharmony_ci		/* 82576 supports 2 RSS queues for SR-IOV */
33228c2ecf20Sopenharmony_ci		if (adapter->vfs_allocated_count)
33238c2ecf20Sopenharmony_ci			shift = 3;
33248c2ecf20Sopenharmony_ci		break;
33258c2ecf20Sopenharmony_ci	default:
33268c2ecf20Sopenharmony_ci		break;
33278c2ecf20Sopenharmony_ci	}
33288c2ecf20Sopenharmony_ci
33298c2ecf20Sopenharmony_ci	while (i < IGB_RETA_SIZE) {
33308c2ecf20Sopenharmony_ci		u32 val = 0;
33318c2ecf20Sopenharmony_ci		int j;
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_ci		for (j = 3; j >= 0; j--) {
33348c2ecf20Sopenharmony_ci			val <<= 8;
33358c2ecf20Sopenharmony_ci			val |= adapter->rss_indir_tbl[i + j];
33368c2ecf20Sopenharmony_ci		}
33378c2ecf20Sopenharmony_ci
33388c2ecf20Sopenharmony_ci		wr32(reg, val << shift);
33398c2ecf20Sopenharmony_ci		reg += 4;
33408c2ecf20Sopenharmony_ci		i += 4;
33418c2ecf20Sopenharmony_ci	}
33428c2ecf20Sopenharmony_ci}
33438c2ecf20Sopenharmony_ci
33448c2ecf20Sopenharmony_cistatic int igb_set_rxfh(struct net_device *netdev, const u32 *indir,
33458c2ecf20Sopenharmony_ci			const u8 *key, const u8 hfunc)
33468c2ecf20Sopenharmony_ci{
33478c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
33488c2ecf20Sopenharmony_ci	struct e1000_hw *hw = &adapter->hw;
33498c2ecf20Sopenharmony_ci	int i;
33508c2ecf20Sopenharmony_ci	u32 num_queues;
33518c2ecf20Sopenharmony_ci
33528c2ecf20Sopenharmony_ci	/* We do not allow change in unsupported parameters */
33538c2ecf20Sopenharmony_ci	if (key ||
33548c2ecf20Sopenharmony_ci	    (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
33558c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
33568c2ecf20Sopenharmony_ci	if (!indir)
33578c2ecf20Sopenharmony_ci		return 0;
33588c2ecf20Sopenharmony_ci
33598c2ecf20Sopenharmony_ci	num_queues = adapter->rss_queues;
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
33628c2ecf20Sopenharmony_ci	case e1000_82576:
33638c2ecf20Sopenharmony_ci		/* 82576 supports 2 RSS queues for SR-IOV */
33648c2ecf20Sopenharmony_ci		if (adapter->vfs_allocated_count)
33658c2ecf20Sopenharmony_ci			num_queues = 2;
33668c2ecf20Sopenharmony_ci		break;
33678c2ecf20Sopenharmony_ci	default:
33688c2ecf20Sopenharmony_ci		break;
33698c2ecf20Sopenharmony_ci	}
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci	/* Verify user input. */
33728c2ecf20Sopenharmony_ci	for (i = 0; i < IGB_RETA_SIZE; i++)
33738c2ecf20Sopenharmony_ci		if (indir[i] >= num_queues)
33748c2ecf20Sopenharmony_ci			return -EINVAL;
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci
33778c2ecf20Sopenharmony_ci	for (i = 0; i < IGB_RETA_SIZE; i++)
33788c2ecf20Sopenharmony_ci		adapter->rss_indir_tbl[i] = indir[i];
33798c2ecf20Sopenharmony_ci
33808c2ecf20Sopenharmony_ci	igb_write_rss_indir_tbl(adapter);
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	return 0;
33838c2ecf20Sopenharmony_ci}
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_cistatic unsigned int igb_max_channels(struct igb_adapter *adapter)
33868c2ecf20Sopenharmony_ci{
33878c2ecf20Sopenharmony_ci	return igb_get_max_rss_queues(adapter);
33888c2ecf20Sopenharmony_ci}
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_cistatic void igb_get_channels(struct net_device *netdev,
33918c2ecf20Sopenharmony_ci			     struct ethtool_channels *ch)
33928c2ecf20Sopenharmony_ci{
33938c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci	/* Report maximum channels */
33968c2ecf20Sopenharmony_ci	ch->max_combined = igb_max_channels(adapter);
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci	/* Report info for other vector */
33998c2ecf20Sopenharmony_ci	if (adapter->flags & IGB_FLAG_HAS_MSIX) {
34008c2ecf20Sopenharmony_ci		ch->max_other = NON_Q_VECTORS;
34018c2ecf20Sopenharmony_ci		ch->other_count = NON_Q_VECTORS;
34028c2ecf20Sopenharmony_ci	}
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	ch->combined_count = adapter->rss_queues;
34058c2ecf20Sopenharmony_ci}
34068c2ecf20Sopenharmony_ci
34078c2ecf20Sopenharmony_cistatic int igb_set_channels(struct net_device *netdev,
34088c2ecf20Sopenharmony_ci			    struct ethtool_channels *ch)
34098c2ecf20Sopenharmony_ci{
34108c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
34118c2ecf20Sopenharmony_ci	unsigned int count = ch->combined_count;
34128c2ecf20Sopenharmony_ci	unsigned int max_combined = 0;
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci	/* Verify they are not requesting separate vectors */
34158c2ecf20Sopenharmony_ci	if (!count || ch->rx_count || ch->tx_count)
34168c2ecf20Sopenharmony_ci		return -EINVAL;
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci	/* Verify other_count is valid and has not been changed */
34198c2ecf20Sopenharmony_ci	if (ch->other_count != NON_Q_VECTORS)
34208c2ecf20Sopenharmony_ci		return -EINVAL;
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	/* Verify the number of channels doesn't exceed hw limits */
34238c2ecf20Sopenharmony_ci	max_combined = igb_max_channels(adapter);
34248c2ecf20Sopenharmony_ci	if (count > max_combined)
34258c2ecf20Sopenharmony_ci		return -EINVAL;
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_ci	if (count != adapter->rss_queues) {
34288c2ecf20Sopenharmony_ci		adapter->rss_queues = count;
34298c2ecf20Sopenharmony_ci		igb_set_flag_queue_pairs(adapter, max_combined);
34308c2ecf20Sopenharmony_ci
34318c2ecf20Sopenharmony_ci		/* Hardware has to reinitialize queues and interrupts to
34328c2ecf20Sopenharmony_ci		 * match the new configuration.
34338c2ecf20Sopenharmony_ci		 */
34348c2ecf20Sopenharmony_ci		return igb_reinit_queues(adapter);
34358c2ecf20Sopenharmony_ci	}
34368c2ecf20Sopenharmony_ci
34378c2ecf20Sopenharmony_ci	return 0;
34388c2ecf20Sopenharmony_ci}
34398c2ecf20Sopenharmony_ci
34408c2ecf20Sopenharmony_cistatic u32 igb_get_priv_flags(struct net_device *netdev)
34418c2ecf20Sopenharmony_ci{
34428c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
34438c2ecf20Sopenharmony_ci	u32 priv_flags = 0;
34448c2ecf20Sopenharmony_ci
34458c2ecf20Sopenharmony_ci	if (adapter->flags & IGB_FLAG_RX_LEGACY)
34468c2ecf20Sopenharmony_ci		priv_flags |= IGB_PRIV_FLAGS_LEGACY_RX;
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci	return priv_flags;
34498c2ecf20Sopenharmony_ci}
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_cistatic int igb_set_priv_flags(struct net_device *netdev, u32 priv_flags)
34528c2ecf20Sopenharmony_ci{
34538c2ecf20Sopenharmony_ci	struct igb_adapter *adapter = netdev_priv(netdev);
34548c2ecf20Sopenharmony_ci	unsigned int flags = adapter->flags;
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_ci	flags &= ~IGB_FLAG_RX_LEGACY;
34578c2ecf20Sopenharmony_ci	if (priv_flags & IGB_PRIV_FLAGS_LEGACY_RX)
34588c2ecf20Sopenharmony_ci		flags |= IGB_FLAG_RX_LEGACY;
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_ci	if (flags != adapter->flags) {
34618c2ecf20Sopenharmony_ci		adapter->flags = flags;
34628c2ecf20Sopenharmony_ci
34638c2ecf20Sopenharmony_ci		/* reset interface to repopulate queues */
34648c2ecf20Sopenharmony_ci		if (netif_running(netdev))
34658c2ecf20Sopenharmony_ci			igb_reinit_locked(adapter);
34668c2ecf20Sopenharmony_ci	}
34678c2ecf20Sopenharmony_ci
34688c2ecf20Sopenharmony_ci	return 0;
34698c2ecf20Sopenharmony_ci}
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_cistatic const struct ethtool_ops igb_ethtool_ops = {
34728c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
34738c2ecf20Sopenharmony_ci	.get_drvinfo		= igb_get_drvinfo,
34748c2ecf20Sopenharmony_ci	.get_regs_len		= igb_get_regs_len,
34758c2ecf20Sopenharmony_ci	.get_regs		= igb_get_regs,
34768c2ecf20Sopenharmony_ci	.get_wol		= igb_get_wol,
34778c2ecf20Sopenharmony_ci	.set_wol		= igb_set_wol,
34788c2ecf20Sopenharmony_ci	.get_msglevel		= igb_get_msglevel,
34798c2ecf20Sopenharmony_ci	.set_msglevel		= igb_set_msglevel,
34808c2ecf20Sopenharmony_ci	.nway_reset		= igb_nway_reset,
34818c2ecf20Sopenharmony_ci	.get_link		= igb_get_link,
34828c2ecf20Sopenharmony_ci	.get_eeprom_len		= igb_get_eeprom_len,
34838c2ecf20Sopenharmony_ci	.get_eeprom		= igb_get_eeprom,
34848c2ecf20Sopenharmony_ci	.set_eeprom		= igb_set_eeprom,
34858c2ecf20Sopenharmony_ci	.get_ringparam		= igb_get_ringparam,
34868c2ecf20Sopenharmony_ci	.set_ringparam		= igb_set_ringparam,
34878c2ecf20Sopenharmony_ci	.get_pauseparam		= igb_get_pauseparam,
34888c2ecf20Sopenharmony_ci	.set_pauseparam		= igb_set_pauseparam,
34898c2ecf20Sopenharmony_ci	.self_test		= igb_diag_test,
34908c2ecf20Sopenharmony_ci	.get_strings		= igb_get_strings,
34918c2ecf20Sopenharmony_ci	.set_phys_id		= igb_set_phys_id,
34928c2ecf20Sopenharmony_ci	.get_sset_count		= igb_get_sset_count,
34938c2ecf20Sopenharmony_ci	.get_ethtool_stats	= igb_get_ethtool_stats,
34948c2ecf20Sopenharmony_ci	.get_coalesce		= igb_get_coalesce,
34958c2ecf20Sopenharmony_ci	.set_coalesce		= igb_set_coalesce,
34968c2ecf20Sopenharmony_ci	.get_ts_info		= igb_get_ts_info,
34978c2ecf20Sopenharmony_ci	.get_rxnfc		= igb_get_rxnfc,
34988c2ecf20Sopenharmony_ci	.set_rxnfc		= igb_set_rxnfc,
34998c2ecf20Sopenharmony_ci	.get_eee		= igb_get_eee,
35008c2ecf20Sopenharmony_ci	.set_eee		= igb_set_eee,
35018c2ecf20Sopenharmony_ci	.get_module_info	= igb_get_module_info,
35028c2ecf20Sopenharmony_ci	.get_module_eeprom	= igb_get_module_eeprom,
35038c2ecf20Sopenharmony_ci	.get_rxfh_indir_size	= igb_get_rxfh_indir_size,
35048c2ecf20Sopenharmony_ci	.get_rxfh		= igb_get_rxfh,
35058c2ecf20Sopenharmony_ci	.set_rxfh		= igb_set_rxfh,
35068c2ecf20Sopenharmony_ci	.get_channels		= igb_get_channels,
35078c2ecf20Sopenharmony_ci	.set_channels		= igb_set_channels,
35088c2ecf20Sopenharmony_ci	.get_priv_flags		= igb_get_priv_flags,
35098c2ecf20Sopenharmony_ci	.set_priv_flags		= igb_set_priv_flags,
35108c2ecf20Sopenharmony_ci	.begin			= igb_ethtool_begin,
35118c2ecf20Sopenharmony_ci	.complete		= igb_ethtool_complete,
35128c2ecf20Sopenharmony_ci	.get_link_ksettings	= igb_get_link_ksettings,
35138c2ecf20Sopenharmony_ci	.set_link_ksettings	= igb_set_link_ksettings,
35148c2ecf20Sopenharmony_ci};
35158c2ecf20Sopenharmony_ci
35168c2ecf20Sopenharmony_civoid igb_set_ethtool_ops(struct net_device *netdev)
35178c2ecf20Sopenharmony_ci{
35188c2ecf20Sopenharmony_ci	netdev->ethtool_ops = &igb_ethtool_ops;
35198c2ecf20Sopenharmony_ci}
3520