162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* ethtool support for ixgbe */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/interrupt.h> 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/ethtool.h> 1362306a36Sopenharmony_ci#include <linux/vmalloc.h> 1462306a36Sopenharmony_ci#include <linux/highmem.h> 1562306a36Sopenharmony_ci#include <linux/uaccess.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "ixgbe.h" 1862306a36Sopenharmony_ci#include "ixgbe_phy.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cienum {NETDEV_STATS, IXGBE_STATS}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct ixgbe_stats { 2462306a36Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 2562306a36Sopenharmony_ci int type; 2662306a36Sopenharmony_ci int sizeof_stat; 2762306a36Sopenharmony_ci int stat_offset; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define IXGBE_STAT(m) IXGBE_STATS, \ 3162306a36Sopenharmony_ci sizeof(((struct ixgbe_adapter *)0)->m), \ 3262306a36Sopenharmony_ci offsetof(struct ixgbe_adapter, m) 3362306a36Sopenharmony_ci#define IXGBE_NETDEV_STAT(m) NETDEV_STATS, \ 3462306a36Sopenharmony_ci sizeof(((struct rtnl_link_stats64 *)0)->m), \ 3562306a36Sopenharmony_ci offsetof(struct rtnl_link_stats64, m) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const struct ixgbe_stats ixgbe_gstrings_stats[] = { 3862306a36Sopenharmony_ci {"rx_packets", IXGBE_NETDEV_STAT(rx_packets)}, 3962306a36Sopenharmony_ci {"tx_packets", IXGBE_NETDEV_STAT(tx_packets)}, 4062306a36Sopenharmony_ci {"rx_bytes", IXGBE_NETDEV_STAT(rx_bytes)}, 4162306a36Sopenharmony_ci {"tx_bytes", IXGBE_NETDEV_STAT(tx_bytes)}, 4262306a36Sopenharmony_ci {"rx_pkts_nic", IXGBE_STAT(stats.gprc)}, 4362306a36Sopenharmony_ci {"tx_pkts_nic", IXGBE_STAT(stats.gptc)}, 4462306a36Sopenharmony_ci {"rx_bytes_nic", IXGBE_STAT(stats.gorc)}, 4562306a36Sopenharmony_ci {"tx_bytes_nic", IXGBE_STAT(stats.gotc)}, 4662306a36Sopenharmony_ci {"lsc_int", IXGBE_STAT(lsc_int)}, 4762306a36Sopenharmony_ci {"tx_busy", IXGBE_STAT(tx_busy)}, 4862306a36Sopenharmony_ci {"non_eop_descs", IXGBE_STAT(non_eop_descs)}, 4962306a36Sopenharmony_ci {"rx_errors", IXGBE_NETDEV_STAT(rx_errors)}, 5062306a36Sopenharmony_ci {"tx_errors", IXGBE_NETDEV_STAT(tx_errors)}, 5162306a36Sopenharmony_ci {"rx_dropped", IXGBE_NETDEV_STAT(rx_dropped)}, 5262306a36Sopenharmony_ci {"tx_dropped", IXGBE_NETDEV_STAT(tx_dropped)}, 5362306a36Sopenharmony_ci {"multicast", IXGBE_NETDEV_STAT(multicast)}, 5462306a36Sopenharmony_ci {"broadcast", IXGBE_STAT(stats.bprc)}, 5562306a36Sopenharmony_ci {"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) }, 5662306a36Sopenharmony_ci {"collisions", IXGBE_NETDEV_STAT(collisions)}, 5762306a36Sopenharmony_ci {"rx_over_errors", IXGBE_NETDEV_STAT(rx_over_errors)}, 5862306a36Sopenharmony_ci {"rx_crc_errors", IXGBE_NETDEV_STAT(rx_crc_errors)}, 5962306a36Sopenharmony_ci {"rx_frame_errors", IXGBE_NETDEV_STAT(rx_frame_errors)}, 6062306a36Sopenharmony_ci {"hw_rsc_aggregated", IXGBE_STAT(rsc_total_count)}, 6162306a36Sopenharmony_ci {"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)}, 6262306a36Sopenharmony_ci {"fdir_match", IXGBE_STAT(stats.fdirmatch)}, 6362306a36Sopenharmony_ci {"fdir_miss", IXGBE_STAT(stats.fdirmiss)}, 6462306a36Sopenharmony_ci {"fdir_overflow", IXGBE_STAT(fdir_overflow)}, 6562306a36Sopenharmony_ci {"rx_fifo_errors", IXGBE_NETDEV_STAT(rx_fifo_errors)}, 6662306a36Sopenharmony_ci {"rx_missed_errors", IXGBE_NETDEV_STAT(rx_missed_errors)}, 6762306a36Sopenharmony_ci {"tx_aborted_errors", IXGBE_NETDEV_STAT(tx_aborted_errors)}, 6862306a36Sopenharmony_ci {"tx_carrier_errors", IXGBE_NETDEV_STAT(tx_carrier_errors)}, 6962306a36Sopenharmony_ci {"tx_fifo_errors", IXGBE_NETDEV_STAT(tx_fifo_errors)}, 7062306a36Sopenharmony_ci {"tx_heartbeat_errors", IXGBE_NETDEV_STAT(tx_heartbeat_errors)}, 7162306a36Sopenharmony_ci {"tx_timeout_count", IXGBE_STAT(tx_timeout_count)}, 7262306a36Sopenharmony_ci {"tx_restart_queue", IXGBE_STAT(restart_queue)}, 7362306a36Sopenharmony_ci {"rx_length_errors", IXGBE_STAT(stats.rlec)}, 7462306a36Sopenharmony_ci {"rx_long_length_errors", IXGBE_STAT(stats.roc)}, 7562306a36Sopenharmony_ci {"rx_short_length_errors", IXGBE_STAT(stats.ruc)}, 7662306a36Sopenharmony_ci {"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)}, 7762306a36Sopenharmony_ci {"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)}, 7862306a36Sopenharmony_ci {"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)}, 7962306a36Sopenharmony_ci {"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)}, 8062306a36Sopenharmony_ci {"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)}, 8162306a36Sopenharmony_ci {"alloc_rx_page", IXGBE_STAT(alloc_rx_page)}, 8262306a36Sopenharmony_ci {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, 8362306a36Sopenharmony_ci {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, 8462306a36Sopenharmony_ci {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)}, 8562306a36Sopenharmony_ci {"os2bmc_rx_by_bmc", IXGBE_STAT(stats.o2bgptc)}, 8662306a36Sopenharmony_ci {"os2bmc_tx_by_bmc", IXGBE_STAT(stats.b2ospc)}, 8762306a36Sopenharmony_ci {"os2bmc_tx_by_host", IXGBE_STAT(stats.o2bspc)}, 8862306a36Sopenharmony_ci {"os2bmc_rx_by_host", IXGBE_STAT(stats.b2ogprc)}, 8962306a36Sopenharmony_ci {"tx_hwtstamp_timeouts", IXGBE_STAT(tx_hwtstamp_timeouts)}, 9062306a36Sopenharmony_ci {"tx_hwtstamp_skipped", IXGBE_STAT(tx_hwtstamp_skipped)}, 9162306a36Sopenharmony_ci {"rx_hwtstamp_cleared", IXGBE_STAT(rx_hwtstamp_cleared)}, 9262306a36Sopenharmony_ci {"tx_ipsec", IXGBE_STAT(tx_ipsec)}, 9362306a36Sopenharmony_ci {"rx_ipsec", IXGBE_STAT(rx_ipsec)}, 9462306a36Sopenharmony_ci#ifdef IXGBE_FCOE 9562306a36Sopenharmony_ci {"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)}, 9662306a36Sopenharmony_ci {"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)}, 9762306a36Sopenharmony_ci {"rx_fcoe_packets", IXGBE_STAT(stats.fcoeprc)}, 9862306a36Sopenharmony_ci {"rx_fcoe_dwords", IXGBE_STAT(stats.fcoedwrc)}, 9962306a36Sopenharmony_ci {"fcoe_noddp", IXGBE_STAT(stats.fcoe_noddp)}, 10062306a36Sopenharmony_ci {"fcoe_noddp_ext_buff", IXGBE_STAT(stats.fcoe_noddp_ext_buff)}, 10162306a36Sopenharmony_ci {"tx_fcoe_packets", IXGBE_STAT(stats.fcoeptc)}, 10262306a36Sopenharmony_ci {"tx_fcoe_dwords", IXGBE_STAT(stats.fcoedwtc)}, 10362306a36Sopenharmony_ci#endif /* IXGBE_FCOE */ 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* ixgbe allocates num_tx_queues and num_rx_queues symmetrically so 10762306a36Sopenharmony_ci * we set the num_rx_queues to evaluate to num_tx_queues. This is 10862306a36Sopenharmony_ci * used because we do not have a good way to get the max number of 10962306a36Sopenharmony_ci * rx queues with CONFIG_RPS disabled. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci#define IXGBE_NUM_RX_QUEUES netdev->num_tx_queues 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define IXGBE_QUEUE_STATS_LEN ( \ 11462306a36Sopenharmony_ci (netdev->num_tx_queues + IXGBE_NUM_RX_QUEUES) * \ 11562306a36Sopenharmony_ci (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) 11662306a36Sopenharmony_ci#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) 11762306a36Sopenharmony_ci#define IXGBE_PB_STATS_LEN ( \ 11862306a36Sopenharmony_ci (sizeof(((struct ixgbe_adapter *)0)->stats.pxonrxc) + \ 11962306a36Sopenharmony_ci sizeof(((struct ixgbe_adapter *)0)->stats.pxontxc) + \ 12062306a36Sopenharmony_ci sizeof(((struct ixgbe_adapter *)0)->stats.pxoffrxc) + \ 12162306a36Sopenharmony_ci sizeof(((struct ixgbe_adapter *)0)->stats.pxofftxc)) \ 12262306a36Sopenharmony_ci / sizeof(u64)) 12362306a36Sopenharmony_ci#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + \ 12462306a36Sopenharmony_ci IXGBE_PB_STATS_LEN + \ 12562306a36Sopenharmony_ci IXGBE_QUEUE_STATS_LEN) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { 12862306a36Sopenharmony_ci "Register test (offline)", "Eeprom test (offline)", 12962306a36Sopenharmony_ci "Interrupt test (offline)", "Loopback test (offline)", 13062306a36Sopenharmony_ci "Link test (on/offline)" 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci#define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic const char ixgbe_priv_flags_strings[][ETH_GSTRING_LEN] = { 13562306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_LEGACY_RX BIT(0) 13662306a36Sopenharmony_ci "legacy-rx", 13762306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_VF_IPSEC_EN BIT(1) 13862306a36Sopenharmony_ci "vf-ipsec", 13962306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF BIT(2) 14062306a36Sopenharmony_ci "mdd-disable-vf", 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define IXGBE_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbe_priv_flags_strings) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define ixgbe_isbackplane(type) ((type) == ixgbe_media_type_backplane) 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic void ixgbe_set_supported_10gtypes(struct ixgbe_hw *hw, 14862306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci if (!ixgbe_isbackplane(hw->phy.media_type)) { 15162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 15262306a36Sopenharmony_ci 10000baseT_Full); 15362306a36Sopenharmony_ci return; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci switch (hw->device_id) { 15762306a36Sopenharmony_ci case IXGBE_DEV_ID_82598: 15862306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KX4: 15962306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KX4_MEZZ: 16062306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_X_KX4: 16162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 16262306a36Sopenharmony_ci (cmd, supported, 10000baseKX4_Full); 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci case IXGBE_DEV_ID_82598_BX: 16562306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KR: 16662306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_X_KR: 16762306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_X_XFI: 16862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 16962306a36Sopenharmony_ci (cmd, supported, 10000baseKR_Full); 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci default: 17262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 17362306a36Sopenharmony_ci (cmd, supported, 10000baseKX4_Full); 17462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 17562306a36Sopenharmony_ci (cmd, supported, 10000baseKR_Full); 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void ixgbe_set_advertising_10gtypes(struct ixgbe_hw *hw, 18162306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci if (!ixgbe_isbackplane(hw->phy.media_type)) { 18462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 18562306a36Sopenharmony_ci 10000baseT_Full); 18662306a36Sopenharmony_ci return; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci switch (hw->device_id) { 19062306a36Sopenharmony_ci case IXGBE_DEV_ID_82598: 19162306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KX4: 19262306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KX4_MEZZ: 19362306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_X_KX4: 19462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 19562306a36Sopenharmony_ci (cmd, advertising, 10000baseKX4_Full); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci case IXGBE_DEV_ID_82598_BX: 19862306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KR: 19962306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_X_KR: 20062306a36Sopenharmony_ci case IXGBE_DEV_ID_X550EM_X_XFI: 20162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 20262306a36Sopenharmony_ci (cmd, advertising, 10000baseKR_Full); 20362306a36Sopenharmony_ci break; 20462306a36Sopenharmony_ci default: 20562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 20662306a36Sopenharmony_ci (cmd, advertising, 10000baseKX4_Full); 20762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 20862306a36Sopenharmony_ci (cmd, advertising, 10000baseKR_Full); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int ixgbe_get_link_ksettings(struct net_device *netdev, 21462306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 21762306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 21862306a36Sopenharmony_ci ixgbe_link_speed supported_link; 21962306a36Sopenharmony_ci bool autoneg = false; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 22262306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, advertising); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci hw->mac.ops.get_link_capabilities(hw, &supported_link, &autoneg); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* set the supported link speeds */ 22762306a36Sopenharmony_ci if (supported_link & IXGBE_LINK_SPEED_10GB_FULL) { 22862306a36Sopenharmony_ci ixgbe_set_supported_10gtypes(hw, cmd); 22962306a36Sopenharmony_ci ixgbe_set_advertising_10gtypes(hw, cmd); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci if (supported_link & IXGBE_LINK_SPEED_5GB_FULL) 23262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 23362306a36Sopenharmony_ci 5000baseT_Full); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (supported_link & IXGBE_LINK_SPEED_2_5GB_FULL) 23662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 23762306a36Sopenharmony_ci 2500baseT_Full); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (supported_link & IXGBE_LINK_SPEED_1GB_FULL) { 24062306a36Sopenharmony_ci if (ixgbe_isbackplane(hw->phy.media_type)) { 24162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 24262306a36Sopenharmony_ci 1000baseKX_Full); 24362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 24462306a36Sopenharmony_ci 1000baseKX_Full); 24562306a36Sopenharmony_ci } else { 24662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 24762306a36Sopenharmony_ci 1000baseT_Full); 24862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 24962306a36Sopenharmony_ci 1000baseT_Full); 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci if (supported_link & IXGBE_LINK_SPEED_100_FULL) { 25362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 25462306a36Sopenharmony_ci 100baseT_Full); 25562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 25662306a36Sopenharmony_ci 100baseT_Full); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci if (supported_link & IXGBE_LINK_SPEED_10_FULL) { 25962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 26062306a36Sopenharmony_ci 10baseT_Full); 26162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 26262306a36Sopenharmony_ci 10baseT_Full); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* set the advertised speeds */ 26662306a36Sopenharmony_ci if (hw->phy.autoneg_advertised) { 26762306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, advertising); 26862306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL) 26962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 27062306a36Sopenharmony_ci 10baseT_Full); 27162306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) 27262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 27362306a36Sopenharmony_ci 100baseT_Full); 27462306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) 27562306a36Sopenharmony_ci ixgbe_set_advertising_10gtypes(hw, cmd); 27662306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) { 27762306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode 27862306a36Sopenharmony_ci (cmd, supported, 1000baseKX_Full)) 27962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 28062306a36Sopenharmony_ci (cmd, advertising, 1000baseKX_Full); 28162306a36Sopenharmony_ci else 28262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 28362306a36Sopenharmony_ci (cmd, advertising, 1000baseT_Full); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) 28662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 28762306a36Sopenharmony_ci 5000baseT_Full); 28862306a36Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) 28962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 29062306a36Sopenharmony_ci 2500baseT_Full); 29162306a36Sopenharmony_ci } else { 29262306a36Sopenharmony_ci if (hw->phy.multispeed_fiber && !autoneg) { 29362306a36Sopenharmony_ci if (supported_link & IXGBE_LINK_SPEED_10GB_FULL) 29462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode 29562306a36Sopenharmony_ci (cmd, advertising, 10000baseT_Full); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (autoneg) { 30062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); 30162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); 30262306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 30362306a36Sopenharmony_ci } else 30462306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Determine the remaining settings based on the PHY type. */ 30762306a36Sopenharmony_ci switch (adapter->hw.phy.type) { 30862306a36Sopenharmony_ci case ixgbe_phy_tn: 30962306a36Sopenharmony_ci case ixgbe_phy_aq: 31062306a36Sopenharmony_ci case ixgbe_phy_x550em_ext_t: 31162306a36Sopenharmony_ci case ixgbe_phy_fw: 31262306a36Sopenharmony_ci case ixgbe_phy_cu_unknown: 31362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, TP); 31462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); 31562306a36Sopenharmony_ci cmd->base.port = PORT_TP; 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci case ixgbe_phy_qt: 31862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 31962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); 32062306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci case ixgbe_phy_nl: 32362306a36Sopenharmony_ci case ixgbe_phy_sfp_passive_tyco: 32462306a36Sopenharmony_ci case ixgbe_phy_sfp_passive_unknown: 32562306a36Sopenharmony_ci case ixgbe_phy_sfp_ftl: 32662306a36Sopenharmony_ci case ixgbe_phy_sfp_avago: 32762306a36Sopenharmony_ci case ixgbe_phy_sfp_intel: 32862306a36Sopenharmony_ci case ixgbe_phy_sfp_unknown: 32962306a36Sopenharmony_ci case ixgbe_phy_qsfp_passive_unknown: 33062306a36Sopenharmony_ci case ixgbe_phy_qsfp_active_unknown: 33162306a36Sopenharmony_ci case ixgbe_phy_qsfp_intel: 33262306a36Sopenharmony_ci case ixgbe_phy_qsfp_unknown: 33362306a36Sopenharmony_ci /* SFP+ devices, further checking needed */ 33462306a36Sopenharmony_ci switch (adapter->hw.phy.sfp_type) { 33562306a36Sopenharmony_ci case ixgbe_sfp_type_da_cu: 33662306a36Sopenharmony_ci case ixgbe_sfp_type_da_cu_core0: 33762306a36Sopenharmony_ci case ixgbe_sfp_type_da_cu_core1: 33862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 33962306a36Sopenharmony_ci FIBRE); 34062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 34162306a36Sopenharmony_ci FIBRE); 34262306a36Sopenharmony_ci cmd->base.port = PORT_DA; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci case ixgbe_sfp_type_sr: 34562306a36Sopenharmony_ci case ixgbe_sfp_type_lr: 34662306a36Sopenharmony_ci case ixgbe_sfp_type_srlr_core0: 34762306a36Sopenharmony_ci case ixgbe_sfp_type_srlr_core1: 34862306a36Sopenharmony_ci case ixgbe_sfp_type_1g_sx_core0: 34962306a36Sopenharmony_ci case ixgbe_sfp_type_1g_sx_core1: 35062306a36Sopenharmony_ci case ixgbe_sfp_type_1g_lx_core0: 35162306a36Sopenharmony_ci case ixgbe_sfp_type_1g_lx_core1: 35262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 35362306a36Sopenharmony_ci FIBRE); 35462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 35562306a36Sopenharmony_ci FIBRE); 35662306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci case ixgbe_sfp_type_not_present: 35962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 36062306a36Sopenharmony_ci FIBRE); 36162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 36262306a36Sopenharmony_ci FIBRE); 36362306a36Sopenharmony_ci cmd->base.port = PORT_NONE; 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case ixgbe_sfp_type_1g_cu_core0: 36662306a36Sopenharmony_ci case ixgbe_sfp_type_1g_cu_core1: 36762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 36862306a36Sopenharmony_ci TP); 36962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 37062306a36Sopenharmony_ci TP); 37162306a36Sopenharmony_ci cmd->base.port = PORT_TP; 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case ixgbe_sfp_type_unknown: 37462306a36Sopenharmony_ci default: 37562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 37662306a36Sopenharmony_ci FIBRE); 37762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 37862306a36Sopenharmony_ci FIBRE); 37962306a36Sopenharmony_ci cmd->base.port = PORT_OTHER; 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case ixgbe_phy_xaui: 38462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 38562306a36Sopenharmony_ci FIBRE); 38662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 38762306a36Sopenharmony_ci FIBRE); 38862306a36Sopenharmony_ci cmd->base.port = PORT_NONE; 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci case ixgbe_phy_unknown: 39162306a36Sopenharmony_ci case ixgbe_phy_generic: 39262306a36Sopenharmony_ci case ixgbe_phy_sfp_unsupported: 39362306a36Sopenharmony_ci default: 39462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 39562306a36Sopenharmony_ci FIBRE); 39662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 39762306a36Sopenharmony_ci FIBRE); 39862306a36Sopenharmony_ci cmd->base.port = PORT_OTHER; 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* Indicate pause support */ 40362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci switch (hw->fc.requested_mode) { 40662306a36Sopenharmony_ci case ixgbe_fc_full: 40762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci case ixgbe_fc_rx_pause: 41062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); 41162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 41262306a36Sopenharmony_ci Asym_Pause); 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci case ixgbe_fc_tx_pause: 41562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 41662306a36Sopenharmony_ci Asym_Pause); 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci default: 41962306a36Sopenharmony_ci ethtool_link_ksettings_del_link_mode(cmd, advertising, Pause); 42062306a36Sopenharmony_ci ethtool_link_ksettings_del_link_mode(cmd, advertising, 42162306a36Sopenharmony_ci Asym_Pause); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) { 42562306a36Sopenharmony_ci switch (adapter->link_speed) { 42662306a36Sopenharmony_ci case IXGBE_LINK_SPEED_10GB_FULL: 42762306a36Sopenharmony_ci cmd->base.speed = SPEED_10000; 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci case IXGBE_LINK_SPEED_5GB_FULL: 43062306a36Sopenharmony_ci cmd->base.speed = SPEED_5000; 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci case IXGBE_LINK_SPEED_2_5GB_FULL: 43362306a36Sopenharmony_ci cmd->base.speed = SPEED_2500; 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci case IXGBE_LINK_SPEED_1GB_FULL: 43662306a36Sopenharmony_ci cmd->base.speed = SPEED_1000; 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci case IXGBE_LINK_SPEED_100_FULL: 43962306a36Sopenharmony_ci cmd->base.speed = SPEED_100; 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci case IXGBE_LINK_SPEED_10_FULL: 44262306a36Sopenharmony_ci cmd->base.speed = SPEED_10; 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci default: 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 44862306a36Sopenharmony_ci } else { 44962306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 45062306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int ixgbe_set_link_ksettings(struct net_device *netdev, 45762306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 46062306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 46162306a36Sopenharmony_ci u32 advertised, old; 46262306a36Sopenharmony_ci s32 err = 0; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if ((hw->phy.media_type == ixgbe_media_type_copper) || 46562306a36Sopenharmony_ci (hw->phy.multispeed_fiber)) { 46662306a36Sopenharmony_ci /* 46762306a36Sopenharmony_ci * this function does not support duplex forcing, but can 46862306a36Sopenharmony_ci * limit the advertising of the adapter to the specified speed 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci if (!linkmode_subset(cmd->link_modes.advertising, 47162306a36Sopenharmony_ci cmd->link_modes.supported)) 47262306a36Sopenharmony_ci return -EINVAL; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* only allow one speed at a time if no autoneg */ 47562306a36Sopenharmony_ci if (!cmd->base.autoneg && hw->phy.multispeed_fiber) { 47662306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 47762306a36Sopenharmony_ci 10000baseT_Full) && 47862306a36Sopenharmony_ci ethtool_link_ksettings_test_link_mode(cmd, advertising, 47962306a36Sopenharmony_ci 1000baseT_Full)) 48062306a36Sopenharmony_ci return -EINVAL; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci old = hw->phy.autoneg_advertised; 48462306a36Sopenharmony_ci advertised = 0; 48562306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 48662306a36Sopenharmony_ci 10000baseT_Full)) 48762306a36Sopenharmony_ci advertised |= IXGBE_LINK_SPEED_10GB_FULL; 48862306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 48962306a36Sopenharmony_ci 5000baseT_Full)) 49062306a36Sopenharmony_ci advertised |= IXGBE_LINK_SPEED_5GB_FULL; 49162306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 49262306a36Sopenharmony_ci 2500baseT_Full)) 49362306a36Sopenharmony_ci advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; 49462306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 49562306a36Sopenharmony_ci 1000baseT_Full)) 49662306a36Sopenharmony_ci advertised |= IXGBE_LINK_SPEED_1GB_FULL; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 49962306a36Sopenharmony_ci 100baseT_Full)) 50062306a36Sopenharmony_ci advertised |= IXGBE_LINK_SPEED_100_FULL; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 50362306a36Sopenharmony_ci 10baseT_Full)) 50462306a36Sopenharmony_ci advertised |= IXGBE_LINK_SPEED_10_FULL; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (old == advertised) 50762306a36Sopenharmony_ci return err; 50862306a36Sopenharmony_ci /* this sets the link speed and restarts auto-neg */ 50962306a36Sopenharmony_ci while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) 51062306a36Sopenharmony_ci usleep_range(1000, 2000); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci hw->mac.autotry_restart = true; 51362306a36Sopenharmony_ci err = hw->mac.ops.setup_link(hw, advertised, true); 51462306a36Sopenharmony_ci if (err) { 51562306a36Sopenharmony_ci e_info(probe, "setup link failed with code %d\n", err); 51662306a36Sopenharmony_ci hw->mac.ops.setup_link(hw, old, true); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); 51962306a36Sopenharmony_ci } else { 52062306a36Sopenharmony_ci /* in this case we currently only support 10Gb/FULL */ 52162306a36Sopenharmony_ci u32 speed = cmd->base.speed; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if ((cmd->base.autoneg == AUTONEG_ENABLE) || 52462306a36Sopenharmony_ci (!ethtool_link_ksettings_test_link_mode(cmd, advertising, 52562306a36Sopenharmony_ci 10000baseT_Full)) || 52662306a36Sopenharmony_ci (speed + cmd->base.duplex != SPEED_10000 + DUPLEX_FULL)) 52762306a36Sopenharmony_ci return -EINVAL; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return err; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic void ixgbe_get_pause_stats(struct net_device *netdev, 53462306a36Sopenharmony_ci struct ethtool_pause_stats *stats) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 53762306a36Sopenharmony_ci struct ixgbe_hw_stats *hwstats = &adapter->stats; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci stats->tx_pause_frames = hwstats->lxontxc + hwstats->lxofftxc; 54062306a36Sopenharmony_ci stats->rx_pause_frames = hwstats->lxonrxc + hwstats->lxoffrxc; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic void ixgbe_get_pauseparam(struct net_device *netdev, 54462306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 54762306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (ixgbe_device_supports_autoneg_fc(hw) && 55062306a36Sopenharmony_ci !hw->fc.disable_fc_autoneg) 55162306a36Sopenharmony_ci pause->autoneg = 1; 55262306a36Sopenharmony_ci else 55362306a36Sopenharmony_ci pause->autoneg = 0; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (hw->fc.current_mode == ixgbe_fc_rx_pause) { 55662306a36Sopenharmony_ci pause->rx_pause = 1; 55762306a36Sopenharmony_ci } else if (hw->fc.current_mode == ixgbe_fc_tx_pause) { 55862306a36Sopenharmony_ci pause->tx_pause = 1; 55962306a36Sopenharmony_ci } else if (hw->fc.current_mode == ixgbe_fc_full) { 56062306a36Sopenharmony_ci pause->rx_pause = 1; 56162306a36Sopenharmony_ci pause->tx_pause = 1; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int ixgbe_set_pauseparam(struct net_device *netdev, 56662306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 56962306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 57062306a36Sopenharmony_ci struct ixgbe_fc_info fc = hw->fc; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* 82598 does no support link flow control with DCB enabled */ 57362306a36Sopenharmony_ci if ((hw->mac.type == ixgbe_mac_82598EB) && 57462306a36Sopenharmony_ci (adapter->flags & IXGBE_FLAG_DCB_ENABLED)) 57562306a36Sopenharmony_ci return -EINVAL; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* some devices do not support autoneg of link flow control */ 57862306a36Sopenharmony_ci if ((pause->autoneg == AUTONEG_ENABLE) && 57962306a36Sopenharmony_ci !ixgbe_device_supports_autoneg_fc(hw)) 58062306a36Sopenharmony_ci return -EINVAL; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci fc.disable_fc_autoneg = (pause->autoneg != AUTONEG_ENABLE); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if ((pause->rx_pause && pause->tx_pause) || pause->autoneg) 58562306a36Sopenharmony_ci fc.requested_mode = ixgbe_fc_full; 58662306a36Sopenharmony_ci else if (pause->rx_pause && !pause->tx_pause) 58762306a36Sopenharmony_ci fc.requested_mode = ixgbe_fc_rx_pause; 58862306a36Sopenharmony_ci else if (!pause->rx_pause && pause->tx_pause) 58962306a36Sopenharmony_ci fc.requested_mode = ixgbe_fc_tx_pause; 59062306a36Sopenharmony_ci else 59162306a36Sopenharmony_ci fc.requested_mode = ixgbe_fc_none; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* if the thing changed then we'll update and use new autoneg */ 59462306a36Sopenharmony_ci if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) { 59562306a36Sopenharmony_ci hw->fc = fc; 59662306a36Sopenharmony_ci if (netif_running(netdev)) 59762306a36Sopenharmony_ci ixgbe_reinit_locked(adapter); 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci ixgbe_reset(adapter); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic u32 ixgbe_get_msglevel(struct net_device *netdev) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 60862306a36Sopenharmony_ci return adapter->msg_enable; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic void ixgbe_set_msglevel(struct net_device *netdev, u32 data) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 61462306a36Sopenharmony_ci adapter->msg_enable = data; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int ixgbe_get_regs_len(struct net_device *netdev) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci#define IXGBE_REGS_LEN 1145 62062306a36Sopenharmony_ci return IXGBE_REGS_LEN * sizeof(u32); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_ 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void ixgbe_get_regs(struct net_device *netdev, 62662306a36Sopenharmony_ci struct ethtool_regs *regs, void *p) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 62962306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 63062306a36Sopenharmony_ci u32 *regs_buff = p; 63162306a36Sopenharmony_ci u8 i; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci memset(p, 0, IXGBE_REGS_LEN * sizeof(u32)); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci regs->version = hw->mac.type << 24 | hw->revision_id << 16 | 63662306a36Sopenharmony_ci hw->device_id; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* General Registers */ 63962306a36Sopenharmony_ci regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL); 64062306a36Sopenharmony_ci regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS); 64162306a36Sopenharmony_ci regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 64262306a36Sopenharmony_ci regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP); 64362306a36Sopenharmony_ci regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP); 64462306a36Sopenharmony_ci regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL); 64562306a36Sopenharmony_ci regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER); 64662306a36Sopenharmony_ci regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* NVM Register */ 64962306a36Sopenharmony_ci regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 65062306a36Sopenharmony_ci regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD); 65162306a36Sopenharmony_ci regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA(hw)); 65262306a36Sopenharmony_ci regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL); 65362306a36Sopenharmony_ci regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA); 65462306a36Sopenharmony_ci regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL); 65562306a36Sopenharmony_ci regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA); 65662306a36Sopenharmony_ci regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT); 65762306a36Sopenharmony_ci regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP); 65862306a36Sopenharmony_ci regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC(hw)); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* Interrupt */ 66162306a36Sopenharmony_ci /* don't read EICR because it can clear interrupt causes, instead 66262306a36Sopenharmony_ci * read EICS which is a shadow but doesn't clear EICR */ 66362306a36Sopenharmony_ci regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICS); 66462306a36Sopenharmony_ci regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS); 66562306a36Sopenharmony_ci regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS); 66662306a36Sopenharmony_ci regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC); 66762306a36Sopenharmony_ci regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC); 66862306a36Sopenharmony_ci regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM); 66962306a36Sopenharmony_ci regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0)); 67062306a36Sopenharmony_ci regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0)); 67162306a36Sopenharmony_ci regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT); 67262306a36Sopenharmony_ci regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA); 67362306a36Sopenharmony_ci regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL(0)); 67462306a36Sopenharmony_ci regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Flow Control */ 67762306a36Sopenharmony_ci regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP); 67862306a36Sopenharmony_ci for (i = 0; i < 4; i++) 67962306a36Sopenharmony_ci regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_FCTTV(i)); 68062306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 68162306a36Sopenharmony_ci switch (hw->mac.type) { 68262306a36Sopenharmony_ci case ixgbe_mac_82598EB: 68362306a36Sopenharmony_ci regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i)); 68462306a36Sopenharmony_ci regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i)); 68562306a36Sopenharmony_ci break; 68662306a36Sopenharmony_ci case ixgbe_mac_82599EB: 68762306a36Sopenharmony_ci case ixgbe_mac_X540: 68862306a36Sopenharmony_ci case ixgbe_mac_X550: 68962306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 69062306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 69162306a36Sopenharmony_ci regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i)); 69262306a36Sopenharmony_ci regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i)); 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci default: 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV); 69962306a36Sopenharmony_ci regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* Receive DMA */ 70262306a36Sopenharmony_ci for (i = 0; i < 64; i++) 70362306a36Sopenharmony_ci regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i)); 70462306a36Sopenharmony_ci for (i = 0; i < 64; i++) 70562306a36Sopenharmony_ci regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i)); 70662306a36Sopenharmony_ci for (i = 0; i < 64; i++) 70762306a36Sopenharmony_ci regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i)); 70862306a36Sopenharmony_ci for (i = 0; i < 64; i++) 70962306a36Sopenharmony_ci regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i)); 71062306a36Sopenharmony_ci for (i = 0; i < 64; i++) 71162306a36Sopenharmony_ci regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i)); 71262306a36Sopenharmony_ci for (i = 0; i < 64; i++) 71362306a36Sopenharmony_ci regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); 71462306a36Sopenharmony_ci for (i = 0; i < 16; i++) 71562306a36Sopenharmony_ci regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); 71662306a36Sopenharmony_ci for (i = 0; i < 16; i++) 71762306a36Sopenharmony_ci regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); 71862306a36Sopenharmony_ci regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 71962306a36Sopenharmony_ci for (i = 0; i < 8; i++) 72062306a36Sopenharmony_ci regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)); 72162306a36Sopenharmony_ci regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 72262306a36Sopenharmony_ci regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Receive */ 72562306a36Sopenharmony_ci regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 72662306a36Sopenharmony_ci regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL); 72762306a36Sopenharmony_ci for (i = 0; i < 16; i++) 72862306a36Sopenharmony_ci regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i)); 72962306a36Sopenharmony_ci for (i = 0; i < 16; i++) 73062306a36Sopenharmony_ci regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i)); 73162306a36Sopenharmony_ci regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0)); 73262306a36Sopenharmony_ci regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL); 73362306a36Sopenharmony_ci regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); 73462306a36Sopenharmony_ci regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL); 73562306a36Sopenharmony_ci regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC); 73662306a36Sopenharmony_ci regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL); 73762306a36Sopenharmony_ci for (i = 0; i < 8; i++) 73862306a36Sopenharmony_ci regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i)); 73962306a36Sopenharmony_ci for (i = 0; i < 8; i++) 74062306a36Sopenharmony_ci regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i)); 74162306a36Sopenharmony_ci regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* Transmit */ 74462306a36Sopenharmony_ci for (i = 0; i < 32; i++) 74562306a36Sopenharmony_ci regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i)); 74662306a36Sopenharmony_ci for (i = 0; i < 32; i++) 74762306a36Sopenharmony_ci regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i)); 74862306a36Sopenharmony_ci for (i = 0; i < 32; i++) 74962306a36Sopenharmony_ci regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i)); 75062306a36Sopenharmony_ci for (i = 0; i < 32; i++) 75162306a36Sopenharmony_ci regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i)); 75262306a36Sopenharmony_ci for (i = 0; i < 32; i++) 75362306a36Sopenharmony_ci regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i)); 75462306a36Sopenharmony_ci for (i = 0; i < 32; i++) 75562306a36Sopenharmony_ci regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); 75662306a36Sopenharmony_ci for (i = 0; i < 32; i++) 75762306a36Sopenharmony_ci regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i)); 75862306a36Sopenharmony_ci for (i = 0; i < 32; i++) 75962306a36Sopenharmony_ci regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i)); 76062306a36Sopenharmony_ci regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL); 76162306a36Sopenharmony_ci for (i = 0; i < 16; i++) 76262306a36Sopenharmony_ci regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); 76362306a36Sopenharmony_ci regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG); 76462306a36Sopenharmony_ci for (i = 0; i < 8; i++) 76562306a36Sopenharmony_ci regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i)); 76662306a36Sopenharmony_ci regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* Wake Up */ 76962306a36Sopenharmony_ci regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC); 77062306a36Sopenharmony_ci regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC); 77162306a36Sopenharmony_ci regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS); 77262306a36Sopenharmony_ci regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV); 77362306a36Sopenharmony_ci regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT); 77462306a36Sopenharmony_ci regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT); 77562306a36Sopenharmony_ci regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL); 77662306a36Sopenharmony_ci regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM); 77762306a36Sopenharmony_ci regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT(0)); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* DCB */ 78062306a36Sopenharmony_ci regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS); /* same as FCCFG */ 78162306a36Sopenharmony_ci regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS); /* same as RTTPCS */ 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci switch (hw->mac.type) { 78462306a36Sopenharmony_ci case ixgbe_mac_82598EB: 78562306a36Sopenharmony_ci regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS); 78662306a36Sopenharmony_ci regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR); 78762306a36Sopenharmony_ci for (i = 0; i < 8; i++) 78862306a36Sopenharmony_ci regs_buff[833 + i] = 78962306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RT2CR(i)); 79062306a36Sopenharmony_ci for (i = 0; i < 8; i++) 79162306a36Sopenharmony_ci regs_buff[841 + i] = 79262306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RT2SR(i)); 79362306a36Sopenharmony_ci for (i = 0; i < 8; i++) 79462306a36Sopenharmony_ci regs_buff[849 + i] = 79562306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i)); 79662306a36Sopenharmony_ci for (i = 0; i < 8; i++) 79762306a36Sopenharmony_ci regs_buff[857 + i] = 79862306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i)); 79962306a36Sopenharmony_ci break; 80062306a36Sopenharmony_ci case ixgbe_mac_82599EB: 80162306a36Sopenharmony_ci case ixgbe_mac_X540: 80262306a36Sopenharmony_ci case ixgbe_mac_X550: 80362306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 80462306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 80562306a36Sopenharmony_ci regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_RTTDCS); 80662306a36Sopenharmony_ci regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RTRPCS); 80762306a36Sopenharmony_ci for (i = 0; i < 8; i++) 80862306a36Sopenharmony_ci regs_buff[833 + i] = 80962306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RTRPT4C(i)); 81062306a36Sopenharmony_ci for (i = 0; i < 8; i++) 81162306a36Sopenharmony_ci regs_buff[841 + i] = 81262306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RTRPT4S(i)); 81362306a36Sopenharmony_ci for (i = 0; i < 8; i++) 81462306a36Sopenharmony_ci regs_buff[849 + i] = 81562306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RTTDT2C(i)); 81662306a36Sopenharmony_ci for (i = 0; i < 8; i++) 81762306a36Sopenharmony_ci regs_buff[857 + i] = 81862306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RTTDT2S(i)); 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci default: 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci for (i = 0; i < 8; i++) 82562306a36Sopenharmony_ci regs_buff[865 + i] = 82662306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i)); /* same as RTTPT2C */ 82762306a36Sopenharmony_ci for (i = 0; i < 8; i++) 82862306a36Sopenharmony_ci regs_buff[873 + i] = 82962306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i)); /* same as RTTPT2S */ 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Statistics */ 83262306a36Sopenharmony_ci regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs); 83362306a36Sopenharmony_ci regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc); 83462306a36Sopenharmony_ci regs_buff[883] = IXGBE_GET_STAT(adapter, errbc); 83562306a36Sopenharmony_ci regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc); 83662306a36Sopenharmony_ci for (i = 0; i < 8; i++) 83762306a36Sopenharmony_ci regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]); 83862306a36Sopenharmony_ci regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc); 83962306a36Sopenharmony_ci regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc); 84062306a36Sopenharmony_ci regs_buff[895] = IXGBE_GET_STAT(adapter, rlec); 84162306a36Sopenharmony_ci regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc); 84262306a36Sopenharmony_ci regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc); 84362306a36Sopenharmony_ci regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc); 84462306a36Sopenharmony_ci regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc); 84562306a36Sopenharmony_ci for (i = 0; i < 8; i++) 84662306a36Sopenharmony_ci regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]); 84762306a36Sopenharmony_ci for (i = 0; i < 8; i++) 84862306a36Sopenharmony_ci regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]); 84962306a36Sopenharmony_ci for (i = 0; i < 8; i++) 85062306a36Sopenharmony_ci regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]); 85162306a36Sopenharmony_ci for (i = 0; i < 8; i++) 85262306a36Sopenharmony_ci regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]); 85362306a36Sopenharmony_ci regs_buff[932] = IXGBE_GET_STAT(adapter, prc64); 85462306a36Sopenharmony_ci regs_buff[933] = IXGBE_GET_STAT(adapter, prc127); 85562306a36Sopenharmony_ci regs_buff[934] = IXGBE_GET_STAT(adapter, prc255); 85662306a36Sopenharmony_ci regs_buff[935] = IXGBE_GET_STAT(adapter, prc511); 85762306a36Sopenharmony_ci regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023); 85862306a36Sopenharmony_ci regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522); 85962306a36Sopenharmony_ci regs_buff[938] = IXGBE_GET_STAT(adapter, gprc); 86062306a36Sopenharmony_ci regs_buff[939] = IXGBE_GET_STAT(adapter, bprc); 86162306a36Sopenharmony_ci regs_buff[940] = IXGBE_GET_STAT(adapter, mprc); 86262306a36Sopenharmony_ci regs_buff[941] = IXGBE_GET_STAT(adapter, gptc); 86362306a36Sopenharmony_ci regs_buff[942] = (u32)IXGBE_GET_STAT(adapter, gorc); 86462306a36Sopenharmony_ci regs_buff[943] = (u32)(IXGBE_GET_STAT(adapter, gorc) >> 32); 86562306a36Sopenharmony_ci regs_buff[944] = (u32)IXGBE_GET_STAT(adapter, gotc); 86662306a36Sopenharmony_ci regs_buff[945] = (u32)(IXGBE_GET_STAT(adapter, gotc) >> 32); 86762306a36Sopenharmony_ci for (i = 0; i < 8; i++) 86862306a36Sopenharmony_ci regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]); 86962306a36Sopenharmony_ci regs_buff[954] = IXGBE_GET_STAT(adapter, ruc); 87062306a36Sopenharmony_ci regs_buff[955] = IXGBE_GET_STAT(adapter, rfc); 87162306a36Sopenharmony_ci regs_buff[956] = IXGBE_GET_STAT(adapter, roc); 87262306a36Sopenharmony_ci regs_buff[957] = IXGBE_GET_STAT(adapter, rjc); 87362306a36Sopenharmony_ci regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc); 87462306a36Sopenharmony_ci regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc); 87562306a36Sopenharmony_ci regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc); 87662306a36Sopenharmony_ci regs_buff[961] = (u32)IXGBE_GET_STAT(adapter, tor); 87762306a36Sopenharmony_ci regs_buff[962] = (u32)(IXGBE_GET_STAT(adapter, tor) >> 32); 87862306a36Sopenharmony_ci regs_buff[963] = IXGBE_GET_STAT(adapter, tpr); 87962306a36Sopenharmony_ci regs_buff[964] = IXGBE_GET_STAT(adapter, tpt); 88062306a36Sopenharmony_ci regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64); 88162306a36Sopenharmony_ci regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127); 88262306a36Sopenharmony_ci regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255); 88362306a36Sopenharmony_ci regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511); 88462306a36Sopenharmony_ci regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023); 88562306a36Sopenharmony_ci regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522); 88662306a36Sopenharmony_ci regs_buff[971] = IXGBE_GET_STAT(adapter, mptc); 88762306a36Sopenharmony_ci regs_buff[972] = IXGBE_GET_STAT(adapter, bptc); 88862306a36Sopenharmony_ci regs_buff[973] = IXGBE_GET_STAT(adapter, xec); 88962306a36Sopenharmony_ci for (i = 0; i < 16; i++) 89062306a36Sopenharmony_ci regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]); 89162306a36Sopenharmony_ci for (i = 0; i < 16; i++) 89262306a36Sopenharmony_ci regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]); 89362306a36Sopenharmony_ci for (i = 0; i < 16; i++) 89462306a36Sopenharmony_ci regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]); 89562306a36Sopenharmony_ci for (i = 0; i < 16; i++) 89662306a36Sopenharmony_ci regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci /* MAC */ 89962306a36Sopenharmony_ci regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG); 90062306a36Sopenharmony_ci regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); 90162306a36Sopenharmony_ci regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); 90262306a36Sopenharmony_ci regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0); 90362306a36Sopenharmony_ci regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1); 90462306a36Sopenharmony_ci regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); 90562306a36Sopenharmony_ci regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); 90662306a36Sopenharmony_ci regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP); 90762306a36Sopenharmony_ci regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP); 90862306a36Sopenharmony_ci regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0); 90962306a36Sopenharmony_ci regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1); 91062306a36Sopenharmony_ci regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP); 91162306a36Sopenharmony_ci regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA); 91262306a36Sopenharmony_ci regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE); 91362306a36Sopenharmony_ci regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD); 91462306a36Sopenharmony_ci regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS); 91562306a36Sopenharmony_ci regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA); 91662306a36Sopenharmony_ci regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD); 91762306a36Sopenharmony_ci regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD); 91862306a36Sopenharmony_ci regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD); 91962306a36Sopenharmony_ci regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG); 92062306a36Sopenharmony_ci regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1); 92162306a36Sopenharmony_ci regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2); 92262306a36Sopenharmony_ci regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS); 92362306a36Sopenharmony_ci regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC); 92462306a36Sopenharmony_ci regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS); 92562306a36Sopenharmony_ci regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC); 92662306a36Sopenharmony_ci regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS); 92762306a36Sopenharmony_ci regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2); 92862306a36Sopenharmony_ci regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3); 92962306a36Sopenharmony_ci regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1); 93062306a36Sopenharmony_ci regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2); 93162306a36Sopenharmony_ci regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Diagnostic */ 93462306a36Sopenharmony_ci regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL); 93562306a36Sopenharmony_ci for (i = 0; i < 8; i++) 93662306a36Sopenharmony_ci regs_buff[1072 + i] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i)); 93762306a36Sopenharmony_ci regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN); 93862306a36Sopenharmony_ci for (i = 0; i < 4; i++) 93962306a36Sopenharmony_ci regs_buff[1081 + i] = IXGBE_READ_REG(hw, IXGBE_RIC_DW(i)); 94062306a36Sopenharmony_ci regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE); 94162306a36Sopenharmony_ci regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL); 94262306a36Sopenharmony_ci for (i = 0; i < 8; i++) 94362306a36Sopenharmony_ci regs_buff[1087 + i] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i)); 94462306a36Sopenharmony_ci regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN); 94562306a36Sopenharmony_ci for (i = 0; i < 4; i++) 94662306a36Sopenharmony_ci regs_buff[1096 + i] = IXGBE_READ_REG(hw, IXGBE_TIC_DW(i)); 94762306a36Sopenharmony_ci regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE); 94862306a36Sopenharmony_ci regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL); 94962306a36Sopenharmony_ci for (i = 0; i < 4; i++) 95062306a36Sopenharmony_ci regs_buff[1102 + i] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA(i)); 95162306a36Sopenharmony_ci regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL); 95262306a36Sopenharmony_ci for (i = 0; i < 4; i++) 95362306a36Sopenharmony_ci regs_buff[1107 + i] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA(i)); 95462306a36Sopenharmony_ci for (i = 0; i < 8; i++) 95562306a36Sopenharmony_ci regs_buff[1111 + i] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i)); 95662306a36Sopenharmony_ci regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL); 95762306a36Sopenharmony_ci regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1); 95862306a36Sopenharmony_ci regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2); 95962306a36Sopenharmony_ci regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1); 96062306a36Sopenharmony_ci regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2); 96162306a36Sopenharmony_ci regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS); 96262306a36Sopenharmony_ci regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL); 96362306a36Sopenharmony_ci regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC); 96462306a36Sopenharmony_ci regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* 82599 X540 specific registers */ 96762306a36Sopenharmony_ci regs_buff[1128] = IXGBE_READ_REG(hw, IXGBE_MFLCN); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* 82599 X540 specific DCB registers */ 97062306a36Sopenharmony_ci regs_buff[1129] = IXGBE_READ_REG(hw, IXGBE_RTRUP2TC); 97162306a36Sopenharmony_ci regs_buff[1130] = IXGBE_READ_REG(hw, IXGBE_RTTUP2TC); 97262306a36Sopenharmony_ci for (i = 0; i < 4; i++) 97362306a36Sopenharmony_ci regs_buff[1131 + i] = IXGBE_READ_REG(hw, IXGBE_TXLLQ(i)); 97462306a36Sopenharmony_ci regs_buff[1135] = IXGBE_READ_REG(hw, IXGBE_RTTBCNRM); 97562306a36Sopenharmony_ci /* same as RTTQCNRM */ 97662306a36Sopenharmony_ci regs_buff[1136] = IXGBE_READ_REG(hw, IXGBE_RTTBCNRD); 97762306a36Sopenharmony_ci /* same as RTTQCNRR */ 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* X540 specific DCB registers */ 98062306a36Sopenharmony_ci regs_buff[1137] = IXGBE_READ_REG(hw, IXGBE_RTTQCNCR); 98162306a36Sopenharmony_ci regs_buff[1138] = IXGBE_READ_REG(hw, IXGBE_RTTQCNTG); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* Security config registers */ 98462306a36Sopenharmony_ci regs_buff[1139] = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL); 98562306a36Sopenharmony_ci regs_buff[1140] = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT); 98662306a36Sopenharmony_ci regs_buff[1141] = IXGBE_READ_REG(hw, IXGBE_SECTXBUFFAF); 98762306a36Sopenharmony_ci regs_buff[1142] = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG); 98862306a36Sopenharmony_ci regs_buff[1143] = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL); 98962306a36Sopenharmony_ci regs_buff[1144] = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic int ixgbe_get_eeprom_len(struct net_device *netdev) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 99562306a36Sopenharmony_ci return adapter->hw.eeprom.word_size * 2; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int ixgbe_get_eeprom(struct net_device *netdev, 99962306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *bytes) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 100262306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 100362306a36Sopenharmony_ci u16 *eeprom_buff; 100462306a36Sopenharmony_ci int first_word, last_word, eeprom_len; 100562306a36Sopenharmony_ci int ret_val = 0; 100662306a36Sopenharmony_ci u16 i; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (eeprom->len == 0) 100962306a36Sopenharmony_ci return -EINVAL; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci eeprom->magic = hw->vendor_id | (hw->device_id << 16); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci first_word = eeprom->offset >> 1; 101462306a36Sopenharmony_ci last_word = (eeprom->offset + eeprom->len - 1) >> 1; 101562306a36Sopenharmony_ci eeprom_len = last_word - first_word + 1; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci eeprom_buff = kmalloc_array(eeprom_len, sizeof(u16), GFP_KERNEL); 101862306a36Sopenharmony_ci if (!eeprom_buff) 101962306a36Sopenharmony_ci return -ENOMEM; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci ret_val = hw->eeprom.ops.read_buffer(hw, first_word, eeprom_len, 102262306a36Sopenharmony_ci eeprom_buff); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* Device's eeprom is always little-endian, word addressable */ 102562306a36Sopenharmony_ci for (i = 0; i < eeprom_len; i++) 102662306a36Sopenharmony_ci le16_to_cpus(&eeprom_buff[i]); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); 102962306a36Sopenharmony_ci kfree(eeprom_buff); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci return ret_val; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic int ixgbe_set_eeprom(struct net_device *netdev, 103562306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *bytes) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 103862306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 103962306a36Sopenharmony_ci u16 *eeprom_buff; 104062306a36Sopenharmony_ci void *ptr; 104162306a36Sopenharmony_ci int max_len, first_word, last_word, ret_val = 0; 104262306a36Sopenharmony_ci u16 i; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci if (eeprom->len == 0) 104562306a36Sopenharmony_ci return -EINVAL; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) 104862306a36Sopenharmony_ci return -EINVAL; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci max_len = hw->eeprom.word_size * 2; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci first_word = eeprom->offset >> 1; 105362306a36Sopenharmony_ci last_word = (eeprom->offset + eeprom->len - 1) >> 1; 105462306a36Sopenharmony_ci eeprom_buff = kmalloc(max_len, GFP_KERNEL); 105562306a36Sopenharmony_ci if (!eeprom_buff) 105662306a36Sopenharmony_ci return -ENOMEM; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci ptr = eeprom_buff; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (eeprom->offset & 1) { 106162306a36Sopenharmony_ci /* 106262306a36Sopenharmony_ci * need read/modify/write of first changed EEPROM word 106362306a36Sopenharmony_ci * only the second byte of the word is being modified 106462306a36Sopenharmony_ci */ 106562306a36Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, first_word, &eeprom_buff[0]); 106662306a36Sopenharmony_ci if (ret_val) 106762306a36Sopenharmony_ci goto err; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci ptr++; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci if ((eeprom->offset + eeprom->len) & 1) { 107262306a36Sopenharmony_ci /* 107362306a36Sopenharmony_ci * need read/modify/write of last changed EEPROM word 107462306a36Sopenharmony_ci * only the first byte of the word is being modified 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, last_word, 107762306a36Sopenharmony_ci &eeprom_buff[last_word - first_word]); 107862306a36Sopenharmony_ci if (ret_val) 107962306a36Sopenharmony_ci goto err; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci /* Device's eeprom is always little-endian, word addressable */ 108362306a36Sopenharmony_ci for (i = 0; i < last_word - first_word + 1; i++) 108462306a36Sopenharmony_ci le16_to_cpus(&eeprom_buff[i]); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci memcpy(ptr, bytes, eeprom->len); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci for (i = 0; i < last_word - first_word + 1; i++) 108962306a36Sopenharmony_ci cpu_to_le16s(&eeprom_buff[i]); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci ret_val = hw->eeprom.ops.write_buffer(hw, first_word, 109262306a36Sopenharmony_ci last_word - first_word + 1, 109362306a36Sopenharmony_ci eeprom_buff); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* Update the checksum */ 109662306a36Sopenharmony_ci if (ret_val == 0) 109762306a36Sopenharmony_ci hw->eeprom.ops.update_checksum(hw); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cierr: 110062306a36Sopenharmony_ci kfree(eeprom_buff); 110162306a36Sopenharmony_ci return ret_val; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic void ixgbe_get_drvinfo(struct net_device *netdev, 110562306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci strscpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver)); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci strscpy(drvinfo->fw_version, adapter->eeprom_id, 111262306a36Sopenharmony_ci sizeof(drvinfo->fw_version)); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci strscpy(drvinfo->bus_info, pci_name(adapter->pdev), 111562306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci drvinfo->n_priv_flags = IXGBE_PRIV_FLAGS_STR_LEN; 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic u32 ixgbe_get_max_rxd(struct ixgbe_adapter *adapter) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 112362306a36Sopenharmony_ci case ixgbe_mac_82598EB: 112462306a36Sopenharmony_ci return IXGBE_MAX_RXD_82598; 112562306a36Sopenharmony_ci case ixgbe_mac_82599EB: 112662306a36Sopenharmony_ci return IXGBE_MAX_RXD_82599; 112762306a36Sopenharmony_ci case ixgbe_mac_X540: 112862306a36Sopenharmony_ci return IXGBE_MAX_RXD_X540; 112962306a36Sopenharmony_ci case ixgbe_mac_X550: 113062306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 113162306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 113262306a36Sopenharmony_ci return IXGBE_MAX_RXD_X550; 113362306a36Sopenharmony_ci default: 113462306a36Sopenharmony_ci return IXGBE_MAX_RXD_82598; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic u32 ixgbe_get_max_txd(struct ixgbe_adapter *adapter) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 114162306a36Sopenharmony_ci case ixgbe_mac_82598EB: 114262306a36Sopenharmony_ci return IXGBE_MAX_TXD_82598; 114362306a36Sopenharmony_ci case ixgbe_mac_82599EB: 114462306a36Sopenharmony_ci return IXGBE_MAX_TXD_82599; 114562306a36Sopenharmony_ci case ixgbe_mac_X540: 114662306a36Sopenharmony_ci return IXGBE_MAX_TXD_X540; 114762306a36Sopenharmony_ci case ixgbe_mac_X550: 114862306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 114962306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 115062306a36Sopenharmony_ci return IXGBE_MAX_TXD_X550; 115162306a36Sopenharmony_ci default: 115262306a36Sopenharmony_ci return IXGBE_MAX_TXD_82598; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic void ixgbe_get_ringparam(struct net_device *netdev, 115762306a36Sopenharmony_ci struct ethtool_ringparam *ring, 115862306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 115962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 116262306a36Sopenharmony_ci struct ixgbe_ring *tx_ring = adapter->tx_ring[0]; 116362306a36Sopenharmony_ci struct ixgbe_ring *rx_ring = adapter->rx_ring[0]; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci ring->rx_max_pending = ixgbe_get_max_rxd(adapter); 116662306a36Sopenharmony_ci ring->tx_max_pending = ixgbe_get_max_txd(adapter); 116762306a36Sopenharmony_ci ring->rx_pending = rx_ring->count; 116862306a36Sopenharmony_ci ring->tx_pending = tx_ring->count; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic int ixgbe_set_ringparam(struct net_device *netdev, 117262306a36Sopenharmony_ci struct ethtool_ringparam *ring, 117362306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 117462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 117762306a36Sopenharmony_ci struct ixgbe_ring *temp_ring; 117862306a36Sopenharmony_ci int i, j, err = 0; 117962306a36Sopenharmony_ci u32 new_rx_count, new_tx_count; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 118262306a36Sopenharmony_ci return -EINVAL; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci new_tx_count = clamp_t(u32, ring->tx_pending, 118562306a36Sopenharmony_ci IXGBE_MIN_TXD, ixgbe_get_max_txd(adapter)); 118662306a36Sopenharmony_ci new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci new_rx_count = clamp_t(u32, ring->rx_pending, 118962306a36Sopenharmony_ci IXGBE_MIN_RXD, ixgbe_get_max_rxd(adapter)); 119062306a36Sopenharmony_ci new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if ((new_tx_count == adapter->tx_ring_count) && 119362306a36Sopenharmony_ci (new_rx_count == adapter->rx_ring_count)) { 119462306a36Sopenharmony_ci /* nothing to do */ 119562306a36Sopenharmony_ci return 0; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) 119962306a36Sopenharmony_ci usleep_range(1000, 2000); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (!netif_running(adapter->netdev)) { 120262306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) 120362306a36Sopenharmony_ci adapter->tx_ring[i]->count = new_tx_count; 120462306a36Sopenharmony_ci for (i = 0; i < adapter->num_xdp_queues; i++) 120562306a36Sopenharmony_ci adapter->xdp_ring[i]->count = new_tx_count; 120662306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) 120762306a36Sopenharmony_ci adapter->rx_ring[i]->count = new_rx_count; 120862306a36Sopenharmony_ci adapter->tx_ring_count = new_tx_count; 120962306a36Sopenharmony_ci adapter->xdp_ring_count = new_tx_count; 121062306a36Sopenharmony_ci adapter->rx_ring_count = new_rx_count; 121162306a36Sopenharmony_ci goto clear_reset; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* allocate temporary buffer to store rings in */ 121562306a36Sopenharmony_ci i = max_t(int, adapter->num_tx_queues + adapter->num_xdp_queues, 121662306a36Sopenharmony_ci adapter->num_rx_queues); 121762306a36Sopenharmony_ci temp_ring = vmalloc(array_size(i, sizeof(struct ixgbe_ring))); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci if (!temp_ring) { 122062306a36Sopenharmony_ci err = -ENOMEM; 122162306a36Sopenharmony_ci goto clear_reset; 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci ixgbe_down(adapter); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * Setup new Tx resources and free the old Tx resources in that order. 122862306a36Sopenharmony_ci * We can then assign the new resources to the rings via a memcpy. 122962306a36Sopenharmony_ci * The advantage to this approach is that we are guaranteed to still 123062306a36Sopenharmony_ci * have resources even in the case of an allocation failure. 123162306a36Sopenharmony_ci */ 123262306a36Sopenharmony_ci if (new_tx_count != adapter->tx_ring_count) { 123362306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 123462306a36Sopenharmony_ci memcpy(&temp_ring[i], adapter->tx_ring[i], 123562306a36Sopenharmony_ci sizeof(struct ixgbe_ring)); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci temp_ring[i].count = new_tx_count; 123862306a36Sopenharmony_ci err = ixgbe_setup_tx_resources(&temp_ring[i]); 123962306a36Sopenharmony_ci if (err) { 124062306a36Sopenharmony_ci while (i) { 124162306a36Sopenharmony_ci i--; 124262306a36Sopenharmony_ci ixgbe_free_tx_resources(&temp_ring[i]); 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci goto err_setup; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci for (j = 0; j < adapter->num_xdp_queues; j++, i++) { 124962306a36Sopenharmony_ci memcpy(&temp_ring[i], adapter->xdp_ring[j], 125062306a36Sopenharmony_ci sizeof(struct ixgbe_ring)); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci temp_ring[i].count = new_tx_count; 125362306a36Sopenharmony_ci err = ixgbe_setup_tx_resources(&temp_ring[i]); 125462306a36Sopenharmony_ci if (err) { 125562306a36Sopenharmony_ci while (i) { 125662306a36Sopenharmony_ci i--; 125762306a36Sopenharmony_ci ixgbe_free_tx_resources(&temp_ring[i]); 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci goto err_setup; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 126462306a36Sopenharmony_ci ixgbe_free_tx_resources(adapter->tx_ring[i]); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci memcpy(adapter->tx_ring[i], &temp_ring[i], 126762306a36Sopenharmony_ci sizeof(struct ixgbe_ring)); 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci for (j = 0; j < adapter->num_xdp_queues; j++, i++) { 127062306a36Sopenharmony_ci ixgbe_free_tx_resources(adapter->xdp_ring[j]); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci memcpy(adapter->xdp_ring[j], &temp_ring[i], 127362306a36Sopenharmony_ci sizeof(struct ixgbe_ring)); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci adapter->tx_ring_count = new_tx_count; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* Repeat the process for the Rx rings if needed */ 128062306a36Sopenharmony_ci if (new_rx_count != adapter->rx_ring_count) { 128162306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 128262306a36Sopenharmony_ci memcpy(&temp_ring[i], adapter->rx_ring[i], 128362306a36Sopenharmony_ci sizeof(struct ixgbe_ring)); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* Clear copied XDP RX-queue info */ 128662306a36Sopenharmony_ci memset(&temp_ring[i].xdp_rxq, 0, 128762306a36Sopenharmony_ci sizeof(temp_ring[i].xdp_rxq)); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci temp_ring[i].count = new_rx_count; 129062306a36Sopenharmony_ci err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); 129162306a36Sopenharmony_ci if (err) { 129262306a36Sopenharmony_ci while (i) { 129362306a36Sopenharmony_ci i--; 129462306a36Sopenharmony_ci ixgbe_free_rx_resources(&temp_ring[i]); 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci goto err_setup; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 130262306a36Sopenharmony_ci ixgbe_free_rx_resources(adapter->rx_ring[i]); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci memcpy(adapter->rx_ring[i], &temp_ring[i], 130562306a36Sopenharmony_ci sizeof(struct ixgbe_ring)); 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci adapter->rx_ring_count = new_rx_count; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cierr_setup: 131262306a36Sopenharmony_ci ixgbe_up(adapter); 131362306a36Sopenharmony_ci vfree(temp_ring); 131462306a36Sopenharmony_ciclear_reset: 131562306a36Sopenharmony_ci clear_bit(__IXGBE_RESETTING, &adapter->state); 131662306a36Sopenharmony_ci return err; 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistatic int ixgbe_get_sset_count(struct net_device *netdev, int sset) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci switch (sset) { 132262306a36Sopenharmony_ci case ETH_SS_TEST: 132362306a36Sopenharmony_ci return IXGBE_TEST_LEN; 132462306a36Sopenharmony_ci case ETH_SS_STATS: 132562306a36Sopenharmony_ci return IXGBE_STATS_LEN; 132662306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 132762306a36Sopenharmony_ci return IXGBE_PRIV_FLAGS_STR_LEN; 132862306a36Sopenharmony_ci default: 132962306a36Sopenharmony_ci return -EOPNOTSUPP; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic void ixgbe_get_ethtool_stats(struct net_device *netdev, 133462306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 133762306a36Sopenharmony_ci struct rtnl_link_stats64 temp; 133862306a36Sopenharmony_ci const struct rtnl_link_stats64 *net_stats; 133962306a36Sopenharmony_ci unsigned int start; 134062306a36Sopenharmony_ci struct ixgbe_ring *ring; 134162306a36Sopenharmony_ci int i, j; 134262306a36Sopenharmony_ci char *p = NULL; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci ixgbe_update_stats(adapter); 134562306a36Sopenharmony_ci net_stats = dev_get_stats(netdev, &temp); 134662306a36Sopenharmony_ci for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { 134762306a36Sopenharmony_ci switch (ixgbe_gstrings_stats[i].type) { 134862306a36Sopenharmony_ci case NETDEV_STATS: 134962306a36Sopenharmony_ci p = (char *) net_stats + 135062306a36Sopenharmony_ci ixgbe_gstrings_stats[i].stat_offset; 135162306a36Sopenharmony_ci break; 135262306a36Sopenharmony_ci case IXGBE_STATS: 135362306a36Sopenharmony_ci p = (char *) adapter + 135462306a36Sopenharmony_ci ixgbe_gstrings_stats[i].stat_offset; 135562306a36Sopenharmony_ci break; 135662306a36Sopenharmony_ci default: 135762306a36Sopenharmony_ci data[i] = 0; 135862306a36Sopenharmony_ci continue; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci data[i] = (ixgbe_gstrings_stats[i].sizeof_stat == 136262306a36Sopenharmony_ci sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci for (j = 0; j < netdev->num_tx_queues; j++) { 136562306a36Sopenharmony_ci ring = adapter->tx_ring[j]; 136662306a36Sopenharmony_ci if (!ring) { 136762306a36Sopenharmony_ci data[i] = 0; 136862306a36Sopenharmony_ci data[i+1] = 0; 136962306a36Sopenharmony_ci i += 2; 137062306a36Sopenharmony_ci continue; 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci do { 137462306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->syncp); 137562306a36Sopenharmony_ci data[i] = ring->stats.packets; 137662306a36Sopenharmony_ci data[i+1] = ring->stats.bytes; 137762306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->syncp, start)); 137862306a36Sopenharmony_ci i += 2; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci for (j = 0; j < IXGBE_NUM_RX_QUEUES; j++) { 138162306a36Sopenharmony_ci ring = adapter->rx_ring[j]; 138262306a36Sopenharmony_ci if (!ring) { 138362306a36Sopenharmony_ci data[i] = 0; 138462306a36Sopenharmony_ci data[i+1] = 0; 138562306a36Sopenharmony_ci i += 2; 138662306a36Sopenharmony_ci continue; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci do { 139062306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->syncp); 139162306a36Sopenharmony_ci data[i] = ring->stats.packets; 139262306a36Sopenharmony_ci data[i+1] = ring->stats.bytes; 139362306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->syncp, start)); 139462306a36Sopenharmony_ci i += 2; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci for (j = 0; j < IXGBE_MAX_PACKET_BUFFERS; j++) { 139862306a36Sopenharmony_ci data[i++] = adapter->stats.pxontxc[j]; 139962306a36Sopenharmony_ci data[i++] = adapter->stats.pxofftxc[j]; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci for (j = 0; j < IXGBE_MAX_PACKET_BUFFERS; j++) { 140262306a36Sopenharmony_ci data[i++] = adapter->stats.pxonrxc[j]; 140362306a36Sopenharmony_ci data[i++] = adapter->stats.pxoffrxc[j]; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic void ixgbe_get_strings(struct net_device *netdev, u32 stringset, 140862306a36Sopenharmony_ci u8 *data) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci unsigned int i; 141162306a36Sopenharmony_ci u8 *p = data; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci switch (stringset) { 141462306a36Sopenharmony_ci case ETH_SS_TEST: 141562306a36Sopenharmony_ci for (i = 0; i < IXGBE_TEST_LEN; i++) 141662306a36Sopenharmony_ci ethtool_sprintf(&p, ixgbe_gstrings_test[i]); 141762306a36Sopenharmony_ci break; 141862306a36Sopenharmony_ci case ETH_SS_STATS: 141962306a36Sopenharmony_ci for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) 142062306a36Sopenharmony_ci ethtool_sprintf(&p, 142162306a36Sopenharmony_ci ixgbe_gstrings_stats[i].stat_string); 142262306a36Sopenharmony_ci for (i = 0; i < netdev->num_tx_queues; i++) { 142362306a36Sopenharmony_ci ethtool_sprintf(&p, "tx_queue_%u_packets", i); 142462306a36Sopenharmony_ci ethtool_sprintf(&p, "tx_queue_%u_bytes", i); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci for (i = 0; i < IXGBE_NUM_RX_QUEUES; i++) { 142762306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_queue_%u_packets", i); 142862306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_queue_%u_bytes", i); 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { 143162306a36Sopenharmony_ci ethtool_sprintf(&p, "tx_pb_%u_pxon", i); 143262306a36Sopenharmony_ci ethtool_sprintf(&p, "tx_pb_%u_pxoff", i); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { 143562306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_pb_%u_pxon", i); 143662306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_pb_%u_pxoff", i); 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci /* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ 143962306a36Sopenharmony_ci break; 144062306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 144162306a36Sopenharmony_ci memcpy(data, ixgbe_priv_flags_strings, 144262306a36Sopenharmony_ci IXGBE_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci} 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_cistatic int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 144962306a36Sopenharmony_ci bool link_up; 145062306a36Sopenharmony_ci u32 link_speed = 0; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci if (ixgbe_removed(hw->hw_addr)) { 145362306a36Sopenharmony_ci *data = 1; 145462306a36Sopenharmony_ci return 1; 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci *data = 0; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci hw->mac.ops.check_link(hw, &link_speed, &link_up, true); 145962306a36Sopenharmony_ci if (link_up) 146062306a36Sopenharmony_ci return *data; 146162306a36Sopenharmony_ci else 146262306a36Sopenharmony_ci *data = 1; 146362306a36Sopenharmony_ci return *data; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci/* ethtool register test data */ 146762306a36Sopenharmony_cistruct ixgbe_reg_test { 146862306a36Sopenharmony_ci u16 reg; 146962306a36Sopenharmony_ci u8 array_len; 147062306a36Sopenharmony_ci u8 test_type; 147162306a36Sopenharmony_ci u32 mask; 147262306a36Sopenharmony_ci u32 write; 147362306a36Sopenharmony_ci}; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci/* In the hardware, registers are laid out either singly, in arrays 147662306a36Sopenharmony_ci * spaced 0x40 bytes apart, or in contiguous tables. We assume 147762306a36Sopenharmony_ci * most tests take place on arrays or single registers (handled 147862306a36Sopenharmony_ci * as a single-element array) and special-case the tables. 147962306a36Sopenharmony_ci * Table tests are always pattern tests. 148062306a36Sopenharmony_ci * 148162306a36Sopenharmony_ci * We also make provision for some required setup steps by specifying 148262306a36Sopenharmony_ci * registers to be written without any read-back testing. 148362306a36Sopenharmony_ci */ 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci#define PATTERN_TEST 1 148662306a36Sopenharmony_ci#define SET_READ_TEST 2 148762306a36Sopenharmony_ci#define WRITE_NO_TEST 3 148862306a36Sopenharmony_ci#define TABLE32_TEST 4 148962306a36Sopenharmony_ci#define TABLE64_TEST_LO 5 149062306a36Sopenharmony_ci#define TABLE64_TEST_HI 6 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci/* default 82599 register test */ 149362306a36Sopenharmony_cistatic const struct ixgbe_reg_test reg_test_82599[] = { 149462306a36Sopenharmony_ci { IXGBE_FCRTL_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, 149562306a36Sopenharmony_ci { IXGBE_FCRTH_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, 149662306a36Sopenharmony_ci { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 149762306a36Sopenharmony_ci { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, 149862306a36Sopenharmony_ci { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, 149962306a36Sopenharmony_ci { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 150062306a36Sopenharmony_ci { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 150162306a36Sopenharmony_ci { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, 150262306a36Sopenharmony_ci { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 150362306a36Sopenharmony_ci { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, 150462306a36Sopenharmony_ci { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, 150562306a36Sopenharmony_ci { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 150662306a36Sopenharmony_ci { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 150762306a36Sopenharmony_ci { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 150862306a36Sopenharmony_ci { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFF80 }, 150962306a36Sopenharmony_ci { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000001, 0x00000001 }, 151062306a36Sopenharmony_ci { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, 151162306a36Sopenharmony_ci { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x8001FFFF, 0x800CFFFF }, 151262306a36Sopenharmony_ci { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 151362306a36Sopenharmony_ci { .reg = 0 } 151462306a36Sopenharmony_ci}; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci/* default 82598 register test */ 151762306a36Sopenharmony_cistatic const struct ixgbe_reg_test reg_test_82598[] = { 151862306a36Sopenharmony_ci { IXGBE_FCRTL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, 151962306a36Sopenharmony_ci { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, 152062306a36Sopenharmony_ci { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 152162306a36Sopenharmony_ci { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, 152262306a36Sopenharmony_ci { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 152362306a36Sopenharmony_ci { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 152462306a36Sopenharmony_ci { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 152562306a36Sopenharmony_ci /* Enable all four RX queues before testing. */ 152662306a36Sopenharmony_ci { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, 152762306a36Sopenharmony_ci /* RDH is read-only for 82598, only test RDT. */ 152862306a36Sopenharmony_ci { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 152962306a36Sopenharmony_ci { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, 153062306a36Sopenharmony_ci { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, 153162306a36Sopenharmony_ci { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 153262306a36Sopenharmony_ci { IXGBE_TIPG, 1, PATTERN_TEST, 0x000000FF, 0x000000FF }, 153362306a36Sopenharmony_ci { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 153462306a36Sopenharmony_ci { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 153562306a36Sopenharmony_ci { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 153662306a36Sopenharmony_ci { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000003, 0x00000003 }, 153762306a36Sopenharmony_ci { IXGBE_DTXCTL, 1, SET_READ_TEST, 0x00000005, 0x00000005 }, 153862306a36Sopenharmony_ci { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, 153962306a36Sopenharmony_ci { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x800CFFFF, 0x800CFFFF }, 154062306a36Sopenharmony_ci { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 154162306a36Sopenharmony_ci { .reg = 0 } 154262306a36Sopenharmony_ci}; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_cistatic bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg, 154562306a36Sopenharmony_ci u32 mask, u32 write) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci u32 pat, val, before; 154862306a36Sopenharmony_ci static const u32 test_pattern[] = { 154962306a36Sopenharmony_ci 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (ixgbe_removed(adapter->hw.hw_addr)) { 155262306a36Sopenharmony_ci *data = 1; 155362306a36Sopenharmony_ci return true; 155462306a36Sopenharmony_ci } 155562306a36Sopenharmony_ci for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) { 155662306a36Sopenharmony_ci before = ixgbe_read_reg(&adapter->hw, reg); 155762306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, test_pattern[pat] & write); 155862306a36Sopenharmony_ci val = ixgbe_read_reg(&adapter->hw, reg); 155962306a36Sopenharmony_ci if (val != (test_pattern[pat] & write & mask)) { 156062306a36Sopenharmony_ci e_err(drv, "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n", 156162306a36Sopenharmony_ci reg, val, (test_pattern[pat] & write & mask)); 156262306a36Sopenharmony_ci *data = reg; 156362306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 156462306a36Sopenharmony_ci return true; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci return false; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg, 157262306a36Sopenharmony_ci u32 mask, u32 write) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci u32 val, before; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (ixgbe_removed(adapter->hw.hw_addr)) { 157762306a36Sopenharmony_ci *data = 1; 157862306a36Sopenharmony_ci return true; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci before = ixgbe_read_reg(&adapter->hw, reg); 158162306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, write & mask); 158262306a36Sopenharmony_ci val = ixgbe_read_reg(&adapter->hw, reg); 158362306a36Sopenharmony_ci if ((write & mask) != (val & mask)) { 158462306a36Sopenharmony_ci e_err(drv, "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", 158562306a36Sopenharmony_ci reg, (val & mask), (write & mask)); 158662306a36Sopenharmony_ci *data = reg; 158762306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 158862306a36Sopenharmony_ci return true; 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, reg, before); 159162306a36Sopenharmony_ci return false; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci const struct ixgbe_reg_test *test; 159762306a36Sopenharmony_ci u32 value, before, after; 159862306a36Sopenharmony_ci u32 i, toggle; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci if (ixgbe_removed(adapter->hw.hw_addr)) { 160162306a36Sopenharmony_ci e_err(drv, "Adapter removed - register test blocked\n"); 160262306a36Sopenharmony_ci *data = 1; 160362306a36Sopenharmony_ci return 1; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 160662306a36Sopenharmony_ci case ixgbe_mac_82598EB: 160762306a36Sopenharmony_ci toggle = 0x7FFFF3FF; 160862306a36Sopenharmony_ci test = reg_test_82598; 160962306a36Sopenharmony_ci break; 161062306a36Sopenharmony_ci case ixgbe_mac_82599EB: 161162306a36Sopenharmony_ci case ixgbe_mac_X540: 161262306a36Sopenharmony_ci case ixgbe_mac_X550: 161362306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 161462306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 161562306a36Sopenharmony_ci toggle = 0x7FFFF30F; 161662306a36Sopenharmony_ci test = reg_test_82599; 161762306a36Sopenharmony_ci break; 161862306a36Sopenharmony_ci default: 161962306a36Sopenharmony_ci *data = 1; 162062306a36Sopenharmony_ci return 1; 162162306a36Sopenharmony_ci } 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci /* 162462306a36Sopenharmony_ci * Because the status register is such a special case, 162562306a36Sopenharmony_ci * we handle it separately from the rest of the register 162662306a36Sopenharmony_ci * tests. Some bits are read-only, some toggle, and some 162762306a36Sopenharmony_ci * are writeable on newer MACs. 162862306a36Sopenharmony_ci */ 162962306a36Sopenharmony_ci before = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS); 163062306a36Sopenharmony_ci value = (ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle); 163162306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, toggle); 163262306a36Sopenharmony_ci after = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle; 163362306a36Sopenharmony_ci if (value != after) { 163462306a36Sopenharmony_ci e_err(drv, "failed STATUS register test got: 0x%08X expected: 0x%08X\n", 163562306a36Sopenharmony_ci after, value); 163662306a36Sopenharmony_ci *data = 1; 163762306a36Sopenharmony_ci return 1; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci /* restore previous status */ 164062306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, before); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci /* 164362306a36Sopenharmony_ci * Perform the remainder of the register test, looping through 164462306a36Sopenharmony_ci * the test table until we either fail or reach the null entry. 164562306a36Sopenharmony_ci */ 164662306a36Sopenharmony_ci while (test->reg) { 164762306a36Sopenharmony_ci for (i = 0; i < test->array_len; i++) { 164862306a36Sopenharmony_ci bool b = false; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci switch (test->test_type) { 165162306a36Sopenharmony_ci case PATTERN_TEST: 165262306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 165362306a36Sopenharmony_ci test->reg + (i * 0x40), 165462306a36Sopenharmony_ci test->mask, 165562306a36Sopenharmony_ci test->write); 165662306a36Sopenharmony_ci break; 165762306a36Sopenharmony_ci case SET_READ_TEST: 165862306a36Sopenharmony_ci b = reg_set_and_check(adapter, data, 165962306a36Sopenharmony_ci test->reg + (i * 0x40), 166062306a36Sopenharmony_ci test->mask, 166162306a36Sopenharmony_ci test->write); 166262306a36Sopenharmony_ci break; 166362306a36Sopenharmony_ci case WRITE_NO_TEST: 166462306a36Sopenharmony_ci ixgbe_write_reg(&adapter->hw, 166562306a36Sopenharmony_ci test->reg + (i * 0x40), 166662306a36Sopenharmony_ci test->write); 166762306a36Sopenharmony_ci break; 166862306a36Sopenharmony_ci case TABLE32_TEST: 166962306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 167062306a36Sopenharmony_ci test->reg + (i * 4), 167162306a36Sopenharmony_ci test->mask, 167262306a36Sopenharmony_ci test->write); 167362306a36Sopenharmony_ci break; 167462306a36Sopenharmony_ci case TABLE64_TEST_LO: 167562306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 167662306a36Sopenharmony_ci test->reg + (i * 8), 167762306a36Sopenharmony_ci test->mask, 167862306a36Sopenharmony_ci test->write); 167962306a36Sopenharmony_ci break; 168062306a36Sopenharmony_ci case TABLE64_TEST_HI: 168162306a36Sopenharmony_ci b = reg_pattern_test(adapter, data, 168262306a36Sopenharmony_ci (test->reg + 4) + (i * 8), 168362306a36Sopenharmony_ci test->mask, 168462306a36Sopenharmony_ci test->write); 168562306a36Sopenharmony_ci break; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci if (b) 168862306a36Sopenharmony_ci return 1; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci test++; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci *data = 0; 169462306a36Sopenharmony_ci return 0; 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_cistatic int ixgbe_eeprom_test(struct ixgbe_adapter *adapter, u64 *data) 169862306a36Sopenharmony_ci{ 169962306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 170062306a36Sopenharmony_ci if (hw->eeprom.ops.validate_checksum(hw, NULL)) 170162306a36Sopenharmony_ci *data = 1; 170262306a36Sopenharmony_ci else 170362306a36Sopenharmony_ci *data = 0; 170462306a36Sopenharmony_ci return *data; 170562306a36Sopenharmony_ci} 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_cistatic irqreturn_t ixgbe_test_intr(int irq, void *data) 170862306a36Sopenharmony_ci{ 170962306a36Sopenharmony_ci struct net_device *netdev = (struct net_device *) data; 171062306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci adapter->test_icr |= IXGBE_READ_REG(&adapter->hw, IXGBE_EICR); 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci return IRQ_HANDLED; 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_cistatic int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 172062306a36Sopenharmony_ci u32 mask, i = 0, shared_int = true; 172162306a36Sopenharmony_ci u32 irq = adapter->pdev->irq; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci *data = 0; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* Hook up test interrupt handler just for this test */ 172662306a36Sopenharmony_ci if (adapter->msix_entries) { 172762306a36Sopenharmony_ci /* NOTE: we don't test MSI-X interrupts here, yet */ 172862306a36Sopenharmony_ci return 0; 172962306a36Sopenharmony_ci } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { 173062306a36Sopenharmony_ci shared_int = false; 173162306a36Sopenharmony_ci if (request_irq(irq, ixgbe_test_intr, 0, netdev->name, 173262306a36Sopenharmony_ci netdev)) { 173362306a36Sopenharmony_ci *data = 1; 173462306a36Sopenharmony_ci return -1; 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci } else if (!request_irq(irq, ixgbe_test_intr, IRQF_PROBE_SHARED, 173762306a36Sopenharmony_ci netdev->name, netdev)) { 173862306a36Sopenharmony_ci shared_int = false; 173962306a36Sopenharmony_ci } else if (request_irq(irq, ixgbe_test_intr, IRQF_SHARED, 174062306a36Sopenharmony_ci netdev->name, netdev)) { 174162306a36Sopenharmony_ci *data = 1; 174262306a36Sopenharmony_ci return -1; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci e_info(hw, "testing %s interrupt\n", shared_int ? 174562306a36Sopenharmony_ci "shared" : "unshared"); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci /* Disable all the interrupts */ 174862306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); 174962306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(&adapter->hw); 175062306a36Sopenharmony_ci usleep_range(10000, 20000); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci /* Test each interrupt */ 175362306a36Sopenharmony_ci for (; i < 10; i++) { 175462306a36Sopenharmony_ci /* Interrupt to test */ 175562306a36Sopenharmony_ci mask = BIT(i); 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if (!shared_int) { 175862306a36Sopenharmony_ci /* 175962306a36Sopenharmony_ci * Disable the interrupts to be reported in 176062306a36Sopenharmony_ci * the cause register and then force the same 176162306a36Sopenharmony_ci * interrupt and see if one gets posted. If 176262306a36Sopenharmony_ci * an interrupt was posted to the bus, the 176362306a36Sopenharmony_ci * test failed. 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_ci adapter->test_icr = 0; 176662306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 176762306a36Sopenharmony_ci ~mask & 0x00007FFF); 176862306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, 176962306a36Sopenharmony_ci ~mask & 0x00007FFF); 177062306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(&adapter->hw); 177162306a36Sopenharmony_ci usleep_range(10000, 20000); 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (adapter->test_icr & mask) { 177462306a36Sopenharmony_ci *data = 3; 177562306a36Sopenharmony_ci break; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci /* 178062306a36Sopenharmony_ci * Enable the interrupt to be reported in the cause 178162306a36Sopenharmony_ci * register and then force the same interrupt and see 178262306a36Sopenharmony_ci * if one gets posted. If an interrupt was not posted 178362306a36Sopenharmony_ci * to the bus, the test failed. 178462306a36Sopenharmony_ci */ 178562306a36Sopenharmony_ci adapter->test_icr = 0; 178662306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); 178762306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); 178862306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(&adapter->hw); 178962306a36Sopenharmony_ci usleep_range(10000, 20000); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (!(adapter->test_icr & mask)) { 179262306a36Sopenharmony_ci *data = 4; 179362306a36Sopenharmony_ci break; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci if (!shared_int) { 179762306a36Sopenharmony_ci /* 179862306a36Sopenharmony_ci * Disable the other interrupts to be reported in 179962306a36Sopenharmony_ci * the cause register and then force the other 180062306a36Sopenharmony_ci * interrupts and see if any get posted. If 180162306a36Sopenharmony_ci * an interrupt was posted to the bus, the 180262306a36Sopenharmony_ci * test failed. 180362306a36Sopenharmony_ci */ 180462306a36Sopenharmony_ci adapter->test_icr = 0; 180562306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 180662306a36Sopenharmony_ci ~mask & 0x00007FFF); 180762306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, 180862306a36Sopenharmony_ci ~mask & 0x00007FFF); 180962306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(&adapter->hw); 181062306a36Sopenharmony_ci usleep_range(10000, 20000); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci if (adapter->test_icr) { 181362306a36Sopenharmony_ci *data = 5; 181462306a36Sopenharmony_ci break; 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci /* Disable all the interrupts */ 182062306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); 182162306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(&adapter->hw); 182262306a36Sopenharmony_ci usleep_range(10000, 20000); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci /* Unhook test interrupt handler */ 182562306a36Sopenharmony_ci free_irq(irq, netdev); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci return *data; 182862306a36Sopenharmony_ci} 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_cistatic void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter) 183162306a36Sopenharmony_ci{ 183262306a36Sopenharmony_ci /* Shut down the DMA engines now so they can be reinitialized later, 183362306a36Sopenharmony_ci * since the test rings and normally used rings should overlap on 183462306a36Sopenharmony_ci * queue 0 we can just use the standard disable Rx/Tx calls and they 183562306a36Sopenharmony_ci * will take care of disabling the test rings for us. 183662306a36Sopenharmony_ci */ 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci /* first Rx */ 183962306a36Sopenharmony_ci ixgbe_disable_rx(adapter); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci /* now Tx */ 184262306a36Sopenharmony_ci ixgbe_disable_tx(adapter); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci ixgbe_reset(adapter); 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci ixgbe_free_tx_resources(&adapter->test_tx_ring); 184762306a36Sopenharmony_ci ixgbe_free_rx_resources(&adapter->test_rx_ring); 184862306a36Sopenharmony_ci} 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_cistatic int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; 185362306a36Sopenharmony_ci struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; 185462306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 185562306a36Sopenharmony_ci u32 rctl, reg_data; 185662306a36Sopenharmony_ci int ret_val; 185762306a36Sopenharmony_ci int err; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci /* Setup Tx descriptor ring and Tx buffers */ 186062306a36Sopenharmony_ci tx_ring->count = IXGBE_DEFAULT_TXD; 186162306a36Sopenharmony_ci tx_ring->queue_index = 0; 186262306a36Sopenharmony_ci tx_ring->dev = &adapter->pdev->dev; 186362306a36Sopenharmony_ci tx_ring->netdev = adapter->netdev; 186462306a36Sopenharmony_ci tx_ring->reg_idx = adapter->tx_ring[0]->reg_idx; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci err = ixgbe_setup_tx_resources(tx_ring); 186762306a36Sopenharmony_ci if (err) 186862306a36Sopenharmony_ci return 1; 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 187162306a36Sopenharmony_ci case ixgbe_mac_82599EB: 187262306a36Sopenharmony_ci case ixgbe_mac_X540: 187362306a36Sopenharmony_ci case ixgbe_mac_X550: 187462306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 187562306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 187662306a36Sopenharmony_ci reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL); 187762306a36Sopenharmony_ci reg_data |= IXGBE_DMATXCTL_TE; 187862306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data); 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci default: 188162306a36Sopenharmony_ci break; 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci ixgbe_configure_tx_ring(adapter, tx_ring); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci /* Setup Rx Descriptor ring and Rx buffers */ 188762306a36Sopenharmony_ci rx_ring->count = IXGBE_DEFAULT_RXD; 188862306a36Sopenharmony_ci rx_ring->queue_index = 0; 188962306a36Sopenharmony_ci rx_ring->dev = &adapter->pdev->dev; 189062306a36Sopenharmony_ci rx_ring->netdev = adapter->netdev; 189162306a36Sopenharmony_ci rx_ring->reg_idx = adapter->rx_ring[0]->reg_idx; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci err = ixgbe_setup_rx_resources(adapter, rx_ring); 189462306a36Sopenharmony_ci if (err) { 189562306a36Sopenharmony_ci ret_val = 4; 189662306a36Sopenharmony_ci goto err_nomem; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci hw->mac.ops.disable_rx(hw); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci ixgbe_configure_rx_ring(adapter, rx_ring); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); 190462306a36Sopenharmony_ci rctl |= IXGBE_RXCTRL_DMBYPS; 190562306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci hw->mac.ops.enable_rx(hw); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci return 0; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_cierr_nomem: 191262306a36Sopenharmony_ci ixgbe_free_desc_rings(adapter); 191362306a36Sopenharmony_ci return ret_val; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) 191762306a36Sopenharmony_ci{ 191862306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 191962306a36Sopenharmony_ci u32 reg_data; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci /* Setup MAC loopback */ 192362306a36Sopenharmony_ci reg_data = IXGBE_READ_REG(hw, IXGBE_HLREG0); 192462306a36Sopenharmony_ci reg_data |= IXGBE_HLREG0_LPBK; 192562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_data); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci reg_data = IXGBE_READ_REG(hw, IXGBE_FCTRL); 192862306a36Sopenharmony_ci reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE; 192962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_data); 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci /* X540 and X550 needs to set the MACC.FLU bit to force link up */ 193262306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 193362306a36Sopenharmony_ci case ixgbe_mac_X540: 193462306a36Sopenharmony_ci case ixgbe_mac_X550: 193562306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 193662306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 193762306a36Sopenharmony_ci reg_data = IXGBE_READ_REG(hw, IXGBE_MACC); 193862306a36Sopenharmony_ci reg_data |= IXGBE_MACC_FLU; 193962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data); 194062306a36Sopenharmony_ci break; 194162306a36Sopenharmony_ci default: 194262306a36Sopenharmony_ci if (hw->mac.orig_autoc) { 194362306a36Sopenharmony_ci reg_data = hw->mac.orig_autoc | IXGBE_AUTOC_FLU; 194462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_data); 194562306a36Sopenharmony_ci } else { 194662306a36Sopenharmony_ci return 10; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 195062306a36Sopenharmony_ci usleep_range(10000, 20000); 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci /* Disable Atlas Tx lanes; re-enabled in reset path */ 195362306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) { 195462306a36Sopenharmony_ci u8 atlas; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &atlas); 195762306a36Sopenharmony_ci atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; 195862306a36Sopenharmony_ci hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, atlas); 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &atlas); 196162306a36Sopenharmony_ci atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; 196262306a36Sopenharmony_ci hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, atlas); 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &atlas); 196562306a36Sopenharmony_ci atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; 196662306a36Sopenharmony_ci hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, atlas); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &atlas); 196962306a36Sopenharmony_ci atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; 197062306a36Sopenharmony_ci hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, atlas); 197162306a36Sopenharmony_ci } 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci return 0; 197462306a36Sopenharmony_ci} 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_cistatic void ixgbe_loopback_cleanup(struct ixgbe_adapter *adapter) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci u32 reg_data; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); 198162306a36Sopenharmony_ci reg_data &= ~IXGBE_HLREG0_LPBK; 198262306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); 198362306a36Sopenharmony_ci} 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_cistatic void ixgbe_create_lbtest_frame(struct sk_buff *skb, 198662306a36Sopenharmony_ci unsigned int frame_size) 198762306a36Sopenharmony_ci{ 198862306a36Sopenharmony_ci memset(skb->data, 0xFF, frame_size); 198962306a36Sopenharmony_ci frame_size >>= 1; 199062306a36Sopenharmony_ci memset(&skb->data[frame_size], 0xAA, frame_size / 2 - 1); 199162306a36Sopenharmony_ci skb->data[frame_size + 10] = 0xBE; 199262306a36Sopenharmony_ci skb->data[frame_size + 12] = 0xAF; 199362306a36Sopenharmony_ci} 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_cistatic bool ixgbe_check_lbtest_frame(struct ixgbe_rx_buffer *rx_buffer, 199662306a36Sopenharmony_ci unsigned int frame_size) 199762306a36Sopenharmony_ci{ 199862306a36Sopenharmony_ci unsigned char *data; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci frame_size >>= 1; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci data = page_address(rx_buffer->page) + rx_buffer->page_offset; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci return data[3] == 0xFF && data[frame_size + 10] == 0xBE && 200562306a36Sopenharmony_ci data[frame_size + 12] == 0xAF; 200662306a36Sopenharmony_ci} 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_cistatic u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring, 200962306a36Sopenharmony_ci struct ixgbe_ring *tx_ring, 201062306a36Sopenharmony_ci unsigned int size) 201162306a36Sopenharmony_ci{ 201262306a36Sopenharmony_ci union ixgbe_adv_rx_desc *rx_desc; 201362306a36Sopenharmony_ci u16 rx_ntc, tx_ntc, count = 0; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci /* initialize next to clean and descriptor values */ 201662306a36Sopenharmony_ci rx_ntc = rx_ring->next_to_clean; 201762306a36Sopenharmony_ci tx_ntc = tx_ring->next_to_clean; 201862306a36Sopenharmony_ci rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci while (tx_ntc != tx_ring->next_to_use) { 202162306a36Sopenharmony_ci union ixgbe_adv_tx_desc *tx_desc; 202262306a36Sopenharmony_ci struct ixgbe_tx_buffer *tx_buffer; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci tx_desc = IXGBE_TX_DESC(tx_ring, tx_ntc); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci /* if DD is not set transmit has not completed */ 202762306a36Sopenharmony_ci if (!(tx_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD))) 202862306a36Sopenharmony_ci return count; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci /* unmap buffer on Tx side */ 203162306a36Sopenharmony_ci tx_buffer = &tx_ring->tx_buffer_info[tx_ntc]; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci /* Free all the Tx ring sk_buffs */ 203462306a36Sopenharmony_ci dev_kfree_skb_any(tx_buffer->skb); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci /* unmap skb header data */ 203762306a36Sopenharmony_ci dma_unmap_single(tx_ring->dev, 203862306a36Sopenharmony_ci dma_unmap_addr(tx_buffer, dma), 203962306a36Sopenharmony_ci dma_unmap_len(tx_buffer, len), 204062306a36Sopenharmony_ci DMA_TO_DEVICE); 204162306a36Sopenharmony_ci dma_unmap_len_set(tx_buffer, len, 0); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci /* increment Tx next to clean counter */ 204462306a36Sopenharmony_ci tx_ntc++; 204562306a36Sopenharmony_ci if (tx_ntc == tx_ring->count) 204662306a36Sopenharmony_ci tx_ntc = 0; 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci while (rx_desc->wb.upper.length) { 205062306a36Sopenharmony_ci struct ixgbe_rx_buffer *rx_buffer; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci /* check Rx buffer */ 205362306a36Sopenharmony_ci rx_buffer = &rx_ring->rx_buffer_info[rx_ntc]; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci /* sync Rx buffer for CPU read */ 205662306a36Sopenharmony_ci dma_sync_single_for_cpu(rx_ring->dev, 205762306a36Sopenharmony_ci rx_buffer->dma, 205862306a36Sopenharmony_ci ixgbe_rx_bufsz(rx_ring), 205962306a36Sopenharmony_ci DMA_FROM_DEVICE); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci /* verify contents of skb */ 206262306a36Sopenharmony_ci if (ixgbe_check_lbtest_frame(rx_buffer, size)) 206362306a36Sopenharmony_ci count++; 206462306a36Sopenharmony_ci else 206562306a36Sopenharmony_ci break; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci /* sync Rx buffer for device write */ 206862306a36Sopenharmony_ci dma_sync_single_for_device(rx_ring->dev, 206962306a36Sopenharmony_ci rx_buffer->dma, 207062306a36Sopenharmony_ci ixgbe_rx_bufsz(rx_ring), 207162306a36Sopenharmony_ci DMA_FROM_DEVICE); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci /* increment Rx next to clean counter */ 207462306a36Sopenharmony_ci rx_ntc++; 207562306a36Sopenharmony_ci if (rx_ntc == rx_ring->count) 207662306a36Sopenharmony_ci rx_ntc = 0; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci /* fetch next descriptor */ 207962306a36Sopenharmony_ci rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc); 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci netdev_tx_reset_queue(txring_txq(tx_ring)); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* re-map buffers to ring, store next to clean values */ 208562306a36Sopenharmony_ci ixgbe_alloc_rx_buffers(rx_ring, count); 208662306a36Sopenharmony_ci rx_ring->next_to_clean = rx_ntc; 208762306a36Sopenharmony_ci tx_ring->next_to_clean = tx_ntc; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci return count; 209062306a36Sopenharmony_ci} 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_cistatic int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter) 209362306a36Sopenharmony_ci{ 209462306a36Sopenharmony_ci struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; 209562306a36Sopenharmony_ci struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; 209662306a36Sopenharmony_ci int i, j, lc, good_cnt, ret_val = 0; 209762306a36Sopenharmony_ci unsigned int size = 1024; 209862306a36Sopenharmony_ci netdev_tx_t tx_ret_val; 209962306a36Sopenharmony_ci struct sk_buff *skb; 210062306a36Sopenharmony_ci u32 flags_orig = adapter->flags; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* DCB can modify the frames on Tx */ 210362306a36Sopenharmony_ci adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci /* allocate test skb */ 210662306a36Sopenharmony_ci skb = alloc_skb(size, GFP_KERNEL); 210762306a36Sopenharmony_ci if (!skb) 210862306a36Sopenharmony_ci return 11; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci /* place data into test skb */ 211162306a36Sopenharmony_ci ixgbe_create_lbtest_frame(skb, size); 211262306a36Sopenharmony_ci skb_put(skb, size); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci /* 211562306a36Sopenharmony_ci * Calculate the loop count based on the largest descriptor ring 211662306a36Sopenharmony_ci * The idea is to wrap the largest ring a number of times using 64 211762306a36Sopenharmony_ci * send/receive pairs during each loop 211862306a36Sopenharmony_ci */ 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci if (rx_ring->count <= tx_ring->count) 212162306a36Sopenharmony_ci lc = ((tx_ring->count / 64) * 2) + 1; 212262306a36Sopenharmony_ci else 212362306a36Sopenharmony_ci lc = ((rx_ring->count / 64) * 2) + 1; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci for (j = 0; j <= lc; j++) { 212662306a36Sopenharmony_ci /* reset count of good packets */ 212762306a36Sopenharmony_ci good_cnt = 0; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci /* place 64 packets on the transmit queue*/ 213062306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 213162306a36Sopenharmony_ci skb_get(skb); 213262306a36Sopenharmony_ci tx_ret_val = ixgbe_xmit_frame_ring(skb, 213362306a36Sopenharmony_ci adapter, 213462306a36Sopenharmony_ci tx_ring); 213562306a36Sopenharmony_ci if (tx_ret_val == NETDEV_TX_OK) 213662306a36Sopenharmony_ci good_cnt++; 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (good_cnt != 64) { 214062306a36Sopenharmony_ci ret_val = 12; 214162306a36Sopenharmony_ci break; 214262306a36Sopenharmony_ci } 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci /* allow 200 milliseconds for packets to go from Tx to Rx */ 214562306a36Sopenharmony_ci msleep(200); 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci good_cnt = ixgbe_clean_test_rings(rx_ring, tx_ring, size); 214862306a36Sopenharmony_ci if (good_cnt != 64) { 214962306a36Sopenharmony_ci ret_val = 13; 215062306a36Sopenharmony_ci break; 215162306a36Sopenharmony_ci } 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci /* free the original skb */ 215562306a36Sopenharmony_ci kfree_skb(skb); 215662306a36Sopenharmony_ci adapter->flags = flags_orig; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci return ret_val; 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_cistatic int ixgbe_loopback_test(struct ixgbe_adapter *adapter, u64 *data) 216262306a36Sopenharmony_ci{ 216362306a36Sopenharmony_ci *data = ixgbe_setup_desc_rings(adapter); 216462306a36Sopenharmony_ci if (*data) 216562306a36Sopenharmony_ci goto out; 216662306a36Sopenharmony_ci *data = ixgbe_setup_loopback_test(adapter); 216762306a36Sopenharmony_ci if (*data) 216862306a36Sopenharmony_ci goto err_loopback; 216962306a36Sopenharmony_ci *data = ixgbe_run_loopback_test(adapter); 217062306a36Sopenharmony_ci ixgbe_loopback_cleanup(adapter); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_cierr_loopback: 217362306a36Sopenharmony_ci ixgbe_free_desc_rings(adapter); 217462306a36Sopenharmony_ciout: 217562306a36Sopenharmony_ci return *data; 217662306a36Sopenharmony_ci} 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_cistatic void ixgbe_diag_test(struct net_device *netdev, 217962306a36Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 218062306a36Sopenharmony_ci{ 218162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 218262306a36Sopenharmony_ci bool if_running = netif_running(netdev); 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci if (ixgbe_removed(adapter->hw.hw_addr)) { 218562306a36Sopenharmony_ci e_err(hw, "Adapter removed - test blocked\n"); 218662306a36Sopenharmony_ci data[0] = 1; 218762306a36Sopenharmony_ci data[1] = 1; 218862306a36Sopenharmony_ci data[2] = 1; 218962306a36Sopenharmony_ci data[3] = 1; 219062306a36Sopenharmony_ci data[4] = 1; 219162306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 219262306a36Sopenharmony_ci return; 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci set_bit(__IXGBE_TESTING, &adapter->state); 219562306a36Sopenharmony_ci if (eth_test->flags == ETH_TEST_FL_OFFLINE) { 219662306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { 219962306a36Sopenharmony_ci int i; 220062306a36Sopenharmony_ci for (i = 0; i < adapter->num_vfs; i++) { 220162306a36Sopenharmony_ci if (adapter->vfinfo[i].clear_to_send) { 220262306a36Sopenharmony_ci netdev_warn(netdev, "offline diagnostic is not supported when VFs are present\n"); 220362306a36Sopenharmony_ci data[0] = 1; 220462306a36Sopenharmony_ci data[1] = 1; 220562306a36Sopenharmony_ci data[2] = 1; 220662306a36Sopenharmony_ci data[3] = 1; 220762306a36Sopenharmony_ci data[4] = 1; 220862306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 220962306a36Sopenharmony_ci clear_bit(__IXGBE_TESTING, 221062306a36Sopenharmony_ci &adapter->state); 221162306a36Sopenharmony_ci return; 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci /* Offline tests */ 221762306a36Sopenharmony_ci e_info(hw, "offline testing starting\n"); 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci /* Link test performed before hardware reset so autoneg doesn't 222062306a36Sopenharmony_ci * interfere with test result 222162306a36Sopenharmony_ci */ 222262306a36Sopenharmony_ci if (ixgbe_link_test(adapter, &data[4])) 222362306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci if (if_running) 222662306a36Sopenharmony_ci /* indicate we're in test mode */ 222762306a36Sopenharmony_ci ixgbe_close(netdev); 222862306a36Sopenharmony_ci else 222962306a36Sopenharmony_ci ixgbe_reset(adapter); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci e_info(hw, "register testing starting\n"); 223262306a36Sopenharmony_ci if (ixgbe_reg_test(adapter, &data[0])) 223362306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci ixgbe_reset(adapter); 223662306a36Sopenharmony_ci e_info(hw, "eeprom testing starting\n"); 223762306a36Sopenharmony_ci if (ixgbe_eeprom_test(adapter, &data[1])) 223862306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci ixgbe_reset(adapter); 224162306a36Sopenharmony_ci e_info(hw, "interrupt testing starting\n"); 224262306a36Sopenharmony_ci if (ixgbe_intr_test(adapter, &data[2])) 224362306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci /* If SRIOV or VMDq is enabled then skip MAC 224662306a36Sopenharmony_ci * loopback diagnostic. */ 224762306a36Sopenharmony_ci if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED | 224862306a36Sopenharmony_ci IXGBE_FLAG_VMDQ_ENABLED)) { 224962306a36Sopenharmony_ci e_info(hw, "Skip MAC loopback diagnostic in VT mode\n"); 225062306a36Sopenharmony_ci data[3] = 0; 225162306a36Sopenharmony_ci goto skip_loopback; 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci ixgbe_reset(adapter); 225562306a36Sopenharmony_ci e_info(hw, "loopback testing starting\n"); 225662306a36Sopenharmony_ci if (ixgbe_loopback_test(adapter, &data[3])) 225762306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ciskip_loopback: 226062306a36Sopenharmony_ci ixgbe_reset(adapter); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci /* clear testing bit and return adapter to previous state */ 226362306a36Sopenharmony_ci clear_bit(__IXGBE_TESTING, &adapter->state); 226462306a36Sopenharmony_ci if (if_running) 226562306a36Sopenharmony_ci ixgbe_open(netdev); 226662306a36Sopenharmony_ci else if (hw->mac.ops.disable_tx_laser) 226762306a36Sopenharmony_ci hw->mac.ops.disable_tx_laser(hw); 226862306a36Sopenharmony_ci } else { 226962306a36Sopenharmony_ci e_info(hw, "online testing starting\n"); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci /* Online tests */ 227262306a36Sopenharmony_ci if (ixgbe_link_test(adapter, &data[4])) 227362306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci /* Offline tests aren't run; pass by default */ 227662306a36Sopenharmony_ci data[0] = 0; 227762306a36Sopenharmony_ci data[1] = 0; 227862306a36Sopenharmony_ci data[2] = 0; 227962306a36Sopenharmony_ci data[3] = 0; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci clear_bit(__IXGBE_TESTING, &adapter->state); 228262306a36Sopenharmony_ci } 228362306a36Sopenharmony_ci} 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_cistatic int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, 228662306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 228762306a36Sopenharmony_ci{ 228862306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 228962306a36Sopenharmony_ci int retval = 0; 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* WOL not supported for all devices */ 229262306a36Sopenharmony_ci if (!ixgbe_wol_supported(adapter, hw->device_id, 229362306a36Sopenharmony_ci hw->subsystem_device_id)) { 229462306a36Sopenharmony_ci retval = 1; 229562306a36Sopenharmony_ci wol->supported = 0; 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci return retval; 229962306a36Sopenharmony_ci} 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_cistatic void ixgbe_get_wol(struct net_device *netdev, 230262306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 230362306a36Sopenharmony_ci{ 230462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci wol->supported = WAKE_UCAST | WAKE_MCAST | 230762306a36Sopenharmony_ci WAKE_BCAST | WAKE_MAGIC; 230862306a36Sopenharmony_ci wol->wolopts = 0; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci if (ixgbe_wol_exclusion(adapter, wol) || 231162306a36Sopenharmony_ci !device_can_wakeup(&adapter->pdev->dev)) 231262306a36Sopenharmony_ci return; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci if (adapter->wol & IXGBE_WUFC_EX) 231562306a36Sopenharmony_ci wol->wolopts |= WAKE_UCAST; 231662306a36Sopenharmony_ci if (adapter->wol & IXGBE_WUFC_MC) 231762306a36Sopenharmony_ci wol->wolopts |= WAKE_MCAST; 231862306a36Sopenharmony_ci if (adapter->wol & IXGBE_WUFC_BC) 231962306a36Sopenharmony_ci wol->wolopts |= WAKE_BCAST; 232062306a36Sopenharmony_ci if (adapter->wol & IXGBE_WUFC_MAG) 232162306a36Sopenharmony_ci wol->wolopts |= WAKE_MAGIC; 232262306a36Sopenharmony_ci} 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_cistatic int ixgbe_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 232562306a36Sopenharmony_ci{ 232662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE | 232962306a36Sopenharmony_ci WAKE_FILTER)) 233062306a36Sopenharmony_ci return -EOPNOTSUPP; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci if (ixgbe_wol_exclusion(adapter, wol)) 233362306a36Sopenharmony_ci return wol->wolopts ? -EOPNOTSUPP : 0; 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci adapter->wol = 0; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci if (wol->wolopts & WAKE_UCAST) 233862306a36Sopenharmony_ci adapter->wol |= IXGBE_WUFC_EX; 233962306a36Sopenharmony_ci if (wol->wolopts & WAKE_MCAST) 234062306a36Sopenharmony_ci adapter->wol |= IXGBE_WUFC_MC; 234162306a36Sopenharmony_ci if (wol->wolopts & WAKE_BCAST) 234262306a36Sopenharmony_ci adapter->wol |= IXGBE_WUFC_BC; 234362306a36Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) 234462306a36Sopenharmony_ci adapter->wol |= IXGBE_WUFC_MAG; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci return 0; 234962306a36Sopenharmony_ci} 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_cistatic int ixgbe_nway_reset(struct net_device *netdev) 235262306a36Sopenharmony_ci{ 235362306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci if (netif_running(netdev)) 235662306a36Sopenharmony_ci ixgbe_reinit_locked(adapter); 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci return 0; 235962306a36Sopenharmony_ci} 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_cistatic int ixgbe_set_phys_id(struct net_device *netdev, 236262306a36Sopenharmony_ci enum ethtool_phys_id_state state) 236362306a36Sopenharmony_ci{ 236462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 236562306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci if (!hw->mac.ops.led_on || !hw->mac.ops.led_off) 236862306a36Sopenharmony_ci return -EOPNOTSUPP; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci switch (state) { 237162306a36Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 237262306a36Sopenharmony_ci adapter->led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); 237362306a36Sopenharmony_ci return 2; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci case ETHTOOL_ID_ON: 237662306a36Sopenharmony_ci hw->mac.ops.led_on(hw, hw->mac.led_link_act); 237762306a36Sopenharmony_ci break; 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci case ETHTOOL_ID_OFF: 238062306a36Sopenharmony_ci hw->mac.ops.led_off(hw, hw->mac.led_link_act); 238162306a36Sopenharmony_ci break; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 238462306a36Sopenharmony_ci /* Restore LED settings */ 238562306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, adapter->led_reg); 238662306a36Sopenharmony_ci break; 238762306a36Sopenharmony_ci } 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci return 0; 239062306a36Sopenharmony_ci} 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_cistatic int ixgbe_get_coalesce(struct net_device *netdev, 239362306a36Sopenharmony_ci struct ethtool_coalesce *ec, 239462306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 239562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 239662306a36Sopenharmony_ci{ 239762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci /* only valid if in constant ITR mode */ 240062306a36Sopenharmony_ci if (adapter->rx_itr_setting <= 1) 240162306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->rx_itr_setting; 240262306a36Sopenharmony_ci else 240362306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci /* if in mixed tx/rx queues per vector mode, report only rx settings */ 240662306a36Sopenharmony_ci if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) 240762306a36Sopenharmony_ci return 0; 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci /* only valid if in constant ITR mode */ 241062306a36Sopenharmony_ci if (adapter->tx_itr_setting <= 1) 241162306a36Sopenharmony_ci ec->tx_coalesce_usecs = adapter->tx_itr_setting; 241262306a36Sopenharmony_ci else 241362306a36Sopenharmony_ci ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2; 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci return 0; 241662306a36Sopenharmony_ci} 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci/* 241962306a36Sopenharmony_ci * this function must be called before setting the new value of 242062306a36Sopenharmony_ci * rx_itr_setting 242162306a36Sopenharmony_ci */ 242262306a36Sopenharmony_cistatic bool ixgbe_update_rsc(struct ixgbe_adapter *adapter) 242362306a36Sopenharmony_ci{ 242462306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci /* nothing to do if LRO or RSC are not enabled */ 242762306a36Sopenharmony_ci if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) || 242862306a36Sopenharmony_ci !(netdev->features & NETIF_F_LRO)) 242962306a36Sopenharmony_ci return false; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci /* check the feature flag value and enable RSC if necessary */ 243262306a36Sopenharmony_ci if (adapter->rx_itr_setting == 1 || 243362306a36Sopenharmony_ci adapter->rx_itr_setting > IXGBE_MIN_RSC_ITR) { 243462306a36Sopenharmony_ci if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)) { 243562306a36Sopenharmony_ci adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED; 243662306a36Sopenharmony_ci e_info(probe, "rx-usecs value high enough to re-enable RSC\n"); 243762306a36Sopenharmony_ci return true; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci /* if interrupt rate is too high then disable RSC */ 244062306a36Sopenharmony_ci } else if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) { 244162306a36Sopenharmony_ci adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED; 244262306a36Sopenharmony_ci e_info(probe, "rx-usecs set too low, disabling RSC\n"); 244362306a36Sopenharmony_ci return true; 244462306a36Sopenharmony_ci } 244562306a36Sopenharmony_ci return false; 244662306a36Sopenharmony_ci} 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_cistatic int ixgbe_set_coalesce(struct net_device *netdev, 244962306a36Sopenharmony_ci struct ethtool_coalesce *ec, 245062306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 245162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 245262306a36Sopenharmony_ci{ 245362306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 245462306a36Sopenharmony_ci struct ixgbe_q_vector *q_vector; 245562306a36Sopenharmony_ci int i; 245662306a36Sopenharmony_ci u16 tx_itr_param, rx_itr_param, tx_itr_prev; 245762306a36Sopenharmony_ci bool need_reset = false; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) { 246062306a36Sopenharmony_ci /* reject Tx specific changes in case of mixed RxTx vectors */ 246162306a36Sopenharmony_ci if (ec->tx_coalesce_usecs) 246262306a36Sopenharmony_ci return -EINVAL; 246362306a36Sopenharmony_ci tx_itr_prev = adapter->rx_itr_setting; 246462306a36Sopenharmony_ci } else { 246562306a36Sopenharmony_ci tx_itr_prev = adapter->tx_itr_setting; 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci if ((ec->rx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)) || 246962306a36Sopenharmony_ci (ec->tx_coalesce_usecs > (IXGBE_MAX_EITR >> 2))) 247062306a36Sopenharmony_ci return -EINVAL; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci if (ec->rx_coalesce_usecs > 1) 247362306a36Sopenharmony_ci adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2; 247462306a36Sopenharmony_ci else 247562306a36Sopenharmony_ci adapter->rx_itr_setting = ec->rx_coalesce_usecs; 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci if (adapter->rx_itr_setting == 1) 247862306a36Sopenharmony_ci rx_itr_param = IXGBE_20K_ITR; 247962306a36Sopenharmony_ci else 248062306a36Sopenharmony_ci rx_itr_param = adapter->rx_itr_setting; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci if (ec->tx_coalesce_usecs > 1) 248362306a36Sopenharmony_ci adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2; 248462306a36Sopenharmony_ci else 248562306a36Sopenharmony_ci adapter->tx_itr_setting = ec->tx_coalesce_usecs; 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci if (adapter->tx_itr_setting == 1) 248862306a36Sopenharmony_ci tx_itr_param = IXGBE_12K_ITR; 248962306a36Sopenharmony_ci else 249062306a36Sopenharmony_ci tx_itr_param = adapter->tx_itr_setting; 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci /* mixed Rx/Tx */ 249362306a36Sopenharmony_ci if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) 249462306a36Sopenharmony_ci adapter->tx_itr_setting = adapter->rx_itr_setting; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci /* detect ITR changes that require update of TXDCTL.WTHRESH */ 249762306a36Sopenharmony_ci if ((adapter->tx_itr_setting != 1) && 249862306a36Sopenharmony_ci (adapter->tx_itr_setting < IXGBE_100K_ITR)) { 249962306a36Sopenharmony_ci if ((tx_itr_prev == 1) || 250062306a36Sopenharmony_ci (tx_itr_prev >= IXGBE_100K_ITR)) 250162306a36Sopenharmony_ci need_reset = true; 250262306a36Sopenharmony_ci } else { 250362306a36Sopenharmony_ci if ((tx_itr_prev != 1) && 250462306a36Sopenharmony_ci (tx_itr_prev < IXGBE_100K_ITR)) 250562306a36Sopenharmony_ci need_reset = true; 250662306a36Sopenharmony_ci } 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci /* check the old value and enable RSC if necessary */ 250962306a36Sopenharmony_ci need_reset |= ixgbe_update_rsc(adapter); 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci for (i = 0; i < adapter->num_q_vectors; i++) { 251262306a36Sopenharmony_ci q_vector = adapter->q_vector[i]; 251362306a36Sopenharmony_ci if (q_vector->tx.count && !q_vector->rx.count) 251462306a36Sopenharmony_ci /* tx only */ 251562306a36Sopenharmony_ci q_vector->itr = tx_itr_param; 251662306a36Sopenharmony_ci else 251762306a36Sopenharmony_ci /* rx only or mixed */ 251862306a36Sopenharmony_ci q_vector->itr = rx_itr_param; 251962306a36Sopenharmony_ci ixgbe_write_eitr(q_vector); 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci /* 252362306a36Sopenharmony_ci * do reset here at the end to make sure EITR==0 case is handled 252462306a36Sopenharmony_ci * correctly w.r.t stopping tx, and changing TXDCTL.WTHRESH settings 252562306a36Sopenharmony_ci * also locks in RSC enable/disable which requires reset 252662306a36Sopenharmony_ci */ 252762306a36Sopenharmony_ci if (need_reset) 252862306a36Sopenharmony_ci ixgbe_do_reset(netdev); 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci return 0; 253162306a36Sopenharmony_ci} 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_cistatic int ixgbe_get_ethtool_fdir_entry(struct ixgbe_adapter *adapter, 253462306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 253562306a36Sopenharmony_ci{ 253662306a36Sopenharmony_ci union ixgbe_atr_input *mask = &adapter->fdir_mask; 253762306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 253862306a36Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 253962306a36Sopenharmony_ci struct hlist_node *node2; 254062306a36Sopenharmony_ci struct ixgbe_fdir_filter *rule = NULL; 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci /* report total rule count */ 254362306a36Sopenharmony_ci cmd->data = (1024 << adapter->fdir_pballoc) - 2; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci hlist_for_each_entry_safe(rule, node2, 254662306a36Sopenharmony_ci &adapter->fdir_filter_list, fdir_node) { 254762306a36Sopenharmony_ci if (fsp->location <= rule->sw_idx) 254862306a36Sopenharmony_ci break; 254962306a36Sopenharmony_ci } 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci if (!rule || fsp->location != rule->sw_idx) 255262306a36Sopenharmony_ci return -EINVAL; 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci /* fill out the flow spec entry */ 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci /* set flow type field */ 255762306a36Sopenharmony_ci switch (rule->filter.formatted.flow_type) { 255862306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_TCPV4: 255962306a36Sopenharmony_ci fsp->flow_type = TCP_V4_FLOW; 256062306a36Sopenharmony_ci break; 256162306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_UDPV4: 256262306a36Sopenharmony_ci fsp->flow_type = UDP_V4_FLOW; 256362306a36Sopenharmony_ci break; 256462306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_SCTPV4: 256562306a36Sopenharmony_ci fsp->flow_type = SCTP_V4_FLOW; 256662306a36Sopenharmony_ci break; 256762306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_IPV4: 256862306a36Sopenharmony_ci fsp->flow_type = IP_USER_FLOW; 256962306a36Sopenharmony_ci fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; 257062306a36Sopenharmony_ci fsp->h_u.usr_ip4_spec.proto = 0; 257162306a36Sopenharmony_ci fsp->m_u.usr_ip4_spec.proto = 0; 257262306a36Sopenharmony_ci break; 257362306a36Sopenharmony_ci default: 257462306a36Sopenharmony_ci return -EINVAL; 257562306a36Sopenharmony_ci } 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci fsp->h_u.tcp_ip4_spec.psrc = rule->filter.formatted.src_port; 257862306a36Sopenharmony_ci fsp->m_u.tcp_ip4_spec.psrc = mask->formatted.src_port; 257962306a36Sopenharmony_ci fsp->h_u.tcp_ip4_spec.pdst = rule->filter.formatted.dst_port; 258062306a36Sopenharmony_ci fsp->m_u.tcp_ip4_spec.pdst = mask->formatted.dst_port; 258162306a36Sopenharmony_ci fsp->h_u.tcp_ip4_spec.ip4src = rule->filter.formatted.src_ip[0]; 258262306a36Sopenharmony_ci fsp->m_u.tcp_ip4_spec.ip4src = mask->formatted.src_ip[0]; 258362306a36Sopenharmony_ci fsp->h_u.tcp_ip4_spec.ip4dst = rule->filter.formatted.dst_ip[0]; 258462306a36Sopenharmony_ci fsp->m_u.tcp_ip4_spec.ip4dst = mask->formatted.dst_ip[0]; 258562306a36Sopenharmony_ci fsp->h_ext.vlan_tci = rule->filter.formatted.vlan_id; 258662306a36Sopenharmony_ci fsp->m_ext.vlan_tci = mask->formatted.vlan_id; 258762306a36Sopenharmony_ci fsp->h_ext.vlan_etype = rule->filter.formatted.flex_bytes; 258862306a36Sopenharmony_ci fsp->m_ext.vlan_etype = mask->formatted.flex_bytes; 258962306a36Sopenharmony_ci fsp->h_ext.data[1] = htonl(rule->filter.formatted.vm_pool); 259062306a36Sopenharmony_ci fsp->m_ext.data[1] = htonl(mask->formatted.vm_pool); 259162306a36Sopenharmony_ci fsp->flow_type |= FLOW_EXT; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci /* record action */ 259462306a36Sopenharmony_ci if (rule->action == IXGBE_FDIR_DROP_QUEUE) 259562306a36Sopenharmony_ci fsp->ring_cookie = RX_CLS_FLOW_DISC; 259662306a36Sopenharmony_ci else 259762306a36Sopenharmony_ci fsp->ring_cookie = rule->action; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci return 0; 260062306a36Sopenharmony_ci} 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_cistatic int ixgbe_get_ethtool_fdir_all(struct ixgbe_adapter *adapter, 260362306a36Sopenharmony_ci struct ethtool_rxnfc *cmd, 260462306a36Sopenharmony_ci u32 *rule_locs) 260562306a36Sopenharmony_ci{ 260662306a36Sopenharmony_ci struct hlist_node *node2; 260762306a36Sopenharmony_ci struct ixgbe_fdir_filter *rule; 260862306a36Sopenharmony_ci int cnt = 0; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci /* report total rule count */ 261162306a36Sopenharmony_ci cmd->data = (1024 << adapter->fdir_pballoc) - 2; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci hlist_for_each_entry_safe(rule, node2, 261462306a36Sopenharmony_ci &adapter->fdir_filter_list, fdir_node) { 261562306a36Sopenharmony_ci if (cnt == cmd->rule_cnt) 261662306a36Sopenharmony_ci return -EMSGSIZE; 261762306a36Sopenharmony_ci rule_locs[cnt] = rule->sw_idx; 261862306a36Sopenharmony_ci cnt++; 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci cmd->rule_cnt = cnt; 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci return 0; 262462306a36Sopenharmony_ci} 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_cistatic int ixgbe_get_rss_hash_opts(struct ixgbe_adapter *adapter, 262762306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 262862306a36Sopenharmony_ci{ 262962306a36Sopenharmony_ci cmd->data = 0; 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_ci /* Report default options for RSS on ixgbe */ 263262306a36Sopenharmony_ci switch (cmd->flow_type) { 263362306a36Sopenharmony_ci case TCP_V4_FLOW: 263462306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 263562306a36Sopenharmony_ci fallthrough; 263662306a36Sopenharmony_ci case UDP_V4_FLOW: 263762306a36Sopenharmony_ci if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP) 263862306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 263962306a36Sopenharmony_ci fallthrough; 264062306a36Sopenharmony_ci case SCTP_V4_FLOW: 264162306a36Sopenharmony_ci case AH_ESP_V4_FLOW: 264262306a36Sopenharmony_ci case AH_V4_FLOW: 264362306a36Sopenharmony_ci case ESP_V4_FLOW: 264462306a36Sopenharmony_ci case IPV4_FLOW: 264562306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST; 264662306a36Sopenharmony_ci break; 264762306a36Sopenharmony_ci case TCP_V6_FLOW: 264862306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 264962306a36Sopenharmony_ci fallthrough; 265062306a36Sopenharmony_ci case UDP_V6_FLOW: 265162306a36Sopenharmony_ci if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP) 265262306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 265362306a36Sopenharmony_ci fallthrough; 265462306a36Sopenharmony_ci case SCTP_V6_FLOW: 265562306a36Sopenharmony_ci case AH_ESP_V6_FLOW: 265662306a36Sopenharmony_ci case AH_V6_FLOW: 265762306a36Sopenharmony_ci case ESP_V6_FLOW: 265862306a36Sopenharmony_ci case IPV6_FLOW: 265962306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST; 266062306a36Sopenharmony_ci break; 266162306a36Sopenharmony_ci default: 266262306a36Sopenharmony_ci return -EINVAL; 266362306a36Sopenharmony_ci } 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci return 0; 266662306a36Sopenharmony_ci} 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_cistatic int ixgbe_rss_indir_tbl_max(struct ixgbe_adapter *adapter) 266962306a36Sopenharmony_ci{ 267062306a36Sopenharmony_ci if (adapter->hw.mac.type < ixgbe_mac_X550) 267162306a36Sopenharmony_ci return 16; 267262306a36Sopenharmony_ci else 267362306a36Sopenharmony_ci return 64; 267462306a36Sopenharmony_ci} 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_cistatic int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 267762306a36Sopenharmony_ci u32 *rule_locs) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(dev); 268062306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci switch (cmd->cmd) { 268362306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 268462306a36Sopenharmony_ci cmd->data = min_t(int, adapter->num_rx_queues, 268562306a36Sopenharmony_ci ixgbe_rss_indir_tbl_max(adapter)); 268662306a36Sopenharmony_ci ret = 0; 268762306a36Sopenharmony_ci break; 268862306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 268962306a36Sopenharmony_ci cmd->rule_cnt = adapter->fdir_filter_count; 269062306a36Sopenharmony_ci ret = 0; 269162306a36Sopenharmony_ci break; 269262306a36Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 269362306a36Sopenharmony_ci ret = ixgbe_get_ethtool_fdir_entry(adapter, cmd); 269462306a36Sopenharmony_ci break; 269562306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 269662306a36Sopenharmony_ci ret = ixgbe_get_ethtool_fdir_all(adapter, cmd, rule_locs); 269762306a36Sopenharmony_ci break; 269862306a36Sopenharmony_ci case ETHTOOL_GRXFH: 269962306a36Sopenharmony_ci ret = ixgbe_get_rss_hash_opts(adapter, cmd); 270062306a36Sopenharmony_ci break; 270162306a36Sopenharmony_ci default: 270262306a36Sopenharmony_ci break; 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci return ret; 270662306a36Sopenharmony_ci} 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ciint ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter, 270962306a36Sopenharmony_ci struct ixgbe_fdir_filter *input, 271062306a36Sopenharmony_ci u16 sw_idx) 271162306a36Sopenharmony_ci{ 271262306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 271362306a36Sopenharmony_ci struct hlist_node *node2; 271462306a36Sopenharmony_ci struct ixgbe_fdir_filter *rule, *parent; 271562306a36Sopenharmony_ci int err = -EINVAL; 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci parent = NULL; 271862306a36Sopenharmony_ci rule = NULL; 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci hlist_for_each_entry_safe(rule, node2, 272162306a36Sopenharmony_ci &adapter->fdir_filter_list, fdir_node) { 272262306a36Sopenharmony_ci /* hash found, or no matching entry */ 272362306a36Sopenharmony_ci if (rule->sw_idx >= sw_idx) 272462306a36Sopenharmony_ci break; 272562306a36Sopenharmony_ci parent = rule; 272662306a36Sopenharmony_ci } 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci /* if there is an old rule occupying our place remove it */ 272962306a36Sopenharmony_ci if (rule && (rule->sw_idx == sw_idx)) { 273062306a36Sopenharmony_ci if (!input || (rule->filter.formatted.bkt_hash != 273162306a36Sopenharmony_ci input->filter.formatted.bkt_hash)) { 273262306a36Sopenharmony_ci err = ixgbe_fdir_erase_perfect_filter_82599(hw, 273362306a36Sopenharmony_ci &rule->filter, 273462306a36Sopenharmony_ci sw_idx); 273562306a36Sopenharmony_ci } 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci hlist_del(&rule->fdir_node); 273862306a36Sopenharmony_ci kfree(rule); 273962306a36Sopenharmony_ci adapter->fdir_filter_count--; 274062306a36Sopenharmony_ci } 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci /* 274362306a36Sopenharmony_ci * If no input this was a delete, err should be 0 if a rule was 274462306a36Sopenharmony_ci * successfully found and removed from the list else -EINVAL 274562306a36Sopenharmony_ci */ 274662306a36Sopenharmony_ci if (!input) 274762306a36Sopenharmony_ci return err; 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci /* initialize node and set software index */ 275062306a36Sopenharmony_ci INIT_HLIST_NODE(&input->fdir_node); 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci /* add filter to the list */ 275362306a36Sopenharmony_ci if (parent) 275462306a36Sopenharmony_ci hlist_add_behind(&input->fdir_node, &parent->fdir_node); 275562306a36Sopenharmony_ci else 275662306a36Sopenharmony_ci hlist_add_head(&input->fdir_node, 275762306a36Sopenharmony_ci &adapter->fdir_filter_list); 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci /* update counts */ 276062306a36Sopenharmony_ci adapter->fdir_filter_count++; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci return 0; 276362306a36Sopenharmony_ci} 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_cistatic int ixgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp, 276662306a36Sopenharmony_ci u8 *flow_type) 276762306a36Sopenharmony_ci{ 276862306a36Sopenharmony_ci switch (fsp->flow_type & ~FLOW_EXT) { 276962306a36Sopenharmony_ci case TCP_V4_FLOW: 277062306a36Sopenharmony_ci *flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4; 277162306a36Sopenharmony_ci break; 277262306a36Sopenharmony_ci case UDP_V4_FLOW: 277362306a36Sopenharmony_ci *flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4; 277462306a36Sopenharmony_ci break; 277562306a36Sopenharmony_ci case SCTP_V4_FLOW: 277662306a36Sopenharmony_ci *flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4; 277762306a36Sopenharmony_ci break; 277862306a36Sopenharmony_ci case IP_USER_FLOW: 277962306a36Sopenharmony_ci switch (fsp->h_u.usr_ip4_spec.proto) { 278062306a36Sopenharmony_ci case IPPROTO_TCP: 278162306a36Sopenharmony_ci *flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4; 278262306a36Sopenharmony_ci break; 278362306a36Sopenharmony_ci case IPPROTO_UDP: 278462306a36Sopenharmony_ci *flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4; 278562306a36Sopenharmony_ci break; 278662306a36Sopenharmony_ci case IPPROTO_SCTP: 278762306a36Sopenharmony_ci *flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4; 278862306a36Sopenharmony_ci break; 278962306a36Sopenharmony_ci case 0: 279062306a36Sopenharmony_ci if (!fsp->m_u.usr_ip4_spec.proto) { 279162306a36Sopenharmony_ci *flow_type = IXGBE_ATR_FLOW_TYPE_IPV4; 279262306a36Sopenharmony_ci break; 279362306a36Sopenharmony_ci } 279462306a36Sopenharmony_ci fallthrough; 279562306a36Sopenharmony_ci default: 279662306a36Sopenharmony_ci return 0; 279762306a36Sopenharmony_ci } 279862306a36Sopenharmony_ci break; 279962306a36Sopenharmony_ci default: 280062306a36Sopenharmony_ci return 0; 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci return 1; 280462306a36Sopenharmony_ci} 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_cistatic int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter, 280762306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 280862306a36Sopenharmony_ci{ 280962306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 281062306a36Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 281162306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 281262306a36Sopenharmony_ci struct ixgbe_fdir_filter *input; 281362306a36Sopenharmony_ci union ixgbe_atr_input mask; 281462306a36Sopenharmony_ci u8 queue; 281562306a36Sopenharmony_ci int err; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) 281862306a36Sopenharmony_ci return -EOPNOTSUPP; 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci /* ring_cookie is a masked into a set of queues and ixgbe pools or 282162306a36Sopenharmony_ci * we use the drop index. 282262306a36Sopenharmony_ci */ 282362306a36Sopenharmony_ci if (fsp->ring_cookie == RX_CLS_FLOW_DISC) { 282462306a36Sopenharmony_ci queue = IXGBE_FDIR_DROP_QUEUE; 282562306a36Sopenharmony_ci } else { 282662306a36Sopenharmony_ci u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie); 282762306a36Sopenharmony_ci u8 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie); 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci if (!vf && (ring >= adapter->num_rx_queues)) 283062306a36Sopenharmony_ci return -EINVAL; 283162306a36Sopenharmony_ci else if (vf && 283262306a36Sopenharmony_ci ((vf > adapter->num_vfs) || 283362306a36Sopenharmony_ci ring >= adapter->num_rx_queues_per_pool)) 283462306a36Sopenharmony_ci return -EINVAL; 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci /* Map the ring onto the absolute queue index */ 283762306a36Sopenharmony_ci if (!vf) 283862306a36Sopenharmony_ci queue = adapter->rx_ring[ring]->reg_idx; 283962306a36Sopenharmony_ci else 284062306a36Sopenharmony_ci queue = ((vf - 1) * 284162306a36Sopenharmony_ci adapter->num_rx_queues_per_pool) + ring; 284262306a36Sopenharmony_ci } 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci /* Don't allow indexes to exist outside of available space */ 284562306a36Sopenharmony_ci if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2)) { 284662306a36Sopenharmony_ci e_err(drv, "Location out of range\n"); 284762306a36Sopenharmony_ci return -EINVAL; 284862306a36Sopenharmony_ci } 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci input = kzalloc(sizeof(*input), GFP_ATOMIC); 285162306a36Sopenharmony_ci if (!input) 285262306a36Sopenharmony_ci return -ENOMEM; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci memset(&mask, 0, sizeof(union ixgbe_atr_input)); 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci /* set SW index */ 285762306a36Sopenharmony_ci input->sw_idx = fsp->location; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci /* record flow type */ 286062306a36Sopenharmony_ci if (!ixgbe_flowspec_to_flow_type(fsp, 286162306a36Sopenharmony_ci &input->filter.formatted.flow_type)) { 286262306a36Sopenharmony_ci e_err(drv, "Unrecognized flow type\n"); 286362306a36Sopenharmony_ci goto err_out; 286462306a36Sopenharmony_ci } 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci mask.formatted.flow_type = IXGBE_ATR_L4TYPE_IPV6_MASK | 286762306a36Sopenharmony_ci IXGBE_ATR_L4TYPE_MASK; 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci if (input->filter.formatted.flow_type == IXGBE_ATR_FLOW_TYPE_IPV4) 287062306a36Sopenharmony_ci mask.formatted.flow_type &= IXGBE_ATR_L4TYPE_IPV6_MASK; 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_ci /* Copy input into formatted structures */ 287362306a36Sopenharmony_ci input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src; 287462306a36Sopenharmony_ci mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src; 287562306a36Sopenharmony_ci input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst; 287662306a36Sopenharmony_ci mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst; 287762306a36Sopenharmony_ci input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc; 287862306a36Sopenharmony_ci mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc; 287962306a36Sopenharmony_ci input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst; 288062306a36Sopenharmony_ci mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst; 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci if (fsp->flow_type & FLOW_EXT) { 288362306a36Sopenharmony_ci input->filter.formatted.vm_pool = 288462306a36Sopenharmony_ci (unsigned char)ntohl(fsp->h_ext.data[1]); 288562306a36Sopenharmony_ci mask.formatted.vm_pool = 288662306a36Sopenharmony_ci (unsigned char)ntohl(fsp->m_ext.data[1]); 288762306a36Sopenharmony_ci input->filter.formatted.vlan_id = fsp->h_ext.vlan_tci; 288862306a36Sopenharmony_ci mask.formatted.vlan_id = fsp->m_ext.vlan_tci; 288962306a36Sopenharmony_ci input->filter.formatted.flex_bytes = 289062306a36Sopenharmony_ci fsp->h_ext.vlan_etype; 289162306a36Sopenharmony_ci mask.formatted.flex_bytes = fsp->m_ext.vlan_etype; 289262306a36Sopenharmony_ci } 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci /* determine if we need to drop or route the packet */ 289562306a36Sopenharmony_ci if (fsp->ring_cookie == RX_CLS_FLOW_DISC) 289662306a36Sopenharmony_ci input->action = IXGBE_FDIR_DROP_QUEUE; 289762306a36Sopenharmony_ci else 289862306a36Sopenharmony_ci input->action = fsp->ring_cookie; 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci spin_lock(&adapter->fdir_perfect_lock); 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci if (hlist_empty(&adapter->fdir_filter_list)) { 290362306a36Sopenharmony_ci /* save mask and program input mask into HW */ 290462306a36Sopenharmony_ci memcpy(&adapter->fdir_mask, &mask, sizeof(mask)); 290562306a36Sopenharmony_ci err = ixgbe_fdir_set_input_mask_82599(hw, &mask); 290662306a36Sopenharmony_ci if (err) { 290762306a36Sopenharmony_ci e_err(drv, "Error writing mask\n"); 290862306a36Sopenharmony_ci goto err_out_w_lock; 290962306a36Sopenharmony_ci } 291062306a36Sopenharmony_ci } else if (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) { 291162306a36Sopenharmony_ci e_err(drv, "Only one mask supported per port\n"); 291262306a36Sopenharmony_ci goto err_out_w_lock; 291362306a36Sopenharmony_ci } 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci /* apply mask and compute/store hash */ 291662306a36Sopenharmony_ci ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci /* program filters to filter memory */ 291962306a36Sopenharmony_ci err = ixgbe_fdir_write_perfect_filter_82599(hw, 292062306a36Sopenharmony_ci &input->filter, input->sw_idx, queue); 292162306a36Sopenharmony_ci if (err) 292262306a36Sopenharmony_ci goto err_out_w_lock; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci spin_unlock(&adapter->fdir_perfect_lock); 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci return err; 292962306a36Sopenharmony_cierr_out_w_lock: 293062306a36Sopenharmony_ci spin_unlock(&adapter->fdir_perfect_lock); 293162306a36Sopenharmony_cierr_out: 293262306a36Sopenharmony_ci kfree(input); 293362306a36Sopenharmony_ci return -EINVAL; 293462306a36Sopenharmony_ci} 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_cistatic int ixgbe_del_ethtool_fdir_entry(struct ixgbe_adapter *adapter, 293762306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 293862306a36Sopenharmony_ci{ 293962306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 294062306a36Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 294162306a36Sopenharmony_ci int err; 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci spin_lock(&adapter->fdir_perfect_lock); 294462306a36Sopenharmony_ci err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, fsp->location); 294562306a36Sopenharmony_ci spin_unlock(&adapter->fdir_perfect_lock); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci return err; 294862306a36Sopenharmony_ci} 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci#define UDP_RSS_FLAGS (IXGBE_FLAG2_RSS_FIELD_IPV4_UDP | \ 295162306a36Sopenharmony_ci IXGBE_FLAG2_RSS_FIELD_IPV6_UDP) 295262306a36Sopenharmony_cistatic int ixgbe_set_rss_hash_opt(struct ixgbe_adapter *adapter, 295362306a36Sopenharmony_ci struct ethtool_rxnfc *nfc) 295462306a36Sopenharmony_ci{ 295562306a36Sopenharmony_ci u32 flags2 = adapter->flags2; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci /* 295862306a36Sopenharmony_ci * RSS does not support anything other than hashing 295962306a36Sopenharmony_ci * to queues on src and dst IPs and ports 296062306a36Sopenharmony_ci */ 296162306a36Sopenharmony_ci if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | 296262306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) 296362306a36Sopenharmony_ci return -EINVAL; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci switch (nfc->flow_type) { 296662306a36Sopenharmony_ci case TCP_V4_FLOW: 296762306a36Sopenharmony_ci case TCP_V6_FLOW: 296862306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 296962306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST) || 297062306a36Sopenharmony_ci !(nfc->data & RXH_L4_B_0_1) || 297162306a36Sopenharmony_ci !(nfc->data & RXH_L4_B_2_3)) 297262306a36Sopenharmony_ci return -EINVAL; 297362306a36Sopenharmony_ci break; 297462306a36Sopenharmony_ci case UDP_V4_FLOW: 297562306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 297662306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST)) 297762306a36Sopenharmony_ci return -EINVAL; 297862306a36Sopenharmony_ci switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 297962306a36Sopenharmony_ci case 0: 298062306a36Sopenharmony_ci flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV4_UDP; 298162306a36Sopenharmony_ci break; 298262306a36Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 298362306a36Sopenharmony_ci flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV4_UDP; 298462306a36Sopenharmony_ci break; 298562306a36Sopenharmony_ci default: 298662306a36Sopenharmony_ci return -EINVAL; 298762306a36Sopenharmony_ci } 298862306a36Sopenharmony_ci break; 298962306a36Sopenharmony_ci case UDP_V6_FLOW: 299062306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 299162306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST)) 299262306a36Sopenharmony_ci return -EINVAL; 299362306a36Sopenharmony_ci switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 299462306a36Sopenharmony_ci case 0: 299562306a36Sopenharmony_ci flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV6_UDP; 299662306a36Sopenharmony_ci break; 299762306a36Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 299862306a36Sopenharmony_ci flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV6_UDP; 299962306a36Sopenharmony_ci break; 300062306a36Sopenharmony_ci default: 300162306a36Sopenharmony_ci return -EINVAL; 300262306a36Sopenharmony_ci } 300362306a36Sopenharmony_ci break; 300462306a36Sopenharmony_ci case AH_ESP_V4_FLOW: 300562306a36Sopenharmony_ci case AH_V4_FLOW: 300662306a36Sopenharmony_ci case ESP_V4_FLOW: 300762306a36Sopenharmony_ci case SCTP_V4_FLOW: 300862306a36Sopenharmony_ci case AH_ESP_V6_FLOW: 300962306a36Sopenharmony_ci case AH_V6_FLOW: 301062306a36Sopenharmony_ci case ESP_V6_FLOW: 301162306a36Sopenharmony_ci case SCTP_V6_FLOW: 301262306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 301362306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST) || 301462306a36Sopenharmony_ci (nfc->data & RXH_L4_B_0_1) || 301562306a36Sopenharmony_ci (nfc->data & RXH_L4_B_2_3)) 301662306a36Sopenharmony_ci return -EINVAL; 301762306a36Sopenharmony_ci break; 301862306a36Sopenharmony_ci default: 301962306a36Sopenharmony_ci return -EINVAL; 302062306a36Sopenharmony_ci } 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci /* if we changed something we need to update flags */ 302362306a36Sopenharmony_ci if (flags2 != adapter->flags2) { 302462306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 302562306a36Sopenharmony_ci u32 mrqc; 302662306a36Sopenharmony_ci unsigned int pf_pool = adapter->num_vfs; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci if ((hw->mac.type >= ixgbe_mac_X550) && 302962306a36Sopenharmony_ci (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) 303062306a36Sopenharmony_ci mrqc = IXGBE_READ_REG(hw, IXGBE_PFVFMRQC(pf_pool)); 303162306a36Sopenharmony_ci else 303262306a36Sopenharmony_ci mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC); 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci if ((flags2 & UDP_RSS_FLAGS) && 303562306a36Sopenharmony_ci !(adapter->flags2 & UDP_RSS_FLAGS)) 303662306a36Sopenharmony_ci e_warn(drv, "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci adapter->flags2 = flags2; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci /* Perform hash on these packet types */ 304162306a36Sopenharmony_ci mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4 304262306a36Sopenharmony_ci | IXGBE_MRQC_RSS_FIELD_IPV4_TCP 304362306a36Sopenharmony_ci | IXGBE_MRQC_RSS_FIELD_IPV6 304462306a36Sopenharmony_ci | IXGBE_MRQC_RSS_FIELD_IPV6_TCP; 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci mrqc &= ~(IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 304762306a36Sopenharmony_ci IXGBE_MRQC_RSS_FIELD_IPV6_UDP); 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP) 305062306a36Sopenharmony_ci mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP) 305362306a36Sopenharmony_ci mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci if ((hw->mac.type >= ixgbe_mac_X550) && 305662306a36Sopenharmony_ci (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) 305762306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_PFVFMRQC(pf_pool), mrqc); 305862306a36Sopenharmony_ci else 305962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 306062306a36Sopenharmony_ci } 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci return 0; 306362306a36Sopenharmony_ci} 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_cistatic int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 306662306a36Sopenharmony_ci{ 306762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(dev); 306862306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci switch (cmd->cmd) { 307162306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 307262306a36Sopenharmony_ci ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd); 307362306a36Sopenharmony_ci break; 307462306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 307562306a36Sopenharmony_ci ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd); 307662306a36Sopenharmony_ci break; 307762306a36Sopenharmony_ci case ETHTOOL_SRXFH: 307862306a36Sopenharmony_ci ret = ixgbe_set_rss_hash_opt(adapter, cmd); 307962306a36Sopenharmony_ci break; 308062306a36Sopenharmony_ci default: 308162306a36Sopenharmony_ci break; 308262306a36Sopenharmony_ci } 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci return ret; 308562306a36Sopenharmony_ci} 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_cistatic u32 ixgbe_get_rxfh_key_size(struct net_device *netdev) 308862306a36Sopenharmony_ci{ 308962306a36Sopenharmony_ci return IXGBE_RSS_KEY_SIZE; 309062306a36Sopenharmony_ci} 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_cistatic u32 ixgbe_rss_indir_size(struct net_device *netdev) 309362306a36Sopenharmony_ci{ 309462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci return ixgbe_rss_indir_tbl_entries(adapter); 309762306a36Sopenharmony_ci} 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_cistatic void ixgbe_get_reta(struct ixgbe_adapter *adapter, u32 *indir) 310062306a36Sopenharmony_ci{ 310162306a36Sopenharmony_ci int i, reta_size = ixgbe_rss_indir_tbl_entries(adapter); 310262306a36Sopenharmony_ci u16 rss_m = adapter->ring_feature[RING_F_RSS].mask; 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) 310562306a36Sopenharmony_ci rss_m = adapter->ring_feature[RING_F_RSS].indices - 1; 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci for (i = 0; i < reta_size; i++) 310862306a36Sopenharmony_ci indir[i] = adapter->rss_indir_tbl[i] & rss_m; 310962306a36Sopenharmony_ci} 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_cistatic int ixgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, 311262306a36Sopenharmony_ci u8 *hfunc) 311362306a36Sopenharmony_ci{ 311462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci if (hfunc) 311762306a36Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (indir) 312062306a36Sopenharmony_ci ixgbe_get_reta(adapter, indir); 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci if (key) 312362306a36Sopenharmony_ci memcpy(key, adapter->rss_key, ixgbe_get_rxfh_key_size(netdev)); 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci return 0; 312662306a36Sopenharmony_ci} 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_cistatic int ixgbe_set_rxfh(struct net_device *netdev, const u32 *indir, 312962306a36Sopenharmony_ci const u8 *key, const u8 hfunc) 313062306a36Sopenharmony_ci{ 313162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 313262306a36Sopenharmony_ci int i; 313362306a36Sopenharmony_ci u32 reta_entries = ixgbe_rss_indir_tbl_entries(adapter); 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 313662306a36Sopenharmony_ci return -EOPNOTSUPP; 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci /* Fill out the redirection table */ 313962306a36Sopenharmony_ci if (indir) { 314062306a36Sopenharmony_ci int max_queues = min_t(int, adapter->num_rx_queues, 314162306a36Sopenharmony_ci ixgbe_rss_indir_tbl_max(adapter)); 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci /*Allow at least 2 queues w/ SR-IOV.*/ 314462306a36Sopenharmony_ci if ((adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) && 314562306a36Sopenharmony_ci (max_queues < 2)) 314662306a36Sopenharmony_ci max_queues = 2; 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci /* Verify user input. */ 314962306a36Sopenharmony_ci for (i = 0; i < reta_entries; i++) 315062306a36Sopenharmony_ci if (indir[i] >= max_queues) 315162306a36Sopenharmony_ci return -EINVAL; 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci for (i = 0; i < reta_entries; i++) 315462306a36Sopenharmony_ci adapter->rss_indir_tbl[i] = indir[i]; 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci ixgbe_store_reta(adapter); 315762306a36Sopenharmony_ci } 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci /* Fill out the rss hash key */ 316062306a36Sopenharmony_ci if (key) { 316162306a36Sopenharmony_ci memcpy(adapter->rss_key, key, ixgbe_get_rxfh_key_size(netdev)); 316262306a36Sopenharmony_ci ixgbe_store_key(adapter); 316362306a36Sopenharmony_ci } 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci return 0; 316662306a36Sopenharmony_ci} 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_cistatic int ixgbe_get_ts_info(struct net_device *dev, 316962306a36Sopenharmony_ci struct ethtool_ts_info *info) 317062306a36Sopenharmony_ci{ 317162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(dev); 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci /* we always support timestamping disabled */ 317462306a36Sopenharmony_ci info->rx_filters = BIT(HWTSTAMP_FILTER_NONE); 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 317762306a36Sopenharmony_ci case ixgbe_mac_X550: 317862306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 317962306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 318062306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL); 318162306a36Sopenharmony_ci break; 318262306a36Sopenharmony_ci case ixgbe_mac_X540: 318362306a36Sopenharmony_ci case ixgbe_mac_82599EB: 318462306a36Sopenharmony_ci info->rx_filters |= 318562306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | 318662306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | 318762306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); 318862306a36Sopenharmony_ci break; 318962306a36Sopenharmony_ci default: 319062306a36Sopenharmony_ci return ethtool_op_get_ts_info(dev, info); 319162306a36Sopenharmony_ci } 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci info->so_timestamping = 319462306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_SOFTWARE | 319562306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 319662306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 319762306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 319862306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 319962306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci if (adapter->ptp_clock) 320262306a36Sopenharmony_ci info->phc_index = ptp_clock_index(adapter->ptp_clock); 320362306a36Sopenharmony_ci else 320462306a36Sopenharmony_ci info->phc_index = -1; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci info->tx_types = 320762306a36Sopenharmony_ci BIT(HWTSTAMP_TX_OFF) | 320862306a36Sopenharmony_ci BIT(HWTSTAMP_TX_ON); 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci return 0; 321162306a36Sopenharmony_ci} 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_cistatic unsigned int ixgbe_max_channels(struct ixgbe_adapter *adapter) 321462306a36Sopenharmony_ci{ 321562306a36Sopenharmony_ci unsigned int max_combined; 321662306a36Sopenharmony_ci u8 tcs = adapter->hw_tcs; 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { 321962306a36Sopenharmony_ci /* We only support one q_vector without MSI-X */ 322062306a36Sopenharmony_ci max_combined = 1; 322162306a36Sopenharmony_ci } else if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { 322262306a36Sopenharmony_ci /* Limit value based on the queue mask */ 322362306a36Sopenharmony_ci max_combined = adapter->ring_feature[RING_F_RSS].mask + 1; 322462306a36Sopenharmony_ci } else if (tcs > 1) { 322562306a36Sopenharmony_ci /* For DCB report channels per traffic class */ 322662306a36Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 322762306a36Sopenharmony_ci /* 8 TC w/ 4 queues per TC */ 322862306a36Sopenharmony_ci max_combined = 4; 322962306a36Sopenharmony_ci } else if (tcs > 4) { 323062306a36Sopenharmony_ci /* 8 TC w/ 8 queues per TC */ 323162306a36Sopenharmony_ci max_combined = 8; 323262306a36Sopenharmony_ci } else { 323362306a36Sopenharmony_ci /* 4 TC w/ 16 queues per TC */ 323462306a36Sopenharmony_ci max_combined = 16; 323562306a36Sopenharmony_ci } 323662306a36Sopenharmony_ci } else if (adapter->atr_sample_rate) { 323762306a36Sopenharmony_ci /* support up to 64 queues with ATR */ 323862306a36Sopenharmony_ci max_combined = IXGBE_MAX_FDIR_INDICES; 323962306a36Sopenharmony_ci } else { 324062306a36Sopenharmony_ci /* support up to 16 queues with RSS */ 324162306a36Sopenharmony_ci max_combined = ixgbe_max_rss_indices(adapter); 324262306a36Sopenharmony_ci } 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci return min_t(int, max_combined, num_online_cpus()); 324562306a36Sopenharmony_ci} 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_cistatic void ixgbe_get_channels(struct net_device *dev, 324862306a36Sopenharmony_ci struct ethtool_channels *ch) 324962306a36Sopenharmony_ci{ 325062306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(dev); 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci /* report maximum channels */ 325362306a36Sopenharmony_ci ch->max_combined = ixgbe_max_channels(adapter); 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci /* report info for other vector */ 325662306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { 325762306a36Sopenharmony_ci ch->max_other = NON_Q_VECTORS; 325862306a36Sopenharmony_ci ch->other_count = NON_Q_VECTORS; 325962306a36Sopenharmony_ci } 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci /* record RSS queues */ 326262306a36Sopenharmony_ci ch->combined_count = adapter->ring_feature[RING_F_RSS].indices; 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci /* nothing else to report if RSS is disabled */ 326562306a36Sopenharmony_ci if (ch->combined_count == 1) 326662306a36Sopenharmony_ci return; 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci /* we do not support ATR queueing if SR-IOV is enabled */ 326962306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) 327062306a36Sopenharmony_ci return; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci /* same thing goes for being DCB enabled */ 327362306a36Sopenharmony_ci if (adapter->hw_tcs > 1) 327462306a36Sopenharmony_ci return; 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci /* if ATR is disabled we can exit */ 327762306a36Sopenharmony_ci if (!adapter->atr_sample_rate) 327862306a36Sopenharmony_ci return; 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci /* report flow director queues as maximum channels */ 328162306a36Sopenharmony_ci ch->combined_count = adapter->ring_feature[RING_F_FDIR].indices; 328262306a36Sopenharmony_ci} 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_cistatic int ixgbe_set_channels(struct net_device *dev, 328562306a36Sopenharmony_ci struct ethtool_channels *ch) 328662306a36Sopenharmony_ci{ 328762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(dev); 328862306a36Sopenharmony_ci unsigned int count = ch->combined_count; 328962306a36Sopenharmony_ci u8 max_rss_indices = ixgbe_max_rss_indices(adapter); 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci /* verify they are not requesting separate vectors */ 329262306a36Sopenharmony_ci if (!count || ch->rx_count || ch->tx_count) 329362306a36Sopenharmony_ci return -EINVAL; 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci /* verify other_count has not changed */ 329662306a36Sopenharmony_ci if (ch->other_count != NON_Q_VECTORS) 329762306a36Sopenharmony_ci return -EINVAL; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci /* verify the number of channels does not exceed hardware limits */ 330062306a36Sopenharmony_ci if (count > ixgbe_max_channels(adapter)) 330162306a36Sopenharmony_ci return -EINVAL; 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci /* update feature limits from largest to smallest supported values */ 330462306a36Sopenharmony_ci adapter->ring_feature[RING_F_FDIR].limit = count; 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci /* cap RSS limit */ 330762306a36Sopenharmony_ci if (count > max_rss_indices) 330862306a36Sopenharmony_ci count = max_rss_indices; 330962306a36Sopenharmony_ci adapter->ring_feature[RING_F_RSS].limit = count; 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci#ifdef IXGBE_FCOE 331262306a36Sopenharmony_ci /* cap FCoE limit at 8 */ 331362306a36Sopenharmony_ci if (count > IXGBE_FCRETA_SIZE) 331462306a36Sopenharmony_ci count = IXGBE_FCRETA_SIZE; 331562306a36Sopenharmony_ci adapter->ring_feature[RING_F_FCOE].limit = count; 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci#endif 331862306a36Sopenharmony_ci /* use setup TC to update any traffic class queue mapping */ 331962306a36Sopenharmony_ci return ixgbe_setup_tc(dev, adapter->hw_tcs); 332062306a36Sopenharmony_ci} 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_cistatic int ixgbe_get_module_info(struct net_device *dev, 332362306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 332462306a36Sopenharmony_ci{ 332562306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(dev); 332662306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 332762306a36Sopenharmony_ci s32 status; 332862306a36Sopenharmony_ci u8 sff8472_rev, addr_mode; 332962306a36Sopenharmony_ci bool page_swap = false; 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_fw) 333262306a36Sopenharmony_ci return -ENXIO; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci /* Check whether we support SFF-8472 or not */ 333562306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 333662306a36Sopenharmony_ci IXGBE_SFF_SFF_8472_COMP, 333762306a36Sopenharmony_ci &sff8472_rev); 333862306a36Sopenharmony_ci if (status) 333962306a36Sopenharmony_ci return -EIO; 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci /* addressing mode is not supported */ 334262306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 334362306a36Sopenharmony_ci IXGBE_SFF_SFF_8472_SWAP, 334462306a36Sopenharmony_ci &addr_mode); 334562306a36Sopenharmony_ci if (status) 334662306a36Sopenharmony_ci return -EIO; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) { 334962306a36Sopenharmony_ci e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n"); 335062306a36Sopenharmony_ci page_swap = true; 335162306a36Sopenharmony_ci } 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap || 335462306a36Sopenharmony_ci !(addr_mode & IXGBE_SFF_DDM_IMPLEMENTED)) { 335562306a36Sopenharmony_ci /* We have a SFP, but it does not support SFF-8472 */ 335662306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 335762306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 335862306a36Sopenharmony_ci } else { 335962306a36Sopenharmony_ci /* We have a SFP which supports a revision of SFF-8472. */ 336062306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 336162306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 336262306a36Sopenharmony_ci } 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci return 0; 336562306a36Sopenharmony_ci} 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_cistatic int ixgbe_get_module_eeprom(struct net_device *dev, 336862306a36Sopenharmony_ci struct ethtool_eeprom *ee, 336962306a36Sopenharmony_ci u8 *data) 337062306a36Sopenharmony_ci{ 337162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(dev); 337262306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 337362306a36Sopenharmony_ci s32 status = -EFAULT; 337462306a36Sopenharmony_ci u8 databyte = 0xFF; 337562306a36Sopenharmony_ci int i = 0; 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci if (ee->len == 0) 337862306a36Sopenharmony_ci return -EINVAL; 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_fw) 338162306a36Sopenharmony_ci return -ENXIO; 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci for (i = ee->offset; i < ee->offset + ee->len; i++) { 338462306a36Sopenharmony_ci /* I2C reads can take long time */ 338562306a36Sopenharmony_ci if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) 338662306a36Sopenharmony_ci return -EBUSY; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci if (i < ETH_MODULE_SFF_8079_LEN) 338962306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte); 339062306a36Sopenharmony_ci else 339162306a36Sopenharmony_ci status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte); 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci if (status) 339462306a36Sopenharmony_ci return -EIO; 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci data[i - ee->offset] = databyte; 339762306a36Sopenharmony_ci } 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci return 0; 340062306a36Sopenharmony_ci} 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_cistatic const struct { 340362306a36Sopenharmony_ci ixgbe_link_speed mac_speed; 340462306a36Sopenharmony_ci u32 supported; 340562306a36Sopenharmony_ci} ixgbe_ls_map[] = { 340662306a36Sopenharmony_ci { IXGBE_LINK_SPEED_10_FULL, SUPPORTED_10baseT_Full }, 340762306a36Sopenharmony_ci { IXGBE_LINK_SPEED_100_FULL, SUPPORTED_100baseT_Full }, 340862306a36Sopenharmony_ci { IXGBE_LINK_SPEED_1GB_FULL, SUPPORTED_1000baseT_Full }, 340962306a36Sopenharmony_ci { IXGBE_LINK_SPEED_2_5GB_FULL, SUPPORTED_2500baseX_Full }, 341062306a36Sopenharmony_ci { IXGBE_LINK_SPEED_10GB_FULL, SUPPORTED_10000baseT_Full }, 341162306a36Sopenharmony_ci}; 341262306a36Sopenharmony_ci 341362306a36Sopenharmony_cistatic const struct { 341462306a36Sopenharmony_ci u32 lp_advertised; 341562306a36Sopenharmony_ci u32 mac_speed; 341662306a36Sopenharmony_ci} ixgbe_lp_map[] = { 341762306a36Sopenharmony_ci { FW_PHY_ACT_UD_2_100M_TX_EEE, SUPPORTED_100baseT_Full }, 341862306a36Sopenharmony_ci { FW_PHY_ACT_UD_2_1G_T_EEE, SUPPORTED_1000baseT_Full }, 341962306a36Sopenharmony_ci { FW_PHY_ACT_UD_2_10G_T_EEE, SUPPORTED_10000baseT_Full }, 342062306a36Sopenharmony_ci { FW_PHY_ACT_UD_2_1G_KX_EEE, SUPPORTED_1000baseKX_Full }, 342162306a36Sopenharmony_ci { FW_PHY_ACT_UD_2_10G_KX4_EEE, SUPPORTED_10000baseKX4_Full }, 342262306a36Sopenharmony_ci { FW_PHY_ACT_UD_2_10G_KR_EEE, SUPPORTED_10000baseKR_Full}, 342362306a36Sopenharmony_ci}; 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_cistatic int 342662306a36Sopenharmony_ciixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_eee *edata) 342762306a36Sopenharmony_ci{ 342862306a36Sopenharmony_ci u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; 342962306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 343062306a36Sopenharmony_ci s32 rc; 343162306a36Sopenharmony_ci u16 i; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_UD_2, &info); 343462306a36Sopenharmony_ci if (rc) 343562306a36Sopenharmony_ci return rc; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci edata->lp_advertised = 0; 343862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ixgbe_lp_map); ++i) { 343962306a36Sopenharmony_ci if (info[0] & ixgbe_lp_map[i].lp_advertised) 344062306a36Sopenharmony_ci edata->lp_advertised |= ixgbe_lp_map[i].mac_speed; 344162306a36Sopenharmony_ci } 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci edata->supported = 0; 344462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { 344562306a36Sopenharmony_ci if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed) 344662306a36Sopenharmony_ci edata->supported |= ixgbe_ls_map[i].supported; 344762306a36Sopenharmony_ci } 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ci edata->advertised = 0; 345062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { 345162306a36Sopenharmony_ci if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed) 345262306a36Sopenharmony_ci edata->advertised |= ixgbe_ls_map[i].supported; 345362306a36Sopenharmony_ci } 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci edata->eee_enabled = !!edata->advertised; 345662306a36Sopenharmony_ci edata->tx_lpi_enabled = edata->eee_enabled; 345762306a36Sopenharmony_ci if (edata->advertised & edata->lp_advertised) 345862306a36Sopenharmony_ci edata->eee_active = true; 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci return 0; 346162306a36Sopenharmony_ci} 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_cistatic int ixgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata) 346462306a36Sopenharmony_ci{ 346562306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 346662306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 346762306a36Sopenharmony_ci 346862306a36Sopenharmony_ci if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE)) 346962306a36Sopenharmony_ci return -EOPNOTSUPP; 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci if (hw->phy.eee_speeds_supported && hw->phy.type == ixgbe_phy_fw) 347262306a36Sopenharmony_ci return ixgbe_get_eee_fw(adapter, edata); 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci return -EOPNOTSUPP; 347562306a36Sopenharmony_ci} 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_cistatic int ixgbe_set_eee(struct net_device *netdev, struct ethtool_eee *edata) 347862306a36Sopenharmony_ci{ 347962306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 348062306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 348162306a36Sopenharmony_ci struct ethtool_eee eee_data; 348262306a36Sopenharmony_ci s32 ret_val; 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE)) 348562306a36Sopenharmony_ci return -EOPNOTSUPP; 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ci memset(&eee_data, 0, sizeof(struct ethtool_eee)); 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci ret_val = ixgbe_get_eee(netdev, &eee_data); 349062306a36Sopenharmony_ci if (ret_val) 349162306a36Sopenharmony_ci return ret_val; 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci if (eee_data.eee_enabled && !edata->eee_enabled) { 349462306a36Sopenharmony_ci if (eee_data.tx_lpi_enabled != edata->tx_lpi_enabled) { 349562306a36Sopenharmony_ci e_err(drv, "Setting EEE tx-lpi is not supported\n"); 349662306a36Sopenharmony_ci return -EINVAL; 349762306a36Sopenharmony_ci } 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci if (eee_data.tx_lpi_timer != edata->tx_lpi_timer) { 350062306a36Sopenharmony_ci e_err(drv, 350162306a36Sopenharmony_ci "Setting EEE Tx LPI timer is not supported\n"); 350262306a36Sopenharmony_ci return -EINVAL; 350362306a36Sopenharmony_ci } 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci if (eee_data.advertised != edata->advertised) { 350662306a36Sopenharmony_ci e_err(drv, 350762306a36Sopenharmony_ci "Setting EEE advertised speeds is not supported\n"); 350862306a36Sopenharmony_ci return -EINVAL; 350962306a36Sopenharmony_ci } 351062306a36Sopenharmony_ci } 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci if (eee_data.eee_enabled != edata->eee_enabled) { 351362306a36Sopenharmony_ci if (edata->eee_enabled) { 351462306a36Sopenharmony_ci adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED; 351562306a36Sopenharmony_ci hw->phy.eee_speeds_advertised = 351662306a36Sopenharmony_ci hw->phy.eee_speeds_supported; 351762306a36Sopenharmony_ci } else { 351862306a36Sopenharmony_ci adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED; 351962306a36Sopenharmony_ci hw->phy.eee_speeds_advertised = 0; 352062306a36Sopenharmony_ci } 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_ci /* reset link */ 352362306a36Sopenharmony_ci if (netif_running(netdev)) 352462306a36Sopenharmony_ci ixgbe_reinit_locked(adapter); 352562306a36Sopenharmony_ci else 352662306a36Sopenharmony_ci ixgbe_reset(adapter); 352762306a36Sopenharmony_ci } 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci return 0; 353062306a36Sopenharmony_ci} 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_cistatic u32 ixgbe_get_priv_flags(struct net_device *netdev) 353362306a36Sopenharmony_ci{ 353462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 353562306a36Sopenharmony_ci u32 priv_flags = 0; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci if (adapter->flags2 & IXGBE_FLAG2_RX_LEGACY) 353862306a36Sopenharmony_ci priv_flags |= IXGBE_PRIV_FLAGS_LEGACY_RX; 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci if (adapter->flags2 & IXGBE_FLAG2_VF_IPSEC_ENABLED) 354162306a36Sopenharmony_ci priv_flags |= IXGBE_PRIV_FLAGS_VF_IPSEC_EN; 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci if (adapter->flags2 & IXGBE_FLAG2_AUTO_DISABLE_VF) 354462306a36Sopenharmony_ci priv_flags |= IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF; 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci return priv_flags; 354762306a36Sopenharmony_ci} 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_cistatic int ixgbe_set_priv_flags(struct net_device *netdev, u32 priv_flags) 355062306a36Sopenharmony_ci{ 355162306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 355262306a36Sopenharmony_ci unsigned int flags2 = adapter->flags2; 355362306a36Sopenharmony_ci unsigned int i; 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci flags2 &= ~IXGBE_FLAG2_RX_LEGACY; 355662306a36Sopenharmony_ci if (priv_flags & IXGBE_PRIV_FLAGS_LEGACY_RX) 355762306a36Sopenharmony_ci flags2 |= IXGBE_FLAG2_RX_LEGACY; 355862306a36Sopenharmony_ci 355962306a36Sopenharmony_ci flags2 &= ~IXGBE_FLAG2_VF_IPSEC_ENABLED; 356062306a36Sopenharmony_ci if (priv_flags & IXGBE_PRIV_FLAGS_VF_IPSEC_EN) 356162306a36Sopenharmony_ci flags2 |= IXGBE_FLAG2_VF_IPSEC_ENABLED; 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_ci flags2 &= ~IXGBE_FLAG2_AUTO_DISABLE_VF; 356462306a36Sopenharmony_ci if (priv_flags & IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF) { 356562306a36Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_82599EB) { 356662306a36Sopenharmony_ci /* Reset primary abort counter */ 356762306a36Sopenharmony_ci for (i = 0; i < adapter->num_vfs; i++) 356862306a36Sopenharmony_ci adapter->vfinfo[i].primary_abort_count = 0; 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF; 357162306a36Sopenharmony_ci } else { 357262306a36Sopenharmony_ci e_info(probe, 357362306a36Sopenharmony_ci "Cannot set private flags: Operation not supported\n"); 357462306a36Sopenharmony_ci return -EOPNOTSUPP; 357562306a36Sopenharmony_ci } 357662306a36Sopenharmony_ci } 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci if (flags2 != adapter->flags2) { 357962306a36Sopenharmony_ci adapter->flags2 = flags2; 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci /* reset interface to repopulate queues */ 358262306a36Sopenharmony_ci if (netif_running(netdev)) 358362306a36Sopenharmony_ci ixgbe_reinit_locked(adapter); 358462306a36Sopenharmony_ci } 358562306a36Sopenharmony_ci 358662306a36Sopenharmony_ci return 0; 358762306a36Sopenharmony_ci} 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_cistatic const struct ethtool_ops ixgbe_ethtool_ops = { 359062306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 359162306a36Sopenharmony_ci .get_drvinfo = ixgbe_get_drvinfo, 359262306a36Sopenharmony_ci .get_regs_len = ixgbe_get_regs_len, 359362306a36Sopenharmony_ci .get_regs = ixgbe_get_regs, 359462306a36Sopenharmony_ci .get_wol = ixgbe_get_wol, 359562306a36Sopenharmony_ci .set_wol = ixgbe_set_wol, 359662306a36Sopenharmony_ci .nway_reset = ixgbe_nway_reset, 359762306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 359862306a36Sopenharmony_ci .get_eeprom_len = ixgbe_get_eeprom_len, 359962306a36Sopenharmony_ci .get_eeprom = ixgbe_get_eeprom, 360062306a36Sopenharmony_ci .set_eeprom = ixgbe_set_eeprom, 360162306a36Sopenharmony_ci .get_ringparam = ixgbe_get_ringparam, 360262306a36Sopenharmony_ci .set_ringparam = ixgbe_set_ringparam, 360362306a36Sopenharmony_ci .get_pause_stats = ixgbe_get_pause_stats, 360462306a36Sopenharmony_ci .get_pauseparam = ixgbe_get_pauseparam, 360562306a36Sopenharmony_ci .set_pauseparam = ixgbe_set_pauseparam, 360662306a36Sopenharmony_ci .get_msglevel = ixgbe_get_msglevel, 360762306a36Sopenharmony_ci .set_msglevel = ixgbe_set_msglevel, 360862306a36Sopenharmony_ci .self_test = ixgbe_diag_test, 360962306a36Sopenharmony_ci .get_strings = ixgbe_get_strings, 361062306a36Sopenharmony_ci .set_phys_id = ixgbe_set_phys_id, 361162306a36Sopenharmony_ci .get_sset_count = ixgbe_get_sset_count, 361262306a36Sopenharmony_ci .get_ethtool_stats = ixgbe_get_ethtool_stats, 361362306a36Sopenharmony_ci .get_coalesce = ixgbe_get_coalesce, 361462306a36Sopenharmony_ci .set_coalesce = ixgbe_set_coalesce, 361562306a36Sopenharmony_ci .get_rxnfc = ixgbe_get_rxnfc, 361662306a36Sopenharmony_ci .set_rxnfc = ixgbe_set_rxnfc, 361762306a36Sopenharmony_ci .get_rxfh_indir_size = ixgbe_rss_indir_size, 361862306a36Sopenharmony_ci .get_rxfh_key_size = ixgbe_get_rxfh_key_size, 361962306a36Sopenharmony_ci .get_rxfh = ixgbe_get_rxfh, 362062306a36Sopenharmony_ci .set_rxfh = ixgbe_set_rxfh, 362162306a36Sopenharmony_ci .get_eee = ixgbe_get_eee, 362262306a36Sopenharmony_ci .set_eee = ixgbe_set_eee, 362362306a36Sopenharmony_ci .get_channels = ixgbe_get_channels, 362462306a36Sopenharmony_ci .set_channels = ixgbe_set_channels, 362562306a36Sopenharmony_ci .get_priv_flags = ixgbe_get_priv_flags, 362662306a36Sopenharmony_ci .set_priv_flags = ixgbe_set_priv_flags, 362762306a36Sopenharmony_ci .get_ts_info = ixgbe_get_ts_info, 362862306a36Sopenharmony_ci .get_module_info = ixgbe_get_module_info, 362962306a36Sopenharmony_ci .get_module_eeprom = ixgbe_get_module_eeprom, 363062306a36Sopenharmony_ci .get_link_ksettings = ixgbe_get_link_ksettings, 363162306a36Sopenharmony_ci .set_link_ksettings = ixgbe_set_link_ksettings, 363262306a36Sopenharmony_ci}; 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_civoid ixgbe_set_ethtool_ops(struct net_device *netdev) 363562306a36Sopenharmony_ci{ 363662306a36Sopenharmony_ci netdev->ethtool_ops = &ixgbe_ethtool_ops; 363762306a36Sopenharmony_ci} 3638