18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "fm10k.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_cistruct fm10k_stats { 98c2ecf20Sopenharmony_ci /* The stat_string is expected to be a format string formatted using 108c2ecf20Sopenharmony_ci * vsnprintf by fm10k_add_stat_strings. Every member of a stats array 118c2ecf20Sopenharmony_ci * should use the same format specifiers as they will be formatted 128c2ecf20Sopenharmony_ci * using the same variadic arguments. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 158c2ecf20Sopenharmony_ci int sizeof_stat; 168c2ecf20Sopenharmony_ci int stat_offset; 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define FM10K_STAT_FIELDS(_type, _name, _stat) { \ 208c2ecf20Sopenharmony_ci .stat_string = _name, \ 218c2ecf20Sopenharmony_ci .sizeof_stat = sizeof_field(_type, _stat), \ 228c2ecf20Sopenharmony_ci .stat_offset = offsetof(_type, _stat) \ 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* netdevice statistics */ 268c2ecf20Sopenharmony_ci#define FM10K_NETDEV_STAT(_net_stat) \ 278c2ecf20Sopenharmony_ci FM10K_STAT_FIELDS(struct net_device_stats, __stringify(_net_stat), \ 288c2ecf20Sopenharmony_ci _net_stat) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const struct fm10k_stats fm10k_gstrings_net_stats[] = { 318c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(tx_packets), 328c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(tx_bytes), 338c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(tx_errors), 348c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(rx_packets), 358c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(rx_bytes), 368c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(rx_errors), 378c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(rx_dropped), 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* detailed Rx errors */ 408c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(rx_length_errors), 418c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(rx_crc_errors), 428c2ecf20Sopenharmony_ci FM10K_NETDEV_STAT(rx_fifo_errors), 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define FM10K_NETDEV_STATS_LEN ARRAY_SIZE(fm10k_gstrings_net_stats) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* General interface statistics */ 488c2ecf20Sopenharmony_ci#define FM10K_STAT(_name, _stat) \ 498c2ecf20Sopenharmony_ci FM10K_STAT_FIELDS(struct fm10k_intfc, _name, _stat) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const struct fm10k_stats fm10k_gstrings_global_stats[] = { 528c2ecf20Sopenharmony_ci FM10K_STAT("tx_restart_queue", restart_queue), 538c2ecf20Sopenharmony_ci FM10K_STAT("tx_busy", tx_busy), 548c2ecf20Sopenharmony_ci FM10K_STAT("tx_csum_errors", tx_csum_errors), 558c2ecf20Sopenharmony_ci FM10K_STAT("rx_alloc_failed", alloc_failed), 568c2ecf20Sopenharmony_ci FM10K_STAT("rx_csum_errors", rx_csum_errors), 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci FM10K_STAT("tx_packets_nic", tx_packets_nic), 598c2ecf20Sopenharmony_ci FM10K_STAT("tx_bytes_nic", tx_bytes_nic), 608c2ecf20Sopenharmony_ci FM10K_STAT("rx_packets_nic", rx_packets_nic), 618c2ecf20Sopenharmony_ci FM10K_STAT("rx_bytes_nic", rx_bytes_nic), 628c2ecf20Sopenharmony_ci FM10K_STAT("rx_drops_nic", rx_drops_nic), 638c2ecf20Sopenharmony_ci FM10K_STAT("rx_overrun_pf", rx_overrun_pf), 648c2ecf20Sopenharmony_ci FM10K_STAT("rx_overrun_vf", rx_overrun_vf), 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci FM10K_STAT("swapi_status", hw.swapi.status), 678c2ecf20Sopenharmony_ci FM10K_STAT("mac_rules_used", hw.swapi.mac.used), 688c2ecf20Sopenharmony_ci FM10K_STAT("mac_rules_avail", hw.swapi.mac.avail), 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci FM10K_STAT("reset_while_pending", hw.mac.reset_while_pending), 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci FM10K_STAT("tx_hang_count", tx_timeout_count), 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct fm10k_stats fm10k_gstrings_pf_stats[] = { 768c2ecf20Sopenharmony_ci FM10K_STAT("timeout", stats.timeout.count), 778c2ecf20Sopenharmony_ci FM10K_STAT("ur", stats.ur.count), 788c2ecf20Sopenharmony_ci FM10K_STAT("ca", stats.ca.count), 798c2ecf20Sopenharmony_ci FM10K_STAT("um", stats.um.count), 808c2ecf20Sopenharmony_ci FM10K_STAT("xec", stats.xec.count), 818c2ecf20Sopenharmony_ci FM10K_STAT("vlan_drop", stats.vlan_drop.count), 828c2ecf20Sopenharmony_ci FM10K_STAT("loopback_drop", stats.loopback_drop.count), 838c2ecf20Sopenharmony_ci FM10K_STAT("nodesc_drop", stats.nodesc_drop.count), 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* mailbox statistics */ 878c2ecf20Sopenharmony_ci#define FM10K_MBX_STAT(_name, _stat) \ 888c2ecf20Sopenharmony_ci FM10K_STAT_FIELDS(struct fm10k_mbx_info, _name, _stat) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const struct fm10k_stats fm10k_gstrings_mbx_stats[] = { 918c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_tx_busy", tx_busy), 928c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_tx_dropped", tx_dropped), 938c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_tx_messages", tx_messages), 948c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_tx_dwords", tx_dwords), 958c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_tx_mbmem_pulled", tx_mbmem_pulled), 968c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_rx_messages", rx_messages), 978c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_rx_dwords", rx_dwords), 988c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_rx_parse_err", rx_parse_err), 998c2ecf20Sopenharmony_ci FM10K_MBX_STAT("mbx_rx_mbmem_pushed", rx_mbmem_pushed), 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* per-queue ring statistics */ 1038c2ecf20Sopenharmony_ci#define FM10K_QUEUE_STAT(_name, _stat) \ 1048c2ecf20Sopenharmony_ci FM10K_STAT_FIELDS(struct fm10k_ring, _name, _stat) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic const struct fm10k_stats fm10k_gstrings_queue_stats[] = { 1078c2ecf20Sopenharmony_ci FM10K_QUEUE_STAT("%s_queue_%u_packets", stats.packets), 1088c2ecf20Sopenharmony_ci FM10K_QUEUE_STAT("%s_queue_%u_bytes", stats.bytes), 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats) 1128c2ecf20Sopenharmony_ci#define FM10K_PF_STATS_LEN ARRAY_SIZE(fm10k_gstrings_pf_stats) 1138c2ecf20Sopenharmony_ci#define FM10K_MBX_STATS_LEN ARRAY_SIZE(fm10k_gstrings_mbx_stats) 1148c2ecf20Sopenharmony_ci#define FM10K_QUEUE_STATS_LEN ARRAY_SIZE(fm10k_gstrings_queue_stats) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \ 1178c2ecf20Sopenharmony_ci FM10K_NETDEV_STATS_LEN + \ 1188c2ecf20Sopenharmony_ci FM10K_MBX_STATS_LEN) 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = { 1218c2ecf20Sopenharmony_ci "Mailbox test (on/offline)" 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define FM10K_TEST_LEN (sizeof(fm10k_gstrings_test) / ETH_GSTRING_LEN) 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cienum fm10k_self_test_types { 1278c2ecf20Sopenharmony_ci FM10K_TEST_MBX, 1288c2ecf20Sopenharmony_ci FM10K_TEST_MAX = FM10K_TEST_LEN 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cienum { 1328c2ecf20Sopenharmony_ci FM10K_PRV_FLAG_LEN, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic const char fm10k_prv_flags[FM10K_PRV_FLAG_LEN][ETH_GSTRING_LEN] = { 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void __fm10k_add_stat_strings(u8 **p, const struct fm10k_stats stats[], 1398c2ecf20Sopenharmony_ci const unsigned int size, ...) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci unsigned int i; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 1448c2ecf20Sopenharmony_ci va_list args; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci va_start(args, size); 1478c2ecf20Sopenharmony_ci vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); 1488c2ecf20Sopenharmony_ci *p += ETH_GSTRING_LEN; 1498c2ecf20Sopenharmony_ci va_end(args); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci#define fm10k_add_stat_strings(p, stats, ...) \ 1548c2ecf20Sopenharmony_ci __fm10k_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void fm10k_get_stat_strings(struct net_device *dev, u8 *data) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 1598c2ecf20Sopenharmony_ci unsigned int i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci fm10k_add_stat_strings(&data, fm10k_gstrings_net_stats); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci fm10k_add_stat_strings(&data, fm10k_gstrings_global_stats); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci fm10k_add_stat_strings(&data, fm10k_gstrings_mbx_stats); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (interface->hw.mac.type != fm10k_mac_vf) 1688c2ecf20Sopenharmony_ci fm10k_add_stat_strings(&data, fm10k_gstrings_pf_stats); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci for (i = 0; i < interface->hw.mac.max_queues; i++) { 1718c2ecf20Sopenharmony_ci fm10k_add_stat_strings(&data, fm10k_gstrings_queue_stats, 1728c2ecf20Sopenharmony_ci "tx", i); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci fm10k_add_stat_strings(&data, fm10k_gstrings_queue_stats, 1758c2ecf20Sopenharmony_ci "rx", i); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void fm10k_get_strings(struct net_device *dev, 1808c2ecf20Sopenharmony_ci u32 stringset, u8 *data) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci switch (stringset) { 1838c2ecf20Sopenharmony_ci case ETH_SS_TEST: 1848c2ecf20Sopenharmony_ci memcpy(data, fm10k_gstrings_test, 1858c2ecf20Sopenharmony_ci FM10K_TEST_LEN * ETH_GSTRING_LEN); 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case ETH_SS_STATS: 1888c2ecf20Sopenharmony_ci fm10k_get_stat_strings(dev, data); 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 1918c2ecf20Sopenharmony_ci memcpy(data, fm10k_prv_flags, 1928c2ecf20Sopenharmony_ci FM10K_PRV_FLAG_LEN * ETH_GSTRING_LEN); 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int fm10k_get_sset_count(struct net_device *dev, int sset) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 2008c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 2018c2ecf20Sopenharmony_ci int stats_len = FM10K_STATIC_STATS_LEN; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci switch (sset) { 2048c2ecf20Sopenharmony_ci case ETH_SS_TEST: 2058c2ecf20Sopenharmony_ci return FM10K_TEST_LEN; 2068c2ecf20Sopenharmony_ci case ETH_SS_STATS: 2078c2ecf20Sopenharmony_ci stats_len += hw->mac.max_queues * 2 * FM10K_QUEUE_STATS_LEN; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (hw->mac.type != fm10k_mac_vf) 2108c2ecf20Sopenharmony_ci stats_len += FM10K_PF_STATS_LEN; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return stats_len; 2138c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 2148c2ecf20Sopenharmony_ci return FM10K_PRV_FLAG_LEN; 2158c2ecf20Sopenharmony_ci default: 2168c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void __fm10k_add_ethtool_stats(u64 **data, void *pointer, 2218c2ecf20Sopenharmony_ci const struct fm10k_stats stats[], 2228c2ecf20Sopenharmony_ci const unsigned int size) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci unsigned int i; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (!pointer) { 2278c2ecf20Sopenharmony_ci /* memory is not zero allocated so we have to clear it */ 2288c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 2298c2ecf20Sopenharmony_ci *((*data)++) = 0; 2308c2ecf20Sopenharmony_ci return; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 2348c2ecf20Sopenharmony_ci char *p = (char *)pointer + stats[i].stat_offset; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci switch (stats[i].sizeof_stat) { 2378c2ecf20Sopenharmony_ci case sizeof(u64): 2388c2ecf20Sopenharmony_ci *((*data)++) = *(u64 *)p; 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci case sizeof(u32): 2418c2ecf20Sopenharmony_ci *((*data)++) = *(u32 *)p; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci case sizeof(u16): 2448c2ecf20Sopenharmony_ci *((*data)++) = *(u16 *)p; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci case sizeof(u8): 2478c2ecf20Sopenharmony_ci *((*data)++) = *(u8 *)p; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci default: 2508c2ecf20Sopenharmony_ci WARN_ONCE(1, "unexpected stat size for %s", 2518c2ecf20Sopenharmony_ci stats[i].stat_string); 2528c2ecf20Sopenharmony_ci *((*data)++) = 0; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define fm10k_add_ethtool_stats(data, pointer, stats) \ 2588c2ecf20Sopenharmony_ci __fm10k_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void fm10k_get_ethtool_stats(struct net_device *netdev, 2618c2ecf20Sopenharmony_ci struct ethtool_stats __always_unused *stats, 2628c2ecf20Sopenharmony_ci u64 *data) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 2658c2ecf20Sopenharmony_ci struct net_device_stats *net_stats = &netdev->stats; 2668c2ecf20Sopenharmony_ci int i; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci fm10k_update_stats(interface); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci fm10k_add_ethtool_stats(&data, net_stats, fm10k_gstrings_net_stats); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci fm10k_add_ethtool_stats(&data, interface, fm10k_gstrings_global_stats); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci fm10k_add_ethtool_stats(&data, &interface->hw.mbx, 2758c2ecf20Sopenharmony_ci fm10k_gstrings_mbx_stats); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (interface->hw.mac.type != fm10k_mac_vf) { 2788c2ecf20Sopenharmony_ci fm10k_add_ethtool_stats(&data, interface, 2798c2ecf20Sopenharmony_ci fm10k_gstrings_pf_stats); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 0; i < interface->hw.mac.max_queues; i++) { 2838c2ecf20Sopenharmony_ci struct fm10k_ring *ring; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci ring = interface->tx_ring[i]; 2868c2ecf20Sopenharmony_ci fm10k_add_ethtool_stats(&data, ring, 2878c2ecf20Sopenharmony_ci fm10k_gstrings_queue_stats); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ring = interface->rx_ring[i]; 2908c2ecf20Sopenharmony_ci fm10k_add_ethtool_stats(&data, ring, 2918c2ecf20Sopenharmony_ci fm10k_gstrings_queue_stats); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* If function below adds more registers this define needs to be updated */ 2968c2ecf20Sopenharmony_ci#define FM10K_REGS_LEN_Q 29 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic void fm10k_get_reg_q(struct fm10k_hw *hw, u32 *buff, int i) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci int idx = 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAL(i)); 3038c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAH(i)); 3048c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RDLEN(i)); 3058c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_RXCTRL(i)); 3068c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RDH(i)); 3078c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RDT(i)); 3088c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RXQCTL(i)); 3098c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RXDCTL(i)); 3108c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RXINT(i)); 3118c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_SRRCTL(i)); 3128c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_QPRC(i)); 3138c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_QPRDC(i)); 3148c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_L(i)); 3158c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_H(i)); 3168c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAL(i)); 3178c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAH(i)); 3188c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TDLEN(i)); 3198c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_TXCTRL(i)); 3208c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TDH(i)); 3218c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TDT(i)); 3228c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TXDCTL(i)); 3238c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TXQCTL(i)); 3248c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TXINT(i)); 3258c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_QPTC(i)); 3268c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_L(i)); 3278c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_H(i)); 3288c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TQDLOC(i)); 3298c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_TX_SGLORT(i)); 3308c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_PFVTCTL(i)); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci BUG_ON(idx != FM10K_REGS_LEN_Q); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* If function above adds more registers this define needs to be updated */ 3368c2ecf20Sopenharmony_ci#define FM10K_REGS_LEN_VSI 43 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic void fm10k_get_reg_vsi(struct fm10k_hw *hw, u32 *buff, int i) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci int idx = 0, j; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_MRQC(i)); 3438c2ecf20Sopenharmony_ci for (j = 0; j < 10; j++) 3448c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RSSRK(i, j)); 3458c2ecf20Sopenharmony_ci for (j = 0; j < 32; j++) 3468c2ecf20Sopenharmony_ci buff[idx++] = fm10k_read_reg(hw, FM10K_RETA(i, j)); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci BUG_ON(idx != FM10K_REGS_LEN_VSI); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void fm10k_get_regs(struct net_device *netdev, 3528c2ecf20Sopenharmony_ci struct ethtool_regs *regs, void *p) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 3558c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 3568c2ecf20Sopenharmony_ci u32 *buff = p; 3578c2ecf20Sopenharmony_ci u16 i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci regs->version = BIT(24) | (hw->revision_id << 16) | hw->device_id; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci switch (hw->mac.type) { 3628c2ecf20Sopenharmony_ci case fm10k_mac_pf: 3638c2ecf20Sopenharmony_ci /* General PF Registers */ 3648c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_CTRL); 3658c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_CTRL_EXT); 3668c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_GCR); 3678c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_GCR_EXT); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 3708c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTMAP(i)); 3718c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTDEC(i)); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (i = 0; i < 65; i++) { 3758c2ecf20Sopenharmony_ci fm10k_get_reg_vsi(hw, buff, i); 3768c2ecf20Sopenharmony_ci buff += FM10K_REGS_LEN_VSI; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL); 3808c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL2); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci for (i = 0; i < FM10K_MAX_QUEUES_PF; i++) { 3838c2ecf20Sopenharmony_ci fm10k_get_reg_q(hw, buff, i); 3848c2ecf20Sopenharmony_ci buff += FM10K_REGS_LEN_Q; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_TPH_CTRL); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 3908c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_INT_MAP(i)); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* Interrupt Throttling Registers */ 3938c2ecf20Sopenharmony_ci for (i = 0; i < 130; i++) 3948c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_ITR(i)); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci case fm10k_mac_vf: 3988c2ecf20Sopenharmony_ci /* General VF registers */ 3998c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_VFCTRL); 4008c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_VFINT_MAP); 4018c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_VFSYSTIME); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Interrupt Throttling Registers */ 4048c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 4058c2ecf20Sopenharmony_ci *(buff++) = fm10k_read_reg(hw, FM10K_VFITR(i)); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci fm10k_get_reg_vsi(hw, buff, 0); 4088c2ecf20Sopenharmony_ci buff += FM10K_REGS_LEN_VSI; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci for (i = 0; i < FM10K_MAX_QUEUES_POOL; i++) { 4118c2ecf20Sopenharmony_ci if (i < hw->mac.max_queues) 4128c2ecf20Sopenharmony_ci fm10k_get_reg_q(hw, buff, i); 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci memset(buff, 0, sizeof(u32) * FM10K_REGS_LEN_Q); 4158c2ecf20Sopenharmony_ci buff += FM10K_REGS_LEN_Q; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci break; 4198c2ecf20Sopenharmony_ci default: 4208c2ecf20Sopenharmony_ci return; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci/* If function above adds more registers these define need to be updated */ 4258c2ecf20Sopenharmony_ci#define FM10K_REGS_LEN_PF \ 4268c2ecf20Sopenharmony_ci(162 + (65 * FM10K_REGS_LEN_VSI) + (FM10K_MAX_QUEUES_PF * FM10K_REGS_LEN_Q)) 4278c2ecf20Sopenharmony_ci#define FM10K_REGS_LEN_VF \ 4288c2ecf20Sopenharmony_ci(11 + FM10K_REGS_LEN_VSI + (FM10K_MAX_QUEUES_POOL * FM10K_REGS_LEN_Q)) 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int fm10k_get_regs_len(struct net_device *netdev) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 4338c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci switch (hw->mac.type) { 4368c2ecf20Sopenharmony_ci case fm10k_mac_pf: 4378c2ecf20Sopenharmony_ci return FM10K_REGS_LEN_PF * sizeof(u32); 4388c2ecf20Sopenharmony_ci case fm10k_mac_vf: 4398c2ecf20Sopenharmony_ci return FM10K_REGS_LEN_VF * sizeof(u32); 4408c2ecf20Sopenharmony_ci default: 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void fm10k_get_drvinfo(struct net_device *dev, 4468c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci strncpy(info->driver, fm10k_driver_name, 4518c2ecf20Sopenharmony_ci sizeof(info->driver) - 1); 4528c2ecf20Sopenharmony_ci strncpy(info->bus_info, pci_name(interface->pdev), 4538c2ecf20Sopenharmony_ci sizeof(info->bus_info) - 1); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void fm10k_get_pauseparam(struct net_device *dev, 4578c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* record fixed values for autoneg and tx pause */ 4628c2ecf20Sopenharmony_ci pause->autoneg = 0; 4638c2ecf20Sopenharmony_ci pause->tx_pause = 1; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci pause->rx_pause = interface->rx_pause ? 1 : 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int fm10k_set_pauseparam(struct net_device *dev, 4698c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 4728c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (pause->autoneg || !pause->tx_pause) 4758c2ecf20Sopenharmony_ci return -EINVAL; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* we can only support pause on the PF to avoid head-of-line blocking */ 4788c2ecf20Sopenharmony_ci if (hw->mac.type == fm10k_mac_pf) 4798c2ecf20Sopenharmony_ci interface->rx_pause = pause->rx_pause ? ~0 : 0; 4808c2ecf20Sopenharmony_ci else if (pause->rx_pause) 4818c2ecf20Sopenharmony_ci return -EINVAL; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (netif_running(dev)) 4848c2ecf20Sopenharmony_ci fm10k_update_rx_drop_en(interface); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic u32 fm10k_get_msglevel(struct net_device *netdev) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return interface->msg_enable; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic void fm10k_set_msglevel(struct net_device *netdev, u32 data) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci interface->msg_enable = data; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic void fm10k_get_ringparam(struct net_device *netdev, 5048c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ring->rx_max_pending = FM10K_MAX_RXD; 5098c2ecf20Sopenharmony_ci ring->tx_max_pending = FM10K_MAX_TXD; 5108c2ecf20Sopenharmony_ci ring->rx_mini_max_pending = 0; 5118c2ecf20Sopenharmony_ci ring->rx_jumbo_max_pending = 0; 5128c2ecf20Sopenharmony_ci ring->rx_pending = interface->rx_ring_count; 5138c2ecf20Sopenharmony_ci ring->tx_pending = interface->tx_ring_count; 5148c2ecf20Sopenharmony_ci ring->rx_mini_pending = 0; 5158c2ecf20Sopenharmony_ci ring->rx_jumbo_pending = 0; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int fm10k_set_ringparam(struct net_device *netdev, 5198c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 5228c2ecf20Sopenharmony_ci struct fm10k_ring *temp_ring; 5238c2ecf20Sopenharmony_ci int i, err = 0; 5248c2ecf20Sopenharmony_ci u32 new_rx_count, new_tx_count; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) 5278c2ecf20Sopenharmony_ci return -EINVAL; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci new_tx_count = clamp_t(u32, ring->tx_pending, 5308c2ecf20Sopenharmony_ci FM10K_MIN_TXD, FM10K_MAX_TXD); 5318c2ecf20Sopenharmony_ci new_tx_count = ALIGN(new_tx_count, FM10K_REQ_TX_DESCRIPTOR_MULTIPLE); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci new_rx_count = clamp_t(u32, ring->rx_pending, 5348c2ecf20Sopenharmony_ci FM10K_MIN_RXD, FM10K_MAX_RXD); 5358c2ecf20Sopenharmony_ci new_rx_count = ALIGN(new_rx_count, FM10K_REQ_RX_DESCRIPTOR_MULTIPLE); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if ((new_tx_count == interface->tx_ring_count) && 5388c2ecf20Sopenharmony_ci (new_rx_count == interface->rx_ring_count)) { 5398c2ecf20Sopenharmony_ci /* nothing to do */ 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci while (test_and_set_bit(__FM10K_RESETTING, interface->state)) 5448c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (!netif_running(interface->netdev)) { 5478c2ecf20Sopenharmony_ci for (i = 0; i < interface->num_tx_queues; i++) 5488c2ecf20Sopenharmony_ci interface->tx_ring[i]->count = new_tx_count; 5498c2ecf20Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) 5508c2ecf20Sopenharmony_ci interface->rx_ring[i]->count = new_rx_count; 5518c2ecf20Sopenharmony_ci interface->tx_ring_count = new_tx_count; 5528c2ecf20Sopenharmony_ci interface->rx_ring_count = new_rx_count; 5538c2ecf20Sopenharmony_ci goto clear_reset; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* allocate temporary buffer to store rings in */ 5578c2ecf20Sopenharmony_ci i = max_t(int, interface->num_tx_queues, interface->num_rx_queues); 5588c2ecf20Sopenharmony_ci temp_ring = vmalloc(array_size(i, sizeof(struct fm10k_ring))); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (!temp_ring) { 5618c2ecf20Sopenharmony_ci err = -ENOMEM; 5628c2ecf20Sopenharmony_ci goto clear_reset; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci fm10k_down(interface); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* Setup new Tx resources and free the old Tx resources in that order. 5688c2ecf20Sopenharmony_ci * We can then assign the new resources to the rings via a memcpy. 5698c2ecf20Sopenharmony_ci * The advantage to this approach is that we are guaranteed to still 5708c2ecf20Sopenharmony_ci * have resources even in the case of an allocation failure. 5718c2ecf20Sopenharmony_ci */ 5728c2ecf20Sopenharmony_ci if (new_tx_count != interface->tx_ring_count) { 5738c2ecf20Sopenharmony_ci for (i = 0; i < interface->num_tx_queues; i++) { 5748c2ecf20Sopenharmony_ci memcpy(&temp_ring[i], interface->tx_ring[i], 5758c2ecf20Sopenharmony_ci sizeof(struct fm10k_ring)); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci temp_ring[i].count = new_tx_count; 5788c2ecf20Sopenharmony_ci err = fm10k_setup_tx_resources(&temp_ring[i]); 5798c2ecf20Sopenharmony_ci if (err) { 5808c2ecf20Sopenharmony_ci while (i) { 5818c2ecf20Sopenharmony_ci i--; 5828c2ecf20Sopenharmony_ci fm10k_free_tx_resources(&temp_ring[i]); 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci goto err_setup; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci for (i = 0; i < interface->num_tx_queues; i++) { 5898c2ecf20Sopenharmony_ci fm10k_free_tx_resources(interface->tx_ring[i]); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci memcpy(interface->tx_ring[i], &temp_ring[i], 5928c2ecf20Sopenharmony_ci sizeof(struct fm10k_ring)); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci interface->tx_ring_count = new_tx_count; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Repeat the process for the Rx rings if needed */ 5998c2ecf20Sopenharmony_ci if (new_rx_count != interface->rx_ring_count) { 6008c2ecf20Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) { 6018c2ecf20Sopenharmony_ci memcpy(&temp_ring[i], interface->rx_ring[i], 6028c2ecf20Sopenharmony_ci sizeof(struct fm10k_ring)); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci temp_ring[i].count = new_rx_count; 6058c2ecf20Sopenharmony_ci err = fm10k_setup_rx_resources(&temp_ring[i]); 6068c2ecf20Sopenharmony_ci if (err) { 6078c2ecf20Sopenharmony_ci while (i) { 6088c2ecf20Sopenharmony_ci i--; 6098c2ecf20Sopenharmony_ci fm10k_free_rx_resources(&temp_ring[i]); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci goto err_setup; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) { 6168c2ecf20Sopenharmony_ci fm10k_free_rx_resources(interface->rx_ring[i]); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci memcpy(interface->rx_ring[i], &temp_ring[i], 6198c2ecf20Sopenharmony_ci sizeof(struct fm10k_ring)); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci interface->rx_ring_count = new_rx_count; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cierr_setup: 6268c2ecf20Sopenharmony_ci fm10k_up(interface); 6278c2ecf20Sopenharmony_ci vfree(temp_ring); 6288c2ecf20Sopenharmony_ciclear_reset: 6298c2ecf20Sopenharmony_ci clear_bit(__FM10K_RESETTING, interface->state); 6308c2ecf20Sopenharmony_ci return err; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int fm10k_get_coalesce(struct net_device *dev, 6348c2ecf20Sopenharmony_ci struct ethtool_coalesce *ec) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ec->use_adaptive_tx_coalesce = ITR_IS_ADAPTIVE(interface->tx_itr); 6398c2ecf20Sopenharmony_ci ec->tx_coalesce_usecs = interface->tx_itr & ~FM10K_ITR_ADAPTIVE; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci ec->use_adaptive_rx_coalesce = ITR_IS_ADAPTIVE(interface->rx_itr); 6428c2ecf20Sopenharmony_ci ec->rx_coalesce_usecs = interface->rx_itr & ~FM10K_ITR_ADAPTIVE; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int fm10k_set_coalesce(struct net_device *dev, 6488c2ecf20Sopenharmony_ci struct ethtool_coalesce *ec) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 6518c2ecf20Sopenharmony_ci u16 tx_itr, rx_itr; 6528c2ecf20Sopenharmony_ci int i; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* verify limits */ 6558c2ecf20Sopenharmony_ci if ((ec->rx_coalesce_usecs > FM10K_ITR_MAX) || 6568c2ecf20Sopenharmony_ci (ec->tx_coalesce_usecs > FM10K_ITR_MAX)) 6578c2ecf20Sopenharmony_ci return -EINVAL; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* record settings */ 6608c2ecf20Sopenharmony_ci tx_itr = ec->tx_coalesce_usecs; 6618c2ecf20Sopenharmony_ci rx_itr = ec->rx_coalesce_usecs; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* set initial values for adaptive ITR */ 6648c2ecf20Sopenharmony_ci if (ec->use_adaptive_tx_coalesce) 6658c2ecf20Sopenharmony_ci tx_itr = FM10K_ITR_ADAPTIVE | FM10K_TX_ITR_DEFAULT; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (ec->use_adaptive_rx_coalesce) 6688c2ecf20Sopenharmony_ci rx_itr = FM10K_ITR_ADAPTIVE | FM10K_RX_ITR_DEFAULT; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* update interface */ 6718c2ecf20Sopenharmony_ci interface->tx_itr = tx_itr; 6728c2ecf20Sopenharmony_ci interface->rx_itr = rx_itr; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* update q_vectors */ 6758c2ecf20Sopenharmony_ci for (i = 0; i < interface->num_q_vectors; i++) { 6768c2ecf20Sopenharmony_ci struct fm10k_q_vector *qv = interface->q_vector[i]; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci qv->tx.itr = tx_itr; 6798c2ecf20Sopenharmony_ci qv->rx.itr = rx_itr; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return 0; 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface, 6868c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci cmd->data = 0; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Report default options for RSS on fm10k */ 6918c2ecf20Sopenharmony_ci switch (cmd->flow_type) { 6928c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 6938c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 6948c2ecf20Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 6958c2ecf20Sopenharmony_ci fallthrough; 6968c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 6978c2ecf20Sopenharmony_ci if (test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, 6988c2ecf20Sopenharmony_ci interface->flags)) 6998c2ecf20Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 7008c2ecf20Sopenharmony_ci fallthrough; 7018c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 7028c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 7038c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 7048c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 7058c2ecf20Sopenharmony_ci case AH_V4_FLOW: 7068c2ecf20Sopenharmony_ci case AH_V6_FLOW: 7078c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 7088c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 7098c2ecf20Sopenharmony_ci case IPV4_FLOW: 7108c2ecf20Sopenharmony_ci case IPV6_FLOW: 7118c2ecf20Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 7148c2ecf20Sopenharmony_ci if (test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, 7158c2ecf20Sopenharmony_ci interface->flags)) 7168c2ecf20Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 7178c2ecf20Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST; 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci default: 7208c2ecf20Sopenharmony_ci return -EINVAL; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return 0; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int fm10k_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 7278c2ecf20Sopenharmony_ci u32 __always_unused *rule_locs) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 7308c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci switch (cmd->cmd) { 7338c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 7348c2ecf20Sopenharmony_ci cmd->data = interface->num_rx_queues; 7358c2ecf20Sopenharmony_ci ret = 0; 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 7388c2ecf20Sopenharmony_ci ret = fm10k_get_rss_hash_opts(interface, cmd); 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci default: 7418c2ecf20Sopenharmony_ci break; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return ret; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface, 7488c2ecf20Sopenharmony_ci struct ethtool_rxnfc *nfc) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci int rss_ipv4_udp = test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, 7518c2ecf20Sopenharmony_ci interface->flags); 7528c2ecf20Sopenharmony_ci int rss_ipv6_udp = test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, 7538c2ecf20Sopenharmony_ci interface->flags); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* RSS does not support anything other than hashing 7568c2ecf20Sopenharmony_ci * to queues on src and dst IPs and ports 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | 7598c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) 7608c2ecf20Sopenharmony_ci return -EINVAL; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci switch (nfc->flow_type) { 7638c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 7648c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 7658c2ecf20Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 7668c2ecf20Sopenharmony_ci !(nfc->data & RXH_IP_DST) || 7678c2ecf20Sopenharmony_ci !(nfc->data & RXH_L4_B_0_1) || 7688c2ecf20Sopenharmony_ci !(nfc->data & RXH_L4_B_2_3)) 7698c2ecf20Sopenharmony_ci return -EINVAL; 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 7728c2ecf20Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 7738c2ecf20Sopenharmony_ci !(nfc->data & RXH_IP_DST)) 7748c2ecf20Sopenharmony_ci return -EINVAL; 7758c2ecf20Sopenharmony_ci switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 7768c2ecf20Sopenharmony_ci case 0: 7778c2ecf20Sopenharmony_ci clear_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, 7788c2ecf20Sopenharmony_ci interface->flags); 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 7818c2ecf20Sopenharmony_ci set_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, 7828c2ecf20Sopenharmony_ci interface->flags); 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci default: 7858c2ecf20Sopenharmony_ci return -EINVAL; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 7898c2ecf20Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 7908c2ecf20Sopenharmony_ci !(nfc->data & RXH_IP_DST)) 7918c2ecf20Sopenharmony_ci return -EINVAL; 7928c2ecf20Sopenharmony_ci switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 7938c2ecf20Sopenharmony_ci case 0: 7948c2ecf20Sopenharmony_ci clear_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, 7958c2ecf20Sopenharmony_ci interface->flags); 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci case (RXH_L4_B_0_1 | RXH_L4_B_2_3): 7988c2ecf20Sopenharmony_ci set_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, 7998c2ecf20Sopenharmony_ci interface->flags); 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci default: 8028c2ecf20Sopenharmony_ci return -EINVAL; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 8068c2ecf20Sopenharmony_ci case AH_V4_FLOW: 8078c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 8088c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 8098c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 8108c2ecf20Sopenharmony_ci case AH_V6_FLOW: 8118c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 8128c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 8138c2ecf20Sopenharmony_ci if (!(nfc->data & RXH_IP_SRC) || 8148c2ecf20Sopenharmony_ci !(nfc->data & RXH_IP_DST) || 8158c2ecf20Sopenharmony_ci (nfc->data & RXH_L4_B_0_1) || 8168c2ecf20Sopenharmony_ci (nfc->data & RXH_L4_B_2_3)) 8178c2ecf20Sopenharmony_ci return -EINVAL; 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci default: 8208c2ecf20Sopenharmony_ci return -EINVAL; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* If something changed we need to update the MRQC register. Note that 8248c2ecf20Sopenharmony_ci * test_bit() is guaranteed to return strictly 0 or 1, so testing for 8258c2ecf20Sopenharmony_ci * equality is safe. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci if ((rss_ipv4_udp != test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, 8288c2ecf20Sopenharmony_ci interface->flags)) || 8298c2ecf20Sopenharmony_ci (rss_ipv6_udp != test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, 8308c2ecf20Sopenharmony_ci interface->flags))) { 8318c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 8328c2ecf20Sopenharmony_ci bool warn = false; 8338c2ecf20Sopenharmony_ci u32 mrqc; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* Perform hash on these packet types */ 8368c2ecf20Sopenharmony_ci mrqc = FM10K_MRQC_IPV4 | 8378c2ecf20Sopenharmony_ci FM10K_MRQC_TCP_IPV4 | 8388c2ecf20Sopenharmony_ci FM10K_MRQC_IPV6 | 8398c2ecf20Sopenharmony_ci FM10K_MRQC_TCP_IPV6; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, 8428c2ecf20Sopenharmony_ci interface->flags)) { 8438c2ecf20Sopenharmony_ci mrqc |= FM10K_MRQC_UDP_IPV4; 8448c2ecf20Sopenharmony_ci warn = true; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci if (test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, 8478c2ecf20Sopenharmony_ci interface->flags)) { 8488c2ecf20Sopenharmony_ci mrqc |= FM10K_MRQC_UDP_IPV6; 8498c2ecf20Sopenharmony_ci warn = true; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* If we enable UDP RSS display a warning that this may cause 8538c2ecf20Sopenharmony_ci * fragmented UDP packets to arrive out of order. 8548c2ecf20Sopenharmony_ci */ 8558c2ecf20Sopenharmony_ci if (warn) 8568c2ecf20Sopenharmony_ci netif_warn(interface, drv, interface->netdev, 8578c2ecf20Sopenharmony_ci "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci fm10k_write_reg(hw, FM10K_MRQC(0), mrqc); 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int fm10k_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 8688c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci switch (cmd->cmd) { 8718c2ecf20Sopenharmony_ci case ETHTOOL_SRXFH: 8728c2ecf20Sopenharmony_ci ret = fm10k_set_rss_hash_opt(interface, cmd); 8738c2ecf20Sopenharmony_ci break; 8748c2ecf20Sopenharmony_ci default: 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return ret; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 8848c2ecf20Sopenharmony_ci struct fm10k_mbx_info *mbx = &hw->mbx; 8858c2ecf20Sopenharmony_ci u32 attr_flag, test_msg[6]; 8868c2ecf20Sopenharmony_ci unsigned long timeout; 8878c2ecf20Sopenharmony_ci int err = -EINVAL; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* For now this is a VF only feature */ 8908c2ecf20Sopenharmony_ci if (hw->mac.type != fm10k_mac_vf) 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* loop through both nested and unnested attribute types */ 8948c2ecf20Sopenharmony_ci for (attr_flag = BIT(FM10K_TEST_MSG_UNSET); 8958c2ecf20Sopenharmony_ci attr_flag < BIT(2 * FM10K_TEST_MSG_NESTED); 8968c2ecf20Sopenharmony_ci attr_flag += attr_flag) { 8978c2ecf20Sopenharmony_ci /* generate message to be tested */ 8988c2ecf20Sopenharmony_ci fm10k_tlv_msg_test_create(test_msg, attr_flag); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci fm10k_mbx_lock(interface); 9018c2ecf20Sopenharmony_ci mbx->test_result = FM10K_NOT_IMPLEMENTED; 9028c2ecf20Sopenharmony_ci err = mbx->ops.enqueue_tx(hw, mbx, test_msg); 9038c2ecf20Sopenharmony_ci fm10k_mbx_unlock(interface); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* wait up to 1 second for response */ 9068c2ecf20Sopenharmony_ci timeout = jiffies + HZ; 9078c2ecf20Sopenharmony_ci do { 9088c2ecf20Sopenharmony_ci if (err < 0) 9098c2ecf20Sopenharmony_ci goto err_out; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci usleep_range(500, 1000); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci fm10k_mbx_lock(interface); 9148c2ecf20Sopenharmony_ci mbx->ops.process(hw, mbx); 9158c2ecf20Sopenharmony_ci fm10k_mbx_unlock(interface); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci err = mbx->test_result; 9188c2ecf20Sopenharmony_ci if (!err) 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci } while (time_is_after_jiffies(timeout)); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* reporting errors */ 9238c2ecf20Sopenharmony_ci if (err) 9248c2ecf20Sopenharmony_ci goto err_out; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cierr_out: 9288c2ecf20Sopenharmony_ci *data = err < 0 ? (attr_flag) : (err > 0); 9298c2ecf20Sopenharmony_ci return err; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void fm10k_self_test(struct net_device *dev, 9338c2ecf20Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 9368c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data) * FM10K_TEST_LEN); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (FM10K_REMOVED(hw->hw_addr)) { 9418c2ecf20Sopenharmony_ci netif_err(interface, drv, dev, 9428c2ecf20Sopenharmony_ci "Interface removed - test blocked\n"); 9438c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 9448c2ecf20Sopenharmony_ci return; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (fm10k_mbx_test(interface, &data[FM10K_TEST_MBX])) 9488c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic u32 fm10k_get_priv_flags(struct net_device *netdev) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci return 0; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic int fm10k_set_priv_flags(struct net_device *netdev, u32 priv_flags) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci if (priv_flags >= BIT(FM10K_PRV_FLAG_LEN)) 9598c2ecf20Sopenharmony_ci return -EINVAL; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci return 0; 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic u32 fm10k_get_reta_size(struct net_device __always_unused *netdev) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_civoid fm10k_write_reta(struct fm10k_intfc *interface, const u32 *indir) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci u16 rss_i = interface->ring_feature[RING_F_RSS].indices; 9728c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 9738c2ecf20Sopenharmony_ci u32 table[4]; 9748c2ecf20Sopenharmony_ci int i, j; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* record entries to reta table */ 9778c2ecf20Sopenharmony_ci for (i = 0; i < FM10K_RETA_SIZE; i++) { 9788c2ecf20Sopenharmony_ci u32 reta, n; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* generate a new table if we weren't given one */ 9818c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) { 9828c2ecf20Sopenharmony_ci if (indir) 9838c2ecf20Sopenharmony_ci n = indir[4 * i + j]; 9848c2ecf20Sopenharmony_ci else 9858c2ecf20Sopenharmony_ci n = ethtool_rxfh_indir_default(4 * i + j, 9868c2ecf20Sopenharmony_ci rss_i); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci table[j] = n; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci reta = table[0] | 9928c2ecf20Sopenharmony_ci (table[1] << 8) | 9938c2ecf20Sopenharmony_ci (table[2] << 16) | 9948c2ecf20Sopenharmony_ci (table[3] << 24); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (interface->reta[i] == reta) 9978c2ecf20Sopenharmony_ci continue; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci interface->reta[i] = reta; 10008c2ecf20Sopenharmony_ci fm10k_write_reg(hw, FM10K_RETA(0, i), reta); 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int fm10k_get_reta(struct net_device *netdev, u32 *indir) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 10078c2ecf20Sopenharmony_ci int i; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (!indir) 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci for (i = 0; i < FM10K_RETA_SIZE; i++, indir += 4) { 10138c2ecf20Sopenharmony_ci u32 reta = interface->reta[i]; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci indir[0] = (reta << 24) >> 24; 10168c2ecf20Sopenharmony_ci indir[1] = (reta << 16) >> 24; 10178c2ecf20Sopenharmony_ci indir[2] = (reta << 8) >> 24; 10188c2ecf20Sopenharmony_ci indir[3] = (reta) >> 24; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci return 0; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic int fm10k_set_reta(struct net_device *netdev, const u32 *indir) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 10278c2ecf20Sopenharmony_ci int i; 10288c2ecf20Sopenharmony_ci u16 rss_i; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (!indir) 10318c2ecf20Sopenharmony_ci return 0; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* Verify user input. */ 10348c2ecf20Sopenharmony_ci rss_i = interface->ring_feature[RING_F_RSS].indices; 10358c2ecf20Sopenharmony_ci for (i = fm10k_get_reta_size(netdev); i--;) { 10368c2ecf20Sopenharmony_ci if (indir[i] < rss_i) 10378c2ecf20Sopenharmony_ci continue; 10388c2ecf20Sopenharmony_ci return -EINVAL; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci fm10k_write_reta(interface, indir); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic u32 fm10k_get_rssrk_size(struct net_device __always_unused *netdev) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key, 10528c2ecf20Sopenharmony_ci u8 *hfunc) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 10558c2ecf20Sopenharmony_ci int i, err; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (hfunc) 10588c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci err = fm10k_get_reta(netdev, indir); 10618c2ecf20Sopenharmony_ci if (err || !key) 10628c2ecf20Sopenharmony_ci return err; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) 10658c2ecf20Sopenharmony_ci *(__le32 *)key = cpu_to_le32(interface->rssrk[i]); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic int fm10k_set_rssh(struct net_device *netdev, const u32 *indir, 10718c2ecf20Sopenharmony_ci const u8 *key, const u8 hfunc) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 10748c2ecf20Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 10758c2ecf20Sopenharmony_ci int i, err; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* We do not allow change in unsupported parameters */ 10788c2ecf20Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 10798c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci err = fm10k_set_reta(netdev, indir); 10828c2ecf20Sopenharmony_ci if (err || !key) 10838c2ecf20Sopenharmony_ci return err; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) { 10868c2ecf20Sopenharmony_ci u32 rssrk = le32_to_cpu(*(__le32 *)key); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (interface->rssrk[i] == rssrk) 10898c2ecf20Sopenharmony_ci continue; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci interface->rssrk[i] = rssrk; 10928c2ecf20Sopenharmony_ci fm10k_write_reg(hw, FM10K_RSSRK(0, i), rssrk); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic unsigned int fm10k_max_channels(struct net_device *dev) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 11018c2ecf20Sopenharmony_ci unsigned int max_combined = interface->hw.mac.max_queues; 11028c2ecf20Sopenharmony_ci u8 tcs = netdev_get_num_tc(dev); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* For QoS report channels per traffic class */ 11058c2ecf20Sopenharmony_ci if (tcs > 1) 11068c2ecf20Sopenharmony_ci max_combined = BIT((fls(max_combined / tcs) - 1)); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return max_combined; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic void fm10k_get_channels(struct net_device *dev, 11128c2ecf20Sopenharmony_ci struct ethtool_channels *ch) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* report maximum channels */ 11178c2ecf20Sopenharmony_ci ch->max_combined = fm10k_max_channels(dev); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* report info for other vector */ 11208c2ecf20Sopenharmony_ci ch->max_other = NON_Q_VECTORS; 11218c2ecf20Sopenharmony_ci ch->other_count = ch->max_other; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* record RSS queues */ 11248c2ecf20Sopenharmony_ci ch->combined_count = interface->ring_feature[RING_F_RSS].indices; 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic int fm10k_set_channels(struct net_device *dev, 11288c2ecf20Sopenharmony_ci struct ethtool_channels *ch) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 11318c2ecf20Sopenharmony_ci unsigned int count = ch->combined_count; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* verify they are not requesting separate vectors */ 11348c2ecf20Sopenharmony_ci if (!count || ch->rx_count || ch->tx_count) 11358c2ecf20Sopenharmony_ci return -EINVAL; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* verify other_count has not changed */ 11388c2ecf20Sopenharmony_ci if (ch->other_count != NON_Q_VECTORS) 11398c2ecf20Sopenharmony_ci return -EINVAL; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* verify the number of channels does not exceed hardware limits */ 11428c2ecf20Sopenharmony_ci if (count > fm10k_max_channels(dev)) 11438c2ecf20Sopenharmony_ci return -EINVAL; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci interface->ring_feature[RING_F_RSS].limit = count; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* use setup TC to update any traffic class queue mapping */ 11488c2ecf20Sopenharmony_ci return fm10k_setup_tc(dev, netdev_get_num_tc(dev)); 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic const struct ethtool_ops fm10k_ethtool_ops = { 11528c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 11538c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE, 11548c2ecf20Sopenharmony_ci .get_strings = fm10k_get_strings, 11558c2ecf20Sopenharmony_ci .get_sset_count = fm10k_get_sset_count, 11568c2ecf20Sopenharmony_ci .get_ethtool_stats = fm10k_get_ethtool_stats, 11578c2ecf20Sopenharmony_ci .get_drvinfo = fm10k_get_drvinfo, 11588c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 11598c2ecf20Sopenharmony_ci .get_pauseparam = fm10k_get_pauseparam, 11608c2ecf20Sopenharmony_ci .set_pauseparam = fm10k_set_pauseparam, 11618c2ecf20Sopenharmony_ci .get_msglevel = fm10k_get_msglevel, 11628c2ecf20Sopenharmony_ci .set_msglevel = fm10k_set_msglevel, 11638c2ecf20Sopenharmony_ci .get_ringparam = fm10k_get_ringparam, 11648c2ecf20Sopenharmony_ci .set_ringparam = fm10k_set_ringparam, 11658c2ecf20Sopenharmony_ci .get_coalesce = fm10k_get_coalesce, 11668c2ecf20Sopenharmony_ci .set_coalesce = fm10k_set_coalesce, 11678c2ecf20Sopenharmony_ci .get_rxnfc = fm10k_get_rxnfc, 11688c2ecf20Sopenharmony_ci .set_rxnfc = fm10k_set_rxnfc, 11698c2ecf20Sopenharmony_ci .get_regs = fm10k_get_regs, 11708c2ecf20Sopenharmony_ci .get_regs_len = fm10k_get_regs_len, 11718c2ecf20Sopenharmony_ci .self_test = fm10k_self_test, 11728c2ecf20Sopenharmony_ci .get_priv_flags = fm10k_get_priv_flags, 11738c2ecf20Sopenharmony_ci .set_priv_flags = fm10k_set_priv_flags, 11748c2ecf20Sopenharmony_ci .get_rxfh_indir_size = fm10k_get_reta_size, 11758c2ecf20Sopenharmony_ci .get_rxfh_key_size = fm10k_get_rssrk_size, 11768c2ecf20Sopenharmony_ci .get_rxfh = fm10k_get_rssh, 11778c2ecf20Sopenharmony_ci .set_rxfh = fm10k_set_rssh, 11788c2ecf20Sopenharmony_ci .get_channels = fm10k_get_channels, 11798c2ecf20Sopenharmony_ci .set_channels = fm10k_set_channels, 11808c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 11818c2ecf20Sopenharmony_ci}; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_civoid fm10k_set_ethtool_ops(struct net_device *dev) 11848c2ecf20Sopenharmony_ci{ 11858c2ecf20Sopenharmony_ci dev->ethtool_ops = &fm10k_ethtool_ops; 11868c2ecf20Sopenharmony_ci} 1187