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