162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* ethtool support for ixgbevf */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/netdevice.h> 1362306a36Sopenharmony_ci#include <linux/ethtool.h> 1462306a36Sopenharmony_ci#include <linux/vmalloc.h> 1562306a36Sopenharmony_ci#include <linux/if_vlan.h> 1662306a36Sopenharmony_ci#include <linux/uaccess.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "ixgbevf.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cienum {NETDEV_STATS, IXGBEVF_STATS}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct ixgbe_stats { 2362306a36Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 2462306a36Sopenharmony_ci int type; 2562306a36Sopenharmony_ci int sizeof_stat; 2662306a36Sopenharmony_ci int stat_offset; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define IXGBEVF_STAT(_name, _stat) { \ 3062306a36Sopenharmony_ci .stat_string = _name, \ 3162306a36Sopenharmony_ci .type = IXGBEVF_STATS, \ 3262306a36Sopenharmony_ci .sizeof_stat = sizeof_field(struct ixgbevf_adapter, _stat), \ 3362306a36Sopenharmony_ci .stat_offset = offsetof(struct ixgbevf_adapter, _stat) \ 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define IXGBEVF_NETDEV_STAT(_net_stat) { \ 3762306a36Sopenharmony_ci .stat_string = #_net_stat, \ 3862306a36Sopenharmony_ci .type = NETDEV_STATS, \ 3962306a36Sopenharmony_ci .sizeof_stat = sizeof_field(struct net_device_stats, _net_stat), \ 4062306a36Sopenharmony_ci .stat_offset = offsetof(struct net_device_stats, _net_stat) \ 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic struct ixgbe_stats ixgbevf_gstrings_stats[] = { 4462306a36Sopenharmony_ci IXGBEVF_NETDEV_STAT(rx_packets), 4562306a36Sopenharmony_ci IXGBEVF_NETDEV_STAT(tx_packets), 4662306a36Sopenharmony_ci IXGBEVF_NETDEV_STAT(rx_bytes), 4762306a36Sopenharmony_ci IXGBEVF_NETDEV_STAT(tx_bytes), 4862306a36Sopenharmony_ci IXGBEVF_STAT("tx_busy", tx_busy), 4962306a36Sopenharmony_ci IXGBEVF_STAT("tx_restart_queue", restart_queue), 5062306a36Sopenharmony_ci IXGBEVF_STAT("tx_timeout_count", tx_timeout_count), 5162306a36Sopenharmony_ci IXGBEVF_NETDEV_STAT(multicast), 5262306a36Sopenharmony_ci IXGBEVF_STAT("rx_csum_offload_errors", hw_csum_rx_error), 5362306a36Sopenharmony_ci IXGBEVF_STAT("alloc_rx_page", alloc_rx_page), 5462306a36Sopenharmony_ci IXGBEVF_STAT("alloc_rx_page_failed", alloc_rx_page_failed), 5562306a36Sopenharmony_ci IXGBEVF_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed), 5662306a36Sopenharmony_ci IXGBEVF_STAT("tx_ipsec", tx_ipsec), 5762306a36Sopenharmony_ci IXGBEVF_STAT("rx_ipsec", rx_ipsec), 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define IXGBEVF_QUEUE_STATS_LEN ( \ 6162306a36Sopenharmony_ci (((struct ixgbevf_adapter *)netdev_priv(netdev))->num_tx_queues + \ 6262306a36Sopenharmony_ci ((struct ixgbevf_adapter *)netdev_priv(netdev))->num_xdp_queues + \ 6362306a36Sopenharmony_ci ((struct ixgbevf_adapter *)netdev_priv(netdev))->num_rx_queues) * \ 6462306a36Sopenharmony_ci (sizeof(struct ixgbevf_stats) / sizeof(u64))) 6562306a36Sopenharmony_ci#define IXGBEVF_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbevf_gstrings_stats) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define IXGBEVF_STATS_LEN (IXGBEVF_GLOBAL_STATS_LEN + IXGBEVF_QUEUE_STATS_LEN) 6862306a36Sopenharmony_cistatic const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { 6962306a36Sopenharmony_ci "Register test (offline)", 7062306a36Sopenharmony_ci "Link test (on/offline)" 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define IXGBEVF_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const char ixgbevf_priv_flags_strings[][ETH_GSTRING_LEN] = { 7662306a36Sopenharmony_ci#define IXGBEVF_PRIV_FLAGS_LEGACY_RX BIT(0) 7762306a36Sopenharmony_ci "legacy-rx", 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define IXGBEVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbevf_priv_flags_strings) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int ixgbevf_get_link_ksettings(struct net_device *netdev, 8362306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 8862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseT_Full); 8962306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 9062306a36Sopenharmony_ci cmd->base.port = -1; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (adapter->link_up) { 9362306a36Sopenharmony_ci __u32 speed = SPEED_10000; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci switch (adapter->link_speed) { 9662306a36Sopenharmony_ci case IXGBE_LINK_SPEED_10GB_FULL: 9762306a36Sopenharmony_ci speed = SPEED_10000; 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci case IXGBE_LINK_SPEED_1GB_FULL: 10062306a36Sopenharmony_ci speed = SPEED_1000; 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci case IXGBE_LINK_SPEED_100_FULL: 10362306a36Sopenharmony_ci speed = SPEED_100; 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci cmd->base.speed = speed; 10862306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 10962306a36Sopenharmony_ci } else { 11062306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 11162306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic u32 ixgbevf_get_msglevel(struct net_device *netdev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return adapter->msg_enable; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void ixgbevf_set_msglevel(struct net_device *netdev, u32 data) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci adapter->msg_enable = data; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int ixgbevf_get_regs_len(struct net_device *netdev) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci#define IXGBE_REGS_LEN 45 13462306a36Sopenharmony_ci return IXGBE_REGS_LEN * sizeof(u32); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void ixgbevf_get_regs(struct net_device *netdev, 13862306a36Sopenharmony_ci struct ethtool_regs *regs, 13962306a36Sopenharmony_ci void *p) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 14262306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 14362306a36Sopenharmony_ci u32 *regs_buff = p; 14462306a36Sopenharmony_ci u32 regs_len = ixgbevf_get_regs_len(netdev); 14562306a36Sopenharmony_ci u8 i; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci memset(p, 0, regs_len); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* generate a number suitable for ethtool's register version */ 15062306a36Sopenharmony_ci regs->version = (1u << 24) | (hw->revision_id << 16) | hw->device_id; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* General Registers */ 15362306a36Sopenharmony_ci regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_VFCTRL); 15462306a36Sopenharmony_ci regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_VFSTATUS); 15562306a36Sopenharmony_ci regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_VFLINKS); 15662306a36Sopenharmony_ci regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_VFRXMEMWRAP); 15762306a36Sopenharmony_ci regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_VFFRTIMER); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Interrupt */ 16062306a36Sopenharmony_ci /* don't read EICR because it can clear interrupt causes, instead 16162306a36Sopenharmony_ci * read EICS which is a shadow but doesn't clear EICR 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_VTEICS); 16462306a36Sopenharmony_ci regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_VTEICS); 16562306a36Sopenharmony_ci regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_VTEIMS); 16662306a36Sopenharmony_ci regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_VTEIMC); 16762306a36Sopenharmony_ci regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_VTEIAC); 16862306a36Sopenharmony_ci regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_VTEIAM); 16962306a36Sopenharmony_ci regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_VTEITR(0)); 17062306a36Sopenharmony_ci regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_VTIVAR(0)); 17162306a36Sopenharmony_ci regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Receive DMA */ 17462306a36Sopenharmony_ci for (i = 0; i < 2; i++) 17562306a36Sopenharmony_ci regs_buff[14 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAL(i)); 17662306a36Sopenharmony_ci for (i = 0; i < 2; i++) 17762306a36Sopenharmony_ci regs_buff[16 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAH(i)); 17862306a36Sopenharmony_ci for (i = 0; i < 2; i++) 17962306a36Sopenharmony_ci regs_buff[18 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDLEN(i)); 18062306a36Sopenharmony_ci for (i = 0; i < 2; i++) 18162306a36Sopenharmony_ci regs_buff[20 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDH(i)); 18262306a36Sopenharmony_ci for (i = 0; i < 2; i++) 18362306a36Sopenharmony_ci regs_buff[22 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDT(i)); 18462306a36Sopenharmony_ci for (i = 0; i < 2; i++) 18562306a36Sopenharmony_ci regs_buff[24 + i] = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)); 18662306a36Sopenharmony_ci for (i = 0; i < 2; i++) 18762306a36Sopenharmony_ci regs_buff[26 + i] = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i)); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Receive */ 19062306a36Sopenharmony_ci regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_VFPSRTYPE); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Transmit */ 19362306a36Sopenharmony_ci for (i = 0; i < 2; i++) 19462306a36Sopenharmony_ci regs_buff[29 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAL(i)); 19562306a36Sopenharmony_ci for (i = 0; i < 2; i++) 19662306a36Sopenharmony_ci regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAH(i)); 19762306a36Sopenharmony_ci for (i = 0; i < 2; i++) 19862306a36Sopenharmony_ci regs_buff[33 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDLEN(i)); 19962306a36Sopenharmony_ci for (i = 0; i < 2; i++) 20062306a36Sopenharmony_ci regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDH(i)); 20162306a36Sopenharmony_ci for (i = 0; i < 2; i++) 20262306a36Sopenharmony_ci regs_buff[37 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDT(i)); 20362306a36Sopenharmony_ci for (i = 0; i < 2; i++) 20462306a36Sopenharmony_ci regs_buff[39 + i] = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i)); 20562306a36Sopenharmony_ci for (i = 0; i < 2; i++) 20662306a36Sopenharmony_ci regs_buff[41 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAL(i)); 20762306a36Sopenharmony_ci for (i = 0; i < 2; i++) 20862306a36Sopenharmony_ci regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAH(i)); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void ixgbevf_get_drvinfo(struct net_device *netdev, 21262306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci strscpy(drvinfo->driver, ixgbevf_driver_name, sizeof(drvinfo->driver)); 21762306a36Sopenharmony_ci strscpy(drvinfo->bus_info, pci_name(adapter->pdev), 21862306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci drvinfo->n_priv_flags = IXGBEVF_PRIV_FLAGS_STR_LEN; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void ixgbevf_get_ringparam(struct net_device *netdev, 22462306a36Sopenharmony_ci struct ethtool_ringparam *ring, 22562306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 22662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci ring->rx_max_pending = IXGBEVF_MAX_RXD; 23162306a36Sopenharmony_ci ring->tx_max_pending = IXGBEVF_MAX_TXD; 23262306a36Sopenharmony_ci ring->rx_pending = adapter->rx_ring_count; 23362306a36Sopenharmony_ci ring->tx_pending = adapter->tx_ring_count; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int ixgbevf_set_ringparam(struct net_device *netdev, 23762306a36Sopenharmony_ci struct ethtool_ringparam *ring, 23862306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 23962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 24262306a36Sopenharmony_ci struct ixgbevf_ring *tx_ring = NULL, *rx_ring = NULL; 24362306a36Sopenharmony_ci u32 new_rx_count, new_tx_count; 24462306a36Sopenharmony_ci int i, j, err = 0; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 24762306a36Sopenharmony_ci return -EINVAL; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci new_tx_count = max_t(u32, ring->tx_pending, IXGBEVF_MIN_TXD); 25062306a36Sopenharmony_ci new_tx_count = min_t(u32, new_tx_count, IXGBEVF_MAX_TXD); 25162306a36Sopenharmony_ci new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci new_rx_count = max_t(u32, ring->rx_pending, IXGBEVF_MIN_RXD); 25462306a36Sopenharmony_ci new_rx_count = min_t(u32, new_rx_count, IXGBEVF_MAX_RXD); 25562306a36Sopenharmony_ci new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* if nothing to do return success */ 25862306a36Sopenharmony_ci if ((new_tx_count == adapter->tx_ring_count) && 25962306a36Sopenharmony_ci (new_rx_count == adapter->rx_ring_count)) 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state)) 26362306a36Sopenharmony_ci usleep_range(1000, 2000); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (!netif_running(adapter->netdev)) { 26662306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) 26762306a36Sopenharmony_ci adapter->tx_ring[i]->count = new_tx_count; 26862306a36Sopenharmony_ci for (i = 0; i < adapter->num_xdp_queues; i++) 26962306a36Sopenharmony_ci adapter->xdp_ring[i]->count = new_tx_count; 27062306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) 27162306a36Sopenharmony_ci adapter->rx_ring[i]->count = new_rx_count; 27262306a36Sopenharmony_ci adapter->tx_ring_count = new_tx_count; 27362306a36Sopenharmony_ci adapter->xdp_ring_count = new_tx_count; 27462306a36Sopenharmony_ci adapter->rx_ring_count = new_rx_count; 27562306a36Sopenharmony_ci goto clear_reset; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (new_tx_count != adapter->tx_ring_count) { 27962306a36Sopenharmony_ci tx_ring = vmalloc(array_size(sizeof(*tx_ring), 28062306a36Sopenharmony_ci adapter->num_tx_queues + 28162306a36Sopenharmony_ci adapter->num_xdp_queues)); 28262306a36Sopenharmony_ci if (!tx_ring) { 28362306a36Sopenharmony_ci err = -ENOMEM; 28462306a36Sopenharmony_ci goto clear_reset; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 28862306a36Sopenharmony_ci /* clone ring and setup updated count */ 28962306a36Sopenharmony_ci tx_ring[i] = *adapter->tx_ring[i]; 29062306a36Sopenharmony_ci tx_ring[i].count = new_tx_count; 29162306a36Sopenharmony_ci err = ixgbevf_setup_tx_resources(&tx_ring[i]); 29262306a36Sopenharmony_ci if (err) { 29362306a36Sopenharmony_ci while (i) { 29462306a36Sopenharmony_ci i--; 29562306a36Sopenharmony_ci ixgbevf_free_tx_resources(&tx_ring[i]); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci vfree(tx_ring); 29962306a36Sopenharmony_ci tx_ring = NULL; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci goto clear_reset; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci for (j = 0; j < adapter->num_xdp_queues; i++, j++) { 30662306a36Sopenharmony_ci /* clone ring and setup updated count */ 30762306a36Sopenharmony_ci tx_ring[i] = *adapter->xdp_ring[j]; 30862306a36Sopenharmony_ci tx_ring[i].count = new_tx_count; 30962306a36Sopenharmony_ci err = ixgbevf_setup_tx_resources(&tx_ring[i]); 31062306a36Sopenharmony_ci if (err) { 31162306a36Sopenharmony_ci while (i) { 31262306a36Sopenharmony_ci i--; 31362306a36Sopenharmony_ci ixgbevf_free_tx_resources(&tx_ring[i]); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci vfree(tx_ring); 31762306a36Sopenharmony_ci tx_ring = NULL; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci goto clear_reset; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (new_rx_count != adapter->rx_ring_count) { 32562306a36Sopenharmony_ci rx_ring = vmalloc(array_size(sizeof(*rx_ring), 32662306a36Sopenharmony_ci adapter->num_rx_queues)); 32762306a36Sopenharmony_ci if (!rx_ring) { 32862306a36Sopenharmony_ci err = -ENOMEM; 32962306a36Sopenharmony_ci goto clear_reset; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 33362306a36Sopenharmony_ci /* clone ring and setup updated count */ 33462306a36Sopenharmony_ci rx_ring[i] = *adapter->rx_ring[i]; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Clear copied XDP RX-queue info */ 33762306a36Sopenharmony_ci memset(&rx_ring[i].xdp_rxq, 0, 33862306a36Sopenharmony_ci sizeof(rx_ring[i].xdp_rxq)); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci rx_ring[i].count = new_rx_count; 34162306a36Sopenharmony_ci err = ixgbevf_setup_rx_resources(adapter, &rx_ring[i]); 34262306a36Sopenharmony_ci if (err) { 34362306a36Sopenharmony_ci while (i) { 34462306a36Sopenharmony_ci i--; 34562306a36Sopenharmony_ci ixgbevf_free_rx_resources(&rx_ring[i]); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci vfree(rx_ring); 34962306a36Sopenharmony_ci rx_ring = NULL; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci goto clear_reset; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* bring interface down to prepare for update */ 35762306a36Sopenharmony_ci ixgbevf_down(adapter); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* Tx */ 36062306a36Sopenharmony_ci if (tx_ring) { 36162306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 36262306a36Sopenharmony_ci ixgbevf_free_tx_resources(adapter->tx_ring[i]); 36362306a36Sopenharmony_ci *adapter->tx_ring[i] = tx_ring[i]; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci adapter->tx_ring_count = new_tx_count; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci for (j = 0; j < adapter->num_xdp_queues; i++, j++) { 36862306a36Sopenharmony_ci ixgbevf_free_tx_resources(adapter->xdp_ring[j]); 36962306a36Sopenharmony_ci *adapter->xdp_ring[j] = tx_ring[i]; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci adapter->xdp_ring_count = new_tx_count; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci vfree(tx_ring); 37462306a36Sopenharmony_ci tx_ring = NULL; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* Rx */ 37862306a36Sopenharmony_ci if (rx_ring) { 37962306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 38062306a36Sopenharmony_ci ixgbevf_free_rx_resources(adapter->rx_ring[i]); 38162306a36Sopenharmony_ci *adapter->rx_ring[i] = rx_ring[i]; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci adapter->rx_ring_count = new_rx_count; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci vfree(rx_ring); 38662306a36Sopenharmony_ci rx_ring = NULL; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* restore interface using new values */ 39062306a36Sopenharmony_ci ixgbevf_up(adapter); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ciclear_reset: 39362306a36Sopenharmony_ci /* free Tx resources if Rx error is encountered */ 39462306a36Sopenharmony_ci if (tx_ring) { 39562306a36Sopenharmony_ci for (i = 0; 39662306a36Sopenharmony_ci i < adapter->num_tx_queues + adapter->num_xdp_queues; i++) 39762306a36Sopenharmony_ci ixgbevf_free_tx_resources(&tx_ring[i]); 39862306a36Sopenharmony_ci vfree(tx_ring); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci clear_bit(__IXGBEVF_RESETTING, &adapter->state); 40262306a36Sopenharmony_ci return err; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int ixgbevf_get_sset_count(struct net_device *netdev, int stringset) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci switch (stringset) { 40862306a36Sopenharmony_ci case ETH_SS_TEST: 40962306a36Sopenharmony_ci return IXGBEVF_TEST_LEN; 41062306a36Sopenharmony_ci case ETH_SS_STATS: 41162306a36Sopenharmony_ci return IXGBEVF_STATS_LEN; 41262306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 41362306a36Sopenharmony_ci return IXGBEVF_PRIV_FLAGS_STR_LEN; 41462306a36Sopenharmony_ci default: 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void ixgbevf_get_ethtool_stats(struct net_device *netdev, 42062306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 42362306a36Sopenharmony_ci struct rtnl_link_stats64 temp; 42462306a36Sopenharmony_ci const struct rtnl_link_stats64 *net_stats; 42562306a36Sopenharmony_ci unsigned int start; 42662306a36Sopenharmony_ci struct ixgbevf_ring *ring; 42762306a36Sopenharmony_ci int i, j; 42862306a36Sopenharmony_ci char *p; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ixgbevf_update_stats(adapter); 43162306a36Sopenharmony_ci net_stats = dev_get_stats(netdev, &temp); 43262306a36Sopenharmony_ci for (i = 0; i < IXGBEVF_GLOBAL_STATS_LEN; i++) { 43362306a36Sopenharmony_ci switch (ixgbevf_gstrings_stats[i].type) { 43462306a36Sopenharmony_ci case NETDEV_STATS: 43562306a36Sopenharmony_ci p = (char *)net_stats + 43662306a36Sopenharmony_ci ixgbevf_gstrings_stats[i].stat_offset; 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci case IXGBEVF_STATS: 43962306a36Sopenharmony_ci p = (char *)adapter + 44062306a36Sopenharmony_ci ixgbevf_gstrings_stats[i].stat_offset; 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci default: 44362306a36Sopenharmony_ci data[i] = 0; 44462306a36Sopenharmony_ci continue; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci data[i] = (ixgbevf_gstrings_stats[i].sizeof_stat == 44862306a36Sopenharmony_ci sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* populate Tx queue data */ 45262306a36Sopenharmony_ci for (j = 0; j < adapter->num_tx_queues; j++) { 45362306a36Sopenharmony_ci ring = adapter->tx_ring[j]; 45462306a36Sopenharmony_ci if (!ring) { 45562306a36Sopenharmony_ci data[i++] = 0; 45662306a36Sopenharmony_ci data[i++] = 0; 45762306a36Sopenharmony_ci continue; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci do { 46162306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->syncp); 46262306a36Sopenharmony_ci data[i] = ring->stats.packets; 46362306a36Sopenharmony_ci data[i + 1] = ring->stats.bytes; 46462306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->syncp, start)); 46562306a36Sopenharmony_ci i += 2; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* populate XDP queue data */ 46962306a36Sopenharmony_ci for (j = 0; j < adapter->num_xdp_queues; j++) { 47062306a36Sopenharmony_ci ring = adapter->xdp_ring[j]; 47162306a36Sopenharmony_ci if (!ring) { 47262306a36Sopenharmony_ci data[i++] = 0; 47362306a36Sopenharmony_ci data[i++] = 0; 47462306a36Sopenharmony_ci continue; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci do { 47862306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->syncp); 47962306a36Sopenharmony_ci data[i] = ring->stats.packets; 48062306a36Sopenharmony_ci data[i + 1] = ring->stats.bytes; 48162306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->syncp, start)); 48262306a36Sopenharmony_ci i += 2; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* populate Rx queue data */ 48662306a36Sopenharmony_ci for (j = 0; j < adapter->num_rx_queues; j++) { 48762306a36Sopenharmony_ci ring = adapter->rx_ring[j]; 48862306a36Sopenharmony_ci if (!ring) { 48962306a36Sopenharmony_ci data[i++] = 0; 49062306a36Sopenharmony_ci data[i++] = 0; 49162306a36Sopenharmony_ci continue; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci do { 49562306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->syncp); 49662306a36Sopenharmony_ci data[i] = ring->stats.packets; 49762306a36Sopenharmony_ci data[i + 1] = ring->stats.bytes; 49862306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->syncp, start)); 49962306a36Sopenharmony_ci i += 2; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic void ixgbevf_get_strings(struct net_device *netdev, u32 stringset, 50462306a36Sopenharmony_ci u8 *data) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 50762306a36Sopenharmony_ci char *p = (char *)data; 50862306a36Sopenharmony_ci int i; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci switch (stringset) { 51162306a36Sopenharmony_ci case ETH_SS_TEST: 51262306a36Sopenharmony_ci memcpy(data, *ixgbe_gstrings_test, 51362306a36Sopenharmony_ci IXGBEVF_TEST_LEN * ETH_GSTRING_LEN); 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci case ETH_SS_STATS: 51662306a36Sopenharmony_ci for (i = 0; i < IXGBEVF_GLOBAL_STATS_LEN; i++) { 51762306a36Sopenharmony_ci memcpy(p, ixgbevf_gstrings_stats[i].stat_string, 51862306a36Sopenharmony_ci ETH_GSTRING_LEN); 51962306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 52362306a36Sopenharmony_ci sprintf(p, "tx_queue_%u_packets", i); 52462306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 52562306a36Sopenharmony_ci sprintf(p, "tx_queue_%u_bytes", i); 52662306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci for (i = 0; i < adapter->num_xdp_queues; i++) { 52962306a36Sopenharmony_ci sprintf(p, "xdp_queue_%u_packets", i); 53062306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 53162306a36Sopenharmony_ci sprintf(p, "xdp_queue_%u_bytes", i); 53262306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 53562306a36Sopenharmony_ci sprintf(p, "rx_queue_%u_packets", i); 53662306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 53762306a36Sopenharmony_ci sprintf(p, "rx_queue_%u_bytes", i); 53862306a36Sopenharmony_ci p += ETH_GSTRING_LEN; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 54262306a36Sopenharmony_ci memcpy(data, ixgbevf_priv_flags_strings, 54362306a36Sopenharmony_ci IXGBEVF_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int ixgbevf_link_test(struct ixgbevf_adapter *adapter, u64 *data) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 55162306a36Sopenharmony_ci bool link_up; 55262306a36Sopenharmony_ci u32 link_speed = 0; 55362306a36Sopenharmony_ci *data = 0; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci hw->mac.ops.check_link(hw, &link_speed, &link_up, true); 55662306a36Sopenharmony_ci if (!link_up) 55762306a36Sopenharmony_ci *data = 1; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return *data; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci/* ethtool register test data */ 56362306a36Sopenharmony_cistruct ixgbevf_reg_test { 56462306a36Sopenharmony_ci u16 reg; 56562306a36Sopenharmony_ci u8 array_len; 56662306a36Sopenharmony_ci u8 test_type; 56762306a36Sopenharmony_ci u32 mask; 56862306a36Sopenharmony_ci u32 write; 56962306a36Sopenharmony_ci}; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/* In the hardware, registers are laid out either singly, in arrays 57262306a36Sopenharmony_ci * spaced 0x40 bytes apart, or in contiguous tables. We assume 57362306a36Sopenharmony_ci * most tests take place on arrays or single registers (handled 57462306a36Sopenharmony_ci * as a single-element array) and special-case the tables. 57562306a36Sopenharmony_ci * Table tests are always pattern tests. 57662306a36Sopenharmony_ci * 57762306a36Sopenharmony_ci * We also make provision for some required setup steps by specifying 57862306a36Sopenharmony_ci * registers to be written without any read-back testing. 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci#define PATTERN_TEST 1 58262306a36Sopenharmony_ci#define SET_READ_TEST 2 58362306a36Sopenharmony_ci#define WRITE_NO_TEST 3 58462306a36Sopenharmony_ci#define TABLE32_TEST 4 58562306a36Sopenharmony_ci#define TABLE64_TEST_LO 5 58662306a36Sopenharmony_ci#define TABLE64_TEST_HI 6 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* default VF register test */ 58962306a36Sopenharmony_cistatic const struct ixgbevf_reg_test reg_test_vf[] = { 59062306a36Sopenharmony_ci { IXGBE_VFRDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, 59162306a36Sopenharmony_ci { IXGBE_VFRDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 59262306a36Sopenharmony_ci { IXGBE_VFRDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 59362306a36Sopenharmony_ci { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, 59462306a36Sopenharmony_ci { IXGBE_VFRDT(0), 2, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 59562306a36Sopenharmony_ci { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, 0 }, 59662306a36Sopenharmony_ci { IXGBE_VFTDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 59762306a36Sopenharmony_ci { IXGBE_VFTDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 59862306a36Sopenharmony_ci { IXGBE_VFTDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFF80 }, 59962306a36Sopenharmony_ci { .reg = 0 } 60062306a36Sopenharmony_ci}; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic const u32 register_test_patterns[] = { 60362306a36Sopenharmony_ci 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF 60462306a36Sopenharmony_ci}; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic bool reg_pattern_test(struct ixgbevf_adapter *adapter, u64 *data, 60762306a36Sopenharmony_ci int reg, u32 mask, u32 write) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci u32 pat, val, before; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (IXGBE_REMOVED(adapter->hw.hw_addr)) { 61262306a36Sopenharmony_ci *data = 1; 61362306a36Sopenharmony_ci return true; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { 61662306a36Sopenharmony_ci before = ixgbevf_read_reg(&adapter->hw, reg); 61762306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, 61862306a36Sopenharmony_ci register_test_patterns[pat] & write); 61962306a36Sopenharmony_ci val = ixgbevf_read_reg(&adapter->hw, reg); 62062306a36Sopenharmony_ci if (val != (register_test_patterns[pat] & write & mask)) { 62162306a36Sopenharmony_ci hw_dbg(&adapter->hw, 62262306a36Sopenharmony_ci "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n", 62362306a36Sopenharmony_ci reg, val, 62462306a36Sopenharmony_ci register_test_patterns[pat] & write & mask); 62562306a36Sopenharmony_ci *data = reg; 62662306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 62762306a36Sopenharmony_ci return true; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci return false; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic bool reg_set_and_check(struct ixgbevf_adapter *adapter, u64 *data, 63562306a36Sopenharmony_ci int reg, u32 mask, u32 write) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci u32 val, before; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (IXGBE_REMOVED(adapter->hw.hw_addr)) { 64062306a36Sopenharmony_ci *data = 1; 64162306a36Sopenharmony_ci return true; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci before = ixgbevf_read_reg(&adapter->hw, reg); 64462306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, write & mask); 64562306a36Sopenharmony_ci val = ixgbevf_read_reg(&adapter->hw, reg); 64662306a36Sopenharmony_ci if ((write & mask) != (val & mask)) { 64762306a36Sopenharmony_ci pr_err("set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", 64862306a36Sopenharmony_ci reg, (val & mask), write & mask); 64962306a36Sopenharmony_ci *data = reg; 65062306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 65162306a36Sopenharmony_ci return true; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 65462306a36Sopenharmony_ci return false; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci const struct ixgbevf_reg_test *test; 66062306a36Sopenharmony_ci u32 i; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (IXGBE_REMOVED(adapter->hw.hw_addr)) { 66362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 66462306a36Sopenharmony_ci "Adapter removed - register test blocked\n"); 66562306a36Sopenharmony_ci *data = 1; 66662306a36Sopenharmony_ci return 1; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci test = reg_test_vf; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* Perform the register test, looping through the test table 67162306a36Sopenharmony_ci * until we either fail or reach the null entry. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci while (test->reg) { 67462306a36Sopenharmony_ci for (i = 0; i < test->array_len; i++) { 67562306a36Sopenharmony_ci bool b = false; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci switch (test->test_type) { 67862306a36Sopenharmony_ci case PATTERN_TEST: 67962306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 68062306a36Sopenharmony_ci test->reg + (i * 0x40), 68162306a36Sopenharmony_ci test->mask, 68262306a36Sopenharmony_ci test->write); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case SET_READ_TEST: 68562306a36Sopenharmony_ci b = reg_set_and_check(adapter, data, 68662306a36Sopenharmony_ci test->reg + (i * 0x40), 68762306a36Sopenharmony_ci test->mask, 68862306a36Sopenharmony_ci test->write); 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci case WRITE_NO_TEST: 69162306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, 69262306a36Sopenharmony_ci test->reg + (i * 0x40), 69362306a36Sopenharmony_ci test->write); 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci case TABLE32_TEST: 69662306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 69762306a36Sopenharmony_ci test->reg + (i * 4), 69862306a36Sopenharmony_ci test->mask, 69962306a36Sopenharmony_ci test->write); 70062306a36Sopenharmony_ci break; 70162306a36Sopenharmony_ci case TABLE64_TEST_LO: 70262306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 70362306a36Sopenharmony_ci test->reg + (i * 8), 70462306a36Sopenharmony_ci test->mask, 70562306a36Sopenharmony_ci test->write); 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci case TABLE64_TEST_HI: 70862306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 70962306a36Sopenharmony_ci test->reg + 4 + (i * 8), 71062306a36Sopenharmony_ci test->mask, 71162306a36Sopenharmony_ci test->write); 71262306a36Sopenharmony_ci break; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci if (b) 71562306a36Sopenharmony_ci return 1; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci test++; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci *data = 0; 72162306a36Sopenharmony_ci return *data; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic void ixgbevf_diag_test(struct net_device *netdev, 72562306a36Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 72862306a36Sopenharmony_ci bool if_running = netif_running(netdev); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (IXGBE_REMOVED(adapter->hw.hw_addr)) { 73162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 73262306a36Sopenharmony_ci "Adapter removed - test blocked\n"); 73362306a36Sopenharmony_ci data[0] = 1; 73462306a36Sopenharmony_ci data[1] = 1; 73562306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 73662306a36Sopenharmony_ci return; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci set_bit(__IXGBEVF_TESTING, &adapter->state); 73962306a36Sopenharmony_ci if (eth_test->flags == ETH_TEST_FL_OFFLINE) { 74062306a36Sopenharmony_ci /* Offline tests */ 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci hw_dbg(&adapter->hw, "offline testing starting\n"); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* Link test performed before hardware reset so autoneg doesn't 74562306a36Sopenharmony_ci * interfere with test result 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_ci if (ixgbevf_link_test(adapter, &data[1])) 74862306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (if_running) 75162306a36Sopenharmony_ci /* indicate we're in test mode */ 75262306a36Sopenharmony_ci ixgbevf_close(netdev); 75362306a36Sopenharmony_ci else 75462306a36Sopenharmony_ci ixgbevf_reset(adapter); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci hw_dbg(&adapter->hw, "register testing starting\n"); 75762306a36Sopenharmony_ci if (ixgbevf_reg_test(adapter, &data[0])) 75862306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci ixgbevf_reset(adapter); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci clear_bit(__IXGBEVF_TESTING, &adapter->state); 76362306a36Sopenharmony_ci if (if_running) 76462306a36Sopenharmony_ci ixgbevf_open(netdev); 76562306a36Sopenharmony_ci } else { 76662306a36Sopenharmony_ci hw_dbg(&adapter->hw, "online testing starting\n"); 76762306a36Sopenharmony_ci /* Online tests */ 76862306a36Sopenharmony_ci if (ixgbevf_link_test(adapter, &data[1])) 76962306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci /* Online tests aren't run; pass by default */ 77262306a36Sopenharmony_ci data[0] = 0; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci clear_bit(__IXGBEVF_TESTING, &adapter->state); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci msleep_interruptible(4 * 1000); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic int ixgbevf_nway_reset(struct net_device *netdev) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (netif_running(netdev)) 78462306a36Sopenharmony_ci ixgbevf_reinit_locked(adapter); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int ixgbevf_get_coalesce(struct net_device *netdev, 79062306a36Sopenharmony_ci struct ethtool_coalesce *ec, 79162306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 79262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* only valid if in constant ITR mode */ 79762306a36Sopenharmony_ci if (adapter->rx_itr_setting <= 1) 79862306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->rx_itr_setting; 79962306a36Sopenharmony_ci else 80062306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* if in mixed Tx/Rx queues per vector mode, report only Rx settings */ 80362306a36Sopenharmony_ci if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* only valid if in constant ITR mode */ 80762306a36Sopenharmony_ci if (adapter->tx_itr_setting <= 1) 80862306a36Sopenharmony_ci ec->tx_coalesce_usecs = adapter->tx_itr_setting; 80962306a36Sopenharmony_ci else 81062306a36Sopenharmony_ci ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int ixgbevf_set_coalesce(struct net_device *netdev, 81662306a36Sopenharmony_ci struct ethtool_coalesce *ec, 81762306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 81862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 82162306a36Sopenharmony_ci struct ixgbevf_q_vector *q_vector; 82262306a36Sopenharmony_ci int num_vectors, i; 82362306a36Sopenharmony_ci u16 tx_itr_param, rx_itr_param; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* don't accept Tx specific changes if we've got mixed RxTx vectors */ 82662306a36Sopenharmony_ci if (adapter->q_vector[0]->tx.count && 82762306a36Sopenharmony_ci adapter->q_vector[0]->rx.count && ec->tx_coalesce_usecs) 82862306a36Sopenharmony_ci return -EINVAL; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if ((ec->rx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)) || 83162306a36Sopenharmony_ci (ec->tx_coalesce_usecs > (IXGBE_MAX_EITR >> 2))) 83262306a36Sopenharmony_ci return -EINVAL; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (ec->rx_coalesce_usecs > 1) 83562306a36Sopenharmony_ci adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2; 83662306a36Sopenharmony_ci else 83762306a36Sopenharmony_ci adapter->rx_itr_setting = ec->rx_coalesce_usecs; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (adapter->rx_itr_setting == 1) 84062306a36Sopenharmony_ci rx_itr_param = IXGBE_20K_ITR; 84162306a36Sopenharmony_ci else 84262306a36Sopenharmony_ci rx_itr_param = adapter->rx_itr_setting; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (ec->tx_coalesce_usecs > 1) 84562306a36Sopenharmony_ci adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2; 84662306a36Sopenharmony_ci else 84762306a36Sopenharmony_ci adapter->tx_itr_setting = ec->tx_coalesce_usecs; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (adapter->tx_itr_setting == 1) 85062306a36Sopenharmony_ci tx_itr_param = IXGBE_12K_ITR; 85162306a36Sopenharmony_ci else 85262306a36Sopenharmony_ci tx_itr_param = adapter->tx_itr_setting; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci num_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci for (i = 0; i < num_vectors; i++) { 85762306a36Sopenharmony_ci q_vector = adapter->q_vector[i]; 85862306a36Sopenharmony_ci if (q_vector->tx.count && !q_vector->rx.count) 85962306a36Sopenharmony_ci /* Tx only */ 86062306a36Sopenharmony_ci q_vector->itr = tx_itr_param; 86162306a36Sopenharmony_ci else 86262306a36Sopenharmony_ci /* Rx only or mixed */ 86362306a36Sopenharmony_ci q_vector->itr = rx_itr_param; 86462306a36Sopenharmony_ci ixgbevf_write_eitr(q_vector); 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return 0; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic int ixgbevf_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 87162306a36Sopenharmony_ci u32 *rules __always_unused) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(dev); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci switch (info->cmd) { 87662306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 87762306a36Sopenharmony_ci info->data = adapter->num_rx_queues; 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci default: 88062306a36Sopenharmony_ci hw_dbg(&adapter->hw, "Command parameters not supported\n"); 88162306a36Sopenharmony_ci return -EOPNOTSUPP; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic u32 ixgbevf_get_rxfh_indir_size(struct net_device *netdev) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (adapter->hw.mac.type >= ixgbe_mac_X550_vf) 89062306a36Sopenharmony_ci return IXGBEVF_X550_VFRETA_SIZE; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci return IXGBEVF_82599_RETA_SIZE; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic u32 ixgbevf_get_rxfh_key_size(struct net_device *netdev) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci return IXGBEVF_RSS_HASH_KEY_SIZE; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic int ixgbevf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, 90162306a36Sopenharmony_ci u8 *hfunc) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 90462306a36Sopenharmony_ci int err = 0; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (hfunc) 90762306a36Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (adapter->hw.mac.type >= ixgbe_mac_X550_vf) { 91062306a36Sopenharmony_ci if (key) 91162306a36Sopenharmony_ci memcpy(key, adapter->rss_key, 91262306a36Sopenharmony_ci ixgbevf_get_rxfh_key_size(netdev)); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (indir) { 91562306a36Sopenharmony_ci int i; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci for (i = 0; i < IXGBEVF_X550_VFRETA_SIZE; i++) 91862306a36Sopenharmony_ci indir[i] = adapter->rss_indir_tbl[i]; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci } else { 92162306a36Sopenharmony_ci /* If neither indirection table nor hash key was requested 92262306a36Sopenharmony_ci * - just return a success avoiding taking any locks. 92362306a36Sopenharmony_ci */ 92462306a36Sopenharmony_ci if (!indir && !key) 92562306a36Sopenharmony_ci return 0; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci spin_lock_bh(&adapter->mbx_lock); 92862306a36Sopenharmony_ci if (indir) 92962306a36Sopenharmony_ci err = ixgbevf_get_reta_locked(&adapter->hw, indir, 93062306a36Sopenharmony_ci adapter->num_rx_queues); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (!err && key) 93362306a36Sopenharmony_ci err = ixgbevf_get_rss_key_locked(&adapter->hw, key); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci spin_unlock_bh(&adapter->mbx_lock); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return err; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic u32 ixgbevf_get_priv_flags(struct net_device *netdev) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 94462306a36Sopenharmony_ci u32 priv_flags = 0; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (adapter->flags & IXGBEVF_FLAGS_LEGACY_RX) 94762306a36Sopenharmony_ci priv_flags |= IXGBEVF_PRIV_FLAGS_LEGACY_RX; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci return priv_flags; 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistatic int ixgbevf_set_priv_flags(struct net_device *netdev, u32 priv_flags) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci struct ixgbevf_adapter *adapter = netdev_priv(netdev); 95562306a36Sopenharmony_ci unsigned int flags = adapter->flags; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci flags &= ~IXGBEVF_FLAGS_LEGACY_RX; 95862306a36Sopenharmony_ci if (priv_flags & IXGBEVF_PRIV_FLAGS_LEGACY_RX) 95962306a36Sopenharmony_ci flags |= IXGBEVF_FLAGS_LEGACY_RX; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (flags != adapter->flags) { 96262306a36Sopenharmony_ci adapter->flags = flags; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* reset interface to repopulate queues */ 96562306a36Sopenharmony_ci if (netif_running(netdev)) 96662306a36Sopenharmony_ci ixgbevf_reinit_locked(adapter); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic const struct ethtool_ops ixgbevf_ethtool_ops = { 97362306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 97462306a36Sopenharmony_ci .get_drvinfo = ixgbevf_get_drvinfo, 97562306a36Sopenharmony_ci .get_regs_len = ixgbevf_get_regs_len, 97662306a36Sopenharmony_ci .get_regs = ixgbevf_get_regs, 97762306a36Sopenharmony_ci .nway_reset = ixgbevf_nway_reset, 97862306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 97962306a36Sopenharmony_ci .get_ringparam = ixgbevf_get_ringparam, 98062306a36Sopenharmony_ci .set_ringparam = ixgbevf_set_ringparam, 98162306a36Sopenharmony_ci .get_msglevel = ixgbevf_get_msglevel, 98262306a36Sopenharmony_ci .set_msglevel = ixgbevf_set_msglevel, 98362306a36Sopenharmony_ci .self_test = ixgbevf_diag_test, 98462306a36Sopenharmony_ci .get_sset_count = ixgbevf_get_sset_count, 98562306a36Sopenharmony_ci .get_strings = ixgbevf_get_strings, 98662306a36Sopenharmony_ci .get_ethtool_stats = ixgbevf_get_ethtool_stats, 98762306a36Sopenharmony_ci .get_coalesce = ixgbevf_get_coalesce, 98862306a36Sopenharmony_ci .set_coalesce = ixgbevf_set_coalesce, 98962306a36Sopenharmony_ci .get_rxnfc = ixgbevf_get_rxnfc, 99062306a36Sopenharmony_ci .get_rxfh_indir_size = ixgbevf_get_rxfh_indir_size, 99162306a36Sopenharmony_ci .get_rxfh_key_size = ixgbevf_get_rxfh_key_size, 99262306a36Sopenharmony_ci .get_rxfh = ixgbevf_get_rxfh, 99362306a36Sopenharmony_ci .get_link_ksettings = ixgbevf_get_link_ksettings, 99462306a36Sopenharmony_ci .get_priv_flags = ixgbevf_get_priv_flags, 99562306a36Sopenharmony_ci .set_priv_flags = ixgbevf_set_priv_flags, 99662306a36Sopenharmony_ci}; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_civoid ixgbevf_set_ethtool_ops(struct net_device *netdev) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci netdev->ethtool_ops = &ixgbevf_ethtool_ops; 100162306a36Sopenharmony_ci} 1002