162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2009 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* ethtool support for igbvf */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/netdevice.h> 762306a36Sopenharmony_ci#include <linux/ethtool.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci#include <linux/vmalloc.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "igbvf.h" 1362306a36Sopenharmony_ci#include <linux/if_vlan.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct igbvf_stats { 1662306a36Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 1762306a36Sopenharmony_ci int sizeof_stat; 1862306a36Sopenharmony_ci int stat_offset; 1962306a36Sopenharmony_ci int base_stat_offset; 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define IGBVF_STAT(current, base) \ 2362306a36Sopenharmony_ci sizeof(((struct igbvf_adapter *)0)->current), \ 2462306a36Sopenharmony_ci offsetof(struct igbvf_adapter, current), \ 2562306a36Sopenharmony_ci offsetof(struct igbvf_adapter, base) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const struct igbvf_stats igbvf_gstrings_stats[] = { 2862306a36Sopenharmony_ci { "rx_packets", IGBVF_STAT(stats.gprc, stats.base_gprc) }, 2962306a36Sopenharmony_ci { "tx_packets", IGBVF_STAT(stats.gptc, stats.base_gptc) }, 3062306a36Sopenharmony_ci { "rx_bytes", IGBVF_STAT(stats.gorc, stats.base_gorc) }, 3162306a36Sopenharmony_ci { "tx_bytes", IGBVF_STAT(stats.gotc, stats.base_gotc) }, 3262306a36Sopenharmony_ci { "multicast", IGBVF_STAT(stats.mprc, stats.base_mprc) }, 3362306a36Sopenharmony_ci { "lbrx_bytes", IGBVF_STAT(stats.gorlbc, stats.base_gorlbc) }, 3462306a36Sopenharmony_ci { "lbrx_packets", IGBVF_STAT(stats.gprlbc, stats.base_gprlbc) }, 3562306a36Sopenharmony_ci { "tx_restart_queue", IGBVF_STAT(restart_queue, zero_base) }, 3662306a36Sopenharmony_ci { "rx_long_byte_count", IGBVF_STAT(stats.gorc, stats.base_gorc) }, 3762306a36Sopenharmony_ci { "rx_csum_offload_good", IGBVF_STAT(hw_csum_good, zero_base) }, 3862306a36Sopenharmony_ci { "rx_csum_offload_errors", IGBVF_STAT(hw_csum_err, zero_base) }, 3962306a36Sopenharmony_ci { "rx_header_split", IGBVF_STAT(rx_hdr_split, zero_base) }, 4062306a36Sopenharmony_ci { "alloc_rx_buff_failed", IGBVF_STAT(alloc_rx_buff_failed, zero_base) }, 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define IGBVF_GLOBAL_STATS_LEN ARRAY_SIZE(igbvf_gstrings_stats) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const char igbvf_gstrings_test[][ETH_GSTRING_LEN] = { 4662306a36Sopenharmony_ci "Link test (on/offline)" 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define IGBVF_TEST_LEN ARRAY_SIZE(igbvf_gstrings_test) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int igbvf_get_link_ksettings(struct net_device *netdev, 5262306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 5562306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 5662306a36Sopenharmony_ci u32 status; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 5962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full); 6062306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, advertising); 6162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci cmd->base.port = -1; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci status = er32(STATUS); 6662306a36Sopenharmony_ci if (status & E1000_STATUS_LU) { 6762306a36Sopenharmony_ci if (status & E1000_STATUS_SPEED_1000) 6862306a36Sopenharmony_ci cmd->base.speed = SPEED_1000; 6962306a36Sopenharmony_ci else if (status & E1000_STATUS_SPEED_100) 7062306a36Sopenharmony_ci cmd->base.speed = SPEED_100; 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci cmd->base.speed = SPEED_10; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (status & E1000_STATUS_FD) 7562306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 7662306a36Sopenharmony_ci else 7762306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_HALF; 7862306a36Sopenharmony_ci } else { 7962306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 8062306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int igbvf_set_link_ksettings(struct net_device *netdev, 8962306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci return -EOPNOTSUPP; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void igbvf_get_pauseparam(struct net_device *netdev, 9562306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int igbvf_set_pauseparam(struct net_device *netdev, 10062306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci return -EOPNOTSUPP; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic u32 igbvf_get_msglevel(struct net_device *netdev) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return adapter->msg_enable; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void igbvf_set_msglevel(struct net_device *netdev, u32 data) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci adapter->msg_enable = data; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int igbvf_get_regs_len(struct net_device *netdev) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci#define IGBVF_REGS_LEN 8 12262306a36Sopenharmony_ci return IGBVF_REGS_LEN * sizeof(u32); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void igbvf_get_regs(struct net_device *netdev, 12662306a36Sopenharmony_ci struct ethtool_regs *regs, void *p) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 12962306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 13062306a36Sopenharmony_ci u32 *regs_buff = p; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci memset(p, 0, IGBVF_REGS_LEN * sizeof(u32)); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci regs->version = (1u << 24) | 13562306a36Sopenharmony_ci (adapter->pdev->revision << 16) | 13662306a36Sopenharmony_ci adapter->pdev->device; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci regs_buff[0] = er32(CTRL); 13962306a36Sopenharmony_ci regs_buff[1] = er32(STATUS); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci regs_buff[2] = er32(RDLEN(0)); 14262306a36Sopenharmony_ci regs_buff[3] = er32(RDH(0)); 14362306a36Sopenharmony_ci regs_buff[4] = er32(RDT(0)); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci regs_buff[5] = er32(TDLEN(0)); 14662306a36Sopenharmony_ci regs_buff[6] = er32(TDH(0)); 14762306a36Sopenharmony_ci regs_buff[7] = er32(TDT(0)); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int igbvf_get_eeprom_len(struct net_device *netdev) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int igbvf_get_eeprom(struct net_device *netdev, 15662306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *bytes) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci return -EOPNOTSUPP; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int igbvf_set_eeprom(struct net_device *netdev, 16262306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *bytes) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci return -EOPNOTSUPP; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void igbvf_get_drvinfo(struct net_device *netdev, 16862306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci strscpy(drvinfo->driver, igbvf_driver_name, sizeof(drvinfo->driver)); 17362306a36Sopenharmony_ci strscpy(drvinfo->bus_info, pci_name(adapter->pdev), 17462306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void igbvf_get_ringparam(struct net_device *netdev, 17862306a36Sopenharmony_ci struct ethtool_ringparam *ring, 17962306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 18062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 18362306a36Sopenharmony_ci struct igbvf_ring *tx_ring = adapter->tx_ring; 18462306a36Sopenharmony_ci struct igbvf_ring *rx_ring = adapter->rx_ring; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ring->rx_max_pending = IGBVF_MAX_RXD; 18762306a36Sopenharmony_ci ring->tx_max_pending = IGBVF_MAX_TXD; 18862306a36Sopenharmony_ci ring->rx_pending = rx_ring->count; 18962306a36Sopenharmony_ci ring->tx_pending = tx_ring->count; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int igbvf_set_ringparam(struct net_device *netdev, 19362306a36Sopenharmony_ci struct ethtool_ringparam *ring, 19462306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 19562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 19862306a36Sopenharmony_ci struct igbvf_ring *temp_ring; 19962306a36Sopenharmony_ci int err = 0; 20062306a36Sopenharmony_ci u32 new_rx_count, new_tx_count; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 20362306a36Sopenharmony_ci return -EINVAL; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci new_rx_count = max_t(u32, ring->rx_pending, IGBVF_MIN_RXD); 20662306a36Sopenharmony_ci new_rx_count = min_t(u32, new_rx_count, IGBVF_MAX_RXD); 20762306a36Sopenharmony_ci new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci new_tx_count = max_t(u32, ring->tx_pending, IGBVF_MIN_TXD); 21062306a36Sopenharmony_ci new_tx_count = min_t(u32, new_tx_count, IGBVF_MAX_TXD); 21162306a36Sopenharmony_ci new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if ((new_tx_count == adapter->tx_ring->count) && 21462306a36Sopenharmony_ci (new_rx_count == adapter->rx_ring->count)) { 21562306a36Sopenharmony_ci /* nothing to do */ 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci while (test_and_set_bit(__IGBVF_RESETTING, &adapter->state)) 22062306a36Sopenharmony_ci usleep_range(1000, 2000); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!netif_running(adapter->netdev)) { 22362306a36Sopenharmony_ci adapter->tx_ring->count = new_tx_count; 22462306a36Sopenharmony_ci adapter->rx_ring->count = new_rx_count; 22562306a36Sopenharmony_ci goto clear_reset; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci temp_ring = vmalloc(sizeof(struct igbvf_ring)); 22962306a36Sopenharmony_ci if (!temp_ring) { 23062306a36Sopenharmony_ci err = -ENOMEM; 23162306a36Sopenharmony_ci goto clear_reset; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci igbvf_down(adapter); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* We can't just free everything and then setup again, 23762306a36Sopenharmony_ci * because the ISRs in MSI-X mode get passed pointers 23862306a36Sopenharmony_ci * to the Tx and Rx ring structs. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci if (new_tx_count != adapter->tx_ring->count) { 24162306a36Sopenharmony_ci memcpy(temp_ring, adapter->tx_ring, sizeof(struct igbvf_ring)); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci temp_ring->count = new_tx_count; 24462306a36Sopenharmony_ci err = igbvf_setup_tx_resources(adapter, temp_ring); 24562306a36Sopenharmony_ci if (err) 24662306a36Sopenharmony_ci goto err_setup; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci igbvf_free_tx_resources(adapter->tx_ring); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci memcpy(adapter->tx_ring, temp_ring, sizeof(struct igbvf_ring)); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (new_rx_count != adapter->rx_ring->count) { 25462306a36Sopenharmony_ci memcpy(temp_ring, adapter->rx_ring, sizeof(struct igbvf_ring)); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci temp_ring->count = new_rx_count; 25762306a36Sopenharmony_ci err = igbvf_setup_rx_resources(adapter, temp_ring); 25862306a36Sopenharmony_ci if (err) 25962306a36Sopenharmony_ci goto err_setup; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci igbvf_free_rx_resources(adapter->rx_ring); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci memcpy(adapter->rx_ring, temp_ring, sizeof(struct igbvf_ring)); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_cierr_setup: 26662306a36Sopenharmony_ci igbvf_up(adapter); 26762306a36Sopenharmony_ci vfree(temp_ring); 26862306a36Sopenharmony_ciclear_reset: 26962306a36Sopenharmony_ci clear_bit(__IGBVF_RESETTING, &adapter->state); 27062306a36Sopenharmony_ci return err; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int igbvf_link_test(struct igbvf_adapter *adapter, u64 *data) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 27662306a36Sopenharmony_ci *data = 0; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci spin_lock_bh(&hw->mbx_lock); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci hw->mac.ops.check_for_link(hw); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci spin_unlock_bh(&hw->mbx_lock); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (!(er32(STATUS) & E1000_STATUS_LU)) 28562306a36Sopenharmony_ci *data = 1; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return *data; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void igbvf_diag_test(struct net_device *netdev, 29162306a36Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci set_bit(__IGBVF_TESTING, &adapter->state); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* Link test performed before hardware reset so autoneg doesn't 29862306a36Sopenharmony_ci * interfere with test result 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci if (igbvf_link_test(adapter, &data[0])) 30162306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci clear_bit(__IGBVF_TESTING, &adapter->state); 30462306a36Sopenharmony_ci msleep_interruptible(4 * 1000); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void igbvf_get_wol(struct net_device *netdev, 30862306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci wol->supported = 0; 31162306a36Sopenharmony_ci wol->wolopts = 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int igbvf_set_wol(struct net_device *netdev, 31562306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci return -EOPNOTSUPP; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int igbvf_get_coalesce(struct net_device *netdev, 32162306a36Sopenharmony_ci struct ethtool_coalesce *ec, 32262306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 32362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (adapter->requested_itr <= 3) 32862306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->requested_itr; 32962306a36Sopenharmony_ci else 33062306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->current_itr >> 2; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int igbvf_set_coalesce(struct net_device *netdev, 33662306a36Sopenharmony_ci struct ethtool_coalesce *ec, 33762306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 33862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 34162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if ((ec->rx_coalesce_usecs >= IGBVF_MIN_ITR_USECS) && 34462306a36Sopenharmony_ci (ec->rx_coalesce_usecs <= IGBVF_MAX_ITR_USECS)) { 34562306a36Sopenharmony_ci adapter->current_itr = ec->rx_coalesce_usecs << 2; 34662306a36Sopenharmony_ci adapter->requested_itr = 1000000000 / 34762306a36Sopenharmony_ci (adapter->current_itr * 256); 34862306a36Sopenharmony_ci } else if ((ec->rx_coalesce_usecs == 3) || 34962306a36Sopenharmony_ci (ec->rx_coalesce_usecs == 2)) { 35062306a36Sopenharmony_ci adapter->current_itr = IGBVF_START_ITR; 35162306a36Sopenharmony_ci adapter->requested_itr = ec->rx_coalesce_usecs; 35262306a36Sopenharmony_ci } else if (ec->rx_coalesce_usecs == 0) { 35362306a36Sopenharmony_ci /* The user's desire is to turn off interrupt throttling 35462306a36Sopenharmony_ci * altogether, but due to HW limitations, we can't do that. 35562306a36Sopenharmony_ci * Instead we set a very small value in EITR, which would 35662306a36Sopenharmony_ci * allow ~967k interrupts per second, but allow the adapter's 35762306a36Sopenharmony_ci * internal clocking to still function properly. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci adapter->current_itr = 4; 36062306a36Sopenharmony_ci adapter->requested_itr = 1000000000 / 36162306a36Sopenharmony_ci (adapter->current_itr * 256); 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci return -EINVAL; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci writel(adapter->current_itr, 36762306a36Sopenharmony_ci hw->hw_addr + adapter->rx_ring->itr_register); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int igbvf_nway_reset(struct net_device *netdev) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (netif_running(netdev)) 37762306a36Sopenharmony_ci igbvf_reinit_locked(adapter); 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic void igbvf_get_ethtool_stats(struct net_device *netdev, 38262306a36Sopenharmony_ci struct ethtool_stats *stats, 38362306a36Sopenharmony_ci u64 *data) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct igbvf_adapter *adapter = netdev_priv(netdev); 38662306a36Sopenharmony_ci int i; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci igbvf_update_stats(adapter); 38962306a36Sopenharmony_ci for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) { 39062306a36Sopenharmony_ci char *p = (char *)adapter + 39162306a36Sopenharmony_ci igbvf_gstrings_stats[i].stat_offset; 39262306a36Sopenharmony_ci char *b = (char *)adapter + 39362306a36Sopenharmony_ci igbvf_gstrings_stats[i].base_stat_offset; 39462306a36Sopenharmony_ci data[i] = ((igbvf_gstrings_stats[i].sizeof_stat == 39562306a36Sopenharmony_ci sizeof(u64)) ? (*(u64 *)p - *(u64 *)b) : 39662306a36Sopenharmony_ci (*(u32 *)p - *(u32 *)b)); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int igbvf_get_sset_count(struct net_device *dev, int stringset) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci switch (stringset) { 40362306a36Sopenharmony_ci case ETH_SS_TEST: 40462306a36Sopenharmony_ci return IGBVF_TEST_LEN; 40562306a36Sopenharmony_ci case ETH_SS_STATS: 40662306a36Sopenharmony_ci return IGBVF_GLOBAL_STATS_LEN; 40762306a36Sopenharmony_ci default: 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void igbvf_get_strings(struct net_device *netdev, u32 stringset, 41362306a36Sopenharmony_ci u8 *data) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci u8 *p = data; 41662306a36Sopenharmony_ci int i; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci switch (stringset) { 41962306a36Sopenharmony_ci case ETH_SS_TEST: 42062306a36Sopenharmony_ci memcpy(data, *igbvf_gstrings_test, sizeof(igbvf_gstrings_test)); 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case ETH_SS_STATS: 42362306a36Sopenharmony_ci for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) { 42462306a36Sopenharmony_ci memcpy(p, igbvf_gstrings_stats[i].stat_string, 42562306a36Sopenharmony_ci ETH_GSTRING_LEN); 42662306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic const struct ethtool_ops igbvf_ethtool_ops = { 43362306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, 43462306a36Sopenharmony_ci .get_drvinfo = igbvf_get_drvinfo, 43562306a36Sopenharmony_ci .get_regs_len = igbvf_get_regs_len, 43662306a36Sopenharmony_ci .get_regs = igbvf_get_regs, 43762306a36Sopenharmony_ci .get_wol = igbvf_get_wol, 43862306a36Sopenharmony_ci .set_wol = igbvf_set_wol, 43962306a36Sopenharmony_ci .get_msglevel = igbvf_get_msglevel, 44062306a36Sopenharmony_ci .set_msglevel = igbvf_set_msglevel, 44162306a36Sopenharmony_ci .nway_reset = igbvf_nway_reset, 44262306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 44362306a36Sopenharmony_ci .get_eeprom_len = igbvf_get_eeprom_len, 44462306a36Sopenharmony_ci .get_eeprom = igbvf_get_eeprom, 44562306a36Sopenharmony_ci .set_eeprom = igbvf_set_eeprom, 44662306a36Sopenharmony_ci .get_ringparam = igbvf_get_ringparam, 44762306a36Sopenharmony_ci .set_ringparam = igbvf_set_ringparam, 44862306a36Sopenharmony_ci .get_pauseparam = igbvf_get_pauseparam, 44962306a36Sopenharmony_ci .set_pauseparam = igbvf_set_pauseparam, 45062306a36Sopenharmony_ci .self_test = igbvf_diag_test, 45162306a36Sopenharmony_ci .get_sset_count = igbvf_get_sset_count, 45262306a36Sopenharmony_ci .get_strings = igbvf_get_strings, 45362306a36Sopenharmony_ci .get_ethtool_stats = igbvf_get_ethtool_stats, 45462306a36Sopenharmony_ci .get_coalesce = igbvf_get_coalesce, 45562306a36Sopenharmony_ci .set_coalesce = igbvf_set_coalesce, 45662306a36Sopenharmony_ci .get_link_ksettings = igbvf_get_link_ksettings, 45762306a36Sopenharmony_ci .set_link_ksettings = igbvf_set_link_ksettings, 45862306a36Sopenharmony_ci}; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_civoid igbvf_set_ethtool_ops(struct net_device *netdev) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci netdev->ethtool_ops = &igbvf_ethtool_ops; 46362306a36Sopenharmony_ci} 464