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), 1145680ea69SJacob Keller FM10K_MBX_STAT("mbx_tx_dropped", tx_dropped), 11580043f3bSJacob Keller FM10K_MBX_STAT("mbx_tx_messages", tx_messages), 11680043f3bSJacob Keller FM10K_MBX_STAT("mbx_tx_dwords", tx_dwords), 11717d39facSJacob Keller FM10K_MBX_STAT("mbx_tx_mbmem_pulled", tx_mbmem_pulled), 11880043f3bSJacob Keller FM10K_MBX_STAT("mbx_rx_messages", rx_messages), 11980043f3bSJacob Keller FM10K_MBX_STAT("mbx_rx_dwords", rx_dwords), 12080043f3bSJacob Keller FM10K_MBX_STAT("mbx_rx_parse_err", rx_parse_err), 12117d39facSJacob Keller FM10K_MBX_STAT("mbx_rx_mbmem_pushed", rx_mbmem_pushed), 12280043f3bSJacob Keller }; 12380043f3bSJacob Keller 124fbdb159fSJeff Kirsher #define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats) 12580043f3bSJacob Keller #define FM10K_DEBUG_STATS_LEN ARRAY_SIZE(fm10k_gstrings_debug_stats) 126fbdb159fSJeff Kirsher #define FM10K_PF_STATS_LEN ARRAY_SIZE(fm10k_gstrings_pf_stats) 12780043f3bSJacob Keller #define FM10K_MBX_STATS_LEN ARRAY_SIZE(fm10k_gstrings_mbx_stats) 12882dd0f7eSAlexander Duyck 129c0e61781SJeff Kirsher #define FM10K_QUEUE_STATS_LEN(_n) \ 130c0e61781SJeff Kirsher ((_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64))) 13182dd0f7eSAlexander Duyck 132c0e61781SJeff Kirsher #define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \ 13380043f3bSJacob Keller FM10K_NETDEV_STATS_LEN + \ 13480043f3bSJacob Keller FM10K_MBX_STATS_LEN) 13582dd0f7eSAlexander Duyck 1365cb8db4aSAlexander Duyck static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = { 1375cb8db4aSAlexander Duyck "Mailbox test (on/offline)" 1385cb8db4aSAlexander Duyck }; 1395cb8db4aSAlexander Duyck 1405cb8db4aSAlexander Duyck #define FM10K_TEST_LEN (sizeof(fm10k_gstrings_test) / ETH_GSTRING_LEN) 1415cb8db4aSAlexander Duyck 1425cb8db4aSAlexander Duyck enum fm10k_self_test_types { 1435cb8db4aSAlexander Duyck FM10K_TEST_MBX, 1445cb8db4aSAlexander Duyck FM10K_TEST_MAX = FM10K_TEST_LEN 1455cb8db4aSAlexander Duyck }; 1465cb8db4aSAlexander Duyck 14780043f3bSJacob Keller enum { 14880043f3bSJacob Keller FM10K_PRV_FLAG_DEBUG_STATS, 14980043f3bSJacob Keller FM10K_PRV_FLAG_LEN, 15080043f3bSJacob Keller }; 15180043f3bSJacob Keller 15280043f3bSJacob Keller static const char fm10k_prv_flags[FM10K_PRV_FLAG_LEN][ETH_GSTRING_LEN] = { 15380043f3bSJacob Keller "debug-statistics", 15480043f3bSJacob Keller }; 15580043f3bSJacob Keller 156d2e0721bSJacob Keller static void fm10k_add_stat_strings(char **p, const char *prefix, 157d2e0721bSJacob Keller const struct fm10k_stats stats[], 158d2e0721bSJacob Keller const unsigned int size) 159d2e0721bSJacob Keller { 160d2e0721bSJacob Keller unsigned int i; 161d2e0721bSJacob Keller 162d2e0721bSJacob Keller for (i = 0; i < size; i++) { 163d2e0721bSJacob Keller snprintf(*p, ETH_GSTRING_LEN, "%s%s", 164d2e0721bSJacob Keller prefix, stats[i].stat_string); 165d2e0721bSJacob Keller *p += ETH_GSTRING_LEN; 166d2e0721bSJacob Keller } 167d2e0721bSJacob Keller } 168d2e0721bSJacob Keller 16980043f3bSJacob Keller static void fm10k_get_stat_strings(struct net_device *dev, u8 *data) 17082dd0f7eSAlexander Duyck { 17129a928eeSJeff Kirsher struct fm10k_intfc *interface = netdev_priv(dev); 17280043f3bSJacob Keller struct fm10k_iov_data *iov_data = interface->iov_data; 17382dd0f7eSAlexander Duyck char *p = (char *)data; 174c0e58e93SJacob Keller unsigned int i; 17582dd0f7eSAlexander Duyck 176d2e0721bSJacob Keller fm10k_add_stat_strings(&p, "", fm10k_gstrings_net_stats, 177d2e0721bSJacob Keller FM10K_NETDEV_STATS_LEN); 17880043f3bSJacob Keller 179d2e0721bSJacob Keller fm10k_add_stat_strings(&p, "", fm10k_gstrings_global_stats, 180d2e0721bSJacob Keller FM10K_GLOBAL_STATS_LEN); 181fbdb159fSJeff Kirsher 182d2e0721bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) 183d2e0721bSJacob Keller fm10k_add_stat_strings(&p, "", fm10k_gstrings_debug_stats, 184d2e0721bSJacob Keller FM10K_DEBUG_STATS_LEN); 18580043f3bSJacob Keller 186d2e0721bSJacob Keller fm10k_add_stat_strings(&p, "", fm10k_gstrings_mbx_stats, 187d2e0721bSJacob Keller FM10K_MBX_STATS_LEN); 18880043f3bSJacob Keller 189d2e0721bSJacob Keller if (interface->hw.mac.type != fm10k_mac_vf) 190d2e0721bSJacob Keller fm10k_add_stat_strings(&p, "", fm10k_gstrings_pf_stats, 191d2e0721bSJacob Keller FM10K_PF_STATS_LEN); 19282dd0f7eSAlexander Duyck 19380043f3bSJacob Keller if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) { 19480043f3bSJacob Keller for (i = 0; i < iov_data->num_vfs; i++) { 195d2e0721bSJacob Keller char prefix[ETH_GSTRING_LEN]; 196d2e0721bSJacob Keller 197d2e0721bSJacob Keller snprintf(prefix, ETH_GSTRING_LEN, "vf_%u_", i); 198d2e0721bSJacob Keller fm10k_add_stat_strings(&p, prefix, 199d2e0721bSJacob Keller fm10k_gstrings_mbx_stats, 200d2e0721bSJacob Keller FM10K_MBX_STATS_LEN); 20180043f3bSJacob Keller } 20280043f3bSJacob Keller } 20380043f3bSJacob Keller 20429a928eeSJeff Kirsher for (i = 0; i < interface->hw.mac.max_queues; i++) { 205f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_packets", i); 20682dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 207f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_bytes", i); 20882dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 209f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_packets", i); 21082dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 211f6f19f8bSJacob Keller snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_bytes", i); 21282dd0f7eSAlexander Duyck p += ETH_GSTRING_LEN; 21382dd0f7eSAlexander Duyck } 21480043f3bSJacob Keller } 21580043f3bSJacob Keller 21680043f3bSJacob Keller static void fm10k_get_strings(struct net_device *dev, 21780043f3bSJacob Keller u32 stringset, u8 *data) 21880043f3bSJacob Keller { 21980043f3bSJacob Keller char *p = (char *)data; 22080043f3bSJacob Keller 22180043f3bSJacob Keller switch (stringset) { 22280043f3bSJacob Keller case ETH_SS_TEST: 22380043f3bSJacob Keller memcpy(data, *fm10k_gstrings_test, 22480043f3bSJacob Keller FM10K_TEST_LEN * ETH_GSTRING_LEN); 22580043f3bSJacob Keller break; 22680043f3bSJacob Keller case ETH_SS_STATS: 22780043f3bSJacob Keller fm10k_get_stat_strings(dev, data); 22880043f3bSJacob Keller break; 22980043f3bSJacob Keller case ETH_SS_PRIV_FLAGS: 23080043f3bSJacob Keller memcpy(p, fm10k_prv_flags, 23180043f3bSJacob Keller FM10K_PRV_FLAG_LEN * ETH_GSTRING_LEN); 23282dd0f7eSAlexander Duyck break; 23382dd0f7eSAlexander Duyck } 23482dd0f7eSAlexander Duyck } 23582dd0f7eSAlexander Duyck 23682dd0f7eSAlexander Duyck static int fm10k_get_sset_count(struct net_device *dev, int sset) 23782dd0f7eSAlexander Duyck { 238c0e61781SJeff Kirsher struct fm10k_intfc *interface = netdev_priv(dev); 23980043f3bSJacob Keller struct fm10k_iov_data *iov_data = interface->iov_data; 240c0e61781SJeff Kirsher struct fm10k_hw *hw = &interface->hw; 241c0e61781SJeff Kirsher int stats_len = FM10K_STATIC_STATS_LEN; 242c0e61781SJeff Kirsher 24382dd0f7eSAlexander Duyck switch (sset) { 2445cb8db4aSAlexander Duyck case ETH_SS_TEST: 2455cb8db4aSAlexander Duyck return FM10K_TEST_LEN; 24682dd0f7eSAlexander Duyck case ETH_SS_STATS: 247c0e61781SJeff Kirsher stats_len += FM10K_QUEUE_STATS_LEN(hw->mac.max_queues); 248fbdb159fSJeff Kirsher 249fbdb159fSJeff Kirsher if (hw->mac.type != fm10k_mac_vf) 250fbdb159fSJeff Kirsher stats_len += FM10K_PF_STATS_LEN; 251fbdb159fSJeff Kirsher 25280043f3bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) { 25380043f3bSJacob Keller stats_len += FM10K_DEBUG_STATS_LEN; 25480043f3bSJacob Keller 25580043f3bSJacob Keller if (iov_data) 2563d02b3dfSBruce Allan stats_len += FM10K_MBX_STATS_LEN * 2573d02b3dfSBruce Allan iov_data->num_vfs; 25880043f3bSJacob Keller } 25980043f3bSJacob Keller 260c0e61781SJeff Kirsher return stats_len; 26180043f3bSJacob Keller case ETH_SS_PRIV_FLAGS: 26280043f3bSJacob Keller return FM10K_PRV_FLAG_LEN; 26382dd0f7eSAlexander Duyck default: 26482dd0f7eSAlexander Duyck return -EOPNOTSUPP; 26582dd0f7eSAlexander Duyck } 26682dd0f7eSAlexander Duyck } 26782dd0f7eSAlexander Duyck 268d2e0721bSJacob Keller static void fm10k_add_ethtool_stats(u64 **data, void *pointer, 269d2e0721bSJacob Keller const struct fm10k_stats stats[], 270d2e0721bSJacob Keller const unsigned int size) 271d2e0721bSJacob Keller { 272d2e0721bSJacob Keller unsigned int i; 273d2e0721bSJacob Keller char *p; 274d2e0721bSJacob Keller 275d2e0721bSJacob Keller /* simply skip forward if we were not given a valid pointer */ 276d2e0721bSJacob Keller if (!pointer) { 277d2e0721bSJacob Keller *data += size; 278d2e0721bSJacob Keller return; 279d2e0721bSJacob Keller } 280d2e0721bSJacob Keller 281d2e0721bSJacob Keller for (i = 0; i < size; i++) { 282d2e0721bSJacob Keller p = (char *)pointer + stats[i].stat_offset; 283d2e0721bSJacob Keller 284d2e0721bSJacob Keller switch (stats[i].sizeof_stat) { 285d2e0721bSJacob Keller case sizeof(u64): 286d2e0721bSJacob Keller *((*data)++) = *(u64 *)p; 287d2e0721bSJacob Keller break; 288d2e0721bSJacob Keller case sizeof(u32): 289d2e0721bSJacob Keller *((*data)++) = *(u32 *)p; 290d2e0721bSJacob Keller break; 291d2e0721bSJacob Keller case sizeof(u16): 292d2e0721bSJacob Keller *((*data)++) = *(u16 *)p; 293d2e0721bSJacob Keller break; 294d2e0721bSJacob Keller case sizeof(u8): 295d2e0721bSJacob Keller *((*data)++) = *(u8 *)p; 296d2e0721bSJacob Keller break; 297d2e0721bSJacob Keller default: 298d2e0721bSJacob Keller *((*data)++) = 0; 299d2e0721bSJacob Keller } 300d2e0721bSJacob Keller } 301d2e0721bSJacob Keller } 302d2e0721bSJacob Keller 30382dd0f7eSAlexander Duyck static void fm10k_get_ethtool_stats(struct net_device *netdev, 304de445199SJeff Kirsher struct ethtool_stats __always_unused *stats, 305de445199SJeff Kirsher u64 *data) 30682dd0f7eSAlexander Duyck { 30782dd0f7eSAlexander Duyck const int stat_count = sizeof(struct fm10k_queue_stats) / sizeof(u64); 30882dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 30980043f3bSJacob Keller struct fm10k_iov_data *iov_data = interface->iov_data; 31082dd0f7eSAlexander Duyck struct net_device_stats *net_stats = &netdev->stats; 31182dd0f7eSAlexander Duyck int i, j; 31282dd0f7eSAlexander Duyck 31382dd0f7eSAlexander Duyck fm10k_update_stats(interface); 31482dd0f7eSAlexander Duyck 315d2e0721bSJacob Keller fm10k_add_ethtool_stats(&data, net_stats, fm10k_gstrings_net_stats, 316d2e0721bSJacob Keller FM10K_NETDEV_STATS_LEN); 31782dd0f7eSAlexander Duyck 318d2e0721bSJacob Keller fm10k_add_ethtool_stats(&data, interface, fm10k_gstrings_global_stats, 319d2e0721bSJacob Keller FM10K_GLOBAL_STATS_LEN); 320fbdb159fSJeff Kirsher 321d2e0721bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) 322d2e0721bSJacob Keller fm10k_add_ethtool_stats(&data, interface, 323d2e0721bSJacob Keller fm10k_gstrings_debug_stats, 324d2e0721bSJacob Keller FM10K_DEBUG_STATS_LEN); 32580043f3bSJacob Keller 326d2e0721bSJacob Keller fm10k_add_ethtool_stats(&data, &interface->hw.mbx, 327d2e0721bSJacob Keller fm10k_gstrings_mbx_stats, 328d2e0721bSJacob Keller FM10K_MBX_STATS_LEN); 32980043f3bSJacob Keller 33080043f3bSJacob Keller if (interface->hw.mac.type != fm10k_mac_vf) { 331d2e0721bSJacob Keller fm10k_add_ethtool_stats(&data, interface, 332d2e0721bSJacob Keller fm10k_gstrings_pf_stats, 333d2e0721bSJacob Keller FM10K_PF_STATS_LEN); 33480043f3bSJacob Keller } 33580043f3bSJacob Keller 33680043f3bSJacob Keller if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) { 33780043f3bSJacob Keller for (i = 0; i < iov_data->num_vfs; i++) { 33880043f3bSJacob Keller struct fm10k_vf_info *vf_info; 339a4fcad65SBruce Allan 34080043f3bSJacob Keller vf_info = &iov_data->vf_info[i]; 34180043f3bSJacob Keller 342d2e0721bSJacob Keller fm10k_add_ethtool_stats(&data, &vf_info->mbx, 343d2e0721bSJacob Keller fm10k_gstrings_mbx_stats, 344d2e0721bSJacob Keller FM10K_MBX_STATS_LEN); 34580043f3bSJacob Keller } 34680043f3bSJacob Keller } 34782dd0f7eSAlexander Duyck 34829a928eeSJeff Kirsher for (i = 0; i < interface->hw.mac.max_queues; i++) { 34982dd0f7eSAlexander Duyck struct fm10k_ring *ring; 35082dd0f7eSAlexander Duyck u64 *queue_stat; 35182dd0f7eSAlexander Duyck 35282dd0f7eSAlexander Duyck ring = interface->tx_ring[i]; 35382dd0f7eSAlexander Duyck if (ring) 35482dd0f7eSAlexander Duyck queue_stat = (u64 *)&ring->stats; 35582dd0f7eSAlexander Duyck for (j = 0; j < stat_count; j++) 35682dd0f7eSAlexander Duyck *(data++) = ring ? queue_stat[j] : 0; 35782dd0f7eSAlexander Duyck 35882dd0f7eSAlexander Duyck ring = interface->rx_ring[i]; 35982dd0f7eSAlexander Duyck if (ring) 36082dd0f7eSAlexander Duyck queue_stat = (u64 *)&ring->stats; 36182dd0f7eSAlexander Duyck for (j = 0; j < stat_count; j++) 36282dd0f7eSAlexander Duyck *(data++) = ring ? queue_stat[j] : 0; 36382dd0f7eSAlexander Duyck } 36482dd0f7eSAlexander Duyck } 36582dd0f7eSAlexander Duyck 36682dd0f7eSAlexander Duyck /* If function below adds more registers this define needs to be updated */ 36782dd0f7eSAlexander Duyck #define FM10K_REGS_LEN_Q 29 36882dd0f7eSAlexander Duyck 36982dd0f7eSAlexander Duyck static void fm10k_get_reg_q(struct fm10k_hw *hw, u32 *buff, int i) 37082dd0f7eSAlexander Duyck { 37182dd0f7eSAlexander Duyck int idx = 0; 37282dd0f7eSAlexander Duyck 37382dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAL(i)); 37482dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAH(i)); 37582dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDLEN(i)); 37682dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_RXCTRL(i)); 37782dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDH(i)); 37882dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RDT(i)); 37982dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RXQCTL(i)); 38082dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RXDCTL(i)); 38182dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RXINT(i)); 38282dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_SRRCTL(i)); 38382dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QPRC(i)); 38482dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QPRDC(i)); 38582dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_L(i)); 38682dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_H(i)); 38782dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAL(i)); 38882dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAH(i)); 38982dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDLEN(i)); 39082dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_TXCTRL(i)); 39182dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDH(i)); 39282dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TDT(i)); 39382dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TXDCTL(i)); 39482dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TXQCTL(i)); 39582dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TXINT(i)); 39682dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QPTC(i)); 39782dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_L(i)); 39882dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_H(i)); 39982dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TQDLOC(i)); 40082dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_TX_SGLORT(i)); 40182dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_PFVTCTL(i)); 40282dd0f7eSAlexander Duyck 40382dd0f7eSAlexander Duyck BUG_ON(idx != FM10K_REGS_LEN_Q); 40482dd0f7eSAlexander Duyck } 40582dd0f7eSAlexander Duyck 40682dd0f7eSAlexander Duyck /* If function above adds more registers this define needs to be updated */ 40782dd0f7eSAlexander Duyck #define FM10K_REGS_LEN_VSI 43 40882dd0f7eSAlexander Duyck 40982dd0f7eSAlexander Duyck static void fm10k_get_reg_vsi(struct fm10k_hw *hw, u32 *buff, int i) 41082dd0f7eSAlexander Duyck { 41182dd0f7eSAlexander Duyck int idx = 0, j; 41282dd0f7eSAlexander Duyck 41382dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_MRQC(i)); 41482dd0f7eSAlexander Duyck for (j = 0; j < 10; j++) 41582dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RSSRK(i, j)); 41682dd0f7eSAlexander Duyck for (j = 0; j < 32; j++) 41782dd0f7eSAlexander Duyck buff[idx++] = fm10k_read_reg(hw, FM10K_RETA(i, j)); 41882dd0f7eSAlexander Duyck 41982dd0f7eSAlexander Duyck BUG_ON(idx != FM10K_REGS_LEN_VSI); 42082dd0f7eSAlexander Duyck } 42182dd0f7eSAlexander Duyck 42282dd0f7eSAlexander Duyck static void fm10k_get_regs(struct net_device *netdev, 42382dd0f7eSAlexander Duyck struct ethtool_regs *regs, void *p) 42482dd0f7eSAlexander Duyck { 42582dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 42682dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 42782dd0f7eSAlexander Duyck u32 *buff = p; 42882dd0f7eSAlexander Duyck u16 i; 42982dd0f7eSAlexander Duyck 430fcdb0a99SBruce Allan regs->version = BIT(24) | (hw->revision_id << 16) | hw->device_id; 43182dd0f7eSAlexander Duyck 43282dd0f7eSAlexander Duyck switch (hw->mac.type) { 43382dd0f7eSAlexander Duyck case fm10k_mac_pf: 43482dd0f7eSAlexander Duyck /* General PF Registers */ 43582dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_CTRL); 43682dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_CTRL_EXT); 43782dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_GCR); 43882dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_GCR_EXT); 43982dd0f7eSAlexander Duyck 44082dd0f7eSAlexander Duyck for (i = 0; i < 8; i++) { 44182dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTMAP(i)); 44282dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTDEC(i)); 44382dd0f7eSAlexander Duyck } 44482dd0f7eSAlexander Duyck 44582dd0f7eSAlexander Duyck for (i = 0; i < 65; i++) { 44682dd0f7eSAlexander Duyck fm10k_get_reg_vsi(hw, buff, i); 44782dd0f7eSAlexander Duyck buff += FM10K_REGS_LEN_VSI; 44882dd0f7eSAlexander Duyck } 44982dd0f7eSAlexander Duyck 45082dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL); 45182dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL2); 45282dd0f7eSAlexander Duyck 45382dd0f7eSAlexander Duyck for (i = 0; i < FM10K_MAX_QUEUES_PF; i++) { 45482dd0f7eSAlexander Duyck fm10k_get_reg_q(hw, buff, i); 45582dd0f7eSAlexander Duyck buff += FM10K_REGS_LEN_Q; 45682dd0f7eSAlexander Duyck } 45782dd0f7eSAlexander Duyck 45882dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_TPH_CTRL); 45982dd0f7eSAlexander Duyck 46082dd0f7eSAlexander Duyck for (i = 0; i < 8; i++) 46182dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_INT_MAP(i)); 46282dd0f7eSAlexander Duyck 46382dd0f7eSAlexander Duyck /* Interrupt Throttling Registers */ 46482dd0f7eSAlexander Duyck for (i = 0; i < 130; i++) 46582dd0f7eSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_ITR(i)); 46682dd0f7eSAlexander Duyck 46782dd0f7eSAlexander Duyck break; 4685cb8db4aSAlexander Duyck case fm10k_mac_vf: 4695cb8db4aSAlexander Duyck /* General VF registers */ 4705cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFCTRL); 4715cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFINT_MAP); 4725cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFSYSTIME); 4735cb8db4aSAlexander Duyck 4745cb8db4aSAlexander Duyck /* Interrupt Throttling Registers */ 4755cb8db4aSAlexander Duyck for (i = 0; i < 8; i++) 4765cb8db4aSAlexander Duyck *(buff++) = fm10k_read_reg(hw, FM10K_VFITR(i)); 4775cb8db4aSAlexander Duyck 4785cb8db4aSAlexander Duyck fm10k_get_reg_vsi(hw, buff, 0); 4795cb8db4aSAlexander Duyck buff += FM10K_REGS_LEN_VSI; 4805cb8db4aSAlexander Duyck 4815cb8db4aSAlexander Duyck for (i = 0; i < FM10K_MAX_QUEUES_POOL; i++) { 4825cb8db4aSAlexander Duyck if (i < hw->mac.max_queues) 4835cb8db4aSAlexander Duyck fm10k_get_reg_q(hw, buff, i); 4845cb8db4aSAlexander Duyck else 4855cb8db4aSAlexander Duyck memset(buff, 0, sizeof(u32) * FM10K_REGS_LEN_Q); 4865cb8db4aSAlexander Duyck buff += FM10K_REGS_LEN_Q; 4875cb8db4aSAlexander Duyck } 4885cb8db4aSAlexander Duyck 4895cb8db4aSAlexander Duyck break; 49082dd0f7eSAlexander Duyck default: 49182dd0f7eSAlexander Duyck return; 49282dd0f7eSAlexander Duyck } 49382dd0f7eSAlexander Duyck } 49482dd0f7eSAlexander Duyck 49582dd0f7eSAlexander Duyck /* If function above adds more registers these define need to be updated */ 49682dd0f7eSAlexander Duyck #define FM10K_REGS_LEN_PF \ 49782dd0f7eSAlexander Duyck (162 + (65 * FM10K_REGS_LEN_VSI) + (FM10K_MAX_QUEUES_PF * FM10K_REGS_LEN_Q)) 4985cb8db4aSAlexander Duyck #define FM10K_REGS_LEN_VF \ 4995cb8db4aSAlexander Duyck (11 + FM10K_REGS_LEN_VSI + (FM10K_MAX_QUEUES_POOL * FM10K_REGS_LEN_Q)) 50082dd0f7eSAlexander Duyck 50182dd0f7eSAlexander Duyck static int fm10k_get_regs_len(struct net_device *netdev) 50282dd0f7eSAlexander Duyck { 50382dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 50482dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 50582dd0f7eSAlexander Duyck 50682dd0f7eSAlexander Duyck switch (hw->mac.type) { 50782dd0f7eSAlexander Duyck case fm10k_mac_pf: 50882dd0f7eSAlexander Duyck return FM10K_REGS_LEN_PF * sizeof(u32); 5095cb8db4aSAlexander Duyck case fm10k_mac_vf: 5105cb8db4aSAlexander Duyck return FM10K_REGS_LEN_VF * sizeof(u32); 51182dd0f7eSAlexander Duyck default: 51282dd0f7eSAlexander Duyck return 0; 51382dd0f7eSAlexander Duyck } 51482dd0f7eSAlexander Duyck } 51582dd0f7eSAlexander Duyck 51682dd0f7eSAlexander Duyck static void fm10k_get_drvinfo(struct net_device *dev, 51782dd0f7eSAlexander Duyck struct ethtool_drvinfo *info) 51882dd0f7eSAlexander Duyck { 51982dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 52082dd0f7eSAlexander Duyck 52182dd0f7eSAlexander Duyck strncpy(info->driver, fm10k_driver_name, 52282dd0f7eSAlexander Duyck sizeof(info->driver) - 1); 52382dd0f7eSAlexander Duyck strncpy(info->version, fm10k_driver_version, 52482dd0f7eSAlexander Duyck sizeof(info->version) - 1); 52582dd0f7eSAlexander Duyck strncpy(info->bus_info, pci_name(interface->pdev), 52682dd0f7eSAlexander Duyck sizeof(info->bus_info) - 1); 52782dd0f7eSAlexander Duyck } 52882dd0f7eSAlexander Duyck 52982dd0f7eSAlexander Duyck static void fm10k_get_pauseparam(struct net_device *dev, 53082dd0f7eSAlexander Duyck struct ethtool_pauseparam *pause) 53182dd0f7eSAlexander Duyck { 53282dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 53382dd0f7eSAlexander Duyck 53482dd0f7eSAlexander Duyck /* record fixed values for autoneg and tx pause */ 53582dd0f7eSAlexander Duyck pause->autoneg = 0; 53682dd0f7eSAlexander Duyck pause->tx_pause = 1; 53782dd0f7eSAlexander Duyck 53882dd0f7eSAlexander Duyck pause->rx_pause = interface->rx_pause ? 1 : 0; 53982dd0f7eSAlexander Duyck } 54082dd0f7eSAlexander Duyck 54182dd0f7eSAlexander Duyck static int fm10k_set_pauseparam(struct net_device *dev, 54282dd0f7eSAlexander Duyck struct ethtool_pauseparam *pause) 54382dd0f7eSAlexander Duyck { 54482dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 54582dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 54682dd0f7eSAlexander Duyck 54782dd0f7eSAlexander Duyck if (pause->autoneg || !pause->tx_pause) 54882dd0f7eSAlexander Duyck return -EINVAL; 54982dd0f7eSAlexander Duyck 55082dd0f7eSAlexander Duyck /* we can only support pause on the PF to avoid head-of-line blocking */ 55182dd0f7eSAlexander Duyck if (hw->mac.type == fm10k_mac_pf) 55282dd0f7eSAlexander Duyck interface->rx_pause = pause->rx_pause ? ~0 : 0; 55382dd0f7eSAlexander Duyck else if (pause->rx_pause) 55482dd0f7eSAlexander Duyck return -EINVAL; 55582dd0f7eSAlexander Duyck 55682dd0f7eSAlexander Duyck if (netif_running(dev)) 55782dd0f7eSAlexander Duyck fm10k_update_rx_drop_en(interface); 55882dd0f7eSAlexander Duyck 55982dd0f7eSAlexander Duyck return 0; 56082dd0f7eSAlexander Duyck } 56182dd0f7eSAlexander Duyck 56282dd0f7eSAlexander Duyck static u32 fm10k_get_msglevel(struct net_device *netdev) 56382dd0f7eSAlexander Duyck { 56482dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 56582dd0f7eSAlexander Duyck 56682dd0f7eSAlexander Duyck return interface->msg_enable; 56782dd0f7eSAlexander Duyck } 56882dd0f7eSAlexander Duyck 56982dd0f7eSAlexander Duyck static void fm10k_set_msglevel(struct net_device *netdev, u32 data) 57082dd0f7eSAlexander Duyck { 57182dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 57282dd0f7eSAlexander Duyck 57382dd0f7eSAlexander Duyck interface->msg_enable = data; 57482dd0f7eSAlexander Duyck } 57582dd0f7eSAlexander Duyck 57682dd0f7eSAlexander Duyck static void fm10k_get_ringparam(struct net_device *netdev, 57782dd0f7eSAlexander Duyck struct ethtool_ringparam *ring) 57882dd0f7eSAlexander Duyck { 57982dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 58082dd0f7eSAlexander Duyck 58182dd0f7eSAlexander Duyck ring->rx_max_pending = FM10K_MAX_RXD; 58282dd0f7eSAlexander Duyck ring->tx_max_pending = FM10K_MAX_TXD; 58382dd0f7eSAlexander Duyck ring->rx_mini_max_pending = 0; 58482dd0f7eSAlexander Duyck ring->rx_jumbo_max_pending = 0; 58582dd0f7eSAlexander Duyck ring->rx_pending = interface->rx_ring_count; 58682dd0f7eSAlexander Duyck ring->tx_pending = interface->tx_ring_count; 58782dd0f7eSAlexander Duyck ring->rx_mini_pending = 0; 58882dd0f7eSAlexander Duyck ring->rx_jumbo_pending = 0; 58982dd0f7eSAlexander Duyck } 59082dd0f7eSAlexander Duyck 59182dd0f7eSAlexander Duyck static int fm10k_set_ringparam(struct net_device *netdev, 59282dd0f7eSAlexander Duyck struct ethtool_ringparam *ring) 59382dd0f7eSAlexander Duyck { 59482dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 59582dd0f7eSAlexander Duyck struct fm10k_ring *temp_ring; 59682dd0f7eSAlexander Duyck int i, err = 0; 59782dd0f7eSAlexander Duyck u32 new_rx_count, new_tx_count; 59882dd0f7eSAlexander Duyck 59982dd0f7eSAlexander Duyck if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 60082dd0f7eSAlexander Duyck return -EINVAL; 60182dd0f7eSAlexander Duyck 60282dd0f7eSAlexander Duyck new_tx_count = clamp_t(u32, ring->tx_pending, 60382dd0f7eSAlexander Duyck FM10K_MIN_TXD, FM10K_MAX_TXD); 60482dd0f7eSAlexander Duyck new_tx_count = ALIGN(new_tx_count, FM10K_REQ_TX_DESCRIPTOR_MULTIPLE); 60582dd0f7eSAlexander Duyck 60682dd0f7eSAlexander Duyck new_rx_count = clamp_t(u32, ring->rx_pending, 60782dd0f7eSAlexander Duyck FM10K_MIN_RXD, FM10K_MAX_RXD); 60882dd0f7eSAlexander Duyck new_rx_count = ALIGN(new_rx_count, FM10K_REQ_RX_DESCRIPTOR_MULTIPLE); 60982dd0f7eSAlexander Duyck 61082dd0f7eSAlexander Duyck if ((new_tx_count == interface->tx_ring_count) && 61182dd0f7eSAlexander Duyck (new_rx_count == interface->rx_ring_count)) { 61282dd0f7eSAlexander Duyck /* nothing to do */ 61382dd0f7eSAlexander Duyck return 0; 61482dd0f7eSAlexander Duyck } 61582dd0f7eSAlexander Duyck 61682dd0f7eSAlexander Duyck while (test_and_set_bit(__FM10K_RESETTING, &interface->state)) 61782dd0f7eSAlexander Duyck usleep_range(1000, 2000); 61882dd0f7eSAlexander Duyck 61982dd0f7eSAlexander Duyck if (!netif_running(interface->netdev)) { 62082dd0f7eSAlexander Duyck for (i = 0; i < interface->num_tx_queues; i++) 62182dd0f7eSAlexander Duyck interface->tx_ring[i]->count = new_tx_count; 62282dd0f7eSAlexander Duyck for (i = 0; i < interface->num_rx_queues; i++) 62382dd0f7eSAlexander Duyck interface->rx_ring[i]->count = new_rx_count; 62482dd0f7eSAlexander Duyck interface->tx_ring_count = new_tx_count; 62582dd0f7eSAlexander Duyck interface->rx_ring_count = new_rx_count; 62682dd0f7eSAlexander Duyck goto clear_reset; 62782dd0f7eSAlexander Duyck } 62882dd0f7eSAlexander Duyck 62982dd0f7eSAlexander Duyck /* allocate temporary buffer to store rings in */ 63082dd0f7eSAlexander Duyck i = max_t(int, interface->num_tx_queues, interface->num_rx_queues); 63182dd0f7eSAlexander Duyck temp_ring = vmalloc(i * sizeof(struct fm10k_ring)); 63282dd0f7eSAlexander Duyck 63382dd0f7eSAlexander Duyck if (!temp_ring) { 63482dd0f7eSAlexander Duyck err = -ENOMEM; 63582dd0f7eSAlexander Duyck goto clear_reset; 63682dd0f7eSAlexander Duyck } 63782dd0f7eSAlexander Duyck 63882dd0f7eSAlexander Duyck fm10k_down(interface); 63982dd0f7eSAlexander Duyck 64082dd0f7eSAlexander Duyck /* Setup new Tx resources and free the old Tx resources in that order. 64182dd0f7eSAlexander Duyck * We can then assign the new resources to the rings via a memcpy. 64282dd0f7eSAlexander Duyck * The advantage to this approach is that we are guaranteed to still 64382dd0f7eSAlexander Duyck * have resources even in the case of an allocation failure. 64482dd0f7eSAlexander Duyck */ 64582dd0f7eSAlexander Duyck if (new_tx_count != interface->tx_ring_count) { 64682dd0f7eSAlexander Duyck for (i = 0; i < interface->num_tx_queues; i++) { 64782dd0f7eSAlexander Duyck memcpy(&temp_ring[i], interface->tx_ring[i], 64882dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 64982dd0f7eSAlexander Duyck 65082dd0f7eSAlexander Duyck temp_ring[i].count = new_tx_count; 65182dd0f7eSAlexander Duyck err = fm10k_setup_tx_resources(&temp_ring[i]); 65282dd0f7eSAlexander Duyck if (err) { 65382dd0f7eSAlexander Duyck while (i) { 65482dd0f7eSAlexander Duyck i--; 65582dd0f7eSAlexander Duyck fm10k_free_tx_resources(&temp_ring[i]); 65682dd0f7eSAlexander Duyck } 65782dd0f7eSAlexander Duyck goto err_setup; 65882dd0f7eSAlexander Duyck } 65982dd0f7eSAlexander Duyck } 66082dd0f7eSAlexander Duyck 66182dd0f7eSAlexander Duyck for (i = 0; i < interface->num_tx_queues; i++) { 66282dd0f7eSAlexander Duyck fm10k_free_tx_resources(interface->tx_ring[i]); 66382dd0f7eSAlexander Duyck 66482dd0f7eSAlexander Duyck memcpy(interface->tx_ring[i], &temp_ring[i], 66582dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 66682dd0f7eSAlexander Duyck } 66782dd0f7eSAlexander Duyck 66882dd0f7eSAlexander Duyck interface->tx_ring_count = new_tx_count; 66982dd0f7eSAlexander Duyck } 67082dd0f7eSAlexander Duyck 67182dd0f7eSAlexander Duyck /* Repeat the process for the Rx rings if needed */ 67282dd0f7eSAlexander Duyck if (new_rx_count != interface->rx_ring_count) { 67382dd0f7eSAlexander Duyck for (i = 0; i < interface->num_rx_queues; i++) { 67482dd0f7eSAlexander Duyck memcpy(&temp_ring[i], interface->rx_ring[i], 67582dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 67682dd0f7eSAlexander Duyck 67782dd0f7eSAlexander Duyck temp_ring[i].count = new_rx_count; 67882dd0f7eSAlexander Duyck err = fm10k_setup_rx_resources(&temp_ring[i]); 67982dd0f7eSAlexander Duyck if (err) { 68082dd0f7eSAlexander Duyck while (i) { 68182dd0f7eSAlexander Duyck i--; 68282dd0f7eSAlexander Duyck fm10k_free_rx_resources(&temp_ring[i]); 68382dd0f7eSAlexander Duyck } 68482dd0f7eSAlexander Duyck goto err_setup; 68582dd0f7eSAlexander Duyck } 68682dd0f7eSAlexander Duyck } 68782dd0f7eSAlexander Duyck 68882dd0f7eSAlexander Duyck for (i = 0; i < interface->num_rx_queues; i++) { 68982dd0f7eSAlexander Duyck fm10k_free_rx_resources(interface->rx_ring[i]); 69082dd0f7eSAlexander Duyck 69182dd0f7eSAlexander Duyck memcpy(interface->rx_ring[i], &temp_ring[i], 69282dd0f7eSAlexander Duyck sizeof(struct fm10k_ring)); 69382dd0f7eSAlexander Duyck } 69482dd0f7eSAlexander Duyck 69582dd0f7eSAlexander Duyck interface->rx_ring_count = new_rx_count; 69682dd0f7eSAlexander Duyck } 69782dd0f7eSAlexander Duyck 69882dd0f7eSAlexander Duyck err_setup: 69982dd0f7eSAlexander Duyck fm10k_up(interface); 70082dd0f7eSAlexander Duyck vfree(temp_ring); 70182dd0f7eSAlexander Duyck clear_reset: 70282dd0f7eSAlexander Duyck clear_bit(__FM10K_RESETTING, &interface->state); 70382dd0f7eSAlexander Duyck return err; 70482dd0f7eSAlexander Duyck } 70582dd0f7eSAlexander Duyck 70682dd0f7eSAlexander Duyck static int fm10k_get_coalesce(struct net_device *dev, 70782dd0f7eSAlexander Duyck struct ethtool_coalesce *ec) 70882dd0f7eSAlexander Duyck { 70982dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 71082dd0f7eSAlexander Duyck 711584373f5SJacob Keller ec->use_adaptive_tx_coalesce = ITR_IS_ADAPTIVE(interface->tx_itr); 71282dd0f7eSAlexander Duyck ec->tx_coalesce_usecs = interface->tx_itr & ~FM10K_ITR_ADAPTIVE; 71382dd0f7eSAlexander Duyck 714584373f5SJacob Keller ec->use_adaptive_rx_coalesce = ITR_IS_ADAPTIVE(interface->rx_itr); 71582dd0f7eSAlexander Duyck ec->rx_coalesce_usecs = interface->rx_itr & ~FM10K_ITR_ADAPTIVE; 71682dd0f7eSAlexander Duyck 71782dd0f7eSAlexander Duyck return 0; 71882dd0f7eSAlexander Duyck } 71982dd0f7eSAlexander Duyck 72082dd0f7eSAlexander Duyck static int fm10k_set_coalesce(struct net_device *dev, 72182dd0f7eSAlexander Duyck struct ethtool_coalesce *ec) 72282dd0f7eSAlexander Duyck { 72382dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 72482dd0f7eSAlexander Duyck struct fm10k_q_vector *qv; 72582dd0f7eSAlexander Duyck u16 tx_itr, rx_itr; 72682dd0f7eSAlexander Duyck int i; 72782dd0f7eSAlexander Duyck 72882dd0f7eSAlexander Duyck /* verify limits */ 72982dd0f7eSAlexander Duyck if ((ec->rx_coalesce_usecs > FM10K_ITR_MAX) || 73082dd0f7eSAlexander Duyck (ec->tx_coalesce_usecs > FM10K_ITR_MAX)) 73182dd0f7eSAlexander Duyck return -EINVAL; 73282dd0f7eSAlexander Duyck 73382dd0f7eSAlexander Duyck /* record settings */ 73482dd0f7eSAlexander Duyck tx_itr = ec->tx_coalesce_usecs; 73582dd0f7eSAlexander Duyck rx_itr = ec->rx_coalesce_usecs; 73682dd0f7eSAlexander Duyck 73782dd0f7eSAlexander Duyck /* set initial values for adaptive ITR */ 73882dd0f7eSAlexander Duyck if (ec->use_adaptive_tx_coalesce) 739436ea956SJacob Keller tx_itr = FM10K_ITR_ADAPTIVE | FM10K_TX_ITR_DEFAULT; 74082dd0f7eSAlexander Duyck 74182dd0f7eSAlexander Duyck if (ec->use_adaptive_rx_coalesce) 742436ea956SJacob Keller rx_itr = FM10K_ITR_ADAPTIVE | FM10K_RX_ITR_DEFAULT; 74382dd0f7eSAlexander Duyck 74482dd0f7eSAlexander Duyck /* update interface */ 74582dd0f7eSAlexander Duyck interface->tx_itr = tx_itr; 74682dd0f7eSAlexander Duyck interface->rx_itr = rx_itr; 74782dd0f7eSAlexander Duyck 74882dd0f7eSAlexander Duyck /* update q_vectors */ 74982dd0f7eSAlexander Duyck for (i = 0; i < interface->num_q_vectors; i++) { 75082dd0f7eSAlexander Duyck qv = interface->q_vector[i]; 75182dd0f7eSAlexander Duyck qv->tx.itr = tx_itr; 75282dd0f7eSAlexander Duyck qv->rx.itr = rx_itr; 75382dd0f7eSAlexander Duyck } 75482dd0f7eSAlexander Duyck 75582dd0f7eSAlexander Duyck return 0; 75682dd0f7eSAlexander Duyck } 75782dd0f7eSAlexander Duyck 75882dd0f7eSAlexander Duyck static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface, 75982dd0f7eSAlexander Duyck struct ethtool_rxnfc *cmd) 76082dd0f7eSAlexander Duyck { 76182dd0f7eSAlexander Duyck cmd->data = 0; 76282dd0f7eSAlexander Duyck 76382dd0f7eSAlexander Duyck /* Report default options for RSS on fm10k */ 76482dd0f7eSAlexander Duyck switch (cmd->flow_type) { 76582dd0f7eSAlexander Duyck case TCP_V4_FLOW: 76682dd0f7eSAlexander Duyck case TCP_V6_FLOW: 76782dd0f7eSAlexander Duyck cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 76882dd0f7eSAlexander Duyck /* fall through */ 76982dd0f7eSAlexander Duyck case UDP_V4_FLOW: 77082dd0f7eSAlexander Duyck if (interface->flags & FM10K_FLAG_RSS_FIELD_IPV4_UDP) 77182dd0f7eSAlexander Duyck cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 77282dd0f7eSAlexander Duyck /* fall through */ 77382dd0f7eSAlexander Duyck case SCTP_V4_FLOW: 77482dd0f7eSAlexander Duyck case SCTP_V6_FLOW: 77582dd0f7eSAlexander Duyck case AH_ESP_V4_FLOW: 77682dd0f7eSAlexander Duyck case AH_ESP_V6_FLOW: 77782dd0f7eSAlexander Duyck case AH_V4_FLOW: 77882dd0f7eSAlexander Duyck case AH_V6_FLOW: 77982dd0f7eSAlexander Duyck case ESP_V4_FLOW: 78082dd0f7eSAlexander Duyck case ESP_V6_FLOW: 78182dd0f7eSAlexander Duyck case IPV4_FLOW: 78282dd0f7eSAlexander Duyck case IPV6_FLOW: 78382dd0f7eSAlexander Duyck cmd->data |= RXH_IP_SRC | RXH_IP_DST; 78482dd0f7eSAlexander Duyck break; 78582dd0f7eSAlexander Duyck case UDP_V6_FLOW: 78682dd0f7eSAlexander Duyck if (interface->flags & FM10K_FLAG_RSS_FIELD_IPV6_UDP) 78782dd0f7eSAlexander Duyck cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 78882dd0f7eSAlexander Duyck cmd->data |= RXH_IP_SRC | RXH_IP_DST; 78982dd0f7eSAlexander Duyck break; 79082dd0f7eSAlexander Duyck default: 79182dd0f7eSAlexander Duyck return -EINVAL; 79282dd0f7eSAlexander Duyck } 79382dd0f7eSAlexander Duyck 79482dd0f7eSAlexander Duyck return 0; 79582dd0f7eSAlexander Duyck } 79682dd0f7eSAlexander Duyck 79782dd0f7eSAlexander Duyck static int fm10k_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 798de445199SJeff Kirsher u32 __always_unused *rule_locs) 79982dd0f7eSAlexander Duyck { 80082dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 80182dd0f7eSAlexander Duyck int ret = -EOPNOTSUPP; 80282dd0f7eSAlexander Duyck 80382dd0f7eSAlexander Duyck switch (cmd->cmd) { 80482dd0f7eSAlexander Duyck case ETHTOOL_GRXRINGS: 80582dd0f7eSAlexander Duyck cmd->data = interface->num_rx_queues; 80682dd0f7eSAlexander Duyck ret = 0; 80782dd0f7eSAlexander Duyck break; 80882dd0f7eSAlexander Duyck case ETHTOOL_GRXFH: 80982dd0f7eSAlexander Duyck ret = fm10k_get_rss_hash_opts(interface, cmd); 81082dd0f7eSAlexander Duyck break; 81182dd0f7eSAlexander Duyck default: 81282dd0f7eSAlexander Duyck break; 81382dd0f7eSAlexander Duyck } 81482dd0f7eSAlexander Duyck 81582dd0f7eSAlexander Duyck return ret; 81682dd0f7eSAlexander Duyck } 81782dd0f7eSAlexander Duyck 81882dd0f7eSAlexander Duyck #define UDP_RSS_FLAGS (FM10K_FLAG_RSS_FIELD_IPV4_UDP | \ 81982dd0f7eSAlexander Duyck FM10K_FLAG_RSS_FIELD_IPV6_UDP) 82082dd0f7eSAlexander Duyck static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface, 82182dd0f7eSAlexander Duyck struct ethtool_rxnfc *nfc) 82282dd0f7eSAlexander Duyck { 82382dd0f7eSAlexander Duyck u32 flags = interface->flags; 82482dd0f7eSAlexander Duyck 82582dd0f7eSAlexander Duyck /* RSS does not support anything other than hashing 82682dd0f7eSAlexander Duyck * to queues on src and dst IPs and ports 82782dd0f7eSAlexander Duyck */ 82882dd0f7eSAlexander Duyck if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | 82982dd0f7eSAlexander Duyck RXH_L4_B_0_1 | RXH_L4_B_2_3)) 83082dd0f7eSAlexander Duyck return -EINVAL; 83182dd0f7eSAlexander Duyck 83282dd0f7eSAlexander Duyck switch (nfc->flow_type) { 83382dd0f7eSAlexander Duyck case TCP_V4_FLOW: 83482dd0f7eSAlexander Duyck case TCP_V6_FLOW: 83582dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 83682dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST) || 83782dd0f7eSAlexander Duyck !(nfc->data & RXH_L4_B_0_1) || 83882dd0f7eSAlexander Duyck !(nfc->data & RXH_L4_B_2_3)) 83982dd0f7eSAlexander Duyck return -EINVAL; 84082dd0f7eSAlexander Duyck break; 84182dd0f7eSAlexander Duyck case UDP_V4_FLOW: 84282dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 84382dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST)) 84482dd0f7eSAlexander Duyck return -EINVAL; 84582dd0f7eSAlexander Duyck switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 84682dd0f7eSAlexander Duyck case 0: 84782dd0f7eSAlexander Duyck flags &= ~FM10K_FLAG_RSS_FIELD_IPV4_UDP; 84882dd0f7eSAlexander Duyck break; 84982dd0f7eSAlexander Duyck case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 85082dd0f7eSAlexander Duyck flags |= FM10K_FLAG_RSS_FIELD_IPV4_UDP; 85182dd0f7eSAlexander Duyck break; 85282dd0f7eSAlexander Duyck default: 85382dd0f7eSAlexander Duyck return -EINVAL; 85482dd0f7eSAlexander Duyck } 85582dd0f7eSAlexander Duyck break; 85682dd0f7eSAlexander Duyck case UDP_V6_FLOW: 85782dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 85882dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST)) 85982dd0f7eSAlexander Duyck return -EINVAL; 86082dd0f7eSAlexander Duyck switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 86182dd0f7eSAlexander Duyck case 0: 86282dd0f7eSAlexander Duyck flags &= ~FM10K_FLAG_RSS_FIELD_IPV6_UDP; 86382dd0f7eSAlexander Duyck break; 86482dd0f7eSAlexander Duyck case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 86582dd0f7eSAlexander Duyck flags |= FM10K_FLAG_RSS_FIELD_IPV6_UDP; 86682dd0f7eSAlexander Duyck break; 86782dd0f7eSAlexander Duyck default: 86882dd0f7eSAlexander Duyck return -EINVAL; 86982dd0f7eSAlexander Duyck } 87082dd0f7eSAlexander Duyck break; 87182dd0f7eSAlexander Duyck case AH_ESP_V4_FLOW: 87282dd0f7eSAlexander Duyck case AH_V4_FLOW: 87382dd0f7eSAlexander Duyck case ESP_V4_FLOW: 87482dd0f7eSAlexander Duyck case SCTP_V4_FLOW: 87582dd0f7eSAlexander Duyck case AH_ESP_V6_FLOW: 87682dd0f7eSAlexander Duyck case AH_V6_FLOW: 87782dd0f7eSAlexander Duyck case ESP_V6_FLOW: 87882dd0f7eSAlexander Duyck case SCTP_V6_FLOW: 87982dd0f7eSAlexander Duyck if (!(nfc->data & RXH_IP_SRC) || 88082dd0f7eSAlexander Duyck !(nfc->data & RXH_IP_DST) || 88182dd0f7eSAlexander Duyck (nfc->data & RXH_L4_B_0_1) || 88282dd0f7eSAlexander Duyck (nfc->data & RXH_L4_B_2_3)) 88382dd0f7eSAlexander Duyck return -EINVAL; 88482dd0f7eSAlexander Duyck break; 88582dd0f7eSAlexander Duyck default: 88682dd0f7eSAlexander Duyck return -EINVAL; 88782dd0f7eSAlexander Duyck } 88882dd0f7eSAlexander Duyck 88982dd0f7eSAlexander Duyck /* if we changed something we need to update flags */ 89082dd0f7eSAlexander Duyck if (flags != interface->flags) { 89182dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 89282dd0f7eSAlexander Duyck u32 mrqc; 89382dd0f7eSAlexander Duyck 89482dd0f7eSAlexander Duyck if ((flags & UDP_RSS_FLAGS) && 89582dd0f7eSAlexander Duyck !(interface->flags & UDP_RSS_FLAGS)) 89682dd0f7eSAlexander Duyck netif_warn(interface, drv, interface->netdev, 89782dd0f7eSAlexander Duyck "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); 89882dd0f7eSAlexander Duyck 89982dd0f7eSAlexander Duyck interface->flags = flags; 90082dd0f7eSAlexander Duyck 90182dd0f7eSAlexander Duyck /* Perform hash on these packet types */ 90282dd0f7eSAlexander Duyck mrqc = FM10K_MRQC_IPV4 | 90382dd0f7eSAlexander Duyck FM10K_MRQC_TCP_IPV4 | 90482dd0f7eSAlexander Duyck FM10K_MRQC_IPV6 | 90582dd0f7eSAlexander Duyck FM10K_MRQC_TCP_IPV6; 90682dd0f7eSAlexander Duyck 90782dd0f7eSAlexander Duyck if (flags & FM10K_FLAG_RSS_FIELD_IPV4_UDP) 90882dd0f7eSAlexander Duyck mrqc |= FM10K_MRQC_UDP_IPV4; 90982dd0f7eSAlexander Duyck if (flags & FM10K_FLAG_RSS_FIELD_IPV6_UDP) 91082dd0f7eSAlexander Duyck mrqc |= FM10K_MRQC_UDP_IPV6; 91182dd0f7eSAlexander Duyck 91282dd0f7eSAlexander Duyck fm10k_write_reg(hw, FM10K_MRQC(0), mrqc); 91382dd0f7eSAlexander Duyck } 91482dd0f7eSAlexander Duyck 91582dd0f7eSAlexander Duyck return 0; 91682dd0f7eSAlexander Duyck } 91782dd0f7eSAlexander Duyck 91882dd0f7eSAlexander Duyck static int fm10k_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 91982dd0f7eSAlexander Duyck { 92082dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 92182dd0f7eSAlexander Duyck int ret = -EOPNOTSUPP; 92282dd0f7eSAlexander Duyck 92382dd0f7eSAlexander Duyck switch (cmd->cmd) { 92482dd0f7eSAlexander Duyck case ETHTOOL_SRXFH: 92582dd0f7eSAlexander Duyck ret = fm10k_set_rss_hash_opt(interface, cmd); 92682dd0f7eSAlexander Duyck break; 92782dd0f7eSAlexander Duyck default: 92882dd0f7eSAlexander Duyck break; 92982dd0f7eSAlexander Duyck } 93082dd0f7eSAlexander Duyck 93182dd0f7eSAlexander Duyck return ret; 93282dd0f7eSAlexander Duyck } 93382dd0f7eSAlexander Duyck 9345cb8db4aSAlexander Duyck static int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data) 9355cb8db4aSAlexander Duyck { 9365cb8db4aSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 9375cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx; 9385cb8db4aSAlexander Duyck u32 attr_flag, test_msg[6]; 9395cb8db4aSAlexander Duyck unsigned long timeout; 940c4114e3dSBruce Allan int err = -EINVAL; 9415cb8db4aSAlexander Duyck 9425cb8db4aSAlexander Duyck /* For now this is a VF only feature */ 9435cb8db4aSAlexander Duyck if (hw->mac.type != fm10k_mac_vf) 9445cb8db4aSAlexander Duyck return 0; 9455cb8db4aSAlexander Duyck 9465cb8db4aSAlexander Duyck /* loop through both nested and unnested attribute types */ 947fcdb0a99SBruce Allan for (attr_flag = BIT(FM10K_TEST_MSG_UNSET); 948fcdb0a99SBruce Allan attr_flag < BIT(2 * FM10K_TEST_MSG_NESTED); 9495cb8db4aSAlexander Duyck attr_flag += attr_flag) { 9505cb8db4aSAlexander Duyck /* generate message to be tested */ 9515cb8db4aSAlexander Duyck fm10k_tlv_msg_test_create(test_msg, attr_flag); 9525cb8db4aSAlexander Duyck 9535cb8db4aSAlexander Duyck fm10k_mbx_lock(interface); 9545cb8db4aSAlexander Duyck mbx->test_result = FM10K_NOT_IMPLEMENTED; 9555cb8db4aSAlexander Duyck err = mbx->ops.enqueue_tx(hw, mbx, test_msg); 9565cb8db4aSAlexander Duyck fm10k_mbx_unlock(interface); 9575cb8db4aSAlexander Duyck 9585cb8db4aSAlexander Duyck /* wait up to 1 second for response */ 9595cb8db4aSAlexander Duyck timeout = jiffies + HZ; 9605cb8db4aSAlexander Duyck do { 9615cb8db4aSAlexander Duyck if (err < 0) 9625cb8db4aSAlexander Duyck goto err_out; 9635cb8db4aSAlexander Duyck 9645cb8db4aSAlexander Duyck usleep_range(500, 1000); 9655cb8db4aSAlexander Duyck 9665cb8db4aSAlexander Duyck fm10k_mbx_lock(interface); 9675cb8db4aSAlexander Duyck mbx->ops.process(hw, mbx); 9685cb8db4aSAlexander Duyck fm10k_mbx_unlock(interface); 9695cb8db4aSAlexander Duyck 9705cb8db4aSAlexander Duyck err = mbx->test_result; 9715cb8db4aSAlexander Duyck if (!err) 9725cb8db4aSAlexander Duyck break; 9735cb8db4aSAlexander Duyck } while (time_is_after_jiffies(timeout)); 9745cb8db4aSAlexander Duyck 9755cb8db4aSAlexander Duyck /* reporting errors */ 9765cb8db4aSAlexander Duyck if (err) 9775cb8db4aSAlexander Duyck goto err_out; 9785cb8db4aSAlexander Duyck } 9795cb8db4aSAlexander Duyck 9805cb8db4aSAlexander Duyck err_out: 9815cb8db4aSAlexander Duyck *data = err < 0 ? (attr_flag) : (err > 0); 9825cb8db4aSAlexander Duyck return err; 9835cb8db4aSAlexander Duyck } 9845cb8db4aSAlexander Duyck 9855cb8db4aSAlexander Duyck static void fm10k_self_test(struct net_device *dev, 9865cb8db4aSAlexander Duyck struct ethtool_test *eth_test, u64 *data) 9875cb8db4aSAlexander Duyck { 9885cb8db4aSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 9895cb8db4aSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 9905cb8db4aSAlexander Duyck 9915cb8db4aSAlexander Duyck memset(data, 0, sizeof(*data) * FM10K_TEST_LEN); 9925cb8db4aSAlexander Duyck 9935cb8db4aSAlexander Duyck if (FM10K_REMOVED(hw)) { 9945cb8db4aSAlexander Duyck netif_err(interface, drv, dev, 9955cb8db4aSAlexander Duyck "Interface removed - test blocked\n"); 9965cb8db4aSAlexander Duyck eth_test->flags |= ETH_TEST_FL_FAILED; 9975cb8db4aSAlexander Duyck return; 9985cb8db4aSAlexander Duyck } 9995cb8db4aSAlexander Duyck 10005cb8db4aSAlexander Duyck if (fm10k_mbx_test(interface, &data[FM10K_TEST_MBX])) 10015cb8db4aSAlexander Duyck eth_test->flags |= ETH_TEST_FL_FAILED; 10025cb8db4aSAlexander Duyck } 10035cb8db4aSAlexander Duyck 100480043f3bSJacob Keller static u32 fm10k_get_priv_flags(struct net_device *netdev) 100580043f3bSJacob Keller { 100680043f3bSJacob Keller struct fm10k_intfc *interface = netdev_priv(netdev); 100780043f3bSJacob Keller u32 priv_flags = 0; 100880043f3bSJacob Keller 100980043f3bSJacob Keller if (interface->flags & FM10K_FLAG_DEBUG_STATS) 1010fcdb0a99SBruce Allan priv_flags |= BIT(FM10K_PRV_FLAG_DEBUG_STATS); 101180043f3bSJacob Keller 101280043f3bSJacob Keller return priv_flags; 101380043f3bSJacob Keller } 101480043f3bSJacob Keller 101580043f3bSJacob Keller static int fm10k_set_priv_flags(struct net_device *netdev, u32 priv_flags) 101680043f3bSJacob Keller { 101780043f3bSJacob Keller struct fm10k_intfc *interface = netdev_priv(netdev); 101880043f3bSJacob Keller 1019fcdb0a99SBruce Allan if (priv_flags >= BIT(FM10K_PRV_FLAG_LEN)) 102080043f3bSJacob Keller return -EINVAL; 102180043f3bSJacob Keller 1022fcdb0a99SBruce Allan if (priv_flags & BIT(FM10K_PRV_FLAG_DEBUG_STATS)) 102380043f3bSJacob Keller interface->flags |= FM10K_FLAG_DEBUG_STATS; 102480043f3bSJacob Keller else 102580043f3bSJacob Keller interface->flags &= ~FM10K_FLAG_DEBUG_STATS; 102680043f3bSJacob Keller 102780043f3bSJacob Keller return 0; 102880043f3bSJacob Keller } 102980043f3bSJacob Keller 10300ea7fae4SJacob Keller u32 fm10k_get_reta_size(struct net_device __always_unused *netdev) 103182dd0f7eSAlexander Duyck { 103282dd0f7eSAlexander Duyck return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG; 103382dd0f7eSAlexander Duyck } 103482dd0f7eSAlexander Duyck 10350ea7fae4SJacob Keller void fm10k_write_reta(struct fm10k_intfc *interface, const u32 *indir) 10360ea7fae4SJacob Keller { 10370ea7fae4SJacob Keller struct fm10k_hw *hw = &interface->hw; 10380ea7fae4SJacob Keller int i; 10390ea7fae4SJacob Keller 10400ea7fae4SJacob Keller /* record entries to reta table */ 10410ea7fae4SJacob Keller for (i = 0; i < FM10K_RETA_SIZE; i++, indir += 4) { 10420ea7fae4SJacob Keller u32 reta = indir[0] | 10430ea7fae4SJacob Keller (indir[1] << 8) | 10440ea7fae4SJacob Keller (indir[2] << 16) | 10450ea7fae4SJacob Keller (indir[3] << 24); 10460ea7fae4SJacob Keller 10470ea7fae4SJacob Keller if (interface->reta[i] == reta) 10480ea7fae4SJacob Keller continue; 10490ea7fae4SJacob Keller 10500ea7fae4SJacob Keller interface->reta[i] = reta; 10510ea7fae4SJacob Keller fm10k_write_reg(hw, FM10K_RETA(0, i), reta); 10520ea7fae4SJacob Keller } 10530ea7fae4SJacob Keller } 10540ea7fae4SJacob Keller 105582dd0f7eSAlexander Duyck static int fm10k_get_reta(struct net_device *netdev, u32 *indir) 105682dd0f7eSAlexander Duyck { 105782dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 105882dd0f7eSAlexander Duyck int i; 105982dd0f7eSAlexander Duyck 106082dd0f7eSAlexander Duyck if (!indir) 106182dd0f7eSAlexander Duyck return 0; 106282dd0f7eSAlexander Duyck 106382dd0f7eSAlexander Duyck for (i = 0; i < FM10K_RETA_SIZE; i++, indir += 4) { 106482dd0f7eSAlexander Duyck u32 reta = interface->reta[i]; 106582dd0f7eSAlexander Duyck 106682dd0f7eSAlexander Duyck indir[0] = (reta << 24) >> 24; 106782dd0f7eSAlexander Duyck indir[1] = (reta << 16) >> 24; 106882dd0f7eSAlexander Duyck indir[2] = (reta << 8) >> 24; 106982dd0f7eSAlexander Duyck indir[3] = (reta) >> 24; 107082dd0f7eSAlexander Duyck } 107182dd0f7eSAlexander Duyck 107282dd0f7eSAlexander Duyck return 0; 107382dd0f7eSAlexander Duyck } 107482dd0f7eSAlexander Duyck 107582dd0f7eSAlexander Duyck static int fm10k_set_reta(struct net_device *netdev, const u32 *indir) 107682dd0f7eSAlexander Duyck { 107782dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 107882dd0f7eSAlexander Duyck int i; 107982dd0f7eSAlexander Duyck u16 rss_i; 108082dd0f7eSAlexander Duyck 108182dd0f7eSAlexander Duyck if (!indir) 108282dd0f7eSAlexander Duyck return 0; 108382dd0f7eSAlexander Duyck 108482dd0f7eSAlexander Duyck /* Verify user input. */ 108582dd0f7eSAlexander Duyck rss_i = interface->ring_feature[RING_F_RSS].indices; 108682dd0f7eSAlexander Duyck for (i = fm10k_get_reta_size(netdev); i--;) { 108782dd0f7eSAlexander Duyck if (indir[i] < rss_i) 108882dd0f7eSAlexander Duyck continue; 108982dd0f7eSAlexander Duyck return -EINVAL; 109082dd0f7eSAlexander Duyck } 109182dd0f7eSAlexander Duyck 10920ea7fae4SJacob Keller fm10k_write_reta(interface, indir); 109382dd0f7eSAlexander Duyck 109482dd0f7eSAlexander Duyck return 0; 109582dd0f7eSAlexander Duyck } 109682dd0f7eSAlexander Duyck 1097de445199SJeff Kirsher static u32 fm10k_get_rssrk_size(struct net_device __always_unused *netdev) 109882dd0f7eSAlexander Duyck { 109982dd0f7eSAlexander Duyck return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG; 110082dd0f7eSAlexander Duyck } 110182dd0f7eSAlexander Duyck 1102892311f6SEyal Perry static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key, 1103892311f6SEyal Perry u8 *hfunc) 110482dd0f7eSAlexander Duyck { 110582dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 110682dd0f7eSAlexander Duyck int i, err; 110782dd0f7eSAlexander Duyck 1108892311f6SEyal Perry if (hfunc) 1109892311f6SEyal Perry *hfunc = ETH_RSS_HASH_TOP; 1110892311f6SEyal Perry 111182dd0f7eSAlexander Duyck err = fm10k_get_reta(netdev, indir); 111282dd0f7eSAlexander Duyck if (err || !key) 111382dd0f7eSAlexander Duyck return err; 111482dd0f7eSAlexander Duyck 111582dd0f7eSAlexander Duyck for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) 111682dd0f7eSAlexander Duyck *(__le32 *)key = cpu_to_le32(interface->rssrk[i]); 111782dd0f7eSAlexander Duyck 111882dd0f7eSAlexander Duyck return 0; 111982dd0f7eSAlexander Duyck } 112082dd0f7eSAlexander Duyck 112182dd0f7eSAlexander Duyck static int fm10k_set_rssh(struct net_device *netdev, const u32 *indir, 1122892311f6SEyal Perry const u8 *key, const u8 hfunc) 112382dd0f7eSAlexander Duyck { 112482dd0f7eSAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 112582dd0f7eSAlexander Duyck struct fm10k_hw *hw = &interface->hw; 112682dd0f7eSAlexander Duyck int i, err; 112782dd0f7eSAlexander Duyck 1128892311f6SEyal Perry /* We do not allow change in unsupported parameters */ 1129892311f6SEyal Perry if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 1130892311f6SEyal Perry return -EOPNOTSUPP; 1131892311f6SEyal Perry 113282dd0f7eSAlexander Duyck err = fm10k_set_reta(netdev, indir); 113382dd0f7eSAlexander Duyck if (err || !key) 113482dd0f7eSAlexander Duyck return err; 113582dd0f7eSAlexander Duyck 113682dd0f7eSAlexander Duyck for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) { 113782dd0f7eSAlexander Duyck u32 rssrk = le32_to_cpu(*(__le32 *)key); 113882dd0f7eSAlexander Duyck 113982dd0f7eSAlexander Duyck if (interface->rssrk[i] == rssrk) 114082dd0f7eSAlexander Duyck continue; 114182dd0f7eSAlexander Duyck 114282dd0f7eSAlexander Duyck interface->rssrk[i] = rssrk; 114382dd0f7eSAlexander Duyck fm10k_write_reg(hw, FM10K_RSSRK(0, i), rssrk); 114482dd0f7eSAlexander Duyck } 114582dd0f7eSAlexander Duyck 114682dd0f7eSAlexander Duyck return 0; 114782dd0f7eSAlexander Duyck } 114882dd0f7eSAlexander Duyck 1149aa3ac822SAlexander Duyck static unsigned int fm10k_max_channels(struct net_device *dev) 1150aa3ac822SAlexander Duyck { 1151aa3ac822SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1152aa3ac822SAlexander Duyck unsigned int max_combined = interface->hw.mac.max_queues; 1153aa3ac822SAlexander Duyck u8 tcs = netdev_get_num_tc(dev); 1154aa3ac822SAlexander Duyck 1155aa3ac822SAlexander Duyck /* For QoS report channels per traffic class */ 1156aa3ac822SAlexander Duyck if (tcs > 1) 1157fcdb0a99SBruce Allan max_combined = BIT((fls(max_combined / tcs) - 1)); 1158aa3ac822SAlexander Duyck 1159aa3ac822SAlexander Duyck return max_combined; 1160aa3ac822SAlexander Duyck } 1161aa3ac822SAlexander Duyck 1162aa3ac822SAlexander Duyck static void fm10k_get_channels(struct net_device *dev, 1163aa3ac822SAlexander Duyck struct ethtool_channels *ch) 1164aa3ac822SAlexander Duyck { 1165aa3ac822SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1166aa3ac822SAlexander Duyck struct fm10k_hw *hw = &interface->hw; 1167aa3ac822SAlexander Duyck 1168aa3ac822SAlexander Duyck /* report maximum channels */ 1169aa3ac822SAlexander Duyck ch->max_combined = fm10k_max_channels(dev); 1170aa3ac822SAlexander Duyck 1171aa3ac822SAlexander Duyck /* report info for other vector */ 1172aa3ac822SAlexander Duyck ch->max_other = NON_Q_VECTORS(hw); 1173aa3ac822SAlexander Duyck ch->other_count = ch->max_other; 1174aa3ac822SAlexander Duyck 1175aa3ac822SAlexander Duyck /* record RSS queues */ 1176aa3ac822SAlexander Duyck ch->combined_count = interface->ring_feature[RING_F_RSS].indices; 1177aa3ac822SAlexander Duyck } 1178aa3ac822SAlexander Duyck 1179aa3ac822SAlexander Duyck static int fm10k_set_channels(struct net_device *dev, 1180aa3ac822SAlexander Duyck struct ethtool_channels *ch) 1181aa3ac822SAlexander Duyck { 1182aa3ac822SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1183aa3ac822SAlexander Duyck unsigned int count = ch->combined_count; 1184aa3ac822SAlexander Duyck struct fm10k_hw *hw = &interface->hw; 1185aa3ac822SAlexander Duyck 1186aa3ac822SAlexander Duyck /* verify they are not requesting separate vectors */ 1187aa3ac822SAlexander Duyck if (!count || ch->rx_count || ch->tx_count) 1188aa3ac822SAlexander Duyck return -EINVAL; 1189aa3ac822SAlexander Duyck 1190aa3ac822SAlexander Duyck /* verify other_count has not changed */ 1191aa3ac822SAlexander Duyck if (ch->other_count != NON_Q_VECTORS(hw)) 1192aa3ac822SAlexander Duyck return -EINVAL; 1193aa3ac822SAlexander Duyck 1194aa3ac822SAlexander Duyck /* verify the number of channels does not exceed hardware limits */ 1195aa3ac822SAlexander Duyck if (count > fm10k_max_channels(dev)) 1196aa3ac822SAlexander Duyck return -EINVAL; 1197aa3ac822SAlexander Duyck 1198aa3ac822SAlexander Duyck interface->ring_feature[RING_F_RSS].limit = count; 1199aa3ac822SAlexander Duyck 1200aa3ac822SAlexander Duyck /* use setup TC to update any traffic class queue mapping */ 1201aa3ac822SAlexander Duyck return fm10k_setup_tc(dev, netdev_get_num_tc(dev)); 1202aa3ac822SAlexander Duyck } 1203aa3ac822SAlexander Duyck 1204a211e013SAlexander Duyck static int fm10k_get_ts_info(struct net_device *dev, 1205a211e013SAlexander Duyck struct ethtool_ts_info *info) 1206a211e013SAlexander Duyck { 1207a211e013SAlexander Duyck struct fm10k_intfc *interface = netdev_priv(dev); 1208a211e013SAlexander Duyck 1209a211e013SAlexander Duyck info->so_timestamping = 1210a211e013SAlexander Duyck SOF_TIMESTAMPING_TX_SOFTWARE | 1211a211e013SAlexander Duyck SOF_TIMESTAMPING_RX_SOFTWARE | 1212a211e013SAlexander Duyck SOF_TIMESTAMPING_SOFTWARE | 1213a211e013SAlexander Duyck SOF_TIMESTAMPING_TX_HARDWARE | 1214a211e013SAlexander Duyck SOF_TIMESTAMPING_RX_HARDWARE | 1215a211e013SAlexander Duyck SOF_TIMESTAMPING_RAW_HARDWARE; 1216a211e013SAlexander Duyck 1217a211e013SAlexander Duyck if (interface->ptp_clock) 1218a211e013SAlexander Duyck info->phc_index = ptp_clock_index(interface->ptp_clock); 1219a211e013SAlexander Duyck else 1220a211e013SAlexander Duyck info->phc_index = -1; 1221a211e013SAlexander Duyck 1222fcdb0a99SBruce Allan info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); 1223a211e013SAlexander Duyck 1224fcdb0a99SBruce Allan info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); 1225a211e013SAlexander Duyck 1226a211e013SAlexander Duyck return 0; 1227a211e013SAlexander Duyck } 1228a211e013SAlexander Duyck 122982dd0f7eSAlexander Duyck static const struct ethtool_ops fm10k_ethtool_ops = { 123082dd0f7eSAlexander Duyck .get_strings = fm10k_get_strings, 123182dd0f7eSAlexander Duyck .get_sset_count = fm10k_get_sset_count, 123282dd0f7eSAlexander Duyck .get_ethtool_stats = fm10k_get_ethtool_stats, 123382dd0f7eSAlexander Duyck .get_drvinfo = fm10k_get_drvinfo, 123482dd0f7eSAlexander Duyck .get_link = ethtool_op_get_link, 123582dd0f7eSAlexander Duyck .get_pauseparam = fm10k_get_pauseparam, 123682dd0f7eSAlexander Duyck .set_pauseparam = fm10k_set_pauseparam, 123782dd0f7eSAlexander Duyck .get_msglevel = fm10k_get_msglevel, 123882dd0f7eSAlexander Duyck .set_msglevel = fm10k_set_msglevel, 123982dd0f7eSAlexander Duyck .get_ringparam = fm10k_get_ringparam, 124082dd0f7eSAlexander Duyck .set_ringparam = fm10k_set_ringparam, 124182dd0f7eSAlexander Duyck .get_coalesce = fm10k_get_coalesce, 124282dd0f7eSAlexander Duyck .set_coalesce = fm10k_set_coalesce, 124382dd0f7eSAlexander Duyck .get_rxnfc = fm10k_get_rxnfc, 124482dd0f7eSAlexander Duyck .set_rxnfc = fm10k_set_rxnfc, 124582dd0f7eSAlexander Duyck .get_regs = fm10k_get_regs, 124682dd0f7eSAlexander Duyck .get_regs_len = fm10k_get_regs_len, 12475cb8db4aSAlexander Duyck .self_test = fm10k_self_test, 124880043f3bSJacob Keller .get_priv_flags = fm10k_get_priv_flags, 124980043f3bSJacob Keller .set_priv_flags = fm10k_set_priv_flags, 125082dd0f7eSAlexander Duyck .get_rxfh_indir_size = fm10k_get_reta_size, 125182dd0f7eSAlexander Duyck .get_rxfh_key_size = fm10k_get_rssrk_size, 125282dd0f7eSAlexander Duyck .get_rxfh = fm10k_get_rssh, 125382dd0f7eSAlexander Duyck .set_rxfh = fm10k_set_rssh, 1254aa3ac822SAlexander Duyck .get_channels = fm10k_get_channels, 1255aa3ac822SAlexander Duyck .set_channels = fm10k_set_channels, 1256a211e013SAlexander Duyck .get_ts_info = fm10k_get_ts_info, 125782dd0f7eSAlexander Duyck }; 125882dd0f7eSAlexander Duyck 125982dd0f7eSAlexander Duyck void fm10k_set_ethtool_ops(struct net_device *dev) 126082dd0f7eSAlexander Duyck { 126182dd0f7eSAlexander Duyck dev->ethtool_ops = &fm10k_ethtool_ops; 126282dd0f7eSAlexander Duyck } 1263