18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* QLogic qede NIC Driver 38c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/version.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/capability.h> 158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 168c2ecf20Sopenharmony_ci#include <linux/phylink.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "qede.h" 198c2ecf20Sopenharmony_ci#include "qede_ptp.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define QEDE_RQSTAT_OFFSET(stat_name) \ 228c2ecf20Sopenharmony_ci (offsetof(struct qede_rx_queue, stat_name)) 238c2ecf20Sopenharmony_ci#define QEDE_RQSTAT_STRING(stat_name) (#stat_name) 248c2ecf20Sopenharmony_ci#define QEDE_RQSTAT(stat_name) \ 258c2ecf20Sopenharmony_ci {QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define QEDE_SELFTEST_POLL_COUNT 100 288c2ecf20Sopenharmony_ci#define QEDE_DUMP_VERSION 0x1 298c2ecf20Sopenharmony_ci#define QEDE_DUMP_NVM_ARG_COUNT 2 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic const struct { 328c2ecf20Sopenharmony_ci u64 offset; 338c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 348c2ecf20Sopenharmony_ci} qede_rqstats_arr[] = { 358c2ecf20Sopenharmony_ci QEDE_RQSTAT(rcv_pkts), 368c2ecf20Sopenharmony_ci QEDE_RQSTAT(rx_hw_errors), 378c2ecf20Sopenharmony_ci QEDE_RQSTAT(rx_alloc_errors), 388c2ecf20Sopenharmony_ci QEDE_RQSTAT(rx_ip_frags), 398c2ecf20Sopenharmony_ci QEDE_RQSTAT(xdp_no_pass), 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr) 438c2ecf20Sopenharmony_ci#define QEDE_TQSTAT_OFFSET(stat_name) \ 448c2ecf20Sopenharmony_ci (offsetof(struct qede_tx_queue, stat_name)) 458c2ecf20Sopenharmony_ci#define QEDE_TQSTAT_STRING(stat_name) (#stat_name) 468c2ecf20Sopenharmony_ci#define QEDE_TQSTAT(stat_name) \ 478c2ecf20Sopenharmony_ci {QEDE_TQSTAT_OFFSET(stat_name), QEDE_TQSTAT_STRING(stat_name)} 488c2ecf20Sopenharmony_ci#define QEDE_NUM_TQSTATS ARRAY_SIZE(qede_tqstats_arr) 498c2ecf20Sopenharmony_cistatic const struct { 508c2ecf20Sopenharmony_ci u64 offset; 518c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 528c2ecf20Sopenharmony_ci} qede_tqstats_arr[] = { 538c2ecf20Sopenharmony_ci QEDE_TQSTAT(xmit_pkts), 548c2ecf20Sopenharmony_ci QEDE_TQSTAT(stopped_cnt), 558c2ecf20Sopenharmony_ci QEDE_TQSTAT(tx_mem_alloc_err), 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define QEDE_STAT_OFFSET(stat_name, type, base) \ 598c2ecf20Sopenharmony_ci (offsetof(type, stat_name) + (base)) 608c2ecf20Sopenharmony_ci#define QEDE_STAT_STRING(stat_name) (#stat_name) 618c2ecf20Sopenharmony_ci#define _QEDE_STAT(stat_name, type, base, attr) \ 628c2ecf20Sopenharmony_ci {QEDE_STAT_OFFSET(stat_name, type, base), \ 638c2ecf20Sopenharmony_ci QEDE_STAT_STRING(stat_name), \ 648c2ecf20Sopenharmony_ci attr} 658c2ecf20Sopenharmony_ci#define QEDE_STAT(stat_name) \ 668c2ecf20Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_common, 0, 0x0) 678c2ecf20Sopenharmony_ci#define QEDE_PF_STAT(stat_name) \ 688c2ecf20Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_common, 0, \ 698c2ecf20Sopenharmony_ci BIT(QEDE_STAT_PF_ONLY)) 708c2ecf20Sopenharmony_ci#define QEDE_PF_BB_STAT(stat_name) \ 718c2ecf20Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_bb, \ 728c2ecf20Sopenharmony_ci offsetof(struct qede_stats, bb), \ 738c2ecf20Sopenharmony_ci BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_BB_ONLY)) 748c2ecf20Sopenharmony_ci#define QEDE_PF_AH_STAT(stat_name) \ 758c2ecf20Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_ah, \ 768c2ecf20Sopenharmony_ci offsetof(struct qede_stats, ah), \ 778c2ecf20Sopenharmony_ci BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_AH_ONLY)) 788c2ecf20Sopenharmony_cistatic const struct { 798c2ecf20Sopenharmony_ci u64 offset; 808c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 818c2ecf20Sopenharmony_ci unsigned long attr; 828c2ecf20Sopenharmony_ci#define QEDE_STAT_PF_ONLY 0 838c2ecf20Sopenharmony_ci#define QEDE_STAT_BB_ONLY 1 848c2ecf20Sopenharmony_ci#define QEDE_STAT_AH_ONLY 2 858c2ecf20Sopenharmony_ci} qede_stats_arr[] = { 868c2ecf20Sopenharmony_ci QEDE_STAT(rx_ucast_bytes), 878c2ecf20Sopenharmony_ci QEDE_STAT(rx_mcast_bytes), 888c2ecf20Sopenharmony_ci QEDE_STAT(rx_bcast_bytes), 898c2ecf20Sopenharmony_ci QEDE_STAT(rx_ucast_pkts), 908c2ecf20Sopenharmony_ci QEDE_STAT(rx_mcast_pkts), 918c2ecf20Sopenharmony_ci QEDE_STAT(rx_bcast_pkts), 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci QEDE_STAT(tx_ucast_bytes), 948c2ecf20Sopenharmony_ci QEDE_STAT(tx_mcast_bytes), 958c2ecf20Sopenharmony_ci QEDE_STAT(tx_bcast_bytes), 968c2ecf20Sopenharmony_ci QEDE_STAT(tx_ucast_pkts), 978c2ecf20Sopenharmony_ci QEDE_STAT(tx_mcast_pkts), 988c2ecf20Sopenharmony_ci QEDE_STAT(tx_bcast_pkts), 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_64_byte_packets), 1018c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_65_to_127_byte_packets), 1028c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_128_to_255_byte_packets), 1038c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_256_to_511_byte_packets), 1048c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_512_to_1023_byte_packets), 1058c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_1024_to_1518_byte_packets), 1068c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(rx_1519_to_1522_byte_packets), 1078c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(rx_1519_to_2047_byte_packets), 1088c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(rx_2048_to_4095_byte_packets), 1098c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(rx_4096_to_9216_byte_packets), 1108c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(rx_9217_to_16383_byte_packets), 1118c2ecf20Sopenharmony_ci QEDE_PF_AH_STAT(rx_1519_to_max_byte_packets), 1128c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_64_byte_packets), 1138c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_65_to_127_byte_packets), 1148c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_128_to_255_byte_packets), 1158c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_256_to_511_byte_packets), 1168c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_512_to_1023_byte_packets), 1178c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_1024_to_1518_byte_packets), 1188c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(tx_1519_to_2047_byte_packets), 1198c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(tx_2048_to_4095_byte_packets), 1208c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(tx_4096_to_9216_byte_packets), 1218c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(tx_9217_to_16383_byte_packets), 1228c2ecf20Sopenharmony_ci QEDE_PF_AH_STAT(tx_1519_to_max_byte_packets), 1238c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_mac_crtl_frames), 1248c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_mac_ctrl_frames), 1258c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_pause_frames), 1268c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_pause_frames), 1278c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_pfc_frames), 1288c2ecf20Sopenharmony_ci QEDE_PF_STAT(tx_pfc_frames), 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_crc_errors), 1318c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_align_errors), 1328c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_carrier_errors), 1338c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_oversize_packets), 1348c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_jabbers), 1358c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_undersize_packets), 1368c2ecf20Sopenharmony_ci QEDE_PF_STAT(rx_fragments), 1378c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(tx_lpi_entry_count), 1388c2ecf20Sopenharmony_ci QEDE_PF_BB_STAT(tx_total_collisions), 1398c2ecf20Sopenharmony_ci QEDE_PF_STAT(brb_truncates), 1408c2ecf20Sopenharmony_ci QEDE_PF_STAT(brb_discards), 1418c2ecf20Sopenharmony_ci QEDE_STAT(no_buff_discards), 1428c2ecf20Sopenharmony_ci QEDE_PF_STAT(mftag_filter_discards), 1438c2ecf20Sopenharmony_ci QEDE_PF_STAT(mac_filter_discards), 1448c2ecf20Sopenharmony_ci QEDE_PF_STAT(gft_filter_drop), 1458c2ecf20Sopenharmony_ci QEDE_STAT(tx_err_drop_pkts), 1468c2ecf20Sopenharmony_ci QEDE_STAT(ttl0_discard), 1478c2ecf20Sopenharmony_ci QEDE_STAT(packet_too_big_discard), 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci QEDE_STAT(coalesced_pkts), 1508c2ecf20Sopenharmony_ci QEDE_STAT(coalesced_events), 1518c2ecf20Sopenharmony_ci QEDE_STAT(coalesced_aborts_num), 1528c2ecf20Sopenharmony_ci QEDE_STAT(non_coalesced_pkts), 1538c2ecf20Sopenharmony_ci QEDE_STAT(coalesced_bytes), 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci QEDE_STAT(link_change_count), 1568c2ecf20Sopenharmony_ci QEDE_STAT(ptp_skip_txts), 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define QEDE_NUM_STATS ARRAY_SIZE(qede_stats_arr) 1608c2ecf20Sopenharmony_ci#define QEDE_STAT_IS_PF_ONLY(i) \ 1618c2ecf20Sopenharmony_ci test_bit(QEDE_STAT_PF_ONLY, &qede_stats_arr[i].attr) 1628c2ecf20Sopenharmony_ci#define QEDE_STAT_IS_BB_ONLY(i) \ 1638c2ecf20Sopenharmony_ci test_bit(QEDE_STAT_BB_ONLY, &qede_stats_arr[i].attr) 1648c2ecf20Sopenharmony_ci#define QEDE_STAT_IS_AH_ONLY(i) \ 1658c2ecf20Sopenharmony_ci test_bit(QEDE_STAT_AH_ONLY, &qede_stats_arr[i].attr) 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cienum { 1688c2ecf20Sopenharmony_ci QEDE_PRI_FLAG_CMT, 1698c2ecf20Sopenharmony_ci QEDE_PRI_FLAG_SMART_AN_SUPPORT, /* MFW supports SmartAN */ 1708c2ecf20Sopenharmony_ci QEDE_PRI_FLAG_RECOVER_ON_ERROR, 1718c2ecf20Sopenharmony_ci QEDE_PRI_FLAG_LEN, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = { 1758c2ecf20Sopenharmony_ci "Coupled-Function", 1768c2ecf20Sopenharmony_ci "SmartAN capable", 1778c2ecf20Sopenharmony_ci "Recover on error", 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cienum qede_ethtool_tests { 1818c2ecf20Sopenharmony_ci QEDE_ETHTOOL_INT_LOOPBACK, 1828c2ecf20Sopenharmony_ci QEDE_ETHTOOL_INTERRUPT_TEST, 1838c2ecf20Sopenharmony_ci QEDE_ETHTOOL_MEMORY_TEST, 1848c2ecf20Sopenharmony_ci QEDE_ETHTOOL_REGISTER_TEST, 1858c2ecf20Sopenharmony_ci QEDE_ETHTOOL_CLOCK_TEST, 1868c2ecf20Sopenharmony_ci QEDE_ETHTOOL_NVRAM_TEST, 1878c2ecf20Sopenharmony_ci QEDE_ETHTOOL_TEST_MAX 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = { 1918c2ecf20Sopenharmony_ci "Internal loopback (offline)", 1928c2ecf20Sopenharmony_ci "Interrupt (online)\t", 1938c2ecf20Sopenharmony_ci "Memory (online)\t\t", 1948c2ecf20Sopenharmony_ci "Register (online)\t", 1958c2ecf20Sopenharmony_ci "Clock (online)\t\t", 1968c2ecf20Sopenharmony_ci "Nvram (online)\t\t", 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* Forced speed capabilities maps */ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistruct qede_forced_speed_map { 2028c2ecf20Sopenharmony_ci u32 speed; 2038c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(caps); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci const u32 *cap_arr; 2068c2ecf20Sopenharmony_ci u32 arr_size; 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#define QEDE_FORCED_SPEED_MAP(value) \ 2108c2ecf20Sopenharmony_ci{ \ 2118c2ecf20Sopenharmony_ci .speed = SPEED_##value, \ 2128c2ecf20Sopenharmony_ci .cap_arr = qede_forced_speed_##value, \ 2138c2ecf20Sopenharmony_ci .arr_size = ARRAY_SIZE(qede_forced_speed_##value), \ 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic const u32 qede_forced_speed_1000[] __initconst = { 2178c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 2188c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 2198c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic const u32 qede_forced_speed_10000[] __initconst = { 2238c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 2248c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 2258c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 2268c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 2278c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 2288c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 2298c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 2308c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic const u32 qede_forced_speed_20000[] __initconst = { 2348c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic const u32 qede_forced_speed_25000[] __initconst = { 2388c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 2398c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 2408c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 2418c2ecf20Sopenharmony_ci}; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic const u32 qede_forced_speed_40000[] __initconst = { 2448c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 2458c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 2468c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 2478c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic const u32 qede_forced_speed_50000[] __initconst = { 2518c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 2528c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 2538c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const u32 qede_forced_speed_100000[] __initconst = { 2578c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 2588c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 2598c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 2608c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 2618c2ecf20Sopenharmony_ci}; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic struct qede_forced_speed_map qede_forced_speed_maps[] __ro_after_init = { 2648c2ecf20Sopenharmony_ci QEDE_FORCED_SPEED_MAP(1000), 2658c2ecf20Sopenharmony_ci QEDE_FORCED_SPEED_MAP(10000), 2668c2ecf20Sopenharmony_ci QEDE_FORCED_SPEED_MAP(20000), 2678c2ecf20Sopenharmony_ci QEDE_FORCED_SPEED_MAP(25000), 2688c2ecf20Sopenharmony_ci QEDE_FORCED_SPEED_MAP(40000), 2698c2ecf20Sopenharmony_ci QEDE_FORCED_SPEED_MAP(50000), 2708c2ecf20Sopenharmony_ci QEDE_FORCED_SPEED_MAP(100000), 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_civoid __init qede_forced_speed_maps_init(void) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct qede_forced_speed_map *map; 2768c2ecf20Sopenharmony_ci u32 i; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qede_forced_speed_maps); i++) { 2798c2ecf20Sopenharmony_ci map = qede_forced_speed_maps + i; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps); 2828c2ecf20Sopenharmony_ci map->cap_arr = NULL; 2838c2ecf20Sopenharmony_ci map->arr_size = 0; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* Ethtool callbacks */ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void qede_get_strings_stats_txq(struct qede_dev *edev, 2908c2ecf20Sopenharmony_ci struct qede_tx_queue *txq, u8 **buf) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci int i; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_NUM_TQSTATS; i++) { 2958c2ecf20Sopenharmony_ci if (txq->is_xdp) 2968c2ecf20Sopenharmony_ci sprintf(*buf, "%d [XDP]: %s", 2978c2ecf20Sopenharmony_ci QEDE_TXQ_XDP_TO_IDX(edev, txq), 2988c2ecf20Sopenharmony_ci qede_tqstats_arr[i].string); 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci sprintf(*buf, "%d_%d: %s", txq->index, txq->cos, 3018c2ecf20Sopenharmony_ci qede_tqstats_arr[i].string); 3028c2ecf20Sopenharmony_ci *buf += ETH_GSTRING_LEN; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void qede_get_strings_stats_rxq(struct qede_dev *edev, 3078c2ecf20Sopenharmony_ci struct qede_rx_queue *rxq, u8 **buf) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int i; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_NUM_RQSTATS; i++) { 3128c2ecf20Sopenharmony_ci sprintf(*buf, "%d: %s", rxq->rxq_id, 3138c2ecf20Sopenharmony_ci qede_rqstats_arr[i].string); 3148c2ecf20Sopenharmony_ci *buf += ETH_GSTRING_LEN; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic bool qede_is_irrelevant_stat(struct qede_dev *edev, int stat_index) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci return (IS_VF(edev) && QEDE_STAT_IS_PF_ONLY(stat_index)) || 3218c2ecf20Sopenharmony_ci (QEDE_IS_BB(edev) && QEDE_STAT_IS_AH_ONLY(stat_index)) || 3228c2ecf20Sopenharmony_ci (QEDE_IS_AH(edev) && QEDE_STAT_IS_BB_ONLY(stat_index)); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic void qede_get_strings_stats(struct qede_dev *edev, u8 *buf) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 3288c2ecf20Sopenharmony_ci int i; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Account for queue statistics */ 3318c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) { 3328c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) 3358c2ecf20Sopenharmony_ci qede_get_strings_stats_rxq(edev, fp->rxq, &buf); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 3388c2ecf20Sopenharmony_ci qede_get_strings_stats_txq(edev, fp->xdp_tx, &buf); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 3418c2ecf20Sopenharmony_ci int cos; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) 3448c2ecf20Sopenharmony_ci qede_get_strings_stats_txq(edev, 3458c2ecf20Sopenharmony_ci &fp->txq[cos], &buf); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* Account for non-queue statistics */ 3508c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_NUM_STATS; i++) { 3518c2ecf20Sopenharmony_ci if (qede_is_irrelevant_stat(edev, i)) 3528c2ecf20Sopenharmony_ci continue; 3538c2ecf20Sopenharmony_ci strcpy(buf, qede_stats_arr[i].string); 3548c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci switch (stringset) { 3638c2ecf20Sopenharmony_ci case ETH_SS_STATS: 3648c2ecf20Sopenharmony_ci qede_get_strings_stats(edev, buf); 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 3678c2ecf20Sopenharmony_ci memcpy(buf, qede_private_arr, 3688c2ecf20Sopenharmony_ci ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN); 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case ETH_SS_TEST: 3718c2ecf20Sopenharmony_ci memcpy(buf, qede_tests_str_arr, 3728c2ecf20Sopenharmony_ci ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX); 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci default: 3758c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 3768c2ecf20Sopenharmony_ci "Unsupported stringset 0x%08x\n", stringset); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void qede_get_ethtool_stats_txq(struct qede_tx_queue *txq, u64 **buf) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int i; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_NUM_TQSTATS; i++) { 3858c2ecf20Sopenharmony_ci **buf = *((u64 *)(((void *)txq) + qede_tqstats_arr[i].offset)); 3868c2ecf20Sopenharmony_ci (*buf)++; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic void qede_get_ethtool_stats_rxq(struct qede_rx_queue *rxq, u64 **buf) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_NUM_RQSTATS; i++) { 3958c2ecf20Sopenharmony_ci **buf = *((u64 *)(((void *)rxq) + qede_rqstats_arr[i].offset)); 3968c2ecf20Sopenharmony_ci (*buf)++; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void qede_get_ethtool_stats(struct net_device *dev, 4018c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *buf) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4048c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 4058c2ecf20Sopenharmony_ci int i; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci qede_fill_by_demand_stats(edev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Need to protect the access to the fastpath array */ 4108c2ecf20Sopenharmony_ci __qede_lock(edev); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) { 4138c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) 4168c2ecf20Sopenharmony_ci qede_get_ethtool_stats_rxq(fp->rxq, &buf); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 4198c2ecf20Sopenharmony_ci qede_get_ethtool_stats_txq(fp->xdp_tx, &buf); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 4228c2ecf20Sopenharmony_ci int cos; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) 4258c2ecf20Sopenharmony_ci qede_get_ethtool_stats_txq(&fp->txq[cos], &buf); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci spin_lock(&edev->stats_lock); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_NUM_STATS; i++) { 4328c2ecf20Sopenharmony_ci if (qede_is_irrelevant_stat(edev, i)) 4338c2ecf20Sopenharmony_ci continue; 4348c2ecf20Sopenharmony_ci *buf = *((u64 *)(((void *)&edev->stats) + 4358c2ecf20Sopenharmony_ci qede_stats_arr[i].offset)); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci buf++; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci spin_unlock(&edev->stats_lock); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci __qede_unlock(edev); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int qede_get_sset_count(struct net_device *dev, int stringset) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4488c2ecf20Sopenharmony_ci int num_stats = QEDE_NUM_STATS, i; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci switch (stringset) { 4518c2ecf20Sopenharmony_ci case ETH_SS_STATS: 4528c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_NUM_STATS; i++) 4538c2ecf20Sopenharmony_ci if (qede_is_irrelevant_stat(edev, i)) 4548c2ecf20Sopenharmony_ci num_stats--; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Account for the Regular Tx statistics */ 4578c2ecf20Sopenharmony_ci num_stats += QEDE_TSS_COUNT(edev) * QEDE_NUM_TQSTATS * 4588c2ecf20Sopenharmony_ci edev->dev_info.num_tc; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* Account for the Regular Rx statistics */ 4618c2ecf20Sopenharmony_ci num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* Account for XDP statistics [if needed] */ 4648c2ecf20Sopenharmony_ci if (edev->xdp_prog) 4658c2ecf20Sopenharmony_ci num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_TQSTATS; 4668c2ecf20Sopenharmony_ci return num_stats; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 4698c2ecf20Sopenharmony_ci return QEDE_PRI_FLAG_LEN; 4708c2ecf20Sopenharmony_ci case ETH_SS_TEST: 4718c2ecf20Sopenharmony_ci if (!IS_VF(edev)) 4728c2ecf20Sopenharmony_ci return QEDE_ETHTOOL_TEST_MAX; 4738c2ecf20Sopenharmony_ci else 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci default: 4768c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 4778c2ecf20Sopenharmony_ci "Unsupported stringset 0x%08x\n", stringset); 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic u32 qede_get_priv_flags(struct net_device *dev) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4858c2ecf20Sopenharmony_ci u32 flags = 0; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (edev->dev_info.common.num_hwfns > 1) 4888c2ecf20Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_CMT); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (edev->dev_info.common.smart_an) 4918c2ecf20Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_SMART_AN_SUPPORT); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (edev->err_flags & BIT(QEDE_ERR_IS_RECOVERABLE)) 4948c2ecf20Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return flags; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic int qede_set_priv_flags(struct net_device *dev, u32 flags) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 5028c2ecf20Sopenharmony_ci u32 cflags = qede_get_priv_flags(dev); 5038c2ecf20Sopenharmony_ci u32 dflags = flags ^ cflags; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* can only change RECOVER_ON_ERROR flag */ 5068c2ecf20Sopenharmony_ci if (dflags & ~BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR)) 5078c2ecf20Sopenharmony_ci return -EINVAL; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (flags & BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR)) 5108c2ecf20Sopenharmony_ci set_bit(QEDE_ERR_IS_RECOVERABLE, &edev->err_flags); 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci clear_bit(QEDE_ERR_IS_RECOVERABLE, &edev->err_flags); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int qede_get_link_ksettings(struct net_device *dev, 5188c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci typeof(cmd->link_modes) *link_modes = &cmd->link_modes; 5218c2ecf20Sopenharmony_ci struct ethtool_link_settings *base = &cmd->base; 5228c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 5238c2ecf20Sopenharmony_ci struct qed_link_output current_link; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci __qede_lock(edev); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 5288c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci linkmode_copy(link_modes->supported, current_link.supported_caps); 5318c2ecf20Sopenharmony_ci linkmode_copy(link_modes->advertising, current_link.advertised_caps); 5328c2ecf20Sopenharmony_ci linkmode_copy(link_modes->lp_advertising, current_link.lp_caps); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) { 5358c2ecf20Sopenharmony_ci base->speed = current_link.speed; 5368c2ecf20Sopenharmony_ci base->duplex = current_link.duplex; 5378c2ecf20Sopenharmony_ci } else { 5388c2ecf20Sopenharmony_ci base->speed = SPEED_UNKNOWN; 5398c2ecf20Sopenharmony_ci base->duplex = DUPLEX_UNKNOWN; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci __qede_unlock(edev); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci base->port = current_link.port; 5458c2ecf20Sopenharmony_ci base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE : 5468c2ecf20Sopenharmony_ci AUTONEG_DISABLE; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int qede_set_link_ksettings(struct net_device *dev, 5528c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci const struct ethtool_link_settings *base = &cmd->base; 5558c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 5568c2ecf20Sopenharmony_ci const struct qede_forced_speed_map *map; 5578c2ecf20Sopenharmony_ci struct qed_link_output current_link; 5588c2ecf20Sopenharmony_ci struct qed_link_params params; 5598c2ecf20Sopenharmony_ci u32 i; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 5628c2ecf20Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 5638c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 5668c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 5678c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS; 5708c2ecf20Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (base->autoneg == AUTONEG_ENABLE) { 5738c2ecf20Sopenharmony_ci if (!phylink_test(current_link.supported_caps, Autoneg)) { 5748c2ecf20Sopenharmony_ci DP_INFO(edev, "Auto negotiation is not supported\n"); 5758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci params.autoneg = true; 5798c2ecf20Sopenharmony_ci params.forced_speed = 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci linkmode_copy(params.adv_speeds, cmd->link_modes.advertising); 5828c2ecf20Sopenharmony_ci } else { /* forced speed */ 5838c2ecf20Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED; 5848c2ecf20Sopenharmony_ci params.autoneg = false; 5858c2ecf20Sopenharmony_ci params.forced_speed = base->speed; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qede_forced_speed_maps); i++) { 5888c2ecf20Sopenharmony_ci map = qede_forced_speed_maps + i; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (base->speed != map->speed || 5918c2ecf20Sopenharmony_ci !linkmode_intersects(current_link.supported_caps, 5928c2ecf20Sopenharmony_ci map->caps)) 5938c2ecf20Sopenharmony_ci continue; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci linkmode_and(params.adv_speeds, 5968c2ecf20Sopenharmony_ci current_link.supported_caps, map->caps); 5978c2ecf20Sopenharmony_ci goto set_link; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci DP_INFO(edev, "Unsupported speed %u\n", base->speed); 6018c2ecf20Sopenharmony_ci return -EINVAL; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciset_link: 6058c2ecf20Sopenharmony_ci params.link_up = true; 6068c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic void qede_get_drvinfo(struct net_device *ndev, 6128c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN]; 6158c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 6168c2ecf20Sopenharmony_ci char mbi[ETHTOOL_FWVERS_LEN]; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci strlcpy(info->driver, "qede", sizeof(info->driver)); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d", 6218c2ecf20Sopenharmony_ci edev->dev_info.common.fw_major, 6228c2ecf20Sopenharmony_ci edev->dev_info.common.fw_minor, 6238c2ecf20Sopenharmony_ci edev->dev_info.common.fw_rev, 6248c2ecf20Sopenharmony_ci edev->dev_info.common.fw_eng); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci snprintf(mfw, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d", 6278c2ecf20Sopenharmony_ci (edev->dev_info.common.mfw_rev >> 24) & 0xFF, 6288c2ecf20Sopenharmony_ci (edev->dev_info.common.mfw_rev >> 16) & 0xFF, 6298c2ecf20Sopenharmony_ci (edev->dev_info.common.mfw_rev >> 8) & 0xFF, 6308c2ecf20Sopenharmony_ci edev->dev_info.common.mfw_rev & 0xFF); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if ((strlen(storm) + strlen(DRV_MODULE_VERSION) + strlen("[storm] ")) < 6338c2ecf20Sopenharmony_ci sizeof(info->version)) 6348c2ecf20Sopenharmony_ci snprintf(info->version, sizeof(info->version), 6358c2ecf20Sopenharmony_ci "%s [storm %s]", DRV_MODULE_VERSION, storm); 6368c2ecf20Sopenharmony_ci else 6378c2ecf20Sopenharmony_ci snprintf(info->version, sizeof(info->version), 6388c2ecf20Sopenharmony_ci "%s %s", DRV_MODULE_VERSION, storm); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (edev->dev_info.common.mbi_version) { 6418c2ecf20Sopenharmony_ci snprintf(mbi, ETHTOOL_FWVERS_LEN, "%d.%d.%d", 6428c2ecf20Sopenharmony_ci (edev->dev_info.common.mbi_version & 6438c2ecf20Sopenharmony_ci QED_MBI_VERSION_2_MASK) >> QED_MBI_VERSION_2_OFFSET, 6448c2ecf20Sopenharmony_ci (edev->dev_info.common.mbi_version & 6458c2ecf20Sopenharmony_ci QED_MBI_VERSION_1_MASK) >> QED_MBI_VERSION_1_OFFSET, 6468c2ecf20Sopenharmony_ci (edev->dev_info.common.mbi_version & 6478c2ecf20Sopenharmony_ci QED_MBI_VERSION_0_MASK) >> QED_MBI_VERSION_0_OFFSET); 6488c2ecf20Sopenharmony_ci snprintf(info->fw_version, sizeof(info->fw_version), 6498c2ecf20Sopenharmony_ci "mbi %s [mfw %s]", mbi, mfw); 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci snprintf(info->fw_version, sizeof(info->fw_version), 6528c2ecf20Sopenharmony_ci "mfw %s", mfw); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info)); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic void qede_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (edev->dev_info.common.wol_support) { 6638c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 6648c2ecf20Sopenharmony_ci wol->wolopts = edev->wol_enabled ? WAKE_MAGIC : 0; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic int qede_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 6718c2ecf20Sopenharmony_ci bool wol_requested; 6728c2ecf20Sopenharmony_ci int rc; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (wol->wolopts & ~WAKE_MAGIC) { 6758c2ecf20Sopenharmony_ci DP_INFO(edev, 6768c2ecf20Sopenharmony_ci "Can't support WoL options other than magic-packet\n"); 6778c2ecf20Sopenharmony_ci return -EINVAL; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci wol_requested = !!(wol->wolopts & WAKE_MAGIC); 6818c2ecf20Sopenharmony_ci if (wol_requested == edev->wol_enabled) 6828c2ecf20Sopenharmony_ci return 0; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Need to actually change configuration */ 6858c2ecf20Sopenharmony_ci if (!edev->dev_info.common.wol_support) { 6868c2ecf20Sopenharmony_ci DP_INFO(edev, "Device doesn't support WoL\n"); 6878c2ecf20Sopenharmony_ci return -EINVAL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci rc = edev->ops->common->update_wol(edev->cdev, wol_requested); 6918c2ecf20Sopenharmony_ci if (!rc) 6928c2ecf20Sopenharmony_ci edev->wol_enabled = wol_requested; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci return rc; 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic u32 qede_get_msglevel(struct net_device *ndev) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci return ((u32)edev->dp_level << QED_LOG_LEVEL_SHIFT) | edev->dp_module; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void qede_set_msglevel(struct net_device *ndev, u32 level) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 7078c2ecf20Sopenharmony_ci u32 dp_module = 0; 7088c2ecf20Sopenharmony_ci u8 dp_level = 0; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci qede_config_debug(level, &dp_module, &dp_level); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci edev->dp_level = dp_level; 7138c2ecf20Sopenharmony_ci edev->dp_module = dp_module; 7148c2ecf20Sopenharmony_ci edev->ops->common->update_msglvl(edev->cdev, 7158c2ecf20Sopenharmony_ci dp_module, dp_level); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int qede_nway_reset(struct net_device *dev) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 7218c2ecf20Sopenharmony_ci struct qed_link_output current_link; 7228c2ecf20Sopenharmony_ci struct qed_link_params link_params; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 7258c2ecf20Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 7268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (!netif_running(dev)) 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 7338c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 7348c2ecf20Sopenharmony_ci if (!current_link.link_up) 7358c2ecf20Sopenharmony_ci return 0; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Toggle the link */ 7388c2ecf20Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 7398c2ecf20Sopenharmony_ci link_params.link_up = false; 7408c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 7418c2ecf20Sopenharmony_ci link_params.link_up = true; 7428c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return 0; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic u32 qede_get_link(struct net_device *dev) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 7508c2ecf20Sopenharmony_ci struct qed_link_output current_link; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 7538c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return current_link.link_up; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int qede_flash_device(struct net_device *dev, 7598c2ecf20Sopenharmony_ci struct ethtool_flash *flash) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return edev->ops->common->nvm_flash(edev->cdev, flash->data); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int qede_get_coalesce(struct net_device *dev, 7678c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci void *rx_handle = NULL, *tx_handle = NULL; 7708c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 7718c2ecf20Sopenharmony_ci u16 rx_coal, tx_coal, i, rc = 0; 7728c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci rx_coal = QED_DEFAULT_RX_USECS; 7758c2ecf20Sopenharmony_ci tx_coal = QED_DEFAULT_TX_USECS; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci memset(coal, 0, sizeof(struct ethtool_coalesce)); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci __qede_lock(edev); 7808c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 7818c2ecf20Sopenharmony_ci for_each_queue(i) { 7828c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 7858c2ecf20Sopenharmony_ci rx_handle = fp->rxq->handle; 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci rc = edev->ops->get_coalesce(edev->cdev, &rx_coal, rx_handle); 7918c2ecf20Sopenharmony_ci if (rc) { 7928c2ecf20Sopenharmony_ci DP_INFO(edev, "Read Rx coalesce error\n"); 7938c2ecf20Sopenharmony_ci goto out; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci for_each_queue(i) { 7978c2ecf20Sopenharmony_ci struct qede_tx_queue *txq; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* All TX queues of given fastpath uses same 8028c2ecf20Sopenharmony_ci * coalescing value, so no need to iterate over 8038c2ecf20Sopenharmony_ci * all TCs, TC0 txq should suffice. 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 8068c2ecf20Sopenharmony_ci txq = QEDE_FP_TC0_TXQ(fp); 8078c2ecf20Sopenharmony_ci tx_handle = txq->handle; 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci rc = edev->ops->get_coalesce(edev->cdev, &tx_coal, tx_handle); 8138c2ecf20Sopenharmony_ci if (rc) 8148c2ecf20Sopenharmony_ci DP_INFO(edev, "Read Tx coalesce error\n"); 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ciout: 8188c2ecf20Sopenharmony_ci __qede_unlock(edev); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs = rx_coal; 8218c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs = tx_coal; 8228c2ecf20Sopenharmony_ci coal->stats_block_coalesce_usecs = edev->stats_coal_usecs; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci return rc; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic int qede_set_coalesce(struct net_device *dev, 8288c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 8318c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 8328c2ecf20Sopenharmony_ci int i, rc = 0; 8338c2ecf20Sopenharmony_ci u16 rxc, txc; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (edev->stats_coal_usecs != coal->stats_block_coalesce_usecs) { 8368c2ecf20Sopenharmony_ci edev->stats_coal_usecs = coal->stats_block_coalesce_usecs; 8378c2ecf20Sopenharmony_ci if (edev->stats_coal_usecs) { 8388c2ecf20Sopenharmony_ci edev->stats_coal_ticks = usecs_to_jiffies(edev->stats_coal_usecs); 8398c2ecf20Sopenharmony_ci schedule_delayed_work(&edev->periodic_task, 0); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci DP_INFO(edev, "Configured stats coal ticks=%lu jiffies\n", 8428c2ecf20Sopenharmony_ci edev->stats_coal_ticks); 8438c2ecf20Sopenharmony_ci } else { 8448c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&edev->periodic_task); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (!netif_running(dev)) { 8498c2ecf20Sopenharmony_ci DP_INFO(edev, "Interface is down\n"); 8508c2ecf20Sopenharmony_ci return -EINVAL; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (coal->rx_coalesce_usecs > QED_COALESCE_MAX || 8548c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs > QED_COALESCE_MAX) { 8558c2ecf20Sopenharmony_ci DP_INFO(edev, 8568c2ecf20Sopenharmony_ci "Can't support requested %s coalesce value [max supported value %d]\n", 8578c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx" : 8588c2ecf20Sopenharmony_ci "tx", QED_COALESCE_MAX); 8598c2ecf20Sopenharmony_ci return -EINVAL; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci rxc = (u16)coal->rx_coalesce_usecs; 8638c2ecf20Sopenharmony_ci txc = (u16)coal->tx_coalesce_usecs; 8648c2ecf20Sopenharmony_ci for_each_queue(i) { 8658c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_RX) { 8688c2ecf20Sopenharmony_ci rc = edev->ops->common->set_coalesce(edev->cdev, 8698c2ecf20Sopenharmony_ci rxc, 0, 8708c2ecf20Sopenharmony_ci fp->rxq->handle); 8718c2ecf20Sopenharmony_ci if (rc) { 8728c2ecf20Sopenharmony_ci DP_INFO(edev, 8738c2ecf20Sopenharmony_ci "Set RX coalesce error, rc = %d\n", rc); 8748c2ecf20Sopenharmony_ci return rc; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { 8798c2ecf20Sopenharmony_ci struct qede_tx_queue *txq; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* All TX queues of given fastpath uses same 8828c2ecf20Sopenharmony_ci * coalescing value, so no need to iterate over 8838c2ecf20Sopenharmony_ci * all TCs, TC0 txq should suffice. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci txq = QEDE_FP_TC0_TXQ(fp); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci rc = edev->ops->common->set_coalesce(edev->cdev, 8888c2ecf20Sopenharmony_ci 0, txc, 8898c2ecf20Sopenharmony_ci txq->handle); 8908c2ecf20Sopenharmony_ci if (rc) { 8918c2ecf20Sopenharmony_ci DP_INFO(edev, 8928c2ecf20Sopenharmony_ci "Set TX coalesce error, rc = %d\n", rc); 8938c2ecf20Sopenharmony_ci return rc; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci return rc; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic void qede_get_ringparam(struct net_device *dev, 9028c2ecf20Sopenharmony_ci struct ethtool_ringparam *ering) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci ering->rx_max_pending = NUM_RX_BDS_MAX; 9078c2ecf20Sopenharmony_ci ering->rx_pending = edev->q_num_rx_buffers; 9088c2ecf20Sopenharmony_ci ering->tx_max_pending = NUM_TX_BDS_MAX; 9098c2ecf20Sopenharmony_ci ering->tx_pending = edev->q_num_tx_buffers; 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic int qede_set_ringparam(struct net_device *dev, 9138c2ecf20Sopenharmony_ci struct ethtool_ringparam *ering) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 9188c2ecf20Sopenharmony_ci "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n", 9198c2ecf20Sopenharmony_ci ering->rx_pending, ering->tx_pending); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* Validate legality of configuration */ 9228c2ecf20Sopenharmony_ci if (ering->rx_pending > NUM_RX_BDS_MAX || 9238c2ecf20Sopenharmony_ci ering->rx_pending < NUM_RX_BDS_MIN || 9248c2ecf20Sopenharmony_ci ering->tx_pending > NUM_TX_BDS_MAX || 9258c2ecf20Sopenharmony_ci ering->tx_pending < NUM_TX_BDS_MIN) { 9268c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 9278c2ecf20Sopenharmony_ci "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n", 9288c2ecf20Sopenharmony_ci NUM_RX_BDS_MIN, NUM_RX_BDS_MAX, 9298c2ecf20Sopenharmony_ci NUM_TX_BDS_MIN, NUM_TX_BDS_MAX); 9308c2ecf20Sopenharmony_ci return -EINVAL; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* Change ring size and re-load */ 9348c2ecf20Sopenharmony_ci edev->q_num_rx_buffers = ering->rx_pending; 9358c2ecf20Sopenharmony_ci edev->q_num_tx_buffers = ering->tx_pending; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci qede_reload(edev, NULL, false); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic void qede_get_pauseparam(struct net_device *dev, 9438c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 9468c2ecf20Sopenharmony_ci struct qed_link_output current_link; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 9498c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 9528c2ecf20Sopenharmony_ci epause->autoneg = true; 9538c2ecf20Sopenharmony_ci if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE) 9548c2ecf20Sopenharmony_ci epause->rx_pause = true; 9558c2ecf20Sopenharmony_ci if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE) 9568c2ecf20Sopenharmony_ci epause->tx_pause = true; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 9598c2ecf20Sopenharmony_ci "ethtool_pauseparam: cmd %d autoneg %d rx_pause %d tx_pause %d\n", 9608c2ecf20Sopenharmony_ci epause->cmd, epause->autoneg, epause->rx_pause, 9618c2ecf20Sopenharmony_ci epause->tx_pause); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic int qede_set_pauseparam(struct net_device *dev, 9658c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 9688c2ecf20Sopenharmony_ci struct qed_link_params params; 9698c2ecf20Sopenharmony_ci struct qed_link_output current_link; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 9728c2ecf20Sopenharmony_ci DP_INFO(edev, 9738c2ecf20Sopenharmony_ci "Pause settings are not allowed to be changed\n"); 9748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 9788c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 9818c2ecf20Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (epause->autoneg) { 9848c2ecf20Sopenharmony_ci if (!phylink_test(current_link.supported_caps, Autoneg)) { 9858c2ecf20Sopenharmony_ci DP_INFO(edev, "autoneg not supported\n"); 9868c2ecf20Sopenharmony_ci return -EINVAL; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (epause->rx_pause) 9938c2ecf20Sopenharmony_ci params.pause_config |= QED_LINK_PAUSE_RX_ENABLE; 9948c2ecf20Sopenharmony_ci if (epause->tx_pause) 9958c2ecf20Sopenharmony_ci params.pause_config |= QED_LINK_PAUSE_TX_ENABLE; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci params.link_up = true; 9988c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci return 0; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic void qede_get_regs(struct net_device *ndev, 10048c2ecf20Sopenharmony_ci struct ethtool_regs *regs, void *buffer) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci regs->version = 0; 10098c2ecf20Sopenharmony_ci memset(buffer, 0, regs->len); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (edev->ops && edev->ops->common) 10128c2ecf20Sopenharmony_ci edev->ops->common->dbg_all_data(edev->cdev, buffer); 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic int qede_get_regs_len(struct net_device *ndev) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (edev->ops && edev->ops->common) 10208c2ecf20Sopenharmony_ci return edev->ops->common->dbg_all_data_size(edev->cdev); 10218c2ecf20Sopenharmony_ci else 10228c2ecf20Sopenharmony_ci return -EINVAL; 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic void qede_update_mtu(struct qede_dev *edev, 10268c2ecf20Sopenharmony_ci struct qede_reload_args *args) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci edev->ndev->mtu = args->u.mtu; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci/* Netdevice NDOs */ 10328c2ecf20Sopenharmony_ciint qede_change_mtu(struct net_device *ndev, int new_mtu) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 10358c2ecf20Sopenharmony_ci struct qede_reload_args args; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 10388c2ecf20Sopenharmony_ci "Configuring MTU size of %d\n", new_mtu); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (new_mtu > PAGE_SIZE) 10418c2ecf20Sopenharmony_ci ndev->features &= ~NETIF_F_GRO_HW; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* Set the mtu field and re-start the interface if needed */ 10448c2ecf20Sopenharmony_ci args.u.mtu = new_mtu; 10458c2ecf20Sopenharmony_ci args.func = &qede_update_mtu; 10468c2ecf20Sopenharmony_ci qede_reload(edev, &args, false); 10478c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_QED_RDMA) 10488c2ecf20Sopenharmony_ci qede_rdma_event_change_mtu(edev); 10498c2ecf20Sopenharmony_ci#endif 10508c2ecf20Sopenharmony_ci edev->ops->common->update_mtu(edev->cdev, new_mtu); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci return 0; 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic void qede_get_channels(struct net_device *dev, 10568c2ecf20Sopenharmony_ci struct ethtool_channels *channels) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci channels->max_combined = QEDE_MAX_RSS_CNT(edev); 10618c2ecf20Sopenharmony_ci channels->max_rx = QEDE_MAX_RSS_CNT(edev); 10628c2ecf20Sopenharmony_ci channels->max_tx = QEDE_MAX_RSS_CNT(edev); 10638c2ecf20Sopenharmony_ci channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx - 10648c2ecf20Sopenharmony_ci edev->fp_num_rx; 10658c2ecf20Sopenharmony_ci channels->tx_count = edev->fp_num_tx; 10668c2ecf20Sopenharmony_ci channels->rx_count = edev->fp_num_rx; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic int qede_set_channels(struct net_device *dev, 10708c2ecf20Sopenharmony_ci struct ethtool_channels *channels) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 10738c2ecf20Sopenharmony_ci u32 count; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 10768c2ecf20Sopenharmony_ci "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n", 10778c2ecf20Sopenharmony_ci channels->rx_count, channels->tx_count, 10788c2ecf20Sopenharmony_ci channels->other_count, channels->combined_count); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci count = channels->rx_count + channels->tx_count + 10818c2ecf20Sopenharmony_ci channels->combined_count; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* We don't support `other' channels */ 10848c2ecf20Sopenharmony_ci if (channels->other_count) { 10858c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 10868c2ecf20Sopenharmony_ci "command parameters not supported\n"); 10878c2ecf20Sopenharmony_ci return -EINVAL; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (!(channels->combined_count || (channels->rx_count && 10918c2ecf20Sopenharmony_ci channels->tx_count))) { 10928c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 10938c2ecf20Sopenharmony_ci "need to request at least one transmit and one receive channel\n"); 10948c2ecf20Sopenharmony_ci return -EINVAL; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (count > QEDE_MAX_RSS_CNT(edev)) { 10988c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 10998c2ecf20Sopenharmony_ci "requested channels = %d max supported channels = %d\n", 11008c2ecf20Sopenharmony_ci count, QEDE_MAX_RSS_CNT(edev)); 11018c2ecf20Sopenharmony_ci return -EINVAL; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* Check if there was a change in the active parameters */ 11058c2ecf20Sopenharmony_ci if ((count == QEDE_QUEUE_CNT(edev)) && 11068c2ecf20Sopenharmony_ci (channels->tx_count == edev->fp_num_tx) && 11078c2ecf20Sopenharmony_ci (channels->rx_count == edev->fp_num_rx)) { 11088c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 11098c2ecf20Sopenharmony_ci "No change in active parameters\n"); 11108c2ecf20Sopenharmony_ci return 0; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* We need the number of queues to be divisible between the hwfns */ 11148c2ecf20Sopenharmony_ci if ((count % edev->dev_info.common.num_hwfns) || 11158c2ecf20Sopenharmony_ci (channels->tx_count % edev->dev_info.common.num_hwfns) || 11168c2ecf20Sopenharmony_ci (channels->rx_count % edev->dev_info.common.num_hwfns)) { 11178c2ecf20Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 11188c2ecf20Sopenharmony_ci "Number of channels must be divisible by %04x\n", 11198c2ecf20Sopenharmony_ci edev->dev_info.common.num_hwfns); 11208c2ecf20Sopenharmony_ci return -EINVAL; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* Set number of queues and reload if necessary */ 11248c2ecf20Sopenharmony_ci edev->req_queues = count; 11258c2ecf20Sopenharmony_ci edev->req_num_tx = channels->tx_count; 11268c2ecf20Sopenharmony_ci edev->req_num_rx = channels->rx_count; 11278c2ecf20Sopenharmony_ci /* Reset the indirection table if rx queue count is updated */ 11288c2ecf20Sopenharmony_ci if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) { 11298c2ecf20Sopenharmony_ci edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED; 11308c2ecf20Sopenharmony_ci memset(edev->rss_ind_table, 0, sizeof(edev->rss_ind_table)); 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci qede_reload(edev, NULL, false); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic int qede_get_ts_info(struct net_device *dev, 11398c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci return qede_ptp_get_ts_info(edev, info); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic int qede_set_phys_id(struct net_device *dev, 11478c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 11508c2ecf20Sopenharmony_ci u8 led_state = 0; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci switch (state) { 11538c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 11548c2ecf20Sopenharmony_ci return 1; /* cycle on/off once per second */ 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci case ETHTOOL_ID_ON: 11578c2ecf20Sopenharmony_ci led_state = QED_LED_MODE_ON; 11588c2ecf20Sopenharmony_ci break; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci case ETHTOOL_ID_OFF: 11618c2ecf20Sopenharmony_ci led_state = QED_LED_MODE_OFF; 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 11658c2ecf20Sopenharmony_ci led_state = QED_LED_MODE_RESTORE; 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci edev->ops->common->set_led(edev->cdev, led_state); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return 0; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cistatic int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci switch (info->flow_type) { 11798c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 11808c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 11818c2ecf20Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 11848c2ecf20Sopenharmony_ci if (edev->rss_caps & QED_RSS_IPV4_UDP) 11858c2ecf20Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 11868c2ecf20Sopenharmony_ci break; 11878c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 11888c2ecf20Sopenharmony_ci if (edev->rss_caps & QED_RSS_IPV6_UDP) 11898c2ecf20Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 11908c2ecf20Sopenharmony_ci break; 11918c2ecf20Sopenharmony_ci case IPV4_FLOW: 11928c2ecf20Sopenharmony_ci case IPV6_FLOW: 11938c2ecf20Sopenharmony_ci break; 11948c2ecf20Sopenharmony_ci default: 11958c2ecf20Sopenharmony_ci info->data = 0; 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci return 0; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 12038c2ecf20Sopenharmony_ci u32 *rule_locs) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 12068c2ecf20Sopenharmony_ci int rc = 0; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci switch (info->cmd) { 12098c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 12108c2ecf20Sopenharmony_ci info->data = QEDE_RSS_COUNT(edev); 12118c2ecf20Sopenharmony_ci break; 12128c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 12138c2ecf20Sopenharmony_ci rc = qede_get_rss_flags(edev, info); 12148c2ecf20Sopenharmony_ci break; 12158c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 12168c2ecf20Sopenharmony_ci info->rule_cnt = qede_get_arfs_filter_count(edev); 12178c2ecf20Sopenharmony_ci info->data = QEDE_RFS_MAX_FLTR; 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 12208c2ecf20Sopenharmony_ci rc = qede_get_cls_rule_entry(edev, info); 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 12238c2ecf20Sopenharmony_ci rc = qede_get_cls_rule_all(edev, info, rule_locs); 12248c2ecf20Sopenharmony_ci break; 12258c2ecf20Sopenharmony_ci default: 12268c2ecf20Sopenharmony_ci DP_ERR(edev, "Command parameters not supported\n"); 12278c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci return rc; 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 12368c2ecf20Sopenharmony_ci u8 set_caps = 0, clr_caps = 0; 12378c2ecf20Sopenharmony_ci int rc = 0; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 12408c2ecf20Sopenharmony_ci "Set rss flags command parameters: flow type = %d, data = %llu\n", 12418c2ecf20Sopenharmony_ci info->flow_type, info->data); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci switch (info->flow_type) { 12448c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 12458c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 12468c2ecf20Sopenharmony_ci /* For TCP only 4-tuple hash is supported */ 12478c2ecf20Sopenharmony_ci if (info->data ^ (RXH_IP_SRC | RXH_IP_DST | 12488c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 12498c2ecf20Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 12508c2ecf20Sopenharmony_ci return -EINVAL; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci return 0; 12538c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 12548c2ecf20Sopenharmony_ci /* For UDP either 2-tuple hash or 4-tuple hash is supported */ 12558c2ecf20Sopenharmony_ci if (info->data == (RXH_IP_SRC | RXH_IP_DST | 12568c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 12578c2ecf20Sopenharmony_ci set_caps = QED_RSS_IPV4_UDP; 12588c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 12598c2ecf20Sopenharmony_ci "UDP 4-tuple enabled\n"); 12608c2ecf20Sopenharmony_ci } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) { 12618c2ecf20Sopenharmony_ci clr_caps = QED_RSS_IPV4_UDP; 12628c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 12638c2ecf20Sopenharmony_ci "UDP 4-tuple disabled\n"); 12648c2ecf20Sopenharmony_ci } else { 12658c2ecf20Sopenharmony_ci return -EINVAL; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci break; 12688c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 12698c2ecf20Sopenharmony_ci /* For UDP either 2-tuple hash or 4-tuple hash is supported */ 12708c2ecf20Sopenharmony_ci if (info->data == (RXH_IP_SRC | RXH_IP_DST | 12718c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 12728c2ecf20Sopenharmony_ci set_caps = QED_RSS_IPV6_UDP; 12738c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 12748c2ecf20Sopenharmony_ci "UDP 4-tuple enabled\n"); 12758c2ecf20Sopenharmony_ci } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) { 12768c2ecf20Sopenharmony_ci clr_caps = QED_RSS_IPV6_UDP; 12778c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 12788c2ecf20Sopenharmony_ci "UDP 4-tuple disabled\n"); 12798c2ecf20Sopenharmony_ci } else { 12808c2ecf20Sopenharmony_ci return -EINVAL; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci break; 12838c2ecf20Sopenharmony_ci case IPV4_FLOW: 12848c2ecf20Sopenharmony_ci case IPV6_FLOW: 12858c2ecf20Sopenharmony_ci /* For IP only 2-tuple hash is supported */ 12868c2ecf20Sopenharmony_ci if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) { 12878c2ecf20Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 12888c2ecf20Sopenharmony_ci return -EINVAL; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci return 0; 12918c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 12928c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 12938c2ecf20Sopenharmony_ci case AH_V4_FLOW: 12948c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 12958c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 12968c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 12978c2ecf20Sopenharmony_ci case AH_V6_FLOW: 12988c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 12998c2ecf20Sopenharmony_ci case IP_USER_FLOW: 13008c2ecf20Sopenharmony_ci case ETHER_FLOW: 13018c2ecf20Sopenharmony_ci /* RSS is not supported for these protocols */ 13028c2ecf20Sopenharmony_ci if (info->data) { 13038c2ecf20Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 13048c2ecf20Sopenharmony_ci return -EINVAL; 13058c2ecf20Sopenharmony_ci } 13068c2ecf20Sopenharmony_ci return 0; 13078c2ecf20Sopenharmony_ci default: 13088c2ecf20Sopenharmony_ci return -EINVAL; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* No action is needed if there is no change in the rss capability */ 13128c2ecf20Sopenharmony_ci if (edev->rss_caps == ((edev->rss_caps & ~clr_caps) | set_caps)) 13138c2ecf20Sopenharmony_ci return 0; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* Update internal configuration */ 13168c2ecf20Sopenharmony_ci edev->rss_caps = ((edev->rss_caps & ~clr_caps) | set_caps); 13178c2ecf20Sopenharmony_ci edev->rss_params_inited |= QEDE_RSS_CAPS_INITED; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* Re-configure if possible */ 13208c2ecf20Sopenharmony_ci __qede_lock(edev); 13218c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 13228c2ecf20Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 13238c2ecf20Sopenharmony_ci if (!vport_update_params) { 13248c2ecf20Sopenharmony_ci __qede_unlock(edev); 13258c2ecf20Sopenharmony_ci return -ENOMEM; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci qede_fill_rss_params(edev, &vport_update_params->rss_params, 13288c2ecf20Sopenharmony_ci &vport_update_params->update_rss_flg); 13298c2ecf20Sopenharmony_ci rc = edev->ops->vport_update(edev->cdev, vport_update_params); 13308c2ecf20Sopenharmony_ci vfree(vport_update_params); 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci __qede_unlock(edev); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci return rc; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 13408c2ecf20Sopenharmony_ci int rc; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci switch (info->cmd) { 13438c2ecf20Sopenharmony_ci case ETHTOOL_SRXFH: 13448c2ecf20Sopenharmony_ci rc = qede_set_rss_flags(edev, info); 13458c2ecf20Sopenharmony_ci break; 13468c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 13478c2ecf20Sopenharmony_ci rc = qede_add_cls_rule(edev, info); 13488c2ecf20Sopenharmony_ci break; 13498c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 13508c2ecf20Sopenharmony_ci rc = qede_delete_flow_filter(edev, info->fs.location); 13518c2ecf20Sopenharmony_ci break; 13528c2ecf20Sopenharmony_ci default: 13538c2ecf20Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 13548c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci return rc; 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic u32 qede_get_rxfh_indir_size(struct net_device *dev) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci return QED_RSS_IND_TABLE_SIZE; 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_cistatic u32 qede_get_rxfh_key_size(struct net_device *dev) 13668c2ecf20Sopenharmony_ci{ 13678c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci return sizeof(edev->rss_key); 13708c2ecf20Sopenharmony_ci} 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_cistatic int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc) 13738c2ecf20Sopenharmony_ci{ 13748c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 13758c2ecf20Sopenharmony_ci int i; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (hfunc) 13788c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (!indir) 13818c2ecf20Sopenharmony_ci return 0; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) 13848c2ecf20Sopenharmony_ci indir[i] = edev->rss_ind_table[i]; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (key) 13878c2ecf20Sopenharmony_ci memcpy(key, edev->rss_key, qede_get_rxfh_key_size(dev)); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci return 0; 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic int qede_set_rxfh(struct net_device *dev, const u32 *indir, 13938c2ecf20Sopenharmony_ci const u8 *key, const u8 hfunc) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 13968c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 13978c2ecf20Sopenharmony_ci int i, rc = 0; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (edev->dev_info.common.num_hwfns > 1) { 14008c2ecf20Sopenharmony_ci DP_INFO(edev, 14018c2ecf20Sopenharmony_ci "RSS configuration is not supported for 100G devices\n"); 14028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 14068c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (!indir && !key) 14098c2ecf20Sopenharmony_ci return 0; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (indir) { 14128c2ecf20Sopenharmony_ci for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) 14138c2ecf20Sopenharmony_ci edev->rss_ind_table[i] = indir[i]; 14148c2ecf20Sopenharmony_ci edev->rss_params_inited |= QEDE_RSS_INDIR_INITED; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci if (key) { 14188c2ecf20Sopenharmony_ci memcpy(&edev->rss_key, key, qede_get_rxfh_key_size(dev)); 14198c2ecf20Sopenharmony_ci edev->rss_params_inited |= QEDE_RSS_KEY_INITED; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci __qede_lock(edev); 14238c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 14248c2ecf20Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 14258c2ecf20Sopenharmony_ci if (!vport_update_params) { 14268c2ecf20Sopenharmony_ci __qede_unlock(edev); 14278c2ecf20Sopenharmony_ci return -ENOMEM; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci qede_fill_rss_params(edev, &vport_update_params->rss_params, 14308c2ecf20Sopenharmony_ci &vport_update_params->update_rss_flg); 14318c2ecf20Sopenharmony_ci rc = edev->ops->vport_update(edev->cdev, vport_update_params); 14328c2ecf20Sopenharmony_ci vfree(vport_update_params); 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci __qede_unlock(edev); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci return rc; 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci/* This function enables the interrupt generation and the NAPI on the device */ 14408c2ecf20Sopenharmony_cistatic void qede_netif_start(struct qede_dev *edev) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci int i; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (!netif_running(edev->ndev)) 14458c2ecf20Sopenharmony_ci return; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci for_each_queue(i) { 14488c2ecf20Sopenharmony_ci /* Update and reenable interrupts */ 14498c2ecf20Sopenharmony_ci qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_ENABLE, 1); 14508c2ecf20Sopenharmony_ci napi_enable(&edev->fp_array[i].napi); 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci/* This function disables the NAPI and the interrupt generation on the device */ 14558c2ecf20Sopenharmony_cistatic void qede_netif_stop(struct qede_dev *edev) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci int i; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci for_each_queue(i) { 14608c2ecf20Sopenharmony_ci napi_disable(&edev->fp_array[i].napi); 14618c2ecf20Sopenharmony_ci /* Disable interrupts */ 14628c2ecf20Sopenharmony_ci qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_DISABLE, 0); 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic int qede_selftest_transmit_traffic(struct qede_dev *edev, 14678c2ecf20Sopenharmony_ci struct sk_buff *skb) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci struct qede_tx_queue *txq = NULL; 14708c2ecf20Sopenharmony_ci struct eth_tx_1st_bd *first_bd; 14718c2ecf20Sopenharmony_ci dma_addr_t mapping; 14728c2ecf20Sopenharmony_ci int i, idx; 14738c2ecf20Sopenharmony_ci u16 val; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci for_each_queue(i) { 14768c2ecf20Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 14798c2ecf20Sopenharmony_ci txq = QEDE_FP_TC0_TXQ(fp); 14808c2ecf20Sopenharmony_ci break; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (!txq) { 14858c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Tx path is not available\n"); 14868c2ecf20Sopenharmony_ci return -1; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci /* Fill the entry in the SW ring and the BDs in the FW ring */ 14908c2ecf20Sopenharmony_ci idx = txq->sw_tx_prod; 14918c2ecf20Sopenharmony_ci txq->sw_tx_ring.skbs[idx].skb = skb; 14928c2ecf20Sopenharmony_ci first_bd = qed_chain_produce(&txq->tx_pbl); 14938c2ecf20Sopenharmony_ci memset(first_bd, 0, sizeof(*first_bd)); 14948c2ecf20Sopenharmony_ci val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT; 14958c2ecf20Sopenharmony_ci first_bd->data.bd_flags.bitfields = val; 14968c2ecf20Sopenharmony_ci val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK; 14978c2ecf20Sopenharmony_ci val = val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; 14988c2ecf20Sopenharmony_ci first_bd->data.bitfields |= cpu_to_le16(val); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* Map skb linear data for DMA and set in the first BD */ 15018c2ecf20Sopenharmony_ci mapping = dma_map_single(&edev->pdev->dev, skb->data, 15028c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 15038c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) { 15048c2ecf20Sopenharmony_ci DP_NOTICE(edev, "SKB mapping failed\n"); 15058c2ecf20Sopenharmony_ci return -ENOMEM; 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb)); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci /* update the first BD with the actual num BDs */ 15108c2ecf20Sopenharmony_ci first_bd->data.nbds = 1; 15118c2ecf20Sopenharmony_ci txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; 15128c2ecf20Sopenharmony_ci /* 'next page' entries are counted in the producer value */ 15138c2ecf20Sopenharmony_ci val = qed_chain_get_prod_idx(&txq->tx_pbl); 15148c2ecf20Sopenharmony_ci txq->tx_db.data.bd_prod = cpu_to_le16(val); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* wmb makes sure that the BDs data is updated before updating the 15178c2ecf20Sopenharmony_ci * producer, otherwise FW may read old data from the BDs. 15188c2ecf20Sopenharmony_ci */ 15198c2ecf20Sopenharmony_ci wmb(); 15208c2ecf20Sopenharmony_ci barrier(); 15218c2ecf20Sopenharmony_ci writel(txq->tx_db.raw, txq->doorbell_addr); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) { 15248c2ecf20Sopenharmony_ci if (qede_txq_has_work(txq)) 15258c2ecf20Sopenharmony_ci break; 15268c2ecf20Sopenharmony_ci usleep_range(100, 200); 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci if (!qede_txq_has_work(txq)) { 15308c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Tx completion didn't happen\n"); 15318c2ecf20Sopenharmony_ci return -1; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl); 15358c2ecf20Sopenharmony_ci dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), 15368c2ecf20Sopenharmony_ci BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); 15378c2ecf20Sopenharmony_ci txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; 15388c2ecf20Sopenharmony_ci txq->sw_tx_ring.skbs[idx].skb = NULL; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci return 0; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int qede_selftest_receive_traffic(struct qede_dev *edev) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci u16 sw_rx_index, len; 15468c2ecf20Sopenharmony_ci struct eth_fast_path_rx_reg_cqe *fp_cqe; 15478c2ecf20Sopenharmony_ci struct qede_rx_queue *rxq = NULL; 15488c2ecf20Sopenharmony_ci struct sw_rx_data *sw_rx_data; 15498c2ecf20Sopenharmony_ci union eth_rx_cqe *cqe; 15508c2ecf20Sopenharmony_ci int i, iter, rc = 0; 15518c2ecf20Sopenharmony_ci u8 *data_ptr; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci for_each_queue(i) { 15548c2ecf20Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_RX) { 15558c2ecf20Sopenharmony_ci rxq = edev->fp_array[i].rxq; 15568c2ecf20Sopenharmony_ci break; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (!rxq) { 15618c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Rx path is not available\n"); 15628c2ecf20Sopenharmony_ci return -1; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci /* The packet is expected to receive on rx-queue 0 even though RSS is 15668c2ecf20Sopenharmony_ci * enabled. This is because the queue 0 is configured as the default 15678c2ecf20Sopenharmony_ci * queue and that the loopback traffic is not IP. 15688c2ecf20Sopenharmony_ci */ 15698c2ecf20Sopenharmony_ci for (iter = 0; iter < QEDE_SELFTEST_POLL_COUNT; iter++) { 15708c2ecf20Sopenharmony_ci if (!qede_has_rx_work(rxq)) { 15718c2ecf20Sopenharmony_ci usleep_range(100, 200); 15728c2ecf20Sopenharmony_ci continue; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci /* Get the CQE from the completion ring */ 15768c2ecf20Sopenharmony_ci cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci /* Get the data from the SW ring */ 15798c2ecf20Sopenharmony_ci sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX; 15808c2ecf20Sopenharmony_ci sw_rx_data = &rxq->sw_rx_ring[sw_rx_index]; 15818c2ecf20Sopenharmony_ci fp_cqe = &cqe->fast_path_regular; 15828c2ecf20Sopenharmony_ci len = le16_to_cpu(fp_cqe->len_on_first_bd); 15838c2ecf20Sopenharmony_ci data_ptr = (u8 *)(page_address(sw_rx_data->data) + 15848c2ecf20Sopenharmony_ci fp_cqe->placement_offset + 15858c2ecf20Sopenharmony_ci sw_rx_data->page_offset + 15868c2ecf20Sopenharmony_ci rxq->rx_headroom); 15878c2ecf20Sopenharmony_ci if (ether_addr_equal(data_ptr, edev->ndev->dev_addr) && 15888c2ecf20Sopenharmony_ci ether_addr_equal(data_ptr + ETH_ALEN, 15898c2ecf20Sopenharmony_ci edev->ndev->dev_addr)) { 15908c2ecf20Sopenharmony_ci for (i = ETH_HLEN; i < len; i++) 15918c2ecf20Sopenharmony_ci if (data_ptr[i] != (unsigned char)(i & 0xff)) { 15928c2ecf20Sopenharmony_ci rc = -1; 15938c2ecf20Sopenharmony_ci break; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci qede_recycle_rx_bd_ring(rxq, 1); 15978c2ecf20Sopenharmony_ci qed_chain_recycle_consumed(&rxq->rx_comp_ring); 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci DP_INFO(edev, "Not the transmitted packet\n"); 16028c2ecf20Sopenharmony_ci qede_recycle_rx_bd_ring(rxq, 1); 16038c2ecf20Sopenharmony_ci qed_chain_recycle_consumed(&rxq->rx_comp_ring); 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (iter == QEDE_SELFTEST_POLL_COUNT) { 16078c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Failed to receive the traffic\n"); 16088c2ecf20Sopenharmony_ci return -1; 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci qede_update_rx_prod(edev, rxq); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci return rc; 16148c2ecf20Sopenharmony_ci} 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_cistatic int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci struct qed_link_params link_params; 16198c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 16208c2ecf20Sopenharmony_ci int rc = 0, i; 16218c2ecf20Sopenharmony_ci u32 pkt_size; 16228c2ecf20Sopenharmony_ci u8 *packet; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (!netif_running(edev->ndev)) { 16258c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Interface is down\n"); 16268c2ecf20Sopenharmony_ci return -EINVAL; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci qede_netif_stop(edev); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* Bring up the link in Loopback mode */ 16328c2ecf20Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 16338c2ecf20Sopenharmony_ci link_params.link_up = true; 16348c2ecf20Sopenharmony_ci link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE; 16358c2ecf20Sopenharmony_ci link_params.loopback_mode = loopback_mode; 16368c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci /* Wait for loopback configuration to apply */ 16398c2ecf20Sopenharmony_ci msleep_interruptible(500); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci /* Setting max packet size to 1.5K to avoid data being split over 16428c2ecf20Sopenharmony_ci * multiple BDs in cases where MTU > PAGE_SIZE. 16438c2ecf20Sopenharmony_ci */ 16448c2ecf20Sopenharmony_ci pkt_size = (((edev->ndev->mtu < ETH_DATA_LEN) ? 16458c2ecf20Sopenharmony_ci edev->ndev->mtu : ETH_DATA_LEN) + ETH_HLEN); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(edev->ndev, pkt_size); 16488c2ecf20Sopenharmony_ci if (!skb) { 16498c2ecf20Sopenharmony_ci DP_INFO(edev, "Can't allocate skb\n"); 16508c2ecf20Sopenharmony_ci rc = -ENOMEM; 16518c2ecf20Sopenharmony_ci goto test_loopback_exit; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci packet = skb_put(skb, pkt_size); 16548c2ecf20Sopenharmony_ci ether_addr_copy(packet, edev->ndev->dev_addr); 16558c2ecf20Sopenharmony_ci ether_addr_copy(packet + ETH_ALEN, edev->ndev->dev_addr); 16568c2ecf20Sopenharmony_ci memset(packet + (2 * ETH_ALEN), 0x77, (ETH_HLEN - (2 * ETH_ALEN))); 16578c2ecf20Sopenharmony_ci for (i = ETH_HLEN; i < pkt_size; i++) 16588c2ecf20Sopenharmony_ci packet[i] = (unsigned char)(i & 0xff); 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci rc = qede_selftest_transmit_traffic(edev, skb); 16618c2ecf20Sopenharmony_ci if (rc) 16628c2ecf20Sopenharmony_ci goto test_loopback_exit; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci rc = qede_selftest_receive_traffic(edev); 16658c2ecf20Sopenharmony_ci if (rc) 16668c2ecf20Sopenharmony_ci goto test_loopback_exit; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_RX_STATUS, "Loopback test successful\n"); 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_citest_loopback_exit: 16718c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci /* Bring up the link in Normal mode */ 16748c2ecf20Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 16758c2ecf20Sopenharmony_ci link_params.link_up = true; 16768c2ecf20Sopenharmony_ci link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE; 16778c2ecf20Sopenharmony_ci link_params.loopback_mode = QED_LINK_LOOPBACK_NONE; 16788c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* Wait for loopback configuration to apply */ 16818c2ecf20Sopenharmony_ci msleep_interruptible(500); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci qede_netif_start(edev); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci return rc; 16868c2ecf20Sopenharmony_ci} 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cistatic void qede_self_test(struct net_device *dev, 16898c2ecf20Sopenharmony_ci struct ethtool_test *etest, u64 *buf) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 16948c2ecf20Sopenharmony_ci "Self-test command parameters: offline = %d, external_lb = %d\n", 16958c2ecf20Sopenharmony_ci (etest->flags & ETH_TEST_FL_OFFLINE), 16968c2ecf20Sopenharmony_ci (etest->flags & ETH_TEST_FL_EXTERNAL_LB) >> 2); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(u64) * QEDE_ETHTOOL_TEST_MAX); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci if (etest->flags & ETH_TEST_FL_OFFLINE) { 17018c2ecf20Sopenharmony_ci if (qede_selftest_run_loopback(edev, 17028c2ecf20Sopenharmony_ci QED_LINK_LOOPBACK_INT_PHY)) { 17038c2ecf20Sopenharmony_ci buf[QEDE_ETHTOOL_INT_LOOPBACK] = 1; 17048c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (edev->ops->common->selftest->selftest_interrupt(edev->cdev)) { 17098c2ecf20Sopenharmony_ci buf[QEDE_ETHTOOL_INTERRUPT_TEST] = 1; 17108c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (edev->ops->common->selftest->selftest_memory(edev->cdev)) { 17148c2ecf20Sopenharmony_ci buf[QEDE_ETHTOOL_MEMORY_TEST] = 1; 17158c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (edev->ops->common->selftest->selftest_register(edev->cdev)) { 17198c2ecf20Sopenharmony_ci buf[QEDE_ETHTOOL_REGISTER_TEST] = 1; 17208c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (edev->ops->common->selftest->selftest_clock(edev->cdev)) { 17248c2ecf20Sopenharmony_ci buf[QEDE_ETHTOOL_CLOCK_TEST] = 1; 17258c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci if (edev->ops->common->selftest->selftest_nvram(edev->cdev)) { 17298c2ecf20Sopenharmony_ci buf[QEDE_ETHTOOL_NVRAM_TEST] = 1; 17308c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_cistatic int qede_set_tunable(struct net_device *dev, 17358c2ecf20Sopenharmony_ci const struct ethtool_tunable *tuna, 17368c2ecf20Sopenharmony_ci const void *data) 17378c2ecf20Sopenharmony_ci{ 17388c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 17398c2ecf20Sopenharmony_ci u32 val; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci switch (tuna->id) { 17428c2ecf20Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 17438c2ecf20Sopenharmony_ci val = *(u32 *)data; 17448c2ecf20Sopenharmony_ci if (val < QEDE_MIN_PKT_LEN || val > QEDE_RX_HDR_SIZE) { 17458c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 17468c2ecf20Sopenharmony_ci "Invalid rx copy break value, range is [%u, %u]", 17478c2ecf20Sopenharmony_ci QEDE_MIN_PKT_LEN, QEDE_RX_HDR_SIZE); 17488c2ecf20Sopenharmony_ci return -EINVAL; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci edev->rx_copybreak = *(u32 *)data; 17528c2ecf20Sopenharmony_ci break; 17538c2ecf20Sopenharmony_ci default: 17548c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci return 0; 17588c2ecf20Sopenharmony_ci} 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_cistatic int qede_get_tunable(struct net_device *dev, 17618c2ecf20Sopenharmony_ci const struct ethtool_tunable *tuna, void *data) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci switch (tuna->id) { 17668c2ecf20Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 17678c2ecf20Sopenharmony_ci *(u32 *)data = edev->rx_copybreak; 17688c2ecf20Sopenharmony_ci break; 17698c2ecf20Sopenharmony_ci default: 17708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci return 0; 17748c2ecf20Sopenharmony_ci} 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_cistatic int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata) 17778c2ecf20Sopenharmony_ci{ 17788c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 17798c2ecf20Sopenharmony_ci struct qed_link_output current_link; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 17828c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (!current_link.eee_supported) { 17858c2ecf20Sopenharmony_ci DP_INFO(edev, "EEE is not supported\n"); 17868c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (current_link.eee.adv_caps & QED_EEE_1G_ADV) 17908c2ecf20Sopenharmony_ci edata->advertised = ADVERTISED_1000baseT_Full; 17918c2ecf20Sopenharmony_ci if (current_link.eee.adv_caps & QED_EEE_10G_ADV) 17928c2ecf20Sopenharmony_ci edata->advertised |= ADVERTISED_10000baseT_Full; 17938c2ecf20Sopenharmony_ci if (current_link.sup_caps & QED_EEE_1G_ADV) 17948c2ecf20Sopenharmony_ci edata->supported = ADVERTISED_1000baseT_Full; 17958c2ecf20Sopenharmony_ci if (current_link.sup_caps & QED_EEE_10G_ADV) 17968c2ecf20Sopenharmony_ci edata->supported |= ADVERTISED_10000baseT_Full; 17978c2ecf20Sopenharmony_ci if (current_link.eee.lp_adv_caps & QED_EEE_1G_ADV) 17988c2ecf20Sopenharmony_ci edata->lp_advertised = ADVERTISED_1000baseT_Full; 17998c2ecf20Sopenharmony_ci if (current_link.eee.lp_adv_caps & QED_EEE_10G_ADV) 18008c2ecf20Sopenharmony_ci edata->lp_advertised |= ADVERTISED_10000baseT_Full; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci edata->tx_lpi_timer = current_link.eee.tx_lpi_timer; 18038c2ecf20Sopenharmony_ci edata->eee_enabled = current_link.eee.enable; 18048c2ecf20Sopenharmony_ci edata->tx_lpi_enabled = current_link.eee.tx_lpi_enable; 18058c2ecf20Sopenharmony_ci edata->eee_active = current_link.eee_active; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci return 0; 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_cistatic int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 18138c2ecf20Sopenharmony_ci struct qed_link_output current_link; 18148c2ecf20Sopenharmony_ci struct qed_link_params params; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (!edev->ops->common->can_link_change(edev->cdev)) { 18178c2ecf20Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 18188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 18228c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci if (!current_link.eee_supported) { 18258c2ecf20Sopenharmony_ci DP_INFO(edev, "EEE is not supported\n"); 18268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 18308c2ecf20Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_EEE_CONFIG; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci if (!(edata->advertised & (ADVERTISED_1000baseT_Full | 18338c2ecf20Sopenharmony_ci ADVERTISED_10000baseT_Full)) || 18348c2ecf20Sopenharmony_ci ((edata->advertised & (ADVERTISED_1000baseT_Full | 18358c2ecf20Sopenharmony_ci ADVERTISED_10000baseT_Full)) != 18368c2ecf20Sopenharmony_ci edata->advertised)) { 18378c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 18388c2ecf20Sopenharmony_ci "Invalid advertised capabilities %d\n", 18398c2ecf20Sopenharmony_ci edata->advertised); 18408c2ecf20Sopenharmony_ci return -EINVAL; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci if (edata->advertised & ADVERTISED_1000baseT_Full) 18448c2ecf20Sopenharmony_ci params.eee.adv_caps = QED_EEE_1G_ADV; 18458c2ecf20Sopenharmony_ci if (edata->advertised & ADVERTISED_10000baseT_Full) 18468c2ecf20Sopenharmony_ci params.eee.adv_caps |= QED_EEE_10G_ADV; 18478c2ecf20Sopenharmony_ci params.eee.enable = edata->eee_enabled; 18488c2ecf20Sopenharmony_ci params.eee.tx_lpi_enable = edata->tx_lpi_enabled; 18498c2ecf20Sopenharmony_ci params.eee.tx_lpi_timer = edata->tx_lpi_timer; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci params.link_up = true; 18528c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci return 0; 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_cistatic u32 qede_link_to_ethtool_fec(u32 link_fec) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci u32 eth_fec = 0; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (link_fec & QED_FEC_MODE_NONE) 18628c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_OFF; 18638c2ecf20Sopenharmony_ci if (link_fec & QED_FEC_MODE_FIRECODE) 18648c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_BASER; 18658c2ecf20Sopenharmony_ci if (link_fec & QED_FEC_MODE_RS) 18668c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_RS; 18678c2ecf20Sopenharmony_ci if (link_fec & QED_FEC_MODE_AUTO) 18688c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_AUTO; 18698c2ecf20Sopenharmony_ci if (link_fec & QED_FEC_MODE_UNSUPPORTED) 18708c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_NONE; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci return eth_fec; 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_cistatic u32 qede_ethtool_to_link_fec(u32 eth_fec) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci u32 link_fec = 0; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_OFF) 18808c2ecf20Sopenharmony_ci link_fec |= QED_FEC_MODE_NONE; 18818c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_BASER) 18828c2ecf20Sopenharmony_ci link_fec |= QED_FEC_MODE_FIRECODE; 18838c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_RS) 18848c2ecf20Sopenharmony_ci link_fec |= QED_FEC_MODE_RS; 18858c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_AUTO) 18868c2ecf20Sopenharmony_ci link_fec |= QED_FEC_MODE_AUTO; 18878c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_NONE) 18888c2ecf20Sopenharmony_ci link_fec |= QED_FEC_MODE_UNSUPPORTED; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci return link_fec; 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic int qede_get_fecparam(struct net_device *dev, 18948c2ecf20Sopenharmony_ci struct ethtool_fecparam *fecparam) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 18978c2ecf20Sopenharmony_ci struct qed_link_output curr_link; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci memset(&curr_link, 0, sizeof(curr_link)); 19008c2ecf20Sopenharmony_ci edev->ops->common->get_link(edev->cdev, &curr_link); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci fecparam->active_fec = qede_link_to_ethtool_fec(curr_link.active_fec); 19038c2ecf20Sopenharmony_ci fecparam->fec = qede_link_to_ethtool_fec(curr_link.sup_fec); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci return 0; 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic int qede_set_fecparam(struct net_device *dev, 19098c2ecf20Sopenharmony_ci struct ethtool_fecparam *fecparam) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 19128c2ecf20Sopenharmony_ci struct qed_link_params params; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 19158c2ecf20Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 19168c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 19208c2ecf20Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_FEC_CONFIG; 19218c2ecf20Sopenharmony_ci params.fec = qede_ethtool_to_link_fec(fecparam->fec); 19228c2ecf20Sopenharmony_ci params.link_up = true; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci return 0; 19278c2ecf20Sopenharmony_ci} 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_cistatic int qede_get_module_info(struct net_device *dev, 19308c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 19318c2ecf20Sopenharmony_ci{ 19328c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 19338c2ecf20Sopenharmony_ci u8 buf[4]; 19348c2ecf20Sopenharmony_ci int rc; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* Read first 4 bytes to find the sfp type */ 19378c2ecf20Sopenharmony_ci rc = edev->ops->common->read_module_eeprom(edev->cdev, buf, 19388c2ecf20Sopenharmony_ci QED_I2C_DEV_ADDR_A0, 0, 4); 19398c2ecf20Sopenharmony_ci if (rc) { 19408c2ecf20Sopenharmony_ci DP_ERR(edev, "Failed reading EEPROM data %d\n", rc); 19418c2ecf20Sopenharmony_ci return rc; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci switch (buf[0]) { 19458c2ecf20Sopenharmony_ci case 0x3: /* SFP, SFP+, SFP-28 */ 19468c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 19478c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 19488c2ecf20Sopenharmony_ci break; 19498c2ecf20Sopenharmony_ci case 0xc: /* QSFP */ 19508c2ecf20Sopenharmony_ci case 0xd: /* QSFP+ */ 19518c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 19528c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 19538c2ecf20Sopenharmony_ci break; 19548c2ecf20Sopenharmony_ci case 0x11: /* QSFP-28 */ 19558c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 19568c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 19578c2ecf20Sopenharmony_ci break; 19588c2ecf20Sopenharmony_ci default: 19598c2ecf20Sopenharmony_ci DP_ERR(edev, "Unknown transceiver type 0x%x\n", buf[0]); 19608c2ecf20Sopenharmony_ci return -EINVAL; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci return 0; 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cistatic int qede_get_module_eeprom(struct net_device *dev, 19678c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 19688c2ecf20Sopenharmony_ci{ 19698c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 19708c2ecf20Sopenharmony_ci u32 start_addr = ee->offset, size = 0; 19718c2ecf20Sopenharmony_ci u8 *buf = data; 19728c2ecf20Sopenharmony_ci int rc = 0; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* Read A0 section */ 19758c2ecf20Sopenharmony_ci if (ee->offset < ETH_MODULE_SFF_8079_LEN) { 19768c2ecf20Sopenharmony_ci /* Limit transfer size to the A0 section boundary */ 19778c2ecf20Sopenharmony_ci if (ee->offset + ee->len > ETH_MODULE_SFF_8079_LEN) 19788c2ecf20Sopenharmony_ci size = ETH_MODULE_SFF_8079_LEN - ee->offset; 19798c2ecf20Sopenharmony_ci else 19808c2ecf20Sopenharmony_ci size = ee->len; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci rc = edev->ops->common->read_module_eeprom(edev->cdev, buf, 19838c2ecf20Sopenharmony_ci QED_I2C_DEV_ADDR_A0, 19848c2ecf20Sopenharmony_ci start_addr, size); 19858c2ecf20Sopenharmony_ci if (rc) { 19868c2ecf20Sopenharmony_ci DP_ERR(edev, "Failed reading A0 section %d\n", rc); 19878c2ecf20Sopenharmony_ci return rc; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci buf += size; 19918c2ecf20Sopenharmony_ci start_addr += size; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci /* Read A2 section */ 19958c2ecf20Sopenharmony_ci if (start_addr >= ETH_MODULE_SFF_8079_LEN && 19968c2ecf20Sopenharmony_ci start_addr < ETH_MODULE_SFF_8472_LEN) { 19978c2ecf20Sopenharmony_ci size = ee->len - size; 19988c2ecf20Sopenharmony_ci /* Limit transfer size to the A2 section boundary */ 19998c2ecf20Sopenharmony_ci if (start_addr + size > ETH_MODULE_SFF_8472_LEN) 20008c2ecf20Sopenharmony_ci size = ETH_MODULE_SFF_8472_LEN - start_addr; 20018c2ecf20Sopenharmony_ci start_addr -= ETH_MODULE_SFF_8079_LEN; 20028c2ecf20Sopenharmony_ci rc = edev->ops->common->read_module_eeprom(edev->cdev, buf, 20038c2ecf20Sopenharmony_ci QED_I2C_DEV_ADDR_A2, 20048c2ecf20Sopenharmony_ci start_addr, size); 20058c2ecf20Sopenharmony_ci if (rc) { 20068c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 20078c2ecf20Sopenharmony_ci "Failed reading A2 section %d\n", rc); 20088c2ecf20Sopenharmony_ci return 0; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci return rc; 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_cistatic int qede_set_dump(struct net_device *dev, struct ethtool_dump *val) 20168c2ecf20Sopenharmony_ci{ 20178c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 20188c2ecf20Sopenharmony_ci int rc = 0; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (edev->dump_info.cmd == QEDE_DUMP_CMD_NONE) { 20218c2ecf20Sopenharmony_ci if (val->flag > QEDE_DUMP_CMD_MAX) { 20228c2ecf20Sopenharmony_ci DP_ERR(edev, "Invalid command %d\n", val->flag); 20238c2ecf20Sopenharmony_ci return -EINVAL; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci edev->dump_info.cmd = val->flag; 20268c2ecf20Sopenharmony_ci edev->dump_info.num_args = 0; 20278c2ecf20Sopenharmony_ci return 0; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci if (edev->dump_info.num_args == QEDE_DUMP_MAX_ARGS) { 20318c2ecf20Sopenharmony_ci DP_ERR(edev, "Arg count = %d\n", edev->dump_info.num_args); 20328c2ecf20Sopenharmony_ci return -EINVAL; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci switch (edev->dump_info.cmd) { 20368c2ecf20Sopenharmony_ci case QEDE_DUMP_CMD_NVM_CFG: 20378c2ecf20Sopenharmony_ci edev->dump_info.args[edev->dump_info.num_args] = val->flag; 20388c2ecf20Sopenharmony_ci edev->dump_info.num_args++; 20398c2ecf20Sopenharmony_ci break; 20408c2ecf20Sopenharmony_ci case QEDE_DUMP_CMD_GRCDUMP: 20418c2ecf20Sopenharmony_ci rc = edev->ops->common->set_grc_config(edev->cdev, 20428c2ecf20Sopenharmony_ci val->flag, 1); 20438c2ecf20Sopenharmony_ci break; 20448c2ecf20Sopenharmony_ci default: 20458c2ecf20Sopenharmony_ci break; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci return rc; 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cistatic int qede_get_dump_flag(struct net_device *dev, 20528c2ecf20Sopenharmony_ci struct ethtool_dump *dump) 20538c2ecf20Sopenharmony_ci{ 20548c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci if (!edev->ops || !edev->ops->common) { 20578c2ecf20Sopenharmony_ci DP_ERR(edev, "Edev ops not populated\n"); 20588c2ecf20Sopenharmony_ci return -EINVAL; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci dump->version = QEDE_DUMP_VERSION; 20628c2ecf20Sopenharmony_ci switch (edev->dump_info.cmd) { 20638c2ecf20Sopenharmony_ci case QEDE_DUMP_CMD_NVM_CFG: 20648c2ecf20Sopenharmony_ci dump->flag = QEDE_DUMP_CMD_NVM_CFG; 20658c2ecf20Sopenharmony_ci dump->len = edev->ops->common->read_nvm_cfg_len(edev->cdev, 20668c2ecf20Sopenharmony_ci edev->dump_info.args[0]); 20678c2ecf20Sopenharmony_ci break; 20688c2ecf20Sopenharmony_ci case QEDE_DUMP_CMD_GRCDUMP: 20698c2ecf20Sopenharmony_ci dump->flag = QEDE_DUMP_CMD_GRCDUMP; 20708c2ecf20Sopenharmony_ci dump->len = edev->ops->common->dbg_all_data_size(edev->cdev); 20718c2ecf20Sopenharmony_ci break; 20728c2ecf20Sopenharmony_ci default: 20738c2ecf20Sopenharmony_ci DP_ERR(edev, "Invalid cmd = %d\n", edev->dump_info.cmd); 20748c2ecf20Sopenharmony_ci return -EINVAL; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 20788c2ecf20Sopenharmony_ci "dump->version = 0x%x dump->flag = %d dump->len = %d\n", 20798c2ecf20Sopenharmony_ci dump->version, dump->flag, dump->len); 20808c2ecf20Sopenharmony_ci return 0; 20818c2ecf20Sopenharmony_ci} 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic int qede_get_dump_data(struct net_device *dev, 20848c2ecf20Sopenharmony_ci struct ethtool_dump *dump, void *buf) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 20878c2ecf20Sopenharmony_ci int rc = 0; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (!edev->ops || !edev->ops->common) { 20908c2ecf20Sopenharmony_ci DP_ERR(edev, "Edev ops not populated\n"); 20918c2ecf20Sopenharmony_ci rc = -EINVAL; 20928c2ecf20Sopenharmony_ci goto err; 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci switch (edev->dump_info.cmd) { 20968c2ecf20Sopenharmony_ci case QEDE_DUMP_CMD_NVM_CFG: 20978c2ecf20Sopenharmony_ci if (edev->dump_info.num_args != QEDE_DUMP_NVM_ARG_COUNT) { 20988c2ecf20Sopenharmony_ci DP_ERR(edev, "Arg count = %d required = %d\n", 20998c2ecf20Sopenharmony_ci edev->dump_info.num_args, 21008c2ecf20Sopenharmony_ci QEDE_DUMP_NVM_ARG_COUNT); 21018c2ecf20Sopenharmony_ci rc = -EINVAL; 21028c2ecf20Sopenharmony_ci goto err; 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci rc = edev->ops->common->read_nvm_cfg(edev->cdev, (u8 **)&buf, 21058c2ecf20Sopenharmony_ci edev->dump_info.args[0], 21068c2ecf20Sopenharmony_ci edev->dump_info.args[1]); 21078c2ecf20Sopenharmony_ci break; 21088c2ecf20Sopenharmony_ci case QEDE_DUMP_CMD_GRCDUMP: 21098c2ecf20Sopenharmony_ci memset(buf, 0, dump->len); 21108c2ecf20Sopenharmony_ci rc = edev->ops->common->dbg_all_data(edev->cdev, buf); 21118c2ecf20Sopenharmony_ci break; 21128c2ecf20Sopenharmony_ci default: 21138c2ecf20Sopenharmony_ci DP_ERR(edev, "Invalid cmd = %d\n", edev->dump_info.cmd); 21148c2ecf20Sopenharmony_ci rc = -EINVAL; 21158c2ecf20Sopenharmony_ci break; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_cierr: 21198c2ecf20Sopenharmony_ci edev->dump_info.cmd = QEDE_DUMP_CMD_NONE; 21208c2ecf20Sopenharmony_ci edev->dump_info.num_args = 0; 21218c2ecf20Sopenharmony_ci memset(edev->dump_info.args, 0, sizeof(edev->dump_info.args)); 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci return rc; 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_cistatic const struct ethtool_ops qede_ethtool_ops = { 21278c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 21288c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_STATS_BLOCK_USECS, 21298c2ecf20Sopenharmony_ci .get_link_ksettings = qede_get_link_ksettings, 21308c2ecf20Sopenharmony_ci .set_link_ksettings = qede_set_link_ksettings, 21318c2ecf20Sopenharmony_ci .get_drvinfo = qede_get_drvinfo, 21328c2ecf20Sopenharmony_ci .get_regs_len = qede_get_regs_len, 21338c2ecf20Sopenharmony_ci .get_regs = qede_get_regs, 21348c2ecf20Sopenharmony_ci .get_wol = qede_get_wol, 21358c2ecf20Sopenharmony_ci .set_wol = qede_set_wol, 21368c2ecf20Sopenharmony_ci .get_msglevel = qede_get_msglevel, 21378c2ecf20Sopenharmony_ci .set_msglevel = qede_set_msglevel, 21388c2ecf20Sopenharmony_ci .nway_reset = qede_nway_reset, 21398c2ecf20Sopenharmony_ci .get_link = qede_get_link, 21408c2ecf20Sopenharmony_ci .get_coalesce = qede_get_coalesce, 21418c2ecf20Sopenharmony_ci .set_coalesce = qede_set_coalesce, 21428c2ecf20Sopenharmony_ci .get_ringparam = qede_get_ringparam, 21438c2ecf20Sopenharmony_ci .set_ringparam = qede_set_ringparam, 21448c2ecf20Sopenharmony_ci .get_pauseparam = qede_get_pauseparam, 21458c2ecf20Sopenharmony_ci .set_pauseparam = qede_set_pauseparam, 21468c2ecf20Sopenharmony_ci .get_strings = qede_get_strings, 21478c2ecf20Sopenharmony_ci .set_phys_id = qede_set_phys_id, 21488c2ecf20Sopenharmony_ci .get_ethtool_stats = qede_get_ethtool_stats, 21498c2ecf20Sopenharmony_ci .get_priv_flags = qede_get_priv_flags, 21508c2ecf20Sopenharmony_ci .set_priv_flags = qede_set_priv_flags, 21518c2ecf20Sopenharmony_ci .get_sset_count = qede_get_sset_count, 21528c2ecf20Sopenharmony_ci .get_rxnfc = qede_get_rxnfc, 21538c2ecf20Sopenharmony_ci .set_rxnfc = qede_set_rxnfc, 21548c2ecf20Sopenharmony_ci .get_rxfh_indir_size = qede_get_rxfh_indir_size, 21558c2ecf20Sopenharmony_ci .get_rxfh_key_size = qede_get_rxfh_key_size, 21568c2ecf20Sopenharmony_ci .get_rxfh = qede_get_rxfh, 21578c2ecf20Sopenharmony_ci .set_rxfh = qede_set_rxfh, 21588c2ecf20Sopenharmony_ci .get_ts_info = qede_get_ts_info, 21598c2ecf20Sopenharmony_ci .get_channels = qede_get_channels, 21608c2ecf20Sopenharmony_ci .set_channels = qede_set_channels, 21618c2ecf20Sopenharmony_ci .self_test = qede_self_test, 21628c2ecf20Sopenharmony_ci .get_module_info = qede_get_module_info, 21638c2ecf20Sopenharmony_ci .get_module_eeprom = qede_get_module_eeprom, 21648c2ecf20Sopenharmony_ci .get_eee = qede_get_eee, 21658c2ecf20Sopenharmony_ci .set_eee = qede_set_eee, 21668c2ecf20Sopenharmony_ci .get_fecparam = qede_get_fecparam, 21678c2ecf20Sopenharmony_ci .set_fecparam = qede_set_fecparam, 21688c2ecf20Sopenharmony_ci .get_tunable = qede_get_tunable, 21698c2ecf20Sopenharmony_ci .set_tunable = qede_set_tunable, 21708c2ecf20Sopenharmony_ci .flash_device = qede_flash_device, 21718c2ecf20Sopenharmony_ci .get_dump_flag = qede_get_dump_flag, 21728c2ecf20Sopenharmony_ci .get_dump_data = qede_get_dump_data, 21738c2ecf20Sopenharmony_ci .set_dump = qede_set_dump, 21748c2ecf20Sopenharmony_ci}; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_cistatic const struct ethtool_ops qede_vf_ethtool_ops = { 21778c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 21788c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_STATS_BLOCK_USECS, 21798c2ecf20Sopenharmony_ci .get_link_ksettings = qede_get_link_ksettings, 21808c2ecf20Sopenharmony_ci .get_drvinfo = qede_get_drvinfo, 21818c2ecf20Sopenharmony_ci .get_msglevel = qede_get_msglevel, 21828c2ecf20Sopenharmony_ci .set_msglevel = qede_set_msglevel, 21838c2ecf20Sopenharmony_ci .get_link = qede_get_link, 21848c2ecf20Sopenharmony_ci .get_coalesce = qede_get_coalesce, 21858c2ecf20Sopenharmony_ci .set_coalesce = qede_set_coalesce, 21868c2ecf20Sopenharmony_ci .get_ringparam = qede_get_ringparam, 21878c2ecf20Sopenharmony_ci .set_ringparam = qede_set_ringparam, 21888c2ecf20Sopenharmony_ci .get_strings = qede_get_strings, 21898c2ecf20Sopenharmony_ci .get_ethtool_stats = qede_get_ethtool_stats, 21908c2ecf20Sopenharmony_ci .get_priv_flags = qede_get_priv_flags, 21918c2ecf20Sopenharmony_ci .get_sset_count = qede_get_sset_count, 21928c2ecf20Sopenharmony_ci .get_rxnfc = qede_get_rxnfc, 21938c2ecf20Sopenharmony_ci .set_rxnfc = qede_set_rxnfc, 21948c2ecf20Sopenharmony_ci .get_rxfh_indir_size = qede_get_rxfh_indir_size, 21958c2ecf20Sopenharmony_ci .get_rxfh_key_size = qede_get_rxfh_key_size, 21968c2ecf20Sopenharmony_ci .get_rxfh = qede_get_rxfh, 21978c2ecf20Sopenharmony_ci .set_rxfh = qede_set_rxfh, 21988c2ecf20Sopenharmony_ci .get_channels = qede_get_channels, 21998c2ecf20Sopenharmony_ci .set_channels = qede_set_channels, 22008c2ecf20Sopenharmony_ci .get_tunable = qede_get_tunable, 22018c2ecf20Sopenharmony_ci .set_tunable = qede_set_tunable, 22028c2ecf20Sopenharmony_ci}; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_civoid qede_set_ethtool_ops(struct net_device *dev) 22058c2ecf20Sopenharmony_ci{ 22068c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (IS_VF(edev)) 22098c2ecf20Sopenharmony_ci dev->ethtool_ops = &qede_vf_ethtool_ops; 22108c2ecf20Sopenharmony_ci else 22118c2ecf20Sopenharmony_ci dev->ethtool_ops = &qede_ethtool_ops; 22128c2ecf20Sopenharmony_ci} 2213