18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c)  2018 Intel Corporation */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci/* ethtool support for igc */
58c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
68c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
78c2ecf20Sopenharmony_ci#include <linux/mdio.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "igc.h"
108c2ecf20Sopenharmony_ci#include "igc_diag.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/* forward declaration */
138c2ecf20Sopenharmony_cistruct igc_stats {
148c2ecf20Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
158c2ecf20Sopenharmony_ci	int sizeof_stat;
168c2ecf20Sopenharmony_ci	int stat_offset;
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define IGC_STAT(_name, _stat) { \
208c2ecf20Sopenharmony_ci	.stat_string = _name, \
218c2ecf20Sopenharmony_ci	.sizeof_stat = sizeof_field(struct igc_adapter, _stat), \
228c2ecf20Sopenharmony_ci	.stat_offset = offsetof(struct igc_adapter, _stat) \
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const struct igc_stats igc_gstrings_stats[] = {
268c2ecf20Sopenharmony_ci	IGC_STAT("rx_packets", stats.gprc),
278c2ecf20Sopenharmony_ci	IGC_STAT("tx_packets", stats.gptc),
288c2ecf20Sopenharmony_ci	IGC_STAT("rx_bytes", stats.gorc),
298c2ecf20Sopenharmony_ci	IGC_STAT("tx_bytes", stats.gotc),
308c2ecf20Sopenharmony_ci	IGC_STAT("rx_broadcast", stats.bprc),
318c2ecf20Sopenharmony_ci	IGC_STAT("tx_broadcast", stats.bptc),
328c2ecf20Sopenharmony_ci	IGC_STAT("rx_multicast", stats.mprc),
338c2ecf20Sopenharmony_ci	IGC_STAT("tx_multicast", stats.mptc),
348c2ecf20Sopenharmony_ci	IGC_STAT("multicast", stats.mprc),
358c2ecf20Sopenharmony_ci	IGC_STAT("collisions", stats.colc),
368c2ecf20Sopenharmony_ci	IGC_STAT("rx_crc_errors", stats.crcerrs),
378c2ecf20Sopenharmony_ci	IGC_STAT("rx_no_buffer_count", stats.rnbc),
388c2ecf20Sopenharmony_ci	IGC_STAT("rx_missed_errors", stats.mpc),
398c2ecf20Sopenharmony_ci	IGC_STAT("tx_aborted_errors", stats.ecol),
408c2ecf20Sopenharmony_ci	IGC_STAT("tx_carrier_errors", stats.tncrs),
418c2ecf20Sopenharmony_ci	IGC_STAT("tx_window_errors", stats.latecol),
428c2ecf20Sopenharmony_ci	IGC_STAT("tx_abort_late_coll", stats.latecol),
438c2ecf20Sopenharmony_ci	IGC_STAT("tx_deferred_ok", stats.dc),
448c2ecf20Sopenharmony_ci	IGC_STAT("tx_single_coll_ok", stats.scc),
458c2ecf20Sopenharmony_ci	IGC_STAT("tx_multi_coll_ok", stats.mcc),
468c2ecf20Sopenharmony_ci	IGC_STAT("tx_timeout_count", tx_timeout_count),
478c2ecf20Sopenharmony_ci	IGC_STAT("rx_long_length_errors", stats.roc),
488c2ecf20Sopenharmony_ci	IGC_STAT("rx_short_length_errors", stats.ruc),
498c2ecf20Sopenharmony_ci	IGC_STAT("rx_align_errors", stats.algnerrc),
508c2ecf20Sopenharmony_ci	IGC_STAT("tx_tcp_seg_good", stats.tsctc),
518c2ecf20Sopenharmony_ci	IGC_STAT("tx_tcp_seg_failed", stats.tsctfc),
528c2ecf20Sopenharmony_ci	IGC_STAT("rx_flow_control_xon", stats.xonrxc),
538c2ecf20Sopenharmony_ci	IGC_STAT("rx_flow_control_xoff", stats.xoffrxc),
548c2ecf20Sopenharmony_ci	IGC_STAT("tx_flow_control_xon", stats.xontxc),
558c2ecf20Sopenharmony_ci	IGC_STAT("tx_flow_control_xoff", stats.xofftxc),
568c2ecf20Sopenharmony_ci	IGC_STAT("rx_long_byte_count", stats.gorc),
578c2ecf20Sopenharmony_ci	IGC_STAT("tx_dma_out_of_sync", stats.doosync),
588c2ecf20Sopenharmony_ci	IGC_STAT("tx_smbus", stats.mgptc),
598c2ecf20Sopenharmony_ci	IGC_STAT("rx_smbus", stats.mgprc),
608c2ecf20Sopenharmony_ci	IGC_STAT("dropped_smbus", stats.mgpdc),
618c2ecf20Sopenharmony_ci	IGC_STAT("os2bmc_rx_by_bmc", stats.o2bgptc),
628c2ecf20Sopenharmony_ci	IGC_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
638c2ecf20Sopenharmony_ci	IGC_STAT("os2bmc_tx_by_host", stats.o2bspc),
648c2ecf20Sopenharmony_ci	IGC_STAT("os2bmc_rx_by_host", stats.b2ogprc),
658c2ecf20Sopenharmony_ci	IGC_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
668c2ecf20Sopenharmony_ci	IGC_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
678c2ecf20Sopenharmony_ci	IGC_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define IGC_NETDEV_STAT(_net_stat) { \
718c2ecf20Sopenharmony_ci	.stat_string = __stringify(_net_stat), \
728c2ecf20Sopenharmony_ci	.sizeof_stat = sizeof_field(struct rtnl_link_stats64, _net_stat), \
738c2ecf20Sopenharmony_ci	.stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic const struct igc_stats igc_gstrings_net_stats[] = {
778c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(rx_errors),
788c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(tx_errors),
798c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(tx_dropped),
808c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(rx_length_errors),
818c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(rx_over_errors),
828c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(rx_frame_errors),
838c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(rx_fifo_errors),
848c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(tx_fifo_errors),
858c2ecf20Sopenharmony_ci	IGC_NETDEV_STAT(tx_heartbeat_errors)
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cienum igc_diagnostics_results {
898c2ecf20Sopenharmony_ci	TEST_REG = 0,
908c2ecf20Sopenharmony_ci	TEST_EEP,
918c2ecf20Sopenharmony_ci	TEST_IRQ,
928c2ecf20Sopenharmony_ci	TEST_LOOP,
938c2ecf20Sopenharmony_ci	TEST_LINK
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic const char igc_gstrings_test[][ETH_GSTRING_LEN] = {
978c2ecf20Sopenharmony_ci	[TEST_REG]  = "Register test  (offline)",
988c2ecf20Sopenharmony_ci	[TEST_EEP]  = "Eeprom test    (offline)",
998c2ecf20Sopenharmony_ci	[TEST_IRQ]  = "Interrupt test (offline)",
1008c2ecf20Sopenharmony_ci	[TEST_LOOP] = "Loopback test  (offline)",
1018c2ecf20Sopenharmony_ci	[TEST_LINK] = "Link test   (on/offline)"
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define IGC_TEST_LEN (sizeof(igc_gstrings_test) / ETH_GSTRING_LEN)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#define IGC_GLOBAL_STATS_LEN	\
1078c2ecf20Sopenharmony_ci	(sizeof(igc_gstrings_stats) / sizeof(struct igc_stats))
1088c2ecf20Sopenharmony_ci#define IGC_NETDEV_STATS_LEN	\
1098c2ecf20Sopenharmony_ci	(sizeof(igc_gstrings_net_stats) / sizeof(struct igc_stats))
1108c2ecf20Sopenharmony_ci#define IGC_RX_QUEUE_STATS_LEN \
1118c2ecf20Sopenharmony_ci	(sizeof(struct igc_rx_queue_stats) / sizeof(u64))
1128c2ecf20Sopenharmony_ci#define IGC_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */
1138c2ecf20Sopenharmony_ci#define IGC_QUEUE_STATS_LEN \
1148c2ecf20Sopenharmony_ci	((((struct igc_adapter *)netdev_priv(netdev))->num_rx_queues * \
1158c2ecf20Sopenharmony_ci	  IGC_RX_QUEUE_STATS_LEN) + \
1168c2ecf20Sopenharmony_ci	 (((struct igc_adapter *)netdev_priv(netdev))->num_tx_queues * \
1178c2ecf20Sopenharmony_ci	  IGC_TX_QUEUE_STATS_LEN))
1188c2ecf20Sopenharmony_ci#define IGC_STATS_LEN \
1198c2ecf20Sopenharmony_ci	(IGC_GLOBAL_STATS_LEN + IGC_NETDEV_STATS_LEN + IGC_QUEUE_STATS_LEN)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = {
1228c2ecf20Sopenharmony_ci#define IGC_PRIV_FLAGS_LEGACY_RX	BIT(0)
1238c2ecf20Sopenharmony_ci	"legacy-rx",
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci#define IGC_PRIV_FLAGS_STR_LEN ARRAY_SIZE(igc_priv_flags_strings)
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic void igc_ethtool_get_drvinfo(struct net_device *netdev,
1298c2ecf20Sopenharmony_ci				    struct ethtool_drvinfo *drvinfo)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	strlcpy(drvinfo->driver,  igc_driver_name, sizeof(drvinfo->driver));
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* add fw_version here */
1368c2ecf20Sopenharmony_ci	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
1378c2ecf20Sopenharmony_ci		sizeof(drvinfo->bus_info));
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	drvinfo->n_priv_flags = IGC_PRIV_FLAGS_STR_LEN;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int igc_ethtool_get_regs_len(struct net_device *netdev)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	return IGC_REGS_LEN * sizeof(u32);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic void igc_ethtool_get_regs(struct net_device *netdev,
1488c2ecf20Sopenharmony_ci				 struct ethtool_regs *regs, void *p)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
1518c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
1528c2ecf20Sopenharmony_ci	u32 *regs_buff = p;
1538c2ecf20Sopenharmony_ci	u8 i;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	memset(p, 0, IGC_REGS_LEN * sizeof(u32));
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	regs->version = (2u << 24) | (hw->revision_id << 16) | hw->device_id;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* General Registers */
1608c2ecf20Sopenharmony_ci	regs_buff[0] = rd32(IGC_CTRL);
1618c2ecf20Sopenharmony_ci	regs_buff[1] = rd32(IGC_STATUS);
1628c2ecf20Sopenharmony_ci	regs_buff[2] = rd32(IGC_CTRL_EXT);
1638c2ecf20Sopenharmony_ci	regs_buff[3] = rd32(IGC_MDIC);
1648c2ecf20Sopenharmony_ci	regs_buff[4] = rd32(IGC_CONNSW);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* NVM Register */
1678c2ecf20Sopenharmony_ci	regs_buff[5] = rd32(IGC_EECD);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* Interrupt */
1708c2ecf20Sopenharmony_ci	/* Reading EICS for EICR because they read the
1718c2ecf20Sopenharmony_ci	 * same but EICS does not clear on read
1728c2ecf20Sopenharmony_ci	 */
1738c2ecf20Sopenharmony_ci	regs_buff[6] = rd32(IGC_EICS);
1748c2ecf20Sopenharmony_ci	regs_buff[7] = rd32(IGC_EICS);
1758c2ecf20Sopenharmony_ci	regs_buff[8] = rd32(IGC_EIMS);
1768c2ecf20Sopenharmony_ci	regs_buff[9] = rd32(IGC_EIMC);
1778c2ecf20Sopenharmony_ci	regs_buff[10] = rd32(IGC_EIAC);
1788c2ecf20Sopenharmony_ci	regs_buff[11] = rd32(IGC_EIAM);
1798c2ecf20Sopenharmony_ci	/* Reading ICS for ICR because they read the
1808c2ecf20Sopenharmony_ci	 * same but ICS does not clear on read
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	regs_buff[12] = rd32(IGC_ICS);
1838c2ecf20Sopenharmony_ci	regs_buff[13] = rd32(IGC_ICS);
1848c2ecf20Sopenharmony_ci	regs_buff[14] = rd32(IGC_IMS);
1858c2ecf20Sopenharmony_ci	regs_buff[15] = rd32(IGC_IMC);
1868c2ecf20Sopenharmony_ci	regs_buff[16] = rd32(IGC_IAC);
1878c2ecf20Sopenharmony_ci	regs_buff[17] = rd32(IGC_IAM);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* Flow Control */
1908c2ecf20Sopenharmony_ci	regs_buff[18] = rd32(IGC_FCAL);
1918c2ecf20Sopenharmony_ci	regs_buff[19] = rd32(IGC_FCAH);
1928c2ecf20Sopenharmony_ci	regs_buff[20] = rd32(IGC_FCTTV);
1938c2ecf20Sopenharmony_ci	regs_buff[21] = rd32(IGC_FCRTL);
1948c2ecf20Sopenharmony_ci	regs_buff[22] = rd32(IGC_FCRTH);
1958c2ecf20Sopenharmony_ci	regs_buff[23] = rd32(IGC_FCRTV);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/* Receive */
1988c2ecf20Sopenharmony_ci	regs_buff[24] = rd32(IGC_RCTL);
1998c2ecf20Sopenharmony_ci	regs_buff[25] = rd32(IGC_RXCSUM);
2008c2ecf20Sopenharmony_ci	regs_buff[26] = rd32(IGC_RLPML);
2018c2ecf20Sopenharmony_ci	regs_buff[27] = rd32(IGC_RFCTL);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* Transmit */
2048c2ecf20Sopenharmony_ci	regs_buff[28] = rd32(IGC_TCTL);
2058c2ecf20Sopenharmony_ci	regs_buff[29] = rd32(IGC_TIPG);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Wake Up */
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* MAC */
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* Statistics */
2128c2ecf20Sopenharmony_ci	regs_buff[30] = adapter->stats.crcerrs;
2138c2ecf20Sopenharmony_ci	regs_buff[31] = adapter->stats.algnerrc;
2148c2ecf20Sopenharmony_ci	regs_buff[32] = adapter->stats.symerrs;
2158c2ecf20Sopenharmony_ci	regs_buff[33] = adapter->stats.rxerrc;
2168c2ecf20Sopenharmony_ci	regs_buff[34] = adapter->stats.mpc;
2178c2ecf20Sopenharmony_ci	regs_buff[35] = adapter->stats.scc;
2188c2ecf20Sopenharmony_ci	regs_buff[36] = adapter->stats.ecol;
2198c2ecf20Sopenharmony_ci	regs_buff[37] = adapter->stats.mcc;
2208c2ecf20Sopenharmony_ci	regs_buff[38] = adapter->stats.latecol;
2218c2ecf20Sopenharmony_ci	regs_buff[39] = adapter->stats.colc;
2228c2ecf20Sopenharmony_ci	regs_buff[40] = adapter->stats.dc;
2238c2ecf20Sopenharmony_ci	regs_buff[41] = adapter->stats.tncrs;
2248c2ecf20Sopenharmony_ci	regs_buff[42] = adapter->stats.sec;
2258c2ecf20Sopenharmony_ci	regs_buff[43] = adapter->stats.htdpmc;
2268c2ecf20Sopenharmony_ci	regs_buff[44] = adapter->stats.rlec;
2278c2ecf20Sopenharmony_ci	regs_buff[45] = adapter->stats.xonrxc;
2288c2ecf20Sopenharmony_ci	regs_buff[46] = adapter->stats.xontxc;
2298c2ecf20Sopenharmony_ci	regs_buff[47] = adapter->stats.xoffrxc;
2308c2ecf20Sopenharmony_ci	regs_buff[48] = adapter->stats.xofftxc;
2318c2ecf20Sopenharmony_ci	regs_buff[49] = adapter->stats.fcruc;
2328c2ecf20Sopenharmony_ci	regs_buff[50] = adapter->stats.prc64;
2338c2ecf20Sopenharmony_ci	regs_buff[51] = adapter->stats.prc127;
2348c2ecf20Sopenharmony_ci	regs_buff[52] = adapter->stats.prc255;
2358c2ecf20Sopenharmony_ci	regs_buff[53] = adapter->stats.prc511;
2368c2ecf20Sopenharmony_ci	regs_buff[54] = adapter->stats.prc1023;
2378c2ecf20Sopenharmony_ci	regs_buff[55] = adapter->stats.prc1522;
2388c2ecf20Sopenharmony_ci	regs_buff[56] = adapter->stats.gprc;
2398c2ecf20Sopenharmony_ci	regs_buff[57] = adapter->stats.bprc;
2408c2ecf20Sopenharmony_ci	regs_buff[58] = adapter->stats.mprc;
2418c2ecf20Sopenharmony_ci	regs_buff[59] = adapter->stats.gptc;
2428c2ecf20Sopenharmony_ci	regs_buff[60] = adapter->stats.gorc;
2438c2ecf20Sopenharmony_ci	regs_buff[61] = adapter->stats.gotc;
2448c2ecf20Sopenharmony_ci	regs_buff[62] = adapter->stats.rnbc;
2458c2ecf20Sopenharmony_ci	regs_buff[63] = adapter->stats.ruc;
2468c2ecf20Sopenharmony_ci	regs_buff[64] = adapter->stats.rfc;
2478c2ecf20Sopenharmony_ci	regs_buff[65] = adapter->stats.roc;
2488c2ecf20Sopenharmony_ci	regs_buff[66] = adapter->stats.rjc;
2498c2ecf20Sopenharmony_ci	regs_buff[67] = adapter->stats.mgprc;
2508c2ecf20Sopenharmony_ci	regs_buff[68] = adapter->stats.mgpdc;
2518c2ecf20Sopenharmony_ci	regs_buff[69] = adapter->stats.mgptc;
2528c2ecf20Sopenharmony_ci	regs_buff[70] = adapter->stats.tor;
2538c2ecf20Sopenharmony_ci	regs_buff[71] = adapter->stats.tot;
2548c2ecf20Sopenharmony_ci	regs_buff[72] = adapter->stats.tpr;
2558c2ecf20Sopenharmony_ci	regs_buff[73] = adapter->stats.tpt;
2568c2ecf20Sopenharmony_ci	regs_buff[74] = adapter->stats.ptc64;
2578c2ecf20Sopenharmony_ci	regs_buff[75] = adapter->stats.ptc127;
2588c2ecf20Sopenharmony_ci	regs_buff[76] = adapter->stats.ptc255;
2598c2ecf20Sopenharmony_ci	regs_buff[77] = adapter->stats.ptc511;
2608c2ecf20Sopenharmony_ci	regs_buff[78] = adapter->stats.ptc1023;
2618c2ecf20Sopenharmony_ci	regs_buff[79] = adapter->stats.ptc1522;
2628c2ecf20Sopenharmony_ci	regs_buff[80] = adapter->stats.mptc;
2638c2ecf20Sopenharmony_ci	regs_buff[81] = adapter->stats.bptc;
2648c2ecf20Sopenharmony_ci	regs_buff[82] = adapter->stats.tsctc;
2658c2ecf20Sopenharmony_ci	regs_buff[83] = adapter->stats.iac;
2668c2ecf20Sopenharmony_ci	regs_buff[84] = adapter->stats.rpthc;
2678c2ecf20Sopenharmony_ci	regs_buff[85] = adapter->stats.hgptc;
2688c2ecf20Sopenharmony_ci	regs_buff[86] = adapter->stats.hgorc;
2698c2ecf20Sopenharmony_ci	regs_buff[87] = adapter->stats.hgotc;
2708c2ecf20Sopenharmony_ci	regs_buff[88] = adapter->stats.lenerrs;
2718c2ecf20Sopenharmony_ci	regs_buff[89] = adapter->stats.scvpc;
2728c2ecf20Sopenharmony_ci	regs_buff[90] = adapter->stats.hrmpc;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2758c2ecf20Sopenharmony_ci		regs_buff[91 + i] = rd32(IGC_SRRCTL(i));
2768c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2778c2ecf20Sopenharmony_ci		regs_buff[95 + i] = rd32(IGC_PSRTYPE(i));
2788c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2798c2ecf20Sopenharmony_ci		regs_buff[99 + i] = rd32(IGC_RDBAL(i));
2808c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2818c2ecf20Sopenharmony_ci		regs_buff[103 + i] = rd32(IGC_RDBAH(i));
2828c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2838c2ecf20Sopenharmony_ci		regs_buff[107 + i] = rd32(IGC_RDLEN(i));
2848c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2858c2ecf20Sopenharmony_ci		regs_buff[111 + i] = rd32(IGC_RDH(i));
2868c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2878c2ecf20Sopenharmony_ci		regs_buff[115 + i] = rd32(IGC_RDT(i));
2888c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2898c2ecf20Sopenharmony_ci		regs_buff[119 + i] = rd32(IGC_RXDCTL(i));
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++)
2928c2ecf20Sopenharmony_ci		regs_buff[123 + i] = rd32(IGC_EITR(i));
2938c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
2948c2ecf20Sopenharmony_ci		regs_buff[139 + i] = rd32(IGC_RAL(i));
2958c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
2968c2ecf20Sopenharmony_ci		regs_buff[145 + i] = rd32(IGC_RAH(i));
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
2998c2ecf20Sopenharmony_ci		regs_buff[149 + i] = rd32(IGC_TDBAL(i));
3008c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
3018c2ecf20Sopenharmony_ci		regs_buff[152 + i] = rd32(IGC_TDBAH(i));
3028c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
3038c2ecf20Sopenharmony_ci		regs_buff[156 + i] = rd32(IGC_TDLEN(i));
3048c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
3058c2ecf20Sopenharmony_ci		regs_buff[160 + i] = rd32(IGC_TDH(i));
3068c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
3078c2ecf20Sopenharmony_ci		regs_buff[164 + i] = rd32(IGC_TDT(i));
3088c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
3098c2ecf20Sopenharmony_ci		regs_buff[168 + i] = rd32(IGC_TXDCTL(i));
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/* XXX: Due to a bug few lines above, RAL and RAH registers are
3128c2ecf20Sopenharmony_ci	 * overwritten. To preserve the ABI, we write these registers again in
3138c2ecf20Sopenharmony_ci	 * regs_buff.
3148c2ecf20Sopenharmony_ci	 */
3158c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
3168c2ecf20Sopenharmony_ci		regs_buff[172 + i] = rd32(IGC_RAL(i));
3178c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
3188c2ecf20Sopenharmony_ci		regs_buff[188 + i] = rd32(IGC_RAH(i));
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	regs_buff[204] = rd32(IGC_VLANPQF);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
3238c2ecf20Sopenharmony_ci		regs_buff[205 + i] = rd32(IGC_ETQF(i));
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	regs_buff[213] = adapter->stats.tlpic;
3268c2ecf20Sopenharmony_ci	regs_buff[214] = adapter->stats.rlpic;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic void igc_ethtool_get_wol(struct net_device *netdev,
3308c2ecf20Sopenharmony_ci				struct ethtool_wolinfo *wol)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	wol->wolopts = 0;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED))
3378c2ecf20Sopenharmony_ci		return;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	wol->supported = WAKE_UCAST | WAKE_MCAST |
3408c2ecf20Sopenharmony_ci			 WAKE_BCAST | WAKE_MAGIC |
3418c2ecf20Sopenharmony_ci			 WAKE_PHY;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/* apply any specific unsupported masks here */
3448c2ecf20Sopenharmony_ci	switch (adapter->hw.device_id) {
3458c2ecf20Sopenharmony_ci	default:
3468c2ecf20Sopenharmony_ci		break;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (adapter->wol & IGC_WUFC_EX)
3508c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_UCAST;
3518c2ecf20Sopenharmony_ci	if (adapter->wol & IGC_WUFC_MC)
3528c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_MCAST;
3538c2ecf20Sopenharmony_ci	if (adapter->wol & IGC_WUFC_BC)
3548c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_BCAST;
3558c2ecf20Sopenharmony_ci	if (adapter->wol & IGC_WUFC_MAG)
3568c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_MAGIC;
3578c2ecf20Sopenharmony_ci	if (adapter->wol & IGC_WUFC_LNKC)
3588c2ecf20Sopenharmony_ci		wol->wolopts |= WAKE_PHY;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int igc_ethtool_set_wol(struct net_device *netdev,
3628c2ecf20Sopenharmony_ci			       struct ethtool_wolinfo *wol)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER))
3678c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED))
3708c2ecf20Sopenharmony_ci		return wol->wolopts ? -EOPNOTSUPP : 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/* these settings will always override what we currently have */
3738c2ecf20Sopenharmony_ci	adapter->wol = 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_UCAST)
3768c2ecf20Sopenharmony_ci		adapter->wol |= IGC_WUFC_EX;
3778c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MCAST)
3788c2ecf20Sopenharmony_ci		adapter->wol |= IGC_WUFC_MC;
3798c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_BCAST)
3808c2ecf20Sopenharmony_ci		adapter->wol |= IGC_WUFC_BC;
3818c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC)
3828c2ecf20Sopenharmony_ci		adapter->wol |= IGC_WUFC_MAG;
3838c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_PHY)
3848c2ecf20Sopenharmony_ci		adapter->wol |= IGC_WUFC_LNKC;
3858c2ecf20Sopenharmony_ci	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	return 0;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic u32 igc_ethtool_get_msglevel(struct net_device *netdev)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return adapter->msg_enable;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic void igc_ethtool_set_msglevel(struct net_device *netdev, u32 data)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	adapter->msg_enable = data;
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic int igc_ethtool_nway_reset(struct net_device *netdev)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (netif_running(netdev))
4098c2ecf20Sopenharmony_ci		igc_reinit_locked(adapter);
4108c2ecf20Sopenharmony_ci	return 0;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic u32 igc_ethtool_get_link(struct net_device *netdev)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
4168c2ecf20Sopenharmony_ci	struct igc_mac_info *mac = &adapter->hw.mac;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* If the link is not reported up to netdev, interrupts are disabled,
4198c2ecf20Sopenharmony_ci	 * and so the physical link state may have changed since we last
4208c2ecf20Sopenharmony_ci	 * looked. Set get_link_status to make sure that the true link
4218c2ecf20Sopenharmony_ci	 * state is interrogated, rather than pulling a cached and possibly
4228c2ecf20Sopenharmony_ci	 * stale link state from the driver.
4238c2ecf20Sopenharmony_ci	 */
4248c2ecf20Sopenharmony_ci	if (!netif_carrier_ok(netdev))
4258c2ecf20Sopenharmony_ci		mac->get_link_status = 1;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return igc_has_link(adapter);
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic int igc_ethtool_get_eeprom_len(struct net_device *netdev)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return adapter->hw.nvm.word_size * 2;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic int igc_ethtool_get_eeprom(struct net_device *netdev,
4388c2ecf20Sopenharmony_ci				  struct ethtool_eeprom *eeprom, u8 *bytes)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
4418c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
4428c2ecf20Sopenharmony_ci	int first_word, last_word;
4438c2ecf20Sopenharmony_ci	u16 *eeprom_buff;
4448c2ecf20Sopenharmony_ci	int ret_val = 0;
4458c2ecf20Sopenharmony_ci	u16 i;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (eeprom->len == 0)
4488c2ecf20Sopenharmony_ci		return -EINVAL;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	first_word = eeprom->offset >> 1;
4538c2ecf20Sopenharmony_ci	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16),
4568c2ecf20Sopenharmony_ci				    GFP_KERNEL);
4578c2ecf20Sopenharmony_ci	if (!eeprom_buff)
4588c2ecf20Sopenharmony_ci		return -ENOMEM;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (hw->nvm.type == igc_nvm_eeprom_spi) {
4618c2ecf20Sopenharmony_ci		ret_val = hw->nvm.ops.read(hw, first_word,
4628c2ecf20Sopenharmony_ci					   last_word - first_word + 1,
4638c2ecf20Sopenharmony_ci					   eeprom_buff);
4648c2ecf20Sopenharmony_ci	} else {
4658c2ecf20Sopenharmony_ci		for (i = 0; i < last_word - first_word + 1; i++) {
4668c2ecf20Sopenharmony_ci			ret_val = hw->nvm.ops.read(hw, first_word + i, 1,
4678c2ecf20Sopenharmony_ci						   &eeprom_buff[i]);
4688c2ecf20Sopenharmony_ci			if (ret_val)
4698c2ecf20Sopenharmony_ci				break;
4708c2ecf20Sopenharmony_ci		}
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* Device's eeprom is always little-endian, word addressable */
4748c2ecf20Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
4758c2ecf20Sopenharmony_ci		le16_to_cpus(&eeprom_buff[i]);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1),
4788c2ecf20Sopenharmony_ci	       eeprom->len);
4798c2ecf20Sopenharmony_ci	kfree(eeprom_buff);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return ret_val;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int igc_ethtool_set_eeprom(struct net_device *netdev,
4858c2ecf20Sopenharmony_ci				  struct ethtool_eeprom *eeprom, u8 *bytes)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
4888c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
4898c2ecf20Sopenharmony_ci	int max_len, first_word, last_word, ret_val = 0;
4908c2ecf20Sopenharmony_ci	u16 *eeprom_buff;
4918c2ecf20Sopenharmony_ci	void *ptr;
4928c2ecf20Sopenharmony_ci	u16 i;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (eeprom->len == 0)
4958c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (hw->mac.type >= igc_i225 &&
4988c2ecf20Sopenharmony_ci	    !igc_get_flash_presence_i225(hw)) {
4998c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
5038c2ecf20Sopenharmony_ci		return -EFAULT;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	max_len = hw->nvm.word_size * 2;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	first_word = eeprom->offset >> 1;
5088c2ecf20Sopenharmony_ci	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
5098c2ecf20Sopenharmony_ci	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
5108c2ecf20Sopenharmony_ci	if (!eeprom_buff)
5118c2ecf20Sopenharmony_ci		return -ENOMEM;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	ptr = (void *)eeprom_buff;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (eeprom->offset & 1) {
5168c2ecf20Sopenharmony_ci		/* need read/modify/write of first changed EEPROM word
5178c2ecf20Sopenharmony_ci		 * only the second byte of the word is being modified
5188c2ecf20Sopenharmony_ci		 */
5198c2ecf20Sopenharmony_ci		ret_val = hw->nvm.ops.read(hw, first_word, 1,
5208c2ecf20Sopenharmony_ci					    &eeprom_buff[0]);
5218c2ecf20Sopenharmony_ci		ptr++;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci	if (((eeprom->offset + eeprom->len) & 1) && ret_val == 0) {
5248c2ecf20Sopenharmony_ci		/* need read/modify/write of last changed EEPROM word
5258c2ecf20Sopenharmony_ci		 * only the first byte of the word is being modified
5268c2ecf20Sopenharmony_ci		 */
5278c2ecf20Sopenharmony_ci		ret_val = hw->nvm.ops.read(hw, last_word, 1,
5288c2ecf20Sopenharmony_ci				   &eeprom_buff[last_word - first_word]);
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/* Device's eeprom is always little-endian, word addressable */
5328c2ecf20Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
5338c2ecf20Sopenharmony_ci		le16_to_cpus(&eeprom_buff[i]);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	memcpy(ptr, bytes, eeprom->len);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	for (i = 0; i < last_word - first_word + 1; i++)
5388c2ecf20Sopenharmony_ci		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	ret_val = hw->nvm.ops.write(hw, first_word,
5418c2ecf20Sopenharmony_ci				    last_word - first_word + 1, eeprom_buff);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* Update the checksum if nvm write succeeded */
5448c2ecf20Sopenharmony_ci	if (ret_val == 0)
5458c2ecf20Sopenharmony_ci		hw->nvm.ops.update(hw);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* check if need: igc_set_fw_version(adapter); */
5488c2ecf20Sopenharmony_ci	kfree(eeprom_buff);
5498c2ecf20Sopenharmony_ci	return ret_val;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic void igc_ethtool_get_ringparam(struct net_device *netdev,
5538c2ecf20Sopenharmony_ci				      struct ethtool_ringparam *ring)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	ring->rx_max_pending = IGC_MAX_RXD;
5588c2ecf20Sopenharmony_ci	ring->tx_max_pending = IGC_MAX_TXD;
5598c2ecf20Sopenharmony_ci	ring->rx_pending = adapter->rx_ring_count;
5608c2ecf20Sopenharmony_ci	ring->tx_pending = adapter->tx_ring_count;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic int igc_ethtool_set_ringparam(struct net_device *netdev,
5648c2ecf20Sopenharmony_ci				     struct ethtool_ringparam *ring)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
5678c2ecf20Sopenharmony_ci	struct igc_ring *temp_ring;
5688c2ecf20Sopenharmony_ci	u16 new_rx_count, new_tx_count;
5698c2ecf20Sopenharmony_ci	int i, err = 0;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
5728c2ecf20Sopenharmony_ci		return -EINVAL;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	new_rx_count = min_t(u32, ring->rx_pending, IGC_MAX_RXD);
5758c2ecf20Sopenharmony_ci	new_rx_count = max_t(u16, new_rx_count, IGC_MIN_RXD);
5768c2ecf20Sopenharmony_ci	new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	new_tx_count = min_t(u32, ring->tx_pending, IGC_MAX_TXD);
5798c2ecf20Sopenharmony_ci	new_tx_count = max_t(u16, new_tx_count, IGC_MIN_TXD);
5808c2ecf20Sopenharmony_ci	new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (new_tx_count == adapter->tx_ring_count &&
5838c2ecf20Sopenharmony_ci	    new_rx_count == adapter->rx_ring_count) {
5848c2ecf20Sopenharmony_ci		/* nothing to do */
5858c2ecf20Sopenharmony_ci		return 0;
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
5898c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (!netif_running(adapter->netdev)) {
5928c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++)
5938c2ecf20Sopenharmony_ci			adapter->tx_ring[i]->count = new_tx_count;
5948c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++)
5958c2ecf20Sopenharmony_ci			adapter->rx_ring[i]->count = new_rx_count;
5968c2ecf20Sopenharmony_ci		adapter->tx_ring_count = new_tx_count;
5978c2ecf20Sopenharmony_ci		adapter->rx_ring_count = new_rx_count;
5988c2ecf20Sopenharmony_ci		goto clear_reset;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (adapter->num_tx_queues > adapter->num_rx_queues)
6028c2ecf20Sopenharmony_ci		temp_ring = vmalloc(array_size(sizeof(struct igc_ring),
6038c2ecf20Sopenharmony_ci					       adapter->num_tx_queues));
6048c2ecf20Sopenharmony_ci	else
6058c2ecf20Sopenharmony_ci		temp_ring = vmalloc(array_size(sizeof(struct igc_ring),
6068c2ecf20Sopenharmony_ci					       adapter->num_rx_queues));
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (!temp_ring) {
6098c2ecf20Sopenharmony_ci		err = -ENOMEM;
6108c2ecf20Sopenharmony_ci		goto clear_reset;
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	igc_down(adapter);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/* We can't just free everything and then setup again,
6168c2ecf20Sopenharmony_ci	 * because the ISRs in MSI-X mode get passed pointers
6178c2ecf20Sopenharmony_ci	 * to the Tx and Rx ring structs.
6188c2ecf20Sopenharmony_ci	 */
6198c2ecf20Sopenharmony_ci	if (new_tx_count != adapter->tx_ring_count) {
6208c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
6218c2ecf20Sopenharmony_ci			memcpy(&temp_ring[i], adapter->tx_ring[i],
6228c2ecf20Sopenharmony_ci			       sizeof(struct igc_ring));
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci			temp_ring[i].count = new_tx_count;
6258c2ecf20Sopenharmony_ci			err = igc_setup_tx_resources(&temp_ring[i]);
6268c2ecf20Sopenharmony_ci			if (err) {
6278c2ecf20Sopenharmony_ci				while (i) {
6288c2ecf20Sopenharmony_ci					i--;
6298c2ecf20Sopenharmony_ci					igc_free_tx_resources(&temp_ring[i]);
6308c2ecf20Sopenharmony_ci				}
6318c2ecf20Sopenharmony_ci				goto err_setup;
6328c2ecf20Sopenharmony_ci			}
6338c2ecf20Sopenharmony_ci		}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
6368c2ecf20Sopenharmony_ci			igc_free_tx_resources(adapter->tx_ring[i]);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci			memcpy(adapter->tx_ring[i], &temp_ring[i],
6398c2ecf20Sopenharmony_ci			       sizeof(struct igc_ring));
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		adapter->tx_ring_count = new_tx_count;
6438c2ecf20Sopenharmony_ci	}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (new_rx_count != adapter->rx_ring_count) {
6468c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
6478c2ecf20Sopenharmony_ci			memcpy(&temp_ring[i], adapter->rx_ring[i],
6488c2ecf20Sopenharmony_ci			       sizeof(struct igc_ring));
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci			temp_ring[i].count = new_rx_count;
6518c2ecf20Sopenharmony_ci			err = igc_setup_rx_resources(&temp_ring[i]);
6528c2ecf20Sopenharmony_ci			if (err) {
6538c2ecf20Sopenharmony_ci				while (i) {
6548c2ecf20Sopenharmony_ci					i--;
6558c2ecf20Sopenharmony_ci					igc_free_rx_resources(&temp_ring[i]);
6568c2ecf20Sopenharmony_ci				}
6578c2ecf20Sopenharmony_ci				goto err_setup;
6588c2ecf20Sopenharmony_ci			}
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
6628c2ecf20Sopenharmony_ci			igc_free_rx_resources(adapter->rx_ring[i]);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci			memcpy(adapter->rx_ring[i], &temp_ring[i],
6658c2ecf20Sopenharmony_ci			       sizeof(struct igc_ring));
6668c2ecf20Sopenharmony_ci		}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		adapter->rx_ring_count = new_rx_count;
6698c2ecf20Sopenharmony_ci	}
6708c2ecf20Sopenharmony_cierr_setup:
6718c2ecf20Sopenharmony_ci	igc_up(adapter);
6728c2ecf20Sopenharmony_ci	vfree(temp_ring);
6738c2ecf20Sopenharmony_ciclear_reset:
6748c2ecf20Sopenharmony_ci	clear_bit(__IGC_RESETTING, &adapter->state);
6758c2ecf20Sopenharmony_ci	return err;
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic void igc_ethtool_get_pauseparam(struct net_device *netdev,
6798c2ecf20Sopenharmony_ci				       struct ethtool_pauseparam *pause)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
6828c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	pause->autoneg =
6858c2ecf20Sopenharmony_ci		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (hw->fc.current_mode == igc_fc_rx_pause) {
6888c2ecf20Sopenharmony_ci		pause->rx_pause = 1;
6898c2ecf20Sopenharmony_ci	} else if (hw->fc.current_mode == igc_fc_tx_pause) {
6908c2ecf20Sopenharmony_ci		pause->tx_pause = 1;
6918c2ecf20Sopenharmony_ci	} else if (hw->fc.current_mode == igc_fc_full) {
6928c2ecf20Sopenharmony_ci		pause->rx_pause = 1;
6938c2ecf20Sopenharmony_ci		pause->tx_pause = 1;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_cistatic int igc_ethtool_set_pauseparam(struct net_device *netdev,
6988c2ecf20Sopenharmony_ci				      struct ethtool_pauseparam *pause)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
7018c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
7028c2ecf20Sopenharmony_ci	int retval = 0;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	adapter->fc_autoneg = pause->autoneg;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
7078c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
7108c2ecf20Sopenharmony_ci		hw->fc.requested_mode = igc_fc_default;
7118c2ecf20Sopenharmony_ci		if (netif_running(adapter->netdev)) {
7128c2ecf20Sopenharmony_ci			igc_down(adapter);
7138c2ecf20Sopenharmony_ci			igc_up(adapter);
7148c2ecf20Sopenharmony_ci		} else {
7158c2ecf20Sopenharmony_ci			igc_reset(adapter);
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci	} else {
7188c2ecf20Sopenharmony_ci		if (pause->rx_pause && pause->tx_pause)
7198c2ecf20Sopenharmony_ci			hw->fc.requested_mode = igc_fc_full;
7208c2ecf20Sopenharmony_ci		else if (pause->rx_pause && !pause->tx_pause)
7218c2ecf20Sopenharmony_ci			hw->fc.requested_mode = igc_fc_rx_pause;
7228c2ecf20Sopenharmony_ci		else if (!pause->rx_pause && pause->tx_pause)
7238c2ecf20Sopenharmony_ci			hw->fc.requested_mode = igc_fc_tx_pause;
7248c2ecf20Sopenharmony_ci		else if (!pause->rx_pause && !pause->tx_pause)
7258c2ecf20Sopenharmony_ci			hw->fc.requested_mode = igc_fc_none;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		hw->fc.current_mode = hw->fc.requested_mode;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci		retval = ((hw->phy.media_type == igc_media_type_copper) ?
7308c2ecf20Sopenharmony_ci			  igc_force_mac_fc(hw) : igc_setup_link(hw));
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	clear_bit(__IGC_RESETTING, &adapter->state);
7348c2ecf20Sopenharmony_ci	return retval;
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_cistatic void igc_ethtool_get_strings(struct net_device *netdev, u32 stringset,
7388c2ecf20Sopenharmony_ci				    u8 *data)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
7418c2ecf20Sopenharmony_ci	u8 *p = data;
7428c2ecf20Sopenharmony_ci	int i;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	switch (stringset) {
7458c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
7468c2ecf20Sopenharmony_ci		memcpy(data, *igc_gstrings_test,
7478c2ecf20Sopenharmony_ci		       IGC_TEST_LEN * ETH_GSTRING_LEN);
7488c2ecf20Sopenharmony_ci		break;
7498c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
7508c2ecf20Sopenharmony_ci		for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) {
7518c2ecf20Sopenharmony_ci			memcpy(p, igc_gstrings_stats[i].stat_string,
7528c2ecf20Sopenharmony_ci			       ETH_GSTRING_LEN);
7538c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7548c2ecf20Sopenharmony_ci		}
7558c2ecf20Sopenharmony_ci		for (i = 0; i < IGC_NETDEV_STATS_LEN; i++) {
7568c2ecf20Sopenharmony_ci			memcpy(p, igc_gstrings_net_stats[i].stat_string,
7578c2ecf20Sopenharmony_ci			       ETH_GSTRING_LEN);
7588c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7598c2ecf20Sopenharmony_ci		}
7608c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_queues; i++) {
7618c2ecf20Sopenharmony_ci			sprintf(p, "tx_queue_%u_packets", i);
7628c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7638c2ecf20Sopenharmony_ci			sprintf(p, "tx_queue_%u_bytes", i);
7648c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7658c2ecf20Sopenharmony_ci			sprintf(p, "tx_queue_%u_restart", i);
7668c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7678c2ecf20Sopenharmony_ci		}
7688c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_queues; i++) {
7698c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_packets", i);
7708c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7718c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_bytes", i);
7728c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7738c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_drops", i);
7748c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7758c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_csum_err", i);
7768c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7778c2ecf20Sopenharmony_ci			sprintf(p, "rx_queue_%u_alloc_failed", i);
7788c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
7798c2ecf20Sopenharmony_ci		}
7808c2ecf20Sopenharmony_ci		/* BUG_ON(p - data != IGC_STATS_LEN * ETH_GSTRING_LEN); */
7818c2ecf20Sopenharmony_ci		break;
7828c2ecf20Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
7838c2ecf20Sopenharmony_ci		memcpy(data, igc_priv_flags_strings,
7848c2ecf20Sopenharmony_ci		       IGC_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN);
7858c2ecf20Sopenharmony_ci		break;
7868c2ecf20Sopenharmony_ci	}
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic int igc_ethtool_get_sset_count(struct net_device *netdev, int sset)
7908c2ecf20Sopenharmony_ci{
7918c2ecf20Sopenharmony_ci	switch (sset) {
7928c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
7938c2ecf20Sopenharmony_ci		return IGC_STATS_LEN;
7948c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
7958c2ecf20Sopenharmony_ci		return IGC_TEST_LEN;
7968c2ecf20Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
7978c2ecf20Sopenharmony_ci		return IGC_PRIV_FLAGS_STR_LEN;
7988c2ecf20Sopenharmony_ci	default:
7998c2ecf20Sopenharmony_ci		return -ENOTSUPP;
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic void igc_ethtool_get_stats(struct net_device *netdev,
8048c2ecf20Sopenharmony_ci				  struct ethtool_stats *stats, u64 *data)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
8078c2ecf20Sopenharmony_ci	struct rtnl_link_stats64 *net_stats = &adapter->stats64;
8088c2ecf20Sopenharmony_ci	unsigned int start;
8098c2ecf20Sopenharmony_ci	struct igc_ring *ring;
8108c2ecf20Sopenharmony_ci	int i, j;
8118c2ecf20Sopenharmony_ci	char *p;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	spin_lock(&adapter->stats64_lock);
8148c2ecf20Sopenharmony_ci	igc_update_stats(adapter);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) {
8178c2ecf20Sopenharmony_ci		p = (char *)adapter + igc_gstrings_stats[i].stat_offset;
8188c2ecf20Sopenharmony_ci		data[i] = (igc_gstrings_stats[i].sizeof_stat ==
8198c2ecf20Sopenharmony_ci			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci	for (j = 0; j < IGC_NETDEV_STATS_LEN; j++, i++) {
8228c2ecf20Sopenharmony_ci		p = (char *)net_stats + igc_gstrings_net_stats[j].stat_offset;
8238c2ecf20Sopenharmony_ci		data[i] = (igc_gstrings_net_stats[j].sizeof_stat ==
8248c2ecf20Sopenharmony_ci			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci	for (j = 0; j < adapter->num_tx_queues; j++) {
8278c2ecf20Sopenharmony_ci		u64	restart2;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci		ring = adapter->tx_ring[j];
8308c2ecf20Sopenharmony_ci		do {
8318c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
8328c2ecf20Sopenharmony_ci			data[i]   = ring->tx_stats.packets;
8338c2ecf20Sopenharmony_ci			data[i + 1] = ring->tx_stats.bytes;
8348c2ecf20Sopenharmony_ci			data[i + 2] = ring->tx_stats.restart_queue;
8358c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
8368c2ecf20Sopenharmony_ci		do {
8378c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&ring->tx_syncp2);
8388c2ecf20Sopenharmony_ci			restart2  = ring->tx_stats.restart_queue2;
8398c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start));
8408c2ecf20Sopenharmony_ci		data[i + 2] += restart2;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci		i += IGC_TX_QUEUE_STATS_LEN;
8438c2ecf20Sopenharmony_ci	}
8448c2ecf20Sopenharmony_ci	for (j = 0; j < adapter->num_rx_queues; j++) {
8458c2ecf20Sopenharmony_ci		ring = adapter->rx_ring[j];
8468c2ecf20Sopenharmony_ci		do {
8478c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
8488c2ecf20Sopenharmony_ci			data[i]   = ring->rx_stats.packets;
8498c2ecf20Sopenharmony_ci			data[i + 1] = ring->rx_stats.bytes;
8508c2ecf20Sopenharmony_ci			data[i + 2] = ring->rx_stats.drops;
8518c2ecf20Sopenharmony_ci			data[i + 3] = ring->rx_stats.csum_err;
8528c2ecf20Sopenharmony_ci			data[i + 4] = ring->rx_stats.alloc_failed;
8538c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
8548c2ecf20Sopenharmony_ci		i += IGC_RX_QUEUE_STATS_LEN;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci	spin_unlock(&adapter->stats64_lock);
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_cistatic int igc_ethtool_get_coalesce(struct net_device *netdev,
8608c2ecf20Sopenharmony_ci				    struct ethtool_coalesce *ec)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if (adapter->rx_itr_setting <= 3)
8658c2ecf20Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->rx_itr_setting;
8668c2ecf20Sopenharmony_ci	else
8678c2ecf20Sopenharmony_ci		ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	if (!(adapter->flags & IGC_FLAG_QUEUE_PAIRS)) {
8708c2ecf20Sopenharmony_ci		if (adapter->tx_itr_setting <= 3)
8718c2ecf20Sopenharmony_ci			ec->tx_coalesce_usecs = adapter->tx_itr_setting;
8728c2ecf20Sopenharmony_ci		else
8738c2ecf20Sopenharmony_ci			ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	return 0;
8778c2ecf20Sopenharmony_ci}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistatic int igc_ethtool_set_coalesce(struct net_device *netdev,
8808c2ecf20Sopenharmony_ci				    struct ethtool_coalesce *ec)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
8838c2ecf20Sopenharmony_ci	int i;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	if (ec->rx_coalesce_usecs > IGC_MAX_ITR_USECS ||
8868c2ecf20Sopenharmony_ci	    (ec->rx_coalesce_usecs > 3 &&
8878c2ecf20Sopenharmony_ci	     ec->rx_coalesce_usecs < IGC_MIN_ITR_USECS) ||
8888c2ecf20Sopenharmony_ci	    ec->rx_coalesce_usecs == 2)
8898c2ecf20Sopenharmony_ci		return -EINVAL;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	if (ec->tx_coalesce_usecs > IGC_MAX_ITR_USECS ||
8928c2ecf20Sopenharmony_ci	    (ec->tx_coalesce_usecs > 3 &&
8938c2ecf20Sopenharmony_ci	     ec->tx_coalesce_usecs < IGC_MIN_ITR_USECS) ||
8948c2ecf20Sopenharmony_ci	    ec->tx_coalesce_usecs == 2)
8958c2ecf20Sopenharmony_ci		return -EINVAL;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS) && ec->tx_coalesce_usecs)
8988c2ecf20Sopenharmony_ci		return -EINVAL;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	/* If ITR is disabled, disable DMAC */
9018c2ecf20Sopenharmony_ci	if (ec->rx_coalesce_usecs == 0) {
9028c2ecf20Sopenharmony_ci		if (adapter->flags & IGC_FLAG_DMAC)
9038c2ecf20Sopenharmony_ci			adapter->flags &= ~IGC_FLAG_DMAC;
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	/* convert to rate of irq's per second */
9078c2ecf20Sopenharmony_ci	if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3)
9088c2ecf20Sopenharmony_ci		adapter->rx_itr_setting = ec->rx_coalesce_usecs;
9098c2ecf20Sopenharmony_ci	else
9108c2ecf20Sopenharmony_ci		adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/* convert to rate of irq's per second */
9138c2ecf20Sopenharmony_ci	if (adapter->flags & IGC_FLAG_QUEUE_PAIRS)
9148c2ecf20Sopenharmony_ci		adapter->tx_itr_setting = adapter->rx_itr_setting;
9158c2ecf20Sopenharmony_ci	else if (ec->tx_coalesce_usecs && ec->tx_coalesce_usecs <= 3)
9168c2ecf20Sopenharmony_ci		adapter->tx_itr_setting = ec->tx_coalesce_usecs;
9178c2ecf20Sopenharmony_ci	else
9188c2ecf20Sopenharmony_ci		adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->num_q_vectors; i++) {
9218c2ecf20Sopenharmony_ci		struct igc_q_vector *q_vector = adapter->q_vector[i];
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		q_vector->tx.work_limit = adapter->tx_work_limit;
9248c2ecf20Sopenharmony_ci		if (q_vector->rx.ring)
9258c2ecf20Sopenharmony_ci			q_vector->itr_val = adapter->rx_itr_setting;
9268c2ecf20Sopenharmony_ci		else
9278c2ecf20Sopenharmony_ci			q_vector->itr_val = adapter->tx_itr_setting;
9288c2ecf20Sopenharmony_ci		if (q_vector->itr_val && q_vector->itr_val <= 3)
9298c2ecf20Sopenharmony_ci			q_vector->itr_val = IGC_START_ITR;
9308c2ecf20Sopenharmony_ci		q_vector->set_itr = 1;
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	return 0;
9348c2ecf20Sopenharmony_ci}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
9378c2ecf20Sopenharmony_cistatic int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter,
9388c2ecf20Sopenharmony_ci				    struct ethtool_rxnfc *cmd)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp = &cmd->fs;
9418c2ecf20Sopenharmony_ci	struct igc_nfc_rule *rule = NULL;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	cmd->data = IGC_MAX_RXNFC_RULES;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	mutex_lock(&adapter->nfc_rule_lock);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	rule = igc_get_nfc_rule(adapter, fsp->location);
9488c2ecf20Sopenharmony_ci	if (!rule)
9498c2ecf20Sopenharmony_ci		goto out;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	fsp->flow_type = ETHER_FLOW;
9528c2ecf20Sopenharmony_ci	fsp->ring_cookie = rule->action;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
9558c2ecf20Sopenharmony_ci		fsp->h_u.ether_spec.h_proto = htons(rule->filter.etype);
9568c2ecf20Sopenharmony_ci		fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK;
9578c2ecf20Sopenharmony_ci	}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
9608c2ecf20Sopenharmony_ci		fsp->flow_type |= FLOW_EXT;
9618c2ecf20Sopenharmony_ci		fsp->h_ext.vlan_tci = htons(rule->filter.vlan_tci);
9628c2ecf20Sopenharmony_ci		fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK);
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
9668c2ecf20Sopenharmony_ci		ether_addr_copy(fsp->h_u.ether_spec.h_dest,
9678c2ecf20Sopenharmony_ci				rule->filter.dst_addr);
9688c2ecf20Sopenharmony_ci		eth_broadcast_addr(fsp->m_u.ether_spec.h_dest);
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
9728c2ecf20Sopenharmony_ci		ether_addr_copy(fsp->h_u.ether_spec.h_source,
9738c2ecf20Sopenharmony_ci				rule->filter.src_addr);
9748c2ecf20Sopenharmony_ci		eth_broadcast_addr(fsp->m_u.ether_spec.h_source);
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->nfc_rule_lock);
9788c2ecf20Sopenharmony_ci	return 0;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ciout:
9818c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->nfc_rule_lock);
9828c2ecf20Sopenharmony_ci	return -EINVAL;
9838c2ecf20Sopenharmony_ci}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter,
9868c2ecf20Sopenharmony_ci				     struct ethtool_rxnfc *cmd,
9878c2ecf20Sopenharmony_ci				     u32 *rule_locs)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct igc_nfc_rule *rule;
9908c2ecf20Sopenharmony_ci	int cnt = 0;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	cmd->data = IGC_MAX_RXNFC_RULES;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	mutex_lock(&adapter->nfc_rule_lock);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	list_for_each_entry(rule, &adapter->nfc_rule_list, list) {
9978c2ecf20Sopenharmony_ci		if (cnt == cmd->rule_cnt) {
9988c2ecf20Sopenharmony_ci			mutex_unlock(&adapter->nfc_rule_lock);
9998c2ecf20Sopenharmony_ci			return -EMSGSIZE;
10008c2ecf20Sopenharmony_ci		}
10018c2ecf20Sopenharmony_ci		rule_locs[cnt] = rule->location;
10028c2ecf20Sopenharmony_ci		cnt++;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->nfc_rule_lock);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	cmd->rule_cnt = cnt;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	return 0;
10108c2ecf20Sopenharmony_ci}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_cistatic int igc_ethtool_get_rss_hash_opts(struct igc_adapter *adapter,
10138c2ecf20Sopenharmony_ci					 struct ethtool_rxnfc *cmd)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	cmd->data = 0;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/* Report default options for RSS on igc */
10188c2ecf20Sopenharmony_ci	switch (cmd->flow_type) {
10198c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
10208c2ecf20Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10218c2ecf20Sopenharmony_ci		fallthrough;
10228c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
10238c2ecf20Sopenharmony_ci		if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV4_UDP)
10248c2ecf20Sopenharmony_ci			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10258c2ecf20Sopenharmony_ci		fallthrough;
10268c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
10278c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
10288c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
10298c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
10308c2ecf20Sopenharmony_ci	case IPV4_FLOW:
10318c2ecf20Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
10328c2ecf20Sopenharmony_ci		break;
10338c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
10348c2ecf20Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10358c2ecf20Sopenharmony_ci		fallthrough;
10368c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
10378c2ecf20Sopenharmony_ci		if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV6_UDP)
10388c2ecf20Sopenharmony_ci			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10398c2ecf20Sopenharmony_ci		fallthrough;
10408c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
10418c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
10428c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
10438c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
10448c2ecf20Sopenharmony_ci	case IPV6_FLOW:
10458c2ecf20Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
10468c2ecf20Sopenharmony_ci		break;
10478c2ecf20Sopenharmony_ci	default:
10488c2ecf20Sopenharmony_ci		return -EINVAL;
10498c2ecf20Sopenharmony_ci	}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	return 0;
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_cistatic int igc_ethtool_get_rxnfc(struct net_device *dev,
10558c2ecf20Sopenharmony_ci				 struct ethtool_rxnfc *cmd, u32 *rule_locs)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(dev);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
10608c2ecf20Sopenharmony_ci	case ETHTOOL_GRXRINGS:
10618c2ecf20Sopenharmony_ci		cmd->data = adapter->num_rx_queues;
10628c2ecf20Sopenharmony_ci		return 0;
10638c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
10648c2ecf20Sopenharmony_ci		cmd->rule_cnt = adapter->nfc_rule_count;
10658c2ecf20Sopenharmony_ci		return 0;
10668c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
10678c2ecf20Sopenharmony_ci		return igc_ethtool_get_nfc_rule(adapter, cmd);
10688c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
10698c2ecf20Sopenharmony_ci		return igc_ethtool_get_nfc_rules(adapter, cmd, rule_locs);
10708c2ecf20Sopenharmony_ci	case ETHTOOL_GRXFH:
10718c2ecf20Sopenharmony_ci		return igc_ethtool_get_rss_hash_opts(adapter, cmd);
10728c2ecf20Sopenharmony_ci	default:
10738c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci#define UDP_RSS_FLAGS (IGC_FLAG_RSS_FIELD_IPV4_UDP | \
10788c2ecf20Sopenharmony_ci		       IGC_FLAG_RSS_FIELD_IPV6_UDP)
10798c2ecf20Sopenharmony_cistatic int igc_ethtool_set_rss_hash_opt(struct igc_adapter *adapter,
10808c2ecf20Sopenharmony_ci					struct ethtool_rxnfc *nfc)
10818c2ecf20Sopenharmony_ci{
10828c2ecf20Sopenharmony_ci	u32 flags = adapter->flags;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	/* RSS does not support anything other than hashing
10858c2ecf20Sopenharmony_ci	 * to queues on src and dst IPs and ports
10868c2ecf20Sopenharmony_ci	 */
10878c2ecf20Sopenharmony_ci	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
10888c2ecf20Sopenharmony_ci			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
10898c2ecf20Sopenharmony_ci		return -EINVAL;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	switch (nfc->flow_type) {
10928c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
10938c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
10948c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
10958c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST) ||
10968c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_L4_B_0_1) ||
10978c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_L4_B_2_3))
10988c2ecf20Sopenharmony_ci			return -EINVAL;
10998c2ecf20Sopenharmony_ci		break;
11008c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
11018c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
11028c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST))
11038c2ecf20Sopenharmony_ci			return -EINVAL;
11048c2ecf20Sopenharmony_ci		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
11058c2ecf20Sopenharmony_ci		case 0:
11068c2ecf20Sopenharmony_ci			flags &= ~IGC_FLAG_RSS_FIELD_IPV4_UDP;
11078c2ecf20Sopenharmony_ci			break;
11088c2ecf20Sopenharmony_ci		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
11098c2ecf20Sopenharmony_ci			flags |= IGC_FLAG_RSS_FIELD_IPV4_UDP;
11108c2ecf20Sopenharmony_ci			break;
11118c2ecf20Sopenharmony_ci		default:
11128c2ecf20Sopenharmony_ci			return -EINVAL;
11138c2ecf20Sopenharmony_ci		}
11148c2ecf20Sopenharmony_ci		break;
11158c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
11168c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
11178c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST))
11188c2ecf20Sopenharmony_ci			return -EINVAL;
11198c2ecf20Sopenharmony_ci		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
11208c2ecf20Sopenharmony_ci		case 0:
11218c2ecf20Sopenharmony_ci			flags &= ~IGC_FLAG_RSS_FIELD_IPV6_UDP;
11228c2ecf20Sopenharmony_ci			break;
11238c2ecf20Sopenharmony_ci		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
11248c2ecf20Sopenharmony_ci			flags |= IGC_FLAG_RSS_FIELD_IPV6_UDP;
11258c2ecf20Sopenharmony_ci			break;
11268c2ecf20Sopenharmony_ci		default:
11278c2ecf20Sopenharmony_ci			return -EINVAL;
11288c2ecf20Sopenharmony_ci		}
11298c2ecf20Sopenharmony_ci		break;
11308c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
11318c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
11328c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
11338c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
11348c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
11358c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
11368c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
11378c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
11388c2ecf20Sopenharmony_ci		if (!(nfc->data & RXH_IP_SRC) ||
11398c2ecf20Sopenharmony_ci		    !(nfc->data & RXH_IP_DST) ||
11408c2ecf20Sopenharmony_ci		    (nfc->data & RXH_L4_B_0_1) ||
11418c2ecf20Sopenharmony_ci		    (nfc->data & RXH_L4_B_2_3))
11428c2ecf20Sopenharmony_ci			return -EINVAL;
11438c2ecf20Sopenharmony_ci		break;
11448c2ecf20Sopenharmony_ci	default:
11458c2ecf20Sopenharmony_ci		return -EINVAL;
11468c2ecf20Sopenharmony_ci	}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	/* if we changed something we need to update flags */
11498c2ecf20Sopenharmony_ci	if (flags != adapter->flags) {
11508c2ecf20Sopenharmony_ci		struct igc_hw *hw = &adapter->hw;
11518c2ecf20Sopenharmony_ci		u32 mrqc = rd32(IGC_MRQC);
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci		if ((flags & UDP_RSS_FLAGS) &&
11548c2ecf20Sopenharmony_ci		    !(adapter->flags & UDP_RSS_FLAGS))
11558c2ecf20Sopenharmony_ci			netdev_err(adapter->netdev,
11568c2ecf20Sopenharmony_ci				   "Enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci		adapter->flags = flags;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci		/* Perform hash on these packet types */
11618c2ecf20Sopenharmony_ci		mrqc |= IGC_MRQC_RSS_FIELD_IPV4 |
11628c2ecf20Sopenharmony_ci			IGC_MRQC_RSS_FIELD_IPV4_TCP |
11638c2ecf20Sopenharmony_ci			IGC_MRQC_RSS_FIELD_IPV6 |
11648c2ecf20Sopenharmony_ci			IGC_MRQC_RSS_FIELD_IPV6_TCP;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci		mrqc &= ~(IGC_MRQC_RSS_FIELD_IPV4_UDP |
11678c2ecf20Sopenharmony_ci			  IGC_MRQC_RSS_FIELD_IPV6_UDP);
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci		if (flags & IGC_FLAG_RSS_FIELD_IPV4_UDP)
11708c2ecf20Sopenharmony_ci			mrqc |= IGC_MRQC_RSS_FIELD_IPV4_UDP;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci		if (flags & IGC_FLAG_RSS_FIELD_IPV6_UDP)
11738c2ecf20Sopenharmony_ci			mrqc |= IGC_MRQC_RSS_FIELD_IPV6_UDP;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci		wr32(IGC_MRQC, mrqc);
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	return 0;
11798c2ecf20Sopenharmony_ci}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_cistatic void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule,
11828c2ecf20Sopenharmony_ci				      const struct ethtool_rx_flow_spec *fsp)
11838c2ecf20Sopenharmony_ci{
11848c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rule->list);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	rule->action = fsp->ring_cookie;
11878c2ecf20Sopenharmony_ci	rule->location = fsp->location;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) {
11908c2ecf20Sopenharmony_ci		rule->filter.vlan_tci = ntohs(fsp->h_ext.vlan_tci);
11918c2ecf20Sopenharmony_ci		rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI;
11928c2ecf20Sopenharmony_ci	}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) {
11958c2ecf20Sopenharmony_ci		rule->filter.etype = ntohs(fsp->h_u.ether_spec.h_proto);
11968c2ecf20Sopenharmony_ci		rule->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE;
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	/* Both source and destination address filters only support the full
12008c2ecf20Sopenharmony_ci	 * mask.
12018c2ecf20Sopenharmony_ci	 */
12028c2ecf20Sopenharmony_ci	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) {
12038c2ecf20Sopenharmony_ci		rule->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR;
12048c2ecf20Sopenharmony_ci		ether_addr_copy(rule->filter.src_addr,
12058c2ecf20Sopenharmony_ci				fsp->h_u.ether_spec.h_source);
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) {
12098c2ecf20Sopenharmony_ci		rule->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR;
12108c2ecf20Sopenharmony_ci		ether_addr_copy(rule->filter.dst_addr,
12118c2ecf20Sopenharmony_ci				fsp->h_u.ether_spec.h_dest);
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci/**
12168c2ecf20Sopenharmony_ci * igc_ethtool_check_nfc_rule() - Check if NFC rule is valid
12178c2ecf20Sopenharmony_ci * @adapter: Pointer to adapter
12188c2ecf20Sopenharmony_ci * @rule: Rule under evaluation
12198c2ecf20Sopenharmony_ci *
12208c2ecf20Sopenharmony_ci * The driver doesn't support rules with multiple matches so if more than
12218c2ecf20Sopenharmony_ci * one bit in filter flags is set, @rule is considered invalid.
12228c2ecf20Sopenharmony_ci *
12238c2ecf20Sopenharmony_ci * Also, if there is already another rule with the same filter in a different
12248c2ecf20Sopenharmony_ci * location, @rule is considered invalid.
12258c2ecf20Sopenharmony_ci *
12268c2ecf20Sopenharmony_ci * Context: Expects adapter->nfc_rule_lock to be held by caller.
12278c2ecf20Sopenharmony_ci *
12288c2ecf20Sopenharmony_ci * Return: 0 in case of success, negative errno code otherwise.
12298c2ecf20Sopenharmony_ci */
12308c2ecf20Sopenharmony_cistatic int igc_ethtool_check_nfc_rule(struct igc_adapter *adapter,
12318c2ecf20Sopenharmony_ci				      struct igc_nfc_rule *rule)
12328c2ecf20Sopenharmony_ci{
12338c2ecf20Sopenharmony_ci	struct net_device *dev = adapter->netdev;
12348c2ecf20Sopenharmony_ci	u8 flags = rule->filter.match_flags;
12358c2ecf20Sopenharmony_ci	struct igc_nfc_rule *tmp;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (!flags) {
12388c2ecf20Sopenharmony_ci		netdev_dbg(dev, "Rule with no match\n");
12398c2ecf20Sopenharmony_ci		return -EINVAL;
12408c2ecf20Sopenharmony_ci	}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	if (flags & (flags - 1)) {
12438c2ecf20Sopenharmony_ci		netdev_dbg(dev, "Rule with multiple matches not supported\n");
12448c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12458c2ecf20Sopenharmony_ci	}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &adapter->nfc_rule_list, list) {
12488c2ecf20Sopenharmony_ci		if (!memcmp(&rule->filter, &tmp->filter,
12498c2ecf20Sopenharmony_ci			    sizeof(rule->filter)) &&
12508c2ecf20Sopenharmony_ci		    tmp->location != rule->location) {
12518c2ecf20Sopenharmony_ci			netdev_dbg(dev, "Rule already exists\n");
12528c2ecf20Sopenharmony_ci			return -EEXIST;
12538c2ecf20Sopenharmony_ci		}
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	return 0;
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_cistatic int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter,
12608c2ecf20Sopenharmony_ci				    struct ethtool_rxnfc *cmd)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
12638c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp =
12648c2ecf20Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
12658c2ecf20Sopenharmony_ci	struct igc_nfc_rule *rule, *old_rule;
12668c2ecf20Sopenharmony_ci	int err;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	if (!(netdev->hw_features & NETIF_F_NTUPLE)) {
12698c2ecf20Sopenharmony_ci		netdev_dbg(netdev, "N-tuple filters disabled\n");
12708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12718c2ecf20Sopenharmony_ci	}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) {
12748c2ecf20Sopenharmony_ci		netdev_dbg(netdev, "Only ethernet flow type is supported\n");
12758c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if ((fsp->flow_type & FLOW_EXT) &&
12798c2ecf20Sopenharmony_ci	    fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) {
12808c2ecf20Sopenharmony_ci		netdev_dbg(netdev, "VLAN mask not supported\n");
12818c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	if (fsp->ring_cookie >= adapter->num_rx_queues) {
12858c2ecf20Sopenharmony_ci		netdev_dbg(netdev, "Invalid action\n");
12868c2ecf20Sopenharmony_ci		return -EINVAL;
12878c2ecf20Sopenharmony_ci	}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	if (fsp->location >= IGC_MAX_RXNFC_RULES) {
12908c2ecf20Sopenharmony_ci		netdev_dbg(netdev, "Invalid location\n");
12918c2ecf20Sopenharmony_ci		return -EINVAL;
12928c2ecf20Sopenharmony_ci	}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
12958c2ecf20Sopenharmony_ci	if (!rule)
12968c2ecf20Sopenharmony_ci		return -ENOMEM;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	igc_ethtool_init_nfc_rule(rule, fsp);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	mutex_lock(&adapter->nfc_rule_lock);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	err = igc_ethtool_check_nfc_rule(adapter, rule);
13038c2ecf20Sopenharmony_ci	if (err)
13048c2ecf20Sopenharmony_ci		goto err;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	old_rule = igc_get_nfc_rule(adapter, fsp->location);
13078c2ecf20Sopenharmony_ci	if (old_rule)
13088c2ecf20Sopenharmony_ci		igc_del_nfc_rule(adapter, old_rule);
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	err = igc_add_nfc_rule(adapter, rule);
13118c2ecf20Sopenharmony_ci	if (err)
13128c2ecf20Sopenharmony_ci		goto err;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->nfc_rule_lock);
13158c2ecf20Sopenharmony_ci	return 0;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_cierr:
13188c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->nfc_rule_lock);
13198c2ecf20Sopenharmony_ci	kfree(rule);
13208c2ecf20Sopenharmony_ci	return err;
13218c2ecf20Sopenharmony_ci}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter,
13248c2ecf20Sopenharmony_ci				    struct ethtool_rxnfc *cmd)
13258c2ecf20Sopenharmony_ci{
13268c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp =
13278c2ecf20Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
13288c2ecf20Sopenharmony_ci	struct igc_nfc_rule *rule;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	mutex_lock(&adapter->nfc_rule_lock);
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	rule = igc_get_nfc_rule(adapter, fsp->location);
13338c2ecf20Sopenharmony_ci	if (!rule) {
13348c2ecf20Sopenharmony_ci		mutex_unlock(&adapter->nfc_rule_lock);
13358c2ecf20Sopenharmony_ci		return -EINVAL;
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	igc_del_nfc_rule(adapter, rule);
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->nfc_rule_lock);
13418c2ecf20Sopenharmony_ci	return 0;
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_cistatic int igc_ethtool_set_rxnfc(struct net_device *dev,
13458c2ecf20Sopenharmony_ci				 struct ethtool_rxnfc *cmd)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(dev);
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
13508c2ecf20Sopenharmony_ci	case ETHTOOL_SRXFH:
13518c2ecf20Sopenharmony_ci		return igc_ethtool_set_rss_hash_opt(adapter, cmd);
13528c2ecf20Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
13538c2ecf20Sopenharmony_ci		return igc_ethtool_add_nfc_rule(adapter, cmd);
13548c2ecf20Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
13558c2ecf20Sopenharmony_ci		return igc_ethtool_del_nfc_rule(adapter, cmd);
13568c2ecf20Sopenharmony_ci	default:
13578c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13588c2ecf20Sopenharmony_ci	}
13598c2ecf20Sopenharmony_ci}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_civoid igc_write_rss_indir_tbl(struct igc_adapter *adapter)
13628c2ecf20Sopenharmony_ci{
13638c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
13648c2ecf20Sopenharmony_ci	u32 reg = IGC_RETA(0);
13658c2ecf20Sopenharmony_ci	u32 shift = 0;
13668c2ecf20Sopenharmony_ci	int i = 0;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	while (i < IGC_RETA_SIZE) {
13698c2ecf20Sopenharmony_ci		u32 val = 0;
13708c2ecf20Sopenharmony_ci		int j;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci		for (j = 3; j >= 0; j--) {
13738c2ecf20Sopenharmony_ci			val <<= 8;
13748c2ecf20Sopenharmony_ci			val |= adapter->rss_indir_tbl[i + j];
13758c2ecf20Sopenharmony_ci		}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci		wr32(reg, val << shift);
13788c2ecf20Sopenharmony_ci		reg += 4;
13798c2ecf20Sopenharmony_ci		i += 4;
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_cistatic u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
13848c2ecf20Sopenharmony_ci{
13858c2ecf20Sopenharmony_ci	return IGC_RETA_SIZE;
13868c2ecf20Sopenharmony_ci}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_cistatic int igc_ethtool_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
13898c2ecf20Sopenharmony_ci				u8 *hfunc)
13908c2ecf20Sopenharmony_ci{
13918c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
13928c2ecf20Sopenharmony_ci	int i;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if (hfunc)
13958c2ecf20Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
13968c2ecf20Sopenharmony_ci	if (!indir)
13978c2ecf20Sopenharmony_ci		return 0;
13988c2ecf20Sopenharmony_ci	for (i = 0; i < IGC_RETA_SIZE; i++)
13998c2ecf20Sopenharmony_ci		indir[i] = adapter->rss_indir_tbl[i];
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	return 0;
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic int igc_ethtool_set_rxfh(struct net_device *netdev, const u32 *indir,
14058c2ecf20Sopenharmony_ci				const u8 *key, const u8 hfunc)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
14088c2ecf20Sopenharmony_ci	u32 num_queues;
14098c2ecf20Sopenharmony_ci	int i;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	/* We do not allow change in unsupported parameters */
14128c2ecf20Sopenharmony_ci	if (key ||
14138c2ecf20Sopenharmony_ci	    (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
14148c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14158c2ecf20Sopenharmony_ci	if (!indir)
14168c2ecf20Sopenharmony_ci		return 0;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	num_queues = adapter->rss_queues;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	/* Verify user input. */
14218c2ecf20Sopenharmony_ci	for (i = 0; i < IGC_RETA_SIZE; i++)
14228c2ecf20Sopenharmony_ci		if (indir[i] >= num_queues)
14238c2ecf20Sopenharmony_ci			return -EINVAL;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	for (i = 0; i < IGC_RETA_SIZE; i++)
14268c2ecf20Sopenharmony_ci		adapter->rss_indir_tbl[i] = indir[i];
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	igc_write_rss_indir_tbl(adapter);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	return 0;
14318c2ecf20Sopenharmony_ci}
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_cistatic void igc_ethtool_get_channels(struct net_device *netdev,
14348c2ecf20Sopenharmony_ci				     struct ethtool_channels *ch)
14358c2ecf20Sopenharmony_ci{
14368c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	/* Report maximum channels */
14398c2ecf20Sopenharmony_ci	ch->max_combined = igc_get_max_rss_queues(adapter);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	/* Report info for other vector */
14428c2ecf20Sopenharmony_ci	if (adapter->flags & IGC_FLAG_HAS_MSIX) {
14438c2ecf20Sopenharmony_ci		ch->max_other = NON_Q_VECTORS;
14448c2ecf20Sopenharmony_ci		ch->other_count = NON_Q_VECTORS;
14458c2ecf20Sopenharmony_ci	}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	ch->combined_count = adapter->rss_queues;
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic int igc_ethtool_set_channels(struct net_device *netdev,
14518c2ecf20Sopenharmony_ci				    struct ethtool_channels *ch)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
14548c2ecf20Sopenharmony_ci	unsigned int count = ch->combined_count;
14558c2ecf20Sopenharmony_ci	unsigned int max_combined = 0;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	/* Verify they are not requesting separate vectors */
14588c2ecf20Sopenharmony_ci	if (!count || ch->rx_count || ch->tx_count)
14598c2ecf20Sopenharmony_ci		return -EINVAL;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	/* Verify other_count is valid and has not been changed */
14628c2ecf20Sopenharmony_ci	if (ch->other_count != NON_Q_VECTORS)
14638c2ecf20Sopenharmony_ci		return -EINVAL;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	/* Verify the number of channels doesn't exceed hw limits */
14668c2ecf20Sopenharmony_ci	max_combined = igc_get_max_rss_queues(adapter);
14678c2ecf20Sopenharmony_ci	if (count > max_combined)
14688c2ecf20Sopenharmony_ci		return -EINVAL;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	if (count != adapter->rss_queues) {
14718c2ecf20Sopenharmony_ci		adapter->rss_queues = count;
14728c2ecf20Sopenharmony_ci		igc_set_flag_queue_pairs(adapter, max_combined);
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci		/* Hardware has to reinitialize queues and interrupts to
14758c2ecf20Sopenharmony_ci		 * match the new configuration.
14768c2ecf20Sopenharmony_ci		 */
14778c2ecf20Sopenharmony_ci		return igc_reinit_queues(adapter);
14788c2ecf20Sopenharmony_ci	}
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	return 0;
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_cistatic int igc_ethtool_get_ts_info(struct net_device *dev,
14848c2ecf20Sopenharmony_ci				   struct ethtool_ts_info *info)
14858c2ecf20Sopenharmony_ci{
14868c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(dev);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	if (adapter->ptp_clock)
14898c2ecf20Sopenharmony_ci		info->phc_index = ptp_clock_index(adapter->ptp_clock);
14908c2ecf20Sopenharmony_ci	else
14918c2ecf20Sopenharmony_ci		info->phc_index = -1;
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	switch (adapter->hw.mac.type) {
14948c2ecf20Sopenharmony_ci	case igc_i225:
14958c2ecf20Sopenharmony_ci		info->so_timestamping =
14968c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_TX_SOFTWARE |
14978c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_RX_SOFTWARE |
14988c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_SOFTWARE |
14998c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_TX_HARDWARE |
15008c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_RX_HARDWARE |
15018c2ecf20Sopenharmony_ci			SOF_TIMESTAMPING_RAW_HARDWARE;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci		info->tx_types =
15048c2ecf20Sopenharmony_ci			BIT(HWTSTAMP_TX_OFF) |
15058c2ecf20Sopenharmony_ci			BIT(HWTSTAMP_TX_ON);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci		info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
15088c2ecf20Sopenharmony_ci		info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci		return 0;
15118c2ecf20Sopenharmony_ci	default:
15128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15138c2ecf20Sopenharmony_ci	}
15148c2ecf20Sopenharmony_ci}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_cistatic u32 igc_ethtool_get_priv_flags(struct net_device *netdev)
15178c2ecf20Sopenharmony_ci{
15188c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
15198c2ecf20Sopenharmony_ci	u32 priv_flags = 0;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	if (adapter->flags & IGC_FLAG_RX_LEGACY)
15228c2ecf20Sopenharmony_ci		priv_flags |= IGC_PRIV_FLAGS_LEGACY_RX;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	return priv_flags;
15258c2ecf20Sopenharmony_ci}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_cistatic int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags)
15288c2ecf20Sopenharmony_ci{
15298c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
15308c2ecf20Sopenharmony_ci	unsigned int flags = adapter->flags;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	flags &= ~IGC_FLAG_RX_LEGACY;
15338c2ecf20Sopenharmony_ci	if (priv_flags & IGC_PRIV_FLAGS_LEGACY_RX)
15348c2ecf20Sopenharmony_ci		flags |= IGC_FLAG_RX_LEGACY;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	if (flags != adapter->flags) {
15378c2ecf20Sopenharmony_ci		adapter->flags = flags;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci		/* reset interface to repopulate queues */
15408c2ecf20Sopenharmony_ci		if (netif_running(netdev))
15418c2ecf20Sopenharmony_ci			igc_reinit_locked(adapter);
15428c2ecf20Sopenharmony_ci	}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	return 0;
15458c2ecf20Sopenharmony_ci}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_cistatic int igc_ethtool_get_eee(struct net_device *netdev,
15488c2ecf20Sopenharmony_ci			       struct ethtool_eee *edata)
15498c2ecf20Sopenharmony_ci{
15508c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
15518c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
15528c2ecf20Sopenharmony_ci	u32 eeer;
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	if (hw->dev_spec._base.eee_enable)
15558c2ecf20Sopenharmony_ci		edata->advertised =
15568c2ecf20Sopenharmony_ci			mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	*edata = adapter->eee;
15598c2ecf20Sopenharmony_ci	edata->supported = SUPPORTED_Autoneg;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	eeer = rd32(IGC_EEER);
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	/* EEE status on negotiated link */
15648c2ecf20Sopenharmony_ci	if (eeer & IGC_EEER_EEE_NEG)
15658c2ecf20Sopenharmony_ci		edata->eee_active = true;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	if (eeer & IGC_EEER_TX_LPI_EN)
15688c2ecf20Sopenharmony_ci		edata->tx_lpi_enabled = true;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	edata->eee_enabled = hw->dev_spec._base.eee_enable;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	edata->advertised = SUPPORTED_Autoneg;
15738c2ecf20Sopenharmony_ci	edata->lp_advertised = SUPPORTED_Autoneg;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	/* Report correct negotiated EEE status for devices that
15768c2ecf20Sopenharmony_ci	 * wrongly report EEE at half-duplex
15778c2ecf20Sopenharmony_ci	 */
15788c2ecf20Sopenharmony_ci	if (adapter->link_duplex == HALF_DUPLEX) {
15798c2ecf20Sopenharmony_ci		edata->eee_enabled = false;
15808c2ecf20Sopenharmony_ci		edata->eee_active = false;
15818c2ecf20Sopenharmony_ci		edata->tx_lpi_enabled = false;
15828c2ecf20Sopenharmony_ci		edata->advertised &= ~edata->advertised;
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	return 0;
15868c2ecf20Sopenharmony_ci}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_cistatic int igc_ethtool_set_eee(struct net_device *netdev,
15898c2ecf20Sopenharmony_ci			       struct ethtool_eee *edata)
15908c2ecf20Sopenharmony_ci{
15918c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
15928c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
15938c2ecf20Sopenharmony_ci	struct ethtool_eee eee_curr;
15948c2ecf20Sopenharmony_ci	s32 ret_val;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	memset(&eee_curr, 0, sizeof(struct ethtool_eee));
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	ret_val = igc_ethtool_get_eee(netdev, &eee_curr);
15998c2ecf20Sopenharmony_ci	if (ret_val) {
16008c2ecf20Sopenharmony_ci		netdev_err(netdev,
16018c2ecf20Sopenharmony_ci			   "Problem setting EEE advertisement options\n");
16028c2ecf20Sopenharmony_ci		return -EINVAL;
16038c2ecf20Sopenharmony_ci	}
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	if (eee_curr.eee_enabled) {
16068c2ecf20Sopenharmony_ci		if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
16078c2ecf20Sopenharmony_ci			netdev_err(netdev,
16088c2ecf20Sopenharmony_ci				   "Setting EEE tx-lpi is not supported\n");
16098c2ecf20Sopenharmony_ci			return -EINVAL;
16108c2ecf20Sopenharmony_ci		}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci		/* Tx LPI timer is not implemented currently */
16138c2ecf20Sopenharmony_ci		if (edata->tx_lpi_timer) {
16148c2ecf20Sopenharmony_ci			netdev_err(netdev,
16158c2ecf20Sopenharmony_ci				   "Setting EEE Tx LPI timer is not supported\n");
16168c2ecf20Sopenharmony_ci			return -EINVAL;
16178c2ecf20Sopenharmony_ci		}
16188c2ecf20Sopenharmony_ci	} else if (!edata->eee_enabled) {
16198c2ecf20Sopenharmony_ci		netdev_err(netdev,
16208c2ecf20Sopenharmony_ci			   "Setting EEE options are not supported with EEE disabled\n");
16218c2ecf20Sopenharmony_ci		return -EINVAL;
16228c2ecf20Sopenharmony_ci	}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
16258c2ecf20Sopenharmony_ci	if (hw->dev_spec._base.eee_enable != edata->eee_enabled) {
16268c2ecf20Sopenharmony_ci		hw->dev_spec._base.eee_enable = edata->eee_enabled;
16278c2ecf20Sopenharmony_ci		adapter->flags |= IGC_FLAG_EEE;
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci		/* reset link */
16308c2ecf20Sopenharmony_ci		if (netif_running(netdev))
16318c2ecf20Sopenharmony_ci			igc_reinit_locked(adapter);
16328c2ecf20Sopenharmony_ci		else
16338c2ecf20Sopenharmony_ci			igc_reset(adapter);
16348c2ecf20Sopenharmony_ci	}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	return 0;
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_cistatic int igc_ethtool_begin(struct net_device *netdev)
16408c2ecf20Sopenharmony_ci{
16418c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&adapter->pdev->dev);
16448c2ecf20Sopenharmony_ci	return 0;
16458c2ecf20Sopenharmony_ci}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_cistatic void igc_ethtool_complete(struct net_device *netdev)
16488c2ecf20Sopenharmony_ci{
16498c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	pm_runtime_put(&adapter->pdev->dev);
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic int igc_ethtool_get_link_ksettings(struct net_device *netdev,
16558c2ecf20Sopenharmony_ci					  struct ethtool_link_ksettings *cmd)
16568c2ecf20Sopenharmony_ci{
16578c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
16588c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
16598c2ecf20Sopenharmony_ci	u32 status;
16608c2ecf20Sopenharmony_ci	u32 speed;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(cmd, supported);
16638c2ecf20Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci	/* supported link modes */
16668c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
16678c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Full);
16688c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Half);
16698c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Full);
16708c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full);
16718c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, 2500baseT_Full);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	/* twisted pair */
16748c2ecf20Sopenharmony_ci	cmd->base.port = PORT_TP;
16758c2ecf20Sopenharmony_ci	cmd->base.phy_address = hw->phy.addr;
16768c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
16778c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	/* advertising link modes */
16808c2ecf20Sopenharmony_ci	if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
16818c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
16828c2ecf20Sopenharmony_ci	if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
16838c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
16848c2ecf20Sopenharmony_ci	if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
16858c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
16868c2ecf20Sopenharmony_ci	if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
16878c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
16888c2ecf20Sopenharmony_ci	if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
16898c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
16908c2ecf20Sopenharmony_ci	if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
16918c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	/* set autoneg settings */
16948c2ecf20Sopenharmony_ci	if (hw->mac.autoneg == 1) {
16958c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
16968c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
16978c2ecf20Sopenharmony_ci						     Autoneg);
16988c2ecf20Sopenharmony_ci	}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	/* Set pause flow control settings */
17018c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	switch (hw->fc.requested_mode) {
17048c2ecf20Sopenharmony_ci	case igc_fc_full:
17058c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
17068c2ecf20Sopenharmony_ci		break;
17078c2ecf20Sopenharmony_ci	case igc_fc_rx_pause:
17088c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
17098c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
17108c2ecf20Sopenharmony_ci						     Asym_Pause);
17118c2ecf20Sopenharmony_ci		break;
17128c2ecf20Sopenharmony_ci	case igc_fc_tx_pause:
17138c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(cmd, advertising,
17148c2ecf20Sopenharmony_ci						     Asym_Pause);
17158c2ecf20Sopenharmony_ci		break;
17168c2ecf20Sopenharmony_ci	default:
17178c2ecf20Sopenharmony_ci		break;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	status = pm_runtime_suspended(&adapter->pdev->dev) ?
17218c2ecf20Sopenharmony_ci		 0 : rd32(IGC_STATUS);
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	if (status & IGC_STATUS_LU) {
17248c2ecf20Sopenharmony_ci		if (status & IGC_STATUS_SPEED_1000) {
17258c2ecf20Sopenharmony_ci			/* For I225, STATUS will indicate 1G speed in both
17268c2ecf20Sopenharmony_ci			 * 1 Gbps and 2.5 Gbps link modes.
17278c2ecf20Sopenharmony_ci			 * An additional bit is used
17288c2ecf20Sopenharmony_ci			 * to differentiate between 1 Gbps and 2.5 Gbps.
17298c2ecf20Sopenharmony_ci			 */
17308c2ecf20Sopenharmony_ci			if (hw->mac.type == igc_i225 &&
17318c2ecf20Sopenharmony_ci			    (status & IGC_STATUS_SPEED_2500)) {
17328c2ecf20Sopenharmony_ci				speed = SPEED_2500;
17338c2ecf20Sopenharmony_ci			} else {
17348c2ecf20Sopenharmony_ci				speed = SPEED_1000;
17358c2ecf20Sopenharmony_ci			}
17368c2ecf20Sopenharmony_ci		} else if (status & IGC_STATUS_SPEED_100) {
17378c2ecf20Sopenharmony_ci			speed = SPEED_100;
17388c2ecf20Sopenharmony_ci		} else {
17398c2ecf20Sopenharmony_ci			speed = SPEED_10;
17408c2ecf20Sopenharmony_ci		}
17418c2ecf20Sopenharmony_ci		if ((status & IGC_STATUS_FD) ||
17428c2ecf20Sopenharmony_ci		    hw->phy.media_type != igc_media_type_copper)
17438c2ecf20Sopenharmony_ci			cmd->base.duplex = DUPLEX_FULL;
17448c2ecf20Sopenharmony_ci		else
17458c2ecf20Sopenharmony_ci			cmd->base.duplex = DUPLEX_HALF;
17468c2ecf20Sopenharmony_ci	} else {
17478c2ecf20Sopenharmony_ci		speed = SPEED_UNKNOWN;
17488c2ecf20Sopenharmony_ci		cmd->base.duplex = DUPLEX_UNKNOWN;
17498c2ecf20Sopenharmony_ci	}
17508c2ecf20Sopenharmony_ci	cmd->base.speed = speed;
17518c2ecf20Sopenharmony_ci	if (hw->mac.autoneg)
17528c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_ENABLE;
17538c2ecf20Sopenharmony_ci	else
17548c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_DISABLE;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	/* MDI-X => 2; MDI =>1; Invalid =>0 */
17578c2ecf20Sopenharmony_ci	if (hw->phy.media_type == igc_media_type_copper)
17588c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
17598c2ecf20Sopenharmony_ci						      ETH_TP_MDI;
17608c2ecf20Sopenharmony_ci	else
17618c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	if (hw->phy.mdix == AUTO_ALL_MODES)
17648c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
17658c2ecf20Sopenharmony_ci	else
17668c2ecf20Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = hw->phy.mdix;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	return 0;
17698c2ecf20Sopenharmony_ci}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_cistatic int
17728c2ecf20Sopenharmony_ciigc_ethtool_set_link_ksettings(struct net_device *netdev,
17738c2ecf20Sopenharmony_ci			       const struct ethtool_link_ksettings *cmd)
17748c2ecf20Sopenharmony_ci{
17758c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
17768c2ecf20Sopenharmony_ci	struct net_device *dev = adapter->netdev;
17778c2ecf20Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
17788c2ecf20Sopenharmony_ci	u16 advertised = 0;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	/* When adapter in resetting mode, autoneg/speed/duplex
17818c2ecf20Sopenharmony_ci	 * cannot be changed
17828c2ecf20Sopenharmony_ci	 */
17838c2ecf20Sopenharmony_ci	if (igc_check_reset_block(hw)) {
17848c2ecf20Sopenharmony_ci		netdev_err(dev, "Cannot change link characteristics when reset is active\n");
17858c2ecf20Sopenharmony_ci		return -EINVAL;
17868c2ecf20Sopenharmony_ci	}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	/* MDI setting is only allowed when autoneg enabled because
17898c2ecf20Sopenharmony_ci	 * some hardware doesn't allow MDI setting when speed or
17908c2ecf20Sopenharmony_ci	 * duplex is forced.
17918c2ecf20Sopenharmony_ci	 */
17928c2ecf20Sopenharmony_ci	if (cmd->base.eth_tp_mdix_ctrl) {
17938c2ecf20Sopenharmony_ci		if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
17948c2ecf20Sopenharmony_ci		    cmd->base.autoneg != AUTONEG_ENABLE) {
17958c2ecf20Sopenharmony_ci			netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
17968c2ecf20Sopenharmony_ci			return -EINVAL;
17978c2ecf20Sopenharmony_ci		}
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
18018c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
18048c2ecf20Sopenharmony_ci						  2500baseT_Full))
18058c2ecf20Sopenharmony_ci		advertised |= ADVERTISE_2500_FULL;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
18088c2ecf20Sopenharmony_ci						  1000baseT_Full))
18098c2ecf20Sopenharmony_ci		advertised |= ADVERTISE_1000_FULL;
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
18128c2ecf20Sopenharmony_ci						  100baseT_Full))
18138c2ecf20Sopenharmony_ci		advertised |= ADVERTISE_100_FULL;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
18168c2ecf20Sopenharmony_ci						  100baseT_Half))
18178c2ecf20Sopenharmony_ci		advertised |= ADVERTISE_100_HALF;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
18208c2ecf20Sopenharmony_ci						  10baseT_Full))
18218c2ecf20Sopenharmony_ci		advertised |= ADVERTISE_10_FULL;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
18248c2ecf20Sopenharmony_ci						  10baseT_Half))
18258c2ecf20Sopenharmony_ci		advertised |= ADVERTISE_10_HALF;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	if (cmd->base.autoneg == AUTONEG_ENABLE) {
18288c2ecf20Sopenharmony_ci		hw->mac.autoneg = 1;
18298c2ecf20Sopenharmony_ci		hw->phy.autoneg_advertised = advertised;
18308c2ecf20Sopenharmony_ci		if (adapter->fc_autoneg)
18318c2ecf20Sopenharmony_ci			hw->fc.requested_mode = igc_fc_default;
18328c2ecf20Sopenharmony_ci	} else {
18338c2ecf20Sopenharmony_ci		netdev_info(dev, "Force mode currently not supported\n");
18348c2ecf20Sopenharmony_ci	}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	/* MDI-X => 2; MDI => 1; Auto => 3 */
18378c2ecf20Sopenharmony_ci	if (cmd->base.eth_tp_mdix_ctrl) {
18388c2ecf20Sopenharmony_ci		/* fix up the value for auto (3 => 0) as zero is mapped
18398c2ecf20Sopenharmony_ci		 * internally to auto
18408c2ecf20Sopenharmony_ci		 */
18418c2ecf20Sopenharmony_ci		if (cmd->base.eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO)
18428c2ecf20Sopenharmony_ci			hw->phy.mdix = AUTO_ALL_MODES;
18438c2ecf20Sopenharmony_ci		else
18448c2ecf20Sopenharmony_ci			hw->phy.mdix = cmd->base.eth_tp_mdix_ctrl;
18458c2ecf20Sopenharmony_ci	}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	/* reset the link */
18488c2ecf20Sopenharmony_ci	if (netif_running(adapter->netdev)) {
18498c2ecf20Sopenharmony_ci		igc_down(adapter);
18508c2ecf20Sopenharmony_ci		igc_up(adapter);
18518c2ecf20Sopenharmony_ci	} else {
18528c2ecf20Sopenharmony_ci		igc_reset(adapter);
18538c2ecf20Sopenharmony_ci	}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	clear_bit(__IGC_RESETTING, &adapter->state);
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	return 0;
18588c2ecf20Sopenharmony_ci}
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_cistatic void igc_ethtool_diag_test(struct net_device *netdev,
18618c2ecf20Sopenharmony_ci				  struct ethtool_test *eth_test, u64 *data)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	struct igc_adapter *adapter = netdev_priv(netdev);
18648c2ecf20Sopenharmony_ci	bool if_running = netif_running(netdev);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
18678c2ecf20Sopenharmony_ci		netdev_info(adapter->netdev, "Offline testing starting");
18688c2ecf20Sopenharmony_ci		set_bit(__IGC_TESTING, &adapter->state);
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci		/* Link test performed before hardware reset so autoneg doesn't
18718c2ecf20Sopenharmony_ci		 * interfere with test result
18728c2ecf20Sopenharmony_ci		 */
18738c2ecf20Sopenharmony_ci		if (!igc_link_test(adapter, &data[TEST_LINK]))
18748c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci		if (if_running)
18778c2ecf20Sopenharmony_ci			igc_close(netdev);
18788c2ecf20Sopenharmony_ci		else
18798c2ecf20Sopenharmony_ci			igc_reset(adapter);
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci		netdev_info(adapter->netdev, "Register testing starting");
18828c2ecf20Sopenharmony_ci		if (!igc_reg_test(adapter, &data[TEST_REG]))
18838c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci		igc_reset(adapter);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci		netdev_info(adapter->netdev, "EEPROM testing starting");
18888c2ecf20Sopenharmony_ci		if (!igc_eeprom_test(adapter, &data[TEST_EEP]))
18898c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci		igc_reset(adapter);
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci		/* loopback and interrupt tests
18948c2ecf20Sopenharmony_ci		 * will be implemented in the future
18958c2ecf20Sopenharmony_ci		 */
18968c2ecf20Sopenharmony_ci		data[TEST_LOOP] = 0;
18978c2ecf20Sopenharmony_ci		data[TEST_IRQ] = 0;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci		clear_bit(__IGC_TESTING, &adapter->state);
19008c2ecf20Sopenharmony_ci		if (if_running)
19018c2ecf20Sopenharmony_ci			igc_open(netdev);
19028c2ecf20Sopenharmony_ci	} else {
19038c2ecf20Sopenharmony_ci		netdev_info(adapter->netdev, "Online testing starting");
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci		/* register, eeprom, intr and loopback tests not run online */
19068c2ecf20Sopenharmony_ci		data[TEST_REG] = 0;
19078c2ecf20Sopenharmony_ci		data[TEST_EEP] = 0;
19088c2ecf20Sopenharmony_ci		data[TEST_IRQ] = 0;
19098c2ecf20Sopenharmony_ci		data[TEST_LOOP] = 0;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci		if (!igc_link_test(adapter, &data[TEST_LINK]))
19128c2ecf20Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
19138c2ecf20Sopenharmony_ci	}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	msleep_interruptible(4 * 1000);
19168c2ecf20Sopenharmony_ci}
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_cistatic const struct ethtool_ops igc_ethtool_ops = {
19198c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
19208c2ecf20Sopenharmony_ci	.get_drvinfo		= igc_ethtool_get_drvinfo,
19218c2ecf20Sopenharmony_ci	.get_regs_len		= igc_ethtool_get_regs_len,
19228c2ecf20Sopenharmony_ci	.get_regs		= igc_ethtool_get_regs,
19238c2ecf20Sopenharmony_ci	.get_wol		= igc_ethtool_get_wol,
19248c2ecf20Sopenharmony_ci	.set_wol		= igc_ethtool_set_wol,
19258c2ecf20Sopenharmony_ci	.get_msglevel		= igc_ethtool_get_msglevel,
19268c2ecf20Sopenharmony_ci	.set_msglevel		= igc_ethtool_set_msglevel,
19278c2ecf20Sopenharmony_ci	.nway_reset		= igc_ethtool_nway_reset,
19288c2ecf20Sopenharmony_ci	.get_link		= igc_ethtool_get_link,
19298c2ecf20Sopenharmony_ci	.get_eeprom_len		= igc_ethtool_get_eeprom_len,
19308c2ecf20Sopenharmony_ci	.get_eeprom		= igc_ethtool_get_eeprom,
19318c2ecf20Sopenharmony_ci	.set_eeprom		= igc_ethtool_set_eeprom,
19328c2ecf20Sopenharmony_ci	.get_ringparam		= igc_ethtool_get_ringparam,
19338c2ecf20Sopenharmony_ci	.set_ringparam		= igc_ethtool_set_ringparam,
19348c2ecf20Sopenharmony_ci	.get_pauseparam		= igc_ethtool_get_pauseparam,
19358c2ecf20Sopenharmony_ci	.set_pauseparam		= igc_ethtool_set_pauseparam,
19368c2ecf20Sopenharmony_ci	.get_strings		= igc_ethtool_get_strings,
19378c2ecf20Sopenharmony_ci	.get_sset_count		= igc_ethtool_get_sset_count,
19388c2ecf20Sopenharmony_ci	.get_ethtool_stats	= igc_ethtool_get_stats,
19398c2ecf20Sopenharmony_ci	.get_coalesce		= igc_ethtool_get_coalesce,
19408c2ecf20Sopenharmony_ci	.set_coalesce		= igc_ethtool_set_coalesce,
19418c2ecf20Sopenharmony_ci	.get_rxnfc		= igc_ethtool_get_rxnfc,
19428c2ecf20Sopenharmony_ci	.set_rxnfc		= igc_ethtool_set_rxnfc,
19438c2ecf20Sopenharmony_ci	.get_rxfh_indir_size	= igc_ethtool_get_rxfh_indir_size,
19448c2ecf20Sopenharmony_ci	.get_rxfh		= igc_ethtool_get_rxfh,
19458c2ecf20Sopenharmony_ci	.set_rxfh		= igc_ethtool_set_rxfh,
19468c2ecf20Sopenharmony_ci	.get_ts_info		= igc_ethtool_get_ts_info,
19478c2ecf20Sopenharmony_ci	.get_channels		= igc_ethtool_get_channels,
19488c2ecf20Sopenharmony_ci	.set_channels		= igc_ethtool_set_channels,
19498c2ecf20Sopenharmony_ci	.get_priv_flags		= igc_ethtool_get_priv_flags,
19508c2ecf20Sopenharmony_ci	.set_priv_flags		= igc_ethtool_set_priv_flags,
19518c2ecf20Sopenharmony_ci	.get_eee		= igc_ethtool_get_eee,
19528c2ecf20Sopenharmony_ci	.set_eee		= igc_ethtool_set_eee,
19538c2ecf20Sopenharmony_ci	.begin			= igc_ethtool_begin,
19548c2ecf20Sopenharmony_ci	.complete		= igc_ethtool_complete,
19558c2ecf20Sopenharmony_ci	.get_link_ksettings	= igc_ethtool_get_link_ksettings,
19568c2ecf20Sopenharmony_ci	.set_link_ksettings	= igc_ethtool_set_link_ksettings,
19578c2ecf20Sopenharmony_ci	.self_test		= igc_ethtool_diag_test,
19588c2ecf20Sopenharmony_ci};
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_civoid igc_ethtool_set_ops(struct net_device *netdev)
19618c2ecf20Sopenharmony_ci{
19628c2ecf20Sopenharmony_ci	netdev->ethtool_ops = &igc_ethtool_ops;
19638c2ecf20Sopenharmony_ci}
1964