xref: /linux/drivers/net/ethernet/intel/igc/igc_ethtool.c (revision 9410645520e9b820069761f3450ef6661418e279)
18c5ad0daSSasha Neftin // SPDX-License-Identifier: GPL-2.0
28c5ad0daSSasha Neftin /* Copyright (c)  2018 Intel Corporation */
38c5ad0daSSasha Neftin 
48c5ad0daSSasha Neftin /* ethtool support for igc */
56245c848SSasha Neftin #include <linux/if_vlan.h>
68c5ad0daSSasha Neftin #include <linux/pm_runtime.h>
793ec439aSSasha Neftin #include <linux/mdio.h>
88c5ad0daSSasha Neftin 
98c5ad0daSSasha Neftin #include "igc.h"
10f026d8caSVitaly Lifshits #include "igc_diag.h"
118c5ad0daSSasha Neftin 
1236b9fea6SSasha Neftin /* forward declaration */
1336b9fea6SSasha Neftin struct igc_stats {
1436b9fea6SSasha Neftin 	char stat_string[ETH_GSTRING_LEN];
1536b9fea6SSasha Neftin 	int sizeof_stat;
1636b9fea6SSasha Neftin 	int stat_offset;
1736b9fea6SSasha Neftin };
1836b9fea6SSasha Neftin 
1936b9fea6SSasha Neftin #define IGC_STAT(_name, _stat) { \
2036b9fea6SSasha Neftin 	.stat_string = _name, \
21c593642cSPankaj Bharadiya 	.sizeof_stat = sizeof_field(struct igc_adapter, _stat), \
2236b9fea6SSasha Neftin 	.stat_offset = offsetof(struct igc_adapter, _stat) \
2336b9fea6SSasha Neftin }
2436b9fea6SSasha Neftin 
2536b9fea6SSasha Neftin static const struct igc_stats igc_gstrings_stats[] = {
2636b9fea6SSasha Neftin 	IGC_STAT("rx_packets", stats.gprc),
2736b9fea6SSasha Neftin 	IGC_STAT("tx_packets", stats.gptc),
2836b9fea6SSasha Neftin 	IGC_STAT("rx_bytes", stats.gorc),
2936b9fea6SSasha Neftin 	IGC_STAT("tx_bytes", stats.gotc),
3036b9fea6SSasha Neftin 	IGC_STAT("rx_broadcast", stats.bprc),
3136b9fea6SSasha Neftin 	IGC_STAT("tx_broadcast", stats.bptc),
3236b9fea6SSasha Neftin 	IGC_STAT("rx_multicast", stats.mprc),
3336b9fea6SSasha Neftin 	IGC_STAT("tx_multicast", stats.mptc),
3436b9fea6SSasha Neftin 	IGC_STAT("multicast", stats.mprc),
3536b9fea6SSasha Neftin 	IGC_STAT("collisions", stats.colc),
3636b9fea6SSasha Neftin 	IGC_STAT("rx_crc_errors", stats.crcerrs),
3736b9fea6SSasha Neftin 	IGC_STAT("rx_no_buffer_count", stats.rnbc),
3836b9fea6SSasha Neftin 	IGC_STAT("rx_missed_errors", stats.mpc),
3936b9fea6SSasha Neftin 	IGC_STAT("tx_aborted_errors", stats.ecol),
4036b9fea6SSasha Neftin 	IGC_STAT("tx_carrier_errors", stats.tncrs),
4136b9fea6SSasha Neftin 	IGC_STAT("tx_window_errors", stats.latecol),
4236b9fea6SSasha Neftin 	IGC_STAT("tx_abort_late_coll", stats.latecol),
4336b9fea6SSasha Neftin 	IGC_STAT("tx_deferred_ok", stats.dc),
4436b9fea6SSasha Neftin 	IGC_STAT("tx_single_coll_ok", stats.scc),
4536b9fea6SSasha Neftin 	IGC_STAT("tx_multi_coll_ok", stats.mcc),
4636b9fea6SSasha Neftin 	IGC_STAT("tx_timeout_count", tx_timeout_count),
4736b9fea6SSasha Neftin 	IGC_STAT("rx_long_length_errors", stats.roc),
4836b9fea6SSasha Neftin 	IGC_STAT("rx_short_length_errors", stats.ruc),
4936b9fea6SSasha Neftin 	IGC_STAT("rx_align_errors", stats.algnerrc),
5036b9fea6SSasha Neftin 	IGC_STAT("tx_tcp_seg_good", stats.tsctc),
5136b9fea6SSasha Neftin 	IGC_STAT("tx_tcp_seg_failed", stats.tsctfc),
5236b9fea6SSasha Neftin 	IGC_STAT("rx_flow_control_xon", stats.xonrxc),
5336b9fea6SSasha Neftin 	IGC_STAT("rx_flow_control_xoff", stats.xoffrxc),
5436b9fea6SSasha Neftin 	IGC_STAT("tx_flow_control_xon", stats.xontxc),
5536b9fea6SSasha Neftin 	IGC_STAT("tx_flow_control_xoff", stats.xofftxc),
5636b9fea6SSasha Neftin 	IGC_STAT("rx_long_byte_count", stats.gorc),
5736b9fea6SSasha Neftin 	IGC_STAT("tx_dma_out_of_sync", stats.doosync),
5836b9fea6SSasha Neftin 	IGC_STAT("tx_smbus", stats.mgptc),
5936b9fea6SSasha Neftin 	IGC_STAT("rx_smbus", stats.mgprc),
6036b9fea6SSasha Neftin 	IGC_STAT("dropped_smbus", stats.mgpdc),
6136b9fea6SSasha Neftin 	IGC_STAT("os2bmc_rx_by_bmc", stats.o2bgptc),
6236b9fea6SSasha Neftin 	IGC_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
6336b9fea6SSasha Neftin 	IGC_STAT("os2bmc_tx_by_host", stats.o2bspc),
6436b9fea6SSasha Neftin 	IGC_STAT("os2bmc_rx_by_host", stats.b2ogprc),
6536b9fea6SSasha Neftin 	IGC_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
6636b9fea6SSasha Neftin 	IGC_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
6736b9fea6SSasha Neftin 	IGC_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
681feaf60fSSasha Neftin 	IGC_STAT("tx_lpi_counter", stats.tlpic),
691feaf60fSSasha Neftin 	IGC_STAT("rx_lpi_counter", stats.rlpic),
70ae4fe469SMuhammad Husaini Zulkifli 	IGC_STAT("qbv_config_change_errors", qbv_config_change_errors),
7136b9fea6SSasha Neftin };
7236b9fea6SSasha Neftin 
7336b9fea6SSasha Neftin #define IGC_NETDEV_STAT(_net_stat) { \
7436b9fea6SSasha Neftin 	.stat_string = __stringify(_net_stat), \
75c593642cSPankaj Bharadiya 	.sizeof_stat = sizeof_field(struct rtnl_link_stats64, _net_stat), \
7636b9fea6SSasha Neftin 	.stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \
7736b9fea6SSasha Neftin }
7836b9fea6SSasha Neftin 
7936b9fea6SSasha Neftin static const struct igc_stats igc_gstrings_net_stats[] = {
8036b9fea6SSasha Neftin 	IGC_NETDEV_STAT(rx_errors),
8136b9fea6SSasha Neftin 	IGC_NETDEV_STAT(tx_errors),
8236b9fea6SSasha Neftin 	IGC_NETDEV_STAT(tx_dropped),
8336b9fea6SSasha Neftin 	IGC_NETDEV_STAT(rx_length_errors),
8436b9fea6SSasha Neftin 	IGC_NETDEV_STAT(rx_over_errors),
8536b9fea6SSasha Neftin 	IGC_NETDEV_STAT(rx_frame_errors),
8636b9fea6SSasha Neftin 	IGC_NETDEV_STAT(rx_fifo_errors),
8736b9fea6SSasha Neftin 	IGC_NETDEV_STAT(tx_fifo_errors),
8836b9fea6SSasha Neftin 	IGC_NETDEV_STAT(tx_heartbeat_errors)
8936b9fea6SSasha Neftin };
9036b9fea6SSasha Neftin 
9136b9fea6SSasha Neftin enum igc_diagnostics_results {
9236b9fea6SSasha Neftin 	TEST_REG = 0,
9336b9fea6SSasha Neftin 	TEST_EEP,
9436b9fea6SSasha Neftin 	TEST_IRQ,
9536b9fea6SSasha Neftin 	TEST_LOOP,
9636b9fea6SSasha Neftin 	TEST_LINK
9736b9fea6SSasha Neftin };
9836b9fea6SSasha Neftin 
9936b9fea6SSasha Neftin static const char igc_gstrings_test[][ETH_GSTRING_LEN] = {
10036b9fea6SSasha Neftin 	[TEST_REG]  = "Register test  (offline)",
10136b9fea6SSasha Neftin 	[TEST_EEP]  = "Eeprom test    (offline)",
10236b9fea6SSasha Neftin 	[TEST_IRQ]  = "Interrupt test (offline)",
10336b9fea6SSasha Neftin 	[TEST_LOOP] = "Loopback test  (offline)",
10436b9fea6SSasha Neftin 	[TEST_LINK] = "Link test   (on/offline)"
10536b9fea6SSasha Neftin };
10636b9fea6SSasha Neftin 
10736b9fea6SSasha Neftin #define IGC_TEST_LEN (sizeof(igc_gstrings_test) / ETH_GSTRING_LEN)
10836b9fea6SSasha Neftin 
10936b9fea6SSasha Neftin #define IGC_GLOBAL_STATS_LEN	\
11036b9fea6SSasha Neftin 	(sizeof(igc_gstrings_stats) / sizeof(struct igc_stats))
11136b9fea6SSasha Neftin #define IGC_NETDEV_STATS_LEN	\
11236b9fea6SSasha Neftin 	(sizeof(igc_gstrings_net_stats) / sizeof(struct igc_stats))
11336b9fea6SSasha Neftin #define IGC_RX_QUEUE_STATS_LEN \
11436b9fea6SSasha Neftin 	(sizeof(struct igc_rx_queue_stats) / sizeof(u64))
11536b9fea6SSasha Neftin #define IGC_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */
11636b9fea6SSasha Neftin #define IGC_QUEUE_STATS_LEN \
11736b9fea6SSasha Neftin 	((((struct igc_adapter *)netdev_priv(netdev))->num_rx_queues * \
11836b9fea6SSasha Neftin 	  IGC_RX_QUEUE_STATS_LEN) + \
11936b9fea6SSasha Neftin 	 (((struct igc_adapter *)netdev_priv(netdev))->num_tx_queues * \
12036b9fea6SSasha Neftin 	  IGC_TX_QUEUE_STATS_LEN))
12136b9fea6SSasha Neftin #define IGC_STATS_LEN \
12236b9fea6SSasha Neftin 	(IGC_GLOBAL_STATS_LEN + IGC_NETDEV_STATS_LEN + IGC_QUEUE_STATS_LEN)
12336b9fea6SSasha Neftin 
1248c5ad0daSSasha Neftin static const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = {
1258c5ad0daSSasha Neftin #define IGC_PRIV_FLAGS_LEGACY_RX	BIT(0)
1268c5ad0daSSasha Neftin 	"legacy-rx",
1278c5ad0daSSasha Neftin };
1288c5ad0daSSasha Neftin 
1298c5ad0daSSasha Neftin #define IGC_PRIV_FLAGS_STR_LEN ARRAY_SIZE(igc_priv_flags_strings)
1308c5ad0daSSasha Neftin 
igc_ethtool_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)1317df76bd1SAndre Guedes static void igc_ethtool_get_drvinfo(struct net_device *netdev,
1328c5ad0daSSasha Neftin 				    struct ethtool_drvinfo *drvinfo)
1338c5ad0daSSasha Neftin {
1348c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
13501bb6129SSasha Neftin 	struct igc_hw *hw = &adapter->hw;
13601bb6129SSasha Neftin 	u16 nvm_version = 0;
13794f794d1SSasha Neftin 	u16 gphy_version;
1388c5ad0daSSasha Neftin 
13901bb6129SSasha Neftin 	strscpy(drvinfo->driver, igc_driver_name, sizeof(drvinfo->driver));
1408c5ad0daSSasha Neftin 
14101bb6129SSasha Neftin 	/* NVM image version is reported as firmware version for i225 device */
14201bb6129SSasha Neftin 	hw->nvm.ops.read(hw, IGC_NVM_DEV_STARTER, 1, &nvm_version);
14301bb6129SSasha Neftin 
14494f794d1SSasha Neftin 	/* gPHY firmware version is reported as PHY FW version */
14594f794d1SSasha Neftin 	gphy_version = igc_read_phy_fw_version(hw);
14694f794d1SSasha Neftin 
14701bb6129SSasha Neftin 	scnprintf(adapter->fw_version,
14801bb6129SSasha Neftin 		  sizeof(adapter->fw_version),
14994f794d1SSasha Neftin 		  "%x:%x",
15094f794d1SSasha Neftin 		  nvm_version,
15194f794d1SSasha Neftin 		  gphy_version);
15201bb6129SSasha Neftin 
15301bb6129SSasha Neftin 	strscpy(drvinfo->fw_version, adapter->fw_version,
15401bb6129SSasha Neftin 		sizeof(drvinfo->fw_version));
15501bb6129SSasha Neftin 
156ed443cdfSSasha Neftin 	strscpy(drvinfo->bus_info, pci_name(adapter->pdev),
1578c5ad0daSSasha Neftin 		sizeof(drvinfo->bus_info));
1588c5ad0daSSasha Neftin 
1598c5ad0daSSasha Neftin 	drvinfo->n_priv_flags = IGC_PRIV_FLAGS_STR_LEN;
1608c5ad0daSSasha Neftin }
1618c5ad0daSSasha Neftin 
igc_ethtool_get_regs_len(struct net_device * netdev)1627df76bd1SAndre Guedes static int igc_ethtool_get_regs_len(struct net_device *netdev)
1638c5ad0daSSasha Neftin {
1648c5ad0daSSasha Neftin 	return IGC_REGS_LEN * sizeof(u32);
1658c5ad0daSSasha Neftin }
1668c5ad0daSSasha Neftin 
igc_ethtool_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)1677df76bd1SAndre Guedes static void igc_ethtool_get_regs(struct net_device *netdev,
1688c5ad0daSSasha Neftin 				 struct ethtool_regs *regs, void *p)
1698c5ad0daSSasha Neftin {
1708c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
1718c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
1728c5ad0daSSasha Neftin 	u32 *regs_buff = p;
1738c5ad0daSSasha Neftin 	u8 i;
1748c5ad0daSSasha Neftin 
1758c5ad0daSSasha Neftin 	memset(p, 0, IGC_REGS_LEN * sizeof(u32));
1768c5ad0daSSasha Neftin 
177b8a61ea1SAndre Guedes 	regs->version = (2u << 24) | (hw->revision_id << 16) | hw->device_id;
1788c5ad0daSSasha Neftin 
1798c5ad0daSSasha Neftin 	/* General Registers */
1808c5ad0daSSasha Neftin 	regs_buff[0] = rd32(IGC_CTRL);
1818c5ad0daSSasha Neftin 	regs_buff[1] = rd32(IGC_STATUS);
1828c5ad0daSSasha Neftin 	regs_buff[2] = rd32(IGC_CTRL_EXT);
1838c5ad0daSSasha Neftin 	regs_buff[3] = rd32(IGC_MDIC);
1848c5ad0daSSasha Neftin 	regs_buff[4] = rd32(IGC_CONNSW);
1858c5ad0daSSasha Neftin 
1868c5ad0daSSasha Neftin 	/* NVM Register */
1878c5ad0daSSasha Neftin 	regs_buff[5] = rd32(IGC_EECD);
1888c5ad0daSSasha Neftin 
1898c5ad0daSSasha Neftin 	/* Interrupt */
1908c5ad0daSSasha Neftin 	/* Reading EICS for EICR because they read the
1918c5ad0daSSasha Neftin 	 * same but EICS does not clear on read
1928c5ad0daSSasha Neftin 	 */
1938c5ad0daSSasha Neftin 	regs_buff[6] = rd32(IGC_EICS);
1948c5ad0daSSasha Neftin 	regs_buff[7] = rd32(IGC_EICS);
1958c5ad0daSSasha Neftin 	regs_buff[8] = rd32(IGC_EIMS);
1968c5ad0daSSasha Neftin 	regs_buff[9] = rd32(IGC_EIMC);
1978c5ad0daSSasha Neftin 	regs_buff[10] = rd32(IGC_EIAC);
1988c5ad0daSSasha Neftin 	regs_buff[11] = rd32(IGC_EIAM);
1998c5ad0daSSasha Neftin 	/* Reading ICS for ICR because they read the
2008c5ad0daSSasha Neftin 	 * same but ICS does not clear on read
2018c5ad0daSSasha Neftin 	 */
2028c5ad0daSSasha Neftin 	regs_buff[12] = rd32(IGC_ICS);
2038c5ad0daSSasha Neftin 	regs_buff[13] = rd32(IGC_ICS);
2048c5ad0daSSasha Neftin 	regs_buff[14] = rd32(IGC_IMS);
2058c5ad0daSSasha Neftin 	regs_buff[15] = rd32(IGC_IMC);
2068c5ad0daSSasha Neftin 	regs_buff[16] = rd32(IGC_IAC);
2078c5ad0daSSasha Neftin 	regs_buff[17] = rd32(IGC_IAM);
2088c5ad0daSSasha Neftin 
2098c5ad0daSSasha Neftin 	/* Flow Control */
2108c5ad0daSSasha Neftin 	regs_buff[18] = rd32(IGC_FCAL);
2118c5ad0daSSasha Neftin 	regs_buff[19] = rd32(IGC_FCAH);
2128c5ad0daSSasha Neftin 	regs_buff[20] = rd32(IGC_FCTTV);
2138c5ad0daSSasha Neftin 	regs_buff[21] = rd32(IGC_FCRTL);
2148c5ad0daSSasha Neftin 	regs_buff[22] = rd32(IGC_FCRTH);
2158c5ad0daSSasha Neftin 	regs_buff[23] = rd32(IGC_FCRTV);
2168c5ad0daSSasha Neftin 
2178c5ad0daSSasha Neftin 	/* Receive */
2188c5ad0daSSasha Neftin 	regs_buff[24] = rd32(IGC_RCTL);
2198c5ad0daSSasha Neftin 	regs_buff[25] = rd32(IGC_RXCSUM);
2208c5ad0daSSasha Neftin 	regs_buff[26] = rd32(IGC_RLPML);
2218c5ad0daSSasha Neftin 	regs_buff[27] = rd32(IGC_RFCTL);
2228c5ad0daSSasha Neftin 
2238c5ad0daSSasha Neftin 	/* Transmit */
2248c5ad0daSSasha Neftin 	regs_buff[28] = rd32(IGC_TCTL);
2258c5ad0daSSasha Neftin 	regs_buff[29] = rd32(IGC_TIPG);
2268c5ad0daSSasha Neftin 
2278c5ad0daSSasha Neftin 	/* Wake Up */
2288c5ad0daSSasha Neftin 
2298c5ad0daSSasha Neftin 	/* MAC */
2308c5ad0daSSasha Neftin 
2318c5ad0daSSasha Neftin 	/* Statistics */
2328c5ad0daSSasha Neftin 	regs_buff[30] = adapter->stats.crcerrs;
2338c5ad0daSSasha Neftin 	regs_buff[31] = adapter->stats.algnerrc;
2348c5ad0daSSasha Neftin 	regs_buff[32] = adapter->stats.symerrs;
2358c5ad0daSSasha Neftin 	regs_buff[33] = adapter->stats.rxerrc;
2368c5ad0daSSasha Neftin 	regs_buff[34] = adapter->stats.mpc;
2378c5ad0daSSasha Neftin 	regs_buff[35] = adapter->stats.scc;
2388c5ad0daSSasha Neftin 	regs_buff[36] = adapter->stats.ecol;
2398c5ad0daSSasha Neftin 	regs_buff[37] = adapter->stats.mcc;
2408c5ad0daSSasha Neftin 	regs_buff[38] = adapter->stats.latecol;
2418c5ad0daSSasha Neftin 	regs_buff[39] = adapter->stats.colc;
2428c5ad0daSSasha Neftin 	regs_buff[40] = adapter->stats.dc;
2438c5ad0daSSasha Neftin 	regs_buff[41] = adapter->stats.tncrs;
2448c5ad0daSSasha Neftin 	regs_buff[42] = adapter->stats.sec;
2458c5ad0daSSasha Neftin 	regs_buff[43] = adapter->stats.htdpmc;
2468c5ad0daSSasha Neftin 	regs_buff[44] = adapter->stats.rlec;
2478c5ad0daSSasha Neftin 	regs_buff[45] = adapter->stats.xonrxc;
2488c5ad0daSSasha Neftin 	regs_buff[46] = adapter->stats.xontxc;
2498c5ad0daSSasha Neftin 	regs_buff[47] = adapter->stats.xoffrxc;
2508c5ad0daSSasha Neftin 	regs_buff[48] = adapter->stats.xofftxc;
2518c5ad0daSSasha Neftin 	regs_buff[49] = adapter->stats.fcruc;
2528c5ad0daSSasha Neftin 	regs_buff[50] = adapter->stats.prc64;
2538c5ad0daSSasha Neftin 	regs_buff[51] = adapter->stats.prc127;
2548c5ad0daSSasha Neftin 	regs_buff[52] = adapter->stats.prc255;
2558c5ad0daSSasha Neftin 	regs_buff[53] = adapter->stats.prc511;
2568c5ad0daSSasha Neftin 	regs_buff[54] = adapter->stats.prc1023;
2578c5ad0daSSasha Neftin 	regs_buff[55] = adapter->stats.prc1522;
2588c5ad0daSSasha Neftin 	regs_buff[56] = adapter->stats.gprc;
2598c5ad0daSSasha Neftin 	regs_buff[57] = adapter->stats.bprc;
2608c5ad0daSSasha Neftin 	regs_buff[58] = adapter->stats.mprc;
2618c5ad0daSSasha Neftin 	regs_buff[59] = adapter->stats.gptc;
2628c5ad0daSSasha Neftin 	regs_buff[60] = adapter->stats.gorc;
2638c5ad0daSSasha Neftin 	regs_buff[61] = adapter->stats.gotc;
2648c5ad0daSSasha Neftin 	regs_buff[62] = adapter->stats.rnbc;
2658c5ad0daSSasha Neftin 	regs_buff[63] = adapter->stats.ruc;
2668c5ad0daSSasha Neftin 	regs_buff[64] = adapter->stats.rfc;
2678c5ad0daSSasha Neftin 	regs_buff[65] = adapter->stats.roc;
2688c5ad0daSSasha Neftin 	regs_buff[66] = adapter->stats.rjc;
2698c5ad0daSSasha Neftin 	regs_buff[67] = adapter->stats.mgprc;
2708c5ad0daSSasha Neftin 	regs_buff[68] = adapter->stats.mgpdc;
2718c5ad0daSSasha Neftin 	regs_buff[69] = adapter->stats.mgptc;
2728c5ad0daSSasha Neftin 	regs_buff[70] = adapter->stats.tor;
2738c5ad0daSSasha Neftin 	regs_buff[71] = adapter->stats.tot;
2748c5ad0daSSasha Neftin 	regs_buff[72] = adapter->stats.tpr;
2758c5ad0daSSasha Neftin 	regs_buff[73] = adapter->stats.tpt;
2768c5ad0daSSasha Neftin 	regs_buff[74] = adapter->stats.ptc64;
2778c5ad0daSSasha Neftin 	regs_buff[75] = adapter->stats.ptc127;
2788c5ad0daSSasha Neftin 	regs_buff[76] = adapter->stats.ptc255;
2798c5ad0daSSasha Neftin 	regs_buff[77] = adapter->stats.ptc511;
2808c5ad0daSSasha Neftin 	regs_buff[78] = adapter->stats.ptc1023;
2818c5ad0daSSasha Neftin 	regs_buff[79] = adapter->stats.ptc1522;
2828c5ad0daSSasha Neftin 	regs_buff[80] = adapter->stats.mptc;
2838c5ad0daSSasha Neftin 	regs_buff[81] = adapter->stats.bptc;
2848c5ad0daSSasha Neftin 	regs_buff[82] = adapter->stats.tsctc;
2858c5ad0daSSasha Neftin 	regs_buff[83] = adapter->stats.iac;
2868c5ad0daSSasha Neftin 	regs_buff[84] = adapter->stats.rpthc;
2878c5ad0daSSasha Neftin 	regs_buff[85] = adapter->stats.hgptc;
2888c5ad0daSSasha Neftin 	regs_buff[86] = adapter->stats.hgorc;
2898c5ad0daSSasha Neftin 	regs_buff[87] = adapter->stats.hgotc;
2908c5ad0daSSasha Neftin 	regs_buff[88] = adapter->stats.lenerrs;
2918c5ad0daSSasha Neftin 	regs_buff[89] = adapter->stats.scvpc;
2928c5ad0daSSasha Neftin 	regs_buff[90] = adapter->stats.hrmpc;
2938c5ad0daSSasha Neftin 
2948c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
2958c5ad0daSSasha Neftin 		regs_buff[91 + i] = rd32(IGC_SRRCTL(i));
2968c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
2978c5ad0daSSasha Neftin 		regs_buff[95 + i] = rd32(IGC_PSRTYPE(i));
2988c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
2998c5ad0daSSasha Neftin 		regs_buff[99 + i] = rd32(IGC_RDBAL(i));
3008c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3018c5ad0daSSasha Neftin 		regs_buff[103 + i] = rd32(IGC_RDBAH(i));
3028c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3038c5ad0daSSasha Neftin 		regs_buff[107 + i] = rd32(IGC_RDLEN(i));
3048c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3058c5ad0daSSasha Neftin 		regs_buff[111 + i] = rd32(IGC_RDH(i));
3068c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3078c5ad0daSSasha Neftin 		regs_buff[115 + i] = rd32(IGC_RDT(i));
3088c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3098c5ad0daSSasha Neftin 		regs_buff[119 + i] = rd32(IGC_RXDCTL(i));
3108c5ad0daSSasha Neftin 
3118c5ad0daSSasha Neftin 	for (i = 0; i < 10; i++)
3128c5ad0daSSasha Neftin 		regs_buff[123 + i] = rd32(IGC_EITR(i));
3138c5ad0daSSasha Neftin 	for (i = 0; i < 16; i++)
3148c5ad0daSSasha Neftin 		regs_buff[139 + i] = rd32(IGC_RAL(i));
3158c5ad0daSSasha Neftin 	for (i = 0; i < 16; i++)
3168c5ad0daSSasha Neftin 		regs_buff[145 + i] = rd32(IGC_RAH(i));
3178c5ad0daSSasha Neftin 
3188c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3198c5ad0daSSasha Neftin 		regs_buff[149 + i] = rd32(IGC_TDBAL(i));
3208c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3218c5ad0daSSasha Neftin 		regs_buff[152 + i] = rd32(IGC_TDBAH(i));
3228c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3238c5ad0daSSasha Neftin 		regs_buff[156 + i] = rd32(IGC_TDLEN(i));
3248c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3258c5ad0daSSasha Neftin 		regs_buff[160 + i] = rd32(IGC_TDH(i));
3268c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3278c5ad0daSSasha Neftin 		regs_buff[164 + i] = rd32(IGC_TDT(i));
3288c5ad0daSSasha Neftin 	for (i = 0; i < 4; i++)
3298c5ad0daSSasha Neftin 		regs_buff[168 + i] = rd32(IGC_TXDCTL(i));
330b8a61ea1SAndre Guedes 
331b8a61ea1SAndre Guedes 	/* XXX: Due to a bug few lines above, RAL and RAH registers are
332b8a61ea1SAndre Guedes 	 * overwritten. To preserve the ABI, we write these registers again in
333b8a61ea1SAndre Guedes 	 * regs_buff.
334b8a61ea1SAndre Guedes 	 */
335b8a61ea1SAndre Guedes 	for (i = 0; i < 16; i++)
336b8a61ea1SAndre Guedes 		regs_buff[172 + i] = rd32(IGC_RAL(i));
337b8a61ea1SAndre Guedes 	for (i = 0; i < 16; i++)
338b8a61ea1SAndre Guedes 		regs_buff[188 + i] = rd32(IGC_RAH(i));
339fbee4760SAndre Guedes 
340fbee4760SAndre Guedes 	regs_buff[204] = rd32(IGC_VLANPQF);
34181e33061SAndre Guedes 
34281e33061SAndre Guedes 	for (i = 0; i < 8; i++)
34381e33061SAndre Guedes 		regs_buff[205 + i] = rd32(IGC_ETQF(i));
34440edc734SSasha Neftin 
34540edc734SSasha Neftin 	regs_buff[213] = adapter->stats.tlpic;
34640edc734SSasha Neftin 	regs_buff[214] = adapter->stats.rlpic;
3478c5ad0daSSasha Neftin }
3488c5ad0daSSasha Neftin 
igc_ethtool_get_wol(struct net_device * netdev,struct ethtool_wolinfo * wol)3497df76bd1SAndre Guedes static void igc_ethtool_get_wol(struct net_device *netdev,
3507df76bd1SAndre Guedes 				struct ethtool_wolinfo *wol)
351e055600dSSasha Neftin {
352e055600dSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
353e055600dSSasha Neftin 
354e055600dSSasha Neftin 	wol->wolopts = 0;
355e055600dSSasha Neftin 
356e055600dSSasha Neftin 	if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED))
357e055600dSSasha Neftin 		return;
358e055600dSSasha Neftin 
359e055600dSSasha Neftin 	wol->supported = WAKE_UCAST | WAKE_MCAST |
360e055600dSSasha Neftin 			 WAKE_BCAST | WAKE_MAGIC |
361e055600dSSasha Neftin 			 WAKE_PHY;
362e055600dSSasha Neftin 
363e055600dSSasha Neftin 	/* apply any specific unsupported masks here */
364e055600dSSasha Neftin 	switch (adapter->hw.device_id) {
365e055600dSSasha Neftin 	default:
366e055600dSSasha Neftin 		break;
367e055600dSSasha Neftin 	}
368e055600dSSasha Neftin 
369e055600dSSasha Neftin 	if (adapter->wol & IGC_WUFC_EX)
370e055600dSSasha Neftin 		wol->wolopts |= WAKE_UCAST;
371e055600dSSasha Neftin 	if (adapter->wol & IGC_WUFC_MC)
372e055600dSSasha Neftin 		wol->wolopts |= WAKE_MCAST;
373e055600dSSasha Neftin 	if (adapter->wol & IGC_WUFC_BC)
374e055600dSSasha Neftin 		wol->wolopts |= WAKE_BCAST;
375e055600dSSasha Neftin 	if (adapter->wol & IGC_WUFC_MAG)
376e055600dSSasha Neftin 		wol->wolopts |= WAKE_MAGIC;
377e055600dSSasha Neftin 	if (adapter->wol & IGC_WUFC_LNKC)
378e055600dSSasha Neftin 		wol->wolopts |= WAKE_PHY;
379e055600dSSasha Neftin }
380e055600dSSasha Neftin 
igc_ethtool_set_wol(struct net_device * netdev,struct ethtool_wolinfo * wol)3817df76bd1SAndre Guedes static int igc_ethtool_set_wol(struct net_device *netdev,
3827df76bd1SAndre Guedes 			       struct ethtool_wolinfo *wol)
383e055600dSSasha Neftin {
384e055600dSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
385e055600dSSasha Neftin 
386e055600dSSasha Neftin 	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER))
387e055600dSSasha Neftin 		return -EOPNOTSUPP;
388e055600dSSasha Neftin 
389e055600dSSasha Neftin 	if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED))
390e055600dSSasha Neftin 		return wol->wolopts ? -EOPNOTSUPP : 0;
391e055600dSSasha Neftin 
392e055600dSSasha Neftin 	/* these settings will always override what we currently have */
393e055600dSSasha Neftin 	adapter->wol = 0;
394e055600dSSasha Neftin 
395e055600dSSasha Neftin 	if (wol->wolopts & WAKE_UCAST)
396e055600dSSasha Neftin 		adapter->wol |= IGC_WUFC_EX;
397e055600dSSasha Neftin 	if (wol->wolopts & WAKE_MCAST)
398e055600dSSasha Neftin 		adapter->wol |= IGC_WUFC_MC;
399e055600dSSasha Neftin 	if (wol->wolopts & WAKE_BCAST)
400e055600dSSasha Neftin 		adapter->wol |= IGC_WUFC_BC;
401e055600dSSasha Neftin 	if (wol->wolopts & WAKE_MAGIC)
402e055600dSSasha Neftin 		adapter->wol |= IGC_WUFC_MAG;
403e055600dSSasha Neftin 	if (wol->wolopts & WAKE_PHY)
404e055600dSSasha Neftin 		adapter->wol |= IGC_WUFC_LNKC;
405e055600dSSasha Neftin 	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
406e055600dSSasha Neftin 
407e055600dSSasha Neftin 	return 0;
408e055600dSSasha Neftin }
409e055600dSSasha Neftin 
igc_ethtool_get_msglevel(struct net_device * netdev)4107df76bd1SAndre Guedes static u32 igc_ethtool_get_msglevel(struct net_device *netdev)
4118c5ad0daSSasha Neftin {
4128c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
4138c5ad0daSSasha Neftin 
4148c5ad0daSSasha Neftin 	return adapter->msg_enable;
4158c5ad0daSSasha Neftin }
4168c5ad0daSSasha Neftin 
igc_ethtool_set_msglevel(struct net_device * netdev,u32 data)4177df76bd1SAndre Guedes static void igc_ethtool_set_msglevel(struct net_device *netdev, u32 data)
4188c5ad0daSSasha Neftin {
4198c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
4208c5ad0daSSasha Neftin 
4218c5ad0daSSasha Neftin 	adapter->msg_enable = data;
4228c5ad0daSSasha Neftin }
4238c5ad0daSSasha Neftin 
igc_ethtool_nway_reset(struct net_device * netdev)4247df76bd1SAndre Guedes static int igc_ethtool_nway_reset(struct net_device *netdev)
4258c5ad0daSSasha Neftin {
4268c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
4278c5ad0daSSasha Neftin 
4288c5ad0daSSasha Neftin 	if (netif_running(netdev))
4298c5ad0daSSasha Neftin 		igc_reinit_locked(adapter);
4308c5ad0daSSasha Neftin 	return 0;
4318c5ad0daSSasha Neftin }
4328c5ad0daSSasha Neftin 
igc_ethtool_get_link(struct net_device * netdev)4337df76bd1SAndre Guedes static u32 igc_ethtool_get_link(struct net_device *netdev)
4348c5ad0daSSasha Neftin {
4358c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
4368c5ad0daSSasha Neftin 	struct igc_mac_info *mac = &adapter->hw.mac;
4378c5ad0daSSasha Neftin 
4388c5ad0daSSasha Neftin 	/* If the link is not reported up to netdev, interrupts are disabled,
4398c5ad0daSSasha Neftin 	 * and so the physical link state may have changed since we last
4408c5ad0daSSasha Neftin 	 * looked. Set get_link_status to make sure that the true link
4418c5ad0daSSasha Neftin 	 * state is interrogated, rather than pulling a cached and possibly
4428c5ad0daSSasha Neftin 	 * stale link state from the driver.
4438c5ad0daSSasha Neftin 	 */
4448c5ad0daSSasha Neftin 	if (!netif_carrier_ok(netdev))
4458c5ad0daSSasha Neftin 		mac->get_link_status = 1;
4468c5ad0daSSasha Neftin 
4478c5ad0daSSasha Neftin 	return igc_has_link(adapter);
4488c5ad0daSSasha Neftin }
4498c5ad0daSSasha Neftin 
igc_ethtool_get_eeprom_len(struct net_device * netdev)4507df76bd1SAndre Guedes static int igc_ethtool_get_eeprom_len(struct net_device *netdev)
4518c5ad0daSSasha Neftin {
4528c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
4538c5ad0daSSasha Neftin 
4548c5ad0daSSasha Neftin 	return adapter->hw.nvm.word_size * 2;
4558c5ad0daSSasha Neftin }
4568c5ad0daSSasha Neftin 
igc_ethtool_get_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)4577df76bd1SAndre Guedes static int igc_ethtool_get_eeprom(struct net_device *netdev,
4588c5ad0daSSasha Neftin 				  struct ethtool_eeprom *eeprom, u8 *bytes)
4598c5ad0daSSasha Neftin {
4608c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
4618c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
4628c5ad0daSSasha Neftin 	int first_word, last_word;
4638c5ad0daSSasha Neftin 	u16 *eeprom_buff;
4648c5ad0daSSasha Neftin 	int ret_val = 0;
4658c5ad0daSSasha Neftin 	u16 i;
4668c5ad0daSSasha Neftin 
4678c5ad0daSSasha Neftin 	if (eeprom->len == 0)
4688c5ad0daSSasha Neftin 		return -EINVAL;
4698c5ad0daSSasha Neftin 
4708c5ad0daSSasha Neftin 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
4718c5ad0daSSasha Neftin 
4728c5ad0daSSasha Neftin 	first_word = eeprom->offset >> 1;
4738c5ad0daSSasha Neftin 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
4748c5ad0daSSasha Neftin 
4758c5ad0daSSasha Neftin 	eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16),
4768c5ad0daSSasha Neftin 				    GFP_KERNEL);
4778c5ad0daSSasha Neftin 	if (!eeprom_buff)
4788c5ad0daSSasha Neftin 		return -ENOMEM;
4798c5ad0daSSasha Neftin 
4808c5ad0daSSasha Neftin 	if (hw->nvm.type == igc_nvm_eeprom_spi) {
4818c5ad0daSSasha Neftin 		ret_val = hw->nvm.ops.read(hw, first_word,
4828c5ad0daSSasha Neftin 					   last_word - first_word + 1,
4838c5ad0daSSasha Neftin 					   eeprom_buff);
4848c5ad0daSSasha Neftin 	} else {
4858c5ad0daSSasha Neftin 		for (i = 0; i < last_word - first_word + 1; i++) {
4868c5ad0daSSasha Neftin 			ret_val = hw->nvm.ops.read(hw, first_word + i, 1,
4878c5ad0daSSasha Neftin 						   &eeprom_buff[i]);
4888c5ad0daSSasha Neftin 			if (ret_val)
4898c5ad0daSSasha Neftin 				break;
4908c5ad0daSSasha Neftin 		}
4918c5ad0daSSasha Neftin 	}
4928c5ad0daSSasha Neftin 
4938c5ad0daSSasha Neftin 	/* Device's eeprom is always little-endian, word addressable */
4948c5ad0daSSasha Neftin 	for (i = 0; i < last_word - first_word + 1; i++)
4958c5ad0daSSasha Neftin 		le16_to_cpus(&eeprom_buff[i]);
4968c5ad0daSSasha Neftin 
4978c5ad0daSSasha Neftin 	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1),
4988c5ad0daSSasha Neftin 	       eeprom->len);
4998c5ad0daSSasha Neftin 	kfree(eeprom_buff);
5008c5ad0daSSasha Neftin 
5018c5ad0daSSasha Neftin 	return ret_val;
5028c5ad0daSSasha Neftin }
5038c5ad0daSSasha Neftin 
igc_ethtool_set_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)5047df76bd1SAndre Guedes static int igc_ethtool_set_eeprom(struct net_device *netdev,
5058c5ad0daSSasha Neftin 				  struct ethtool_eeprom *eeprom, u8 *bytes)
5068c5ad0daSSasha Neftin {
5078c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
5088c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
5098c5ad0daSSasha Neftin 	int max_len, first_word, last_word, ret_val = 0;
5108c5ad0daSSasha Neftin 	u16 *eeprom_buff;
5118c5ad0daSSasha Neftin 	void *ptr;
5128c5ad0daSSasha Neftin 	u16 i;
5138c5ad0daSSasha Neftin 
5148c5ad0daSSasha Neftin 	if (eeprom->len == 0)
5158c5ad0daSSasha Neftin 		return -EOPNOTSUPP;
5168c5ad0daSSasha Neftin 
5178c5ad0daSSasha Neftin 	if (hw->mac.type >= igc_i225 &&
5188c5ad0daSSasha Neftin 	    !igc_get_flash_presence_i225(hw)) {
5198c5ad0daSSasha Neftin 		return -EOPNOTSUPP;
5208c5ad0daSSasha Neftin 	}
5218c5ad0daSSasha Neftin 
5228c5ad0daSSasha Neftin 	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
5238c5ad0daSSasha Neftin 		return -EFAULT;
5248c5ad0daSSasha Neftin 
5258c5ad0daSSasha Neftin 	max_len = hw->nvm.word_size * 2;
5268c5ad0daSSasha Neftin 
5278c5ad0daSSasha Neftin 	first_word = eeprom->offset >> 1;
5288c5ad0daSSasha Neftin 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
5298c5ad0daSSasha Neftin 	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
5308c5ad0daSSasha Neftin 	if (!eeprom_buff)
5318c5ad0daSSasha Neftin 		return -ENOMEM;
5328c5ad0daSSasha Neftin 
5338c5ad0daSSasha Neftin 	ptr = (void *)eeprom_buff;
5348c5ad0daSSasha Neftin 
5358c5ad0daSSasha Neftin 	if (eeprom->offset & 1) {
5368c5ad0daSSasha Neftin 		/* need read/modify/write of first changed EEPROM word
5378c5ad0daSSasha Neftin 		 * only the second byte of the word is being modified
5388c5ad0daSSasha Neftin 		 */
5398c5ad0daSSasha Neftin 		ret_val = hw->nvm.ops.read(hw, first_word, 1,
5408c5ad0daSSasha Neftin 					    &eeprom_buff[0]);
5418c5ad0daSSasha Neftin 		ptr++;
5428c5ad0daSSasha Neftin 	}
5438c5ad0daSSasha Neftin 	if (((eeprom->offset + eeprom->len) & 1) && ret_val == 0) {
5448c5ad0daSSasha Neftin 		/* need read/modify/write of last changed EEPROM word
5458c5ad0daSSasha Neftin 		 * only the first byte of the word is being modified
5468c5ad0daSSasha Neftin 		 */
5478c5ad0daSSasha Neftin 		ret_val = hw->nvm.ops.read(hw, last_word, 1,
5488c5ad0daSSasha Neftin 				   &eeprom_buff[last_word - first_word]);
5498c5ad0daSSasha Neftin 	}
5508c5ad0daSSasha Neftin 
5518c5ad0daSSasha Neftin 	/* Device's eeprom is always little-endian, word addressable */
5528c5ad0daSSasha Neftin 	for (i = 0; i < last_word - first_word + 1; i++)
5538c5ad0daSSasha Neftin 		le16_to_cpus(&eeprom_buff[i]);
5548c5ad0daSSasha Neftin 
5558c5ad0daSSasha Neftin 	memcpy(ptr, bytes, eeprom->len);
5568c5ad0daSSasha Neftin 
5578c5ad0daSSasha Neftin 	for (i = 0; i < last_word - first_word + 1; i++)
558c40591ccSJesse Brandeburg 		cpu_to_le16s(&eeprom_buff[i]);
5598c5ad0daSSasha Neftin 
5608c5ad0daSSasha Neftin 	ret_val = hw->nvm.ops.write(hw, first_word,
5618c5ad0daSSasha Neftin 				    last_word - first_word + 1, eeprom_buff);
5628c5ad0daSSasha Neftin 
5638c5ad0daSSasha Neftin 	/* Update the checksum if nvm write succeeded */
5648c5ad0daSSasha Neftin 	if (ret_val == 0)
5658c5ad0daSSasha Neftin 		hw->nvm.ops.update(hw);
5668c5ad0daSSasha Neftin 
5678c5ad0daSSasha Neftin 	kfree(eeprom_buff);
5688c5ad0daSSasha Neftin 	return ret_val;
5698c5ad0daSSasha Neftin }
5708c5ad0daSSasha Neftin 
57174624944SHao Chen static void
igc_ethtool_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ering,struct netlink_ext_ack * extack)57274624944SHao Chen igc_ethtool_get_ringparam(struct net_device *netdev,
57374624944SHao Chen 			  struct ethtool_ringparam *ring,
57474624944SHao Chen 			  struct kernel_ethtool_ringparam *kernel_ering,
57574624944SHao Chen 			  struct netlink_ext_ack *extack)
5768c5ad0daSSasha Neftin {
5778c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
5788c5ad0daSSasha Neftin 
5798c5ad0daSSasha Neftin 	ring->rx_max_pending = IGC_MAX_RXD;
5808c5ad0daSSasha Neftin 	ring->tx_max_pending = IGC_MAX_TXD;
5818c5ad0daSSasha Neftin 	ring->rx_pending = adapter->rx_ring_count;
5828c5ad0daSSasha Neftin 	ring->tx_pending = adapter->tx_ring_count;
5838c5ad0daSSasha Neftin }
5848c5ad0daSSasha Neftin 
58574624944SHao Chen static int
igc_ethtool_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ering,struct netlink_ext_ack * extack)58674624944SHao Chen igc_ethtool_set_ringparam(struct net_device *netdev,
58774624944SHao Chen 			  struct ethtool_ringparam *ring,
58874624944SHao Chen 			  struct kernel_ethtool_ringparam *kernel_ering,
58974624944SHao Chen 			  struct netlink_ext_ack *extack)
5908c5ad0daSSasha Neftin {
5918c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
5928c5ad0daSSasha Neftin 	struct igc_ring *temp_ring;
5938c5ad0daSSasha Neftin 	u16 new_rx_count, new_tx_count;
5948c5ad0daSSasha Neftin 	int i, err = 0;
5958c5ad0daSSasha Neftin 
5968c5ad0daSSasha Neftin 	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
5978c5ad0daSSasha Neftin 		return -EINVAL;
5988c5ad0daSSasha Neftin 
5998c5ad0daSSasha Neftin 	new_rx_count = min_t(u32, ring->rx_pending, IGC_MAX_RXD);
6008c5ad0daSSasha Neftin 	new_rx_count = max_t(u16, new_rx_count, IGC_MIN_RXD);
6018c5ad0daSSasha Neftin 	new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE);
6028c5ad0daSSasha Neftin 
6038c5ad0daSSasha Neftin 	new_tx_count = min_t(u32, ring->tx_pending, IGC_MAX_TXD);
6048c5ad0daSSasha Neftin 	new_tx_count = max_t(u16, new_tx_count, IGC_MIN_TXD);
6058c5ad0daSSasha Neftin 	new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
6068c5ad0daSSasha Neftin 
6078c5ad0daSSasha Neftin 	if (new_tx_count == adapter->tx_ring_count &&
6088c5ad0daSSasha Neftin 	    new_rx_count == adapter->rx_ring_count) {
6098c5ad0daSSasha Neftin 		/* nothing to do */
6108c5ad0daSSasha Neftin 		return 0;
6118c5ad0daSSasha Neftin 	}
6128c5ad0daSSasha Neftin 
6138c5ad0daSSasha Neftin 	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
6148c5ad0daSSasha Neftin 		usleep_range(1000, 2000);
6158c5ad0daSSasha Neftin 
6168c5ad0daSSasha Neftin 	if (!netif_running(adapter->netdev)) {
6178c5ad0daSSasha Neftin 		for (i = 0; i < adapter->num_tx_queues; i++)
6188c5ad0daSSasha Neftin 			adapter->tx_ring[i]->count = new_tx_count;
6198c5ad0daSSasha Neftin 		for (i = 0; i < adapter->num_rx_queues; i++)
6208c5ad0daSSasha Neftin 			adapter->rx_ring[i]->count = new_rx_count;
6218c5ad0daSSasha Neftin 		adapter->tx_ring_count = new_tx_count;
6228c5ad0daSSasha Neftin 		adapter->rx_ring_count = new_rx_count;
6238c5ad0daSSasha Neftin 		goto clear_reset;
6248c5ad0daSSasha Neftin 	}
6258c5ad0daSSasha Neftin 
6268c5ad0daSSasha Neftin 	if (adapter->num_tx_queues > adapter->num_rx_queues)
6278c5ad0daSSasha Neftin 		temp_ring = vmalloc(array_size(sizeof(struct igc_ring),
6288c5ad0daSSasha Neftin 					       adapter->num_tx_queues));
6298c5ad0daSSasha Neftin 	else
6308c5ad0daSSasha Neftin 		temp_ring = vmalloc(array_size(sizeof(struct igc_ring),
6318c5ad0daSSasha Neftin 					       adapter->num_rx_queues));
6328c5ad0daSSasha Neftin 
6338c5ad0daSSasha Neftin 	if (!temp_ring) {
6348c5ad0daSSasha Neftin 		err = -ENOMEM;
6358c5ad0daSSasha Neftin 		goto clear_reset;
6368c5ad0daSSasha Neftin 	}
6378c5ad0daSSasha Neftin 
6388c5ad0daSSasha Neftin 	igc_down(adapter);
6398c5ad0daSSasha Neftin 
6408c5ad0daSSasha Neftin 	/* We can't just free everything and then setup again,
6418c5ad0daSSasha Neftin 	 * because the ISRs in MSI-X mode get passed pointers
6428c5ad0daSSasha Neftin 	 * to the Tx and Rx ring structs.
6438c5ad0daSSasha Neftin 	 */
6448c5ad0daSSasha Neftin 	if (new_tx_count != adapter->tx_ring_count) {
6458c5ad0daSSasha Neftin 		for (i = 0; i < adapter->num_tx_queues; i++) {
6468c5ad0daSSasha Neftin 			memcpy(&temp_ring[i], adapter->tx_ring[i],
6478c5ad0daSSasha Neftin 			       sizeof(struct igc_ring));
6488c5ad0daSSasha Neftin 
6498c5ad0daSSasha Neftin 			temp_ring[i].count = new_tx_count;
6508c5ad0daSSasha Neftin 			err = igc_setup_tx_resources(&temp_ring[i]);
6518c5ad0daSSasha Neftin 			if (err) {
6528c5ad0daSSasha Neftin 				while (i) {
6538c5ad0daSSasha Neftin 					i--;
6548c5ad0daSSasha Neftin 					igc_free_tx_resources(&temp_ring[i]);
6558c5ad0daSSasha Neftin 				}
6568c5ad0daSSasha Neftin 				goto err_setup;
6578c5ad0daSSasha Neftin 			}
6588c5ad0daSSasha Neftin 		}
6598c5ad0daSSasha Neftin 
6608c5ad0daSSasha Neftin 		for (i = 0; i < adapter->num_tx_queues; i++) {
6618c5ad0daSSasha Neftin 			igc_free_tx_resources(adapter->tx_ring[i]);
6628c5ad0daSSasha Neftin 
6638c5ad0daSSasha Neftin 			memcpy(adapter->tx_ring[i], &temp_ring[i],
6648c5ad0daSSasha Neftin 			       sizeof(struct igc_ring));
6658c5ad0daSSasha Neftin 		}
6668c5ad0daSSasha Neftin 
6678c5ad0daSSasha Neftin 		adapter->tx_ring_count = new_tx_count;
6688c5ad0daSSasha Neftin 	}
6698c5ad0daSSasha Neftin 
6708c5ad0daSSasha Neftin 	if (new_rx_count != adapter->rx_ring_count) {
6718c5ad0daSSasha Neftin 		for (i = 0; i < adapter->num_rx_queues; i++) {
6728c5ad0daSSasha Neftin 			memcpy(&temp_ring[i], adapter->rx_ring[i],
6738c5ad0daSSasha Neftin 			       sizeof(struct igc_ring));
6748c5ad0daSSasha Neftin 
6758c5ad0daSSasha Neftin 			temp_ring[i].count = new_rx_count;
6768c5ad0daSSasha Neftin 			err = igc_setup_rx_resources(&temp_ring[i]);
6778c5ad0daSSasha Neftin 			if (err) {
6788c5ad0daSSasha Neftin 				while (i) {
6798c5ad0daSSasha Neftin 					i--;
6808c5ad0daSSasha Neftin 					igc_free_rx_resources(&temp_ring[i]);
6818c5ad0daSSasha Neftin 				}
6828c5ad0daSSasha Neftin 				goto err_setup;
6838c5ad0daSSasha Neftin 			}
6848c5ad0daSSasha Neftin 		}
6858c5ad0daSSasha Neftin 
6868c5ad0daSSasha Neftin 		for (i = 0; i < adapter->num_rx_queues; i++) {
6878c5ad0daSSasha Neftin 			igc_free_rx_resources(adapter->rx_ring[i]);
6888c5ad0daSSasha Neftin 
6898c5ad0daSSasha Neftin 			memcpy(adapter->rx_ring[i], &temp_ring[i],
6908c5ad0daSSasha Neftin 			       sizeof(struct igc_ring));
6918c5ad0daSSasha Neftin 		}
6928c5ad0daSSasha Neftin 
6938c5ad0daSSasha Neftin 		adapter->rx_ring_count = new_rx_count;
6948c5ad0daSSasha Neftin 	}
6958c5ad0daSSasha Neftin err_setup:
6968c5ad0daSSasha Neftin 	igc_up(adapter);
6978c5ad0daSSasha Neftin 	vfree(temp_ring);
6988c5ad0daSSasha Neftin clear_reset:
6998c5ad0daSSasha Neftin 	clear_bit(__IGC_RESETTING, &adapter->state);
7008c5ad0daSSasha Neftin 	return err;
7018c5ad0daSSasha Neftin }
7028c5ad0daSSasha Neftin 
igc_ethtool_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)7037df76bd1SAndre Guedes static void igc_ethtool_get_pauseparam(struct net_device *netdev,
7048c5ad0daSSasha Neftin 				       struct ethtool_pauseparam *pause)
7058c5ad0daSSasha Neftin {
7068c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
7078c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
7088c5ad0daSSasha Neftin 
7098c5ad0daSSasha Neftin 	pause->autoneg =
7108c5ad0daSSasha Neftin 		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
7118c5ad0daSSasha Neftin 
7128c5ad0daSSasha Neftin 	if (hw->fc.current_mode == igc_fc_rx_pause) {
7138c5ad0daSSasha Neftin 		pause->rx_pause = 1;
7148c5ad0daSSasha Neftin 	} else if (hw->fc.current_mode == igc_fc_tx_pause) {
7158c5ad0daSSasha Neftin 		pause->tx_pause = 1;
7168c5ad0daSSasha Neftin 	} else if (hw->fc.current_mode == igc_fc_full) {
7178c5ad0daSSasha Neftin 		pause->rx_pause = 1;
7188c5ad0daSSasha Neftin 		pause->tx_pause = 1;
7198c5ad0daSSasha Neftin 	}
7208c5ad0daSSasha Neftin }
7218c5ad0daSSasha Neftin 
igc_ethtool_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)7227df76bd1SAndre Guedes static int igc_ethtool_set_pauseparam(struct net_device *netdev,
7238c5ad0daSSasha Neftin 				      struct ethtool_pauseparam *pause)
7248c5ad0daSSasha Neftin {
7258c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
7268c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
7278c5ad0daSSasha Neftin 	int retval = 0;
7288c5ad0daSSasha Neftin 
7298c5ad0daSSasha Neftin 	adapter->fc_autoneg = pause->autoneg;
7308c5ad0daSSasha Neftin 
7318c5ad0daSSasha Neftin 	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
7328c5ad0daSSasha Neftin 		usleep_range(1000, 2000);
7338c5ad0daSSasha Neftin 
7348c5ad0daSSasha Neftin 	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
7358c5ad0daSSasha Neftin 		hw->fc.requested_mode = igc_fc_default;
7368c5ad0daSSasha Neftin 		if (netif_running(adapter->netdev)) {
7378c5ad0daSSasha Neftin 			igc_down(adapter);
7388c5ad0daSSasha Neftin 			igc_up(adapter);
7398c5ad0daSSasha Neftin 		} else {
7408c5ad0daSSasha Neftin 			igc_reset(adapter);
7418c5ad0daSSasha Neftin 		}
7428c5ad0daSSasha Neftin 	} else {
7438c5ad0daSSasha Neftin 		if (pause->rx_pause && pause->tx_pause)
7448c5ad0daSSasha Neftin 			hw->fc.requested_mode = igc_fc_full;
7458c5ad0daSSasha Neftin 		else if (pause->rx_pause && !pause->tx_pause)
7468c5ad0daSSasha Neftin 			hw->fc.requested_mode = igc_fc_rx_pause;
7478c5ad0daSSasha Neftin 		else if (!pause->rx_pause && pause->tx_pause)
7488c5ad0daSSasha Neftin 			hw->fc.requested_mode = igc_fc_tx_pause;
7498c5ad0daSSasha Neftin 		else if (!pause->rx_pause && !pause->tx_pause)
7508c5ad0daSSasha Neftin 			hw->fc.requested_mode = igc_fc_none;
7518c5ad0daSSasha Neftin 
7528c5ad0daSSasha Neftin 		hw->fc.current_mode = hw->fc.requested_mode;
7538c5ad0daSSasha Neftin 
7548c5ad0daSSasha Neftin 		retval = ((hw->phy.media_type == igc_media_type_copper) ?
7558c5ad0daSSasha Neftin 			  igc_force_mac_fc(hw) : igc_setup_link(hw));
7568c5ad0daSSasha Neftin 	}
7578c5ad0daSSasha Neftin 
7588c5ad0daSSasha Neftin 	clear_bit(__IGC_RESETTING, &adapter->state);
7598c5ad0daSSasha Neftin 	return retval;
7608c5ad0daSSasha Neftin }
7618c5ad0daSSasha Neftin 
igc_ethtool_get_strings(struct net_device * netdev,u32 stringset,u8 * data)7627df76bd1SAndre Guedes static void igc_ethtool_get_strings(struct net_device *netdev, u32 stringset,
7637df76bd1SAndre Guedes 				    u8 *data)
76436b9fea6SSasha Neftin {
76536b9fea6SSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
76636b9fea6SSasha Neftin 	u8 *p = data;
76736b9fea6SSasha Neftin 	int i;
76836b9fea6SSasha Neftin 
76936b9fea6SSasha Neftin 	switch (stringset) {
77036b9fea6SSasha Neftin 	case ETH_SS_TEST:
77136b9fea6SSasha Neftin 		memcpy(data, *igc_gstrings_test,
77236b9fea6SSasha Neftin 		       IGC_TEST_LEN * ETH_GSTRING_LEN);
77336b9fea6SSasha Neftin 		break;
77436b9fea6SSasha Neftin 	case ETH_SS_STATS:
775220ef1f9SSasha Neftin 		for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++)
776e403cfffSjustinstitt@google.com 			ethtool_puts(&p, igc_gstrings_stats[i].stat_string);
777220ef1f9SSasha Neftin 		for (i = 0; i < IGC_NETDEV_STATS_LEN; i++)
778e403cfffSjustinstitt@google.com 			ethtool_puts(&p, igc_gstrings_net_stats[i].stat_string);
77936b9fea6SSasha Neftin 		for (i = 0; i < adapter->num_tx_queues; i++) {
780220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "tx_queue_%u_packets", i);
781220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
782220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "tx_queue_%u_restart", i);
78336b9fea6SSasha Neftin 		}
78436b9fea6SSasha Neftin 		for (i = 0; i < adapter->num_rx_queues; i++) {
785220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "rx_queue_%u_packets", i);
786220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "rx_queue_%u_bytes", i);
787220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "rx_queue_%u_drops", i);
788220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "rx_queue_%u_csum_err", i);
789220ef1f9SSasha Neftin 			ethtool_sprintf(&p, "rx_queue_%u_alloc_failed", i);
79036b9fea6SSasha Neftin 		}
79136b9fea6SSasha Neftin 		/* BUG_ON(p - data != IGC_STATS_LEN * ETH_GSTRING_LEN); */
79236b9fea6SSasha Neftin 		break;
79336b9fea6SSasha Neftin 	case ETH_SS_PRIV_FLAGS:
79436b9fea6SSasha Neftin 		memcpy(data, igc_priv_flags_strings,
79536b9fea6SSasha Neftin 		       IGC_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN);
79636b9fea6SSasha Neftin 		break;
79736b9fea6SSasha Neftin 	}
79836b9fea6SSasha Neftin }
79936b9fea6SSasha Neftin 
igc_ethtool_get_sset_count(struct net_device * netdev,int sset)8007df76bd1SAndre Guedes static int igc_ethtool_get_sset_count(struct net_device *netdev, int sset)
80136b9fea6SSasha Neftin {
80236b9fea6SSasha Neftin 	switch (sset) {
80336b9fea6SSasha Neftin 	case ETH_SS_STATS:
80436b9fea6SSasha Neftin 		return IGC_STATS_LEN;
80536b9fea6SSasha Neftin 	case ETH_SS_TEST:
80636b9fea6SSasha Neftin 		return IGC_TEST_LEN;
80736b9fea6SSasha Neftin 	case ETH_SS_PRIV_FLAGS:
80836b9fea6SSasha Neftin 		return IGC_PRIV_FLAGS_STR_LEN;
80936b9fea6SSasha Neftin 	default:
81036b9fea6SSasha Neftin 		return -ENOTSUPP;
81136b9fea6SSasha Neftin 	}
81236b9fea6SSasha Neftin }
81336b9fea6SSasha Neftin 
igc_ethtool_get_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)8147df76bd1SAndre Guedes static void igc_ethtool_get_stats(struct net_device *netdev,
81536b9fea6SSasha Neftin 				  struct ethtool_stats *stats, u64 *data)
81636b9fea6SSasha Neftin {
81736b9fea6SSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
81836b9fea6SSasha Neftin 	struct rtnl_link_stats64 *net_stats = &adapter->stats64;
81936b9fea6SSasha Neftin 	unsigned int start;
82036b9fea6SSasha Neftin 	struct igc_ring *ring;
82136b9fea6SSasha Neftin 	int i, j;
82236b9fea6SSasha Neftin 	char *p;
82336b9fea6SSasha Neftin 
82436b9fea6SSasha Neftin 	spin_lock(&adapter->stats64_lock);
82536b9fea6SSasha Neftin 	igc_update_stats(adapter);
82636b9fea6SSasha Neftin 
82736b9fea6SSasha Neftin 	for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) {
82836b9fea6SSasha Neftin 		p = (char *)adapter + igc_gstrings_stats[i].stat_offset;
82936b9fea6SSasha Neftin 		data[i] = (igc_gstrings_stats[i].sizeof_stat ==
83036b9fea6SSasha Neftin 			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
83136b9fea6SSasha Neftin 	}
83236b9fea6SSasha Neftin 	for (j = 0; j < IGC_NETDEV_STATS_LEN; j++, i++) {
83336b9fea6SSasha Neftin 		p = (char *)net_stats + igc_gstrings_net_stats[j].stat_offset;
83436b9fea6SSasha Neftin 		data[i] = (igc_gstrings_net_stats[j].sizeof_stat ==
83536b9fea6SSasha Neftin 			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
83636b9fea6SSasha Neftin 	}
83736b9fea6SSasha Neftin 	for (j = 0; j < adapter->num_tx_queues; j++) {
83836b9fea6SSasha Neftin 		u64	restart2;
83936b9fea6SSasha Neftin 
84036b9fea6SSasha Neftin 		ring = adapter->tx_ring[j];
84136b9fea6SSasha Neftin 		do {
842068c38adSThomas Gleixner 			start = u64_stats_fetch_begin(&ring->tx_syncp);
84336b9fea6SSasha Neftin 			data[i]   = ring->tx_stats.packets;
84436b9fea6SSasha Neftin 			data[i + 1] = ring->tx_stats.bytes;
84536b9fea6SSasha Neftin 			data[i + 2] = ring->tx_stats.restart_queue;
846068c38adSThomas Gleixner 		} while (u64_stats_fetch_retry(&ring->tx_syncp, start));
84736b9fea6SSasha Neftin 		do {
848068c38adSThomas Gleixner 			start = u64_stats_fetch_begin(&ring->tx_syncp2);
84936b9fea6SSasha Neftin 			restart2  = ring->tx_stats.restart_queue2;
850068c38adSThomas Gleixner 		} while (u64_stats_fetch_retry(&ring->tx_syncp2, start));
85136b9fea6SSasha Neftin 		data[i + 2] += restart2;
85236b9fea6SSasha Neftin 
85336b9fea6SSasha Neftin 		i += IGC_TX_QUEUE_STATS_LEN;
85436b9fea6SSasha Neftin 	}
85536b9fea6SSasha Neftin 	for (j = 0; j < adapter->num_rx_queues; j++) {
85636b9fea6SSasha Neftin 		ring = adapter->rx_ring[j];
85736b9fea6SSasha Neftin 		do {
858068c38adSThomas Gleixner 			start = u64_stats_fetch_begin(&ring->rx_syncp);
85936b9fea6SSasha Neftin 			data[i]   = ring->rx_stats.packets;
86036b9fea6SSasha Neftin 			data[i + 1] = ring->rx_stats.bytes;
86136b9fea6SSasha Neftin 			data[i + 2] = ring->rx_stats.drops;
86236b9fea6SSasha Neftin 			data[i + 3] = ring->rx_stats.csum_err;
86336b9fea6SSasha Neftin 			data[i + 4] = ring->rx_stats.alloc_failed;
864068c38adSThomas Gleixner 		} while (u64_stats_fetch_retry(&ring->rx_syncp, start));
86536b9fea6SSasha Neftin 		i += IGC_RX_QUEUE_STATS_LEN;
86636b9fea6SSasha Neftin 	}
86736b9fea6SSasha Neftin 	spin_unlock(&adapter->stats64_lock);
86836b9fea6SSasha Neftin }
86936b9fea6SSasha Neftin 
igc_ethtool_get_previous_rx_coalesce(struct igc_adapter * adapter)8701703b2e0SMuhammad Husaini Zulkifli static int igc_ethtool_get_previous_rx_coalesce(struct igc_adapter *adapter)
8711703b2e0SMuhammad Husaini Zulkifli {
8721703b2e0SMuhammad Husaini Zulkifli 	return (adapter->rx_itr_setting <= 3) ?
8731703b2e0SMuhammad Husaini Zulkifli 		adapter->rx_itr_setting : adapter->rx_itr_setting >> 2;
8741703b2e0SMuhammad Husaini Zulkifli }
8751703b2e0SMuhammad Husaini Zulkifli 
igc_ethtool_get_previous_tx_coalesce(struct igc_adapter * adapter)8761703b2e0SMuhammad Husaini Zulkifli static int igc_ethtool_get_previous_tx_coalesce(struct igc_adapter *adapter)
8771703b2e0SMuhammad Husaini Zulkifli {
8781703b2e0SMuhammad Husaini Zulkifli 	return (adapter->tx_itr_setting <= 3) ?
8791703b2e0SMuhammad Husaini Zulkifli 		adapter->tx_itr_setting : adapter->tx_itr_setting >> 2;
8801703b2e0SMuhammad Husaini Zulkifli }
8811703b2e0SMuhammad Husaini Zulkifli 
igc_ethtool_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)8827df76bd1SAndre Guedes static int igc_ethtool_get_coalesce(struct net_device *netdev,
883f3ccfda1SYufeng Mo 				    struct ethtool_coalesce *ec,
884f3ccfda1SYufeng Mo 				    struct kernel_ethtool_coalesce *kernel_coal,
885f3ccfda1SYufeng Mo 				    struct netlink_ext_ack *extack)
8868c5ad0daSSasha Neftin {
8878c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
8888c5ad0daSSasha Neftin 
8891703b2e0SMuhammad Husaini Zulkifli 	ec->rx_coalesce_usecs = igc_ethtool_get_previous_rx_coalesce(adapter);
8901703b2e0SMuhammad Husaini Zulkifli 	ec->tx_coalesce_usecs = igc_ethtool_get_previous_tx_coalesce(adapter);
8918c5ad0daSSasha Neftin 
8928c5ad0daSSasha Neftin 	return 0;
8938c5ad0daSSasha Neftin }
8948c5ad0daSSasha Neftin 
igc_ethtool_set_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)8957df76bd1SAndre Guedes static int igc_ethtool_set_coalesce(struct net_device *netdev,
896f3ccfda1SYufeng Mo 				    struct ethtool_coalesce *ec,
897f3ccfda1SYufeng Mo 				    struct kernel_ethtool_coalesce *kernel_coal,
898f3ccfda1SYufeng Mo 				    struct netlink_ext_ack *extack)
8998c5ad0daSSasha Neftin {
9008c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
9018c5ad0daSSasha Neftin 	int i;
9028c5ad0daSSasha Neftin 
9038c5ad0daSSasha Neftin 	if (ec->rx_coalesce_usecs > IGC_MAX_ITR_USECS ||
9048c5ad0daSSasha Neftin 	    (ec->rx_coalesce_usecs > 3 &&
9058c5ad0daSSasha Neftin 	     ec->rx_coalesce_usecs < IGC_MIN_ITR_USECS) ||
9068c5ad0daSSasha Neftin 	    ec->rx_coalesce_usecs == 2)
9078c5ad0daSSasha Neftin 		return -EINVAL;
9088c5ad0daSSasha Neftin 
9098c5ad0daSSasha Neftin 	if (ec->tx_coalesce_usecs > IGC_MAX_ITR_USECS ||
9108c5ad0daSSasha Neftin 	    (ec->tx_coalesce_usecs > 3 &&
9118c5ad0daSSasha Neftin 	     ec->tx_coalesce_usecs < IGC_MIN_ITR_USECS) ||
9128c5ad0daSSasha Neftin 	    ec->tx_coalesce_usecs == 2)
9138c5ad0daSSasha Neftin 		return -EINVAL;
9148c5ad0daSSasha Neftin 
9151703b2e0SMuhammad Husaini Zulkifli 	if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS) &&
9161703b2e0SMuhammad Husaini Zulkifli 	    ec->tx_coalesce_usecs != igc_ethtool_get_previous_tx_coalesce(adapter)) {
9171703b2e0SMuhammad Husaini Zulkifli 		NL_SET_ERR_MSG_MOD(extack,
9181703b2e0SMuhammad Husaini Zulkifli 				   "Queue Pair mode enabled, both Rx and Tx coalescing controlled by rx-usecs");
9198c5ad0daSSasha Neftin 		return -EINVAL;
9201703b2e0SMuhammad Husaini Zulkifli 	}
9218c5ad0daSSasha Neftin 
9228c5ad0daSSasha Neftin 	/* If ITR is disabled, disable DMAC */
9238c5ad0daSSasha Neftin 	if (ec->rx_coalesce_usecs == 0) {
9248c5ad0daSSasha Neftin 		if (adapter->flags & IGC_FLAG_DMAC)
9258c5ad0daSSasha Neftin 			adapter->flags &= ~IGC_FLAG_DMAC;
9268c5ad0daSSasha Neftin 	}
9278c5ad0daSSasha Neftin 
9288c5ad0daSSasha Neftin 	/* convert to rate of irq's per second */
9298c5ad0daSSasha Neftin 	if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3)
9308c5ad0daSSasha Neftin 		adapter->rx_itr_setting = ec->rx_coalesce_usecs;
9318c5ad0daSSasha Neftin 	else
9328c5ad0daSSasha Neftin 		adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2;
9338c5ad0daSSasha Neftin 
9348c5ad0daSSasha Neftin 	/* convert to rate of irq's per second */
9358c5ad0daSSasha Neftin 	if (adapter->flags & IGC_FLAG_QUEUE_PAIRS)
9368c5ad0daSSasha Neftin 		adapter->tx_itr_setting = adapter->rx_itr_setting;
9378c5ad0daSSasha Neftin 	else if (ec->tx_coalesce_usecs && ec->tx_coalesce_usecs <= 3)
9388c5ad0daSSasha Neftin 		adapter->tx_itr_setting = ec->tx_coalesce_usecs;
9398c5ad0daSSasha Neftin 	else
9408c5ad0daSSasha Neftin 		adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2;
9418c5ad0daSSasha Neftin 
9428c5ad0daSSasha Neftin 	for (i = 0; i < adapter->num_q_vectors; i++) {
9438c5ad0daSSasha Neftin 		struct igc_q_vector *q_vector = adapter->q_vector[i];
9448c5ad0daSSasha Neftin 
9458c5ad0daSSasha Neftin 		q_vector->tx.work_limit = adapter->tx_work_limit;
9468c5ad0daSSasha Neftin 		if (q_vector->rx.ring)
9478c5ad0daSSasha Neftin 			q_vector->itr_val = adapter->rx_itr_setting;
9488c5ad0daSSasha Neftin 		else
9498c5ad0daSSasha Neftin 			q_vector->itr_val = adapter->tx_itr_setting;
9508c5ad0daSSasha Neftin 		if (q_vector->itr_val && q_vector->itr_val <= 3)
9518c5ad0daSSasha Neftin 			q_vector->itr_val = IGC_START_ITR;
9528c5ad0daSSasha Neftin 		q_vector->set_itr = 1;
9538c5ad0daSSasha Neftin 	}
9548c5ad0daSSasha Neftin 
9558c5ad0daSSasha Neftin 	return 0;
9568c5ad0daSSasha Neftin }
9578c5ad0daSSasha Neftin 
9586245c848SSasha Neftin #define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
959b5063cbeSKurt Kanzenbach #define VLAN_TCI_FULL_MASK ((__force __be16)~0)
igc_ethtool_get_nfc_rule(struct igc_adapter * adapter,struct ethtool_rxnfc * cmd)96097700bc8SAndre Guedes static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter,
9616245c848SSasha Neftin 				    struct ethtool_rxnfc *cmd)
9626245c848SSasha Neftin {
9636245c848SSasha Neftin 	struct ethtool_rx_flow_spec *fsp = &cmd->fs;
96497700bc8SAndre Guedes 	struct igc_nfc_rule *rule = NULL;
9656245c848SSasha Neftin 
96697700bc8SAndre Guedes 	cmd->data = IGC_MAX_RXNFC_RULES;
9676245c848SSasha Neftin 
96842fc5dc0SAndre Guedes 	mutex_lock(&adapter->nfc_rule_lock);
969b500350aSAndre Guedes 
97036fa2152SAndre Guedes 	rule = igc_get_nfc_rule(adapter, fsp->location);
97136fa2152SAndre Guedes 	if (!rule)
972b500350aSAndre Guedes 		goto out;
973876ea04dSAndre Guedes 
9746245c848SSasha Neftin 	fsp->flow_type = ETHER_FLOW;
9756245c848SSasha Neftin 	fsp->ring_cookie = rule->action;
976876ea04dSAndre Guedes 
9776245c848SSasha Neftin 	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
978c983e327SAndre Guedes 		fsp->h_u.ether_spec.h_proto = htons(rule->filter.etype);
9796245c848SSasha Neftin 		fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK;
9806245c848SSasha Neftin 	}
981876ea04dSAndre Guedes 
982088464abSKurt Kanzenbach 	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_ETYPE) {
983088464abSKurt Kanzenbach 		fsp->flow_type |= FLOW_EXT;
984b7471025SKurt Kanzenbach 		fsp->h_ext.vlan_etype = htons(rule->filter.vlan_etype);
985088464abSKurt Kanzenbach 		fsp->m_ext.vlan_etype = ETHER_TYPE_FULL_MASK;
986088464abSKurt Kanzenbach 	}
987088464abSKurt Kanzenbach 
9886245c848SSasha Neftin 	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
9896245c848SSasha Neftin 		fsp->flow_type |= FLOW_EXT;
990c983e327SAndre Guedes 		fsp->h_ext.vlan_tci = htons(rule->filter.vlan_tci);
991b5063cbeSKurt Kanzenbach 		fsp->m_ext.vlan_tci = htons(rule->filter.vlan_tci_mask);
9926245c848SSasha Neftin 	}
993876ea04dSAndre Guedes 
9946245c848SSasha Neftin 	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
9956245c848SSasha Neftin 		ether_addr_copy(fsp->h_u.ether_spec.h_dest,
9966245c848SSasha Neftin 				rule->filter.dst_addr);
9976245c848SSasha Neftin 		eth_broadcast_addr(fsp->m_u.ether_spec.h_dest);
9986245c848SSasha Neftin 	}
999876ea04dSAndre Guedes 
10006245c848SSasha Neftin 	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
10016245c848SSasha Neftin 		ether_addr_copy(fsp->h_u.ether_spec.h_source,
10026245c848SSasha Neftin 				rule->filter.src_addr);
10036245c848SSasha Neftin 		eth_broadcast_addr(fsp->m_u.ether_spec.h_source);
10046245c848SSasha Neftin 	}
10056245c848SSasha Neftin 
10062b477d05SKurt Kanzenbach 	if (rule->filter.match_flags & IGC_FILTER_FLAG_USER_DATA) {
10072b477d05SKurt Kanzenbach 		fsp->flow_type |= FLOW_EXT;
10082b477d05SKurt Kanzenbach 		memcpy(fsp->h_ext.data, rule->filter.user_data, sizeof(fsp->h_ext.data));
10092b477d05SKurt Kanzenbach 		memcpy(fsp->m_ext.data, rule->filter.user_mask, sizeof(fsp->m_ext.data));
10102b477d05SKurt Kanzenbach 	}
10112b477d05SKurt Kanzenbach 
101242fc5dc0SAndre Guedes 	mutex_unlock(&adapter->nfc_rule_lock);
10136245c848SSasha Neftin 	return 0;
1014b500350aSAndre Guedes 
1015b500350aSAndre Guedes out:
101642fc5dc0SAndre Guedes 	mutex_unlock(&adapter->nfc_rule_lock);
1017b500350aSAndre Guedes 	return -EINVAL;
10186245c848SSasha Neftin }
10196245c848SSasha Neftin 
igc_ethtool_get_nfc_rules(struct igc_adapter * adapter,struct ethtool_rxnfc * cmd,u32 * rule_locs)102097700bc8SAndre Guedes static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter,
10216245c848SSasha Neftin 				     struct ethtool_rxnfc *cmd,
10226245c848SSasha Neftin 				     u32 *rule_locs)
10236245c848SSasha Neftin {
102497700bc8SAndre Guedes 	struct igc_nfc_rule *rule;
10256245c848SSasha Neftin 	int cnt = 0;
10266245c848SSasha Neftin 
102797700bc8SAndre Guedes 	cmd->data = IGC_MAX_RXNFC_RULES;
10286245c848SSasha Neftin 
102942fc5dc0SAndre Guedes 	mutex_lock(&adapter->nfc_rule_lock);
1030b500350aSAndre Guedes 
1031d957c601SAndre Guedes 	list_for_each_entry(rule, &adapter->nfc_rule_list, list) {
1032b500350aSAndre Guedes 		if (cnt == cmd->rule_cnt) {
103342fc5dc0SAndre Guedes 			mutex_unlock(&adapter->nfc_rule_lock);
10346245c848SSasha Neftin 			return -EMSGSIZE;
1035b500350aSAndre Guedes 		}
1036d3ba9e6fSAndre Guedes 		rule_locs[cnt] = rule->location;
10376245c848SSasha Neftin 		cnt++;
10386245c848SSasha Neftin 	}
10396245c848SSasha Neftin 
104042fc5dc0SAndre Guedes 	mutex_unlock(&adapter->nfc_rule_lock);
1041b500350aSAndre Guedes 
10426245c848SSasha Neftin 	cmd->rule_cnt = cnt;
10436245c848SSasha Neftin 
10446245c848SSasha Neftin 	return 0;
10456245c848SSasha Neftin }
10466245c848SSasha Neftin 
igc_ethtool_get_rss_hash_opts(struct igc_adapter * adapter,struct ethtool_rxnfc * cmd)10477df76bd1SAndre Guedes static int igc_ethtool_get_rss_hash_opts(struct igc_adapter *adapter,
10486245c848SSasha Neftin 					 struct ethtool_rxnfc *cmd)
10496245c848SSasha Neftin {
10506245c848SSasha Neftin 	cmd->data = 0;
10516245c848SSasha Neftin 
10526245c848SSasha Neftin 	/* Report default options for RSS on igc */
10536245c848SSasha Neftin 	switch (cmd->flow_type) {
10546245c848SSasha Neftin 	case TCP_V4_FLOW:
10556245c848SSasha Neftin 		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10565463fce6SJeff Kirsher 		fallthrough;
10576245c848SSasha Neftin 	case UDP_V4_FLOW:
10586245c848SSasha Neftin 		if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV4_UDP)
10596245c848SSasha Neftin 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10605463fce6SJeff Kirsher 		fallthrough;
10616245c848SSasha Neftin 	case SCTP_V4_FLOW:
10626245c848SSasha Neftin 	case AH_ESP_V4_FLOW:
10636245c848SSasha Neftin 	case AH_V4_FLOW:
10646245c848SSasha Neftin 	case ESP_V4_FLOW:
10656245c848SSasha Neftin 	case IPV4_FLOW:
10666245c848SSasha Neftin 		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
10676245c848SSasha Neftin 		break;
10686245c848SSasha Neftin 	case TCP_V6_FLOW:
10696245c848SSasha Neftin 		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10705463fce6SJeff Kirsher 		fallthrough;
10716245c848SSasha Neftin 	case UDP_V6_FLOW:
10726245c848SSasha Neftin 		if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV6_UDP)
10736245c848SSasha Neftin 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10745463fce6SJeff Kirsher 		fallthrough;
10756245c848SSasha Neftin 	case SCTP_V6_FLOW:
10766245c848SSasha Neftin 	case AH_ESP_V6_FLOW:
10776245c848SSasha Neftin 	case AH_V6_FLOW:
10786245c848SSasha Neftin 	case ESP_V6_FLOW:
10796245c848SSasha Neftin 	case IPV6_FLOW:
10806245c848SSasha Neftin 		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
10816245c848SSasha Neftin 		break;
10826245c848SSasha Neftin 	default:
10836245c848SSasha Neftin 		return -EINVAL;
10846245c848SSasha Neftin 	}
10856245c848SSasha Neftin 
10866245c848SSasha Neftin 	return 0;
10876245c848SSasha Neftin }
10886245c848SSasha Neftin 
igc_ethtool_get_rxnfc(struct net_device * dev,struct ethtool_rxnfc * cmd,u32 * rule_locs)10897df76bd1SAndre Guedes static int igc_ethtool_get_rxnfc(struct net_device *dev,
10907df76bd1SAndre Guedes 				 struct ethtool_rxnfc *cmd, u32 *rule_locs)
10916245c848SSasha Neftin {
10926245c848SSasha Neftin 	struct igc_adapter *adapter = netdev_priv(dev);
10936245c848SSasha Neftin 
10946245c848SSasha Neftin 	switch (cmd->cmd) {
10956245c848SSasha Neftin 	case ETHTOOL_GRXRINGS:
10966245c848SSasha Neftin 		cmd->data = adapter->num_rx_queues;
10978b9c23cdSAndre Guedes 		return 0;
10986245c848SSasha Neftin 	case ETHTOOL_GRXCLSRLCNT:
109997700bc8SAndre Guedes 		cmd->rule_cnt = adapter->nfc_rule_count;
11008b9c23cdSAndre Guedes 		return 0;
11016245c848SSasha Neftin 	case ETHTOOL_GRXCLSRULE:
110297700bc8SAndre Guedes 		return igc_ethtool_get_nfc_rule(adapter, cmd);
11036245c848SSasha Neftin 	case ETHTOOL_GRXCLSRLALL:
110497700bc8SAndre Guedes 		return igc_ethtool_get_nfc_rules(adapter, cmd, rule_locs);
11056245c848SSasha Neftin 	case ETHTOOL_GRXFH:
11067df76bd1SAndre Guedes 		return igc_ethtool_get_rss_hash_opts(adapter, cmd);
11076245c848SSasha Neftin 	default:
11088b9c23cdSAndre Guedes 		return -EOPNOTSUPP;
11096245c848SSasha Neftin 	}
11106245c848SSasha Neftin }
11116245c848SSasha Neftin 
11126245c848SSasha Neftin #define UDP_RSS_FLAGS (IGC_FLAG_RSS_FIELD_IPV4_UDP | \
11136245c848SSasha Neftin 		       IGC_FLAG_RSS_FIELD_IPV6_UDP)
igc_ethtool_set_rss_hash_opt(struct igc_adapter * adapter,struct ethtool_rxnfc * nfc)11147df76bd1SAndre Guedes static int igc_ethtool_set_rss_hash_opt(struct igc_adapter *adapter,
11156245c848SSasha Neftin 					struct ethtool_rxnfc *nfc)
11166245c848SSasha Neftin {
11176245c848SSasha Neftin 	u32 flags = adapter->flags;
11186245c848SSasha Neftin 
11196245c848SSasha Neftin 	/* RSS does not support anything other than hashing
11206245c848SSasha Neftin 	 * to queues on src and dst IPs and ports
11216245c848SSasha Neftin 	 */
11226245c848SSasha Neftin 	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
11236245c848SSasha Neftin 			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
11246245c848SSasha Neftin 		return -EINVAL;
11256245c848SSasha Neftin 
11266245c848SSasha Neftin 	switch (nfc->flow_type) {
11276245c848SSasha Neftin 	case TCP_V4_FLOW:
11286245c848SSasha Neftin 	case TCP_V6_FLOW:
11296245c848SSasha Neftin 		if (!(nfc->data & RXH_IP_SRC) ||
11306245c848SSasha Neftin 		    !(nfc->data & RXH_IP_DST) ||
11316245c848SSasha Neftin 		    !(nfc->data & RXH_L4_B_0_1) ||
11326245c848SSasha Neftin 		    !(nfc->data & RXH_L4_B_2_3))
11336245c848SSasha Neftin 			return -EINVAL;
11346245c848SSasha Neftin 		break;
11356245c848SSasha Neftin 	case UDP_V4_FLOW:
11366245c848SSasha Neftin 		if (!(nfc->data & RXH_IP_SRC) ||
11376245c848SSasha Neftin 		    !(nfc->data & RXH_IP_DST))
11386245c848SSasha Neftin 			return -EINVAL;
11396245c848SSasha Neftin 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
11406245c848SSasha Neftin 		case 0:
11416245c848SSasha Neftin 			flags &= ~IGC_FLAG_RSS_FIELD_IPV4_UDP;
11426245c848SSasha Neftin 			break;
11436245c848SSasha Neftin 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
11446245c848SSasha Neftin 			flags |= IGC_FLAG_RSS_FIELD_IPV4_UDP;
11456245c848SSasha Neftin 			break;
11466245c848SSasha Neftin 		default:
11476245c848SSasha Neftin 			return -EINVAL;
11486245c848SSasha Neftin 		}
11496245c848SSasha Neftin 		break;
11506245c848SSasha Neftin 	case UDP_V6_FLOW:
11516245c848SSasha Neftin 		if (!(nfc->data & RXH_IP_SRC) ||
11526245c848SSasha Neftin 		    !(nfc->data & RXH_IP_DST))
11536245c848SSasha Neftin 			return -EINVAL;
11546245c848SSasha Neftin 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
11556245c848SSasha Neftin 		case 0:
11566245c848SSasha Neftin 			flags &= ~IGC_FLAG_RSS_FIELD_IPV6_UDP;
11576245c848SSasha Neftin 			break;
11586245c848SSasha Neftin 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
11596245c848SSasha Neftin 			flags |= IGC_FLAG_RSS_FIELD_IPV6_UDP;
11606245c848SSasha Neftin 			break;
11616245c848SSasha Neftin 		default:
11626245c848SSasha Neftin 			return -EINVAL;
11636245c848SSasha Neftin 		}
11646245c848SSasha Neftin 		break;
11656245c848SSasha Neftin 	case AH_ESP_V4_FLOW:
11666245c848SSasha Neftin 	case AH_V4_FLOW:
11676245c848SSasha Neftin 	case ESP_V4_FLOW:
11686245c848SSasha Neftin 	case SCTP_V4_FLOW:
11696245c848SSasha Neftin 	case AH_ESP_V6_FLOW:
11706245c848SSasha Neftin 	case AH_V6_FLOW:
11716245c848SSasha Neftin 	case ESP_V6_FLOW:
11726245c848SSasha Neftin 	case SCTP_V6_FLOW:
11736245c848SSasha Neftin 		if (!(nfc->data & RXH_IP_SRC) ||
11746245c848SSasha Neftin 		    !(nfc->data & RXH_IP_DST) ||
11756245c848SSasha Neftin 		    (nfc->data & RXH_L4_B_0_1) ||
11766245c848SSasha Neftin 		    (nfc->data & RXH_L4_B_2_3))
11776245c848SSasha Neftin 			return -EINVAL;
11786245c848SSasha Neftin 		break;
11796245c848SSasha Neftin 	default:
11806245c848SSasha Neftin 		return -EINVAL;
11816245c848SSasha Neftin 	}
11826245c848SSasha Neftin 
11836245c848SSasha Neftin 	/* if we changed something we need to update flags */
11846245c848SSasha Neftin 	if (flags != adapter->flags) {
11856245c848SSasha Neftin 		struct igc_hw *hw = &adapter->hw;
11866245c848SSasha Neftin 		u32 mrqc = rd32(IGC_MRQC);
11876245c848SSasha Neftin 
11886245c848SSasha Neftin 		if ((flags & UDP_RSS_FLAGS) &&
11896245c848SSasha Neftin 		    !(adapter->flags & UDP_RSS_FLAGS))
119095f96a9fSAndre Guedes 			netdev_err(adapter->netdev,
119195f96a9fSAndre Guedes 				   "Enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");
11926245c848SSasha Neftin 
11936245c848SSasha Neftin 		adapter->flags = flags;
11946245c848SSasha Neftin 
11956245c848SSasha Neftin 		/* Perform hash on these packet types */
11966245c848SSasha Neftin 		mrqc |= IGC_MRQC_RSS_FIELD_IPV4 |
11976245c848SSasha Neftin 			IGC_MRQC_RSS_FIELD_IPV4_TCP |
11986245c848SSasha Neftin 			IGC_MRQC_RSS_FIELD_IPV6 |
11996245c848SSasha Neftin 			IGC_MRQC_RSS_FIELD_IPV6_TCP;
12006245c848SSasha Neftin 
12016245c848SSasha Neftin 		mrqc &= ~(IGC_MRQC_RSS_FIELD_IPV4_UDP |
12026245c848SSasha Neftin 			  IGC_MRQC_RSS_FIELD_IPV6_UDP);
12036245c848SSasha Neftin 
12046245c848SSasha Neftin 		if (flags & IGC_FLAG_RSS_FIELD_IPV4_UDP)
12056245c848SSasha Neftin 			mrqc |= IGC_MRQC_RSS_FIELD_IPV4_UDP;
12066245c848SSasha Neftin 
12076245c848SSasha Neftin 		if (flags & IGC_FLAG_RSS_FIELD_IPV6_UDP)
12086245c848SSasha Neftin 			mrqc |= IGC_MRQC_RSS_FIELD_IPV6_UDP;
12096245c848SSasha Neftin 
12106245c848SSasha Neftin 		wr32(IGC_MRQC, mrqc);
12116245c848SSasha Neftin 	}
12126245c848SSasha Neftin 
12136245c848SSasha Neftin 	return 0;
12146245c848SSasha Neftin }
12156245c848SSasha Neftin 
igc_ethtool_init_nfc_rule(struct igc_nfc_rule * rule,const struct ethtool_rx_flow_spec * fsp)121616fdc16cSAndre Guedes static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule,
121716fdc16cSAndre Guedes 				      const struct ethtool_rx_flow_spec *fsp)
12186245c848SSasha Neftin {
1219d957c601SAndre Guedes 	INIT_LIST_HEAD(&rule->list);
12206245c848SSasha Neftin 
122116fdc16cSAndre Guedes 	rule->action = fsp->ring_cookie;
1222d3ba9e6fSAndre Guedes 	rule->location = fsp->location;
12236245c848SSasha Neftin 
122416fdc16cSAndre Guedes 	if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) {
122516fdc16cSAndre Guedes 		rule->filter.vlan_tci = ntohs(fsp->h_ext.vlan_tci);
1226b5063cbeSKurt Kanzenbach 		rule->filter.vlan_tci_mask = ntohs(fsp->m_ext.vlan_tci);
122716fdc16cSAndre Guedes 		rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI;
12286245c848SSasha Neftin 	}
12296245c848SSasha Neftin 
12306245c848SSasha Neftin 	if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) {
1231c983e327SAndre Guedes 		rule->filter.etype = ntohs(fsp->h_u.ether_spec.h_proto);
123297700bc8SAndre Guedes 		rule->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE;
12336245c848SSasha Neftin 	}
12346245c848SSasha Neftin 
12358eb2449dSAndre Guedes 	/* Both source and destination address filters only support the full
12368eb2449dSAndre Guedes 	 * mask.
12378eb2449dSAndre Guedes 	 */
12386245c848SSasha Neftin 	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) {
123997700bc8SAndre Guedes 		rule->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR;
124097700bc8SAndre Guedes 		ether_addr_copy(rule->filter.src_addr,
12416245c848SSasha Neftin 				fsp->h_u.ether_spec.h_source);
12426245c848SSasha Neftin 	}
12436245c848SSasha Neftin 
12446245c848SSasha Neftin 	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) {
124597700bc8SAndre Guedes 		rule->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR;
124697700bc8SAndre Guedes 		ether_addr_copy(rule->filter.dst_addr,
12476245c848SSasha Neftin 				fsp->h_u.ether_spec.h_dest);
12486245c848SSasha Neftin 	}
12492b477d05SKurt Kanzenbach 
125073744262SKurt Kanzenbach 	/* VLAN etype matching */
125173744262SKurt Kanzenbach 	if ((fsp->flow_type & FLOW_EXT) && fsp->h_ext.vlan_etype) {
1252b7471025SKurt Kanzenbach 		rule->filter.vlan_etype = ntohs(fsp->h_ext.vlan_etype);
125373744262SKurt Kanzenbach 		rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_ETYPE;
125473744262SKurt Kanzenbach 	}
125573744262SKurt Kanzenbach 
12562b477d05SKurt Kanzenbach 	/* Check for user defined data */
12572b477d05SKurt Kanzenbach 	if ((fsp->flow_type & FLOW_EXT) &&
12582b477d05SKurt Kanzenbach 	    (fsp->h_ext.data[0] || fsp->h_ext.data[1])) {
12592b477d05SKurt Kanzenbach 		rule->filter.match_flags |= IGC_FILTER_FLAG_USER_DATA;
12602b477d05SKurt Kanzenbach 		memcpy(rule->filter.user_data, fsp->h_ext.data, sizeof(fsp->h_ext.data));
12612b477d05SKurt Kanzenbach 		memcpy(rule->filter.user_mask, fsp->m_ext.data, sizeof(fsp->m_ext.data));
126273744262SKurt Kanzenbach 	}
12632b477d05SKurt Kanzenbach 
1264b5063cbeSKurt Kanzenbach 	/* The i225/i226 has various different filters. Flex filters provide a
1265b5063cbeSKurt Kanzenbach 	 * way to match up to the first 128 bytes of a packet. Use them for:
1266b5063cbeSKurt Kanzenbach 	 *   a) For specific user data
1267b5063cbeSKurt Kanzenbach 	 *   b) For VLAN EtherType
1268b5063cbeSKurt Kanzenbach 	 *   c) For full TCI match
1269b5063cbeSKurt Kanzenbach 	 *   d) Or in case multiple filter criteria are set
1270b5063cbeSKurt Kanzenbach 	 *
1271b5063cbeSKurt Kanzenbach 	 * Otherwise, use the simple MAC, VLAN PRIO or EtherType filters.
127273744262SKurt Kanzenbach 	 */
127373744262SKurt Kanzenbach 	if ((rule->filter.match_flags & IGC_FILTER_FLAG_USER_DATA) ||
127473744262SKurt Kanzenbach 	    (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_ETYPE) ||
1275b5063cbeSKurt Kanzenbach 	    ((rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) &&
1276b5063cbeSKurt Kanzenbach 	     rule->filter.vlan_tci_mask == ntohs(VLAN_TCI_FULL_MASK)) ||
127773744262SKurt Kanzenbach 	    (rule->filter.match_flags & (rule->filter.match_flags - 1)))
127873744262SKurt Kanzenbach 		rule->flex = true;
127973744262SKurt Kanzenbach 	else
128073744262SKurt Kanzenbach 		rule->flex = false;
12818eb2449dSAndre Guedes }
12828eb2449dSAndre Guedes 
128316fdc16cSAndre Guedes /**
128416fdc16cSAndre Guedes  * igc_ethtool_check_nfc_rule() - Check if NFC rule is valid
128516fdc16cSAndre Guedes  * @adapter: Pointer to adapter
128616fdc16cSAndre Guedes  * @rule: Rule under evaluation
128716fdc16cSAndre Guedes  *
12883d3e9b6bSAndre Guedes  * The driver doesn't support rules with multiple matches so if more than
12893d3e9b6bSAndre Guedes  * one bit in filter flags is set, @rule is considered invalid.
129016fdc16cSAndre Guedes  *
12911894df0cSAndre Guedes  * Also, if there is already another rule with the same filter in a different
12921894df0cSAndre Guedes  * location, @rule is considered invalid.
129316fdc16cSAndre Guedes  *
129416fdc16cSAndre Guedes  * Context: Expects adapter->nfc_rule_lock to be held by caller.
129516fdc16cSAndre Guedes  *
129616fdc16cSAndre Guedes  * Return: 0 in case of success, negative errno code otherwise.
129716fdc16cSAndre Guedes  */
igc_ethtool_check_nfc_rule(struct igc_adapter * adapter,struct igc_nfc_rule * rule)129816fdc16cSAndre Guedes static int igc_ethtool_check_nfc_rule(struct igc_adapter *adapter,
129916fdc16cSAndre Guedes 				      struct igc_nfc_rule *rule)
130016fdc16cSAndre Guedes {
130116fdc16cSAndre Guedes 	struct net_device *dev = adapter->netdev;
130216fdc16cSAndre Guedes 	u8 flags = rule->filter.match_flags;
130316fdc16cSAndre Guedes 	struct igc_nfc_rule *tmp;
130416fdc16cSAndre Guedes 
130516fdc16cSAndre Guedes 	if (!flags) {
130616fdc16cSAndre Guedes 		netdev_dbg(dev, "Rule with no match\n");
130716fdc16cSAndre Guedes 		return -EINVAL;
13086245c848SSasha Neftin 	}
13096245c848SSasha Neftin 
1310d957c601SAndre Guedes 	list_for_each_entry(tmp, &adapter->nfc_rule_list, list) {
131197700bc8SAndre Guedes 		if (!memcmp(&rule->filter, &tmp->filter,
13121894df0cSAndre Guedes 			    sizeof(rule->filter)) &&
13131894df0cSAndre Guedes 		    tmp->location != rule->location) {
131416fdc16cSAndre Guedes 			netdev_dbg(dev, "Rule already exists\n");
131516fdc16cSAndre Guedes 			return -EEXIST;
13166245c848SSasha Neftin 		}
13176245c848SSasha Neftin 	}
13186245c848SSasha Neftin 
131916fdc16cSAndre Guedes 	return 0;
132016fdc16cSAndre Guedes }
132116fdc16cSAndre Guedes 
igc_ethtool_add_nfc_rule(struct igc_adapter * adapter,struct ethtool_rxnfc * cmd)132216fdc16cSAndre Guedes static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter,
132316fdc16cSAndre Guedes 				    struct ethtool_rxnfc *cmd)
132416fdc16cSAndre Guedes {
132516fdc16cSAndre Guedes 	struct net_device *netdev = adapter->netdev;
132616fdc16cSAndre Guedes 	struct ethtool_rx_flow_spec *fsp =
132716fdc16cSAndre Guedes 		(struct ethtool_rx_flow_spec *)&cmd->fs;
132836fa2152SAndre Guedes 	struct igc_nfc_rule *rule, *old_rule;
132916fdc16cSAndre Guedes 	int err;
133016fdc16cSAndre Guedes 
133116fdc16cSAndre Guedes 	if (!(netdev->hw_features & NETIF_F_NTUPLE)) {
133216fdc16cSAndre Guedes 		netdev_dbg(netdev, "N-tuple filters disabled\n");
133316fdc16cSAndre Guedes 		return -EOPNOTSUPP;
133416fdc16cSAndre Guedes 	}
133516fdc16cSAndre Guedes 
133616fdc16cSAndre Guedes 	if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) {
133716fdc16cSAndre Guedes 		netdev_dbg(netdev, "Only ethernet flow type is supported\n");
133816fdc16cSAndre Guedes 		return -EOPNOTSUPP;
133916fdc16cSAndre Guedes 	}
134016fdc16cSAndre Guedes 
134116fdc16cSAndre Guedes 	if (fsp->ring_cookie >= adapter->num_rx_queues) {
134216fdc16cSAndre Guedes 		netdev_dbg(netdev, "Invalid action\n");
134316fdc16cSAndre Guedes 		return -EINVAL;
134416fdc16cSAndre Guedes 	}
134516fdc16cSAndre Guedes 
1346b5063cbeSKurt Kanzenbach 	/* There are two ways to match the VLAN TCI:
1347b5063cbeSKurt Kanzenbach 	 *  1. Match on PCP field and use vlan prio filter for it
1348b5063cbeSKurt Kanzenbach 	 *  2. Match on complete TCI field and use flex filter for it
1349b5063cbeSKurt Kanzenbach 	 */
1350b5063cbeSKurt Kanzenbach 	if ((fsp->flow_type & FLOW_EXT) &&
1351b5063cbeSKurt Kanzenbach 	    fsp->m_ext.vlan_tci &&
1352b5063cbeSKurt Kanzenbach 	    fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK) &&
1353b5063cbeSKurt Kanzenbach 	    fsp->m_ext.vlan_tci != VLAN_TCI_FULL_MASK) {
1354b5063cbeSKurt Kanzenbach 		netdev_dbg(netdev, "VLAN mask not supported\n");
1355b5063cbeSKurt Kanzenbach 		return -EOPNOTSUPP;
1356b5063cbeSKurt Kanzenbach 	}
1357b5063cbeSKurt Kanzenbach 
13587afd49a3SKurt Kanzenbach 	/* VLAN EtherType can only be matched by full mask. */
13597afd49a3SKurt Kanzenbach 	if ((fsp->flow_type & FLOW_EXT) &&
13607afd49a3SKurt Kanzenbach 	    fsp->m_ext.vlan_etype &&
13617afd49a3SKurt Kanzenbach 	    fsp->m_ext.vlan_etype != ETHER_TYPE_FULL_MASK) {
13627afd49a3SKurt Kanzenbach 		netdev_dbg(netdev, "VLAN EtherType mask not supported\n");
13637afd49a3SKurt Kanzenbach 		return -EOPNOTSUPP;
13647afd49a3SKurt Kanzenbach 	}
13657afd49a3SKurt Kanzenbach 
136616fdc16cSAndre Guedes 	if (fsp->location >= IGC_MAX_RXNFC_RULES) {
136716fdc16cSAndre Guedes 		netdev_dbg(netdev, "Invalid location\n");
136816fdc16cSAndre Guedes 		return -EINVAL;
136916fdc16cSAndre Guedes 	}
137016fdc16cSAndre Guedes 
137116fdc16cSAndre Guedes 	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
137216fdc16cSAndre Guedes 	if (!rule)
137316fdc16cSAndre Guedes 		return -ENOMEM;
137416fdc16cSAndre Guedes 
137516fdc16cSAndre Guedes 	igc_ethtool_init_nfc_rule(rule, fsp);
137616fdc16cSAndre Guedes 
137742fc5dc0SAndre Guedes 	mutex_lock(&adapter->nfc_rule_lock);
137816fdc16cSAndre Guedes 
137916fdc16cSAndre Guedes 	err = igc_ethtool_check_nfc_rule(adapter, rule);
138016fdc16cSAndre Guedes 	if (err)
138116fdc16cSAndre Guedes 		goto err;
138216fdc16cSAndre Guedes 
138336fa2152SAndre Guedes 	old_rule = igc_get_nfc_rule(adapter, fsp->location);
138436fa2152SAndre Guedes 	if (old_rule)
138536fa2152SAndre Guedes 		igc_del_nfc_rule(adapter, old_rule);
138636fa2152SAndre Guedes 
138736fa2152SAndre Guedes 	err = igc_add_nfc_rule(adapter, rule);
13886245c848SSasha Neftin 	if (err)
138916fdc16cSAndre Guedes 		goto err;
13906245c848SSasha Neftin 
139142fc5dc0SAndre Guedes 	mutex_unlock(&adapter->nfc_rule_lock);
13926245c848SSasha Neftin 	return 0;
13936245c848SSasha Neftin 
139416fdc16cSAndre Guedes err:
139542fc5dc0SAndre Guedes 	mutex_unlock(&adapter->nfc_rule_lock);
139697700bc8SAndre Guedes 	kfree(rule);
13976245c848SSasha Neftin 	return err;
13986245c848SSasha Neftin }
13996245c848SSasha Neftin 
igc_ethtool_del_nfc_rule(struct igc_adapter * adapter,struct ethtool_rxnfc * cmd)140097700bc8SAndre Guedes static int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter,
14016245c848SSasha Neftin 				    struct ethtool_rxnfc *cmd)
14026245c848SSasha Neftin {
14036245c848SSasha Neftin 	struct ethtool_rx_flow_spec *fsp =
14046245c848SSasha Neftin 		(struct ethtool_rx_flow_spec *)&cmd->fs;
140536fa2152SAndre Guedes 	struct igc_nfc_rule *rule;
14066245c848SSasha Neftin 
140742fc5dc0SAndre Guedes 	mutex_lock(&adapter->nfc_rule_lock);
14086245c848SSasha Neftin 
140936fa2152SAndre Guedes 	rule = igc_get_nfc_rule(adapter, fsp->location);
141036fa2152SAndre Guedes 	if (!rule) {
141142fc5dc0SAndre Guedes 		mutex_unlock(&adapter->nfc_rule_lock);
141236fa2152SAndre Guedes 		return -EINVAL;
141336fa2152SAndre Guedes 	}
141436fa2152SAndre Guedes 
141536fa2152SAndre Guedes 	igc_del_nfc_rule(adapter, rule);
141636fa2152SAndre Guedes 
141742fc5dc0SAndre Guedes 	mutex_unlock(&adapter->nfc_rule_lock);
141836fa2152SAndre Guedes 	return 0;
14196245c848SSasha Neftin }
14206245c848SSasha Neftin 
igc_ethtool_set_rxnfc(struct net_device * dev,struct ethtool_rxnfc * cmd)14217df76bd1SAndre Guedes static int igc_ethtool_set_rxnfc(struct net_device *dev,
14227df76bd1SAndre Guedes 				 struct ethtool_rxnfc *cmd)
14236245c848SSasha Neftin {
14246245c848SSasha Neftin 	struct igc_adapter *adapter = netdev_priv(dev);
14256245c848SSasha Neftin 
14266245c848SSasha Neftin 	switch (cmd->cmd) {
14276245c848SSasha Neftin 	case ETHTOOL_SRXFH:
14287df76bd1SAndre Guedes 		return igc_ethtool_set_rss_hash_opt(adapter, cmd);
14296245c848SSasha Neftin 	case ETHTOOL_SRXCLSRLINS:
143097700bc8SAndre Guedes 		return igc_ethtool_add_nfc_rule(adapter, cmd);
14316245c848SSasha Neftin 	case ETHTOOL_SRXCLSRLDEL:
143297700bc8SAndre Guedes 		return igc_ethtool_del_nfc_rule(adapter, cmd);
14336245c848SSasha Neftin 	default:
14348b9c23cdSAndre Guedes 		return -EOPNOTSUPP;
14356245c848SSasha Neftin 	}
14366245c848SSasha Neftin }
14376245c848SSasha Neftin 
igc_write_rss_indir_tbl(struct igc_adapter * adapter)14388c5ad0daSSasha Neftin void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
14398c5ad0daSSasha Neftin {
14408c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
14418c5ad0daSSasha Neftin 	u32 reg = IGC_RETA(0);
14428c5ad0daSSasha Neftin 	u32 shift = 0;
14438c5ad0daSSasha Neftin 	int i = 0;
14448c5ad0daSSasha Neftin 
14458c5ad0daSSasha Neftin 	while (i < IGC_RETA_SIZE) {
14468c5ad0daSSasha Neftin 		u32 val = 0;
14478c5ad0daSSasha Neftin 		int j;
14488c5ad0daSSasha Neftin 
14498c5ad0daSSasha Neftin 		for (j = 3; j >= 0; j--) {
14508c5ad0daSSasha Neftin 			val <<= 8;
14518c5ad0daSSasha Neftin 			val |= adapter->rss_indir_tbl[i + j];
14528c5ad0daSSasha Neftin 		}
14538c5ad0daSSasha Neftin 
14548c5ad0daSSasha Neftin 		wr32(reg, val << shift);
14558c5ad0daSSasha Neftin 		reg += 4;
14568c5ad0daSSasha Neftin 		i += 4;
14578c5ad0daSSasha Neftin 	}
14588c5ad0daSSasha Neftin }
14598c5ad0daSSasha Neftin 
igc_ethtool_get_rxfh_indir_size(struct net_device * netdev)14607df76bd1SAndre Guedes static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
14618c5ad0daSSasha Neftin {
14628c5ad0daSSasha Neftin 	return IGC_RETA_SIZE;
14638c5ad0daSSasha Neftin }
14648c5ad0daSSasha Neftin 
igc_ethtool_get_rxfh(struct net_device * netdev,struct ethtool_rxfh_param * rxfh)1465fb6e30a7SAhmed Zaki static int igc_ethtool_get_rxfh(struct net_device *netdev,
1466fb6e30a7SAhmed Zaki 				struct ethtool_rxfh_param *rxfh)
14678c5ad0daSSasha Neftin {
14688c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
14698c5ad0daSSasha Neftin 	int i;
14708c5ad0daSSasha Neftin 
1471fb6e30a7SAhmed Zaki 	rxfh->hfunc = ETH_RSS_HASH_TOP;
1472fb6e30a7SAhmed Zaki 	if (!rxfh->indir)
14738c5ad0daSSasha Neftin 		return 0;
14748c5ad0daSSasha Neftin 	for (i = 0; i < IGC_RETA_SIZE; i++)
1475fb6e30a7SAhmed Zaki 		rxfh->indir[i] = adapter->rss_indir_tbl[i];
14768c5ad0daSSasha Neftin 
14778c5ad0daSSasha Neftin 	return 0;
14788c5ad0daSSasha Neftin }
14798c5ad0daSSasha Neftin 
igc_ethtool_set_rxfh(struct net_device * netdev,struct ethtool_rxfh_param * rxfh,struct netlink_ext_ack * extack)1480fb6e30a7SAhmed Zaki static int igc_ethtool_set_rxfh(struct net_device *netdev,
1481fb6e30a7SAhmed Zaki 				struct ethtool_rxfh_param *rxfh,
1482fb6e30a7SAhmed Zaki 				struct netlink_ext_ack *extack)
14838c5ad0daSSasha Neftin {
14848c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
14858c5ad0daSSasha Neftin 	u32 num_queues;
14868c5ad0daSSasha Neftin 	int i;
14878c5ad0daSSasha Neftin 
14888c5ad0daSSasha Neftin 	/* We do not allow change in unsupported parameters */
1489fb6e30a7SAhmed Zaki 	if (rxfh->key ||
1490fb6e30a7SAhmed Zaki 	    (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
1491fb6e30a7SAhmed Zaki 	     rxfh->hfunc != ETH_RSS_HASH_TOP))
14928c5ad0daSSasha Neftin 		return -EOPNOTSUPP;
1493fb6e30a7SAhmed Zaki 	if (!rxfh->indir)
14948c5ad0daSSasha Neftin 		return 0;
14958c5ad0daSSasha Neftin 
14968c5ad0daSSasha Neftin 	num_queues = adapter->rss_queues;
14978c5ad0daSSasha Neftin 
14988c5ad0daSSasha Neftin 	/* Verify user input. */
14998c5ad0daSSasha Neftin 	for (i = 0; i < IGC_RETA_SIZE; i++)
1500fb6e30a7SAhmed Zaki 		if (rxfh->indir[i] >= num_queues)
15018c5ad0daSSasha Neftin 			return -EINVAL;
15028c5ad0daSSasha Neftin 
15038c5ad0daSSasha Neftin 	for (i = 0; i < IGC_RETA_SIZE; i++)
1504fb6e30a7SAhmed Zaki 		adapter->rss_indir_tbl[i] = rxfh->indir[i];
15058c5ad0daSSasha Neftin 
15068c5ad0daSSasha Neftin 	igc_write_rss_indir_tbl(adapter);
15078c5ad0daSSasha Neftin 
15088c5ad0daSSasha Neftin 	return 0;
15098c5ad0daSSasha Neftin }
15108c5ad0daSSasha Neftin 
igc_ethtool_get_channels(struct net_device * netdev,struct ethtool_channels * ch)15117df76bd1SAndre Guedes static void igc_ethtool_get_channels(struct net_device *netdev,
15128c5ad0daSSasha Neftin 				     struct ethtool_channels *ch)
15138c5ad0daSSasha Neftin {
15148c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
15158c5ad0daSSasha Neftin 
15168c5ad0daSSasha Neftin 	/* Report maximum channels */
15174d0710c2SAndre Guedes 	ch->max_combined = igc_get_max_rss_queues(adapter);
15188c5ad0daSSasha Neftin 
15198c5ad0daSSasha Neftin 	/* Report info for other vector */
15208c5ad0daSSasha Neftin 	if (adapter->flags & IGC_FLAG_HAS_MSIX) {
15218c5ad0daSSasha Neftin 		ch->max_other = NON_Q_VECTORS;
15228c5ad0daSSasha Neftin 		ch->other_count = NON_Q_VECTORS;
15238c5ad0daSSasha Neftin 	}
15248c5ad0daSSasha Neftin 
15258c5ad0daSSasha Neftin 	ch->combined_count = adapter->rss_queues;
15268c5ad0daSSasha Neftin }
15278c5ad0daSSasha Neftin 
igc_ethtool_set_channels(struct net_device * netdev,struct ethtool_channels * ch)15287df76bd1SAndre Guedes static int igc_ethtool_set_channels(struct net_device *netdev,
15298c5ad0daSSasha Neftin 				    struct ethtool_channels *ch)
15308c5ad0daSSasha Neftin {
15318c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
15328c5ad0daSSasha Neftin 	unsigned int count = ch->combined_count;
15338c5ad0daSSasha Neftin 	unsigned int max_combined = 0;
15348c5ad0daSSasha Neftin 
15358c5ad0daSSasha Neftin 	/* Verify they are not requesting separate vectors */
15368c5ad0daSSasha Neftin 	if (!count || ch->rx_count || ch->tx_count)
15378c5ad0daSSasha Neftin 		return -EINVAL;
15388c5ad0daSSasha Neftin 
15398c5ad0daSSasha Neftin 	/* Verify other_count is valid and has not been changed */
15408c5ad0daSSasha Neftin 	if (ch->other_count != NON_Q_VECTORS)
15418c5ad0daSSasha Neftin 		return -EINVAL;
15428c5ad0daSSasha Neftin 
15439f329751SKurt Kanzenbach 	/* Do not allow channel reconfiguration when mqprio is enabled */
15449f329751SKurt Kanzenbach 	if (adapter->strict_priority_enable)
15459f329751SKurt Kanzenbach 		return -EINVAL;
15469f329751SKurt Kanzenbach 
15478c5ad0daSSasha Neftin 	/* Verify the number of channels doesn't exceed hw limits */
15484d0710c2SAndre Guedes 	max_combined = igc_get_max_rss_queues(adapter);
15498c5ad0daSSasha Neftin 	if (count > max_combined)
15508c5ad0daSSasha Neftin 		return -EINVAL;
15518c5ad0daSSasha Neftin 
15528c5ad0daSSasha Neftin 	if (count != adapter->rss_queues) {
15538c5ad0daSSasha Neftin 		adapter->rss_queues = count;
15548c5ad0daSSasha Neftin 		igc_set_flag_queue_pairs(adapter, max_combined);
15558c5ad0daSSasha Neftin 
15568c5ad0daSSasha Neftin 		/* Hardware has to reinitialize queues and interrupts to
15578c5ad0daSSasha Neftin 		 * match the new configuration.
15588c5ad0daSSasha Neftin 		 */
15598c5ad0daSSasha Neftin 		return igc_reinit_queues(adapter);
15608c5ad0daSSasha Neftin 	}
15618c5ad0daSSasha Neftin 
15628c5ad0daSSasha Neftin 	return 0;
15638c5ad0daSSasha Neftin }
15648c5ad0daSSasha Neftin 
igc_ethtool_get_ts_info(struct net_device * dev,struct kernel_ethtool_ts_info * info)15657df76bd1SAndre Guedes static int igc_ethtool_get_ts_info(struct net_device *dev,
15662111375bSKory Maincent 				   struct kernel_ethtool_ts_info *info)
156760dbede0SVinicius Costa Gomes {
156860dbede0SVinicius Costa Gomes 	struct igc_adapter *adapter = netdev_priv(dev);
156960dbede0SVinicius Costa Gomes 
157060dbede0SVinicius Costa Gomes 	if (adapter->ptp_clock)
157160dbede0SVinicius Costa Gomes 		info->phc_index = ptp_clock_index(adapter->ptp_clock);
157260dbede0SVinicius Costa Gomes 
157360dbede0SVinicius Costa Gomes 	switch (adapter->hw.mac.type) {
157460dbede0SVinicius Costa Gomes 	case igc_i225:
157560dbede0SVinicius Costa Gomes 		info->so_timestamping =
157660dbede0SVinicius Costa Gomes 			SOF_TIMESTAMPING_TX_SOFTWARE |
157760dbede0SVinicius Costa Gomes 			SOF_TIMESTAMPING_TX_HARDWARE |
157860dbede0SVinicius Costa Gomes 			SOF_TIMESTAMPING_RX_HARDWARE |
157960dbede0SVinicius Costa Gomes 			SOF_TIMESTAMPING_RAW_HARDWARE;
158060dbede0SVinicius Costa Gomes 
158160dbede0SVinicius Costa Gomes 		info->tx_types =
158260dbede0SVinicius Costa Gomes 			BIT(HWTSTAMP_TX_OFF) |
158360dbede0SVinicius Costa Gomes 			BIT(HWTSTAMP_TX_ON);
158460dbede0SVinicius Costa Gomes 
158560dbede0SVinicius Costa Gomes 		info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
158660dbede0SVinicius Costa Gomes 		info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL);
158760dbede0SVinicius Costa Gomes 
158860dbede0SVinicius Costa Gomes 		return 0;
158960dbede0SVinicius Costa Gomes 	default:
159060dbede0SVinicius Costa Gomes 		return -EOPNOTSUPP;
159160dbede0SVinicius Costa Gomes 	}
159260dbede0SVinicius Costa Gomes }
159360dbede0SVinicius Costa Gomes 
igc_ethtool_get_priv_flags(struct net_device * netdev)15947df76bd1SAndre Guedes static u32 igc_ethtool_get_priv_flags(struct net_device *netdev)
15958c5ad0daSSasha Neftin {
15968c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
15978c5ad0daSSasha Neftin 	u32 priv_flags = 0;
15988c5ad0daSSasha Neftin 
15998c5ad0daSSasha Neftin 	if (adapter->flags & IGC_FLAG_RX_LEGACY)
16008c5ad0daSSasha Neftin 		priv_flags |= IGC_PRIV_FLAGS_LEGACY_RX;
16018c5ad0daSSasha Neftin 
16028c5ad0daSSasha Neftin 	return priv_flags;
16038c5ad0daSSasha Neftin }
16048c5ad0daSSasha Neftin 
igc_ethtool_set_priv_flags(struct net_device * netdev,u32 priv_flags)16057df76bd1SAndre Guedes static int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags)
16068c5ad0daSSasha Neftin {
16078c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
16088c5ad0daSSasha Neftin 	unsigned int flags = adapter->flags;
16098c5ad0daSSasha Neftin 
16108c5ad0daSSasha Neftin 	flags &= ~IGC_FLAG_RX_LEGACY;
16118c5ad0daSSasha Neftin 	if (priv_flags & IGC_PRIV_FLAGS_LEGACY_RX)
16128c5ad0daSSasha Neftin 		flags |= IGC_FLAG_RX_LEGACY;
16138c5ad0daSSasha Neftin 
16148c5ad0daSSasha Neftin 	if (flags != adapter->flags) {
16158c5ad0daSSasha Neftin 		adapter->flags = flags;
16168c5ad0daSSasha Neftin 
16178c5ad0daSSasha Neftin 		/* reset interface to repopulate queues */
16188c5ad0daSSasha Neftin 		if (netif_running(netdev))
16198c5ad0daSSasha Neftin 			igc_reinit_locked(adapter);
16208c5ad0daSSasha Neftin 	}
16218c5ad0daSSasha Neftin 
16228c5ad0daSSasha Neftin 	return 0;
16238c5ad0daSSasha Neftin }
16248c5ad0daSSasha Neftin 
igc_ethtool_get_eee(struct net_device * netdev,struct ethtool_keee * edata)162593ec439aSSasha Neftin static int igc_ethtool_get_eee(struct net_device *netdev,
1626d80a5233SHeiner Kallweit 			       struct ethtool_keee *edata)
162793ec439aSSasha Neftin {
162893ec439aSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
162993ec439aSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
1630*ad7dffaeSSasha Neftin 	struct igc_phy_info *phy = &hw->phy;
1631*ad7dffaeSSasha Neftin 	u16 eee_advert, eee_lp_advert;
1632*ad7dffaeSSasha Neftin 	u32 eeer, ret_val;
163393ec439aSSasha Neftin 
1634*ad7dffaeSSasha Neftin 	/* EEE supported */
16357d67d11fSSasha Neftin 	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
16367d67d11fSSasha Neftin 			 edata->supported);
16377d67d11fSSasha Neftin 	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
16387d67d11fSSasha Neftin 			 edata->supported);
16397d67d11fSSasha Neftin 	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
16407d67d11fSSasha Neftin 			 edata->supported);
16417d67d11fSSasha Neftin 
1642*ad7dffaeSSasha Neftin 	/* EEE Advertisement 1 - reg 7.60 */
1643*ad7dffaeSSasha Neftin 	ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
1644*ad7dffaeSSasha Neftin 				    MMD_DEVADDR_SHIFT) |
1645*ad7dffaeSSasha Neftin 				    IGC_ANEG_EEE_AB1,
1646*ad7dffaeSSasha Neftin 				    &eee_advert);
1647*ad7dffaeSSasha Neftin 	if (ret_val) {
1648*ad7dffaeSSasha Neftin 		netdev_err(adapter->netdev,
1649*ad7dffaeSSasha Neftin 			   "Failed to read IEEE 7.60 register\n");
1650*ad7dffaeSSasha Neftin 		return -EINVAL;
1651*ad7dffaeSSasha Neftin 	}
1652*ad7dffaeSSasha Neftin 
1653*ad7dffaeSSasha Neftin 	if (eee_advert & IGC_EEE_1000BT_MASK)
1654*ad7dffaeSSasha Neftin 		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
1655*ad7dffaeSSasha Neftin 				 edata->advertised);
1656*ad7dffaeSSasha Neftin 
1657*ad7dffaeSSasha Neftin 	if (eee_advert & IGC_EEE_100BT_MASK)
1658*ad7dffaeSSasha Neftin 		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
1659*ad7dffaeSSasha Neftin 				 edata->advertised);
1660*ad7dffaeSSasha Neftin 
1661*ad7dffaeSSasha Neftin 	/* EEE Advertisement 2 - reg 7.62 */
1662*ad7dffaeSSasha Neftin 	ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
1663*ad7dffaeSSasha Neftin 				    MMD_DEVADDR_SHIFT) |
1664*ad7dffaeSSasha Neftin 				    IGC_ANEG_EEE_AB2,
1665*ad7dffaeSSasha Neftin 				    &eee_advert);
1666*ad7dffaeSSasha Neftin 	if (ret_val) {
1667*ad7dffaeSSasha Neftin 		netdev_err(adapter->netdev,
1668*ad7dffaeSSasha Neftin 			   "Failed to read IEEE 7.62 register\n");
1669*ad7dffaeSSasha Neftin 		return -EINVAL;
1670*ad7dffaeSSasha Neftin 	}
1671*ad7dffaeSSasha Neftin 
1672*ad7dffaeSSasha Neftin 	if (eee_advert & IGC_EEE_2500BT_MASK)
1673*ad7dffaeSSasha Neftin 		linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
1674*ad7dffaeSSasha Neftin 				 edata->advertised);
1675*ad7dffaeSSasha Neftin 
1676*ad7dffaeSSasha Neftin 	/* EEE Link-Partner Ability 1 - reg 7.61 */
1677*ad7dffaeSSasha Neftin 	ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
1678*ad7dffaeSSasha Neftin 				    MMD_DEVADDR_SHIFT) |
1679*ad7dffaeSSasha Neftin 				    IGC_ANEG_EEE_LP_AB1,
1680*ad7dffaeSSasha Neftin 				    &eee_lp_advert);
1681*ad7dffaeSSasha Neftin 	if (ret_val) {
1682*ad7dffaeSSasha Neftin 		netdev_err(adapter->netdev,
1683*ad7dffaeSSasha Neftin 			   "Failed to read IEEE 7.61 register\n");
1684*ad7dffaeSSasha Neftin 		return -EINVAL;
1685*ad7dffaeSSasha Neftin 	}
1686*ad7dffaeSSasha Neftin 
1687*ad7dffaeSSasha Neftin 	if (eee_lp_advert & IGC_LP_EEE_1000BT_MASK)
1688*ad7dffaeSSasha Neftin 		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
1689*ad7dffaeSSasha Neftin 				 edata->lp_advertised);
1690*ad7dffaeSSasha Neftin 
1691*ad7dffaeSSasha Neftin 	if (eee_lp_advert & IGC_LP_EEE_100BT_MASK)
1692*ad7dffaeSSasha Neftin 		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
1693*ad7dffaeSSasha Neftin 				 edata->lp_advertised);
1694*ad7dffaeSSasha Neftin 
1695*ad7dffaeSSasha Neftin 	/* EEE Link-Partner Ability 2 - reg 7.63 */
1696*ad7dffaeSSasha Neftin 	ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
1697*ad7dffaeSSasha Neftin 				    MMD_DEVADDR_SHIFT) |
1698*ad7dffaeSSasha Neftin 				    IGC_ANEG_EEE_LP_AB2,
1699*ad7dffaeSSasha Neftin 				    &eee_lp_advert);
1700*ad7dffaeSSasha Neftin 	if (ret_val) {
1701*ad7dffaeSSasha Neftin 		netdev_err(adapter->netdev,
1702*ad7dffaeSSasha Neftin 			   "Failed to read IEEE 7.63 register\n");
1703*ad7dffaeSSasha Neftin 		return -EINVAL;
1704*ad7dffaeSSasha Neftin 	}
1705*ad7dffaeSSasha Neftin 
1706*ad7dffaeSSasha Neftin 	if (eee_lp_advert & IGC_LP_EEE_2500BT_MASK)
1707*ad7dffaeSSasha Neftin 		linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
1708*ad7dffaeSSasha Neftin 				 edata->lp_advertised);
1709*ad7dffaeSSasha Neftin 
171093ec439aSSasha Neftin 	eeer = rd32(IGC_EEER);
171193ec439aSSasha Neftin 
171293ec439aSSasha Neftin 	/* EEE status on negotiated link */
171393ec439aSSasha Neftin 	if (eeer & IGC_EEER_EEE_NEG)
171493ec439aSSasha Neftin 		edata->eee_active = true;
171593ec439aSSasha Neftin 
171693ec439aSSasha Neftin 	if (eeer & IGC_EEER_TX_LPI_EN)
171793ec439aSSasha Neftin 		edata->tx_lpi_enabled = true;
171893ec439aSSasha Neftin 
171993ec439aSSasha Neftin 	edata->eee_enabled = hw->dev_spec._base.eee_enable;
172093ec439aSSasha Neftin 
172193ec439aSSasha Neftin 	/* Report correct negotiated EEE status for devices that
172293ec439aSSasha Neftin 	 * wrongly report EEE at half-duplex
172393ec439aSSasha Neftin 	 */
172493ec439aSSasha Neftin 	if (adapter->link_duplex == HALF_DUPLEX) {
172593ec439aSSasha Neftin 		edata->eee_enabled = false;
172693ec439aSSasha Neftin 		edata->eee_active = false;
172793ec439aSSasha Neftin 		edata->tx_lpi_enabled = false;
17281e45b5f2SAndrew Lunn 		linkmode_zero(edata->advertised);
172993ec439aSSasha Neftin 	}
173093ec439aSSasha Neftin 
173193ec439aSSasha Neftin 	return 0;
173293ec439aSSasha Neftin }
173393ec439aSSasha Neftin 
igc_ethtool_set_eee(struct net_device * netdev,struct ethtool_keee * edata)173493ec439aSSasha Neftin static int igc_ethtool_set_eee(struct net_device *netdev,
1735d80a5233SHeiner Kallweit 			       struct ethtool_keee *edata)
173693ec439aSSasha Neftin {
173793ec439aSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
173893ec439aSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
1739d80a5233SHeiner Kallweit 	struct ethtool_keee eee_curr;
174093ec439aSSasha Neftin 	s32 ret_val;
174193ec439aSSasha Neftin 
1742d80a5233SHeiner Kallweit 	memset(&eee_curr, 0, sizeof(struct ethtool_keee));
174393ec439aSSasha Neftin 
174493ec439aSSasha Neftin 	ret_val = igc_ethtool_get_eee(netdev, &eee_curr);
174593ec439aSSasha Neftin 	if (ret_val) {
174693ec439aSSasha Neftin 		netdev_err(netdev,
174793ec439aSSasha Neftin 			   "Problem setting EEE advertisement options\n");
174893ec439aSSasha Neftin 		return -EINVAL;
174993ec439aSSasha Neftin 	}
175093ec439aSSasha Neftin 
175193ec439aSSasha Neftin 	if (eee_curr.eee_enabled) {
175293ec439aSSasha Neftin 		if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
175393ec439aSSasha Neftin 			netdev_err(netdev,
175493ec439aSSasha Neftin 				   "Setting EEE tx-lpi is not supported\n");
175593ec439aSSasha Neftin 			return -EINVAL;
175693ec439aSSasha Neftin 		}
175793ec439aSSasha Neftin 
175893ec439aSSasha Neftin 		/* Tx LPI timer is not implemented currently */
175993ec439aSSasha Neftin 		if (edata->tx_lpi_timer) {
176093ec439aSSasha Neftin 			netdev_err(netdev,
176193ec439aSSasha Neftin 				   "Setting EEE Tx LPI timer is not supported\n");
176293ec439aSSasha Neftin 			return -EINVAL;
176393ec439aSSasha Neftin 		}
176493ec439aSSasha Neftin 	} else if (!edata->eee_enabled) {
176593ec439aSSasha Neftin 		netdev_err(netdev,
176693ec439aSSasha Neftin 			   "Setting EEE options are not supported with EEE disabled\n");
176793ec439aSSasha Neftin 		return -EINVAL;
176893ec439aSSasha Neftin 	}
176993ec439aSSasha Neftin 
177093ec439aSSasha Neftin 	if (hw->dev_spec._base.eee_enable != edata->eee_enabled) {
177193ec439aSSasha Neftin 		hw->dev_spec._base.eee_enable = edata->eee_enabled;
177293ec439aSSasha Neftin 		adapter->flags |= IGC_FLAG_EEE;
177393ec439aSSasha Neftin 
177493ec439aSSasha Neftin 		/* reset link */
177593ec439aSSasha Neftin 		if (netif_running(netdev))
177693ec439aSSasha Neftin 			igc_reinit_locked(adapter);
177793ec439aSSasha Neftin 		else
177893ec439aSSasha Neftin 			igc_reset(adapter);
177993ec439aSSasha Neftin 	}
178093ec439aSSasha Neftin 
178193ec439aSSasha Neftin 	return 0;
178293ec439aSSasha Neftin }
178393ec439aSSasha Neftin 
igc_ethtool_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)17847df76bd1SAndre Guedes static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
17858c5ad0daSSasha Neftin 					  struct ethtool_link_ksettings *cmd)
17868c5ad0daSSasha Neftin {
17878c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
17888c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
17898c5ad0daSSasha Neftin 	u32 status;
17908c5ad0daSSasha Neftin 	u32 speed;
17918c5ad0daSSasha Neftin 
17928c5ad0daSSasha Neftin 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
17938c5ad0daSSasha Neftin 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
17948c5ad0daSSasha Neftin 
17958c5ad0daSSasha Neftin 	/* supported link modes */
17968c5ad0daSSasha Neftin 	ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
17978c5ad0daSSasha Neftin 	ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Full);
17988c5ad0daSSasha Neftin 	ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Half);
17998c5ad0daSSasha Neftin 	ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Full);
18008c5ad0daSSasha Neftin 	ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full);
18018c5ad0daSSasha Neftin 	ethtool_link_ksettings_add_link_mode(cmd, supported, 2500baseT_Full);
18028c5ad0daSSasha Neftin 
18038c5ad0daSSasha Neftin 	/* twisted pair */
18048c5ad0daSSasha Neftin 	cmd->base.port = PORT_TP;
18058c5ad0daSSasha Neftin 	cmd->base.phy_address = hw->phy.addr;
18069ac3fc2fSPrasad Koya 	ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
18079ac3fc2fSPrasad Koya 	ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
18088c5ad0daSSasha Neftin 
18098c5ad0daSSasha Neftin 	/* advertising link modes */
1810329a3678SCorinna Vinschen 	if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
18118c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
1812329a3678SCorinna Vinschen 	if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
18138c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
1814329a3678SCorinna Vinschen 	if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
18158c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
1816329a3678SCorinna Vinschen 	if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
18178c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
1818329a3678SCorinna Vinschen 	if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
18198c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
1820329a3678SCorinna Vinschen 	if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
18218c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
18228c5ad0daSSasha Neftin 
18238c5ad0daSSasha Neftin 	/* set autoneg settings */
18248c5ad0daSSasha Neftin 	if (hw->mac.autoneg == 1) {
18258c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
18268c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
18278c5ad0daSSasha Neftin 						     Autoneg);
18288c5ad0daSSasha Neftin 	}
18298c5ad0daSSasha Neftin 
18309a4a1cdcSMuhammad Husaini Zulkifli 	/* Set pause flow control settings */
18319a4a1cdcSMuhammad Husaini Zulkifli 	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
18329a4a1cdcSMuhammad Husaini Zulkifli 
18338c5ad0daSSasha Neftin 	switch (hw->fc.requested_mode) {
18348c5ad0daSSasha Neftin 	case igc_fc_full:
18358c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
18368c5ad0daSSasha Neftin 		break;
18378c5ad0daSSasha Neftin 	case igc_fc_rx_pause:
18388c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
18398c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
18408c5ad0daSSasha Neftin 						     Asym_Pause);
18418c5ad0daSSasha Neftin 		break;
18428c5ad0daSSasha Neftin 	case igc_fc_tx_pause:
18438c5ad0daSSasha Neftin 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
18448c5ad0daSSasha Neftin 						     Asym_Pause);
18458c5ad0daSSasha Neftin 		break;
18468c5ad0daSSasha Neftin 	default:
184788765294SMuhammad Husaini Zulkifli 		break;
18488c5ad0daSSasha Neftin 	}
18498c5ad0daSSasha Neftin 
18502e99dedcSKai-Heng Feng 	status = pm_runtime_suspended(&adapter->pdev->dev) ?
18512e99dedcSKai-Heng Feng 		 0 : rd32(IGC_STATUS);
18528c5ad0daSSasha Neftin 
18538c5ad0daSSasha Neftin 	if (status & IGC_STATUS_LU) {
18548c5ad0daSSasha Neftin 		if (status & IGC_STATUS_SPEED_1000) {
18558c5ad0daSSasha Neftin 			/* For I225, STATUS will indicate 1G speed in both
18568c5ad0daSSasha Neftin 			 * 1 Gbps and 2.5 Gbps link modes.
18578c5ad0daSSasha Neftin 			 * An additional bit is used
18588c5ad0daSSasha Neftin 			 * to differentiate between 1 Gbps and 2.5 Gbps.
18598c5ad0daSSasha Neftin 			 */
18608c5ad0daSSasha Neftin 			if (hw->mac.type == igc_i225 &&
18618c5ad0daSSasha Neftin 			    (status & IGC_STATUS_SPEED_2500)) {
18628c5ad0daSSasha Neftin 				speed = SPEED_2500;
18638c5ad0daSSasha Neftin 			} else {
18648c5ad0daSSasha Neftin 				speed = SPEED_1000;
18658c5ad0daSSasha Neftin 			}
18668c5ad0daSSasha Neftin 		} else if (status & IGC_STATUS_SPEED_100) {
18678c5ad0daSSasha Neftin 			speed = SPEED_100;
18688c5ad0daSSasha Neftin 		} else {
18698c5ad0daSSasha Neftin 			speed = SPEED_10;
18708c5ad0daSSasha Neftin 		}
18718c5ad0daSSasha Neftin 		if ((status & IGC_STATUS_FD) ||
18728c5ad0daSSasha Neftin 		    hw->phy.media_type != igc_media_type_copper)
18738c5ad0daSSasha Neftin 			cmd->base.duplex = DUPLEX_FULL;
18748c5ad0daSSasha Neftin 		else
18758c5ad0daSSasha Neftin 			cmd->base.duplex = DUPLEX_HALF;
18768c5ad0daSSasha Neftin 	} else {
18778c5ad0daSSasha Neftin 		speed = SPEED_UNKNOWN;
18788c5ad0daSSasha Neftin 		cmd->base.duplex = DUPLEX_UNKNOWN;
18798c5ad0daSSasha Neftin 	}
18808c5ad0daSSasha Neftin 	cmd->base.speed = speed;
18818c5ad0daSSasha Neftin 	if (hw->mac.autoneg)
18828c5ad0daSSasha Neftin 		cmd->base.autoneg = AUTONEG_ENABLE;
18838c5ad0daSSasha Neftin 	else
18848c5ad0daSSasha Neftin 		cmd->base.autoneg = AUTONEG_DISABLE;
18858c5ad0daSSasha Neftin 
18868c5ad0daSSasha Neftin 	/* MDI-X => 2; MDI =>1; Invalid =>0 */
18878c5ad0daSSasha Neftin 	if (hw->phy.media_type == igc_media_type_copper)
18888c5ad0daSSasha Neftin 		cmd->base.eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
18898c5ad0daSSasha Neftin 						      ETH_TP_MDI;
18908c5ad0daSSasha Neftin 	else
18918c5ad0daSSasha Neftin 		cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
18928c5ad0daSSasha Neftin 
18938c5ad0daSSasha Neftin 	if (hw->phy.mdix == AUTO_ALL_MODES)
18948c5ad0daSSasha Neftin 		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
18958c5ad0daSSasha Neftin 	else
18968c5ad0daSSasha Neftin 		cmd->base.eth_tp_mdix_ctrl = hw->phy.mdix;
18978c5ad0daSSasha Neftin 
18988c5ad0daSSasha Neftin 	return 0;
18998c5ad0daSSasha Neftin }
19008c5ad0daSSasha Neftin 
19017df76bd1SAndre Guedes static int
igc_ethtool_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * cmd)19027df76bd1SAndre Guedes igc_ethtool_set_link_ksettings(struct net_device *netdev,
19038c5ad0daSSasha Neftin 			       const struct ethtool_link_ksettings *cmd)
19048c5ad0daSSasha Neftin {
19058c5ad0daSSasha Neftin 	struct igc_adapter *adapter = netdev_priv(netdev);
190695f96a9fSAndre Guedes 	struct net_device *dev = adapter->netdev;
19078c5ad0daSSasha Neftin 	struct igc_hw *hw = &adapter->hw;
1908e7684d29SSasha Neftin 	u16 advertised = 0;
19098c5ad0daSSasha Neftin 
19108c5ad0daSSasha Neftin 	/* When adapter in resetting mode, autoneg/speed/duplex
19118c5ad0daSSasha Neftin 	 * cannot be changed
19128c5ad0daSSasha Neftin 	 */
19138c5ad0daSSasha Neftin 	if (igc_check_reset_block(hw)) {
191495f96a9fSAndre Guedes 		netdev_err(dev, "Cannot change link characteristics when reset is active\n");
19158c5ad0daSSasha Neftin 		return -EINVAL;
19168c5ad0daSSasha Neftin 	}
19178c5ad0daSSasha Neftin 
19188c5ad0daSSasha Neftin 	/* MDI setting is only allowed when autoneg enabled because
19198c5ad0daSSasha Neftin 	 * some hardware doesn't allow MDI setting when speed or
19208c5ad0daSSasha Neftin 	 * duplex is forced.
19218c5ad0daSSasha Neftin 	 */
19228c5ad0daSSasha Neftin 	if (cmd->base.eth_tp_mdix_ctrl) {
19238c5ad0daSSasha Neftin 		if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
19248c5ad0daSSasha Neftin 		    cmd->base.autoneg != AUTONEG_ENABLE) {
192595f96a9fSAndre Guedes 			netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
19268c5ad0daSSasha Neftin 			return -EINVAL;
19278c5ad0daSSasha Neftin 		}
19288c5ad0daSSasha Neftin 	}
19298c5ad0daSSasha Neftin 
19308c5ad0daSSasha Neftin 	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
19318c5ad0daSSasha Neftin 		usleep_range(1000, 2000);
19328c5ad0daSSasha Neftin 
1933e7684d29SSasha Neftin 	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
1934e7684d29SSasha Neftin 						  2500baseT_Full))
1935e7684d29SSasha Neftin 		advertised |= ADVERTISE_2500_FULL;
1936e7684d29SSasha Neftin 
1937e7684d29SSasha Neftin 	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
1938e7684d29SSasha Neftin 						  1000baseT_Full))
1939e7684d29SSasha Neftin 		advertised |= ADVERTISE_1000_FULL;
1940e7684d29SSasha Neftin 
1941e7684d29SSasha Neftin 	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
1942e7684d29SSasha Neftin 						  100baseT_Full))
1943e7684d29SSasha Neftin 		advertised |= ADVERTISE_100_FULL;
1944e7684d29SSasha Neftin 
1945e7684d29SSasha Neftin 	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
1946e7684d29SSasha Neftin 						  100baseT_Half))
1947e7684d29SSasha Neftin 		advertised |= ADVERTISE_100_HALF;
1948e7684d29SSasha Neftin 
1949e7684d29SSasha Neftin 	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
1950e7684d29SSasha Neftin 						  10baseT_Full))
1951e7684d29SSasha Neftin 		advertised |= ADVERTISE_10_FULL;
1952e7684d29SSasha Neftin 
1953e7684d29SSasha Neftin 	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
1954e7684d29SSasha Neftin 						  10baseT_Half))
1955e7684d29SSasha Neftin 		advertised |= ADVERTISE_10_HALF;
19568c5ad0daSSasha Neftin 
19578c5ad0daSSasha Neftin 	if (cmd->base.autoneg == AUTONEG_ENABLE) {
19588c5ad0daSSasha Neftin 		hw->mac.autoneg = 1;
1959e7684d29SSasha Neftin 		hw->phy.autoneg_advertised = advertised;
19608c5ad0daSSasha Neftin 		if (adapter->fc_autoneg)
19618c5ad0daSSasha Neftin 			hw->fc.requested_mode = igc_fc_default;
19628c5ad0daSSasha Neftin 	} else {
196395f96a9fSAndre Guedes 		netdev_info(dev, "Force mode currently not supported\n");
19648c5ad0daSSasha Neftin 	}
19658c5ad0daSSasha Neftin 
19668c5ad0daSSasha Neftin 	/* MDI-X => 2; MDI => 1; Auto => 3 */
19678c5ad0daSSasha Neftin 	if (cmd->base.eth_tp_mdix_ctrl) {
19688c5ad0daSSasha Neftin 		/* fix up the value for auto (3 => 0) as zero is mapped
19698c5ad0daSSasha Neftin 		 * internally to auto
19708c5ad0daSSasha Neftin 		 */
19718c5ad0daSSasha Neftin 		if (cmd->base.eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO)
19728c5ad0daSSasha Neftin 			hw->phy.mdix = AUTO_ALL_MODES;
19738c5ad0daSSasha Neftin 		else
19748c5ad0daSSasha Neftin 			hw->phy.mdix = cmd->base.eth_tp_mdix_ctrl;
19758c5ad0daSSasha Neftin 	}
19768c5ad0daSSasha Neftin 
19778c5ad0daSSasha Neftin 	/* reset the link */
19788c5ad0daSSasha Neftin 	if (netif_running(adapter->netdev)) {
19798c5ad0daSSasha Neftin 		igc_down(adapter);
19808c5ad0daSSasha Neftin 		igc_up(adapter);
19818c5ad0daSSasha Neftin 	} else {
19828c5ad0daSSasha Neftin 		igc_reset(adapter);
19838c5ad0daSSasha Neftin 	}
19848c5ad0daSSasha Neftin 
19858c5ad0daSSasha Neftin 	clear_bit(__IGC_RESETTING, &adapter->state);
19868c5ad0daSSasha Neftin 
19878c5ad0daSSasha Neftin 	return 0;
19888c5ad0daSSasha Neftin }
19898c5ad0daSSasha Neftin 
igc_ethtool_diag_test(struct net_device * netdev,struct ethtool_test * eth_test,u64 * data)19907df76bd1SAndre Guedes static void igc_ethtool_diag_test(struct net_device *netdev,
1991f026d8caSVitaly Lifshits 				  struct ethtool_test *eth_test, u64 *data)
1992f026d8caSVitaly Lifshits {
1993f026d8caSVitaly Lifshits 	struct igc_adapter *adapter = netdev_priv(netdev);
1994f026d8caSVitaly Lifshits 	bool if_running = netif_running(netdev);
1995f026d8caSVitaly Lifshits 
1996f026d8caSVitaly Lifshits 	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
199795f96a9fSAndre Guedes 		netdev_info(adapter->netdev, "Offline testing starting");
1998f026d8caSVitaly Lifshits 		set_bit(__IGC_TESTING, &adapter->state);
1999f026d8caSVitaly Lifshits 
2000f026d8caSVitaly Lifshits 		/* Link test performed before hardware reset so autoneg doesn't
2001f026d8caSVitaly Lifshits 		 * interfere with test result
2002f026d8caSVitaly Lifshits 		 */
2003f026d8caSVitaly Lifshits 		if (!igc_link_test(adapter, &data[TEST_LINK]))
2004f026d8caSVitaly Lifshits 			eth_test->flags |= ETH_TEST_FL_FAILED;
2005f026d8caSVitaly Lifshits 
2006f026d8caSVitaly Lifshits 		if (if_running)
2007f026d8caSVitaly Lifshits 			igc_close(netdev);
2008f026d8caSVitaly Lifshits 		else
2009f026d8caSVitaly Lifshits 			igc_reset(adapter);
2010f026d8caSVitaly Lifshits 
201195f96a9fSAndre Guedes 		netdev_info(adapter->netdev, "Register testing starting");
2012f026d8caSVitaly Lifshits 		if (!igc_reg_test(adapter, &data[TEST_REG]))
2013f026d8caSVitaly Lifshits 			eth_test->flags |= ETH_TEST_FL_FAILED;
2014f026d8caSVitaly Lifshits 
2015f026d8caSVitaly Lifshits 		igc_reset(adapter);
2016f026d8caSVitaly Lifshits 
201795f96a9fSAndre Guedes 		netdev_info(adapter->netdev, "EEPROM testing starting");
2018f026d8caSVitaly Lifshits 		if (!igc_eeprom_test(adapter, &data[TEST_EEP]))
2019f026d8caSVitaly Lifshits 			eth_test->flags |= ETH_TEST_FL_FAILED;
2020f026d8caSVitaly Lifshits 
2021f026d8caSVitaly Lifshits 		igc_reset(adapter);
2022f026d8caSVitaly Lifshits 
2023f026d8caSVitaly Lifshits 		/* loopback and interrupt tests
2024f026d8caSVitaly Lifshits 		 * will be implemented in the future
2025f026d8caSVitaly Lifshits 		 */
2026f026d8caSVitaly Lifshits 		data[TEST_LOOP] = 0;
2027f026d8caSVitaly Lifshits 		data[TEST_IRQ] = 0;
2028f026d8caSVitaly Lifshits 
2029f026d8caSVitaly Lifshits 		clear_bit(__IGC_TESTING, &adapter->state);
2030f026d8caSVitaly Lifshits 		if (if_running)
2031f026d8caSVitaly Lifshits 			igc_open(netdev);
2032f026d8caSVitaly Lifshits 	} else {
203395f96a9fSAndre Guedes 		netdev_info(adapter->netdev, "Online testing starting");
2034f026d8caSVitaly Lifshits 
2035f026d8caSVitaly Lifshits 		/* register, eeprom, intr and loopback tests not run online */
2036f026d8caSVitaly Lifshits 		data[TEST_REG] = 0;
2037f026d8caSVitaly Lifshits 		data[TEST_EEP] = 0;
2038f026d8caSVitaly Lifshits 		data[TEST_IRQ] = 0;
2039f026d8caSVitaly Lifshits 		data[TEST_LOOP] = 0;
2040f026d8caSVitaly Lifshits 
2041f026d8caSVitaly Lifshits 		if (!igc_link_test(adapter, &data[TEST_LINK]))
2042f026d8caSVitaly Lifshits 			eth_test->flags |= ETH_TEST_FL_FAILED;
2043f026d8caSVitaly Lifshits 	}
2044f026d8caSVitaly Lifshits 
2045f026d8caSVitaly Lifshits 	msleep_interruptible(4 * 1000);
2046f026d8caSVitaly Lifshits }
2047f026d8caSVitaly Lifshits 
20488c5ad0daSSasha Neftin static const struct ethtool_ops igc_ethtool_ops = {
2049dbfa497aSJakub Kicinski 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
20507df76bd1SAndre Guedes 	.get_drvinfo		= igc_ethtool_get_drvinfo,
20517df76bd1SAndre Guedes 	.get_regs_len		= igc_ethtool_get_regs_len,
20527df76bd1SAndre Guedes 	.get_regs		= igc_ethtool_get_regs,
20537df76bd1SAndre Guedes 	.get_wol		= igc_ethtool_get_wol,
20547df76bd1SAndre Guedes 	.set_wol		= igc_ethtool_set_wol,
20557df76bd1SAndre Guedes 	.get_msglevel		= igc_ethtool_get_msglevel,
20567df76bd1SAndre Guedes 	.set_msglevel		= igc_ethtool_set_msglevel,
20577df76bd1SAndre Guedes 	.nway_reset		= igc_ethtool_nway_reset,
20587df76bd1SAndre Guedes 	.get_link		= igc_ethtool_get_link,
20597df76bd1SAndre Guedes 	.get_eeprom_len		= igc_ethtool_get_eeprom_len,
20607df76bd1SAndre Guedes 	.get_eeprom		= igc_ethtool_get_eeprom,
20617df76bd1SAndre Guedes 	.set_eeprom		= igc_ethtool_set_eeprom,
20627df76bd1SAndre Guedes 	.get_ringparam		= igc_ethtool_get_ringparam,
20637df76bd1SAndre Guedes 	.set_ringparam		= igc_ethtool_set_ringparam,
20647df76bd1SAndre Guedes 	.get_pauseparam		= igc_ethtool_get_pauseparam,
20657df76bd1SAndre Guedes 	.set_pauseparam		= igc_ethtool_set_pauseparam,
20667df76bd1SAndre Guedes 	.get_strings		= igc_ethtool_get_strings,
20677df76bd1SAndre Guedes 	.get_sset_count		= igc_ethtool_get_sset_count,
20687df76bd1SAndre Guedes 	.get_ethtool_stats	= igc_ethtool_get_stats,
20697df76bd1SAndre Guedes 	.get_coalesce		= igc_ethtool_get_coalesce,
20707df76bd1SAndre Guedes 	.set_coalesce		= igc_ethtool_set_coalesce,
20717df76bd1SAndre Guedes 	.get_rxnfc		= igc_ethtool_get_rxnfc,
20727df76bd1SAndre Guedes 	.set_rxnfc		= igc_ethtool_set_rxnfc,
20737df76bd1SAndre Guedes 	.get_rxfh_indir_size	= igc_ethtool_get_rxfh_indir_size,
20747df76bd1SAndre Guedes 	.get_rxfh		= igc_ethtool_get_rxfh,
20757df76bd1SAndre Guedes 	.set_rxfh		= igc_ethtool_set_rxfh,
20767df76bd1SAndre Guedes 	.get_ts_info		= igc_ethtool_get_ts_info,
20777df76bd1SAndre Guedes 	.get_channels		= igc_ethtool_get_channels,
20787df76bd1SAndre Guedes 	.set_channels		= igc_ethtool_set_channels,
20797df76bd1SAndre Guedes 	.get_priv_flags		= igc_ethtool_get_priv_flags,
20807df76bd1SAndre Guedes 	.set_priv_flags		= igc_ethtool_set_priv_flags,
208193ec439aSSasha Neftin 	.get_eee		= igc_ethtool_get_eee,
208293ec439aSSasha Neftin 	.set_eee		= igc_ethtool_set_eee,
20837df76bd1SAndre Guedes 	.get_link_ksettings	= igc_ethtool_get_link_ksettings,
20847df76bd1SAndre Guedes 	.set_link_ksettings	= igc_ethtool_set_link_ksettings,
20857df76bd1SAndre Guedes 	.self_test		= igc_ethtool_diag_test,
20868c5ad0daSSasha Neftin };
20878c5ad0daSSasha Neftin 
igc_ethtool_set_ops(struct net_device * netdev)20887df76bd1SAndre Guedes void igc_ethtool_set_ops(struct net_device *netdev)
20898c5ad0daSSasha Neftin {
20908c5ad0daSSasha Neftin 	netdev->ethtool_ops = &igc_ethtool_ops;
20918c5ad0daSSasha Neftin }
2092