182dd0f7eSAlexander Duyck /* Intel Ethernet Switch Host Interface Driver 297c71e3cSJeff Kirsher * Copyright(c) 2013 - 2015 Intel Corporation. 382dd0f7eSAlexander Duyck * 482dd0f7eSAlexander Duyck * This program is free software; you can redistribute it and/or modify it 582dd0f7eSAlexander Duyck * under the terms and conditions of the GNU General Public License, 682dd0f7eSAlexander Duyck * version 2, as published by the Free Software Foundation. 782dd0f7eSAlexander Duyck * 882dd0f7eSAlexander Duyck * This program is distributed in the hope it will be useful, but WITHOUT 982dd0f7eSAlexander Duyck * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1082dd0f7eSAlexander Duyck * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1182dd0f7eSAlexander Duyck * more details. 1282dd0f7eSAlexander Duyck * 1382dd0f7eSAlexander Duyck * The full GNU General Public License is included in this distribution in 1482dd0f7eSAlexander Duyck * the file called "COPYING". 1582dd0f7eSAlexander Duyck * 1682dd0f7eSAlexander Duyck * Contact Information: 1782dd0f7eSAlexander Duyck * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 1882dd0f7eSAlexander Duyck * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 1982dd0f7eSAlexander Duyck */ 2082dd0f7eSAlexander Duyck 21eb51bbafSStephen Rothwell #include <linux/vmalloc.h> 22eb51bbafSStephen Rothwell 2382dd0f7eSAlexander Duyck #include "fm10k.h" 2482dd0f7eSAlexander Duyck 2582dd0f7eSAlexander Duyck struct fm10k_stats { 2682dd0f7eSAlexander Duyck char stat_string[ETH_GSTRING_LEN]; 2782dd0f7eSAlexander Duyck int sizeof_stat; 2882dd0f7eSAlexander Duyck int stat_offset; 2982dd0f7eSAlexander Duyck }; 3082dd0f7eSAlexander Duyck 3182dd0f7eSAlexander Duyck #define FM10K_NETDEV_STAT(_net_stat) { \ 3282dd0f7eSAlexander Duyck .stat_string = #_net_stat, \ 3382dd0f7eSAlexander Duyck .sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \ 3482dd0f7eSAlexander Duyck .stat_offset = offsetof(struct net_device_stats, _net_stat) \ 3582dd0f7eSAlexander Duyck } 3682dd0f7eSAlexander Duyck 3782dd0f7eSAlexander Duyck static const struct fm10k_stats fm10k_gstrings_net_stats[] = { 3882dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(tx_packets), 3982dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(tx_bytes), 4082dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(tx_errors), 4182dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(rx_packets), 4282dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(rx_bytes), 4382dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(rx_errors), 4482dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(rx_dropped), 4582dd0f7eSAlexander Duyck 4682dd0f7eSAlexander Duyck /* detailed Rx errors */ 4782dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(rx_length_errors), 4882dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(rx_crc_errors), 4982dd0f7eSAlexander Duyck FM10K_NETDEV_STAT(rx_fifo_errors), 5082dd0f7eSAlexander Duyck }; 5182dd0f7eSAlexander Duyck 5282dd0f7eSAlexander Duyck #define FM10K_NETDEV_STATS_LEN ARRAY_SIZE(fm10k_gstrings_net_stats) 5382dd0f7eSAlexander Duyck 5482dd0f7eSAlexander Duyck #define FM10K_STAT(_name, _stat) { \ 5582dd0f7eSAlexander Duyck .stat_string = _name, \ 5682dd0f7eSAlexander Duyck .sizeof_stat = FIELD_SIZEOF(struct fm10k_intfc, _stat), \ 5782dd0f7eSAlexander Duyck .stat_offset = offsetof(struct fm10k_intfc, _stat) \ 5882dd0f7eSAlexander Duyck } 5982dd0f7eSAlexander Duyck 60fbdb159fSJeff Kirsher static const struct fm10k_stats fm10k_gstrings_global_stats[] = { 6182dd0f7eSAlexander Duyck FM10K_STAT("tx_restart_queue", restart_queue), 6282dd0f7eSAlexander Duyck FM10K_STAT("tx_busy", tx_busy), 6382dd0f7eSAlexander Duyck FM10K_STAT("tx_csum_errors", tx_csum_errors), 6482dd0f7eSAlexander Duyck FM10K_STAT("rx_alloc_failed", alloc_failed), 6582dd0f7eSAlexander Duyck FM10K_STAT("rx_csum_errors", rx_csum_errors), 6682dd0f7eSAlexander Duyck 6782dd0f7eSAlexander Duyck FM10K_STAT("tx_packets_nic", tx_packets_nic), 6882dd0f7eSAlexander Duyck FM10K_STAT("tx_bytes_nic", tx_bytes_nic), 6982dd0f7eSAlexander Duyck FM10K_STAT("rx_packets_nic", rx_packets_nic), 7082dd0f7eSAlexander Duyck FM10K_STAT("rx_bytes_nic", rx_bytes_nic), 7182dd0f7eSAlexander Duyck FM10K_STAT("rx_drops_nic", rx_drops_nic), 7282dd0f7eSAlexander Duyck FM10K_STAT("rx_overrun_pf", rx_overrun_pf), 7382dd0f7eSAlexander Duyck FM10K_STAT("rx_overrun_vf", rx_overrun_vf), 7482dd0f7eSAlexander Duyck 7582dd0f7eSAlexander Duyck FM10K_STAT("swapi_status", hw.swapi.status), 7682dd0f7eSAlexander Duyck FM10K_STAT("mac_rules_used", hw.swapi.mac.used), 7782dd0f7eSAlexander Duyck FM10K_STAT("mac_rules_avail", hw.swapi.mac.avail), 7882dd0f7eSAlexander Duyck 79e05546ecSJeff Kirsher FM10K_STAT("tx_hang_count", tx_timeout_count), 80e05546ecSJeff Kirsher 81a211e013SAlexander Duyck FM10K_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), 8282dd0f7eSAlexander Duyck }; 8382dd0f7eSAlexander Duyck 8480043f3bSJacob Keller static const struct fm10k_stats fm10k_gstrings_debug_stats[] = { 8580043f3bSJacob Keller FM10K_STAT("hw_sm_mbx_full", hw_sm_mbx_full), 8680043f3bSJacob Keller FM10K_STAT("hw_csum_tx_good", hw_csum_tx_good), 8780043f3bSJacob Keller FM10K_STAT("hw_csum_rx_good", hw_csum_rx_good), 8880043f3bSJacob Keller FM10K_STAT("rx_switch_errors", rx_switch_errors), 8980043f3bSJacob Keller FM10K_STAT("rx_drops", rx_drops), 9080043f3bSJacob Keller FM10K_STAT("rx_pp_errors", rx_pp_errors), 9180043f3bSJacob Keller FM10K_STAT("rx_link_errors", rx_link_errors), 9280043f3bSJacob Keller FM10K_STAT("rx_length_errors", rx_length_errors), 9380043f3bSJacob Keller }; 9480043f3bSJacob Keller 95fbdb159fSJeff Kirsher static const struct fm10k_stats fm10k_gstrings_pf_stats[] = { 96fbdb159fSJeff Kirsher FM10K_STAT("timeout", stats.timeout.count), 97fbdb159fSJeff Kirsher FM10K_STAT("ur", stats.ur.count), 98fbdb159fSJeff Kirsher FM10K_STAT("ca", stats.ca.count), 99fbdb159fSJeff Kirsher FM10K_STAT("um", stats.um.count), 100fbdb159fSJeff Kirsher FM10K_STAT("xec", stats.xec.count), 101fbdb159fSJeff Kirsher FM10K_STAT("vlan_drop", stats.vlan_drop.count), 102fbdb159fSJeff Kirsher FM10K_STAT("loopback_drop", stats.loopback_drop.count), 103fbdb159fSJeff Kirsher FM10K_STAT("nodesc_drop", stats.nodesc_drop.count), 104fbdb159fSJeff Kirsher }; 105fbdb159fSJeff Kirsher 10680043f3bSJacob Keller #define FM10K_MBX_STAT(_name, _stat) { \ 10780043f3bSJacob Keller .stat_string = _name, \ 10880043f3bSJacob Keller .sizeof_stat = FIELD_SIZEOF(struct fm10k_mbx_info, _stat), \ 10980043f3bSJacob Keller .stat_offset = offsetof(struct fm10k_mbx_info, _stat) \ 11080043f3bSJacob Keller } 11180043f3bSJacob Keller 11280043f3bSJacob Keller static const struct fm10k_stats fm10k_gstrings_mbx_stats[] = { 11380043f3bSJacob Keller FM10K_MBX_STAT("mbx_tx_busy", tx_busy), 11480043f3bSJacob Keller FM10K_MBX_STAT("mbx_tx_oversized", tx_dropped), 11580043f3bSJacob Keller FM10K_MBX_STAT("mbx_tx_messages", tx_messages), 11680043f3bSJacob Keller FM10K_MBX_STAT("mbx_tx_dwords", tx_dwords), 11780043f3bSJacob Keller FM10K_MBX_STAT("mbx_rx_messages", rx_messages), 11880043f3bSJacob Keller FM10K_MBX_STAT("mbx_rx_dwords", rx_dwords), 11980043f3bSJacob Keller FM10K_MBX_STAT("mbx_rx_parse_err", rx_parse_err), 12080043f3bSJacob Keller }; 12180043f3bSJacob Keller 122fbdb159fSJeff Kirsher #define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats) 12380043f3bSJacob Keller #define FM10K_DEBUG_STATS_LEN ARRAY_SIZE(fm10k_gstrings_debug_stats) 124fbdb159fSJeff Kirsher #define FM10K_PF_STATS_LEN ARRAY_SIZE(fm10k_gstrings_pf_stats) 12580043f3bSJacob Keller #define FM10K_MBX_STATS_LEN ARRAY_SIZE(fm10k_gstrings_mbx_stats) 12682dd0f7eSAlexander Duyck 127c0e61781SJeff Kirsher #define FM10K_QUEUE_STATS_LEN(_n) \ 128c0e61781SJeff Kirsher ( (_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64))) 12982dd0f7eSAlexander Duyck 130c0e61781SJeff Kirsher #define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \ 13180043f3bSJacob Keller FM10K_NETDEV_STATS_LEN + \ 13280043f3bSJacob Keller FM10K_MBX_STATS_LEN) 13382dd0f7eSAlexander Duyck 1345cb8db4aSAlexander Duyck static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = { 1355cb8db4aSAlexander Duyck "Mailbox test (on/offline)" 1365cb8db4aSAlexander Duyck }; 1375cb8db4aSAlexander Duyck 1385cb8db4aSAlexander Duyck #define FM10K_TEST_LEN (sizeof(fm10k_gstrings_test) / ETH_GSTRING_LEN) 1395cb8db4aSAlexander Duyck 1405cb8db4aSAlexander Duyck enum fm10k_self_test_types { 1415cb8db4aSAlexander Duyck FM10K_TEST_MBX, 1425cb8db4aSAlexander Duyck FM10K_TEST_MAX = FM10K_TEST_LEN 1435cb8db4aSAlexander Duyck }; 1445cb8db4aSAlexander Duyck 14580043f3bSJacob Keller enum { 14680043f3bSJacob Keller FM10K_PRV_FLAG_DEBUG_STATS, 14780043f3bSJacob Keller FM10K_PRV_FLAG_LEN, 14880043f3bSJacob Keller }; 14980043f3bSJacob Keller 15080043f3bSJacob Keller static const char fm10k_prv_flags[FM10K_PRV_FLAG_LEN][ETH_GSTRING_LEN] = { 15180043f3bSJacob Keller "debug-statistics", 15280043f3bSJacob Keller }; 15380043f3bSJacob Keller 15480043f3bSJacob Keller static void fm10k_get_stat_strings(struct net_device *dev, u8 *data) 15582dd0f7eSAlexander Duyck { 15629a928eeSJeff Kirsher struct fm10k_intfc *interface = netdev_priv(dev); 15780043f3bSJacob Keller struct fm10k_iov_data *iov_data = interface->iov_data; 15882dd0f7eSAlexander Duyck char *p = (char *)data; 159c0e58e93SJacob Keller unsigned int i; 16080043f3bSJacob Keller unsigned int j; 16182dd0f7eSAlexander Duyck 16282dd0f7eSAlexander Duyck for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) { 16382dd0f7eSAlexander Duyck memcpy(p, fm10k_gstrings_net_stats[i].stat_string, 16482dd0f7eSAlexander Duyck ETH_GSTRING_LEN); 16582dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 16682dd0f7eSAlexander Duyck } 16780043f3bSJacob Keller 16882dd0f7eSAlexander Duyck for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) { 169fbdb159fSJeff Kirsher memcpy(p, fm10k_gstrings_global_stats[i].stat_string, 170fbdb159fSJeff Kirsher ETH_GSTRING_LEN); 171fbdb159fSJeff Kirsher p += ETH_GSTRING_LEN; 172fbdb159fSJeff Kirsher } 173fbdb159fSJeff Kirsher 17480043f3bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) { 17580043f3bSJacob Keller for (i = 0; i < FM10K_DEBUG_STATS_LEN; i++) { 17680043f3bSJacob Keller memcpy(p, fm10k_gstrings_debug_stats[i].stat_string, 17780043f3bSJacob Keller ETH_GSTRING_LEN); 17880043f3bSJacob Keller p += ETH_GSTRING_LEN; 17980043f3bSJacob Keller } 18080043f3bSJacob Keller } 18180043f3bSJacob Keller 18280043f3bSJacob Keller for (i = 0; i < FM10K_MBX_STATS_LEN; i++) { 18380043f3bSJacob Keller memcpy(p, fm10k_gstrings_mbx_stats[i].stat_string, 18480043f3bSJacob Keller ETH_GSTRING_LEN); 18580043f3bSJacob Keller p += ETH_GSTRING_LEN; 18680043f3bSJacob Keller } 18780043f3bSJacob Keller 188986eec43SAlexander Duyck if (interface->hw.mac.type != fm10k_mac_vf) { 189fbdb159fSJeff Kirsher for (i = 0; i < FM10K_PF_STATS_LEN; i++) { 190fbdb159fSJeff Kirsher memcpy(p, fm10k_gstrings_pf_stats[i].stat_string, 19182dd0f7eSAlexander Duyck ETH_GSTRING_LEN); 19282dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 19382dd0f7eSAlexander Duyck } 194986eec43SAlexander Duyck } 19582dd0f7eSAlexander Duyck 19680043f3bSJacob Keller if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) { 19780043f3bSJacob Keller for (i = 0; i < iov_data->num_vfs; i++) { 19880043f3bSJacob Keller for (j = 0; j < FM10K_MBX_STATS_LEN; j++) { 19980043f3bSJacob Keller snprintf(p, 20080043f3bSJacob Keller ETH_GSTRING_LEN, 20180043f3bSJacob Keller "vf_%u_%s", i, 20280043f3bSJacob Keller fm10k_gstrings_mbx_stats[j].stat_string); 20380043f3bSJacob Keller p += ETH_GSTRING_LEN; 20480043f3bSJacob Keller } 20580043f3bSJacob Keller } 20680043f3bSJacob Keller } 20780043f3bSJacob Keller 20829a928eeSJeff Kirsher for (i = 0; i < interface->hw.mac.max_queues; i++) { 209f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_packets", i); 21082dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 211f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_bytes", i); 21282dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 213f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_packets", i); 21482dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 215f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_bytes", i); 21682dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 21782dd0f7eSAlexander Duyck } 21880043f3bSJacob Keller } 21980043f3bSJacob Keller 22080043f3bSJacob Keller static void fm10k_get_strings(struct net_device *dev, 22180043f3bSJacob Keller u32 stringset, u8 *data) 22280043f3bSJacob Keller { 22380043f3bSJacob Keller char *p = (char *)data; 22480043f3bSJacob Keller 22580043f3bSJacob Keller switch (stringset) { 22680043f3bSJacob Keller case ETH_SS_TEST: 22780043f3bSJacob Keller memcpy(data, *fm10k_gstrings_test, 22880043f3bSJacob Keller FM10K_TEST_LEN * ETH_GSTRING_LEN); 22980043f3bSJacob Keller break; 23080043f3bSJacob Keller case ETH_SS_STATS: 23180043f3bSJacob Keller fm10k_get_stat_strings(dev, data); 23280043f3bSJacob Keller break; 23380043f3bSJacob Keller case ETH_SS_PRIV_FLAGS: 23480043f3bSJacob Keller memcpy(p, fm10k_prv_flags, 23580043f3bSJacob Keller FM10K_PRV_FLAG_LEN * ETH_GSTRING_LEN); 23682dd0f7eSAlexander Duyck break; 23782dd0f7eSAlexander Duyck } 23882dd0f7eSAlexander Duyck } 23982dd0f7eSAlexander Duyck 24082dd0f7eSAlexander Duyck static int fm10k_get_sset_count(struct net_device *dev, int sset) 24182dd0f7eSAlexander Duyck { 242c0e61781SJeff Kirsher struct fm10k_intfc *interface = netdev_priv(dev); 24380043f3bSJacob Keller struct fm10k_iov_data *iov_data = interface->iov_data; 244c0e61781SJeff Kirsher struct fm10k_hw *hw = &interface->hw; 245c0e61781SJeff Kirsher int stats_len = FM10K_STATIC_STATS_LEN; 246c0e61781SJeff Kirsher 24782dd0f7eSAlexander Duyck switch (sset) { 2485cb8db4aSAlexander Duyck case ETH_SS_TEST: 2495cb8db4aSAlexander Duyck return FM10K_TEST_LEN; 25082dd0f7eSAlexander Duyck case ETH_SS_STATS: 251c0e61781SJeff Kirsher stats_len += FM10K_QUEUE_STATS_LEN(hw->mac.max_queues); 252fbdb159fSJeff Kirsher 253fbdb159fSJeff Kirsher if (hw->mac.type != fm10k_mac_vf) 254fbdb159fSJeff Kirsher stats_len += FM10K_PF_STATS_LEN; 255fbdb159fSJeff Kirsher 25680043f3bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) { 25780043f3bSJacob Keller stats_len += FM10K_DEBUG_STATS_LEN; 25880043f3bSJacob Keller 25980043f3bSJacob Keller if (iov_data) 26080043f3bSJacob Keller stats_len += FM10K_MBX_STATS_LEN * iov_data->num_vfs; 26180043f3bSJacob Keller } 26280043f3bSJacob Keller 263c0e61781SJeff Kirsher return stats_len; 26480043f3bSJacob Keller case ETH_SS_PRIV_FLAGS: 26580043f3bSJacob Keller return FM10K_PRV_FLAG_LEN; 26682dd0f7eSAlexander Duyck default: 26782dd0f7eSAlexander Duyck return -EOPNOTSUPP; 26882dd0f7eSAlexander Duyck } 26982dd0f7eSAlexander Duyck } 27082dd0f7eSAlexander Duyck 27182dd0f7eSAlexander Duyck static void fm10k_get_ethtool_stats(struct net_device *netdev, 272de445199SJeff Kirsher struct ethtool_stats __always_unused *stats, 273de445199SJeff Kirsher u64 *data) 27482dd0f7eSAlexander Duyck { 27582dd0f7eSAlexander Duyck const int stat_count = sizeof(struct fm10k_queue_stats) / sizeof(u64); 27682dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 27780043f3bSJacob Keller struct fm10k_iov_data *iov_data = interface->iov_data; 27882dd0f7eSAlexander Duyck struct net_device_stats *net_stats = &netdev->stats; 27982dd0f7eSAlexander Duyck char *p; 28082dd0f7eSAlexander Duyck int i, j; 28182dd0f7eSAlexander Duyck 28282dd0f7eSAlexander Duyck fm10k_update_stats(interface); 28382dd0f7eSAlexander Duyck 28482dd0f7eSAlexander Duyck for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) { 28582dd0f7eSAlexander Duyck p = (char *)net_stats + fm10k_gstrings_net_stats[i].stat_offset; 28682dd0f7eSAlexander Duyck *(data++) = (fm10k_gstrings_net_stats[i].sizeof_stat == 28782dd0f7eSAlexander Duyck sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 28882dd0f7eSAlexander Duyck } 28982dd0f7eSAlexander Duyck 29082dd0f7eSAlexander Duyck for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) { 291fbdb159fSJeff Kirsher p = (char *)interface + 292fbdb159fSJeff Kirsher fm10k_gstrings_global_stats[i].stat_offset; 293fbdb159fSJeff Kirsher *(data++) = (fm10k_gstrings_global_stats[i].sizeof_stat == 294fbdb159fSJeff Kirsher sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 295fbdb159fSJeff Kirsher } 296fbdb159fSJeff Kirsher 29780043f3bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) { 29880043f3bSJacob Keller for (i = 0; i < FM10K_DEBUG_STATS_LEN; i++) { 29980043f3bSJacob Keller p = (char *)interface + fm10k_gstrings_debug_stats[i].stat_offset; 30080043f3bSJacob Keller *(data++) = (fm10k_gstrings_debug_stats[i].sizeof_stat == 30180043f3bSJacob Keller sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 30280043f3bSJacob Keller } 30380043f3bSJacob Keller } 30480043f3bSJacob Keller 30580043f3bSJacob Keller for (i = 0; i < FM10K_MBX_STATS_LEN; i++) { 30680043f3bSJacob Keller p = (char *)&interface->hw.mbx + fm10k_gstrings_mbx_stats[i].stat_offset; 30780043f3bSJacob Keller *(data++) = (fm10k_gstrings_mbx_stats[i].sizeof_stat == 30880043f3bSJacob Keller sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 30980043f3bSJacob Keller } 31080043f3bSJacob Keller 31180043f3bSJacob Keller if (interface->hw.mac.type != fm10k_mac_vf) { 312fbdb159fSJeff Kirsher for (i = 0; i < FM10K_PF_STATS_LEN; i++) { 313fbdb159fSJeff Kirsher p = (char *)interface + 314fbdb159fSJeff Kirsher fm10k_gstrings_pf_stats[i].stat_offset; 315fbdb159fSJeff Kirsher *(data++) = (fm10k_gstrings_pf_stats[i].sizeof_stat == 31682dd0f7eSAlexander Duyck sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 31782dd0f7eSAlexander Duyck } 31880043f3bSJacob Keller } 31980043f3bSJacob Keller 32080043f3bSJacob Keller if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) { 32180043f3bSJacob Keller for (i = 0; i < iov_data->num_vfs; i++) { 32280043f3bSJacob Keller struct fm10k_vf_info *vf_info; 32380043f3bSJacob Keller vf_info = &iov_data->vf_info[i]; 32480043f3bSJacob Keller 32580043f3bSJacob Keller /* skip stats if we don't have a vf info */ 32680043f3bSJacob Keller if (!vf_info) { 32780043f3bSJacob Keller data += FM10K_MBX_STATS_LEN; 32880043f3bSJacob Keller continue; 32980043f3bSJacob Keller } 33080043f3bSJacob Keller 33180043f3bSJacob Keller for (j = 0; j < FM10K_MBX_STATS_LEN; j++) { 33280043f3bSJacob Keller p = (char *)&vf_info->mbx + fm10k_gstrings_mbx_stats[j].stat_offset; 33380043f3bSJacob Keller *(data++) = (fm10k_gstrings_mbx_stats[j].sizeof_stat == 33480043f3bSJacob Keller sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 33580043f3bSJacob Keller } 33680043f3bSJacob Keller } 33780043f3bSJacob Keller } 33882dd0f7eSAlexander Duyck 33929a928eeSJeff Kirsher for (i = 0; i < interface->hw.mac.max_queues; i++) { 34082dd0f7eSAlexander Duyck struct fm10k_ring *ring; 34182dd0f7eSAlexander Duyck u64 *queue_stat; 34282dd0f7eSAlexander Duyck 34382dd0f7eSAlexander Duyck ring = interface->tx_ring[i]; 34482dd0f7eSAlexander Duyck if (ring) 34582dd0f7eSAlexander Duyck queue_stat = (u64 *)&ring->stats; 34682dd0f7eSAlexander Duyck for (j = 0; j < stat_count; j++) 34782dd0f7eSAlexander Duyck *(data++) = ring ? queue_stat[j] : 0; 34882dd0f7eSAlexander Duyck 34982dd0f7eSAlexander Duyck ring = interface->rx_ring[i]; 35082dd0f7eSAlexander Duyck if (ring) 35182dd0f7eSAlexander Duyck queue_stat = (u64 *)&ring->stats; 35282dd0f7eSAlexander Duyck for (j = 0; j < stat_count; j++) 35382dd0f7eSAlexander Duyck *(data++) = ring ? queue_stat[j] : 0; 35482dd0f7eSAlexander Duyck } 35582dd0f7eSAlexander Duyck } 35682dd0f7eSAlexander Duyck 35782dd0f7eSAlexander Duyck /* If function below adds more registers this define needs to be updated */ 35882dd0f7eSAlexander Duyck #define FM10K_REGS_LEN_Q 29 35982dd0f7eSAlexander Duyck 36082dd0f7eSAlexander Duyck static void fm10k_get_reg_q(struct fm10k_hw *hw, u32 *buff, int i) 36182dd0f7eSAlexander Duyck { 36282dd0f7eSAlexander Duyck int idx = 0; 36382dd0f7eSAlexander Duyck 36482dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAL(i)); 36582dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAH(i)); 36682dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDLEN(i)); 36782dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_RXCTRL(i)); 36882dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDH(i)); 36982dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDT(i)); 37082dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RXQCTL(i)); 37182dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RXDCTL(i)); 37282dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RXINT(i)); 37382dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_SRRCTL(i)); 37482dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QPRC(i)); 37582dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QPRDC(i)); 37682dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_L(i)); 37782dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_H(i)); 37882dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAL(i)); 37982dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAH(i)); 38082dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDLEN(i)); 38182dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_TXCTRL(i)); 38282dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDH(i)); 38382dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDT(i)); 38482dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TXDCTL(i)); 38582dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TXQCTL(i)); 38682dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TXINT(i)); 38782dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QPTC(i)); 38882dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_L(i)); 38982dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_H(i)); 39082dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TQDLOC(i)); 39182dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TX_SGLORT(i)); 39282dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_PFVTCTL(i)); 39382dd0f7eSAlexander Duyck 39482dd0f7eSAlexander Duyck BUG_ON(idx != FM10K_REGS_LEN_Q); 39582dd0f7eSAlexander Duyck } 39682dd0f7eSAlexander Duyck 39782dd0f7eSAlexander Duyck /* If function above adds more registers this define needs to be updated */ 39882dd0f7eSAlexander Duyck #define FM10K_REGS_LEN_VSI 43 39982dd0f7eSAlexander Duyck 40082dd0f7eSAlexander Duyck static void fm10k_get_reg_vsi(struct fm10k_hw *hw, u32 *buff, int i) 40182dd0f7eSAlexander Duyck { 40282dd0f7eSAlexander Duyck int idx = 0, j; 40382dd0f7eSAlexander Duyck 40482dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_MRQC(i)); 40582dd0f7eSAlexander Duyck for (j = 0; j < 10; j++) 40682dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RSSRK(i, j)); 40782dd0f7eSAlexander Duyck for (j = 0; j < 32; j++) 40882dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RETA(i, j)); 40982dd0f7eSAlexander Duyck 41082dd0f7eSAlexander Duyck BUG_ON(idx != FM10K_REGS_LEN_VSI); 41182dd0f7eSAlexander Duyck } 41282dd0f7eSAlexander Duyck 41382dd0f7eSAlexander Duyck static void fm10k_get_regs(struct net_device *netdev, 41482dd0f7eSAlexander Duyck struct ethtool_regs *regs, void *p) 41582dd0f7eSAlexander Duyck { 41682dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 41782dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 41882dd0f7eSAlexander Duyck u32 *buff = p; 41982dd0f7eSAlexander Duyck u16 i; 42082dd0f7eSAlexander Duyck 42182dd0f7eSAlexander Duyck regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; 42282dd0f7eSAlexander Duyck 42382dd0f7eSAlexander Duyck switch (hw->mac.type) { 42482dd0f7eSAlexander Duyck case fm10k_mac_pf: 42582dd0f7eSAlexander Duyck /* General PF Registers */ 42682dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_CTRL); 42782dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_CTRL_EXT); 42882dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_GCR); 42982dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_GCR_EXT); 43082dd0f7eSAlexander Duyck 43182dd0f7eSAlexander Duyck for (i = 0; i < 8; i++) { 43282dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTMAP(i)); 43382dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTDEC(i)); 43482dd0f7eSAlexander Duyck } 43582dd0f7eSAlexander Duyck 43682dd0f7eSAlexander Duyck for (i = 0; i < 65; i++) { 43782dd0f7eSAlexander Duyck fm10k_get_reg_vsi(hw, buff, i); 43882dd0f7eSAlexander Duyck buff += FM10K_REGS_LEN_VSI; 43982dd0f7eSAlexander Duyck } 44082dd0f7eSAlexander Duyck 44182dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL); 44282dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL2); 44382dd0f7eSAlexander Duyck 44482dd0f7eSAlexander Duyck for (i = 0; i < FM10K_MAX_QUEUES_PF; i++) { 44582dd0f7eSAlexander Duyck fm10k_get_reg_q(hw, buff, i); 44682dd0f7eSAlexander Duyck buff += FM10K_REGS_LEN_Q; 44782dd0f7eSAlexander Duyck } 44882dd0f7eSAlexander Duyck 44982dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_TPH_CTRL); 45082dd0f7eSAlexander Duyck 45182dd0f7eSAlexander Duyck for (i = 0; i < 8; i++) 45282dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_INT_MAP(i)); 45382dd0f7eSAlexander Duyck 45482dd0f7eSAlexander Duyck /* Interrupt Throttling Registers */ 45582dd0f7eSAlexander Duyck for (i = 0; i < 130; i++) 45682dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_ITR(i)); 45782dd0f7eSAlexander Duyck 45882dd0f7eSAlexander Duyck break; 4595cb8db4aSAlexander Duyck case fm10k_mac_vf: 4605cb8db4aSAlexander Duyck /* General VF registers */ 4615cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFCTRL); 4625cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFINT_MAP); 4635cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFSYSTIME); 4645cb8db4aSAlexander Duyck 4655cb8db4aSAlexander Duyck /* Interrupt Throttling Registers */ 4665cb8db4aSAlexander Duyck for (i = 0; i < 8; i++) 4675cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFITR(i)); 4685cb8db4aSAlexander Duyck 4695cb8db4aSAlexander Duyck fm10k_get_reg_vsi(hw, buff, 0); 4705cb8db4aSAlexander Duyck buff += FM10K_REGS_LEN_VSI; 4715cb8db4aSAlexander Duyck 4725cb8db4aSAlexander Duyck for (i = 0; i < FM10K_MAX_QUEUES_POOL; i++) { 4735cb8db4aSAlexander Duyck if (i < hw->mac.max_queues) 4745cb8db4aSAlexander Duyck fm10k_get_reg_q(hw, buff, i); 4755cb8db4aSAlexander Duyck else 4765cb8db4aSAlexander Duyck memset(buff, 0, sizeof(u32) * FM10K_REGS_LEN_Q); 4775cb8db4aSAlexander Duyck buff += FM10K_REGS_LEN_Q; 4785cb8db4aSAlexander Duyck } 4795cb8db4aSAlexander Duyck 4805cb8db4aSAlexander Duyck break; 48182dd0f7eSAlexander Duyck default: 48282dd0f7eSAlexander Duyck return; 48382dd0f7eSAlexander Duyck } 48482dd0f7eSAlexander Duyck } 48582dd0f7eSAlexander Duyck 48682dd0f7eSAlexander Duyck /* If function above adds more registers these define need to be updated */ 48782dd0f7eSAlexander Duyck #define FM10K_REGS_LEN_PF \ 48882dd0f7eSAlexander Duyck (162 + (65 * FM10K_REGS_LEN_VSI) + (FM10K_MAX_QUEUES_PF * FM10K_REGS_LEN_Q)) 4895cb8db4aSAlexander Duyck #define FM10K_REGS_LEN_VF \ 4905cb8db4aSAlexander Duyck (11 + FM10K_REGS_LEN_VSI + (FM10K_MAX_QUEUES_POOL * FM10K_REGS_LEN_Q)) 49182dd0f7eSAlexander Duyck 49282dd0f7eSAlexander Duyck static int fm10k_get_regs_len(struct net_device *netdev) 49382dd0f7eSAlexander Duyck { 49482dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 49582dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 49682dd0f7eSAlexander Duyck 49782dd0f7eSAlexander Duyck switch (hw->mac.type) { 49882dd0f7eSAlexander Duyck case fm10k_mac_pf: 49982dd0f7eSAlexander Duyck return FM10K_REGS_LEN_PF * sizeof(u32); 5005cb8db4aSAlexander Duyck case fm10k_mac_vf: 5015cb8db4aSAlexander Duyck return FM10K_REGS_LEN_VF * sizeof(u32); 50282dd0f7eSAlexander Duyck default: 50382dd0f7eSAlexander Duyck return 0; 50482dd0f7eSAlexander Duyck } 50582dd0f7eSAlexander Duyck } 50682dd0f7eSAlexander Duyck 50782dd0f7eSAlexander Duyck static void fm10k_get_drvinfo(struct net_device *dev, 50882dd0f7eSAlexander Duyck struct ethtool_drvinfo *info) 50982dd0f7eSAlexander Duyck { 51082dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 51182dd0f7eSAlexander Duyck 51282dd0f7eSAlexander Duyck strncpy(info->driver, fm10k_driver_name, 51382dd0f7eSAlexander Duyck sizeof(info->driver) - 1); 51482dd0f7eSAlexander Duyck strncpy(info->version, fm10k_driver_version, 51582dd0f7eSAlexander Duyck sizeof(info->version) - 1); 51682dd0f7eSAlexander Duyck strncpy(info->bus_info, pci_name(interface->pdev), 51782dd0f7eSAlexander Duyck sizeof(info->bus_info) - 1); 51882dd0f7eSAlexander Duyck 519c0e61781SJeff Kirsher info->n_stats = fm10k_get_sset_count(dev, ETH_SS_STATS); 52082dd0f7eSAlexander Duyck 52182dd0f7eSAlexander Duyck info->regdump_len = fm10k_get_regs_len(dev); 52282dd0f7eSAlexander Duyck } 52382dd0f7eSAlexander Duyck 52482dd0f7eSAlexander Duyck static void fm10k_get_pauseparam(struct net_device *dev, 52582dd0f7eSAlexander Duyck struct ethtool_pauseparam *pause) 52682dd0f7eSAlexander Duyck { 52782dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 52882dd0f7eSAlexander Duyck 52982dd0f7eSAlexander Duyck /* record fixed values for autoneg and tx pause */ 53082dd0f7eSAlexander Duyck pause->autoneg = 0; 53182dd0f7eSAlexander Duyck pause->tx_pause = 1; 53282dd0f7eSAlexander Duyck 53382dd0f7eSAlexander Duyck pause->rx_pause = interface->rx_pause ? 1 : 0; 53482dd0f7eSAlexander Duyck } 53582dd0f7eSAlexander Duyck 53682dd0f7eSAlexander Duyck static int fm10k_set_pauseparam(struct net_device *dev, 53782dd0f7eSAlexander Duyck struct ethtool_pauseparam *pause) 53882dd0f7eSAlexander Duyck { 53982dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 54082dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 54182dd0f7eSAlexander Duyck 54282dd0f7eSAlexander Duyck if (pause->autoneg || !pause->tx_pause) 54382dd0f7eSAlexander Duyck return -EINVAL; 54482dd0f7eSAlexander Duyck 54582dd0f7eSAlexander Duyck /* we can only support pause on the PF to avoid head-of-line blocking */ 54682dd0f7eSAlexander Duyck if (hw->mac.type == fm10k_mac_pf) 54782dd0f7eSAlexander Duyck interface->rx_pause = pause->rx_pause ? ~0 : 0; 54882dd0f7eSAlexander Duyck else if (pause->rx_pause) 54982dd0f7eSAlexander Duyck return -EINVAL; 55082dd0f7eSAlexander Duyck 55182dd0f7eSAlexander Duyck if (netif_running(dev)) 55282dd0f7eSAlexander Duyck fm10k_update_rx_drop_en(interface); 55382dd0f7eSAlexander Duyck 55482dd0f7eSAlexander Duyck return 0; 55582dd0f7eSAlexander Duyck } 55682dd0f7eSAlexander Duyck 55782dd0f7eSAlexander Duyck static u32 fm10k_get_msglevel(struct net_device *netdev) 55882dd0f7eSAlexander Duyck { 55982dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 56082dd0f7eSAlexander Duyck 56182dd0f7eSAlexander Duyck return interface->msg_enable; 56282dd0f7eSAlexander Duyck } 56382dd0f7eSAlexander Duyck 56482dd0f7eSAlexander Duyck static void fm10k_set_msglevel(struct net_device *netdev, u32 data) 56582dd0f7eSAlexander Duyck { 56682dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 56782dd0f7eSAlexander Duyck 56882dd0f7eSAlexander Duyck interface->msg_enable = data; 56982dd0f7eSAlexander Duyck } 57082dd0f7eSAlexander Duyck 57182dd0f7eSAlexander Duyck static void fm10k_get_ringparam(struct net_device *netdev, 57282dd0f7eSAlexander Duyck struct ethtool_ringparam *ring) 57382dd0f7eSAlexander Duyck { 57482dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 57582dd0f7eSAlexander Duyck 57682dd0f7eSAlexander Duyck ring->rx_max_pending = FM10K_MAX_RXD; 57782dd0f7eSAlexander Duyck ring->tx_max_pending = FM10K_MAX_TXD; 57882dd0f7eSAlexander Duyck ring->rx_mini_max_pending = 0; 57982dd0f7eSAlexander Duyck ring->rx_jumbo_max_pending = 0; 58082dd0f7eSAlexander Duyck ring->rx_pending = interface->rx_ring_count; 58182dd0f7eSAlexander Duyck ring->tx_pending = interface->tx_ring_count; 58282dd0f7eSAlexander Duyck ring->rx_mini_pending = 0; 58382dd0f7eSAlexander Duyck ring->rx_jumbo_pending = 0; 58482dd0f7eSAlexander Duyck } 58582dd0f7eSAlexander Duyck 58682dd0f7eSAlexander Duyck static int fm10k_set_ringparam(struct net_device *netdev, 58782dd0f7eSAlexander Duyck struct ethtool_ringparam *ring) 58882dd0f7eSAlexander Duyck { 58982dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 59082dd0f7eSAlexander Duyck struct fm10k_ring *temp_ring; 59182dd0f7eSAlexander Duyck int i, err = 0; 59282dd0f7eSAlexander Duyck u32 new_rx_count, new_tx_count; 59382dd0f7eSAlexander Duyck 59482dd0f7eSAlexander Duyck if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 59582dd0f7eSAlexander Duyck return -EINVAL; 59682dd0f7eSAlexander Duyck 59782dd0f7eSAlexander Duyck new_tx_count = clamp_t(u32, ring->tx_pending, 59882dd0f7eSAlexander Duyck FM10K_MIN_TXD, FM10K_MAX_TXD); 59982dd0f7eSAlexander Duyck new_tx_count = ALIGN(new_tx_count, FM10K_REQ_TX_DESCRIPTOR_MULTIPLE); 60082dd0f7eSAlexander Duyck 60182dd0f7eSAlexander Duyck new_rx_count = clamp_t(u32, ring->rx_pending, 60282dd0f7eSAlexander Duyck FM10K_MIN_RXD, FM10K_MAX_RXD); 60382dd0f7eSAlexander Duyck new_rx_count = ALIGN(new_rx_count, FM10K_REQ_RX_DESCRIPTOR_MULTIPLE); 60482dd0f7eSAlexander Duyck 60582dd0f7eSAlexander Duyck if ((new_tx_count == interface->tx_ring_count) && 60682dd0f7eSAlexander Duyck (new_rx_count == interface->rx_ring_count)) { 60782dd0f7eSAlexander Duyck /* nothing to do */ 60882dd0f7eSAlexander Duyck return 0; 60982dd0f7eSAlexander Duyck } 61082dd0f7eSAlexander Duyck 61182dd0f7eSAlexander Duyck while (test_and_set_bit(__FM10K_RESETTING, &interface->state)) 61282dd0f7eSAlexander Duyck usleep_range(1000, 2000); 61382dd0f7eSAlexander Duyck 61482dd0f7eSAlexander Duyck if (!netif_running(interface->netdev)) { 61582dd0f7eSAlexander Duyck for (i = 0; i < interface->num_tx_queues; i++) 61682dd0f7eSAlexander Duyck interface->tx_ring[i]->count = new_tx_count; 61782dd0f7eSAlexander Duyck for (i = 0; i < interface->num_rx_queues; i++) 61882dd0f7eSAlexander Duyck interface->rx_ring[i]->count = new_rx_count; 61982dd0f7eSAlexander Duyck interface->tx_ring_count = new_tx_count; 62082dd0f7eSAlexander Duyck interface->rx_ring_count = new_rx_count; 62182dd0f7eSAlexander Duyck goto clear_reset; 62282dd0f7eSAlexander Duyck } 62382dd0f7eSAlexander Duyck 62482dd0f7eSAlexander Duyck /* allocate temporary buffer to store rings in */ 62582dd0f7eSAlexander Duyck i = max_t(int, interface->num_tx_queues, interface->num_rx_queues); 62682dd0f7eSAlexander Duyck temp_ring = vmalloc(i * sizeof(struct fm10k_ring)); 62782dd0f7eSAlexander Duyck 62882dd0f7eSAlexander Duyck if (!temp_ring) { 62982dd0f7eSAlexander Duyck err = -ENOMEM; 63082dd0f7eSAlexander Duyck goto clear_reset; 63182dd0f7eSAlexander Duyck } 63282dd0f7eSAlexander Duyck 63382dd0f7eSAlexander Duyck fm10k_down(interface); 63482dd0f7eSAlexander Duyck 63582dd0f7eSAlexander Duyck /* Setup new Tx resources and free the old Tx resources in that order. 63682dd0f7eSAlexander Duyck * We can then assign the new resources to the rings via a memcpy. 63782dd0f7eSAlexander Duyck * The advantage to this approach is that we are guaranteed to still 63882dd0f7eSAlexander Duyck * have resources even in the case of an allocation failure. 63982dd0f7eSAlexander Duyck */ 64082dd0f7eSAlexander Duyck if (new_tx_count != interface->tx_ring_count) { 64182dd0f7eSAlexander Duyck for (i = 0; i < interface->num_tx_queues; i++) { 64282dd0f7eSAlexander Duyck memcpy(&temp_ring[i], interface->tx_ring[i], 64382dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 64482dd0f7eSAlexander Duyck 64582dd0f7eSAlexander Duyck temp_ring[i].count = new_tx_count; 64682dd0f7eSAlexander Duyck err = fm10k_setup_tx_resources(&temp_ring[i]); 64782dd0f7eSAlexander Duyck if (err) { 64882dd0f7eSAlexander Duyck while (i) { 64982dd0f7eSAlexander Duyck i--; 65082dd0f7eSAlexander Duyck fm10k_free_tx_resources(&temp_ring[i]); 65182dd0f7eSAlexander Duyck } 65282dd0f7eSAlexander Duyck goto err_setup; 65382dd0f7eSAlexander Duyck } 65482dd0f7eSAlexander Duyck } 65582dd0f7eSAlexander Duyck 65682dd0f7eSAlexander Duyck for (i = 0; i < interface->num_tx_queues; i++) { 65782dd0f7eSAlexander Duyck fm10k_free_tx_resources(interface->tx_ring[i]); 65882dd0f7eSAlexander Duyck 65982dd0f7eSAlexander Duyck memcpy(interface->tx_ring[i], &temp_ring[i], 66082dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 66182dd0f7eSAlexander Duyck } 66282dd0f7eSAlexander Duyck 66382dd0f7eSAlexander Duyck interface->tx_ring_count = new_tx_count; 66482dd0f7eSAlexander Duyck } 66582dd0f7eSAlexander Duyck 66682dd0f7eSAlexander Duyck /* Repeat the process for the Rx rings if needed */ 66782dd0f7eSAlexander Duyck if (new_rx_count != interface->rx_ring_count) { 66882dd0f7eSAlexander Duyck for (i = 0; i < interface->num_rx_queues; i++) { 66982dd0f7eSAlexander Duyck memcpy(&temp_ring[i], interface->rx_ring[i], 67082dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 67182dd0f7eSAlexander Duyck 67282dd0f7eSAlexander Duyck temp_ring[i].count = new_rx_count; 67382dd0f7eSAlexander Duyck err = fm10k_setup_rx_resources(&temp_ring[i]); 67482dd0f7eSAlexander Duyck if (err) { 67582dd0f7eSAlexander Duyck while (i) { 67682dd0f7eSAlexander Duyck i--; 67782dd0f7eSAlexander Duyck fm10k_free_rx_resources(&temp_ring[i]); 67882dd0f7eSAlexander Duyck } 67982dd0f7eSAlexander Duyck goto err_setup; 68082dd0f7eSAlexander Duyck } 68182dd0f7eSAlexander Duyck } 68282dd0f7eSAlexander Duyck 68382dd0f7eSAlexander Duyck for (i = 0; i < interface->num_rx_queues; i++) { 68482dd0f7eSAlexander Duyck fm10k_free_rx_resources(interface->rx_ring[i]); 68582dd0f7eSAlexander Duyck 68682dd0f7eSAlexander Duyck memcpy(interface->rx_ring[i], &temp_ring[i], 68782dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 68882dd0f7eSAlexander Duyck } 68982dd0f7eSAlexander Duyck 69082dd0f7eSAlexander Duyck interface->rx_ring_count = new_rx_count; 69182dd0f7eSAlexander Duyck } 69282dd0f7eSAlexander Duyck 69382dd0f7eSAlexander Duyck err_setup: 69482dd0f7eSAlexander Duyck fm10k_up(interface); 69582dd0f7eSAlexander Duyck vfree(temp_ring); 69682dd0f7eSAlexander Duyck clear_reset: 69782dd0f7eSAlexander Duyck clear_bit(__FM10K_RESETTING, &interface->state); 69882dd0f7eSAlexander Duyck return err; 69982dd0f7eSAlexander Duyck } 70082dd0f7eSAlexander Duyck 70182dd0f7eSAlexander Duyck static int fm10k_get_coalesce(struct net_device *dev, 70282dd0f7eSAlexander Duyck struct ethtool_coalesce *ec) 70382dd0f7eSAlexander Duyck { 70482dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 70582dd0f7eSAlexander Duyck 70682dd0f7eSAlexander Duyck ec->use_adaptive_tx_coalesce = 70782dd0f7eSAlexander Duyck !!(interface->tx_itr & FM10K_ITR_ADAPTIVE); 70882dd0f7eSAlexander Duyck ec->tx_coalesce_usecs = interface->tx_itr & ~FM10K_ITR_ADAPTIVE; 70982dd0f7eSAlexander Duyck 71082dd0f7eSAlexander Duyck ec->use_adaptive_rx_coalesce = 71182dd0f7eSAlexander Duyck !!(interface->rx_itr & FM10K_ITR_ADAPTIVE); 71282dd0f7eSAlexander Duyck ec->rx_coalesce_usecs = interface->rx_itr & ~FM10K_ITR_ADAPTIVE; 71382dd0f7eSAlexander Duyck 71482dd0f7eSAlexander Duyck return 0; 71582dd0f7eSAlexander Duyck } 71682dd0f7eSAlexander Duyck 71782dd0f7eSAlexander Duyck static int fm10k_set_coalesce(struct net_device *dev, 71882dd0f7eSAlexander Duyck struct ethtool_coalesce *ec) 71982dd0f7eSAlexander Duyck { 72082dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 72182dd0f7eSAlexander Duyck struct fm10k_q_vector *qv; 72282dd0f7eSAlexander Duyck u16 tx_itr, rx_itr; 72382dd0f7eSAlexander Duyck int i; 72482dd0f7eSAlexander Duyck 72582dd0f7eSAlexander Duyck /* verify limits */ 72682dd0f7eSAlexander Duyck if ((ec->rx_coalesce_usecs > FM10K_ITR_MAX) || 72782dd0f7eSAlexander Duyck (ec->tx_coalesce_usecs > FM10K_ITR_MAX)) 72882dd0f7eSAlexander Duyck return -EINVAL; 72982dd0f7eSAlexander Duyck 73082dd0f7eSAlexander Duyck /* record settings */ 73182dd0f7eSAlexander Duyck tx_itr = ec->tx_coalesce_usecs; 73282dd0f7eSAlexander Duyck rx_itr = ec->rx_coalesce_usecs; 73382dd0f7eSAlexander Duyck 73482dd0f7eSAlexander Duyck /* set initial values for adaptive ITR */ 73582dd0f7eSAlexander Duyck if (ec->use_adaptive_tx_coalesce) 73682dd0f7eSAlexander Duyck tx_itr = FM10K_ITR_ADAPTIVE | FM10K_ITR_10K; 73782dd0f7eSAlexander Duyck 73882dd0f7eSAlexander Duyck if (ec->use_adaptive_rx_coalesce) 73982dd0f7eSAlexander Duyck rx_itr = FM10K_ITR_ADAPTIVE | FM10K_ITR_20K; 74082dd0f7eSAlexander Duyck 74182dd0f7eSAlexander Duyck /* update interface */ 74282dd0f7eSAlexander Duyck interface->tx_itr = tx_itr; 74382dd0f7eSAlexander Duyck interface->rx_itr = rx_itr; 74482dd0f7eSAlexander Duyck 74582dd0f7eSAlexander Duyck /* update q_vectors */ 74682dd0f7eSAlexander Duyck for (i = 0; i < interface->num_q_vectors; i++) { 74782dd0f7eSAlexander Duyck qv = interface->q_vector[i]; 74882dd0f7eSAlexander Duyck qv->tx.itr = tx_itr; 74982dd0f7eSAlexander Duyck qv->rx.itr = rx_itr; 75082dd0f7eSAlexander Duyck } 75182dd0f7eSAlexander Duyck 75282dd0f7eSAlexander Duyck return 0; 75382dd0f7eSAlexander Duyck } 75482dd0f7eSAlexander Duyck 75582dd0f7eSAlexander Duyck static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface, 75682dd0f7eSAlexander Duyck struct ethtool_rxnfc *cmd) 75782dd0f7eSAlexander Duyck { 75882dd0f7eSAlexander Duyck cmd->data = 0; 75982dd0f7eSAlexander Duyck 76082dd0f7eSAlexander Duyck /* Report default options for RSS on fm10k */ 76182dd0f7eSAlexander Duyck switch (cmd->flow_type) { 76282dd0f7eSAlexander Duyck case TCP_V4_FLOW: 76382dd0f7eSAlexander Duyck case TCP_V6_FLOW: 76482dd0f7eSAlexander Duyck cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 76582dd0f7eSAlexander Duyck /* fall through */ 76682dd0f7eSAlexander Duyck case UDP_V4_FLOW: 76782dd0f7eSAlexander Duyck if (interface->flags & FM10K_FLAG_RSS_FIELD_IPV4_UDP) 76882dd0f7eSAlexander Duyck cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 76982dd0f7eSAlexander Duyck /* fall through */ 77082dd0f7eSAlexander Duyck case SCTP_V4_FLOW: 77182dd0f7eSAlexander Duyck case SCTP_V6_FLOW: 77282dd0f7eSAlexander Duyck case AH_ESP_V4_FLOW: 77382dd0f7eSAlexander Duyck case AH_ESP_V6_FLOW: 77482dd0f7eSAlexander Duyck case AH_V4_FLOW: 77582dd0f7eSAlexander Duyck case AH_V6_FLOW: 77682dd0f7eSAlexander Duyck case ESP_V4_FLOW: 77782dd0f7eSAlexander Duyck case ESP_V6_FLOW: 77882dd0f7eSAlexander Duyck case IPV4_FLOW: 77982dd0f7eSAlexander Duyck case IPV6_FLOW: 78082dd0f7eSAlexander Duyck cmd->data |= RXH_IP_SRC | RXH_IP_DST; 78182dd0f7eSAlexander Duyck break; 78282dd0f7eSAlexander Duyck case UDP_V6_FLOW: 78382dd0f7eSAlexander Duyck if (interface->flags & FM10K_FLAG_RSS_FIELD_IPV6_UDP) 78482dd0f7eSAlexander Duyck cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 78582dd0f7eSAlexander Duyck cmd->data |= RXH_IP_SRC | RXH_IP_DST; 78682dd0f7eSAlexander Duyck break; 78782dd0f7eSAlexander Duyck default: 78882dd0f7eSAlexander Duyck return -EINVAL; 78982dd0f7eSAlexander Duyck } 79082dd0f7eSAlexander Duyck 79182dd0f7eSAlexander Duyck return 0; 79282dd0f7eSAlexander Duyck } 79382dd0f7eSAlexander Duyck 79482dd0f7eSAlexander Duyck static int fm10k_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 795de445199SJeff Kirsher u32 __always_unused *rule_locs) 79682dd0f7eSAlexander Duyck { 79782dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 79882dd0f7eSAlexander Duyck int ret = -EOPNOTSUPP; 79982dd0f7eSAlexander Duyck 80082dd0f7eSAlexander Duyck switch (cmd->cmd) { 80182dd0f7eSAlexander Duyck case ETHTOOL_GRXRINGS: 80282dd0f7eSAlexander Duyck cmd->data = interface->num_rx_queues; 80382dd0f7eSAlexander Duyck ret = 0; 80482dd0f7eSAlexander Duyck break; 80582dd0f7eSAlexander Duyck case ETHTOOL_GRXFH: 80682dd0f7eSAlexander Duyck ret = fm10k_get_rss_hash_opts(interface, cmd); 80782dd0f7eSAlexander Duyck break; 80882dd0f7eSAlexander Duyck default: 80982dd0f7eSAlexander Duyck break; 81082dd0f7eSAlexander Duyck } 81182dd0f7eSAlexander Duyck 81282dd0f7eSAlexander Duyck return ret; 81382dd0f7eSAlexander Duyck } 81482dd0f7eSAlexander Duyck 81582dd0f7eSAlexander Duyck #define UDP_RSS_FLAGS (FM10K_FLAG_RSS_FIELD_IPV4_UDP | \ 81682dd0f7eSAlexander Duyck FM10K_FLAG_RSS_FIELD_IPV6_UDP) 81782dd0f7eSAlexander Duyck static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface, 81882dd0f7eSAlexander Duyck struct ethtool_rxnfc *nfc) 81982dd0f7eSAlexander Duyck { 82082dd0f7eSAlexander Duyck u32 flags = interface->flags; 82182dd0f7eSAlexander Duyck 82282dd0f7eSAlexander Duyck /* RSS does not support anything other than hashing 82382dd0f7eSAlexander Duyck * to queues on src and dst IPs and ports 82482dd0f7eSAlexander Duyck */ 82582dd0f7eSAlexander Duyck if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | 82682dd0f7eSAlexander Duyck RXH_L4_B_0_1 | RXH_L4_B_2_3)) 82782dd0f7eSAlexander Duyck return -EINVAL; 82882dd0f7eSAlexander Duyck 82982dd0f7eSAlexander Duyck switch (nfc->flow_type) { 83082dd0f7eSAlexander Duyck case TCP_V4_FLOW: 83182dd0f7eSAlexander Duyck case TCP_V6_FLOW: 83282dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 83382dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST) || 83482dd0f7eSAlexander Duyck !(nfc->data & RXH_L4_B_0_1) || 83582dd0f7eSAlexander Duyck !(nfc->data & RXH_L4_B_2_3)) 83682dd0f7eSAlexander Duyck return -EINVAL; 83782dd0f7eSAlexander Duyck break; 83882dd0f7eSAlexander Duyck case UDP_V4_FLOW: 83982dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 84082dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST)) 84182dd0f7eSAlexander Duyck return -EINVAL; 84282dd0f7eSAlexander Duyck switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 84382dd0f7eSAlexander Duyck case 0: 84482dd0f7eSAlexander Duyck flags &= ~FM10K_FLAG_RSS_FIELD_IPV4_UDP; 84582dd0f7eSAlexander Duyck break; 84682dd0f7eSAlexander Duyck case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 84782dd0f7eSAlexander Duyck flags |= FM10K_FLAG_RSS_FIELD_IPV4_UDP; 84882dd0f7eSAlexander Duyck break; 84982dd0f7eSAlexander Duyck default: 85082dd0f7eSAlexander Duyck return -EINVAL; 85182dd0f7eSAlexander Duyck } 85282dd0f7eSAlexander Duyck break; 85382dd0f7eSAlexander Duyck case UDP_V6_FLOW: 85482dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 85582dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST)) 85682dd0f7eSAlexander Duyck return -EINVAL; 85782dd0f7eSAlexander Duyck switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 85882dd0f7eSAlexander Duyck case 0: 85982dd0f7eSAlexander Duyck flags &= ~FM10K_FLAG_RSS_FIELD_IPV6_UDP; 86082dd0f7eSAlexander Duyck break; 86182dd0f7eSAlexander Duyck case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 86282dd0f7eSAlexander Duyck flags |= FM10K_FLAG_RSS_FIELD_IPV6_UDP; 86382dd0f7eSAlexander Duyck break; 86482dd0f7eSAlexander Duyck default: 86582dd0f7eSAlexander Duyck return -EINVAL; 86682dd0f7eSAlexander Duyck } 86782dd0f7eSAlexander Duyck break; 86882dd0f7eSAlexander Duyck case AH_ESP_V4_FLOW: 86982dd0f7eSAlexander Duyck case AH_V4_FLOW: 87082dd0f7eSAlexander Duyck case ESP_V4_FLOW: 87182dd0f7eSAlexander Duyck case SCTP_V4_FLOW: 87282dd0f7eSAlexander Duyck case AH_ESP_V6_FLOW: 87382dd0f7eSAlexander Duyck case AH_V6_FLOW: 87482dd0f7eSAlexander Duyck case ESP_V6_FLOW: 87582dd0f7eSAlexander Duyck case SCTP_V6_FLOW: 87682dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 87782dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST) || 87882dd0f7eSAlexander Duyck (nfc->data & RXH_L4_B_0_1) || 87982dd0f7eSAlexander Duyck (nfc->data & RXH_L4_B_2_3)) 88082dd0f7eSAlexander Duyck return -EINVAL; 88182dd0f7eSAlexander Duyck break; 88282dd0f7eSAlexander Duyck default: 88382dd0f7eSAlexander Duyck return -EINVAL; 88482dd0f7eSAlexander Duyck } 88582dd0f7eSAlexander Duyck 88682dd0f7eSAlexander Duyck /* if we changed something we need to update flags */ 88782dd0f7eSAlexander Duyck if (flags != interface->flags) { 88882dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 88982dd0f7eSAlexander Duyck u32 mrqc; 89082dd0f7eSAlexander Duyck 89182dd0f7eSAlexander Duyck if ((flags & UDP_RSS_FLAGS) && 89282dd0f7eSAlexander Duyck !(interface->flags & UDP_RSS_FLAGS)) 89382dd0f7eSAlexander Duyck netif_warn(interface, drv, interface->netdev, 89482dd0f7eSAlexander Duyck "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); 89582dd0f7eSAlexander Duyck 89682dd0f7eSAlexander Duyck interface->flags = flags; 89782dd0f7eSAlexander Duyck 89882dd0f7eSAlexander Duyck /* Perform hash on these packet types */ 89982dd0f7eSAlexander Duyck mrqc = FM10K_MRQC_IPV4 | 90082dd0f7eSAlexander Duyck FM10K_MRQC_TCP_IPV4 | 90182dd0f7eSAlexander Duyck FM10K_MRQC_IPV6 | 90282dd0f7eSAlexander Duyck FM10K_MRQC_TCP_IPV6; 90382dd0f7eSAlexander Duyck 90482dd0f7eSAlexander Duyck if (flags & FM10K_FLAG_RSS_FIELD_IPV4_UDP) 90582dd0f7eSAlexander Duyck mrqc |= FM10K_MRQC_UDP_IPV4; 90682dd0f7eSAlexander Duyck if (flags & FM10K_FLAG_RSS_FIELD_IPV6_UDP) 90782dd0f7eSAlexander Duyck mrqc |= FM10K_MRQC_UDP_IPV6; 90882dd0f7eSAlexander Duyck 90982dd0f7eSAlexander Duyck fm10k_write_reg(hw, FM10K_MRQC(0), mrqc); 91082dd0f7eSAlexander Duyck } 91182dd0f7eSAlexander Duyck 91282dd0f7eSAlexander Duyck return 0; 91382dd0f7eSAlexander Duyck } 91482dd0f7eSAlexander Duyck 91582dd0f7eSAlexander Duyck static int fm10k_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 91682dd0f7eSAlexander Duyck { 91782dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 91882dd0f7eSAlexander Duyck int ret = -EOPNOTSUPP; 91982dd0f7eSAlexander Duyck 92082dd0f7eSAlexander Duyck switch (cmd->cmd) { 92182dd0f7eSAlexander Duyck case ETHTOOL_SRXFH: 92282dd0f7eSAlexander Duyck ret = fm10k_set_rss_hash_opt(interface, cmd); 92382dd0f7eSAlexander Duyck break; 92482dd0f7eSAlexander Duyck default: 92582dd0f7eSAlexander Duyck break; 92682dd0f7eSAlexander Duyck } 92782dd0f7eSAlexander Duyck 92882dd0f7eSAlexander Duyck return ret; 92982dd0f7eSAlexander Duyck } 93082dd0f7eSAlexander Duyck 9315cb8db4aSAlexander Duyck static int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data) 9325cb8db4aSAlexander Duyck { 9335cb8db4aSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 9345cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx; 9355cb8db4aSAlexander Duyck u32 attr_flag, test_msg[6]; 9365cb8db4aSAlexander Duyck unsigned long timeout; 9375cb8db4aSAlexander Duyck int err; 9385cb8db4aSAlexander Duyck 9395cb8db4aSAlexander Duyck /* For now this is a VF only feature */ 9405cb8db4aSAlexander Duyck if (hw->mac.type != fm10k_mac_vf) 9415cb8db4aSAlexander Duyck return 0; 9425cb8db4aSAlexander Duyck 9435cb8db4aSAlexander Duyck /* loop through both nested and unnested attribute types */ 9445cb8db4aSAlexander Duyck for (attr_flag = (1 << FM10K_TEST_MSG_UNSET); 9455cb8db4aSAlexander Duyck attr_flag < (1 << (2 * FM10K_TEST_MSG_NESTED)); 9465cb8db4aSAlexander Duyck attr_flag += attr_flag) { 9475cb8db4aSAlexander Duyck /* generate message to be tested */ 9485cb8db4aSAlexander Duyck fm10k_tlv_msg_test_create(test_msg, attr_flag); 9495cb8db4aSAlexander Duyck 9505cb8db4aSAlexander Duyck fm10k_mbx_lock(interface); 9515cb8db4aSAlexander Duyck mbx->test_result = FM10K_NOT_IMPLEMENTED; 9525cb8db4aSAlexander Duyck err = mbx->ops.enqueue_tx(hw, mbx, test_msg); 9535cb8db4aSAlexander Duyck fm10k_mbx_unlock(interface); 9545cb8db4aSAlexander Duyck 9555cb8db4aSAlexander Duyck /* wait up to 1 second for response */ 9565cb8db4aSAlexander Duyck timeout = jiffies + HZ; 9575cb8db4aSAlexander Duyck do { 9585cb8db4aSAlexander Duyck if (err < 0) 9595cb8db4aSAlexander Duyck goto err_out; 9605cb8db4aSAlexander Duyck 9615cb8db4aSAlexander Duyck usleep_range(500, 1000); 9625cb8db4aSAlexander Duyck 9635cb8db4aSAlexander Duyck fm10k_mbx_lock(interface); 9645cb8db4aSAlexander Duyck mbx->ops.process(hw, mbx); 9655cb8db4aSAlexander Duyck fm10k_mbx_unlock(interface); 9665cb8db4aSAlexander Duyck 9675cb8db4aSAlexander Duyck err = mbx->test_result; 9685cb8db4aSAlexander Duyck if (!err) 9695cb8db4aSAlexander Duyck break; 9705cb8db4aSAlexander Duyck } while (time_is_after_jiffies(timeout)); 9715cb8db4aSAlexander Duyck 9725cb8db4aSAlexander Duyck /* reporting errors */ 9735cb8db4aSAlexander Duyck if (err) 9745cb8db4aSAlexander Duyck goto err_out; 9755cb8db4aSAlexander Duyck } 9765cb8db4aSAlexander Duyck 9775cb8db4aSAlexander Duyck err_out: 9785cb8db4aSAlexander Duyck *data = err < 0 ? (attr_flag) : (err > 0); 9795cb8db4aSAlexander Duyck return err; 9805cb8db4aSAlexander Duyck } 9815cb8db4aSAlexander Duyck 9825cb8db4aSAlexander Duyck static void fm10k_self_test(struct net_device *dev, 9835cb8db4aSAlexander Duyck struct ethtool_test *eth_test, u64 *data) 9845cb8db4aSAlexander Duyck { 9855cb8db4aSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 9865cb8db4aSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 9875cb8db4aSAlexander Duyck 9885cb8db4aSAlexander Duyck memset(data, 0, sizeof(*data) * FM10K_TEST_LEN); 9895cb8db4aSAlexander Duyck 9905cb8db4aSAlexander Duyck if (FM10K_REMOVED(hw)) { 9915cb8db4aSAlexander Duyck netif_err(interface, drv, dev, 9925cb8db4aSAlexander Duyck "Interface removed - test blocked\n"); 9935cb8db4aSAlexander Duyck eth_test->flags |= ETH_TEST_FL_FAILED; 9945cb8db4aSAlexander Duyck return; 9955cb8db4aSAlexander Duyck } 9965cb8db4aSAlexander Duyck 9975cb8db4aSAlexander Duyck if (fm10k_mbx_test(interface, &data[FM10K_TEST_MBX])) 9985cb8db4aSAlexander Duyck eth_test->flags |= ETH_TEST_FL_FAILED; 9995cb8db4aSAlexander Duyck } 10005cb8db4aSAlexander Duyck 100180043f3bSJacob Keller static u32 fm10k_get_priv_flags(struct net_device *netdev) 100280043f3bSJacob Keller { 100380043f3bSJacob Keller struct fm10k_intfc *interface = netdev_priv(netdev); 100480043f3bSJacob Keller u32 priv_flags = 0; 100580043f3bSJacob Keller 100680043f3bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) 100780043f3bSJacob Keller priv_flags |= 1 << FM10K_PRV_FLAG_DEBUG_STATS; 100880043f3bSJacob Keller 100980043f3bSJacob Keller return priv_flags; 101080043f3bSJacob Keller } 101180043f3bSJacob Keller 101280043f3bSJacob Keller static int fm10k_set_priv_flags(struct net_device *netdev, u32 priv_flags) 101380043f3bSJacob Keller { 101480043f3bSJacob Keller struct fm10k_intfc *interface = netdev_priv(netdev); 101580043f3bSJacob Keller 101680043f3bSJacob Keller if (priv_flags >= (1 << FM10K_PRV_FLAG_LEN)) 101780043f3bSJacob Keller return -EINVAL; 101880043f3bSJacob Keller 101980043f3bSJacob Keller if (priv_flags & (1 << FM10K_PRV_FLAG_DEBUG_STATS)) 102080043f3bSJacob Keller interface->flags |= FM10K_FLAG_DEBUG_STATS; 102180043f3bSJacob Keller else 102280043f3bSJacob Keller interface->flags &= ~FM10K_FLAG_DEBUG_STATS; 102380043f3bSJacob Keller 102480043f3bSJacob Keller return 0; 102580043f3bSJacob Keller } 102680043f3bSJacob Keller 102780043f3bSJacob Keller 1028de445199SJeff Kirsher static u32 fm10k_get_reta_size(struct net_device __always_unused *netdev) 102982dd0f7eSAlexander Duyck { 103082dd0f7eSAlexander Duyck return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG; 103182dd0f7eSAlexander Duyck } 103282dd0f7eSAlexander Duyck 103382dd0f7eSAlexander Duyck static int fm10k_get_reta(struct net_device *netdev, u32 *indir) 103482dd0f7eSAlexander Duyck { 103582dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 103682dd0f7eSAlexander Duyck int i; 103782dd0f7eSAlexander Duyck 103882dd0f7eSAlexander Duyck if (!indir) 103982dd0f7eSAlexander Duyck return 0; 104082dd0f7eSAlexander Duyck 104182dd0f7eSAlexander Duyck for (i = 0; i < FM10K_RETA_SIZE; i++, indir += 4) { 104282dd0f7eSAlexander Duyck u32 reta = interface->reta[i]; 104382dd0f7eSAlexander Duyck 104482dd0f7eSAlexander Duyck indir[0] = (reta << 24) >> 24; 104582dd0f7eSAlexander Duyck indir[1] = (reta << 16) >> 24; 104682dd0f7eSAlexander Duyck indir[2] = (reta << 8) >> 24; 104782dd0f7eSAlexander Duyck indir[3] = (reta) >> 24; 104882dd0f7eSAlexander Duyck } 104982dd0f7eSAlexander Duyck 105082dd0f7eSAlexander Duyck return 0; 105182dd0f7eSAlexander Duyck } 105282dd0f7eSAlexander Duyck 105382dd0f7eSAlexander Duyck static int fm10k_set_reta(struct net_device *netdev, const u32 *indir) 105482dd0f7eSAlexander Duyck { 105582dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 105682dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 105782dd0f7eSAlexander Duyck int i; 105882dd0f7eSAlexander Duyck u16 rss_i; 105982dd0f7eSAlexander Duyck 106082dd0f7eSAlexander Duyck if (!indir) 106182dd0f7eSAlexander Duyck return 0; 106282dd0f7eSAlexander Duyck 106382dd0f7eSAlexander Duyck /* Verify user input. */ 106482dd0f7eSAlexander Duyck rss_i = interface->ring_feature[RING_F_RSS].indices; 106582dd0f7eSAlexander Duyck for (i = fm10k_get_reta_size(netdev); i--;) { 106682dd0f7eSAlexander Duyck if (indir[i] < rss_i) 106782dd0f7eSAlexander Duyck continue; 106882dd0f7eSAlexander Duyck return -EINVAL; 106982dd0f7eSAlexander Duyck } 107082dd0f7eSAlexander Duyck 107182dd0f7eSAlexander Duyck /* record entries to reta table */ 107282dd0f7eSAlexander Duyck for (i = 0; i < FM10K_RETA_SIZE; i++, indir += 4) { 107382dd0f7eSAlexander Duyck u32 reta = indir[0] | 107482dd0f7eSAlexander Duyck (indir[1] << 8) | 107582dd0f7eSAlexander Duyck (indir[2] << 16) | 107682dd0f7eSAlexander Duyck (indir[3] << 24); 107782dd0f7eSAlexander Duyck 107882dd0f7eSAlexander Duyck if (interface->reta[i] == reta) 107982dd0f7eSAlexander Duyck continue; 108082dd0f7eSAlexander Duyck 108182dd0f7eSAlexander Duyck interface->reta[i] = reta; 108282dd0f7eSAlexander Duyck fm10k_write_reg(hw, FM10K_RETA(0, i), reta); 108382dd0f7eSAlexander Duyck } 108482dd0f7eSAlexander Duyck 108582dd0f7eSAlexander Duyck return 0; 108682dd0f7eSAlexander Duyck } 108782dd0f7eSAlexander Duyck 1088de445199SJeff Kirsher static u32 fm10k_get_rssrk_size(struct net_device __always_unused *netdev) 108982dd0f7eSAlexander Duyck { 109082dd0f7eSAlexander Duyck return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG; 109182dd0f7eSAlexander Duyck } 109282dd0f7eSAlexander Duyck 1093892311f6SEyal Perry static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key, 1094892311f6SEyal Perry u8 *hfunc) 109582dd0f7eSAlexander Duyck { 109682dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 109782dd0f7eSAlexander Duyck int i, err; 109882dd0f7eSAlexander Duyck 1099892311f6SEyal Perry if (hfunc) 1100892311f6SEyal Perry *hfunc = ETH_RSS_HASH_TOP; 1101892311f6SEyal Perry 110282dd0f7eSAlexander Duyck err = fm10k_get_reta(netdev, indir); 110382dd0f7eSAlexander Duyck if (err || !key) 110482dd0f7eSAlexander Duyck return err; 110582dd0f7eSAlexander Duyck 110682dd0f7eSAlexander Duyck for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) 110782dd0f7eSAlexander Duyck *(__le32 *)key = cpu_to_le32(interface->rssrk[i]); 110882dd0f7eSAlexander Duyck 110982dd0f7eSAlexander Duyck return 0; 111082dd0f7eSAlexander Duyck } 111182dd0f7eSAlexander Duyck 111282dd0f7eSAlexander Duyck static int fm10k_set_rssh(struct net_device *netdev, const u32 *indir, 1113892311f6SEyal Perry const u8 *key, const u8 hfunc) 111482dd0f7eSAlexander Duyck { 111582dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 111682dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 111782dd0f7eSAlexander Duyck int i, err; 111882dd0f7eSAlexander Duyck 1119892311f6SEyal Perry /* We do not allow change in unsupported parameters */ 1120892311f6SEyal Perry if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 1121892311f6SEyal Perry return -EOPNOTSUPP; 1122892311f6SEyal Perry 112382dd0f7eSAlexander Duyck err = fm10k_set_reta(netdev, indir); 112482dd0f7eSAlexander Duyck if (err || !key) 112582dd0f7eSAlexander Duyck return err; 112682dd0f7eSAlexander Duyck 112782dd0f7eSAlexander Duyck for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) { 112882dd0f7eSAlexander Duyck u32 rssrk = le32_to_cpu(*(__le32 *)key); 112982dd0f7eSAlexander Duyck 113082dd0f7eSAlexander Duyck if (interface->rssrk[i] == rssrk) 113182dd0f7eSAlexander Duyck continue; 113282dd0f7eSAlexander Duyck 113382dd0f7eSAlexander Duyck interface->rssrk[i] = rssrk; 113482dd0f7eSAlexander Duyck fm10k_write_reg(hw, FM10K_RSSRK(0, i), rssrk); 113582dd0f7eSAlexander Duyck } 113682dd0f7eSAlexander Duyck 113782dd0f7eSAlexander Duyck return 0; 113882dd0f7eSAlexander Duyck } 113982dd0f7eSAlexander Duyck 1140aa3ac822SAlexander Duyck static unsigned int fm10k_max_channels(struct net_device *dev) 1141aa3ac822SAlexander Duyck { 1142aa3ac822SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1143aa3ac822SAlexander Duyck unsigned int max_combined = interface->hw.mac.max_queues; 1144aa3ac822SAlexander Duyck u8 tcs = netdev_get_num_tc(dev); 1145aa3ac822SAlexander Duyck 1146aa3ac822SAlexander Duyck /* For QoS report channels per traffic class */ 1147aa3ac822SAlexander Duyck if (tcs > 1) 1148aa3ac822SAlexander Duyck max_combined = 1 << (fls(max_combined / tcs) - 1); 1149aa3ac822SAlexander Duyck 1150aa3ac822SAlexander Duyck return max_combined; 1151aa3ac822SAlexander Duyck } 1152aa3ac822SAlexander Duyck 1153aa3ac822SAlexander Duyck static void fm10k_get_channels(struct net_device *dev, 1154aa3ac822SAlexander Duyck struct ethtool_channels *ch) 1155aa3ac822SAlexander Duyck { 1156aa3ac822SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1157aa3ac822SAlexander Duyck struct fm10k_hw *hw = &interface->hw; 1158aa3ac822SAlexander Duyck 1159aa3ac822SAlexander Duyck /* report maximum channels */ 1160aa3ac822SAlexander Duyck ch->max_combined = fm10k_max_channels(dev); 1161aa3ac822SAlexander Duyck 1162aa3ac822SAlexander Duyck /* report info for other vector */ 1163aa3ac822SAlexander Duyck ch->max_other = NON_Q_VECTORS(hw); 1164aa3ac822SAlexander Duyck ch->other_count = ch->max_other; 1165aa3ac822SAlexander Duyck 1166aa3ac822SAlexander Duyck /* record RSS queues */ 1167aa3ac822SAlexander Duyck ch->combined_count = interface->ring_feature[RING_F_RSS].indices; 1168aa3ac822SAlexander Duyck } 1169aa3ac822SAlexander Duyck 1170aa3ac822SAlexander Duyck static int fm10k_set_channels(struct net_device *dev, 1171aa3ac822SAlexander Duyck struct ethtool_channels *ch) 1172aa3ac822SAlexander Duyck { 1173aa3ac822SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1174aa3ac822SAlexander Duyck unsigned int count = ch->combined_count; 1175aa3ac822SAlexander Duyck struct fm10k_hw *hw = &interface->hw; 1176aa3ac822SAlexander Duyck 1177aa3ac822SAlexander Duyck /* verify they are not requesting separate vectors */ 1178aa3ac822SAlexander Duyck if (!count || ch->rx_count || ch->tx_count) 1179aa3ac822SAlexander Duyck return -EINVAL; 1180aa3ac822SAlexander Duyck 1181aa3ac822SAlexander Duyck /* verify other_count has not changed */ 1182aa3ac822SAlexander Duyck if (ch->other_count != NON_Q_VECTORS(hw)) 1183aa3ac822SAlexander Duyck return -EINVAL; 1184aa3ac822SAlexander Duyck 1185aa3ac822SAlexander Duyck /* verify the number of channels does not exceed hardware limits */ 1186aa3ac822SAlexander Duyck if (count > fm10k_max_channels(dev)) 1187aa3ac822SAlexander Duyck return -EINVAL; 1188aa3ac822SAlexander Duyck 1189aa3ac822SAlexander Duyck interface->ring_feature[RING_F_RSS].limit = count; 1190aa3ac822SAlexander Duyck 1191aa3ac822SAlexander Duyck /* use setup TC to update any traffic class queue mapping */ 1192aa3ac822SAlexander Duyck return fm10k_setup_tc(dev, netdev_get_num_tc(dev)); 1193aa3ac822SAlexander Duyck } 1194aa3ac822SAlexander Duyck 1195a211e013SAlexander Duyck static int fm10k_get_ts_info(struct net_device *dev, 1196a211e013SAlexander Duyck struct ethtool_ts_info *info) 1197a211e013SAlexander Duyck { 1198a211e013SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1199a211e013SAlexander Duyck 1200a211e013SAlexander Duyck info->so_timestamping = 1201a211e013SAlexander Duyck SOF_TIMESTAMPING_TX_SOFTWARE | 1202a211e013SAlexander Duyck SOF_TIMESTAMPING_RX_SOFTWARE | 1203a211e013SAlexander Duyck SOF_TIMESTAMPING_SOFTWARE | 1204a211e013SAlexander Duyck SOF_TIMESTAMPING_TX_HARDWARE | 1205a211e013SAlexander Duyck SOF_TIMESTAMPING_RX_HARDWARE | 1206a211e013SAlexander Duyck SOF_TIMESTAMPING_RAW_HARDWARE; 1207a211e013SAlexander Duyck 1208a211e013SAlexander Duyck if (interface->ptp_clock) 1209a211e013SAlexander Duyck info->phc_index = ptp_clock_index(interface->ptp_clock); 1210a211e013SAlexander Duyck else 1211a211e013SAlexander Duyck info->phc_index = -1; 1212a211e013SAlexander Duyck 1213a211e013SAlexander Duyck info->tx_types = (1 << HWTSTAMP_TX_OFF) | 1214a211e013SAlexander Duyck (1 << HWTSTAMP_TX_ON); 1215a211e013SAlexander Duyck 1216a211e013SAlexander Duyck info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 1217a211e013SAlexander Duyck (1 << HWTSTAMP_FILTER_ALL); 1218a211e013SAlexander Duyck 1219a211e013SAlexander Duyck return 0; 1220a211e013SAlexander Duyck } 1221a211e013SAlexander Duyck 122282dd0f7eSAlexander Duyck static const struct ethtool_ops fm10k_ethtool_ops = { 122382dd0f7eSAlexander Duyck .get_strings = fm10k_get_strings, 122482dd0f7eSAlexander Duyck .get_sset_count = fm10k_get_sset_count, 122582dd0f7eSAlexander Duyck .get_ethtool_stats = fm10k_get_ethtool_stats, 122682dd0f7eSAlexander Duyck .get_drvinfo = fm10k_get_drvinfo, 122782dd0f7eSAlexander Duyck .get_link = ethtool_op_get_link, 122882dd0f7eSAlexander Duyck .get_pauseparam = fm10k_get_pauseparam, 122982dd0f7eSAlexander Duyck .set_pauseparam = fm10k_set_pauseparam, 123082dd0f7eSAlexander Duyck .get_msglevel = fm10k_get_msglevel, 123182dd0f7eSAlexander Duyck .set_msglevel = fm10k_set_msglevel, 123282dd0f7eSAlexander Duyck .get_ringparam = fm10k_get_ringparam, 123382dd0f7eSAlexander Duyck .set_ringparam = fm10k_set_ringparam, 123482dd0f7eSAlexander Duyck .get_coalesce = fm10k_get_coalesce, 123582dd0f7eSAlexander Duyck .set_coalesce = fm10k_set_coalesce, 123682dd0f7eSAlexander Duyck .get_rxnfc = fm10k_get_rxnfc, 123782dd0f7eSAlexander Duyck .set_rxnfc = fm10k_set_rxnfc, 123882dd0f7eSAlexander Duyck .get_regs = fm10k_get_regs, 123982dd0f7eSAlexander Duyck .get_regs_len = fm10k_get_regs_len, 12405cb8db4aSAlexander Duyck .self_test = fm10k_self_test, 124180043f3bSJacob Keller .get_priv_flags = fm10k_get_priv_flags, 124280043f3bSJacob Keller .set_priv_flags = fm10k_set_priv_flags, 124382dd0f7eSAlexander Duyck .get_rxfh_indir_size = fm10k_get_reta_size, 124482dd0f7eSAlexander Duyck .get_rxfh_key_size = fm10k_get_rssrk_size, 124582dd0f7eSAlexander Duyck .get_rxfh = fm10k_get_rssh, 124682dd0f7eSAlexander Duyck .set_rxfh = fm10k_set_rssh, 1247aa3ac822SAlexander Duyck .get_channels = fm10k_get_channels, 1248aa3ac822SAlexander Duyck .set_channels = fm10k_set_channels, 1249a211e013SAlexander Duyck .get_ts_info = fm10k_get_ts_info, 125082dd0f7eSAlexander Duyck }; 125182dd0f7eSAlexander Duyck 125282dd0f7eSAlexander Duyck void fm10k_set_ethtool_ops(struct net_device *dev) 125382dd0f7eSAlexander Duyck { 125482dd0f7eSAlexander Duyck dev->ethtool_ops = &fm10k_ethtool_ops; 125582dd0f7eSAlexander Duyck } 1256