162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2007 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* ethtool support for igb */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/vmalloc.h> 762306a36Sopenharmony_ci#include <linux/netdevice.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/if_ether.h> 1262306a36Sopenharmony_ci#include <linux/ethtool.h> 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci#include <linux/highmem.h> 1762306a36Sopenharmony_ci#include <linux/mdio.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "igb.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct igb_stats { 2262306a36Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 2362306a36Sopenharmony_ci int sizeof_stat; 2462306a36Sopenharmony_ci int stat_offset; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define IGB_STAT(_name, _stat) { \ 2862306a36Sopenharmony_ci .stat_string = _name, \ 2962306a36Sopenharmony_ci .sizeof_stat = sizeof_field(struct igb_adapter, _stat), \ 3062306a36Sopenharmony_ci .stat_offset = offsetof(struct igb_adapter, _stat) \ 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_cistatic const struct igb_stats igb_gstrings_stats[] = { 3362306a36Sopenharmony_ci IGB_STAT("rx_packets", stats.gprc), 3462306a36Sopenharmony_ci IGB_STAT("tx_packets", stats.gptc), 3562306a36Sopenharmony_ci IGB_STAT("rx_bytes", stats.gorc), 3662306a36Sopenharmony_ci IGB_STAT("tx_bytes", stats.gotc), 3762306a36Sopenharmony_ci IGB_STAT("rx_broadcast", stats.bprc), 3862306a36Sopenharmony_ci IGB_STAT("tx_broadcast", stats.bptc), 3962306a36Sopenharmony_ci IGB_STAT("rx_multicast", stats.mprc), 4062306a36Sopenharmony_ci IGB_STAT("tx_multicast", stats.mptc), 4162306a36Sopenharmony_ci IGB_STAT("multicast", stats.mprc), 4262306a36Sopenharmony_ci IGB_STAT("collisions", stats.colc), 4362306a36Sopenharmony_ci IGB_STAT("rx_crc_errors", stats.crcerrs), 4462306a36Sopenharmony_ci IGB_STAT("rx_no_buffer_count", stats.rnbc), 4562306a36Sopenharmony_ci IGB_STAT("rx_missed_errors", stats.mpc), 4662306a36Sopenharmony_ci IGB_STAT("tx_aborted_errors", stats.ecol), 4762306a36Sopenharmony_ci IGB_STAT("tx_carrier_errors", stats.tncrs), 4862306a36Sopenharmony_ci IGB_STAT("tx_window_errors", stats.latecol), 4962306a36Sopenharmony_ci IGB_STAT("tx_abort_late_coll", stats.latecol), 5062306a36Sopenharmony_ci IGB_STAT("tx_deferred_ok", stats.dc), 5162306a36Sopenharmony_ci IGB_STAT("tx_single_coll_ok", stats.scc), 5262306a36Sopenharmony_ci IGB_STAT("tx_multi_coll_ok", stats.mcc), 5362306a36Sopenharmony_ci IGB_STAT("tx_timeout_count", tx_timeout_count), 5462306a36Sopenharmony_ci IGB_STAT("rx_long_length_errors", stats.roc), 5562306a36Sopenharmony_ci IGB_STAT("rx_short_length_errors", stats.ruc), 5662306a36Sopenharmony_ci IGB_STAT("rx_align_errors", stats.algnerrc), 5762306a36Sopenharmony_ci IGB_STAT("tx_tcp_seg_good", stats.tsctc), 5862306a36Sopenharmony_ci IGB_STAT("tx_tcp_seg_failed", stats.tsctfc), 5962306a36Sopenharmony_ci IGB_STAT("rx_flow_control_xon", stats.xonrxc), 6062306a36Sopenharmony_ci IGB_STAT("rx_flow_control_xoff", stats.xoffrxc), 6162306a36Sopenharmony_ci IGB_STAT("tx_flow_control_xon", stats.xontxc), 6262306a36Sopenharmony_ci IGB_STAT("tx_flow_control_xoff", stats.xofftxc), 6362306a36Sopenharmony_ci IGB_STAT("rx_long_byte_count", stats.gorc), 6462306a36Sopenharmony_ci IGB_STAT("tx_dma_out_of_sync", stats.doosync), 6562306a36Sopenharmony_ci IGB_STAT("tx_smbus", stats.mgptc), 6662306a36Sopenharmony_ci IGB_STAT("rx_smbus", stats.mgprc), 6762306a36Sopenharmony_ci IGB_STAT("dropped_smbus", stats.mgpdc), 6862306a36Sopenharmony_ci IGB_STAT("os2bmc_rx_by_bmc", stats.o2bgptc), 6962306a36Sopenharmony_ci IGB_STAT("os2bmc_tx_by_bmc", stats.b2ospc), 7062306a36Sopenharmony_ci IGB_STAT("os2bmc_tx_by_host", stats.o2bspc), 7162306a36Sopenharmony_ci IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc), 7262306a36Sopenharmony_ci IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), 7362306a36Sopenharmony_ci IGB_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), 7462306a36Sopenharmony_ci IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define IGB_NETDEV_STAT(_net_stat) { \ 7862306a36Sopenharmony_ci .stat_string = __stringify(_net_stat), \ 7962306a36Sopenharmony_ci .sizeof_stat = sizeof_field(struct rtnl_link_stats64, _net_stat), \ 8062306a36Sopenharmony_ci .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \ 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_cistatic const struct igb_stats igb_gstrings_net_stats[] = { 8362306a36Sopenharmony_ci IGB_NETDEV_STAT(rx_errors), 8462306a36Sopenharmony_ci IGB_NETDEV_STAT(tx_errors), 8562306a36Sopenharmony_ci IGB_NETDEV_STAT(tx_dropped), 8662306a36Sopenharmony_ci IGB_NETDEV_STAT(rx_length_errors), 8762306a36Sopenharmony_ci IGB_NETDEV_STAT(rx_over_errors), 8862306a36Sopenharmony_ci IGB_NETDEV_STAT(rx_frame_errors), 8962306a36Sopenharmony_ci IGB_NETDEV_STAT(rx_fifo_errors), 9062306a36Sopenharmony_ci IGB_NETDEV_STAT(tx_fifo_errors), 9162306a36Sopenharmony_ci IGB_NETDEV_STAT(tx_heartbeat_errors) 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define IGB_GLOBAL_STATS_LEN \ 9562306a36Sopenharmony_ci (sizeof(igb_gstrings_stats) / sizeof(struct igb_stats)) 9662306a36Sopenharmony_ci#define IGB_NETDEV_STATS_LEN \ 9762306a36Sopenharmony_ci (sizeof(igb_gstrings_net_stats) / sizeof(struct igb_stats)) 9862306a36Sopenharmony_ci#define IGB_RX_QUEUE_STATS_LEN \ 9962306a36Sopenharmony_ci (sizeof(struct igb_rx_queue_stats) / sizeof(u64)) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define IGB_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define IGB_QUEUE_STATS_LEN \ 10462306a36Sopenharmony_ci ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues * \ 10562306a36Sopenharmony_ci IGB_RX_QUEUE_STATS_LEN) + \ 10662306a36Sopenharmony_ci (((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues * \ 10762306a36Sopenharmony_ci IGB_TX_QUEUE_STATS_LEN)) 10862306a36Sopenharmony_ci#define IGB_STATS_LEN \ 10962306a36Sopenharmony_ci (IGB_GLOBAL_STATS_LEN + IGB_NETDEV_STATS_LEN + IGB_QUEUE_STATS_LEN) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cienum igb_diagnostics_results { 11262306a36Sopenharmony_ci TEST_REG = 0, 11362306a36Sopenharmony_ci TEST_EEP, 11462306a36Sopenharmony_ci TEST_IRQ, 11562306a36Sopenharmony_ci TEST_LOOP, 11662306a36Sopenharmony_ci TEST_LINK 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic const char igb_gstrings_test[][ETH_GSTRING_LEN] = { 12062306a36Sopenharmony_ci [TEST_REG] = "Register test (offline)", 12162306a36Sopenharmony_ci [TEST_EEP] = "Eeprom test (offline)", 12262306a36Sopenharmony_ci [TEST_IRQ] = "Interrupt test (offline)", 12362306a36Sopenharmony_ci [TEST_LOOP] = "Loopback test (offline)", 12462306a36Sopenharmony_ci [TEST_LINK] = "Link test (on/offline)" 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci#define IGB_TEST_LEN (sizeof(igb_gstrings_test) / ETH_GSTRING_LEN) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic const char igb_priv_flags_strings[][ETH_GSTRING_LEN] = { 12962306a36Sopenharmony_ci#define IGB_PRIV_FLAGS_LEGACY_RX BIT(0) 13062306a36Sopenharmony_ci "legacy-rx", 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define IGB_PRIV_FLAGS_STR_LEN ARRAY_SIZE(igb_priv_flags_strings) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int igb_get_link_ksettings(struct net_device *netdev, 13662306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 13962306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 14062306a36Sopenharmony_ci struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; 14162306a36Sopenharmony_ci struct e1000_sfp_flags *eth_flags = &dev_spec->eth_flags; 14262306a36Sopenharmony_ci u32 status; 14362306a36Sopenharmony_ci u32 speed; 14462306a36Sopenharmony_ci u32 supported, advertising; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci status = pm_runtime_suspended(&adapter->pdev->dev) ? 14762306a36Sopenharmony_ci 0 : rd32(E1000_STATUS); 14862306a36Sopenharmony_ci if (hw->phy.media_type == e1000_media_type_copper) { 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci supported = (SUPPORTED_10baseT_Half | 15162306a36Sopenharmony_ci SUPPORTED_10baseT_Full | 15262306a36Sopenharmony_ci SUPPORTED_100baseT_Half | 15362306a36Sopenharmony_ci SUPPORTED_100baseT_Full | 15462306a36Sopenharmony_ci SUPPORTED_1000baseT_Full| 15562306a36Sopenharmony_ci SUPPORTED_Autoneg | 15662306a36Sopenharmony_ci SUPPORTED_TP | 15762306a36Sopenharmony_ci SUPPORTED_Pause); 15862306a36Sopenharmony_ci advertising = ADVERTISED_TP; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (hw->mac.autoneg == 1) { 16162306a36Sopenharmony_ci advertising |= ADVERTISED_Autoneg; 16262306a36Sopenharmony_ci /* the e1000 autoneg seems to match ethtool nicely */ 16362306a36Sopenharmony_ci advertising |= hw->phy.autoneg_advertised; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci cmd->base.port = PORT_TP; 16762306a36Sopenharmony_ci cmd->base.phy_address = hw->phy.addr; 16862306a36Sopenharmony_ci } else { 16962306a36Sopenharmony_ci supported = (SUPPORTED_FIBRE | 17062306a36Sopenharmony_ci SUPPORTED_1000baseKX_Full | 17162306a36Sopenharmony_ci SUPPORTED_Autoneg | 17262306a36Sopenharmony_ci SUPPORTED_Pause); 17362306a36Sopenharmony_ci advertising = (ADVERTISED_FIBRE | 17462306a36Sopenharmony_ci ADVERTISED_1000baseKX_Full); 17562306a36Sopenharmony_ci if (hw->mac.type == e1000_i354) { 17662306a36Sopenharmony_ci if ((hw->device_id == 17762306a36Sopenharmony_ci E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) && 17862306a36Sopenharmony_ci !(status & E1000_STATUS_2P5_SKU_OVER)) { 17962306a36Sopenharmony_ci supported |= SUPPORTED_2500baseX_Full; 18062306a36Sopenharmony_ci supported &= ~SUPPORTED_1000baseKX_Full; 18162306a36Sopenharmony_ci advertising |= ADVERTISED_2500baseX_Full; 18262306a36Sopenharmony_ci advertising &= ~ADVERTISED_1000baseKX_Full; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) { 18662306a36Sopenharmony_ci supported |= SUPPORTED_100baseT_Full; 18762306a36Sopenharmony_ci advertising |= ADVERTISED_100baseT_Full; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci if (hw->mac.autoneg == 1) 19062306a36Sopenharmony_ci advertising |= ADVERTISED_Autoneg; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci if (hw->mac.autoneg != 1) 19562306a36Sopenharmony_ci advertising &= ~(ADVERTISED_Pause | 19662306a36Sopenharmony_ci ADVERTISED_Asym_Pause); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci switch (hw->fc.requested_mode) { 19962306a36Sopenharmony_ci case e1000_fc_full: 20062306a36Sopenharmony_ci advertising |= ADVERTISED_Pause; 20162306a36Sopenharmony_ci break; 20262306a36Sopenharmony_ci case e1000_fc_rx_pause: 20362306a36Sopenharmony_ci advertising |= (ADVERTISED_Pause | 20462306a36Sopenharmony_ci ADVERTISED_Asym_Pause); 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci case e1000_fc_tx_pause: 20762306a36Sopenharmony_ci advertising |= ADVERTISED_Asym_Pause; 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci default: 21062306a36Sopenharmony_ci advertising &= ~(ADVERTISED_Pause | 21162306a36Sopenharmony_ci ADVERTISED_Asym_Pause); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci if (status & E1000_STATUS_LU) { 21462306a36Sopenharmony_ci if ((status & E1000_STATUS_2P5_SKU) && 21562306a36Sopenharmony_ci !(status & E1000_STATUS_2P5_SKU_OVER)) { 21662306a36Sopenharmony_ci speed = SPEED_2500; 21762306a36Sopenharmony_ci } else if (status & E1000_STATUS_SPEED_1000) { 21862306a36Sopenharmony_ci speed = SPEED_1000; 21962306a36Sopenharmony_ci } else if (status & E1000_STATUS_SPEED_100) { 22062306a36Sopenharmony_ci speed = SPEED_100; 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci speed = SPEED_10; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci if ((status & E1000_STATUS_FD) || 22562306a36Sopenharmony_ci hw->phy.media_type != e1000_media_type_copper) 22662306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_HALF; 22962306a36Sopenharmony_ci } else { 23062306a36Sopenharmony_ci speed = SPEED_UNKNOWN; 23162306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci cmd->base.speed = speed; 23462306a36Sopenharmony_ci if ((hw->phy.media_type == e1000_media_type_fiber) || 23562306a36Sopenharmony_ci hw->mac.autoneg) 23662306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 23762306a36Sopenharmony_ci else 23862306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* MDI-X => 2; MDI =>1; Invalid =>0 */ 24162306a36Sopenharmony_ci if (hw->phy.media_type == e1000_media_type_copper) 24262306a36Sopenharmony_ci cmd->base.eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : 24362306a36Sopenharmony_ci ETH_TP_MDI; 24462306a36Sopenharmony_ci else 24562306a36Sopenharmony_ci cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (hw->phy.mdix == AUTO_ALL_MODES) 24862306a36Sopenharmony_ci cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; 24962306a36Sopenharmony_ci else 25062306a36Sopenharmony_ci cmd->base.eth_tp_mdix_ctrl = hw->phy.mdix; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 25362306a36Sopenharmony_ci supported); 25462306a36Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 25562306a36Sopenharmony_ci advertising); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return 0; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int igb_set_link_ksettings(struct net_device *netdev, 26162306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 26462306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 26562306a36Sopenharmony_ci u32 advertising; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* When SoL/IDER sessions are active, autoneg/speed/duplex 26862306a36Sopenharmony_ci * cannot be changed 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci if (igb_check_reset_block(hw)) { 27162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 27262306a36Sopenharmony_ci "Cannot change link characteristics when SoL/IDER is active.\n"); 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* MDI setting is only allowed when autoneg enabled because 27762306a36Sopenharmony_ci * some hardware doesn't allow MDI setting when speed or 27862306a36Sopenharmony_ci * duplex is forced. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci if (cmd->base.eth_tp_mdix_ctrl) { 28162306a36Sopenharmony_ci if (hw->phy.media_type != e1000_media_type_copper) 28262306a36Sopenharmony_ci return -EOPNOTSUPP; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if ((cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) && 28562306a36Sopenharmony_ci (cmd->base.autoneg != AUTONEG_ENABLE)) { 28662306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); 28762306a36Sopenharmony_ci return -EINVAL; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) 29262306a36Sopenharmony_ci usleep_range(1000, 2000); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32(&advertising, 29562306a36Sopenharmony_ci cmd->link_modes.advertising); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (cmd->base.autoneg == AUTONEG_ENABLE) { 29862306a36Sopenharmony_ci hw->mac.autoneg = 1; 29962306a36Sopenharmony_ci if (hw->phy.media_type == e1000_media_type_fiber) { 30062306a36Sopenharmony_ci hw->phy.autoneg_advertised = advertising | 30162306a36Sopenharmony_ci ADVERTISED_FIBRE | 30262306a36Sopenharmony_ci ADVERTISED_Autoneg; 30362306a36Sopenharmony_ci switch (adapter->link_speed) { 30462306a36Sopenharmony_ci case SPEED_2500: 30562306a36Sopenharmony_ci hw->phy.autoneg_advertised = 30662306a36Sopenharmony_ci ADVERTISED_2500baseX_Full; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci case SPEED_1000: 30962306a36Sopenharmony_ci hw->phy.autoneg_advertised = 31062306a36Sopenharmony_ci ADVERTISED_1000baseT_Full; 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci case SPEED_100: 31362306a36Sopenharmony_ci hw->phy.autoneg_advertised = 31462306a36Sopenharmony_ci ADVERTISED_100baseT_Full; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci default: 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci } else { 32062306a36Sopenharmony_ci hw->phy.autoneg_advertised = advertising | 32162306a36Sopenharmony_ci ADVERTISED_TP | 32262306a36Sopenharmony_ci ADVERTISED_Autoneg; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci advertising = hw->phy.autoneg_advertised; 32562306a36Sopenharmony_ci if (adapter->fc_autoneg) 32662306a36Sopenharmony_ci hw->fc.requested_mode = e1000_fc_default; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci u32 speed = cmd->base.speed; 32962306a36Sopenharmony_ci /* calling this overrides forced MDI setting */ 33062306a36Sopenharmony_ci if (igb_set_spd_dplx(adapter, speed, cmd->base.duplex)) { 33162306a36Sopenharmony_ci clear_bit(__IGB_RESETTING, &adapter->state); 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* MDI-X => 2; MDI => 1; Auto => 3 */ 33762306a36Sopenharmony_ci if (cmd->base.eth_tp_mdix_ctrl) { 33862306a36Sopenharmony_ci /* fix up the value for auto (3 => 0) as zero is mapped 33962306a36Sopenharmony_ci * internally to auto 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci if (cmd->base.eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) 34262306a36Sopenharmony_ci hw->phy.mdix = AUTO_ALL_MODES; 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci hw->phy.mdix = cmd->base.eth_tp_mdix_ctrl; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* reset the link */ 34862306a36Sopenharmony_ci if (netif_running(adapter->netdev)) { 34962306a36Sopenharmony_ci igb_down(adapter); 35062306a36Sopenharmony_ci igb_up(adapter); 35162306a36Sopenharmony_ci } else 35262306a36Sopenharmony_ci igb_reset(adapter); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci clear_bit(__IGB_RESETTING, &adapter->state); 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic u32 igb_get_link(struct net_device *netdev) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 36162306a36Sopenharmony_ci struct e1000_mac_info *mac = &adapter->hw.mac; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* If the link is not reported up to netdev, interrupts are disabled, 36462306a36Sopenharmony_ci * and so the physical link state may have changed since we last 36562306a36Sopenharmony_ci * looked. Set get_link_status to make sure that the true link 36662306a36Sopenharmony_ci * state is interrogated, rather than pulling a cached and possibly 36762306a36Sopenharmony_ci * stale link state from the driver. 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if (!netif_carrier_ok(netdev)) 37062306a36Sopenharmony_ci mac->get_link_status = 1; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return igb_has_link(adapter); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic void igb_get_pauseparam(struct net_device *netdev, 37662306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 37962306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci pause->autoneg = 38262306a36Sopenharmony_ci (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (hw->fc.current_mode == e1000_fc_rx_pause) 38562306a36Sopenharmony_ci pause->rx_pause = 1; 38662306a36Sopenharmony_ci else if (hw->fc.current_mode == e1000_fc_tx_pause) 38762306a36Sopenharmony_ci pause->tx_pause = 1; 38862306a36Sopenharmony_ci else if (hw->fc.current_mode == e1000_fc_full) { 38962306a36Sopenharmony_ci pause->rx_pause = 1; 39062306a36Sopenharmony_ci pause->tx_pause = 1; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int igb_set_pauseparam(struct net_device *netdev, 39562306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 39862306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 39962306a36Sopenharmony_ci int retval = 0; 40062306a36Sopenharmony_ci int i; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* 100basefx does not support setting link flow control */ 40362306a36Sopenharmony_ci if (hw->dev_spec._82575.eth_flags.e100_base_fx) 40462306a36Sopenharmony_ci return -EINVAL; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci adapter->fc_autoneg = pause->autoneg; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) 40962306a36Sopenharmony_ci usleep_range(1000, 2000); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (adapter->fc_autoneg == AUTONEG_ENABLE) { 41262306a36Sopenharmony_ci hw->fc.requested_mode = e1000_fc_default; 41362306a36Sopenharmony_ci if (netif_running(adapter->netdev)) { 41462306a36Sopenharmony_ci igb_down(adapter); 41562306a36Sopenharmony_ci igb_up(adapter); 41662306a36Sopenharmony_ci } else { 41762306a36Sopenharmony_ci igb_reset(adapter); 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } else { 42062306a36Sopenharmony_ci if (pause->rx_pause && pause->tx_pause) 42162306a36Sopenharmony_ci hw->fc.requested_mode = e1000_fc_full; 42262306a36Sopenharmony_ci else if (pause->rx_pause && !pause->tx_pause) 42362306a36Sopenharmony_ci hw->fc.requested_mode = e1000_fc_rx_pause; 42462306a36Sopenharmony_ci else if (!pause->rx_pause && pause->tx_pause) 42562306a36Sopenharmony_ci hw->fc.requested_mode = e1000_fc_tx_pause; 42662306a36Sopenharmony_ci else if (!pause->rx_pause && !pause->tx_pause) 42762306a36Sopenharmony_ci hw->fc.requested_mode = e1000_fc_none; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci hw->fc.current_mode = hw->fc.requested_mode; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci retval = ((hw->phy.media_type == e1000_media_type_copper) ? 43262306a36Sopenharmony_ci igb_force_mac_fc(hw) : igb_setup_link(hw)); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Make sure SRRCTL considers new fc settings for each ring */ 43562306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 43662306a36Sopenharmony_ci struct igb_ring *ring = adapter->rx_ring[i]; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci igb_setup_srrctl(adapter, ring); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci clear_bit(__IGB_RESETTING, &adapter->state); 44362306a36Sopenharmony_ci return retval; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic u32 igb_get_msglevel(struct net_device *netdev) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 44962306a36Sopenharmony_ci return adapter->msg_enable; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic void igb_set_msglevel(struct net_device *netdev, u32 data) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 45562306a36Sopenharmony_ci adapter->msg_enable = data; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int igb_get_regs_len(struct net_device *netdev) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci#define IGB_REGS_LEN 740 46162306a36Sopenharmony_ci return IGB_REGS_LEN * sizeof(u32); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic void igb_get_regs(struct net_device *netdev, 46562306a36Sopenharmony_ci struct ethtool_regs *regs, void *p) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 46862306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 46962306a36Sopenharmony_ci u32 *regs_buff = p; 47062306a36Sopenharmony_ci u8 i; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci memset(p, 0, IGB_REGS_LEN * sizeof(u32)); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci regs->version = (1u << 24) | (hw->revision_id << 16) | hw->device_id; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* General Registers */ 47762306a36Sopenharmony_ci regs_buff[0] = rd32(E1000_CTRL); 47862306a36Sopenharmony_ci regs_buff[1] = rd32(E1000_STATUS); 47962306a36Sopenharmony_ci regs_buff[2] = rd32(E1000_CTRL_EXT); 48062306a36Sopenharmony_ci regs_buff[3] = rd32(E1000_MDIC); 48162306a36Sopenharmony_ci regs_buff[4] = rd32(E1000_SCTL); 48262306a36Sopenharmony_ci regs_buff[5] = rd32(E1000_CONNSW); 48362306a36Sopenharmony_ci regs_buff[6] = rd32(E1000_VET); 48462306a36Sopenharmony_ci regs_buff[7] = rd32(E1000_LEDCTL); 48562306a36Sopenharmony_ci regs_buff[8] = rd32(E1000_PBA); 48662306a36Sopenharmony_ci regs_buff[9] = rd32(E1000_PBS); 48762306a36Sopenharmony_ci regs_buff[10] = rd32(E1000_FRTIMER); 48862306a36Sopenharmony_ci regs_buff[11] = rd32(E1000_TCPTIMER); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* NVM Register */ 49162306a36Sopenharmony_ci regs_buff[12] = rd32(E1000_EECD); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Interrupt */ 49462306a36Sopenharmony_ci /* Reading EICS for EICR because they read the 49562306a36Sopenharmony_ci * same but EICS does not clear on read 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci regs_buff[13] = rd32(E1000_EICS); 49862306a36Sopenharmony_ci regs_buff[14] = rd32(E1000_EICS); 49962306a36Sopenharmony_ci regs_buff[15] = rd32(E1000_EIMS); 50062306a36Sopenharmony_ci regs_buff[16] = rd32(E1000_EIMC); 50162306a36Sopenharmony_ci regs_buff[17] = rd32(E1000_EIAC); 50262306a36Sopenharmony_ci regs_buff[18] = rd32(E1000_EIAM); 50362306a36Sopenharmony_ci /* Reading ICS for ICR because they read the 50462306a36Sopenharmony_ci * same but ICS does not clear on read 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci regs_buff[19] = rd32(E1000_ICS); 50762306a36Sopenharmony_ci regs_buff[20] = rd32(E1000_ICS); 50862306a36Sopenharmony_ci regs_buff[21] = rd32(E1000_IMS); 50962306a36Sopenharmony_ci regs_buff[22] = rd32(E1000_IMC); 51062306a36Sopenharmony_ci regs_buff[23] = rd32(E1000_IAC); 51162306a36Sopenharmony_ci regs_buff[24] = rd32(E1000_IAM); 51262306a36Sopenharmony_ci regs_buff[25] = rd32(E1000_IMIRVP); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Flow Control */ 51562306a36Sopenharmony_ci regs_buff[26] = rd32(E1000_FCAL); 51662306a36Sopenharmony_ci regs_buff[27] = rd32(E1000_FCAH); 51762306a36Sopenharmony_ci regs_buff[28] = rd32(E1000_FCTTV); 51862306a36Sopenharmony_ci regs_buff[29] = rd32(E1000_FCRTL); 51962306a36Sopenharmony_ci regs_buff[30] = rd32(E1000_FCRTH); 52062306a36Sopenharmony_ci regs_buff[31] = rd32(E1000_FCRTV); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Receive */ 52362306a36Sopenharmony_ci regs_buff[32] = rd32(E1000_RCTL); 52462306a36Sopenharmony_ci regs_buff[33] = rd32(E1000_RXCSUM); 52562306a36Sopenharmony_ci regs_buff[34] = rd32(E1000_RLPML); 52662306a36Sopenharmony_ci regs_buff[35] = rd32(E1000_RFCTL); 52762306a36Sopenharmony_ci regs_buff[36] = rd32(E1000_MRQC); 52862306a36Sopenharmony_ci regs_buff[37] = rd32(E1000_VT_CTL); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Transmit */ 53162306a36Sopenharmony_ci regs_buff[38] = rd32(E1000_TCTL); 53262306a36Sopenharmony_ci regs_buff[39] = rd32(E1000_TCTL_EXT); 53362306a36Sopenharmony_ci regs_buff[40] = rd32(E1000_TIPG); 53462306a36Sopenharmony_ci regs_buff[41] = rd32(E1000_DTXCTL); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Wake Up */ 53762306a36Sopenharmony_ci regs_buff[42] = rd32(E1000_WUC); 53862306a36Sopenharmony_ci regs_buff[43] = rd32(E1000_WUFC); 53962306a36Sopenharmony_ci regs_buff[44] = rd32(E1000_WUS); 54062306a36Sopenharmony_ci regs_buff[45] = rd32(E1000_IPAV); 54162306a36Sopenharmony_ci regs_buff[46] = rd32(E1000_WUPL); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* MAC */ 54462306a36Sopenharmony_ci regs_buff[47] = rd32(E1000_PCS_CFG0); 54562306a36Sopenharmony_ci regs_buff[48] = rd32(E1000_PCS_LCTL); 54662306a36Sopenharmony_ci regs_buff[49] = rd32(E1000_PCS_LSTAT); 54762306a36Sopenharmony_ci regs_buff[50] = rd32(E1000_PCS_ANADV); 54862306a36Sopenharmony_ci regs_buff[51] = rd32(E1000_PCS_LPAB); 54962306a36Sopenharmony_ci regs_buff[52] = rd32(E1000_PCS_NPTX); 55062306a36Sopenharmony_ci regs_buff[53] = rd32(E1000_PCS_LPABNP); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Statistics */ 55362306a36Sopenharmony_ci regs_buff[54] = adapter->stats.crcerrs; 55462306a36Sopenharmony_ci regs_buff[55] = adapter->stats.algnerrc; 55562306a36Sopenharmony_ci regs_buff[56] = adapter->stats.symerrs; 55662306a36Sopenharmony_ci regs_buff[57] = adapter->stats.rxerrc; 55762306a36Sopenharmony_ci regs_buff[58] = adapter->stats.mpc; 55862306a36Sopenharmony_ci regs_buff[59] = adapter->stats.scc; 55962306a36Sopenharmony_ci regs_buff[60] = adapter->stats.ecol; 56062306a36Sopenharmony_ci regs_buff[61] = adapter->stats.mcc; 56162306a36Sopenharmony_ci regs_buff[62] = adapter->stats.latecol; 56262306a36Sopenharmony_ci regs_buff[63] = adapter->stats.colc; 56362306a36Sopenharmony_ci regs_buff[64] = adapter->stats.dc; 56462306a36Sopenharmony_ci regs_buff[65] = adapter->stats.tncrs; 56562306a36Sopenharmony_ci regs_buff[66] = adapter->stats.sec; 56662306a36Sopenharmony_ci regs_buff[67] = adapter->stats.htdpmc; 56762306a36Sopenharmony_ci regs_buff[68] = adapter->stats.rlec; 56862306a36Sopenharmony_ci regs_buff[69] = adapter->stats.xonrxc; 56962306a36Sopenharmony_ci regs_buff[70] = adapter->stats.xontxc; 57062306a36Sopenharmony_ci regs_buff[71] = adapter->stats.xoffrxc; 57162306a36Sopenharmony_ci regs_buff[72] = adapter->stats.xofftxc; 57262306a36Sopenharmony_ci regs_buff[73] = adapter->stats.fcruc; 57362306a36Sopenharmony_ci regs_buff[74] = adapter->stats.prc64; 57462306a36Sopenharmony_ci regs_buff[75] = adapter->stats.prc127; 57562306a36Sopenharmony_ci regs_buff[76] = adapter->stats.prc255; 57662306a36Sopenharmony_ci regs_buff[77] = adapter->stats.prc511; 57762306a36Sopenharmony_ci regs_buff[78] = adapter->stats.prc1023; 57862306a36Sopenharmony_ci regs_buff[79] = adapter->stats.prc1522; 57962306a36Sopenharmony_ci regs_buff[80] = adapter->stats.gprc; 58062306a36Sopenharmony_ci regs_buff[81] = adapter->stats.bprc; 58162306a36Sopenharmony_ci regs_buff[82] = adapter->stats.mprc; 58262306a36Sopenharmony_ci regs_buff[83] = adapter->stats.gptc; 58362306a36Sopenharmony_ci regs_buff[84] = adapter->stats.gorc; 58462306a36Sopenharmony_ci regs_buff[86] = adapter->stats.gotc; 58562306a36Sopenharmony_ci regs_buff[88] = adapter->stats.rnbc; 58662306a36Sopenharmony_ci regs_buff[89] = adapter->stats.ruc; 58762306a36Sopenharmony_ci regs_buff[90] = adapter->stats.rfc; 58862306a36Sopenharmony_ci regs_buff[91] = adapter->stats.roc; 58962306a36Sopenharmony_ci regs_buff[92] = adapter->stats.rjc; 59062306a36Sopenharmony_ci regs_buff[93] = adapter->stats.mgprc; 59162306a36Sopenharmony_ci regs_buff[94] = adapter->stats.mgpdc; 59262306a36Sopenharmony_ci regs_buff[95] = adapter->stats.mgptc; 59362306a36Sopenharmony_ci regs_buff[96] = adapter->stats.tor; 59462306a36Sopenharmony_ci regs_buff[98] = adapter->stats.tot; 59562306a36Sopenharmony_ci regs_buff[100] = adapter->stats.tpr; 59662306a36Sopenharmony_ci regs_buff[101] = adapter->stats.tpt; 59762306a36Sopenharmony_ci regs_buff[102] = adapter->stats.ptc64; 59862306a36Sopenharmony_ci regs_buff[103] = adapter->stats.ptc127; 59962306a36Sopenharmony_ci regs_buff[104] = adapter->stats.ptc255; 60062306a36Sopenharmony_ci regs_buff[105] = adapter->stats.ptc511; 60162306a36Sopenharmony_ci regs_buff[106] = adapter->stats.ptc1023; 60262306a36Sopenharmony_ci regs_buff[107] = adapter->stats.ptc1522; 60362306a36Sopenharmony_ci regs_buff[108] = adapter->stats.mptc; 60462306a36Sopenharmony_ci regs_buff[109] = adapter->stats.bptc; 60562306a36Sopenharmony_ci regs_buff[110] = adapter->stats.tsctc; 60662306a36Sopenharmony_ci regs_buff[111] = adapter->stats.iac; 60762306a36Sopenharmony_ci regs_buff[112] = adapter->stats.rpthc; 60862306a36Sopenharmony_ci regs_buff[113] = adapter->stats.hgptc; 60962306a36Sopenharmony_ci regs_buff[114] = adapter->stats.hgorc; 61062306a36Sopenharmony_ci regs_buff[116] = adapter->stats.hgotc; 61162306a36Sopenharmony_ci regs_buff[118] = adapter->stats.lenerrs; 61262306a36Sopenharmony_ci regs_buff[119] = adapter->stats.scvpc; 61362306a36Sopenharmony_ci regs_buff[120] = adapter->stats.hrmpc; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci for (i = 0; i < 4; i++) 61662306a36Sopenharmony_ci regs_buff[121 + i] = rd32(E1000_SRRCTL(i)); 61762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 61862306a36Sopenharmony_ci regs_buff[125 + i] = rd32(E1000_PSRTYPE(i)); 61962306a36Sopenharmony_ci for (i = 0; i < 4; i++) 62062306a36Sopenharmony_ci regs_buff[129 + i] = rd32(E1000_RDBAL(i)); 62162306a36Sopenharmony_ci for (i = 0; i < 4; i++) 62262306a36Sopenharmony_ci regs_buff[133 + i] = rd32(E1000_RDBAH(i)); 62362306a36Sopenharmony_ci for (i = 0; i < 4; i++) 62462306a36Sopenharmony_ci regs_buff[137 + i] = rd32(E1000_RDLEN(i)); 62562306a36Sopenharmony_ci for (i = 0; i < 4; i++) 62662306a36Sopenharmony_ci regs_buff[141 + i] = rd32(E1000_RDH(i)); 62762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 62862306a36Sopenharmony_ci regs_buff[145 + i] = rd32(E1000_RDT(i)); 62962306a36Sopenharmony_ci for (i = 0; i < 4; i++) 63062306a36Sopenharmony_ci regs_buff[149 + i] = rd32(E1000_RXDCTL(i)); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci for (i = 0; i < 10; i++) 63362306a36Sopenharmony_ci regs_buff[153 + i] = rd32(E1000_EITR(i)); 63462306a36Sopenharmony_ci for (i = 0; i < 8; i++) 63562306a36Sopenharmony_ci regs_buff[163 + i] = rd32(E1000_IMIR(i)); 63662306a36Sopenharmony_ci for (i = 0; i < 8; i++) 63762306a36Sopenharmony_ci regs_buff[171 + i] = rd32(E1000_IMIREXT(i)); 63862306a36Sopenharmony_ci for (i = 0; i < 16; i++) 63962306a36Sopenharmony_ci regs_buff[179 + i] = rd32(E1000_RAL(i)); 64062306a36Sopenharmony_ci for (i = 0; i < 16; i++) 64162306a36Sopenharmony_ci regs_buff[195 + i] = rd32(E1000_RAH(i)); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci for (i = 0; i < 4; i++) 64462306a36Sopenharmony_ci regs_buff[211 + i] = rd32(E1000_TDBAL(i)); 64562306a36Sopenharmony_ci for (i = 0; i < 4; i++) 64662306a36Sopenharmony_ci regs_buff[215 + i] = rd32(E1000_TDBAH(i)); 64762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 64862306a36Sopenharmony_ci regs_buff[219 + i] = rd32(E1000_TDLEN(i)); 64962306a36Sopenharmony_ci for (i = 0; i < 4; i++) 65062306a36Sopenharmony_ci regs_buff[223 + i] = rd32(E1000_TDH(i)); 65162306a36Sopenharmony_ci for (i = 0; i < 4; i++) 65262306a36Sopenharmony_ci regs_buff[227 + i] = rd32(E1000_TDT(i)); 65362306a36Sopenharmony_ci for (i = 0; i < 4; i++) 65462306a36Sopenharmony_ci regs_buff[231 + i] = rd32(E1000_TXDCTL(i)); 65562306a36Sopenharmony_ci for (i = 0; i < 4; i++) 65662306a36Sopenharmony_ci regs_buff[235 + i] = rd32(E1000_TDWBAL(i)); 65762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 65862306a36Sopenharmony_ci regs_buff[239 + i] = rd32(E1000_TDWBAH(i)); 65962306a36Sopenharmony_ci for (i = 0; i < 4; i++) 66062306a36Sopenharmony_ci regs_buff[243 + i] = rd32(E1000_DCA_TXCTRL(i)); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci for (i = 0; i < 4; i++) 66362306a36Sopenharmony_ci regs_buff[247 + i] = rd32(E1000_IP4AT_REG(i)); 66462306a36Sopenharmony_ci for (i = 0; i < 4; i++) 66562306a36Sopenharmony_ci regs_buff[251 + i] = rd32(E1000_IP6AT_REG(i)); 66662306a36Sopenharmony_ci for (i = 0; i < 32; i++) 66762306a36Sopenharmony_ci regs_buff[255 + i] = rd32(E1000_WUPM_REG(i)); 66862306a36Sopenharmony_ci for (i = 0; i < 128; i++) 66962306a36Sopenharmony_ci regs_buff[287 + i] = rd32(E1000_FFMT_REG(i)); 67062306a36Sopenharmony_ci for (i = 0; i < 128; i++) 67162306a36Sopenharmony_ci regs_buff[415 + i] = rd32(E1000_FFVT_REG(i)); 67262306a36Sopenharmony_ci for (i = 0; i < 4; i++) 67362306a36Sopenharmony_ci regs_buff[543 + i] = rd32(E1000_FFLT_REG(i)); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci regs_buff[547] = rd32(E1000_TDFH); 67662306a36Sopenharmony_ci regs_buff[548] = rd32(E1000_TDFT); 67762306a36Sopenharmony_ci regs_buff[549] = rd32(E1000_TDFHS); 67862306a36Sopenharmony_ci regs_buff[550] = rd32(E1000_TDFPC); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (hw->mac.type > e1000_82580) { 68162306a36Sopenharmony_ci regs_buff[551] = adapter->stats.o2bgptc; 68262306a36Sopenharmony_ci regs_buff[552] = adapter->stats.b2ospc; 68362306a36Sopenharmony_ci regs_buff[553] = adapter->stats.o2bspc; 68462306a36Sopenharmony_ci regs_buff[554] = adapter->stats.b2ogprc; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (hw->mac.type == e1000_82576) { 68862306a36Sopenharmony_ci for (i = 0; i < 12; i++) 68962306a36Sopenharmony_ci regs_buff[555 + i] = rd32(E1000_SRRCTL(i + 4)); 69062306a36Sopenharmony_ci for (i = 0; i < 4; i++) 69162306a36Sopenharmony_ci regs_buff[567 + i] = rd32(E1000_PSRTYPE(i + 4)); 69262306a36Sopenharmony_ci for (i = 0; i < 12; i++) 69362306a36Sopenharmony_ci regs_buff[571 + i] = rd32(E1000_RDBAL(i + 4)); 69462306a36Sopenharmony_ci for (i = 0; i < 12; i++) 69562306a36Sopenharmony_ci regs_buff[583 + i] = rd32(E1000_RDBAH(i + 4)); 69662306a36Sopenharmony_ci for (i = 0; i < 12; i++) 69762306a36Sopenharmony_ci regs_buff[595 + i] = rd32(E1000_RDLEN(i + 4)); 69862306a36Sopenharmony_ci for (i = 0; i < 12; i++) 69962306a36Sopenharmony_ci regs_buff[607 + i] = rd32(E1000_RDH(i + 4)); 70062306a36Sopenharmony_ci for (i = 0; i < 12; i++) 70162306a36Sopenharmony_ci regs_buff[619 + i] = rd32(E1000_RDT(i + 4)); 70262306a36Sopenharmony_ci for (i = 0; i < 12; i++) 70362306a36Sopenharmony_ci regs_buff[631 + i] = rd32(E1000_RXDCTL(i + 4)); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci for (i = 0; i < 12; i++) 70662306a36Sopenharmony_ci regs_buff[643 + i] = rd32(E1000_TDBAL(i + 4)); 70762306a36Sopenharmony_ci for (i = 0; i < 12; i++) 70862306a36Sopenharmony_ci regs_buff[655 + i] = rd32(E1000_TDBAH(i + 4)); 70962306a36Sopenharmony_ci for (i = 0; i < 12; i++) 71062306a36Sopenharmony_ci regs_buff[667 + i] = rd32(E1000_TDLEN(i + 4)); 71162306a36Sopenharmony_ci for (i = 0; i < 12; i++) 71262306a36Sopenharmony_ci regs_buff[679 + i] = rd32(E1000_TDH(i + 4)); 71362306a36Sopenharmony_ci for (i = 0; i < 12; i++) 71462306a36Sopenharmony_ci regs_buff[691 + i] = rd32(E1000_TDT(i + 4)); 71562306a36Sopenharmony_ci for (i = 0; i < 12; i++) 71662306a36Sopenharmony_ci regs_buff[703 + i] = rd32(E1000_TXDCTL(i + 4)); 71762306a36Sopenharmony_ci for (i = 0; i < 12; i++) 71862306a36Sopenharmony_ci regs_buff[715 + i] = rd32(E1000_TDWBAL(i + 4)); 71962306a36Sopenharmony_ci for (i = 0; i < 12; i++) 72062306a36Sopenharmony_ci regs_buff[727 + i] = rd32(E1000_TDWBAH(i + 4)); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) 72462306a36Sopenharmony_ci regs_buff[739] = rd32(E1000_I210_RR2DCDELAY); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic int igb_get_eeprom_len(struct net_device *netdev) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 73062306a36Sopenharmony_ci return adapter->hw.nvm.word_size * 2; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int igb_get_eeprom(struct net_device *netdev, 73462306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *bytes) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 73762306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 73862306a36Sopenharmony_ci u16 *eeprom_buff; 73962306a36Sopenharmony_ci int first_word, last_word; 74062306a36Sopenharmony_ci int ret_val = 0; 74162306a36Sopenharmony_ci u16 i; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (eeprom->len == 0) 74462306a36Sopenharmony_ci return -EINVAL; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci eeprom->magic = hw->vendor_id | (hw->device_id << 16); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci first_word = eeprom->offset >> 1; 74962306a36Sopenharmony_ci last_word = (eeprom->offset + eeprom->len - 1) >> 1; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), 75262306a36Sopenharmony_ci GFP_KERNEL); 75362306a36Sopenharmony_ci if (!eeprom_buff) 75462306a36Sopenharmony_ci return -ENOMEM; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (hw->nvm.type == e1000_nvm_eeprom_spi) 75762306a36Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, first_word, 75862306a36Sopenharmony_ci last_word - first_word + 1, 75962306a36Sopenharmony_ci eeprom_buff); 76062306a36Sopenharmony_ci else { 76162306a36Sopenharmony_ci for (i = 0; i < last_word - first_word + 1; i++) { 76262306a36Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, first_word + i, 1, 76362306a36Sopenharmony_ci &eeprom_buff[i]); 76462306a36Sopenharmony_ci if (ret_val) 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Device's eeprom is always little-endian, word addressable */ 77062306a36Sopenharmony_ci for (i = 0; i < last_word - first_word + 1; i++) 77162306a36Sopenharmony_ci le16_to_cpus(&eeprom_buff[i]); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), 77462306a36Sopenharmony_ci eeprom->len); 77562306a36Sopenharmony_ci kfree(eeprom_buff); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return ret_val; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int igb_set_eeprom(struct net_device *netdev, 78162306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *bytes) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 78462306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 78562306a36Sopenharmony_ci u16 *eeprom_buff; 78662306a36Sopenharmony_ci void *ptr; 78762306a36Sopenharmony_ci int max_len, first_word, last_word, ret_val = 0; 78862306a36Sopenharmony_ci u16 i; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (eeprom->len == 0) 79162306a36Sopenharmony_ci return -EOPNOTSUPP; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if ((hw->mac.type >= e1000_i210) && 79462306a36Sopenharmony_ci !igb_get_flash_presence_i210(hw)) { 79562306a36Sopenharmony_ci return -EOPNOTSUPP; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) 79962306a36Sopenharmony_ci return -EFAULT; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci max_len = hw->nvm.word_size * 2; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci first_word = eeprom->offset >> 1; 80462306a36Sopenharmony_ci last_word = (eeprom->offset + eeprom->len - 1) >> 1; 80562306a36Sopenharmony_ci eeprom_buff = kmalloc(max_len, GFP_KERNEL); 80662306a36Sopenharmony_ci if (!eeprom_buff) 80762306a36Sopenharmony_ci return -ENOMEM; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci ptr = (void *)eeprom_buff; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (eeprom->offset & 1) { 81262306a36Sopenharmony_ci /* need read/modify/write of first changed EEPROM word 81362306a36Sopenharmony_ci * only the second byte of the word is being modified 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, first_word, 1, 81662306a36Sopenharmony_ci &eeprom_buff[0]); 81762306a36Sopenharmony_ci ptr++; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) { 82062306a36Sopenharmony_ci /* need read/modify/write of last changed EEPROM word 82162306a36Sopenharmony_ci * only the first byte of the word is being modified 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, last_word, 1, 82462306a36Sopenharmony_ci &eeprom_buff[last_word - first_word]); 82562306a36Sopenharmony_ci if (ret_val) 82662306a36Sopenharmony_ci goto out; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* Device's eeprom is always little-endian, word addressable */ 83062306a36Sopenharmony_ci for (i = 0; i < last_word - first_word + 1; i++) 83162306a36Sopenharmony_ci le16_to_cpus(&eeprom_buff[i]); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci memcpy(ptr, bytes, eeprom->len); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci for (i = 0; i < last_word - first_word + 1; i++) 83662306a36Sopenharmony_ci cpu_to_le16s(&eeprom_buff[i]); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci ret_val = hw->nvm.ops.write(hw, first_word, 83962306a36Sopenharmony_ci last_word - first_word + 1, eeprom_buff); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* Update the checksum if nvm write succeeded */ 84262306a36Sopenharmony_ci if (ret_val == 0) 84362306a36Sopenharmony_ci hw->nvm.ops.update(hw); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci igb_set_fw_version(adapter); 84662306a36Sopenharmony_ciout: 84762306a36Sopenharmony_ci kfree(eeprom_buff); 84862306a36Sopenharmony_ci return ret_val; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic void igb_get_drvinfo(struct net_device *netdev, 85262306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci strscpy(drvinfo->driver, igb_driver_name, sizeof(drvinfo->driver)); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci /* EEPROM image version # is reported as firmware version # for 85962306a36Sopenharmony_ci * 82575 controllers 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ci strscpy(drvinfo->fw_version, adapter->fw_version, 86262306a36Sopenharmony_ci sizeof(drvinfo->fw_version)); 86362306a36Sopenharmony_ci strscpy(drvinfo->bus_info, pci_name(adapter->pdev), 86462306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci drvinfo->n_priv_flags = IGB_PRIV_FLAGS_STR_LEN; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic void igb_get_ringparam(struct net_device *netdev, 87062306a36Sopenharmony_ci struct ethtool_ringparam *ring, 87162306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 87262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci ring->rx_max_pending = IGB_MAX_RXD; 87762306a36Sopenharmony_ci ring->tx_max_pending = IGB_MAX_TXD; 87862306a36Sopenharmony_ci ring->rx_pending = adapter->rx_ring_count; 87962306a36Sopenharmony_ci ring->tx_pending = adapter->tx_ring_count; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic int igb_set_ringparam(struct net_device *netdev, 88362306a36Sopenharmony_ci struct ethtool_ringparam *ring, 88462306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 88562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 88862306a36Sopenharmony_ci struct igb_ring *temp_ring; 88962306a36Sopenharmony_ci int i, err = 0; 89062306a36Sopenharmony_ci u16 new_rx_count, new_tx_count; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 89362306a36Sopenharmony_ci return -EINVAL; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci new_rx_count = min_t(u32, ring->rx_pending, IGB_MAX_RXD); 89662306a36Sopenharmony_ci new_rx_count = max_t(u16, new_rx_count, IGB_MIN_RXD); 89762306a36Sopenharmony_ci new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci new_tx_count = min_t(u32, ring->tx_pending, IGB_MAX_TXD); 90062306a36Sopenharmony_ci new_tx_count = max_t(u16, new_tx_count, IGB_MIN_TXD); 90162306a36Sopenharmony_ci new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if ((new_tx_count == adapter->tx_ring_count) && 90462306a36Sopenharmony_ci (new_rx_count == adapter->rx_ring_count)) { 90562306a36Sopenharmony_ci /* nothing to do */ 90662306a36Sopenharmony_ci return 0; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) 91062306a36Sopenharmony_ci usleep_range(1000, 2000); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (!netif_running(adapter->netdev)) { 91362306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) 91462306a36Sopenharmony_ci adapter->tx_ring[i]->count = new_tx_count; 91562306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) 91662306a36Sopenharmony_ci adapter->rx_ring[i]->count = new_rx_count; 91762306a36Sopenharmony_ci adapter->tx_ring_count = new_tx_count; 91862306a36Sopenharmony_ci adapter->rx_ring_count = new_rx_count; 91962306a36Sopenharmony_ci goto clear_reset; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (adapter->num_tx_queues > adapter->num_rx_queues) 92362306a36Sopenharmony_ci temp_ring = vmalloc(array_size(sizeof(struct igb_ring), 92462306a36Sopenharmony_ci adapter->num_tx_queues)); 92562306a36Sopenharmony_ci else 92662306a36Sopenharmony_ci temp_ring = vmalloc(array_size(sizeof(struct igb_ring), 92762306a36Sopenharmony_ci adapter->num_rx_queues)); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (!temp_ring) { 93062306a36Sopenharmony_ci err = -ENOMEM; 93162306a36Sopenharmony_ci goto clear_reset; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci igb_down(adapter); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* We can't just free everything and then setup again, 93762306a36Sopenharmony_ci * because the ISRs in MSI-X mode get passed pointers 93862306a36Sopenharmony_ci * to the Tx and Rx ring structs. 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci if (new_tx_count != adapter->tx_ring_count) { 94162306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 94262306a36Sopenharmony_ci memcpy(&temp_ring[i], adapter->tx_ring[i], 94362306a36Sopenharmony_ci sizeof(struct igb_ring)); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci temp_ring[i].count = new_tx_count; 94662306a36Sopenharmony_ci err = igb_setup_tx_resources(&temp_ring[i]); 94762306a36Sopenharmony_ci if (err) { 94862306a36Sopenharmony_ci while (i) { 94962306a36Sopenharmony_ci i--; 95062306a36Sopenharmony_ci igb_free_tx_resources(&temp_ring[i]); 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci goto err_setup; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 95762306a36Sopenharmony_ci igb_free_tx_resources(adapter->tx_ring[i]); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci memcpy(adapter->tx_ring[i], &temp_ring[i], 96062306a36Sopenharmony_ci sizeof(struct igb_ring)); 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci adapter->tx_ring_count = new_tx_count; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (new_rx_count != adapter->rx_ring_count) { 96762306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 96862306a36Sopenharmony_ci memcpy(&temp_ring[i], adapter->rx_ring[i], 96962306a36Sopenharmony_ci sizeof(struct igb_ring)); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci temp_ring[i].count = new_rx_count; 97262306a36Sopenharmony_ci err = igb_setup_rx_resources(&temp_ring[i]); 97362306a36Sopenharmony_ci if (err) { 97462306a36Sopenharmony_ci while (i) { 97562306a36Sopenharmony_ci i--; 97662306a36Sopenharmony_ci igb_free_rx_resources(&temp_ring[i]); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci goto err_setup; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 98462306a36Sopenharmony_ci igb_free_rx_resources(adapter->rx_ring[i]); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci memcpy(adapter->rx_ring[i], &temp_ring[i], 98762306a36Sopenharmony_ci sizeof(struct igb_ring)); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci adapter->rx_ring_count = new_rx_count; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_cierr_setup: 99362306a36Sopenharmony_ci igb_up(adapter); 99462306a36Sopenharmony_ci vfree(temp_ring); 99562306a36Sopenharmony_ciclear_reset: 99662306a36Sopenharmony_ci clear_bit(__IGB_RESETTING, &adapter->state); 99762306a36Sopenharmony_ci return err; 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci/* ethtool register test data */ 100162306a36Sopenharmony_cistruct igb_reg_test { 100262306a36Sopenharmony_ci u16 reg; 100362306a36Sopenharmony_ci u16 reg_offset; 100462306a36Sopenharmony_ci u16 array_len; 100562306a36Sopenharmony_ci u16 test_type; 100662306a36Sopenharmony_ci u32 mask; 100762306a36Sopenharmony_ci u32 write; 100862306a36Sopenharmony_ci}; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci/* In the hardware, registers are laid out either singly, in arrays 101162306a36Sopenharmony_ci * spaced 0x100 bytes apart, or in contiguous tables. We assume 101262306a36Sopenharmony_ci * most tests take place on arrays or single registers (handled 101362306a36Sopenharmony_ci * as a single-element array) and special-case the tables. 101462306a36Sopenharmony_ci * Table tests are always pattern tests. 101562306a36Sopenharmony_ci * 101662306a36Sopenharmony_ci * We also make provision for some required setup steps by specifying 101762306a36Sopenharmony_ci * registers to be written without any read-back testing. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci#define PATTERN_TEST 1 102162306a36Sopenharmony_ci#define SET_READ_TEST 2 102262306a36Sopenharmony_ci#define WRITE_NO_TEST 3 102362306a36Sopenharmony_ci#define TABLE32_TEST 4 102462306a36Sopenharmony_ci#define TABLE64_TEST_LO 5 102562306a36Sopenharmony_ci#define TABLE64_TEST_HI 6 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci/* i210 reg test */ 102862306a36Sopenharmony_cistatic struct igb_reg_test reg_test_i210[] = { 102962306a36Sopenharmony_ci { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 103062306a36Sopenharmony_ci { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 103162306a36Sopenharmony_ci { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 103262306a36Sopenharmony_ci { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 103362306a36Sopenharmony_ci { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 103462306a36Sopenharmony_ci { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 103562306a36Sopenharmony_ci /* RDH is read-only for i210, only test RDT. */ 103662306a36Sopenharmony_ci { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 103762306a36Sopenharmony_ci { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, 103862306a36Sopenharmony_ci { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 103962306a36Sopenharmony_ci { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, 104062306a36Sopenharmony_ci { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 104162306a36Sopenharmony_ci { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 104262306a36Sopenharmony_ci { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 104362306a36Sopenharmony_ci { E1000_TDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 104462306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 104562306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, 104662306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, 104762306a36Sopenharmony_ci { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 104862306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_LO, 104962306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 105062306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_HI, 105162306a36Sopenharmony_ci 0x900FFFFF, 0xFFFFFFFF }, 105262306a36Sopenharmony_ci { E1000_MTA, 0, 128, TABLE32_TEST, 105362306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 105462306a36Sopenharmony_ci { 0, 0, 0, 0, 0 } 105562306a36Sopenharmony_ci}; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci/* i350 reg test */ 105862306a36Sopenharmony_cistatic struct igb_reg_test reg_test_i350[] = { 105962306a36Sopenharmony_ci { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 106062306a36Sopenharmony_ci { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 106162306a36Sopenharmony_ci { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 106262306a36Sopenharmony_ci { E1000_VET, 0x100, 1, PATTERN_TEST, 0xFFFF0000, 0xFFFF0000 }, 106362306a36Sopenharmony_ci { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 106462306a36Sopenharmony_ci { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 106562306a36Sopenharmony_ci { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 106662306a36Sopenharmony_ci { E1000_RDBAL(4), 0x40, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 106762306a36Sopenharmony_ci { E1000_RDBAH(4), 0x40, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 106862306a36Sopenharmony_ci { E1000_RDLEN(4), 0x40, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 106962306a36Sopenharmony_ci /* RDH is read-only for i350, only test RDT. */ 107062306a36Sopenharmony_ci { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 107162306a36Sopenharmony_ci { E1000_RDT(4), 0x40, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 107262306a36Sopenharmony_ci { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, 107362306a36Sopenharmony_ci { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 107462306a36Sopenharmony_ci { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, 107562306a36Sopenharmony_ci { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 107662306a36Sopenharmony_ci { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 107762306a36Sopenharmony_ci { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 107862306a36Sopenharmony_ci { E1000_TDBAL(4), 0x40, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 107962306a36Sopenharmony_ci { E1000_TDBAH(4), 0x40, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 108062306a36Sopenharmony_ci { E1000_TDLEN(4), 0x40, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 108162306a36Sopenharmony_ci { E1000_TDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 108262306a36Sopenharmony_ci { E1000_TDT(4), 0x40, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 108362306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 108462306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, 108562306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, 108662306a36Sopenharmony_ci { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 108762306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_LO, 108862306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 108962306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_HI, 109062306a36Sopenharmony_ci 0xC3FFFFFF, 0xFFFFFFFF }, 109162306a36Sopenharmony_ci { E1000_RA2, 0, 16, TABLE64_TEST_LO, 109262306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 109362306a36Sopenharmony_ci { E1000_RA2, 0, 16, TABLE64_TEST_HI, 109462306a36Sopenharmony_ci 0xC3FFFFFF, 0xFFFFFFFF }, 109562306a36Sopenharmony_ci { E1000_MTA, 0, 128, TABLE32_TEST, 109662306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 109762306a36Sopenharmony_ci { 0, 0, 0, 0 } 109862306a36Sopenharmony_ci}; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci/* 82580 reg test */ 110162306a36Sopenharmony_cistatic struct igb_reg_test reg_test_82580[] = { 110262306a36Sopenharmony_ci { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 110362306a36Sopenharmony_ci { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 110462306a36Sopenharmony_ci { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 110562306a36Sopenharmony_ci { E1000_VET, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 110662306a36Sopenharmony_ci { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 110762306a36Sopenharmony_ci { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 110862306a36Sopenharmony_ci { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 110962306a36Sopenharmony_ci { E1000_RDBAL(4), 0x40, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 111062306a36Sopenharmony_ci { E1000_RDBAH(4), 0x40, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 111162306a36Sopenharmony_ci { E1000_RDLEN(4), 0x40, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 111262306a36Sopenharmony_ci /* RDH is read-only for 82580, only test RDT. */ 111362306a36Sopenharmony_ci { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 111462306a36Sopenharmony_ci { E1000_RDT(4), 0x40, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 111562306a36Sopenharmony_ci { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, 111662306a36Sopenharmony_ci { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 111762306a36Sopenharmony_ci { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, 111862306a36Sopenharmony_ci { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 111962306a36Sopenharmony_ci { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 112062306a36Sopenharmony_ci { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 112162306a36Sopenharmony_ci { E1000_TDBAL(4), 0x40, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 112262306a36Sopenharmony_ci { E1000_TDBAH(4), 0x40, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 112362306a36Sopenharmony_ci { E1000_TDLEN(4), 0x40, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 112462306a36Sopenharmony_ci { E1000_TDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 112562306a36Sopenharmony_ci { E1000_TDT(4), 0x40, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 112662306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 112762306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, 112862306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, 112962306a36Sopenharmony_ci { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 113062306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_LO, 113162306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 113262306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_HI, 113362306a36Sopenharmony_ci 0x83FFFFFF, 0xFFFFFFFF }, 113462306a36Sopenharmony_ci { E1000_RA2, 0, 8, TABLE64_TEST_LO, 113562306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 113662306a36Sopenharmony_ci { E1000_RA2, 0, 8, TABLE64_TEST_HI, 113762306a36Sopenharmony_ci 0x83FFFFFF, 0xFFFFFFFF }, 113862306a36Sopenharmony_ci { E1000_MTA, 0, 128, TABLE32_TEST, 113962306a36Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 114062306a36Sopenharmony_ci { 0, 0, 0, 0 } 114162306a36Sopenharmony_ci}; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci/* 82576 reg test */ 114462306a36Sopenharmony_cistatic struct igb_reg_test reg_test_82576[] = { 114562306a36Sopenharmony_ci { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 114662306a36Sopenharmony_ci { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 114762306a36Sopenharmony_ci { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 114862306a36Sopenharmony_ci { E1000_VET, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 114962306a36Sopenharmony_ci { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 115062306a36Sopenharmony_ci { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 115162306a36Sopenharmony_ci { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 115262306a36Sopenharmony_ci { E1000_RDBAL(4), 0x40, 12, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 115362306a36Sopenharmony_ci { E1000_RDBAH(4), 0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 115462306a36Sopenharmony_ci { E1000_RDLEN(4), 0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 115562306a36Sopenharmony_ci /* Enable all RX queues before testing. */ 115662306a36Sopenharmony_ci { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 115762306a36Sopenharmony_ci E1000_RXDCTL_QUEUE_ENABLE }, 115862306a36Sopenharmony_ci { E1000_RXDCTL(4), 0x40, 12, WRITE_NO_TEST, 0, 115962306a36Sopenharmony_ci E1000_RXDCTL_QUEUE_ENABLE }, 116062306a36Sopenharmony_ci /* RDH is read-only for 82576, only test RDT. */ 116162306a36Sopenharmony_ci { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 116262306a36Sopenharmony_ci { E1000_RDT(4), 0x40, 12, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 116362306a36Sopenharmony_ci { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 }, 116462306a36Sopenharmony_ci { E1000_RXDCTL(4), 0x40, 12, WRITE_NO_TEST, 0, 0 }, 116562306a36Sopenharmony_ci { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, 116662306a36Sopenharmony_ci { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 116762306a36Sopenharmony_ci { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, 116862306a36Sopenharmony_ci { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 116962306a36Sopenharmony_ci { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 117062306a36Sopenharmony_ci { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 117162306a36Sopenharmony_ci { E1000_TDBAL(4), 0x40, 12, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 117262306a36Sopenharmony_ci { E1000_TDBAH(4), 0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 117362306a36Sopenharmony_ci { E1000_TDLEN(4), 0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, 117462306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 117562306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, 117662306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, 117762306a36Sopenharmony_ci { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 117862306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, 117962306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF }, 118062306a36Sopenharmony_ci { E1000_RA2, 0, 8, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, 118162306a36Sopenharmony_ci { E1000_RA2, 0, 8, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF }, 118262306a36Sopenharmony_ci { E1000_MTA, 0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 118362306a36Sopenharmony_ci { 0, 0, 0, 0 } 118462306a36Sopenharmony_ci}; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci/* 82575 register test */ 118762306a36Sopenharmony_cistatic struct igb_reg_test reg_test_82575[] = { 118862306a36Sopenharmony_ci { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 118962306a36Sopenharmony_ci { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 119062306a36Sopenharmony_ci { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 119162306a36Sopenharmony_ci { E1000_VET, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 119262306a36Sopenharmony_ci { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 119362306a36Sopenharmony_ci { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 119462306a36Sopenharmony_ci { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 119562306a36Sopenharmony_ci /* Enable all four RX queues before testing. */ 119662306a36Sopenharmony_ci { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 119762306a36Sopenharmony_ci E1000_RXDCTL_QUEUE_ENABLE }, 119862306a36Sopenharmony_ci /* RDH is read-only for 82575, only test RDT. */ 119962306a36Sopenharmony_ci { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 120062306a36Sopenharmony_ci { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 }, 120162306a36Sopenharmony_ci { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, 120262306a36Sopenharmony_ci { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 120362306a36Sopenharmony_ci { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, 120462306a36Sopenharmony_ci { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, 120562306a36Sopenharmony_ci { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 120662306a36Sopenharmony_ci { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 120762306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 120862306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB3FE, 0x003FFFFB }, 120962306a36Sopenharmony_ci { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB3FE, 0xFFFFFFFF }, 121062306a36Sopenharmony_ci { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 121162306a36Sopenharmony_ci { E1000_TXCW, 0x100, 1, PATTERN_TEST, 0xC000FFFF, 0x0000FFFF }, 121262306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, 121362306a36Sopenharmony_ci { E1000_RA, 0, 16, TABLE64_TEST_HI, 0x800FFFFF, 0xFFFFFFFF }, 121462306a36Sopenharmony_ci { E1000_MTA, 0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 121562306a36Sopenharmony_ci { 0, 0, 0, 0 } 121662306a36Sopenharmony_ci}; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_cistatic bool reg_pattern_test(struct igb_adapter *adapter, u64 *data, 121962306a36Sopenharmony_ci int reg, u32 mask, u32 write) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 122262306a36Sopenharmony_ci u32 pat, val; 122362306a36Sopenharmony_ci static const u32 _test[] = { 122462306a36Sopenharmony_ci 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; 122562306a36Sopenharmony_ci for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { 122662306a36Sopenharmony_ci wr32(reg, (_test[pat] & write)); 122762306a36Sopenharmony_ci val = rd32(reg) & mask; 122862306a36Sopenharmony_ci if (val != (_test[pat] & write & mask)) { 122962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 123062306a36Sopenharmony_ci "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n", 123162306a36Sopenharmony_ci reg, val, (_test[pat] & write & mask)); 123262306a36Sopenharmony_ci *data = reg; 123362306a36Sopenharmony_ci return true; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci return false; 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic bool reg_set_and_check(struct igb_adapter *adapter, u64 *data, 124162306a36Sopenharmony_ci int reg, u32 mask, u32 write) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 124462306a36Sopenharmony_ci u32 val; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci wr32(reg, write & mask); 124762306a36Sopenharmony_ci val = rd32(reg); 124862306a36Sopenharmony_ci if ((write & mask) != (val & mask)) { 124962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 125062306a36Sopenharmony_ci "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", 125162306a36Sopenharmony_ci reg, (val & mask), (write & mask)); 125262306a36Sopenharmony_ci *data = reg; 125362306a36Sopenharmony_ci return true; 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci return false; 125762306a36Sopenharmony_ci} 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci#define REG_PATTERN_TEST(reg, mask, write) \ 126062306a36Sopenharmony_ci do { \ 126162306a36Sopenharmony_ci if (reg_pattern_test(adapter, data, reg, mask, write)) \ 126262306a36Sopenharmony_ci return 1; \ 126362306a36Sopenharmony_ci } while (0) 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci#define REG_SET_AND_CHECK(reg, mask, write) \ 126662306a36Sopenharmony_ci do { \ 126762306a36Sopenharmony_ci if (reg_set_and_check(adapter, data, reg, mask, write)) \ 126862306a36Sopenharmony_ci return 1; \ 126962306a36Sopenharmony_ci } while (0) 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cistatic int igb_reg_test(struct igb_adapter *adapter, u64 *data) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 127462306a36Sopenharmony_ci struct igb_reg_test *test; 127562306a36Sopenharmony_ci u32 value, before, after; 127662306a36Sopenharmony_ci u32 i, toggle; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 127962306a36Sopenharmony_ci case e1000_i350: 128062306a36Sopenharmony_ci case e1000_i354: 128162306a36Sopenharmony_ci test = reg_test_i350; 128262306a36Sopenharmony_ci toggle = 0x7FEFF3FF; 128362306a36Sopenharmony_ci break; 128462306a36Sopenharmony_ci case e1000_i210: 128562306a36Sopenharmony_ci case e1000_i211: 128662306a36Sopenharmony_ci test = reg_test_i210; 128762306a36Sopenharmony_ci toggle = 0x7FEFF3FF; 128862306a36Sopenharmony_ci break; 128962306a36Sopenharmony_ci case e1000_82580: 129062306a36Sopenharmony_ci test = reg_test_82580; 129162306a36Sopenharmony_ci toggle = 0x7FEFF3FF; 129262306a36Sopenharmony_ci break; 129362306a36Sopenharmony_ci case e1000_82576: 129462306a36Sopenharmony_ci test = reg_test_82576; 129562306a36Sopenharmony_ci toggle = 0x7FFFF3FF; 129662306a36Sopenharmony_ci break; 129762306a36Sopenharmony_ci default: 129862306a36Sopenharmony_ci test = reg_test_82575; 129962306a36Sopenharmony_ci toggle = 0x7FFFF3FF; 130062306a36Sopenharmony_ci break; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci /* Because the status register is such a special case, 130462306a36Sopenharmony_ci * we handle it separately from the rest of the register 130562306a36Sopenharmony_ci * tests. Some bits are read-only, some toggle, and some 130662306a36Sopenharmony_ci * are writable on newer MACs. 130762306a36Sopenharmony_ci */ 130862306a36Sopenharmony_ci before = rd32(E1000_STATUS); 130962306a36Sopenharmony_ci value = (rd32(E1000_STATUS) & toggle); 131062306a36Sopenharmony_ci wr32(E1000_STATUS, toggle); 131162306a36Sopenharmony_ci after = rd32(E1000_STATUS) & toggle; 131262306a36Sopenharmony_ci if (value != after) { 131362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 131462306a36Sopenharmony_ci "failed STATUS register test got: 0x%08X expected: 0x%08X\n", 131562306a36Sopenharmony_ci after, value); 131662306a36Sopenharmony_ci *data = 1; 131762306a36Sopenharmony_ci return 1; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci /* restore previous status */ 132062306a36Sopenharmony_ci wr32(E1000_STATUS, before); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci /* Perform the remainder of the register test, looping through 132362306a36Sopenharmony_ci * the test table until we either fail or reach the null entry. 132462306a36Sopenharmony_ci */ 132562306a36Sopenharmony_ci while (test->reg) { 132662306a36Sopenharmony_ci for (i = 0; i < test->array_len; i++) { 132762306a36Sopenharmony_ci switch (test->test_type) { 132862306a36Sopenharmony_ci case PATTERN_TEST: 132962306a36Sopenharmony_ci REG_PATTERN_TEST(test->reg + 133062306a36Sopenharmony_ci (i * test->reg_offset), 133162306a36Sopenharmony_ci test->mask, 133262306a36Sopenharmony_ci test->write); 133362306a36Sopenharmony_ci break; 133462306a36Sopenharmony_ci case SET_READ_TEST: 133562306a36Sopenharmony_ci REG_SET_AND_CHECK(test->reg + 133662306a36Sopenharmony_ci (i * test->reg_offset), 133762306a36Sopenharmony_ci test->mask, 133862306a36Sopenharmony_ci test->write); 133962306a36Sopenharmony_ci break; 134062306a36Sopenharmony_ci case WRITE_NO_TEST: 134162306a36Sopenharmony_ci writel(test->write, 134262306a36Sopenharmony_ci (adapter->hw.hw_addr + test->reg) 134362306a36Sopenharmony_ci + (i * test->reg_offset)); 134462306a36Sopenharmony_ci break; 134562306a36Sopenharmony_ci case TABLE32_TEST: 134662306a36Sopenharmony_ci REG_PATTERN_TEST(test->reg + (i * 4), 134762306a36Sopenharmony_ci test->mask, 134862306a36Sopenharmony_ci test->write); 134962306a36Sopenharmony_ci break; 135062306a36Sopenharmony_ci case TABLE64_TEST_LO: 135162306a36Sopenharmony_ci REG_PATTERN_TEST(test->reg + (i * 8), 135262306a36Sopenharmony_ci test->mask, 135362306a36Sopenharmony_ci test->write); 135462306a36Sopenharmony_ci break; 135562306a36Sopenharmony_ci case TABLE64_TEST_HI: 135662306a36Sopenharmony_ci REG_PATTERN_TEST((test->reg + 4) + (i * 8), 135762306a36Sopenharmony_ci test->mask, 135862306a36Sopenharmony_ci test->write); 135962306a36Sopenharmony_ci break; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci test++; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci *data = 0; 136662306a36Sopenharmony_ci return 0; 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_cistatic int igb_eeprom_test(struct igb_adapter *adapter, u64 *data) 137062306a36Sopenharmony_ci{ 137162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci *data = 0; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci /* Validate eeprom on all parts but flashless */ 137662306a36Sopenharmony_ci switch (hw->mac.type) { 137762306a36Sopenharmony_ci case e1000_i210: 137862306a36Sopenharmony_ci case e1000_i211: 137962306a36Sopenharmony_ci if (igb_get_flash_presence_i210(hw)) { 138062306a36Sopenharmony_ci if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0) 138162306a36Sopenharmony_ci *data = 2; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci break; 138462306a36Sopenharmony_ci default: 138562306a36Sopenharmony_ci if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0) 138662306a36Sopenharmony_ci *data = 2; 138762306a36Sopenharmony_ci break; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci return *data; 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cistatic irqreturn_t igb_test_intr(int irq, void *data) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci struct igb_adapter *adapter = (struct igb_adapter *) data; 139662306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci adapter->test_icr |= rd32(E1000_ICR); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci return IRQ_HANDLED; 140162306a36Sopenharmony_ci} 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cistatic int igb_intr_test(struct igb_adapter *adapter, u64 *data) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 140662306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 140762306a36Sopenharmony_ci u32 mask, ics_mask, i = 0, shared_int = true; 140862306a36Sopenharmony_ci u32 irq = adapter->pdev->irq; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci *data = 0; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* Hook up test interrupt handler just for this test */ 141362306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_HAS_MSIX) { 141462306a36Sopenharmony_ci if (request_irq(adapter->msix_entries[0].vector, 141562306a36Sopenharmony_ci igb_test_intr, 0, netdev->name, adapter)) { 141662306a36Sopenharmony_ci *data = 1; 141762306a36Sopenharmony_ci return -1; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci wr32(E1000_IVAR_MISC, E1000_IVAR_VALID << 8); 142062306a36Sopenharmony_ci wr32(E1000_EIMS, BIT(0)); 142162306a36Sopenharmony_ci } else if (adapter->flags & IGB_FLAG_HAS_MSI) { 142262306a36Sopenharmony_ci shared_int = false; 142362306a36Sopenharmony_ci if (request_irq(irq, 142462306a36Sopenharmony_ci igb_test_intr, 0, netdev->name, adapter)) { 142562306a36Sopenharmony_ci *data = 1; 142662306a36Sopenharmony_ci return -1; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci } else if (!request_irq(irq, igb_test_intr, IRQF_PROBE_SHARED, 142962306a36Sopenharmony_ci netdev->name, adapter)) { 143062306a36Sopenharmony_ci shared_int = false; 143162306a36Sopenharmony_ci } else if (request_irq(irq, igb_test_intr, IRQF_SHARED, 143262306a36Sopenharmony_ci netdev->name, adapter)) { 143362306a36Sopenharmony_ci *data = 1; 143462306a36Sopenharmony_ci return -1; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "testing %s interrupt\n", 143762306a36Sopenharmony_ci (shared_int ? "shared" : "unshared")); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci /* Disable all the interrupts */ 144062306a36Sopenharmony_ci wr32(E1000_IMC, ~0); 144162306a36Sopenharmony_ci wrfl(); 144262306a36Sopenharmony_ci usleep_range(10000, 11000); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci /* Define all writable bits for ICS */ 144562306a36Sopenharmony_ci switch (hw->mac.type) { 144662306a36Sopenharmony_ci case e1000_82575: 144762306a36Sopenharmony_ci ics_mask = 0x37F47EDD; 144862306a36Sopenharmony_ci break; 144962306a36Sopenharmony_ci case e1000_82576: 145062306a36Sopenharmony_ci ics_mask = 0x77D4FBFD; 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci case e1000_82580: 145362306a36Sopenharmony_ci ics_mask = 0x77DCFED5; 145462306a36Sopenharmony_ci break; 145562306a36Sopenharmony_ci case e1000_i350: 145662306a36Sopenharmony_ci case e1000_i354: 145762306a36Sopenharmony_ci case e1000_i210: 145862306a36Sopenharmony_ci case e1000_i211: 145962306a36Sopenharmony_ci ics_mask = 0x77DCFED5; 146062306a36Sopenharmony_ci break; 146162306a36Sopenharmony_ci default: 146262306a36Sopenharmony_ci ics_mask = 0x7FFFFFFF; 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* Test each interrupt */ 146762306a36Sopenharmony_ci for (; i < 31; i++) { 146862306a36Sopenharmony_ci /* Interrupt to test */ 146962306a36Sopenharmony_ci mask = BIT(i); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci if (!(mask & ics_mask)) 147262306a36Sopenharmony_ci continue; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (!shared_int) { 147562306a36Sopenharmony_ci /* Disable the interrupt to be reported in 147662306a36Sopenharmony_ci * the cause register and then force the same 147762306a36Sopenharmony_ci * interrupt and see if one gets posted. If 147862306a36Sopenharmony_ci * an interrupt was posted to the bus, the 147962306a36Sopenharmony_ci * test failed. 148062306a36Sopenharmony_ci */ 148162306a36Sopenharmony_ci adapter->test_icr = 0; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci /* Flush any pending interrupts */ 148462306a36Sopenharmony_ci wr32(E1000_ICR, ~0); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci wr32(E1000_IMC, mask); 148762306a36Sopenharmony_ci wr32(E1000_ICS, mask); 148862306a36Sopenharmony_ci wrfl(); 148962306a36Sopenharmony_ci usleep_range(10000, 11000); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (adapter->test_icr & mask) { 149262306a36Sopenharmony_ci *data = 3; 149362306a36Sopenharmony_ci break; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci /* Enable the interrupt to be reported in 149862306a36Sopenharmony_ci * the cause register and then force the same 149962306a36Sopenharmony_ci * interrupt and see if one gets posted. If 150062306a36Sopenharmony_ci * an interrupt was not posted to the bus, the 150162306a36Sopenharmony_ci * test failed. 150262306a36Sopenharmony_ci */ 150362306a36Sopenharmony_ci adapter->test_icr = 0; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci /* Flush any pending interrupts */ 150662306a36Sopenharmony_ci wr32(E1000_ICR, ~0); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci wr32(E1000_IMS, mask); 150962306a36Sopenharmony_ci wr32(E1000_ICS, mask); 151062306a36Sopenharmony_ci wrfl(); 151162306a36Sopenharmony_ci usleep_range(10000, 11000); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if (!(adapter->test_icr & mask)) { 151462306a36Sopenharmony_ci *data = 4; 151562306a36Sopenharmony_ci break; 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if (!shared_int) { 151962306a36Sopenharmony_ci /* Disable the other interrupts to be reported in 152062306a36Sopenharmony_ci * the cause register and then force the other 152162306a36Sopenharmony_ci * interrupts and see if any get posted. If 152262306a36Sopenharmony_ci * an interrupt was posted to the bus, the 152362306a36Sopenharmony_ci * test failed. 152462306a36Sopenharmony_ci */ 152562306a36Sopenharmony_ci adapter->test_icr = 0; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci /* Flush any pending interrupts */ 152862306a36Sopenharmony_ci wr32(E1000_ICR, ~0); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci wr32(E1000_IMC, ~mask); 153162306a36Sopenharmony_ci wr32(E1000_ICS, ~mask); 153262306a36Sopenharmony_ci wrfl(); 153362306a36Sopenharmony_ci usleep_range(10000, 11000); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci if (adapter->test_icr & mask) { 153662306a36Sopenharmony_ci *data = 5; 153762306a36Sopenharmony_ci break; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* Disable all the interrupts */ 154362306a36Sopenharmony_ci wr32(E1000_IMC, ~0); 154462306a36Sopenharmony_ci wrfl(); 154562306a36Sopenharmony_ci usleep_range(10000, 11000); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci /* Unhook test interrupt handler */ 154862306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_HAS_MSIX) 154962306a36Sopenharmony_ci free_irq(adapter->msix_entries[0].vector, adapter); 155062306a36Sopenharmony_ci else 155162306a36Sopenharmony_ci free_irq(irq, adapter); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci return *data; 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic void igb_free_desc_rings(struct igb_adapter *adapter) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci igb_free_tx_resources(&adapter->test_tx_ring); 155962306a36Sopenharmony_ci igb_free_rx_resources(&adapter->test_rx_ring); 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic int igb_setup_desc_rings(struct igb_adapter *adapter) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci struct igb_ring *tx_ring = &adapter->test_tx_ring; 156562306a36Sopenharmony_ci struct igb_ring *rx_ring = &adapter->test_rx_ring; 156662306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 156762306a36Sopenharmony_ci int ret_val; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* Setup Tx descriptor ring and Tx buffers */ 157062306a36Sopenharmony_ci tx_ring->count = IGB_DEFAULT_TXD; 157162306a36Sopenharmony_ci tx_ring->dev = &adapter->pdev->dev; 157262306a36Sopenharmony_ci tx_ring->netdev = adapter->netdev; 157362306a36Sopenharmony_ci tx_ring->reg_idx = adapter->vfs_allocated_count; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (igb_setup_tx_resources(tx_ring)) { 157662306a36Sopenharmony_ci ret_val = 1; 157762306a36Sopenharmony_ci goto err_nomem; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci igb_setup_tctl(adapter); 158162306a36Sopenharmony_ci igb_configure_tx_ring(adapter, tx_ring); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci /* Setup Rx descriptor ring and Rx buffers */ 158462306a36Sopenharmony_ci rx_ring->count = IGB_DEFAULT_RXD; 158562306a36Sopenharmony_ci rx_ring->dev = &adapter->pdev->dev; 158662306a36Sopenharmony_ci rx_ring->netdev = adapter->netdev; 158762306a36Sopenharmony_ci rx_ring->reg_idx = adapter->vfs_allocated_count; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci if (igb_setup_rx_resources(rx_ring)) { 159062306a36Sopenharmony_ci ret_val = 3; 159162306a36Sopenharmony_ci goto err_nomem; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci /* set the default queue to queue 0 of PF */ 159562306a36Sopenharmony_ci wr32(E1000_MRQC, adapter->vfs_allocated_count << 3); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* enable receive ring */ 159862306a36Sopenharmony_ci igb_setup_rctl(adapter); 159962306a36Sopenharmony_ci igb_configure_rx_ring(adapter, rx_ring); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci igb_alloc_rx_buffers(rx_ring, igb_desc_unused(rx_ring)); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci return 0; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cierr_nomem: 160662306a36Sopenharmony_ci igb_free_desc_rings(adapter); 160762306a36Sopenharmony_ci return ret_val; 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_cistatic void igb_phy_disable_receiver(struct igb_adapter *adapter) 161162306a36Sopenharmony_ci{ 161262306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci /* Write out to PHY registers 29 and 30 to disable the Receiver. */ 161562306a36Sopenharmony_ci igb_write_phy_reg(hw, 29, 0x001F); 161662306a36Sopenharmony_ci igb_write_phy_reg(hw, 30, 0x8FFC); 161762306a36Sopenharmony_ci igb_write_phy_reg(hw, 29, 0x001A); 161862306a36Sopenharmony_ci igb_write_phy_reg(hw, 30, 0x8FF0); 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic int igb_integrated_phy_loopback(struct igb_adapter *adapter) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 162462306a36Sopenharmony_ci u32 ctrl_reg = 0; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci hw->mac.autoneg = false; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci if (hw->phy.type == e1000_phy_m88) { 162962306a36Sopenharmony_ci if (hw->phy.id != I210_I_PHY_ID) { 163062306a36Sopenharmony_ci /* Auto-MDI/MDIX Off */ 163162306a36Sopenharmony_ci igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); 163262306a36Sopenharmony_ci /* reset to update Auto-MDI/MDIX */ 163362306a36Sopenharmony_ci igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); 163462306a36Sopenharmony_ci /* autoneg off */ 163562306a36Sopenharmony_ci igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); 163662306a36Sopenharmony_ci } else { 163762306a36Sopenharmony_ci /* force 1000, set loopback */ 163862306a36Sopenharmony_ci igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0); 163962306a36Sopenharmony_ci igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci } else if (hw->phy.type == e1000_phy_82580) { 164262306a36Sopenharmony_ci /* enable MII loopback */ 164362306a36Sopenharmony_ci igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041); 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci /* add small delay to avoid loopback test failure */ 164762306a36Sopenharmony_ci msleep(50); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci /* force 1000, set loopback */ 165062306a36Sopenharmony_ci igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* Now set up the MAC to the same speed/duplex as the PHY. */ 165362306a36Sopenharmony_ci ctrl_reg = rd32(E1000_CTRL); 165462306a36Sopenharmony_ci ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ 165562306a36Sopenharmony_ci ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ 165662306a36Sopenharmony_ci E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ 165762306a36Sopenharmony_ci E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ 165862306a36Sopenharmony_ci E1000_CTRL_FD | /* Force Duplex to FULL */ 165962306a36Sopenharmony_ci E1000_CTRL_SLU); /* Set link up enable bit */ 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci if (hw->phy.type == e1000_phy_m88) 166262306a36Sopenharmony_ci ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci wr32(E1000_CTRL, ctrl_reg); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci /* Disable the receiver on the PHY so when a cable is plugged in, the 166762306a36Sopenharmony_ci * PHY does not begin to autoneg when a cable is reconnected to the NIC. 166862306a36Sopenharmony_ci */ 166962306a36Sopenharmony_ci if (hw->phy.type == e1000_phy_m88) 167062306a36Sopenharmony_ci igb_phy_disable_receiver(adapter); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci msleep(500); 167362306a36Sopenharmony_ci return 0; 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_cistatic int igb_set_phy_loopback(struct igb_adapter *adapter) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci return igb_integrated_phy_loopback(adapter); 167962306a36Sopenharmony_ci} 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_cistatic int igb_setup_loopback_test(struct igb_adapter *adapter) 168262306a36Sopenharmony_ci{ 168362306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 168462306a36Sopenharmony_ci u32 reg; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci reg = rd32(E1000_CTRL_EXT); 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci /* use CTRL_EXT to identify link type as SGMII can appear as copper */ 168962306a36Sopenharmony_ci if (reg & E1000_CTRL_EXT_LINK_MODE_MASK) { 169062306a36Sopenharmony_ci if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) || 169162306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) || 169262306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) || 169362306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_DH89XXCC_SFP) || 169462306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_I354_SGMII) || 169562306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_I354_BACKPLANE_2_5GBPS)) { 169662306a36Sopenharmony_ci /* Enable DH89xxCC MPHY for near end loopback */ 169762306a36Sopenharmony_ci reg = rd32(E1000_MPHY_ADDR_CTL); 169862306a36Sopenharmony_ci reg = (reg & E1000_MPHY_ADDR_CTL_OFFSET_MASK) | 169962306a36Sopenharmony_ci E1000_MPHY_PCS_CLK_REG_OFFSET; 170062306a36Sopenharmony_ci wr32(E1000_MPHY_ADDR_CTL, reg); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci reg = rd32(E1000_MPHY_DATA); 170362306a36Sopenharmony_ci reg |= E1000_MPHY_PCS_CLK_REG_DIGINELBEN; 170462306a36Sopenharmony_ci wr32(E1000_MPHY_DATA, reg); 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci reg = rd32(E1000_RCTL); 170862306a36Sopenharmony_ci reg |= E1000_RCTL_LBM_TCVR; 170962306a36Sopenharmony_ci wr32(E1000_RCTL, reg); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci wr32(E1000_SCTL, E1000_ENABLE_SERDES_LOOPBACK); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci reg = rd32(E1000_CTRL); 171462306a36Sopenharmony_ci reg &= ~(E1000_CTRL_RFCE | 171562306a36Sopenharmony_ci E1000_CTRL_TFCE | 171662306a36Sopenharmony_ci E1000_CTRL_LRST); 171762306a36Sopenharmony_ci reg |= E1000_CTRL_SLU | 171862306a36Sopenharmony_ci E1000_CTRL_FD; 171962306a36Sopenharmony_ci wr32(E1000_CTRL, reg); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci /* Unset switch control to serdes energy detect */ 172262306a36Sopenharmony_ci reg = rd32(E1000_CONNSW); 172362306a36Sopenharmony_ci reg &= ~E1000_CONNSW_ENRGSRC; 172462306a36Sopenharmony_ci wr32(E1000_CONNSW, reg); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci /* Unset sigdetect for SERDES loopback on 172762306a36Sopenharmony_ci * 82580 and newer devices. 172862306a36Sopenharmony_ci */ 172962306a36Sopenharmony_ci if (hw->mac.type >= e1000_82580) { 173062306a36Sopenharmony_ci reg = rd32(E1000_PCS_CFG0); 173162306a36Sopenharmony_ci reg |= E1000_PCS_CFG_IGN_SD; 173262306a36Sopenharmony_ci wr32(E1000_PCS_CFG0, reg); 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci /* Set PCS register for forced speed */ 173662306a36Sopenharmony_ci reg = rd32(E1000_PCS_LCTL); 173762306a36Sopenharmony_ci reg &= ~E1000_PCS_LCTL_AN_ENABLE; /* Disable Autoneg*/ 173862306a36Sopenharmony_ci reg |= E1000_PCS_LCTL_FLV_LINK_UP | /* Force link up */ 173962306a36Sopenharmony_ci E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */ 174062306a36Sopenharmony_ci E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ 174162306a36Sopenharmony_ci E1000_PCS_LCTL_FSD | /* Force Speed */ 174262306a36Sopenharmony_ci E1000_PCS_LCTL_FORCE_LINK; /* Force Link */ 174362306a36Sopenharmony_ci wr32(E1000_PCS_LCTL, reg); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci return 0; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci return igb_set_phy_loopback(adapter); 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_cistatic void igb_loopback_cleanup(struct igb_adapter *adapter) 175262306a36Sopenharmony_ci{ 175362306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 175462306a36Sopenharmony_ci u32 rctl; 175562306a36Sopenharmony_ci u16 phy_reg; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) || 175862306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) || 175962306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) || 176062306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_DH89XXCC_SFP) || 176162306a36Sopenharmony_ci (hw->device_id == E1000_DEV_ID_I354_SGMII)) { 176262306a36Sopenharmony_ci u32 reg; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci /* Disable near end loopback on DH89xxCC */ 176562306a36Sopenharmony_ci reg = rd32(E1000_MPHY_ADDR_CTL); 176662306a36Sopenharmony_ci reg = (reg & E1000_MPHY_ADDR_CTL_OFFSET_MASK) | 176762306a36Sopenharmony_ci E1000_MPHY_PCS_CLK_REG_OFFSET; 176862306a36Sopenharmony_ci wr32(E1000_MPHY_ADDR_CTL, reg); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci reg = rd32(E1000_MPHY_DATA); 177162306a36Sopenharmony_ci reg &= ~E1000_MPHY_PCS_CLK_REG_DIGINELBEN; 177262306a36Sopenharmony_ci wr32(E1000_MPHY_DATA, reg); 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci rctl = rd32(E1000_RCTL); 177662306a36Sopenharmony_ci rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); 177762306a36Sopenharmony_ci wr32(E1000_RCTL, rctl); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci hw->mac.autoneg = true; 178062306a36Sopenharmony_ci igb_read_phy_reg(hw, PHY_CONTROL, &phy_reg); 178162306a36Sopenharmony_ci if (phy_reg & MII_CR_LOOPBACK) { 178262306a36Sopenharmony_ci phy_reg &= ~MII_CR_LOOPBACK; 178362306a36Sopenharmony_ci igb_write_phy_reg(hw, PHY_CONTROL, phy_reg); 178462306a36Sopenharmony_ci igb_phy_sw_reset(hw); 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci} 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_cistatic void igb_create_lbtest_frame(struct sk_buff *skb, 178962306a36Sopenharmony_ci unsigned int frame_size) 179062306a36Sopenharmony_ci{ 179162306a36Sopenharmony_ci memset(skb->data, 0xFF, frame_size); 179262306a36Sopenharmony_ci frame_size /= 2; 179362306a36Sopenharmony_ci memset(&skb->data[frame_size], 0xAA, frame_size - 1); 179462306a36Sopenharmony_ci skb->data[frame_size + 10] = 0xBE; 179562306a36Sopenharmony_ci skb->data[frame_size + 12] = 0xAF; 179662306a36Sopenharmony_ci} 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_cistatic int igb_check_lbtest_frame(struct igb_rx_buffer *rx_buffer, 179962306a36Sopenharmony_ci unsigned int frame_size) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci unsigned char *data; 180262306a36Sopenharmony_ci bool match = true; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci frame_size >>= 1; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci data = kmap_local_page(rx_buffer->page); 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci if (data[3] != 0xFF || 180962306a36Sopenharmony_ci data[frame_size + 10] != 0xBE || 181062306a36Sopenharmony_ci data[frame_size + 12] != 0xAF) 181162306a36Sopenharmony_ci match = false; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci kunmap_local(data); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci return match; 181662306a36Sopenharmony_ci} 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_cistatic int igb_clean_test_rings(struct igb_ring *rx_ring, 181962306a36Sopenharmony_ci struct igb_ring *tx_ring, 182062306a36Sopenharmony_ci unsigned int size) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci union e1000_adv_rx_desc *rx_desc; 182362306a36Sopenharmony_ci struct igb_rx_buffer *rx_buffer_info; 182462306a36Sopenharmony_ci struct igb_tx_buffer *tx_buffer_info; 182562306a36Sopenharmony_ci u16 rx_ntc, tx_ntc, count = 0; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci /* initialize next to clean and descriptor values */ 182862306a36Sopenharmony_ci rx_ntc = rx_ring->next_to_clean; 182962306a36Sopenharmony_ci tx_ntc = tx_ring->next_to_clean; 183062306a36Sopenharmony_ci rx_desc = IGB_RX_DESC(rx_ring, rx_ntc); 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci while (rx_desc->wb.upper.length) { 183362306a36Sopenharmony_ci /* check Rx buffer */ 183462306a36Sopenharmony_ci rx_buffer_info = &rx_ring->rx_buffer_info[rx_ntc]; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci /* sync Rx buffer for CPU read */ 183762306a36Sopenharmony_ci dma_sync_single_for_cpu(rx_ring->dev, 183862306a36Sopenharmony_ci rx_buffer_info->dma, 183962306a36Sopenharmony_ci size, 184062306a36Sopenharmony_ci DMA_FROM_DEVICE); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* verify contents of skb */ 184362306a36Sopenharmony_ci if (igb_check_lbtest_frame(rx_buffer_info, size)) 184462306a36Sopenharmony_ci count++; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci /* sync Rx buffer for device write */ 184762306a36Sopenharmony_ci dma_sync_single_for_device(rx_ring->dev, 184862306a36Sopenharmony_ci rx_buffer_info->dma, 184962306a36Sopenharmony_ci size, 185062306a36Sopenharmony_ci DMA_FROM_DEVICE); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci /* unmap buffer on Tx side */ 185362306a36Sopenharmony_ci tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc]; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci /* Free all the Tx ring sk_buffs */ 185662306a36Sopenharmony_ci dev_kfree_skb_any(tx_buffer_info->skb); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci /* unmap skb header data */ 185962306a36Sopenharmony_ci dma_unmap_single(tx_ring->dev, 186062306a36Sopenharmony_ci dma_unmap_addr(tx_buffer_info, dma), 186162306a36Sopenharmony_ci dma_unmap_len(tx_buffer_info, len), 186262306a36Sopenharmony_ci DMA_TO_DEVICE); 186362306a36Sopenharmony_ci dma_unmap_len_set(tx_buffer_info, len, 0); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci /* increment Rx/Tx next to clean counters */ 186662306a36Sopenharmony_ci rx_ntc++; 186762306a36Sopenharmony_ci if (rx_ntc == rx_ring->count) 186862306a36Sopenharmony_ci rx_ntc = 0; 186962306a36Sopenharmony_ci tx_ntc++; 187062306a36Sopenharmony_ci if (tx_ntc == tx_ring->count) 187162306a36Sopenharmony_ci tx_ntc = 0; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci /* fetch next descriptor */ 187462306a36Sopenharmony_ci rx_desc = IGB_RX_DESC(rx_ring, rx_ntc); 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci netdev_tx_reset_queue(txring_txq(tx_ring)); 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci /* re-map buffers to ring, store next to clean values */ 188062306a36Sopenharmony_ci igb_alloc_rx_buffers(rx_ring, count); 188162306a36Sopenharmony_ci rx_ring->next_to_clean = rx_ntc; 188262306a36Sopenharmony_ci tx_ring->next_to_clean = tx_ntc; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci return count; 188562306a36Sopenharmony_ci} 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_cistatic int igb_run_loopback_test(struct igb_adapter *adapter) 188862306a36Sopenharmony_ci{ 188962306a36Sopenharmony_ci struct igb_ring *tx_ring = &adapter->test_tx_ring; 189062306a36Sopenharmony_ci struct igb_ring *rx_ring = &adapter->test_rx_ring; 189162306a36Sopenharmony_ci u16 i, j, lc, good_cnt; 189262306a36Sopenharmony_ci int ret_val = 0; 189362306a36Sopenharmony_ci unsigned int size = IGB_RX_HDR_LEN; 189462306a36Sopenharmony_ci netdev_tx_t tx_ret_val; 189562306a36Sopenharmony_ci struct sk_buff *skb; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci /* allocate test skb */ 189862306a36Sopenharmony_ci skb = alloc_skb(size, GFP_KERNEL); 189962306a36Sopenharmony_ci if (!skb) 190062306a36Sopenharmony_ci return 11; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* place data into test skb */ 190362306a36Sopenharmony_ci igb_create_lbtest_frame(skb, size); 190462306a36Sopenharmony_ci skb_put(skb, size); 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci /* Calculate the loop count based on the largest descriptor ring 190762306a36Sopenharmony_ci * The idea is to wrap the largest ring a number of times using 64 190862306a36Sopenharmony_ci * send/receive pairs during each loop 190962306a36Sopenharmony_ci */ 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci if (rx_ring->count <= tx_ring->count) 191262306a36Sopenharmony_ci lc = ((tx_ring->count / 64) * 2) + 1; 191362306a36Sopenharmony_ci else 191462306a36Sopenharmony_ci lc = ((rx_ring->count / 64) * 2) + 1; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci for (j = 0; j <= lc; j++) { /* loop count loop */ 191762306a36Sopenharmony_ci /* reset count of good packets */ 191862306a36Sopenharmony_ci good_cnt = 0; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci /* place 64 packets on the transmit queue*/ 192162306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 192262306a36Sopenharmony_ci skb_get(skb); 192362306a36Sopenharmony_ci tx_ret_val = igb_xmit_frame_ring(skb, tx_ring); 192462306a36Sopenharmony_ci if (tx_ret_val == NETDEV_TX_OK) 192562306a36Sopenharmony_ci good_cnt++; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci if (good_cnt != 64) { 192962306a36Sopenharmony_ci ret_val = 12; 193062306a36Sopenharmony_ci break; 193162306a36Sopenharmony_ci } 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci /* allow 200 milliseconds for packets to go from Tx to Rx */ 193462306a36Sopenharmony_ci msleep(200); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci good_cnt = igb_clean_test_rings(rx_ring, tx_ring, size); 193762306a36Sopenharmony_ci if (good_cnt != 64) { 193862306a36Sopenharmony_ci ret_val = 13; 193962306a36Sopenharmony_ci break; 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci } /* end loop count loop */ 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci /* free the original skb */ 194462306a36Sopenharmony_ci kfree_skb(skb); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci return ret_val; 194762306a36Sopenharmony_ci} 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_cistatic int igb_loopback_test(struct igb_adapter *adapter, u64 *data) 195062306a36Sopenharmony_ci{ 195162306a36Sopenharmony_ci /* PHY loopback cannot be performed if SoL/IDER 195262306a36Sopenharmony_ci * sessions are active 195362306a36Sopenharmony_ci */ 195462306a36Sopenharmony_ci if (igb_check_reset_block(&adapter->hw)) { 195562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 195662306a36Sopenharmony_ci "Cannot do PHY loopback test when SoL/IDER is active.\n"); 195762306a36Sopenharmony_ci *data = 0; 195862306a36Sopenharmony_ci goto out; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci if (adapter->hw.mac.type == e1000_i354) { 196262306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, 196362306a36Sopenharmony_ci "Loopback test not supported on i354.\n"); 196462306a36Sopenharmony_ci *data = 0; 196562306a36Sopenharmony_ci goto out; 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci *data = igb_setup_desc_rings(adapter); 196862306a36Sopenharmony_ci if (*data) 196962306a36Sopenharmony_ci goto out; 197062306a36Sopenharmony_ci *data = igb_setup_loopback_test(adapter); 197162306a36Sopenharmony_ci if (*data) 197262306a36Sopenharmony_ci goto err_loopback; 197362306a36Sopenharmony_ci *data = igb_run_loopback_test(adapter); 197462306a36Sopenharmony_ci igb_loopback_cleanup(adapter); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_cierr_loopback: 197762306a36Sopenharmony_ci igb_free_desc_rings(adapter); 197862306a36Sopenharmony_ciout: 197962306a36Sopenharmony_ci return *data; 198062306a36Sopenharmony_ci} 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_cistatic int igb_link_test(struct igb_adapter *adapter, u64 *data) 198362306a36Sopenharmony_ci{ 198462306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 198562306a36Sopenharmony_ci *data = 0; 198662306a36Sopenharmony_ci if (hw->phy.media_type == e1000_media_type_internal_serdes) { 198762306a36Sopenharmony_ci int i = 0; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci hw->mac.serdes_has_link = false; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci /* On some blade server designs, link establishment 199262306a36Sopenharmony_ci * could take as long as 2-3 minutes 199362306a36Sopenharmony_ci */ 199462306a36Sopenharmony_ci do { 199562306a36Sopenharmony_ci hw->mac.ops.check_for_link(&adapter->hw); 199662306a36Sopenharmony_ci if (hw->mac.serdes_has_link) 199762306a36Sopenharmony_ci return *data; 199862306a36Sopenharmony_ci msleep(20); 199962306a36Sopenharmony_ci } while (i++ < 3750); 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci *data = 1; 200262306a36Sopenharmony_ci } else { 200362306a36Sopenharmony_ci hw->mac.ops.check_for_link(&adapter->hw); 200462306a36Sopenharmony_ci if (hw->mac.autoneg) 200562306a36Sopenharmony_ci msleep(5000); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (!(rd32(E1000_STATUS) & E1000_STATUS_LU)) 200862306a36Sopenharmony_ci *data = 1; 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci return *data; 201162306a36Sopenharmony_ci} 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_cistatic void igb_diag_test(struct net_device *netdev, 201462306a36Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 201562306a36Sopenharmony_ci{ 201662306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 201762306a36Sopenharmony_ci u16 autoneg_advertised; 201862306a36Sopenharmony_ci u8 forced_speed_duplex, autoneg; 201962306a36Sopenharmony_ci bool if_running = netif_running(netdev); 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci set_bit(__IGB_TESTING, &adapter->state); 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci /* can't do offline tests on media switching devices */ 202462306a36Sopenharmony_ci if (adapter->hw.dev_spec._82575.mas_capable) 202562306a36Sopenharmony_ci eth_test->flags &= ~ETH_TEST_FL_OFFLINE; 202662306a36Sopenharmony_ci if (eth_test->flags == ETH_TEST_FL_OFFLINE) { 202762306a36Sopenharmony_ci /* Offline tests */ 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci /* save speed, duplex, autoneg settings */ 203062306a36Sopenharmony_ci autoneg_advertised = adapter->hw.phy.autoneg_advertised; 203162306a36Sopenharmony_ci forced_speed_duplex = adapter->hw.mac.forced_speed_duplex; 203262306a36Sopenharmony_ci autoneg = adapter->hw.mac.autoneg; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "offline testing starting\n"); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci /* power up link for link test */ 203762306a36Sopenharmony_ci igb_power_up_link(adapter); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci /* Link test performed before hardware reset so autoneg doesn't 204062306a36Sopenharmony_ci * interfere with test result 204162306a36Sopenharmony_ci */ 204262306a36Sopenharmony_ci if (igb_link_test(adapter, &data[TEST_LINK])) 204362306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci if (if_running) 204662306a36Sopenharmony_ci /* indicate we're in test mode */ 204762306a36Sopenharmony_ci igb_close(netdev); 204862306a36Sopenharmony_ci else 204962306a36Sopenharmony_ci igb_reset(adapter); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if (igb_reg_test(adapter, &data[TEST_REG])) 205262306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci igb_reset(adapter); 205562306a36Sopenharmony_ci if (igb_eeprom_test(adapter, &data[TEST_EEP])) 205662306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci igb_reset(adapter); 205962306a36Sopenharmony_ci if (igb_intr_test(adapter, &data[TEST_IRQ])) 206062306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci igb_reset(adapter); 206362306a36Sopenharmony_ci /* power up link for loopback test */ 206462306a36Sopenharmony_ci igb_power_up_link(adapter); 206562306a36Sopenharmony_ci if (igb_loopback_test(adapter, &data[TEST_LOOP])) 206662306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci /* restore speed, duplex, autoneg settings */ 206962306a36Sopenharmony_ci adapter->hw.phy.autoneg_advertised = autoneg_advertised; 207062306a36Sopenharmony_ci adapter->hw.mac.forced_speed_duplex = forced_speed_duplex; 207162306a36Sopenharmony_ci adapter->hw.mac.autoneg = autoneg; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci /* force this routine to wait until autoneg complete/timeout */ 207462306a36Sopenharmony_ci adapter->hw.phy.autoneg_wait_to_complete = true; 207562306a36Sopenharmony_ci igb_reset(adapter); 207662306a36Sopenharmony_ci adapter->hw.phy.autoneg_wait_to_complete = false; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci clear_bit(__IGB_TESTING, &adapter->state); 207962306a36Sopenharmony_ci if (if_running) 208062306a36Sopenharmony_ci igb_open(netdev); 208162306a36Sopenharmony_ci } else { 208262306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "online testing starting\n"); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* PHY is powered down when interface is down */ 208562306a36Sopenharmony_ci if (if_running && igb_link_test(adapter, &data[TEST_LINK])) 208662306a36Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 208762306a36Sopenharmony_ci else 208862306a36Sopenharmony_ci data[TEST_LINK] = 0; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci /* Online tests aren't run; pass by default */ 209162306a36Sopenharmony_ci data[TEST_REG] = 0; 209262306a36Sopenharmony_ci data[TEST_EEP] = 0; 209362306a36Sopenharmony_ci data[TEST_IRQ] = 0; 209462306a36Sopenharmony_ci data[TEST_LOOP] = 0; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci clear_bit(__IGB_TESTING, &adapter->state); 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci msleep_interruptible(4 * 1000); 209962306a36Sopenharmony_ci} 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_cistatic void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 210262306a36Sopenharmony_ci{ 210362306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci wol->wolopts = 0; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci if (!(adapter->flags & IGB_FLAG_WOL_SUPPORTED)) 210862306a36Sopenharmony_ci return; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci wol->supported = WAKE_UCAST | WAKE_MCAST | 211162306a36Sopenharmony_ci WAKE_BCAST | WAKE_MAGIC | 211262306a36Sopenharmony_ci WAKE_PHY; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci /* apply any specific unsupported masks here */ 211562306a36Sopenharmony_ci switch (adapter->hw.device_id) { 211662306a36Sopenharmony_ci default: 211762306a36Sopenharmony_ci break; 211862306a36Sopenharmony_ci } 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci if (adapter->wol & E1000_WUFC_EX) 212162306a36Sopenharmony_ci wol->wolopts |= WAKE_UCAST; 212262306a36Sopenharmony_ci if (adapter->wol & E1000_WUFC_MC) 212362306a36Sopenharmony_ci wol->wolopts |= WAKE_MCAST; 212462306a36Sopenharmony_ci if (adapter->wol & E1000_WUFC_BC) 212562306a36Sopenharmony_ci wol->wolopts |= WAKE_BCAST; 212662306a36Sopenharmony_ci if (adapter->wol & E1000_WUFC_MAG) 212762306a36Sopenharmony_ci wol->wolopts |= WAKE_MAGIC; 212862306a36Sopenharmony_ci if (adapter->wol & E1000_WUFC_LNKC) 212962306a36Sopenharmony_ci wol->wolopts |= WAKE_PHY; 213062306a36Sopenharmony_ci} 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_cistatic int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 213362306a36Sopenharmony_ci{ 213462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER)) 213762306a36Sopenharmony_ci return -EOPNOTSUPP; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (!(adapter->flags & IGB_FLAG_WOL_SUPPORTED)) 214062306a36Sopenharmony_ci return wol->wolopts ? -EOPNOTSUPP : 0; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci /* these settings will always override what we currently have */ 214362306a36Sopenharmony_ci adapter->wol = 0; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (wol->wolopts & WAKE_UCAST) 214662306a36Sopenharmony_ci adapter->wol |= E1000_WUFC_EX; 214762306a36Sopenharmony_ci if (wol->wolopts & WAKE_MCAST) 214862306a36Sopenharmony_ci adapter->wol |= E1000_WUFC_MC; 214962306a36Sopenharmony_ci if (wol->wolopts & WAKE_BCAST) 215062306a36Sopenharmony_ci adapter->wol |= E1000_WUFC_BC; 215162306a36Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) 215262306a36Sopenharmony_ci adapter->wol |= E1000_WUFC_MAG; 215362306a36Sopenharmony_ci if (wol->wolopts & WAKE_PHY) 215462306a36Sopenharmony_ci adapter->wol |= E1000_WUFC_LNKC; 215562306a36Sopenharmony_ci device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci return 0; 215862306a36Sopenharmony_ci} 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci/* bit defines for adapter->led_status */ 216162306a36Sopenharmony_ci#define IGB_LED_ON 0 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_cistatic int igb_set_phys_id(struct net_device *netdev, 216462306a36Sopenharmony_ci enum ethtool_phys_id_state state) 216562306a36Sopenharmony_ci{ 216662306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 216762306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci switch (state) { 217062306a36Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 217162306a36Sopenharmony_ci igb_blink_led(hw); 217262306a36Sopenharmony_ci return 2; 217362306a36Sopenharmony_ci case ETHTOOL_ID_ON: 217462306a36Sopenharmony_ci igb_blink_led(hw); 217562306a36Sopenharmony_ci break; 217662306a36Sopenharmony_ci case ETHTOOL_ID_OFF: 217762306a36Sopenharmony_ci igb_led_off(hw); 217862306a36Sopenharmony_ci break; 217962306a36Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 218062306a36Sopenharmony_ci igb_led_off(hw); 218162306a36Sopenharmony_ci clear_bit(IGB_LED_ON, &adapter->led_status); 218262306a36Sopenharmony_ci igb_cleanup_led(hw); 218362306a36Sopenharmony_ci break; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci return 0; 218762306a36Sopenharmony_ci} 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_cistatic int igb_set_coalesce(struct net_device *netdev, 219062306a36Sopenharmony_ci struct ethtool_coalesce *ec, 219162306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 219262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 219562306a36Sopenharmony_ci int i; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) || 219862306a36Sopenharmony_ci ((ec->rx_coalesce_usecs > 3) && 219962306a36Sopenharmony_ci (ec->rx_coalesce_usecs < IGB_MIN_ITR_USECS)) || 220062306a36Sopenharmony_ci (ec->rx_coalesce_usecs == 2)) 220162306a36Sopenharmony_ci return -EINVAL; 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci if ((ec->tx_coalesce_usecs > IGB_MAX_ITR_USECS) || 220462306a36Sopenharmony_ci ((ec->tx_coalesce_usecs > 3) && 220562306a36Sopenharmony_ci (ec->tx_coalesce_usecs < IGB_MIN_ITR_USECS)) || 220662306a36Sopenharmony_ci (ec->tx_coalesce_usecs == 2)) 220762306a36Sopenharmony_ci return -EINVAL; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci if ((adapter->flags & IGB_FLAG_QUEUE_PAIRS) && ec->tx_coalesce_usecs) 221062306a36Sopenharmony_ci return -EINVAL; 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci /* If ITR is disabled, disable DMAC */ 221362306a36Sopenharmony_ci if (ec->rx_coalesce_usecs == 0) { 221462306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_DMAC) 221562306a36Sopenharmony_ci adapter->flags &= ~IGB_FLAG_DMAC; 221662306a36Sopenharmony_ci } 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci /* convert to rate of irq's per second */ 221962306a36Sopenharmony_ci if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) 222062306a36Sopenharmony_ci adapter->rx_itr_setting = ec->rx_coalesce_usecs; 222162306a36Sopenharmony_ci else 222262306a36Sopenharmony_ci adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2; 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci /* convert to rate of irq's per second */ 222562306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_QUEUE_PAIRS) 222662306a36Sopenharmony_ci adapter->tx_itr_setting = adapter->rx_itr_setting; 222762306a36Sopenharmony_ci else if (ec->tx_coalesce_usecs && ec->tx_coalesce_usecs <= 3) 222862306a36Sopenharmony_ci adapter->tx_itr_setting = ec->tx_coalesce_usecs; 222962306a36Sopenharmony_ci else 223062306a36Sopenharmony_ci adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci for (i = 0; i < adapter->num_q_vectors; i++) { 223362306a36Sopenharmony_ci struct igb_q_vector *q_vector = adapter->q_vector[i]; 223462306a36Sopenharmony_ci q_vector->tx.work_limit = adapter->tx_work_limit; 223562306a36Sopenharmony_ci if (q_vector->rx.ring) 223662306a36Sopenharmony_ci q_vector->itr_val = adapter->rx_itr_setting; 223762306a36Sopenharmony_ci else 223862306a36Sopenharmony_ci q_vector->itr_val = adapter->tx_itr_setting; 223962306a36Sopenharmony_ci if (q_vector->itr_val && q_vector->itr_val <= 3) 224062306a36Sopenharmony_ci q_vector->itr_val = IGB_START_ITR; 224162306a36Sopenharmony_ci q_vector->set_itr = 1; 224262306a36Sopenharmony_ci } 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci return 0; 224562306a36Sopenharmony_ci} 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_cistatic int igb_get_coalesce(struct net_device *netdev, 224862306a36Sopenharmony_ci struct ethtool_coalesce *ec, 224962306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 225062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 225162306a36Sopenharmony_ci{ 225262306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci if (adapter->rx_itr_setting <= 3) 225562306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->rx_itr_setting; 225662306a36Sopenharmony_ci else 225762306a36Sopenharmony_ci ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS)) { 226062306a36Sopenharmony_ci if (adapter->tx_itr_setting <= 3) 226162306a36Sopenharmony_ci ec->tx_coalesce_usecs = adapter->tx_itr_setting; 226262306a36Sopenharmony_ci else 226362306a36Sopenharmony_ci ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2; 226462306a36Sopenharmony_ci } 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci return 0; 226762306a36Sopenharmony_ci} 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_cistatic int igb_nway_reset(struct net_device *netdev) 227062306a36Sopenharmony_ci{ 227162306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 227262306a36Sopenharmony_ci if (netif_running(netdev)) 227362306a36Sopenharmony_ci igb_reinit_locked(adapter); 227462306a36Sopenharmony_ci return 0; 227562306a36Sopenharmony_ci} 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_cistatic int igb_get_sset_count(struct net_device *netdev, int sset) 227862306a36Sopenharmony_ci{ 227962306a36Sopenharmony_ci switch (sset) { 228062306a36Sopenharmony_ci case ETH_SS_STATS: 228162306a36Sopenharmony_ci return IGB_STATS_LEN; 228262306a36Sopenharmony_ci case ETH_SS_TEST: 228362306a36Sopenharmony_ci return IGB_TEST_LEN; 228462306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 228562306a36Sopenharmony_ci return IGB_PRIV_FLAGS_STR_LEN; 228662306a36Sopenharmony_ci default: 228762306a36Sopenharmony_ci return -ENOTSUPP; 228862306a36Sopenharmony_ci } 228962306a36Sopenharmony_ci} 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_cistatic void igb_get_ethtool_stats(struct net_device *netdev, 229262306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 229362306a36Sopenharmony_ci{ 229462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 229562306a36Sopenharmony_ci struct rtnl_link_stats64 *net_stats = &adapter->stats64; 229662306a36Sopenharmony_ci unsigned int start; 229762306a36Sopenharmony_ci struct igb_ring *ring; 229862306a36Sopenharmony_ci int i, j; 229962306a36Sopenharmony_ci char *p; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci spin_lock(&adapter->stats64_lock); 230262306a36Sopenharmony_ci igb_update_stats(adapter); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { 230562306a36Sopenharmony_ci p = (char *)adapter + igb_gstrings_stats[i].stat_offset; 230662306a36Sopenharmony_ci data[i] = (igb_gstrings_stats[i].sizeof_stat == 230762306a36Sopenharmony_ci sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci for (j = 0; j < IGB_NETDEV_STATS_LEN; j++, i++) { 231062306a36Sopenharmony_ci p = (char *)net_stats + igb_gstrings_net_stats[j].stat_offset; 231162306a36Sopenharmony_ci data[i] = (igb_gstrings_net_stats[j].sizeof_stat == 231262306a36Sopenharmony_ci sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci for (j = 0; j < adapter->num_tx_queues; j++) { 231562306a36Sopenharmony_ci u64 restart2; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci ring = adapter->tx_ring[j]; 231862306a36Sopenharmony_ci do { 231962306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->tx_syncp); 232062306a36Sopenharmony_ci data[i] = ring->tx_stats.packets; 232162306a36Sopenharmony_ci data[i+1] = ring->tx_stats.bytes; 232262306a36Sopenharmony_ci data[i+2] = ring->tx_stats.restart_queue; 232362306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); 232462306a36Sopenharmony_ci do { 232562306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->tx_syncp2); 232662306a36Sopenharmony_ci restart2 = ring->tx_stats.restart_queue2; 232762306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->tx_syncp2, start)); 232862306a36Sopenharmony_ci data[i+2] += restart2; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci i += IGB_TX_QUEUE_STATS_LEN; 233162306a36Sopenharmony_ci } 233262306a36Sopenharmony_ci for (j = 0; j < adapter->num_rx_queues; j++) { 233362306a36Sopenharmony_ci ring = adapter->rx_ring[j]; 233462306a36Sopenharmony_ci do { 233562306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->rx_syncp); 233662306a36Sopenharmony_ci data[i] = ring->rx_stats.packets; 233762306a36Sopenharmony_ci data[i+1] = ring->rx_stats.bytes; 233862306a36Sopenharmony_ci data[i+2] = ring->rx_stats.drops; 233962306a36Sopenharmony_ci data[i+3] = ring->rx_stats.csum_err; 234062306a36Sopenharmony_ci data[i+4] = ring->rx_stats.alloc_failed; 234162306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); 234262306a36Sopenharmony_ci i += IGB_RX_QUEUE_STATS_LEN; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci spin_unlock(&adapter->stats64_lock); 234562306a36Sopenharmony_ci} 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_cistatic void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 234862306a36Sopenharmony_ci{ 234962306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 235062306a36Sopenharmony_ci u8 *p = data; 235162306a36Sopenharmony_ci int i; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci switch (stringset) { 235462306a36Sopenharmony_ci case ETH_SS_TEST: 235562306a36Sopenharmony_ci memcpy(data, igb_gstrings_test, sizeof(igb_gstrings_test)); 235662306a36Sopenharmony_ci break; 235762306a36Sopenharmony_ci case ETH_SS_STATS: 235862306a36Sopenharmony_ci for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) 235962306a36Sopenharmony_ci ethtool_sprintf(&p, 236062306a36Sopenharmony_ci igb_gstrings_stats[i].stat_string); 236162306a36Sopenharmony_ci for (i = 0; i < IGB_NETDEV_STATS_LEN; i++) 236262306a36Sopenharmony_ci ethtool_sprintf(&p, 236362306a36Sopenharmony_ci igb_gstrings_net_stats[i].stat_string); 236462306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 236562306a36Sopenharmony_ci ethtool_sprintf(&p, "tx_queue_%u_packets", i); 236662306a36Sopenharmony_ci ethtool_sprintf(&p, "tx_queue_%u_bytes", i); 236762306a36Sopenharmony_ci ethtool_sprintf(&p, "tx_queue_%u_restart", i); 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 237062306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_queue_%u_packets", i); 237162306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_queue_%u_bytes", i); 237262306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_queue_%u_drops", i); 237362306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_queue_%u_csum_err", i); 237462306a36Sopenharmony_ci ethtool_sprintf(&p, "rx_queue_%u_alloc_failed", i); 237562306a36Sopenharmony_ci } 237662306a36Sopenharmony_ci /* BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */ 237762306a36Sopenharmony_ci break; 237862306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 237962306a36Sopenharmony_ci memcpy(data, igb_priv_flags_strings, 238062306a36Sopenharmony_ci IGB_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); 238162306a36Sopenharmony_ci break; 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci} 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_cistatic int igb_get_ts_info(struct net_device *dev, 238662306a36Sopenharmony_ci struct ethtool_ts_info *info) 238762306a36Sopenharmony_ci{ 238862306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(dev); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci if (adapter->ptp_clock) 239162306a36Sopenharmony_ci info->phc_index = ptp_clock_index(adapter->ptp_clock); 239262306a36Sopenharmony_ci else 239362306a36Sopenharmony_ci info->phc_index = -1; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 239662306a36Sopenharmony_ci case e1000_82575: 239762306a36Sopenharmony_ci info->so_timestamping = 239862306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_SOFTWARE | 239962306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 240062306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE; 240162306a36Sopenharmony_ci return 0; 240262306a36Sopenharmony_ci case e1000_82576: 240362306a36Sopenharmony_ci case e1000_82580: 240462306a36Sopenharmony_ci case e1000_i350: 240562306a36Sopenharmony_ci case e1000_i354: 240662306a36Sopenharmony_ci case e1000_i210: 240762306a36Sopenharmony_ci case e1000_i211: 240862306a36Sopenharmony_ci info->so_timestamping = 240962306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_SOFTWARE | 241062306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 241162306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 241262306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 241362306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 241462306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci info->tx_types = 241762306a36Sopenharmony_ci BIT(HWTSTAMP_TX_OFF) | 241862306a36Sopenharmony_ci BIT(HWTSTAMP_TX_ON); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci info->rx_filters = BIT(HWTSTAMP_FILTER_NONE); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci /* 82576 does not support timestamping all packets. */ 242362306a36Sopenharmony_ci if (adapter->hw.mac.type >= e1000_82580) 242462306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL); 242562306a36Sopenharmony_ci else 242662306a36Sopenharmony_ci info->rx_filters |= 242762306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | 242862306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | 242962306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci return 0; 243262306a36Sopenharmony_ci default: 243362306a36Sopenharmony_ci return -EOPNOTSUPP; 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci} 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci#define ETHER_TYPE_FULL_MASK ((__force __be16)~0) 243862306a36Sopenharmony_cistatic int igb_get_ethtool_nfc_entry(struct igb_adapter *adapter, 243962306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 244062306a36Sopenharmony_ci{ 244162306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = &cmd->fs; 244262306a36Sopenharmony_ci struct igb_nfc_filter *rule = NULL; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci /* report total rule count */ 244562306a36Sopenharmony_ci cmd->data = IGB_MAX_RXNFC_FILTERS; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { 244862306a36Sopenharmony_ci if (fsp->location <= rule->sw_idx) 244962306a36Sopenharmony_ci break; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci if (!rule || fsp->location != rule->sw_idx) 245362306a36Sopenharmony_ci return -EINVAL; 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci if (rule->filter.match_flags) { 245662306a36Sopenharmony_ci fsp->flow_type = ETHER_FLOW; 245762306a36Sopenharmony_ci fsp->ring_cookie = rule->action; 245862306a36Sopenharmony_ci if (rule->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE) { 245962306a36Sopenharmony_ci fsp->h_u.ether_spec.h_proto = rule->filter.etype; 246062306a36Sopenharmony_ci fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK; 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci if (rule->filter.match_flags & IGB_FILTER_FLAG_VLAN_TCI) { 246362306a36Sopenharmony_ci fsp->flow_type |= FLOW_EXT; 246462306a36Sopenharmony_ci fsp->h_ext.vlan_tci = rule->filter.vlan_tci; 246562306a36Sopenharmony_ci fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK); 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci if (rule->filter.match_flags & IGB_FILTER_FLAG_DST_MAC_ADDR) { 246862306a36Sopenharmony_ci ether_addr_copy(fsp->h_u.ether_spec.h_dest, 246962306a36Sopenharmony_ci rule->filter.dst_addr); 247062306a36Sopenharmony_ci /* As we only support matching by the full 247162306a36Sopenharmony_ci * mask, return the mask to userspace 247262306a36Sopenharmony_ci */ 247362306a36Sopenharmony_ci eth_broadcast_addr(fsp->m_u.ether_spec.h_dest); 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci if (rule->filter.match_flags & IGB_FILTER_FLAG_SRC_MAC_ADDR) { 247662306a36Sopenharmony_ci ether_addr_copy(fsp->h_u.ether_spec.h_source, 247762306a36Sopenharmony_ci rule->filter.src_addr); 247862306a36Sopenharmony_ci /* As we only support matching by the full 247962306a36Sopenharmony_ci * mask, return the mask to userspace 248062306a36Sopenharmony_ci */ 248162306a36Sopenharmony_ci eth_broadcast_addr(fsp->m_u.ether_spec.h_source); 248262306a36Sopenharmony_ci } 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci return 0; 248562306a36Sopenharmony_ci } 248662306a36Sopenharmony_ci return -EINVAL; 248762306a36Sopenharmony_ci} 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_cistatic int igb_get_ethtool_nfc_all(struct igb_adapter *adapter, 249062306a36Sopenharmony_ci struct ethtool_rxnfc *cmd, 249162306a36Sopenharmony_ci u32 *rule_locs) 249262306a36Sopenharmony_ci{ 249362306a36Sopenharmony_ci struct igb_nfc_filter *rule; 249462306a36Sopenharmony_ci int cnt = 0; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci /* report total rule count */ 249762306a36Sopenharmony_ci cmd->data = IGB_MAX_RXNFC_FILTERS; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { 250062306a36Sopenharmony_ci if (cnt == cmd->rule_cnt) 250162306a36Sopenharmony_ci return -EMSGSIZE; 250262306a36Sopenharmony_ci rule_locs[cnt] = rule->sw_idx; 250362306a36Sopenharmony_ci cnt++; 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci cmd->rule_cnt = cnt; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci return 0; 250962306a36Sopenharmony_ci} 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_cistatic int igb_get_rss_hash_opts(struct igb_adapter *adapter, 251262306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 251362306a36Sopenharmony_ci{ 251462306a36Sopenharmony_ci cmd->data = 0; 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci /* Report default options for RSS on igb */ 251762306a36Sopenharmony_ci switch (cmd->flow_type) { 251862306a36Sopenharmony_ci case TCP_V4_FLOW: 251962306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 252062306a36Sopenharmony_ci fallthrough; 252162306a36Sopenharmony_ci case UDP_V4_FLOW: 252262306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV4_UDP) 252362306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 252462306a36Sopenharmony_ci fallthrough; 252562306a36Sopenharmony_ci case SCTP_V4_FLOW: 252662306a36Sopenharmony_ci case AH_ESP_V4_FLOW: 252762306a36Sopenharmony_ci case AH_V4_FLOW: 252862306a36Sopenharmony_ci case ESP_V4_FLOW: 252962306a36Sopenharmony_ci case IPV4_FLOW: 253062306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST; 253162306a36Sopenharmony_ci break; 253262306a36Sopenharmony_ci case TCP_V6_FLOW: 253362306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 253462306a36Sopenharmony_ci fallthrough; 253562306a36Sopenharmony_ci case UDP_V6_FLOW: 253662306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV6_UDP) 253762306a36Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 253862306a36Sopenharmony_ci fallthrough; 253962306a36Sopenharmony_ci case SCTP_V6_FLOW: 254062306a36Sopenharmony_ci case AH_ESP_V6_FLOW: 254162306a36Sopenharmony_ci case AH_V6_FLOW: 254262306a36Sopenharmony_ci case ESP_V6_FLOW: 254362306a36Sopenharmony_ci case IPV6_FLOW: 254462306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST; 254562306a36Sopenharmony_ci break; 254662306a36Sopenharmony_ci default: 254762306a36Sopenharmony_ci return -EINVAL; 254862306a36Sopenharmony_ci } 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci return 0; 255162306a36Sopenharmony_ci} 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_cistatic int igb_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 255462306a36Sopenharmony_ci u32 *rule_locs) 255562306a36Sopenharmony_ci{ 255662306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(dev); 255762306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci switch (cmd->cmd) { 256062306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 256162306a36Sopenharmony_ci cmd->data = adapter->num_rx_queues; 256262306a36Sopenharmony_ci ret = 0; 256362306a36Sopenharmony_ci break; 256462306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 256562306a36Sopenharmony_ci cmd->rule_cnt = adapter->nfc_filter_count; 256662306a36Sopenharmony_ci ret = 0; 256762306a36Sopenharmony_ci break; 256862306a36Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 256962306a36Sopenharmony_ci ret = igb_get_ethtool_nfc_entry(adapter, cmd); 257062306a36Sopenharmony_ci break; 257162306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 257262306a36Sopenharmony_ci ret = igb_get_ethtool_nfc_all(adapter, cmd, rule_locs); 257362306a36Sopenharmony_ci break; 257462306a36Sopenharmony_ci case ETHTOOL_GRXFH: 257562306a36Sopenharmony_ci ret = igb_get_rss_hash_opts(adapter, cmd); 257662306a36Sopenharmony_ci break; 257762306a36Sopenharmony_ci default: 257862306a36Sopenharmony_ci break; 257962306a36Sopenharmony_ci } 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci return ret; 258262306a36Sopenharmony_ci} 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci#define UDP_RSS_FLAGS (IGB_FLAG_RSS_FIELD_IPV4_UDP | \ 258562306a36Sopenharmony_ci IGB_FLAG_RSS_FIELD_IPV6_UDP) 258662306a36Sopenharmony_cistatic int igb_set_rss_hash_opt(struct igb_adapter *adapter, 258762306a36Sopenharmony_ci struct ethtool_rxnfc *nfc) 258862306a36Sopenharmony_ci{ 258962306a36Sopenharmony_ci u32 flags = adapter->flags; 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci /* RSS does not support anything other than hashing 259262306a36Sopenharmony_ci * to queues on src and dst IPs and ports 259362306a36Sopenharmony_ci */ 259462306a36Sopenharmony_ci if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | 259562306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) 259662306a36Sopenharmony_ci return -EINVAL; 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci switch (nfc->flow_type) { 259962306a36Sopenharmony_ci case TCP_V4_FLOW: 260062306a36Sopenharmony_ci case TCP_V6_FLOW: 260162306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 260262306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST) || 260362306a36Sopenharmony_ci !(nfc->data & RXH_L4_B_0_1) || 260462306a36Sopenharmony_ci !(nfc->data & RXH_L4_B_2_3)) 260562306a36Sopenharmony_ci return -EINVAL; 260662306a36Sopenharmony_ci break; 260762306a36Sopenharmony_ci case UDP_V4_FLOW: 260862306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 260962306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST)) 261062306a36Sopenharmony_ci return -EINVAL; 261162306a36Sopenharmony_ci switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 261262306a36Sopenharmony_ci case 0: 261362306a36Sopenharmony_ci flags &= ~IGB_FLAG_RSS_FIELD_IPV4_UDP; 261462306a36Sopenharmony_ci break; 261562306a36Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 261662306a36Sopenharmony_ci flags |= IGB_FLAG_RSS_FIELD_IPV4_UDP; 261762306a36Sopenharmony_ci break; 261862306a36Sopenharmony_ci default: 261962306a36Sopenharmony_ci return -EINVAL; 262062306a36Sopenharmony_ci } 262162306a36Sopenharmony_ci break; 262262306a36Sopenharmony_ci case UDP_V6_FLOW: 262362306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 262462306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST)) 262562306a36Sopenharmony_ci return -EINVAL; 262662306a36Sopenharmony_ci switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 262762306a36Sopenharmony_ci case 0: 262862306a36Sopenharmony_ci flags &= ~IGB_FLAG_RSS_FIELD_IPV6_UDP; 262962306a36Sopenharmony_ci break; 263062306a36Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 263162306a36Sopenharmony_ci flags |= IGB_FLAG_RSS_FIELD_IPV6_UDP; 263262306a36Sopenharmony_ci break; 263362306a36Sopenharmony_ci default: 263462306a36Sopenharmony_ci return -EINVAL; 263562306a36Sopenharmony_ci } 263662306a36Sopenharmony_ci break; 263762306a36Sopenharmony_ci case AH_ESP_V4_FLOW: 263862306a36Sopenharmony_ci case AH_V4_FLOW: 263962306a36Sopenharmony_ci case ESP_V4_FLOW: 264062306a36Sopenharmony_ci case SCTP_V4_FLOW: 264162306a36Sopenharmony_ci case AH_ESP_V6_FLOW: 264262306a36Sopenharmony_ci case AH_V6_FLOW: 264362306a36Sopenharmony_ci case ESP_V6_FLOW: 264462306a36Sopenharmony_ci case SCTP_V6_FLOW: 264562306a36Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 264662306a36Sopenharmony_ci !(nfc->data & RXH_IP_DST) || 264762306a36Sopenharmony_ci (nfc->data & RXH_L4_B_0_1) || 264862306a36Sopenharmony_ci (nfc->data & RXH_L4_B_2_3)) 264962306a36Sopenharmony_ci return -EINVAL; 265062306a36Sopenharmony_ci break; 265162306a36Sopenharmony_ci default: 265262306a36Sopenharmony_ci return -EINVAL; 265362306a36Sopenharmony_ci } 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci /* if we changed something we need to update flags */ 265662306a36Sopenharmony_ci if (flags != adapter->flags) { 265762306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 265862306a36Sopenharmony_ci u32 mrqc = rd32(E1000_MRQC); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci if ((flags & UDP_RSS_FLAGS) && 266162306a36Sopenharmony_ci !(adapter->flags & UDP_RSS_FLAGS)) 266262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 266362306a36Sopenharmony_ci "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci adapter->flags = flags; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci /* Perform hash on these packet types */ 266862306a36Sopenharmony_ci mrqc |= E1000_MRQC_RSS_FIELD_IPV4 | 266962306a36Sopenharmony_ci E1000_MRQC_RSS_FIELD_IPV4_TCP | 267062306a36Sopenharmony_ci E1000_MRQC_RSS_FIELD_IPV6 | 267162306a36Sopenharmony_ci E1000_MRQC_RSS_FIELD_IPV6_TCP; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci mrqc &= ~(E1000_MRQC_RSS_FIELD_IPV4_UDP | 267462306a36Sopenharmony_ci E1000_MRQC_RSS_FIELD_IPV6_UDP); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci if (flags & IGB_FLAG_RSS_FIELD_IPV4_UDP) 267762306a36Sopenharmony_ci mrqc |= E1000_MRQC_RSS_FIELD_IPV4_UDP; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci if (flags & IGB_FLAG_RSS_FIELD_IPV6_UDP) 268062306a36Sopenharmony_ci mrqc |= E1000_MRQC_RSS_FIELD_IPV6_UDP; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci wr32(E1000_MRQC, mrqc); 268362306a36Sopenharmony_ci } 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci return 0; 268662306a36Sopenharmony_ci} 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_cistatic int igb_rxnfc_write_etype_filter(struct igb_adapter *adapter, 268962306a36Sopenharmony_ci struct igb_nfc_filter *input) 269062306a36Sopenharmony_ci{ 269162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 269262306a36Sopenharmony_ci u8 i; 269362306a36Sopenharmony_ci u32 etqf; 269462306a36Sopenharmony_ci u16 etype; 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci /* find an empty etype filter register */ 269762306a36Sopenharmony_ci for (i = 0; i < MAX_ETYPE_FILTER; ++i) { 269862306a36Sopenharmony_ci if (!adapter->etype_bitmap[i]) 269962306a36Sopenharmony_ci break; 270062306a36Sopenharmony_ci } 270162306a36Sopenharmony_ci if (i == MAX_ETYPE_FILTER) { 270262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "ethtool -N: etype filters are all used.\n"); 270362306a36Sopenharmony_ci return -EINVAL; 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci adapter->etype_bitmap[i] = true; 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci etqf = rd32(E1000_ETQF(i)); 270962306a36Sopenharmony_ci etype = ntohs(input->filter.etype & ETHER_TYPE_FULL_MASK); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci etqf |= E1000_ETQF_FILTER_ENABLE; 271262306a36Sopenharmony_ci etqf &= ~E1000_ETQF_ETYPE_MASK; 271362306a36Sopenharmony_ci etqf |= (etype & E1000_ETQF_ETYPE_MASK); 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci etqf &= ~E1000_ETQF_QUEUE_MASK; 271662306a36Sopenharmony_ci etqf |= ((input->action << E1000_ETQF_QUEUE_SHIFT) 271762306a36Sopenharmony_ci & E1000_ETQF_QUEUE_MASK); 271862306a36Sopenharmony_ci etqf |= E1000_ETQF_QUEUE_ENABLE; 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci wr32(E1000_ETQF(i), etqf); 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci input->etype_reg_index = i; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci return 0; 272562306a36Sopenharmony_ci} 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_cistatic int igb_rxnfc_write_vlan_prio_filter(struct igb_adapter *adapter, 272862306a36Sopenharmony_ci struct igb_nfc_filter *input) 272962306a36Sopenharmony_ci{ 273062306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 273162306a36Sopenharmony_ci u8 vlan_priority; 273262306a36Sopenharmony_ci u16 queue_index; 273362306a36Sopenharmony_ci u32 vlapqf; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci vlapqf = rd32(E1000_VLAPQF); 273662306a36Sopenharmony_ci vlan_priority = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK) 273762306a36Sopenharmony_ci >> VLAN_PRIO_SHIFT; 273862306a36Sopenharmony_ci queue_index = (vlapqf >> (vlan_priority * 4)) & E1000_VLAPQF_QUEUE_MASK; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci /* check whether this vlan prio is already set */ 274162306a36Sopenharmony_ci if ((vlapqf & E1000_VLAPQF_P_VALID(vlan_priority)) && 274262306a36Sopenharmony_ci (queue_index != input->action)) { 274362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "ethtool rxnfc set vlan prio filter failed.\n"); 274462306a36Sopenharmony_ci return -EEXIST; 274562306a36Sopenharmony_ci } 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci vlapqf |= E1000_VLAPQF_P_VALID(vlan_priority); 274862306a36Sopenharmony_ci vlapqf |= E1000_VLAPQF_QUEUE_SEL(vlan_priority, input->action); 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci wr32(E1000_VLAPQF, vlapqf); 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci return 0; 275362306a36Sopenharmony_ci} 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ciint igb_add_filter(struct igb_adapter *adapter, struct igb_nfc_filter *input) 275662306a36Sopenharmony_ci{ 275762306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 275862306a36Sopenharmony_ci int err = -EINVAL; 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci if (hw->mac.type == e1000_i210 && 276162306a36Sopenharmony_ci !(input->filter.match_flags & ~IGB_FILTER_FLAG_SRC_MAC_ADDR)) { 276262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 276362306a36Sopenharmony_ci "i210 doesn't support flow classification rules specifying only source addresses.\n"); 276462306a36Sopenharmony_ci return -EOPNOTSUPP; 276562306a36Sopenharmony_ci } 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE) { 276862306a36Sopenharmony_ci err = igb_rxnfc_write_etype_filter(adapter, input); 276962306a36Sopenharmony_ci if (err) 277062306a36Sopenharmony_ci return err; 277162306a36Sopenharmony_ci } 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_DST_MAC_ADDR) { 277462306a36Sopenharmony_ci err = igb_add_mac_steering_filter(adapter, 277562306a36Sopenharmony_ci input->filter.dst_addr, 277662306a36Sopenharmony_ci input->action, 0); 277762306a36Sopenharmony_ci err = min_t(int, err, 0); 277862306a36Sopenharmony_ci if (err) 277962306a36Sopenharmony_ci return err; 278062306a36Sopenharmony_ci } 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_SRC_MAC_ADDR) { 278362306a36Sopenharmony_ci err = igb_add_mac_steering_filter(adapter, 278462306a36Sopenharmony_ci input->filter.src_addr, 278562306a36Sopenharmony_ci input->action, 278662306a36Sopenharmony_ci IGB_MAC_STATE_SRC_ADDR); 278762306a36Sopenharmony_ci err = min_t(int, err, 0); 278862306a36Sopenharmony_ci if (err) 278962306a36Sopenharmony_ci return err; 279062306a36Sopenharmony_ci } 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_VLAN_TCI) 279362306a36Sopenharmony_ci err = igb_rxnfc_write_vlan_prio_filter(adapter, input); 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci return err; 279662306a36Sopenharmony_ci} 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_cistatic void igb_clear_etype_filter_regs(struct igb_adapter *adapter, 279962306a36Sopenharmony_ci u16 reg_index) 280062306a36Sopenharmony_ci{ 280162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 280262306a36Sopenharmony_ci u32 etqf = rd32(E1000_ETQF(reg_index)); 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci etqf &= ~E1000_ETQF_QUEUE_ENABLE; 280562306a36Sopenharmony_ci etqf &= ~E1000_ETQF_QUEUE_MASK; 280662306a36Sopenharmony_ci etqf &= ~E1000_ETQF_FILTER_ENABLE; 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci wr32(E1000_ETQF(reg_index), etqf); 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci adapter->etype_bitmap[reg_index] = false; 281162306a36Sopenharmony_ci} 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_cistatic void igb_clear_vlan_prio_filter(struct igb_adapter *adapter, 281462306a36Sopenharmony_ci u16 vlan_tci) 281562306a36Sopenharmony_ci{ 281662306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 281762306a36Sopenharmony_ci u8 vlan_priority; 281862306a36Sopenharmony_ci u32 vlapqf; 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci vlan_priority = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci vlapqf = rd32(E1000_VLAPQF); 282362306a36Sopenharmony_ci vlapqf &= ~E1000_VLAPQF_P_VALID(vlan_priority); 282462306a36Sopenharmony_ci vlapqf &= ~E1000_VLAPQF_QUEUE_SEL(vlan_priority, 282562306a36Sopenharmony_ci E1000_VLAPQF_QUEUE_MASK); 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci wr32(E1000_VLAPQF, vlapqf); 282862306a36Sopenharmony_ci} 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ciint igb_erase_filter(struct igb_adapter *adapter, struct igb_nfc_filter *input) 283162306a36Sopenharmony_ci{ 283262306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE) 283362306a36Sopenharmony_ci igb_clear_etype_filter_regs(adapter, 283462306a36Sopenharmony_ci input->etype_reg_index); 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_VLAN_TCI) 283762306a36Sopenharmony_ci igb_clear_vlan_prio_filter(adapter, 283862306a36Sopenharmony_ci ntohs(input->filter.vlan_tci)); 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_SRC_MAC_ADDR) 284162306a36Sopenharmony_ci igb_del_mac_steering_filter(adapter, input->filter.src_addr, 284262306a36Sopenharmony_ci input->action, 284362306a36Sopenharmony_ci IGB_MAC_STATE_SRC_ADDR); 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci if (input->filter.match_flags & IGB_FILTER_FLAG_DST_MAC_ADDR) 284662306a36Sopenharmony_ci igb_del_mac_steering_filter(adapter, input->filter.dst_addr, 284762306a36Sopenharmony_ci input->action, 0); 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci return 0; 285062306a36Sopenharmony_ci} 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_cistatic int igb_update_ethtool_nfc_entry(struct igb_adapter *adapter, 285362306a36Sopenharmony_ci struct igb_nfc_filter *input, 285462306a36Sopenharmony_ci u16 sw_idx) 285562306a36Sopenharmony_ci{ 285662306a36Sopenharmony_ci struct igb_nfc_filter *rule, *parent; 285762306a36Sopenharmony_ci int err = -EINVAL; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci parent = NULL; 286062306a36Sopenharmony_ci rule = NULL; 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { 286362306a36Sopenharmony_ci /* hash found, or no matching entry */ 286462306a36Sopenharmony_ci if (rule->sw_idx >= sw_idx) 286562306a36Sopenharmony_ci break; 286662306a36Sopenharmony_ci parent = rule; 286762306a36Sopenharmony_ci } 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci /* if there is an old rule occupying our place remove it */ 287062306a36Sopenharmony_ci if (rule && (rule->sw_idx == sw_idx)) { 287162306a36Sopenharmony_ci if (!input) 287262306a36Sopenharmony_ci err = igb_erase_filter(adapter, rule); 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci hlist_del(&rule->nfc_node); 287562306a36Sopenharmony_ci kfree(rule); 287662306a36Sopenharmony_ci adapter->nfc_filter_count--; 287762306a36Sopenharmony_ci } 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci /* If no input this was a delete, err should be 0 if a rule was 288062306a36Sopenharmony_ci * successfully found and removed from the list else -EINVAL 288162306a36Sopenharmony_ci */ 288262306a36Sopenharmony_ci if (!input) 288362306a36Sopenharmony_ci return err; 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_ci /* initialize node */ 288662306a36Sopenharmony_ci INIT_HLIST_NODE(&input->nfc_node); 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci /* add filter to the list */ 288962306a36Sopenharmony_ci if (parent) 289062306a36Sopenharmony_ci hlist_add_behind(&input->nfc_node, &parent->nfc_node); 289162306a36Sopenharmony_ci else 289262306a36Sopenharmony_ci hlist_add_head(&input->nfc_node, &adapter->nfc_filter_list); 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci /* update counts */ 289562306a36Sopenharmony_ci adapter->nfc_filter_count++; 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci return 0; 289862306a36Sopenharmony_ci} 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_cistatic int igb_add_ethtool_nfc_entry(struct igb_adapter *adapter, 290162306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 290262306a36Sopenharmony_ci{ 290362306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 290462306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 290562306a36Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 290662306a36Sopenharmony_ci struct igb_nfc_filter *input, *rule; 290762306a36Sopenharmony_ci int err = 0; 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci if (!(netdev->hw_features & NETIF_F_NTUPLE)) 291062306a36Sopenharmony_ci return -EOPNOTSUPP; 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci /* Don't allow programming if the action is a queue greater than 291362306a36Sopenharmony_ci * the number of online Rx queues. 291462306a36Sopenharmony_ci */ 291562306a36Sopenharmony_ci if ((fsp->ring_cookie == RX_CLS_FLOW_DISC) || 291662306a36Sopenharmony_ci (fsp->ring_cookie >= adapter->num_rx_queues)) { 291762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "ethtool -N: The specified action is invalid\n"); 291862306a36Sopenharmony_ci return -EINVAL; 291962306a36Sopenharmony_ci } 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci /* Don't allow indexes to exist outside of available space */ 292262306a36Sopenharmony_ci if (fsp->location >= IGB_MAX_RXNFC_FILTERS) { 292362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Location out of range\n"); 292462306a36Sopenharmony_ci return -EINVAL; 292562306a36Sopenharmony_ci } 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) 292862306a36Sopenharmony_ci return -EINVAL; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci input = kzalloc(sizeof(*input), GFP_KERNEL); 293162306a36Sopenharmony_ci if (!input) 293262306a36Sopenharmony_ci return -ENOMEM; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) { 293562306a36Sopenharmony_ci input->filter.etype = fsp->h_u.ether_spec.h_proto; 293662306a36Sopenharmony_ci input->filter.match_flags = IGB_FILTER_FLAG_ETHER_TYPE; 293762306a36Sopenharmony_ci } 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ci /* Only support matching addresses by the full mask */ 294062306a36Sopenharmony_ci if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) { 294162306a36Sopenharmony_ci input->filter.match_flags |= IGB_FILTER_FLAG_SRC_MAC_ADDR; 294262306a36Sopenharmony_ci ether_addr_copy(input->filter.src_addr, 294362306a36Sopenharmony_ci fsp->h_u.ether_spec.h_source); 294462306a36Sopenharmony_ci } 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci /* Only support matching addresses by the full mask */ 294762306a36Sopenharmony_ci if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) { 294862306a36Sopenharmony_ci input->filter.match_flags |= IGB_FILTER_FLAG_DST_MAC_ADDR; 294962306a36Sopenharmony_ci ether_addr_copy(input->filter.dst_addr, 295062306a36Sopenharmony_ci fsp->h_u.ether_spec.h_dest); 295162306a36Sopenharmony_ci } 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { 295462306a36Sopenharmony_ci if (fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) { 295562306a36Sopenharmony_ci err = -EINVAL; 295662306a36Sopenharmony_ci goto err_out; 295762306a36Sopenharmony_ci } 295862306a36Sopenharmony_ci input->filter.vlan_tci = fsp->h_ext.vlan_tci; 295962306a36Sopenharmony_ci input->filter.match_flags |= IGB_FILTER_FLAG_VLAN_TCI; 296062306a36Sopenharmony_ci } 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci input->action = fsp->ring_cookie; 296362306a36Sopenharmony_ci input->sw_idx = fsp->location; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci spin_lock(&adapter->nfc_lock); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { 296862306a36Sopenharmony_ci if (!memcmp(&input->filter, &rule->filter, 296962306a36Sopenharmony_ci sizeof(input->filter))) { 297062306a36Sopenharmony_ci err = -EEXIST; 297162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 297262306a36Sopenharmony_ci "ethtool: this filter is already set\n"); 297362306a36Sopenharmony_ci goto err_out_w_lock; 297462306a36Sopenharmony_ci } 297562306a36Sopenharmony_ci } 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci err = igb_add_filter(adapter, input); 297862306a36Sopenharmony_ci if (err) 297962306a36Sopenharmony_ci goto err_out_w_lock; 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci err = igb_update_ethtool_nfc_entry(adapter, input, input->sw_idx); 298262306a36Sopenharmony_ci if (err) 298362306a36Sopenharmony_ci goto err_out_input_filter; 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci spin_unlock(&adapter->nfc_lock); 298662306a36Sopenharmony_ci return 0; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_cierr_out_input_filter: 298962306a36Sopenharmony_ci igb_erase_filter(adapter, input); 299062306a36Sopenharmony_cierr_out_w_lock: 299162306a36Sopenharmony_ci spin_unlock(&adapter->nfc_lock); 299262306a36Sopenharmony_cierr_out: 299362306a36Sopenharmony_ci kfree(input); 299462306a36Sopenharmony_ci return err; 299562306a36Sopenharmony_ci} 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_cistatic int igb_del_ethtool_nfc_entry(struct igb_adapter *adapter, 299862306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 299962306a36Sopenharmony_ci{ 300062306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 300162306a36Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 300262306a36Sopenharmony_ci int err; 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci spin_lock(&adapter->nfc_lock); 300562306a36Sopenharmony_ci err = igb_update_ethtool_nfc_entry(adapter, NULL, fsp->location); 300662306a36Sopenharmony_ci spin_unlock(&adapter->nfc_lock); 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci return err; 300962306a36Sopenharmony_ci} 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_cistatic int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 301262306a36Sopenharmony_ci{ 301362306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(dev); 301462306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci switch (cmd->cmd) { 301762306a36Sopenharmony_ci case ETHTOOL_SRXFH: 301862306a36Sopenharmony_ci ret = igb_set_rss_hash_opt(adapter, cmd); 301962306a36Sopenharmony_ci break; 302062306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 302162306a36Sopenharmony_ci ret = igb_add_ethtool_nfc_entry(adapter, cmd); 302262306a36Sopenharmony_ci break; 302362306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 302462306a36Sopenharmony_ci ret = igb_del_ethtool_nfc_entry(adapter, cmd); 302562306a36Sopenharmony_ci break; 302662306a36Sopenharmony_ci default: 302762306a36Sopenharmony_ci break; 302862306a36Sopenharmony_ci } 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci return ret; 303162306a36Sopenharmony_ci} 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_cistatic int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) 303462306a36Sopenharmony_ci{ 303562306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 303662306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 303762306a36Sopenharmony_ci u32 ret_val; 303862306a36Sopenharmony_ci u16 phy_data; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci if ((hw->mac.type < e1000_i350) || 304162306a36Sopenharmony_ci (hw->phy.media_type != e1000_media_type_copper)) 304262306a36Sopenharmony_ci return -EOPNOTSUPP; 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci edata->supported = (SUPPORTED_1000baseT_Full | 304562306a36Sopenharmony_ci SUPPORTED_100baseT_Full); 304662306a36Sopenharmony_ci if (!hw->dev_spec._82575.eee_disable) 304762306a36Sopenharmony_ci edata->advertised = 304862306a36Sopenharmony_ci mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci /* The IPCNFG and EEER registers are not supported on I354. */ 305162306a36Sopenharmony_ci if (hw->mac.type == e1000_i354) { 305262306a36Sopenharmony_ci igb_get_eee_status_i354(hw, (bool *)&edata->eee_active); 305362306a36Sopenharmony_ci } else { 305462306a36Sopenharmony_ci u32 eeer; 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci eeer = rd32(E1000_EEER); 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* EEE status on negotiated link */ 305962306a36Sopenharmony_ci if (eeer & E1000_EEER_EEE_NEG) 306062306a36Sopenharmony_ci edata->eee_active = true; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci if (eeer & E1000_EEER_TX_LPI_EN) 306362306a36Sopenharmony_ci edata->tx_lpi_enabled = true; 306462306a36Sopenharmony_ci } 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci /* EEE Link Partner Advertised */ 306762306a36Sopenharmony_ci switch (hw->mac.type) { 306862306a36Sopenharmony_ci case e1000_i350: 306962306a36Sopenharmony_ci ret_val = igb_read_emi_reg(hw, E1000_EEE_LP_ADV_ADDR_I350, 307062306a36Sopenharmony_ci &phy_data); 307162306a36Sopenharmony_ci if (ret_val) 307262306a36Sopenharmony_ci return -ENODATA; 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); 307562306a36Sopenharmony_ci break; 307662306a36Sopenharmony_ci case e1000_i354: 307762306a36Sopenharmony_ci case e1000_i210: 307862306a36Sopenharmony_ci case e1000_i211: 307962306a36Sopenharmony_ci ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210, 308062306a36Sopenharmony_ci E1000_EEE_LP_ADV_DEV_I210, 308162306a36Sopenharmony_ci &phy_data); 308262306a36Sopenharmony_ci if (ret_val) 308362306a36Sopenharmony_ci return -ENODATA; 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci break; 308862306a36Sopenharmony_ci default: 308962306a36Sopenharmony_ci break; 309062306a36Sopenharmony_ci } 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci edata->eee_enabled = !hw->dev_spec._82575.eee_disable; 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci if ((hw->mac.type == e1000_i354) && 309562306a36Sopenharmony_ci (edata->eee_enabled)) 309662306a36Sopenharmony_ci edata->tx_lpi_enabled = true; 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci /* Report correct negotiated EEE status for devices that 309962306a36Sopenharmony_ci * wrongly report EEE at half-duplex 310062306a36Sopenharmony_ci */ 310162306a36Sopenharmony_ci if (adapter->link_duplex == HALF_DUPLEX) { 310262306a36Sopenharmony_ci edata->eee_enabled = false; 310362306a36Sopenharmony_ci edata->eee_active = false; 310462306a36Sopenharmony_ci edata->tx_lpi_enabled = false; 310562306a36Sopenharmony_ci edata->advertised &= ~edata->advertised; 310662306a36Sopenharmony_ci } 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci return 0; 310962306a36Sopenharmony_ci} 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_cistatic int igb_set_eee(struct net_device *netdev, 311262306a36Sopenharmony_ci struct ethtool_eee *edata) 311362306a36Sopenharmony_ci{ 311462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 311562306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 311662306a36Sopenharmony_ci struct ethtool_eee eee_curr; 311762306a36Sopenharmony_ci bool adv1g_eee = true, adv100m_eee = true; 311862306a36Sopenharmony_ci s32 ret_val; 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci if ((hw->mac.type < e1000_i350) || 312162306a36Sopenharmony_ci (hw->phy.media_type != e1000_media_type_copper)) 312262306a36Sopenharmony_ci return -EOPNOTSUPP; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci memset(&eee_curr, 0, sizeof(struct ethtool_eee)); 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_ci ret_val = igb_get_eee(netdev, &eee_curr); 312762306a36Sopenharmony_ci if (ret_val) 312862306a36Sopenharmony_ci return ret_val; 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci if (eee_curr.eee_enabled) { 313162306a36Sopenharmony_ci if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) { 313262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 313362306a36Sopenharmony_ci "Setting EEE tx-lpi is not supported\n"); 313462306a36Sopenharmony_ci return -EINVAL; 313562306a36Sopenharmony_ci } 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci /* Tx LPI timer is not implemented currently */ 313862306a36Sopenharmony_ci if (edata->tx_lpi_timer) { 313962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 314062306a36Sopenharmony_ci "Setting EEE Tx LPI timer is not supported\n"); 314162306a36Sopenharmony_ci return -EINVAL; 314262306a36Sopenharmony_ci } 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci if (!edata->advertised || (edata->advertised & 314562306a36Sopenharmony_ci ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) { 314662306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 314762306a36Sopenharmony_ci "EEE Advertisement supports only 100Tx and/or 100T full duplex\n"); 314862306a36Sopenharmony_ci return -EINVAL; 314962306a36Sopenharmony_ci } 315062306a36Sopenharmony_ci adv100m_eee = !!(edata->advertised & ADVERTISE_100_FULL); 315162306a36Sopenharmony_ci adv1g_eee = !!(edata->advertised & ADVERTISE_1000_FULL); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci } else if (!edata->eee_enabled) { 315462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 315562306a36Sopenharmony_ci "Setting EEE options are not supported with EEE disabled\n"); 315662306a36Sopenharmony_ci return -EINVAL; 315762306a36Sopenharmony_ci } 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); 316062306a36Sopenharmony_ci if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) { 316162306a36Sopenharmony_ci hw->dev_spec._82575.eee_disable = !edata->eee_enabled; 316262306a36Sopenharmony_ci adapter->flags |= IGB_FLAG_EEE; 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_ci /* reset link */ 316562306a36Sopenharmony_ci if (netif_running(netdev)) 316662306a36Sopenharmony_ci igb_reinit_locked(adapter); 316762306a36Sopenharmony_ci else 316862306a36Sopenharmony_ci igb_reset(adapter); 316962306a36Sopenharmony_ci } 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci if (hw->mac.type == e1000_i354) 317262306a36Sopenharmony_ci ret_val = igb_set_eee_i354(hw, adv1g_eee, adv100m_eee); 317362306a36Sopenharmony_ci else 317462306a36Sopenharmony_ci ret_val = igb_set_eee_i350(hw, adv1g_eee, adv100m_eee); 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci if (ret_val) { 317762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 317862306a36Sopenharmony_ci "Problem setting EEE advertisement options\n"); 317962306a36Sopenharmony_ci return -EINVAL; 318062306a36Sopenharmony_ci } 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci return 0; 318362306a36Sopenharmony_ci} 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_cistatic int igb_get_module_info(struct net_device *netdev, 318662306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 318762306a36Sopenharmony_ci{ 318862306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 318962306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 319062306a36Sopenharmony_ci u32 status = 0; 319162306a36Sopenharmony_ci u16 sff8472_rev, addr_mode; 319262306a36Sopenharmony_ci bool page_swap = false; 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_ci if ((hw->phy.media_type == e1000_media_type_copper) || 319562306a36Sopenharmony_ci (hw->phy.media_type == e1000_media_type_unknown)) 319662306a36Sopenharmony_ci return -EOPNOTSUPP; 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci /* Check whether we support SFF-8472 or not */ 319962306a36Sopenharmony_ci status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_COMP, &sff8472_rev); 320062306a36Sopenharmony_ci if (status) 320162306a36Sopenharmony_ci return -EIO; 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci /* addressing mode is not supported */ 320462306a36Sopenharmony_ci status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_SWAP, &addr_mode); 320562306a36Sopenharmony_ci if (status) 320662306a36Sopenharmony_ci return -EIO; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci /* addressing mode is not supported */ 320962306a36Sopenharmony_ci if ((addr_mode & 0xFF) & IGB_SFF_ADDRESSING_MODE) { 321062306a36Sopenharmony_ci hw_dbg("Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n"); 321162306a36Sopenharmony_ci page_swap = true; 321262306a36Sopenharmony_ci } 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci if ((sff8472_rev & 0xFF) == IGB_SFF_8472_UNSUP || page_swap) { 321562306a36Sopenharmony_ci /* We have an SFP, but it does not support SFF-8472 */ 321662306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 321762306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 321862306a36Sopenharmony_ci } else { 321962306a36Sopenharmony_ci /* We have an SFP which supports a revision of SFF-8472 */ 322062306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 322162306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 322262306a36Sopenharmony_ci } 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci return 0; 322562306a36Sopenharmony_ci} 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_cistatic int igb_get_module_eeprom(struct net_device *netdev, 322862306a36Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 322962306a36Sopenharmony_ci{ 323062306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 323162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 323262306a36Sopenharmony_ci u32 status = 0; 323362306a36Sopenharmony_ci u16 *dataword; 323462306a36Sopenharmony_ci u16 first_word, last_word; 323562306a36Sopenharmony_ci int i = 0; 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci if (ee->len == 0) 323862306a36Sopenharmony_ci return -EINVAL; 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_ci first_word = ee->offset >> 1; 324162306a36Sopenharmony_ci last_word = (ee->offset + ee->len - 1) >> 1; 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci dataword = kmalloc_array(last_word - first_word + 1, sizeof(u16), 324462306a36Sopenharmony_ci GFP_KERNEL); 324562306a36Sopenharmony_ci if (!dataword) 324662306a36Sopenharmony_ci return -ENOMEM; 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci /* Read EEPROM block, SFF-8079/SFF-8472, word at a time */ 324962306a36Sopenharmony_ci for (i = 0; i < last_word - first_word + 1; i++) { 325062306a36Sopenharmony_ci status = igb_read_phy_reg_i2c(hw, (first_word + i) * 2, 325162306a36Sopenharmony_ci &dataword[i]); 325262306a36Sopenharmony_ci if (status) { 325362306a36Sopenharmony_ci /* Error occurred while reading module */ 325462306a36Sopenharmony_ci kfree(dataword); 325562306a36Sopenharmony_ci return -EIO; 325662306a36Sopenharmony_ci } 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci be16_to_cpus(&dataword[i]); 325962306a36Sopenharmony_ci } 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci memcpy(data, (u8 *)dataword + (ee->offset & 1), ee->len); 326262306a36Sopenharmony_ci kfree(dataword); 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci return 0; 326562306a36Sopenharmony_ci} 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_cistatic int igb_ethtool_begin(struct net_device *netdev) 326862306a36Sopenharmony_ci{ 326962306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 327062306a36Sopenharmony_ci pm_runtime_get_sync(&adapter->pdev->dev); 327162306a36Sopenharmony_ci return 0; 327262306a36Sopenharmony_ci} 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_cistatic void igb_ethtool_complete(struct net_device *netdev) 327562306a36Sopenharmony_ci{ 327662306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 327762306a36Sopenharmony_ci pm_runtime_put(&adapter->pdev->dev); 327862306a36Sopenharmony_ci} 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_cistatic u32 igb_get_rxfh_indir_size(struct net_device *netdev) 328162306a36Sopenharmony_ci{ 328262306a36Sopenharmony_ci return IGB_RETA_SIZE; 328362306a36Sopenharmony_ci} 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_cistatic int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, 328662306a36Sopenharmony_ci u8 *hfunc) 328762306a36Sopenharmony_ci{ 328862306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 328962306a36Sopenharmony_ci int i; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci if (hfunc) 329262306a36Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 329362306a36Sopenharmony_ci if (!indir) 329462306a36Sopenharmony_ci return 0; 329562306a36Sopenharmony_ci for (i = 0; i < IGB_RETA_SIZE; i++) 329662306a36Sopenharmony_ci indir[i] = adapter->rss_indir_tbl[i]; 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci return 0; 329962306a36Sopenharmony_ci} 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_civoid igb_write_rss_indir_tbl(struct igb_adapter *adapter) 330262306a36Sopenharmony_ci{ 330362306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 330462306a36Sopenharmony_ci u32 reg = E1000_RETA(0); 330562306a36Sopenharmony_ci u32 shift = 0; 330662306a36Sopenharmony_ci int i = 0; 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_ci switch (hw->mac.type) { 330962306a36Sopenharmony_ci case e1000_82575: 331062306a36Sopenharmony_ci shift = 6; 331162306a36Sopenharmony_ci break; 331262306a36Sopenharmony_ci case e1000_82576: 331362306a36Sopenharmony_ci /* 82576 supports 2 RSS queues for SR-IOV */ 331462306a36Sopenharmony_ci if (adapter->vfs_allocated_count) 331562306a36Sopenharmony_ci shift = 3; 331662306a36Sopenharmony_ci break; 331762306a36Sopenharmony_ci default: 331862306a36Sopenharmony_ci break; 331962306a36Sopenharmony_ci } 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci while (i < IGB_RETA_SIZE) { 332262306a36Sopenharmony_ci u32 val = 0; 332362306a36Sopenharmony_ci int j; 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci for (j = 3; j >= 0; j--) { 332662306a36Sopenharmony_ci val <<= 8; 332762306a36Sopenharmony_ci val |= adapter->rss_indir_tbl[i + j]; 332862306a36Sopenharmony_ci } 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci wr32(reg, val << shift); 333162306a36Sopenharmony_ci reg += 4; 333262306a36Sopenharmony_ci i += 4; 333362306a36Sopenharmony_ci } 333462306a36Sopenharmony_ci} 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_cistatic int igb_set_rxfh(struct net_device *netdev, const u32 *indir, 333762306a36Sopenharmony_ci const u8 *key, const u8 hfunc) 333862306a36Sopenharmony_ci{ 333962306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 334062306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 334162306a36Sopenharmony_ci int i; 334262306a36Sopenharmony_ci u32 num_queues; 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci /* We do not allow change in unsupported parameters */ 334562306a36Sopenharmony_ci if (key || 334662306a36Sopenharmony_ci (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) 334762306a36Sopenharmony_ci return -EOPNOTSUPP; 334862306a36Sopenharmony_ci if (!indir) 334962306a36Sopenharmony_ci return 0; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci num_queues = adapter->rss_queues; 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci switch (hw->mac.type) { 335462306a36Sopenharmony_ci case e1000_82576: 335562306a36Sopenharmony_ci /* 82576 supports 2 RSS queues for SR-IOV */ 335662306a36Sopenharmony_ci if (adapter->vfs_allocated_count) 335762306a36Sopenharmony_ci num_queues = 2; 335862306a36Sopenharmony_ci break; 335962306a36Sopenharmony_ci default: 336062306a36Sopenharmony_ci break; 336162306a36Sopenharmony_ci } 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci /* Verify user input. */ 336462306a36Sopenharmony_ci for (i = 0; i < IGB_RETA_SIZE; i++) 336562306a36Sopenharmony_ci if (indir[i] >= num_queues) 336662306a36Sopenharmony_ci return -EINVAL; 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci for (i = 0; i < IGB_RETA_SIZE; i++) 337062306a36Sopenharmony_ci adapter->rss_indir_tbl[i] = indir[i]; 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci igb_write_rss_indir_tbl(adapter); 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci return 0; 337562306a36Sopenharmony_ci} 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_cistatic unsigned int igb_max_channels(struct igb_adapter *adapter) 337862306a36Sopenharmony_ci{ 337962306a36Sopenharmony_ci return igb_get_max_rss_queues(adapter); 338062306a36Sopenharmony_ci} 338162306a36Sopenharmony_ci 338262306a36Sopenharmony_cistatic void igb_get_channels(struct net_device *netdev, 338362306a36Sopenharmony_ci struct ethtool_channels *ch) 338462306a36Sopenharmony_ci{ 338562306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_ci /* Report maximum channels */ 338862306a36Sopenharmony_ci ch->max_combined = igb_max_channels(adapter); 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci /* Report info for other vector */ 339162306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_HAS_MSIX) { 339262306a36Sopenharmony_ci ch->max_other = NON_Q_VECTORS; 339362306a36Sopenharmony_ci ch->other_count = NON_Q_VECTORS; 339462306a36Sopenharmony_ci } 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci ch->combined_count = adapter->rss_queues; 339762306a36Sopenharmony_ci} 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_cistatic int igb_set_channels(struct net_device *netdev, 340062306a36Sopenharmony_ci struct ethtool_channels *ch) 340162306a36Sopenharmony_ci{ 340262306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 340362306a36Sopenharmony_ci unsigned int count = ch->combined_count; 340462306a36Sopenharmony_ci unsigned int max_combined = 0; 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci /* Verify they are not requesting separate vectors */ 340762306a36Sopenharmony_ci if (!count || ch->rx_count || ch->tx_count) 340862306a36Sopenharmony_ci return -EINVAL; 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci /* Verify other_count is valid and has not been changed */ 341162306a36Sopenharmony_ci if (ch->other_count != NON_Q_VECTORS) 341262306a36Sopenharmony_ci return -EINVAL; 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci /* Verify the number of channels doesn't exceed hw limits */ 341562306a36Sopenharmony_ci max_combined = igb_max_channels(adapter); 341662306a36Sopenharmony_ci if (count > max_combined) 341762306a36Sopenharmony_ci return -EINVAL; 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci if (count != adapter->rss_queues) { 342062306a36Sopenharmony_ci adapter->rss_queues = count; 342162306a36Sopenharmony_ci igb_set_flag_queue_pairs(adapter, max_combined); 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci /* Hardware has to reinitialize queues and interrupts to 342462306a36Sopenharmony_ci * match the new configuration. 342562306a36Sopenharmony_ci */ 342662306a36Sopenharmony_ci return igb_reinit_queues(adapter); 342762306a36Sopenharmony_ci } 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci return 0; 343062306a36Sopenharmony_ci} 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_cistatic u32 igb_get_priv_flags(struct net_device *netdev) 343362306a36Sopenharmony_ci{ 343462306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 343562306a36Sopenharmony_ci u32 priv_flags = 0; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci if (adapter->flags & IGB_FLAG_RX_LEGACY) 343862306a36Sopenharmony_ci priv_flags |= IGB_PRIV_FLAGS_LEGACY_RX; 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci return priv_flags; 344162306a36Sopenharmony_ci} 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_cistatic int igb_set_priv_flags(struct net_device *netdev, u32 priv_flags) 344462306a36Sopenharmony_ci{ 344562306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 344662306a36Sopenharmony_ci unsigned int flags = adapter->flags; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci flags &= ~IGB_FLAG_RX_LEGACY; 344962306a36Sopenharmony_ci if (priv_flags & IGB_PRIV_FLAGS_LEGACY_RX) 345062306a36Sopenharmony_ci flags |= IGB_FLAG_RX_LEGACY; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci if (flags != adapter->flags) { 345362306a36Sopenharmony_ci adapter->flags = flags; 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci /* reset interface to repopulate queues */ 345662306a36Sopenharmony_ci if (netif_running(netdev)) 345762306a36Sopenharmony_ci igb_reinit_locked(adapter); 345862306a36Sopenharmony_ci } 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci return 0; 346162306a36Sopenharmony_ci} 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_cistatic const struct ethtool_ops igb_ethtool_ops = { 346462306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 346562306a36Sopenharmony_ci .get_drvinfo = igb_get_drvinfo, 346662306a36Sopenharmony_ci .get_regs_len = igb_get_regs_len, 346762306a36Sopenharmony_ci .get_regs = igb_get_regs, 346862306a36Sopenharmony_ci .get_wol = igb_get_wol, 346962306a36Sopenharmony_ci .set_wol = igb_set_wol, 347062306a36Sopenharmony_ci .get_msglevel = igb_get_msglevel, 347162306a36Sopenharmony_ci .set_msglevel = igb_set_msglevel, 347262306a36Sopenharmony_ci .nway_reset = igb_nway_reset, 347362306a36Sopenharmony_ci .get_link = igb_get_link, 347462306a36Sopenharmony_ci .get_eeprom_len = igb_get_eeprom_len, 347562306a36Sopenharmony_ci .get_eeprom = igb_get_eeprom, 347662306a36Sopenharmony_ci .set_eeprom = igb_set_eeprom, 347762306a36Sopenharmony_ci .get_ringparam = igb_get_ringparam, 347862306a36Sopenharmony_ci .set_ringparam = igb_set_ringparam, 347962306a36Sopenharmony_ci .get_pauseparam = igb_get_pauseparam, 348062306a36Sopenharmony_ci .set_pauseparam = igb_set_pauseparam, 348162306a36Sopenharmony_ci .self_test = igb_diag_test, 348262306a36Sopenharmony_ci .get_strings = igb_get_strings, 348362306a36Sopenharmony_ci .set_phys_id = igb_set_phys_id, 348462306a36Sopenharmony_ci .get_sset_count = igb_get_sset_count, 348562306a36Sopenharmony_ci .get_ethtool_stats = igb_get_ethtool_stats, 348662306a36Sopenharmony_ci .get_coalesce = igb_get_coalesce, 348762306a36Sopenharmony_ci .set_coalesce = igb_set_coalesce, 348862306a36Sopenharmony_ci .get_ts_info = igb_get_ts_info, 348962306a36Sopenharmony_ci .get_rxnfc = igb_get_rxnfc, 349062306a36Sopenharmony_ci .set_rxnfc = igb_set_rxnfc, 349162306a36Sopenharmony_ci .get_eee = igb_get_eee, 349262306a36Sopenharmony_ci .set_eee = igb_set_eee, 349362306a36Sopenharmony_ci .get_module_info = igb_get_module_info, 349462306a36Sopenharmony_ci .get_module_eeprom = igb_get_module_eeprom, 349562306a36Sopenharmony_ci .get_rxfh_indir_size = igb_get_rxfh_indir_size, 349662306a36Sopenharmony_ci .get_rxfh = igb_get_rxfh, 349762306a36Sopenharmony_ci .set_rxfh = igb_set_rxfh, 349862306a36Sopenharmony_ci .get_channels = igb_get_channels, 349962306a36Sopenharmony_ci .set_channels = igb_set_channels, 350062306a36Sopenharmony_ci .get_priv_flags = igb_get_priv_flags, 350162306a36Sopenharmony_ci .set_priv_flags = igb_set_priv_flags, 350262306a36Sopenharmony_ci .begin = igb_ethtool_begin, 350362306a36Sopenharmony_ci .complete = igb_ethtool_complete, 350462306a36Sopenharmony_ci .get_link_ksettings = igb_get_link_ksettings, 350562306a36Sopenharmony_ci .set_link_ksettings = igb_set_link_ksettings, 350662306a36Sopenharmony_ci}; 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_civoid igb_set_ethtool_ops(struct net_device *netdev) 350962306a36Sopenharmony_ci{ 351062306a36Sopenharmony_ci netdev->ethtool_ops = &igb_ethtool_ops; 351162306a36Sopenharmony_ci} 3512