162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 262306a36Sopenharmony_ci/* QLogic qede NIC Driver 362306a36Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 462306a36Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/netdevice.h> 962306a36Sopenharmony_ci#include <linux/etherdevice.h> 1062306a36Sopenharmony_ci#include <linux/ethtool.h> 1162306a36Sopenharmony_ci#include <linux/string.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/capability.h> 1462306a36Sopenharmony_ci#include <linux/vmalloc.h> 1562306a36Sopenharmony_ci#include <linux/phylink.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "qede.h" 1862306a36Sopenharmony_ci#include "qede_ptp.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define QEDE_RQSTAT_OFFSET(stat_name) \ 2162306a36Sopenharmony_ci (offsetof(struct qede_rx_queue, stat_name)) 2262306a36Sopenharmony_ci#define QEDE_RQSTAT_STRING(stat_name) (#stat_name) 2362306a36Sopenharmony_ci#define QEDE_RQSTAT(stat_name) \ 2462306a36Sopenharmony_ci {QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define QEDE_SELFTEST_POLL_COUNT 100 2762306a36Sopenharmony_ci#define QEDE_DUMP_VERSION 0x1 2862306a36Sopenharmony_ci#define QEDE_DUMP_NVM_ARG_COUNT 2 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const struct { 3162306a36Sopenharmony_ci u64 offset; 3262306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 3362306a36Sopenharmony_ci} qede_rqstats_arr[] = { 3462306a36Sopenharmony_ci QEDE_RQSTAT(rcv_pkts), 3562306a36Sopenharmony_ci QEDE_RQSTAT(rx_hw_errors), 3662306a36Sopenharmony_ci QEDE_RQSTAT(rx_alloc_errors), 3762306a36Sopenharmony_ci QEDE_RQSTAT(rx_ip_frags), 3862306a36Sopenharmony_ci QEDE_RQSTAT(xdp_no_pass), 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr) 4262306a36Sopenharmony_ci#define QEDE_TQSTAT_OFFSET(stat_name) \ 4362306a36Sopenharmony_ci (offsetof(struct qede_tx_queue, stat_name)) 4462306a36Sopenharmony_ci#define QEDE_TQSTAT_STRING(stat_name) (#stat_name) 4562306a36Sopenharmony_ci#define QEDE_TQSTAT(stat_name) \ 4662306a36Sopenharmony_ci {QEDE_TQSTAT_OFFSET(stat_name), QEDE_TQSTAT_STRING(stat_name)} 4762306a36Sopenharmony_ci#define QEDE_NUM_TQSTATS ARRAY_SIZE(qede_tqstats_arr) 4862306a36Sopenharmony_cistatic const struct { 4962306a36Sopenharmony_ci u64 offset; 5062306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 5162306a36Sopenharmony_ci} qede_tqstats_arr[] = { 5262306a36Sopenharmony_ci QEDE_TQSTAT(xmit_pkts), 5362306a36Sopenharmony_ci QEDE_TQSTAT(stopped_cnt), 5462306a36Sopenharmony_ci QEDE_TQSTAT(tx_mem_alloc_err), 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define QEDE_STAT_OFFSET(stat_name, type, base) \ 5862306a36Sopenharmony_ci (offsetof(type, stat_name) + (base)) 5962306a36Sopenharmony_ci#define QEDE_STAT_STRING(stat_name) (#stat_name) 6062306a36Sopenharmony_ci#define _QEDE_STAT(stat_name, type, base, attr) \ 6162306a36Sopenharmony_ci {QEDE_STAT_OFFSET(stat_name, type, base), \ 6262306a36Sopenharmony_ci QEDE_STAT_STRING(stat_name), \ 6362306a36Sopenharmony_ci attr} 6462306a36Sopenharmony_ci#define QEDE_STAT(stat_name) \ 6562306a36Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_common, 0, 0x0) 6662306a36Sopenharmony_ci#define QEDE_PF_STAT(stat_name) \ 6762306a36Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_common, 0, \ 6862306a36Sopenharmony_ci BIT(QEDE_STAT_PF_ONLY)) 6962306a36Sopenharmony_ci#define QEDE_PF_BB_STAT(stat_name) \ 7062306a36Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_bb, \ 7162306a36Sopenharmony_ci offsetof(struct qede_stats, bb), \ 7262306a36Sopenharmony_ci BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_BB_ONLY)) 7362306a36Sopenharmony_ci#define QEDE_PF_AH_STAT(stat_name) \ 7462306a36Sopenharmony_ci _QEDE_STAT(stat_name, struct qede_stats_ah, \ 7562306a36Sopenharmony_ci offsetof(struct qede_stats, ah), \ 7662306a36Sopenharmony_ci BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_AH_ONLY)) 7762306a36Sopenharmony_cistatic const struct { 7862306a36Sopenharmony_ci u64 offset; 7962306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 8062306a36Sopenharmony_ci unsigned long attr; 8162306a36Sopenharmony_ci#define QEDE_STAT_PF_ONLY 0 8262306a36Sopenharmony_ci#define QEDE_STAT_BB_ONLY 1 8362306a36Sopenharmony_ci#define QEDE_STAT_AH_ONLY 2 8462306a36Sopenharmony_ci} qede_stats_arr[] = { 8562306a36Sopenharmony_ci QEDE_STAT(rx_ucast_bytes), 8662306a36Sopenharmony_ci QEDE_STAT(rx_mcast_bytes), 8762306a36Sopenharmony_ci QEDE_STAT(rx_bcast_bytes), 8862306a36Sopenharmony_ci QEDE_STAT(rx_ucast_pkts), 8962306a36Sopenharmony_ci QEDE_STAT(rx_mcast_pkts), 9062306a36Sopenharmony_ci QEDE_STAT(rx_bcast_pkts), 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci QEDE_STAT(tx_ucast_bytes), 9362306a36Sopenharmony_ci QEDE_STAT(tx_mcast_bytes), 9462306a36Sopenharmony_ci QEDE_STAT(tx_bcast_bytes), 9562306a36Sopenharmony_ci QEDE_STAT(tx_ucast_pkts), 9662306a36Sopenharmony_ci QEDE_STAT(tx_mcast_pkts), 9762306a36Sopenharmony_ci QEDE_STAT(tx_bcast_pkts), 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci QEDE_PF_STAT(rx_64_byte_packets), 10062306a36Sopenharmony_ci QEDE_PF_STAT(rx_65_to_127_byte_packets), 10162306a36Sopenharmony_ci QEDE_PF_STAT(rx_128_to_255_byte_packets), 10262306a36Sopenharmony_ci QEDE_PF_STAT(rx_256_to_511_byte_packets), 10362306a36Sopenharmony_ci QEDE_PF_STAT(rx_512_to_1023_byte_packets), 10462306a36Sopenharmony_ci QEDE_PF_STAT(rx_1024_to_1518_byte_packets), 10562306a36Sopenharmony_ci QEDE_PF_BB_STAT(rx_1519_to_1522_byte_packets), 10662306a36Sopenharmony_ci QEDE_PF_BB_STAT(rx_1519_to_2047_byte_packets), 10762306a36Sopenharmony_ci QEDE_PF_BB_STAT(rx_2048_to_4095_byte_packets), 10862306a36Sopenharmony_ci QEDE_PF_BB_STAT(rx_4096_to_9216_byte_packets), 10962306a36Sopenharmony_ci QEDE_PF_BB_STAT(rx_9217_to_16383_byte_packets), 11062306a36Sopenharmony_ci QEDE_PF_AH_STAT(rx_1519_to_max_byte_packets), 11162306a36Sopenharmony_ci QEDE_PF_STAT(tx_64_byte_packets), 11262306a36Sopenharmony_ci QEDE_PF_STAT(tx_65_to_127_byte_packets), 11362306a36Sopenharmony_ci QEDE_PF_STAT(tx_128_to_255_byte_packets), 11462306a36Sopenharmony_ci QEDE_PF_STAT(tx_256_to_511_byte_packets), 11562306a36Sopenharmony_ci QEDE_PF_STAT(tx_512_to_1023_byte_packets), 11662306a36Sopenharmony_ci QEDE_PF_STAT(tx_1024_to_1518_byte_packets), 11762306a36Sopenharmony_ci QEDE_PF_BB_STAT(tx_1519_to_2047_byte_packets), 11862306a36Sopenharmony_ci QEDE_PF_BB_STAT(tx_2048_to_4095_byte_packets), 11962306a36Sopenharmony_ci QEDE_PF_BB_STAT(tx_4096_to_9216_byte_packets), 12062306a36Sopenharmony_ci QEDE_PF_BB_STAT(tx_9217_to_16383_byte_packets), 12162306a36Sopenharmony_ci QEDE_PF_AH_STAT(tx_1519_to_max_byte_packets), 12262306a36Sopenharmony_ci QEDE_PF_STAT(rx_mac_crtl_frames), 12362306a36Sopenharmony_ci QEDE_PF_STAT(tx_mac_ctrl_frames), 12462306a36Sopenharmony_ci QEDE_PF_STAT(rx_pause_frames), 12562306a36Sopenharmony_ci QEDE_PF_STAT(tx_pause_frames), 12662306a36Sopenharmony_ci QEDE_PF_STAT(rx_pfc_frames), 12762306a36Sopenharmony_ci QEDE_PF_STAT(tx_pfc_frames), 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci QEDE_PF_STAT(rx_crc_errors), 13062306a36Sopenharmony_ci QEDE_PF_STAT(rx_align_errors), 13162306a36Sopenharmony_ci QEDE_PF_STAT(rx_carrier_errors), 13262306a36Sopenharmony_ci QEDE_PF_STAT(rx_oversize_packets), 13362306a36Sopenharmony_ci QEDE_PF_STAT(rx_jabbers), 13462306a36Sopenharmony_ci QEDE_PF_STAT(rx_undersize_packets), 13562306a36Sopenharmony_ci QEDE_PF_STAT(rx_fragments), 13662306a36Sopenharmony_ci QEDE_PF_BB_STAT(tx_lpi_entry_count), 13762306a36Sopenharmony_ci QEDE_PF_BB_STAT(tx_total_collisions), 13862306a36Sopenharmony_ci QEDE_PF_STAT(brb_truncates), 13962306a36Sopenharmony_ci QEDE_PF_STAT(brb_discards), 14062306a36Sopenharmony_ci QEDE_STAT(no_buff_discards), 14162306a36Sopenharmony_ci QEDE_PF_STAT(mftag_filter_discards), 14262306a36Sopenharmony_ci QEDE_PF_STAT(mac_filter_discards), 14362306a36Sopenharmony_ci QEDE_PF_STAT(gft_filter_drop), 14462306a36Sopenharmony_ci QEDE_STAT(tx_err_drop_pkts), 14562306a36Sopenharmony_ci QEDE_STAT(ttl0_discard), 14662306a36Sopenharmony_ci QEDE_STAT(packet_too_big_discard), 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci QEDE_STAT(coalesced_pkts), 14962306a36Sopenharmony_ci QEDE_STAT(coalesced_events), 15062306a36Sopenharmony_ci QEDE_STAT(coalesced_aborts_num), 15162306a36Sopenharmony_ci QEDE_STAT(non_coalesced_pkts), 15262306a36Sopenharmony_ci QEDE_STAT(coalesced_bytes), 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci QEDE_STAT(link_change_count), 15562306a36Sopenharmony_ci QEDE_STAT(ptp_skip_txts), 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define QEDE_NUM_STATS ARRAY_SIZE(qede_stats_arr) 15962306a36Sopenharmony_ci#define QEDE_STAT_IS_PF_ONLY(i) \ 16062306a36Sopenharmony_ci test_bit(QEDE_STAT_PF_ONLY, &qede_stats_arr[i].attr) 16162306a36Sopenharmony_ci#define QEDE_STAT_IS_BB_ONLY(i) \ 16262306a36Sopenharmony_ci test_bit(QEDE_STAT_BB_ONLY, &qede_stats_arr[i].attr) 16362306a36Sopenharmony_ci#define QEDE_STAT_IS_AH_ONLY(i) \ 16462306a36Sopenharmony_ci test_bit(QEDE_STAT_AH_ONLY, &qede_stats_arr[i].attr) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cienum { 16762306a36Sopenharmony_ci QEDE_PRI_FLAG_CMT, 16862306a36Sopenharmony_ci QEDE_PRI_FLAG_SMART_AN_SUPPORT, /* MFW supports SmartAN */ 16962306a36Sopenharmony_ci QEDE_PRI_FLAG_RECOVER_ON_ERROR, 17062306a36Sopenharmony_ci QEDE_PRI_FLAG_ESL_SUPPORT, /* MFW supports Enhanced System Lockdown */ 17162306a36Sopenharmony_ci QEDE_PRI_FLAG_ESL_ACTIVE, /* Enhanced System Lockdown Active status */ 17262306a36Sopenharmony_ci QEDE_PRI_FLAG_LEN, 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = { 17662306a36Sopenharmony_ci "Coupled-Function", 17762306a36Sopenharmony_ci "SmartAN capable", 17862306a36Sopenharmony_ci "Recover on error", 17962306a36Sopenharmony_ci "ESL capable", 18062306a36Sopenharmony_ci "ESL active", 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cienum qede_ethtool_tests { 18462306a36Sopenharmony_ci QEDE_ETHTOOL_INT_LOOPBACK, 18562306a36Sopenharmony_ci QEDE_ETHTOOL_INTERRUPT_TEST, 18662306a36Sopenharmony_ci QEDE_ETHTOOL_MEMORY_TEST, 18762306a36Sopenharmony_ci QEDE_ETHTOOL_REGISTER_TEST, 18862306a36Sopenharmony_ci QEDE_ETHTOOL_CLOCK_TEST, 18962306a36Sopenharmony_ci QEDE_ETHTOOL_NVRAM_TEST, 19062306a36Sopenharmony_ci QEDE_ETHTOOL_TEST_MAX 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = { 19462306a36Sopenharmony_ci "Internal loopback (offline)", 19562306a36Sopenharmony_ci "Interrupt (online)\t", 19662306a36Sopenharmony_ci "Memory (online)\t\t", 19762306a36Sopenharmony_ci "Register (online)\t", 19862306a36Sopenharmony_ci "Clock (online)\t\t", 19962306a36Sopenharmony_ci "Nvram (online)\t\t", 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* Forced speed capabilities maps */ 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistruct qede_forced_speed_map { 20562306a36Sopenharmony_ci u32 speed; 20662306a36Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(caps); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci const u32 *cap_arr; 20962306a36Sopenharmony_ci u32 arr_size; 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#define QEDE_FORCED_SPEED_MAP(value) \ 21362306a36Sopenharmony_ci{ \ 21462306a36Sopenharmony_ci .speed = SPEED_##value, \ 21562306a36Sopenharmony_ci .cap_arr = qede_forced_speed_##value, \ 21662306a36Sopenharmony_ci .arr_size = ARRAY_SIZE(qede_forced_speed_##value), \ 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic const u32 qede_forced_speed_1000[] __initconst = { 22062306a36Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 22162306a36Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 22262306a36Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic const u32 qede_forced_speed_10000[] __initconst = { 22662306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 22762306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 22862306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 22962306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 23062306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 23162306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 23262306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 23362306a36Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const u32 qede_forced_speed_20000[] __initconst = { 23762306a36Sopenharmony_ci ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic const u32 qede_forced_speed_25000[] __initconst = { 24162306a36Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 24262306a36Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 24362306a36Sopenharmony_ci ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic const u32 qede_forced_speed_40000[] __initconst = { 24762306a36Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 24862306a36Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 24962306a36Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 25062306a36Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 25162306a36Sopenharmony_ci}; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic const u32 qede_forced_speed_50000[] __initconst = { 25462306a36Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 25562306a36Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 25662306a36Sopenharmony_ci ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic const u32 qede_forced_speed_100000[] __initconst = { 26062306a36Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 26162306a36Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 26262306a36Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 26362306a36Sopenharmony_ci ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 26462306a36Sopenharmony_ci}; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic struct qede_forced_speed_map qede_forced_speed_maps[] __ro_after_init = { 26762306a36Sopenharmony_ci QEDE_FORCED_SPEED_MAP(1000), 26862306a36Sopenharmony_ci QEDE_FORCED_SPEED_MAP(10000), 26962306a36Sopenharmony_ci QEDE_FORCED_SPEED_MAP(20000), 27062306a36Sopenharmony_ci QEDE_FORCED_SPEED_MAP(25000), 27162306a36Sopenharmony_ci QEDE_FORCED_SPEED_MAP(40000), 27262306a36Sopenharmony_ci QEDE_FORCED_SPEED_MAP(50000), 27362306a36Sopenharmony_ci QEDE_FORCED_SPEED_MAP(100000), 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_civoid __init qede_forced_speed_maps_init(void) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct qede_forced_speed_map *map; 27962306a36Sopenharmony_ci u32 i; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qede_forced_speed_maps); i++) { 28262306a36Sopenharmony_ci map = qede_forced_speed_maps + i; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci linkmode_set_bit_array(map->cap_arr, map->arr_size, map->caps); 28562306a36Sopenharmony_ci map->cap_arr = NULL; 28662306a36Sopenharmony_ci map->arr_size = 0; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci/* Ethtool callbacks */ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic void qede_get_strings_stats_txq(struct qede_dev *edev, 29362306a36Sopenharmony_ci struct qede_tx_queue *txq, u8 **buf) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci int i; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci for (i = 0; i < QEDE_NUM_TQSTATS; i++) { 29862306a36Sopenharmony_ci if (txq->is_xdp) 29962306a36Sopenharmony_ci sprintf(*buf, "%d [XDP]: %s", 30062306a36Sopenharmony_ci QEDE_TXQ_XDP_TO_IDX(edev, txq), 30162306a36Sopenharmony_ci qede_tqstats_arr[i].string); 30262306a36Sopenharmony_ci else 30362306a36Sopenharmony_ci sprintf(*buf, "%d_%d: %s", txq->index, txq->cos, 30462306a36Sopenharmony_ci qede_tqstats_arr[i].string); 30562306a36Sopenharmony_ci *buf += ETH_GSTRING_LEN; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic void qede_get_strings_stats_rxq(struct qede_dev *edev, 31062306a36Sopenharmony_ci struct qede_rx_queue *rxq, u8 **buf) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int i; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci for (i = 0; i < QEDE_NUM_RQSTATS; i++) { 31562306a36Sopenharmony_ci sprintf(*buf, "%d: %s", rxq->rxq_id, 31662306a36Sopenharmony_ci qede_rqstats_arr[i].string); 31762306a36Sopenharmony_ci *buf += ETH_GSTRING_LEN; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic bool qede_is_irrelevant_stat(struct qede_dev *edev, int stat_index) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci return (IS_VF(edev) && QEDE_STAT_IS_PF_ONLY(stat_index)) || 32462306a36Sopenharmony_ci (QEDE_IS_BB(edev) && QEDE_STAT_IS_AH_ONLY(stat_index)) || 32562306a36Sopenharmony_ci (QEDE_IS_AH(edev) && QEDE_STAT_IS_BB_ONLY(stat_index)); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void qede_get_strings_stats(struct qede_dev *edev, u8 *buf) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct qede_fastpath *fp; 33162306a36Sopenharmony_ci int i; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Account for queue statistics */ 33462306a36Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) { 33562306a36Sopenharmony_ci fp = &edev->fp_array[i]; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) 33862306a36Sopenharmony_ci qede_get_strings_stats_rxq(edev, fp->rxq, &buf); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 34162306a36Sopenharmony_ci qede_get_strings_stats_txq(edev, fp->xdp_tx, &buf); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 34462306a36Sopenharmony_ci int cos; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) 34762306a36Sopenharmony_ci qede_get_strings_stats_txq(edev, 34862306a36Sopenharmony_ci &fp->txq[cos], &buf); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* Account for non-queue statistics */ 35362306a36Sopenharmony_ci for (i = 0; i < QEDE_NUM_STATS; i++) { 35462306a36Sopenharmony_ci if (qede_is_irrelevant_stat(edev, i)) 35562306a36Sopenharmony_ci continue; 35662306a36Sopenharmony_ci strcpy(buf, qede_stats_arr[i].string); 35762306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci switch (stringset) { 36662306a36Sopenharmony_ci case ETH_SS_STATS: 36762306a36Sopenharmony_ci qede_get_strings_stats(edev, buf); 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 37062306a36Sopenharmony_ci memcpy(buf, qede_private_arr, 37162306a36Sopenharmony_ci ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN); 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case ETH_SS_TEST: 37462306a36Sopenharmony_ci memcpy(buf, qede_tests_str_arr, 37562306a36Sopenharmony_ci ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX); 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci default: 37862306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 37962306a36Sopenharmony_ci "Unsupported stringset 0x%08x\n", stringset); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic void qede_get_ethtool_stats_txq(struct qede_tx_queue *txq, u64 **buf) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci int i; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci for (i = 0; i < QEDE_NUM_TQSTATS; i++) { 38862306a36Sopenharmony_ci **buf = *((u64 *)(((void *)txq) + qede_tqstats_arr[i].offset)); 38962306a36Sopenharmony_ci (*buf)++; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void qede_get_ethtool_stats_rxq(struct qede_rx_queue *rxq, u64 **buf) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci int i; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci for (i = 0; i < QEDE_NUM_RQSTATS; i++) { 39862306a36Sopenharmony_ci **buf = *((u64 *)(((void *)rxq) + qede_rqstats_arr[i].offset)); 39962306a36Sopenharmony_ci (*buf)++; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void qede_get_ethtool_stats(struct net_device *dev, 40462306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *buf) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 40762306a36Sopenharmony_ci struct qede_fastpath *fp; 40862306a36Sopenharmony_ci int i; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci qede_fill_by_demand_stats(edev); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Need to protect the access to the fastpath array */ 41362306a36Sopenharmony_ci __qede_lock(edev); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) { 41662306a36Sopenharmony_ci fp = &edev->fp_array[i]; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) 41962306a36Sopenharmony_ci qede_get_ethtool_stats_rxq(fp->rxq, &buf); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 42262306a36Sopenharmony_ci qede_get_ethtool_stats_txq(fp->xdp_tx, &buf); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 42562306a36Sopenharmony_ci int cos; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) 42862306a36Sopenharmony_ci qede_get_ethtool_stats_txq(&fp->txq[cos], &buf); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci spin_lock(&edev->stats_lock); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci for (i = 0; i < QEDE_NUM_STATS; i++) { 43562306a36Sopenharmony_ci if (qede_is_irrelevant_stat(edev, i)) 43662306a36Sopenharmony_ci continue; 43762306a36Sopenharmony_ci *buf = *((u64 *)(((void *)&edev->stats) + 43862306a36Sopenharmony_ci qede_stats_arr[i].offset)); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci buf++; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci spin_unlock(&edev->stats_lock); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci __qede_unlock(edev); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int qede_get_sset_count(struct net_device *dev, int stringset) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 45162306a36Sopenharmony_ci int num_stats = QEDE_NUM_STATS, i; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci switch (stringset) { 45462306a36Sopenharmony_ci case ETH_SS_STATS: 45562306a36Sopenharmony_ci for (i = 0; i < QEDE_NUM_STATS; i++) 45662306a36Sopenharmony_ci if (qede_is_irrelevant_stat(edev, i)) 45762306a36Sopenharmony_ci num_stats--; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Account for the Regular Tx statistics */ 46062306a36Sopenharmony_ci num_stats += QEDE_TSS_COUNT(edev) * QEDE_NUM_TQSTATS * 46162306a36Sopenharmony_ci edev->dev_info.num_tc; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Account for the Regular Rx statistics */ 46462306a36Sopenharmony_ci num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Account for XDP statistics [if needed] */ 46762306a36Sopenharmony_ci if (edev->xdp_prog) 46862306a36Sopenharmony_ci num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_TQSTATS; 46962306a36Sopenharmony_ci return num_stats; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 47262306a36Sopenharmony_ci return QEDE_PRI_FLAG_LEN; 47362306a36Sopenharmony_ci case ETH_SS_TEST: 47462306a36Sopenharmony_ci if (!IS_VF(edev)) 47562306a36Sopenharmony_ci return QEDE_ETHTOOL_TEST_MAX; 47662306a36Sopenharmony_ci else 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci default: 47962306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 48062306a36Sopenharmony_ci "Unsupported stringset 0x%08x\n", stringset); 48162306a36Sopenharmony_ci return -EINVAL; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic u32 qede_get_priv_flags(struct net_device *dev) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 48862306a36Sopenharmony_ci bool esl_active; 48962306a36Sopenharmony_ci u32 flags = 0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (edev->dev_info.common.num_hwfns > 1) 49262306a36Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_CMT); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (edev->dev_info.common.smart_an) 49562306a36Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_SMART_AN_SUPPORT); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (edev->err_flags & BIT(QEDE_ERR_IS_RECOVERABLE)) 49862306a36Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (edev->dev_info.common.esl) 50162306a36Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_ESL_SUPPORT); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci edev->ops->common->get_esl_status(edev->cdev, &esl_active); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (esl_active) 50662306a36Sopenharmony_ci flags |= BIT(QEDE_PRI_FLAG_ESL_ACTIVE); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return flags; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int qede_set_priv_flags(struct net_device *dev, u32 flags) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 51462306a36Sopenharmony_ci u32 cflags = qede_get_priv_flags(dev); 51562306a36Sopenharmony_ci u32 dflags = flags ^ cflags; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* can only change RECOVER_ON_ERROR flag */ 51862306a36Sopenharmony_ci if (dflags & ~BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR)) 51962306a36Sopenharmony_ci return -EINVAL; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (flags & BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR)) 52262306a36Sopenharmony_ci set_bit(QEDE_ERR_IS_RECOVERABLE, &edev->err_flags); 52362306a36Sopenharmony_ci else 52462306a36Sopenharmony_ci clear_bit(QEDE_ERR_IS_RECOVERABLE, &edev->err_flags); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return 0; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int qede_get_link_ksettings(struct net_device *dev, 53062306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci typeof(cmd->link_modes) *link_modes = &cmd->link_modes; 53362306a36Sopenharmony_ci struct ethtool_link_settings *base = &cmd->base; 53462306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 53562306a36Sopenharmony_ci struct qed_link_output current_link; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci __qede_lock(edev); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 54062306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci linkmode_copy(link_modes->supported, current_link.supported_caps); 54362306a36Sopenharmony_ci linkmode_copy(link_modes->advertising, current_link.advertised_caps); 54462306a36Sopenharmony_ci linkmode_copy(link_modes->lp_advertising, current_link.lp_caps); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) { 54762306a36Sopenharmony_ci base->speed = current_link.speed; 54862306a36Sopenharmony_ci base->duplex = current_link.duplex; 54962306a36Sopenharmony_ci } else { 55062306a36Sopenharmony_ci base->speed = SPEED_UNKNOWN; 55162306a36Sopenharmony_ci base->duplex = DUPLEX_UNKNOWN; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci __qede_unlock(edev); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci base->port = current_link.port; 55762306a36Sopenharmony_ci base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE : 55862306a36Sopenharmony_ci AUTONEG_DISABLE; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int qede_set_link_ksettings(struct net_device *dev, 56462306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci const struct ethtool_link_settings *base = &cmd->base; 56762306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 56862306a36Sopenharmony_ci const struct qede_forced_speed_map *map; 56962306a36Sopenharmony_ci struct qed_link_output current_link; 57062306a36Sopenharmony_ci struct qed_link_params params; 57162306a36Sopenharmony_ci u32 i; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 57462306a36Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 57562306a36Sopenharmony_ci return -EOPNOTSUPP; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 57862306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 57962306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS; 58262306a36Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (base->autoneg == AUTONEG_ENABLE) { 58562306a36Sopenharmony_ci if (!phylink_test(current_link.supported_caps, Autoneg)) { 58662306a36Sopenharmony_ci DP_INFO(edev, "Auto negotiation is not supported\n"); 58762306a36Sopenharmony_ci return -EOPNOTSUPP; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci params.autoneg = true; 59162306a36Sopenharmony_ci params.forced_speed = 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci linkmode_copy(params.adv_speeds, cmd->link_modes.advertising); 59462306a36Sopenharmony_ci } else { /* forced speed */ 59562306a36Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED; 59662306a36Sopenharmony_ci params.autoneg = false; 59762306a36Sopenharmony_ci params.forced_speed = base->speed; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qede_forced_speed_maps); i++) { 60062306a36Sopenharmony_ci map = qede_forced_speed_maps + i; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (base->speed != map->speed || 60362306a36Sopenharmony_ci !linkmode_intersects(current_link.supported_caps, 60462306a36Sopenharmony_ci map->caps)) 60562306a36Sopenharmony_ci continue; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci linkmode_and(params.adv_speeds, 60862306a36Sopenharmony_ci current_link.supported_caps, map->caps); 60962306a36Sopenharmony_ci goto set_link; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci DP_INFO(edev, "Unsupported speed %u\n", base->speed); 61362306a36Sopenharmony_ci return -EINVAL; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ciset_link: 61762306a36Sopenharmony_ci params.link_up = true; 61862306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic void qede_get_drvinfo(struct net_device *ndev, 62462306a36Sopenharmony_ci struct ethtool_drvinfo *info) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN]; 62762306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 62862306a36Sopenharmony_ci char mbi[ETHTOOL_FWVERS_LEN]; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci strscpy(info->driver, "qede", sizeof(info->driver)); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d", 63362306a36Sopenharmony_ci edev->dev_info.common.fw_major, 63462306a36Sopenharmony_ci edev->dev_info.common.fw_minor, 63562306a36Sopenharmony_ci edev->dev_info.common.fw_rev, 63662306a36Sopenharmony_ci edev->dev_info.common.fw_eng); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci snprintf(mfw, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d", 63962306a36Sopenharmony_ci (edev->dev_info.common.mfw_rev >> 24) & 0xFF, 64062306a36Sopenharmony_ci (edev->dev_info.common.mfw_rev >> 16) & 0xFF, 64162306a36Sopenharmony_ci (edev->dev_info.common.mfw_rev >> 8) & 0xFF, 64262306a36Sopenharmony_ci edev->dev_info.common.mfw_rev & 0xFF); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if ((strlen(storm) + strlen("[storm]")) < 64562306a36Sopenharmony_ci sizeof(info->version)) 64662306a36Sopenharmony_ci snprintf(info->version, sizeof(info->version), 64762306a36Sopenharmony_ci "[storm %s]", storm); 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci snprintf(info->version, sizeof(info->version), 65062306a36Sopenharmony_ci "%s", storm); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (edev->dev_info.common.mbi_version) { 65362306a36Sopenharmony_ci snprintf(mbi, ETHTOOL_FWVERS_LEN, "%d.%d.%d", 65462306a36Sopenharmony_ci (edev->dev_info.common.mbi_version & 65562306a36Sopenharmony_ci QED_MBI_VERSION_2_MASK) >> QED_MBI_VERSION_2_OFFSET, 65662306a36Sopenharmony_ci (edev->dev_info.common.mbi_version & 65762306a36Sopenharmony_ci QED_MBI_VERSION_1_MASK) >> QED_MBI_VERSION_1_OFFSET, 65862306a36Sopenharmony_ci (edev->dev_info.common.mbi_version & 65962306a36Sopenharmony_ci QED_MBI_VERSION_0_MASK) >> QED_MBI_VERSION_0_OFFSET); 66062306a36Sopenharmony_ci snprintf(info->fw_version, sizeof(info->fw_version), 66162306a36Sopenharmony_ci "mbi %s [mfw %s]", mbi, mfw); 66262306a36Sopenharmony_ci } else { 66362306a36Sopenharmony_ci snprintf(info->fw_version, sizeof(info->fw_version), 66462306a36Sopenharmony_ci "mfw %s", mfw); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info)); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic void qede_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (edev->dev_info.common.wol_support) { 67562306a36Sopenharmony_ci wol->supported = WAKE_MAGIC; 67662306a36Sopenharmony_ci wol->wolopts = edev->wol_enabled ? WAKE_MAGIC : 0; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int qede_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 68362306a36Sopenharmony_ci bool wol_requested; 68462306a36Sopenharmony_ci int rc; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (wol->wolopts & ~WAKE_MAGIC) { 68762306a36Sopenharmony_ci DP_INFO(edev, 68862306a36Sopenharmony_ci "Can't support WoL options other than magic-packet\n"); 68962306a36Sopenharmony_ci return -EINVAL; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci wol_requested = !!(wol->wolopts & WAKE_MAGIC); 69362306a36Sopenharmony_ci if (wol_requested == edev->wol_enabled) 69462306a36Sopenharmony_ci return 0; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Need to actually change configuration */ 69762306a36Sopenharmony_ci if (!edev->dev_info.common.wol_support) { 69862306a36Sopenharmony_ci DP_INFO(edev, "Device doesn't support WoL\n"); 69962306a36Sopenharmony_ci return -EINVAL; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci rc = edev->ops->common->update_wol(edev->cdev, wol_requested); 70362306a36Sopenharmony_ci if (!rc) 70462306a36Sopenharmony_ci edev->wol_enabled = wol_requested; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return rc; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic u32 qede_get_msglevel(struct net_device *ndev) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return ((u32)edev->dp_level << QED_LOG_LEVEL_SHIFT) | edev->dp_module; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void qede_set_msglevel(struct net_device *ndev, u32 level) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 71962306a36Sopenharmony_ci u32 dp_module = 0; 72062306a36Sopenharmony_ci u8 dp_level = 0; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci qede_config_debug(level, &dp_module, &dp_level); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci edev->dp_level = dp_level; 72562306a36Sopenharmony_ci edev->dp_module = dp_module; 72662306a36Sopenharmony_ci edev->ops->common->update_msglvl(edev->cdev, 72762306a36Sopenharmony_ci dp_module, dp_level); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic int qede_nway_reset(struct net_device *dev) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 73362306a36Sopenharmony_ci struct qed_link_output current_link; 73462306a36Sopenharmony_ci struct qed_link_params link_params; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 73762306a36Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 73862306a36Sopenharmony_ci return -EOPNOTSUPP; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (!netif_running(dev)) 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 74562306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 74662306a36Sopenharmony_ci if (!current_link.link_up) 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* Toggle the link */ 75062306a36Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 75162306a36Sopenharmony_ci link_params.link_up = false; 75262306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 75362306a36Sopenharmony_ci link_params.link_up = true; 75462306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic u32 qede_get_link(struct net_device *dev) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 76262306a36Sopenharmony_ci struct qed_link_output current_link; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 76562306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci return current_link.link_up; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic int qede_flash_device(struct net_device *dev, 77162306a36Sopenharmony_ci struct ethtool_flash *flash) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci return edev->ops->common->nvm_flash(edev->cdev, flash->data); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic int qede_get_coalesce(struct net_device *dev, 77962306a36Sopenharmony_ci struct ethtool_coalesce *coal, 78062306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 78162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci void *rx_handle = NULL, *tx_handle = NULL; 78462306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 78562306a36Sopenharmony_ci u16 rx_coal, tx_coal, i, rc = 0; 78662306a36Sopenharmony_ci struct qede_fastpath *fp; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci rx_coal = QED_DEFAULT_RX_USECS; 78962306a36Sopenharmony_ci tx_coal = QED_DEFAULT_TX_USECS; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci memset(coal, 0, sizeof(struct ethtool_coalesce)); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci __qede_lock(edev); 79462306a36Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 79562306a36Sopenharmony_ci for_each_queue(i) { 79662306a36Sopenharmony_ci fp = &edev->fp_array[i]; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 79962306a36Sopenharmony_ci rx_handle = fp->rxq->handle; 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci rc = edev->ops->get_coalesce(edev->cdev, &rx_coal, rx_handle); 80562306a36Sopenharmony_ci if (rc) { 80662306a36Sopenharmony_ci DP_INFO(edev, "Read Rx coalesce error\n"); 80762306a36Sopenharmony_ci goto out; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci for_each_queue(i) { 81162306a36Sopenharmony_ci struct qede_tx_queue *txq; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci fp = &edev->fp_array[i]; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* All TX queues of given fastpath uses same 81662306a36Sopenharmony_ci * coalescing value, so no need to iterate over 81762306a36Sopenharmony_ci * all TCs, TC0 txq should suffice. 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 82062306a36Sopenharmony_ci txq = QEDE_FP_TC0_TXQ(fp); 82162306a36Sopenharmony_ci tx_handle = txq->handle; 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci rc = edev->ops->get_coalesce(edev->cdev, &tx_coal, tx_handle); 82762306a36Sopenharmony_ci if (rc) 82862306a36Sopenharmony_ci DP_INFO(edev, "Read Tx coalesce error\n"); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ciout: 83262306a36Sopenharmony_ci __qede_unlock(edev); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci coal->rx_coalesce_usecs = rx_coal; 83562306a36Sopenharmony_ci coal->tx_coalesce_usecs = tx_coal; 83662306a36Sopenharmony_ci coal->stats_block_coalesce_usecs = edev->stats_coal_usecs; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci return rc; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ciint qede_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal, 84262306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 84362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 84662306a36Sopenharmony_ci struct qede_fastpath *fp; 84762306a36Sopenharmony_ci int i, rc = 0; 84862306a36Sopenharmony_ci u16 rxc, txc; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (edev->stats_coal_usecs != coal->stats_block_coalesce_usecs) { 85162306a36Sopenharmony_ci edev->stats_coal_usecs = coal->stats_block_coalesce_usecs; 85262306a36Sopenharmony_ci if (edev->stats_coal_usecs) { 85362306a36Sopenharmony_ci edev->stats_coal_ticks = usecs_to_jiffies(edev->stats_coal_usecs); 85462306a36Sopenharmony_ci schedule_delayed_work(&edev->periodic_task, 0); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci DP_INFO(edev, "Configured stats coal ticks=%lu jiffies\n", 85762306a36Sopenharmony_ci edev->stats_coal_ticks); 85862306a36Sopenharmony_ci } else { 85962306a36Sopenharmony_ci cancel_delayed_work_sync(&edev->periodic_task); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (!netif_running(dev)) { 86462306a36Sopenharmony_ci DP_INFO(edev, "Interface is down\n"); 86562306a36Sopenharmony_ci return -EINVAL; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (coal->rx_coalesce_usecs > QED_COALESCE_MAX || 86962306a36Sopenharmony_ci coal->tx_coalesce_usecs > QED_COALESCE_MAX) { 87062306a36Sopenharmony_ci DP_INFO(edev, 87162306a36Sopenharmony_ci "Can't support requested %s coalesce value [max supported value %d]\n", 87262306a36Sopenharmony_ci coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx" : 87362306a36Sopenharmony_ci "tx", QED_COALESCE_MAX); 87462306a36Sopenharmony_ci return -EINVAL; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci rxc = (u16)coal->rx_coalesce_usecs; 87862306a36Sopenharmony_ci txc = (u16)coal->tx_coalesce_usecs; 87962306a36Sopenharmony_ci for_each_queue(i) { 88062306a36Sopenharmony_ci fp = &edev->fp_array[i]; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_RX) { 88362306a36Sopenharmony_ci rc = edev->ops->common->set_coalesce(edev->cdev, 88462306a36Sopenharmony_ci rxc, 0, 88562306a36Sopenharmony_ci fp->rxq->handle); 88662306a36Sopenharmony_ci if (rc) { 88762306a36Sopenharmony_ci DP_INFO(edev, 88862306a36Sopenharmony_ci "Set RX coalesce error, rc = %d\n", rc); 88962306a36Sopenharmony_ci return rc; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci edev->coal_entry[i].rxc = rxc; 89262306a36Sopenharmony_ci edev->coal_entry[i].isvalid = true; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { 89662306a36Sopenharmony_ci struct qede_tx_queue *txq; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci /* All TX queues of given fastpath uses same 89962306a36Sopenharmony_ci * coalescing value, so no need to iterate over 90062306a36Sopenharmony_ci * all TCs, TC0 txq should suffice. 90162306a36Sopenharmony_ci */ 90262306a36Sopenharmony_ci txq = QEDE_FP_TC0_TXQ(fp); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci rc = edev->ops->common->set_coalesce(edev->cdev, 90562306a36Sopenharmony_ci 0, txc, 90662306a36Sopenharmony_ci txq->handle); 90762306a36Sopenharmony_ci if (rc) { 90862306a36Sopenharmony_ci DP_INFO(edev, 90962306a36Sopenharmony_ci "Set TX coalesce error, rc = %d\n", rc); 91062306a36Sopenharmony_ci return rc; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci edev->coal_entry[i].txc = txc; 91362306a36Sopenharmony_ci edev->coal_entry[i].isvalid = true; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return rc; 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic void qede_get_ringparam(struct net_device *dev, 92162306a36Sopenharmony_ci struct ethtool_ringparam *ering, 92262306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ering, 92362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci ering->rx_max_pending = NUM_RX_BDS_MAX; 92862306a36Sopenharmony_ci ering->rx_pending = edev->q_num_rx_buffers; 92962306a36Sopenharmony_ci ering->tx_max_pending = NUM_TX_BDS_MAX; 93062306a36Sopenharmony_ci ering->tx_pending = edev->q_num_tx_buffers; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic int qede_set_ringparam(struct net_device *dev, 93462306a36Sopenharmony_ci struct ethtool_ringparam *ering, 93562306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ering, 93662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 94162306a36Sopenharmony_ci "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n", 94262306a36Sopenharmony_ci ering->rx_pending, ering->tx_pending); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* Validate legality of configuration */ 94562306a36Sopenharmony_ci if (ering->rx_pending > NUM_RX_BDS_MAX || 94662306a36Sopenharmony_ci ering->rx_pending < NUM_RX_BDS_MIN || 94762306a36Sopenharmony_ci ering->tx_pending > NUM_TX_BDS_MAX || 94862306a36Sopenharmony_ci ering->tx_pending < NUM_TX_BDS_MIN) { 94962306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 95062306a36Sopenharmony_ci "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n", 95162306a36Sopenharmony_ci NUM_RX_BDS_MIN, NUM_RX_BDS_MAX, 95262306a36Sopenharmony_ci NUM_TX_BDS_MIN, NUM_TX_BDS_MAX); 95362306a36Sopenharmony_ci return -EINVAL; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Change ring size and re-load */ 95762306a36Sopenharmony_ci edev->q_num_rx_buffers = ering->rx_pending; 95862306a36Sopenharmony_ci edev->q_num_tx_buffers = ering->tx_pending; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci qede_reload(edev, NULL, false); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci return 0; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic void qede_get_pauseparam(struct net_device *dev, 96662306a36Sopenharmony_ci struct ethtool_pauseparam *epause) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 96962306a36Sopenharmony_ci struct qed_link_output current_link; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 97262306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 97562306a36Sopenharmony_ci epause->autoneg = true; 97662306a36Sopenharmony_ci if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE) 97762306a36Sopenharmony_ci epause->rx_pause = true; 97862306a36Sopenharmony_ci if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE) 97962306a36Sopenharmony_ci epause->tx_pause = true; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 98262306a36Sopenharmony_ci "ethtool_pauseparam: cmd %d autoneg %d rx_pause %d tx_pause %d\n", 98362306a36Sopenharmony_ci epause->cmd, epause->autoneg, epause->rx_pause, 98462306a36Sopenharmony_ci epause->tx_pause); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic int qede_set_pauseparam(struct net_device *dev, 98862306a36Sopenharmony_ci struct ethtool_pauseparam *epause) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 99162306a36Sopenharmony_ci struct qed_link_params params; 99262306a36Sopenharmony_ci struct qed_link_output current_link; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 99562306a36Sopenharmony_ci DP_INFO(edev, 99662306a36Sopenharmony_ci "Pause settings are not allowed to be changed\n"); 99762306a36Sopenharmony_ci return -EOPNOTSUPP; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 100162306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 100462306a36Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (epause->autoneg) { 100762306a36Sopenharmony_ci if (!phylink_test(current_link.supported_caps, Autoneg)) { 100862306a36Sopenharmony_ci DP_INFO(edev, "autoneg not supported\n"); 100962306a36Sopenharmony_ci return -EINVAL; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (epause->rx_pause) 101662306a36Sopenharmony_ci params.pause_config |= QED_LINK_PAUSE_RX_ENABLE; 101762306a36Sopenharmony_ci if (epause->tx_pause) 101862306a36Sopenharmony_ci params.pause_config |= QED_LINK_PAUSE_TX_ENABLE; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci params.link_up = true; 102162306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic void qede_get_regs(struct net_device *ndev, 102762306a36Sopenharmony_ci struct ethtool_regs *regs, void *buffer) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci regs->version = 0; 103262306a36Sopenharmony_ci memset(buffer, 0, regs->len); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if (edev->ops && edev->ops->common) 103562306a36Sopenharmony_ci edev->ops->common->dbg_all_data(edev->cdev, buffer); 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic int qede_get_regs_len(struct net_device *ndev) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (edev->ops && edev->ops->common) 104362306a36Sopenharmony_ci return edev->ops->common->dbg_all_data_size(edev->cdev); 104462306a36Sopenharmony_ci else 104562306a36Sopenharmony_ci return -EINVAL; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic void qede_update_mtu(struct qede_dev *edev, 104962306a36Sopenharmony_ci struct qede_reload_args *args) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci edev->ndev->mtu = args->u.mtu; 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci/* Netdevice NDOs */ 105562306a36Sopenharmony_ciint qede_change_mtu(struct net_device *ndev, int new_mtu) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 105862306a36Sopenharmony_ci struct qede_reload_args args; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 106162306a36Sopenharmony_ci "Configuring MTU size of %d\n", new_mtu); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (new_mtu > PAGE_SIZE) 106462306a36Sopenharmony_ci ndev->features &= ~NETIF_F_GRO_HW; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* Set the mtu field and re-start the interface if needed */ 106762306a36Sopenharmony_ci args.u.mtu = new_mtu; 106862306a36Sopenharmony_ci args.func = &qede_update_mtu; 106962306a36Sopenharmony_ci qede_reload(edev, &args, false); 107062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_QED_RDMA) 107162306a36Sopenharmony_ci qede_rdma_event_change_mtu(edev); 107262306a36Sopenharmony_ci#endif 107362306a36Sopenharmony_ci edev->ops->common->update_mtu(edev->cdev, new_mtu); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return 0; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic void qede_get_channels(struct net_device *dev, 107962306a36Sopenharmony_ci struct ethtool_channels *channels) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci channels->max_combined = QEDE_MAX_RSS_CNT(edev); 108462306a36Sopenharmony_ci channels->max_rx = QEDE_MAX_RSS_CNT(edev); 108562306a36Sopenharmony_ci channels->max_tx = QEDE_MAX_RSS_CNT(edev); 108662306a36Sopenharmony_ci channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx - 108762306a36Sopenharmony_ci edev->fp_num_rx; 108862306a36Sopenharmony_ci channels->tx_count = edev->fp_num_tx; 108962306a36Sopenharmony_ci channels->rx_count = edev->fp_num_rx; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic int qede_set_channels(struct net_device *dev, 109362306a36Sopenharmony_ci struct ethtool_channels *channels) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 109662306a36Sopenharmony_ci u32 count; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 109962306a36Sopenharmony_ci "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n", 110062306a36Sopenharmony_ci channels->rx_count, channels->tx_count, 110162306a36Sopenharmony_ci channels->other_count, channels->combined_count); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci count = channels->rx_count + channels->tx_count + 110462306a36Sopenharmony_ci channels->combined_count; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* We don't support `other' channels */ 110762306a36Sopenharmony_ci if (channels->other_count) { 110862306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 110962306a36Sopenharmony_ci "command parameters not supported\n"); 111062306a36Sopenharmony_ci return -EINVAL; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (!(channels->combined_count || (channels->rx_count && 111462306a36Sopenharmony_ci channels->tx_count))) { 111562306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 111662306a36Sopenharmony_ci "need to request at least one transmit and one receive channel\n"); 111762306a36Sopenharmony_ci return -EINVAL; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci if (count > QEDE_MAX_RSS_CNT(edev)) { 112162306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 112262306a36Sopenharmony_ci "requested channels = %d max supported channels = %d\n", 112362306a36Sopenharmony_ci count, QEDE_MAX_RSS_CNT(edev)); 112462306a36Sopenharmony_ci return -EINVAL; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci /* Check if there was a change in the active parameters */ 112862306a36Sopenharmony_ci if ((count == QEDE_QUEUE_CNT(edev)) && 112962306a36Sopenharmony_ci (channels->tx_count == edev->fp_num_tx) && 113062306a36Sopenharmony_ci (channels->rx_count == edev->fp_num_rx)) { 113162306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 113262306a36Sopenharmony_ci "No change in active parameters\n"); 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* We need the number of queues to be divisible between the hwfns */ 113762306a36Sopenharmony_ci if ((count % edev->dev_info.common.num_hwfns) || 113862306a36Sopenharmony_ci (channels->tx_count % edev->dev_info.common.num_hwfns) || 113962306a36Sopenharmony_ci (channels->rx_count % edev->dev_info.common.num_hwfns)) { 114062306a36Sopenharmony_ci DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 114162306a36Sopenharmony_ci "Number of channels must be divisible by %04x\n", 114262306a36Sopenharmony_ci edev->dev_info.common.num_hwfns); 114362306a36Sopenharmony_ci return -EINVAL; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* Set number of queues and reload if necessary */ 114762306a36Sopenharmony_ci edev->req_queues = count; 114862306a36Sopenharmony_ci edev->req_num_tx = channels->tx_count; 114962306a36Sopenharmony_ci edev->req_num_rx = channels->rx_count; 115062306a36Sopenharmony_ci /* Reset the indirection table if rx queue count is updated */ 115162306a36Sopenharmony_ci if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) { 115262306a36Sopenharmony_ci edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED; 115362306a36Sopenharmony_ci memset(edev->rss_ind_table, 0, sizeof(edev->rss_ind_table)); 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci qede_reload(edev, NULL, false); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci return 0; 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic int qede_get_ts_info(struct net_device *dev, 116262306a36Sopenharmony_ci struct ethtool_ts_info *info) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci return qede_ptp_get_ts_info(edev, info); 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic int qede_set_phys_id(struct net_device *dev, 117062306a36Sopenharmony_ci enum ethtool_phys_id_state state) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 117362306a36Sopenharmony_ci u8 led_state = 0; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci switch (state) { 117662306a36Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 117762306a36Sopenharmony_ci return 1; /* cycle on/off once per second */ 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci case ETHTOOL_ID_ON: 118062306a36Sopenharmony_ci led_state = QED_LED_MODE_ON; 118162306a36Sopenharmony_ci break; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci case ETHTOOL_ID_OFF: 118462306a36Sopenharmony_ci led_state = QED_LED_MODE_OFF; 118562306a36Sopenharmony_ci break; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 118862306a36Sopenharmony_ci led_state = QED_LED_MODE_RESTORE; 118962306a36Sopenharmony_ci break; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci edev->ops->common->set_led(edev->cdev, led_state); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci return 0; 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci switch (info->flow_type) { 120262306a36Sopenharmony_ci case TCP_V4_FLOW: 120362306a36Sopenharmony_ci case TCP_V6_FLOW: 120462306a36Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 120562306a36Sopenharmony_ci break; 120662306a36Sopenharmony_ci case UDP_V4_FLOW: 120762306a36Sopenharmony_ci if (edev->rss_caps & QED_RSS_IPV4_UDP) 120862306a36Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 120962306a36Sopenharmony_ci break; 121062306a36Sopenharmony_ci case UDP_V6_FLOW: 121162306a36Sopenharmony_ci if (edev->rss_caps & QED_RSS_IPV6_UDP) 121262306a36Sopenharmony_ci info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 121362306a36Sopenharmony_ci break; 121462306a36Sopenharmony_ci case IPV4_FLOW: 121562306a36Sopenharmony_ci case IPV6_FLOW: 121662306a36Sopenharmony_ci break; 121762306a36Sopenharmony_ci default: 121862306a36Sopenharmony_ci info->data = 0; 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci return 0; 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_cistatic int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 122662306a36Sopenharmony_ci u32 *rule_locs) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 122962306a36Sopenharmony_ci int rc = 0; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci switch (info->cmd) { 123262306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 123362306a36Sopenharmony_ci info->data = QEDE_RSS_COUNT(edev); 123462306a36Sopenharmony_ci break; 123562306a36Sopenharmony_ci case ETHTOOL_GRXFH: 123662306a36Sopenharmony_ci rc = qede_get_rss_flags(edev, info); 123762306a36Sopenharmony_ci break; 123862306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 123962306a36Sopenharmony_ci info->rule_cnt = qede_get_arfs_filter_count(edev); 124062306a36Sopenharmony_ci info->data = QEDE_RFS_MAX_FLTR; 124162306a36Sopenharmony_ci break; 124262306a36Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 124362306a36Sopenharmony_ci rc = qede_get_cls_rule_entry(edev, info); 124462306a36Sopenharmony_ci break; 124562306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 124662306a36Sopenharmony_ci rc = qede_get_cls_rule_all(edev, info, rule_locs); 124762306a36Sopenharmony_ci break; 124862306a36Sopenharmony_ci default: 124962306a36Sopenharmony_ci DP_ERR(edev, "Command parameters not supported\n"); 125062306a36Sopenharmony_ci rc = -EOPNOTSUPP; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci return rc; 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 125962306a36Sopenharmony_ci u8 set_caps = 0, clr_caps = 0; 126062306a36Sopenharmony_ci int rc = 0; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 126362306a36Sopenharmony_ci "Set rss flags command parameters: flow type = %d, data = %llu\n", 126462306a36Sopenharmony_ci info->flow_type, info->data); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci switch (info->flow_type) { 126762306a36Sopenharmony_ci case TCP_V4_FLOW: 126862306a36Sopenharmony_ci case TCP_V6_FLOW: 126962306a36Sopenharmony_ci /* For TCP only 4-tuple hash is supported */ 127062306a36Sopenharmony_ci if (info->data ^ (RXH_IP_SRC | RXH_IP_DST | 127162306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 127262306a36Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 127362306a36Sopenharmony_ci return -EINVAL; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci return 0; 127662306a36Sopenharmony_ci case UDP_V4_FLOW: 127762306a36Sopenharmony_ci /* For UDP either 2-tuple hash or 4-tuple hash is supported */ 127862306a36Sopenharmony_ci if (info->data == (RXH_IP_SRC | RXH_IP_DST | 127962306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 128062306a36Sopenharmony_ci set_caps = QED_RSS_IPV4_UDP; 128162306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 128262306a36Sopenharmony_ci "UDP 4-tuple enabled\n"); 128362306a36Sopenharmony_ci } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) { 128462306a36Sopenharmony_ci clr_caps = QED_RSS_IPV4_UDP; 128562306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 128662306a36Sopenharmony_ci "UDP 4-tuple disabled\n"); 128762306a36Sopenharmony_ci } else { 128862306a36Sopenharmony_ci return -EINVAL; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci break; 129162306a36Sopenharmony_ci case UDP_V6_FLOW: 129262306a36Sopenharmony_ci /* For UDP either 2-tuple hash or 4-tuple hash is supported */ 129362306a36Sopenharmony_ci if (info->data == (RXH_IP_SRC | RXH_IP_DST | 129462306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 129562306a36Sopenharmony_ci set_caps = QED_RSS_IPV6_UDP; 129662306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 129762306a36Sopenharmony_ci "UDP 4-tuple enabled\n"); 129862306a36Sopenharmony_ci } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) { 129962306a36Sopenharmony_ci clr_caps = QED_RSS_IPV6_UDP; 130062306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 130162306a36Sopenharmony_ci "UDP 4-tuple disabled\n"); 130262306a36Sopenharmony_ci } else { 130362306a36Sopenharmony_ci return -EINVAL; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci break; 130662306a36Sopenharmony_ci case IPV4_FLOW: 130762306a36Sopenharmony_ci case IPV6_FLOW: 130862306a36Sopenharmony_ci /* For IP only 2-tuple hash is supported */ 130962306a36Sopenharmony_ci if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) { 131062306a36Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 131162306a36Sopenharmony_ci return -EINVAL; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci return 0; 131462306a36Sopenharmony_ci case SCTP_V4_FLOW: 131562306a36Sopenharmony_ci case AH_ESP_V4_FLOW: 131662306a36Sopenharmony_ci case AH_V4_FLOW: 131762306a36Sopenharmony_ci case ESP_V4_FLOW: 131862306a36Sopenharmony_ci case SCTP_V6_FLOW: 131962306a36Sopenharmony_ci case AH_ESP_V6_FLOW: 132062306a36Sopenharmony_ci case AH_V6_FLOW: 132162306a36Sopenharmony_ci case ESP_V6_FLOW: 132262306a36Sopenharmony_ci case IP_USER_FLOW: 132362306a36Sopenharmony_ci case ETHER_FLOW: 132462306a36Sopenharmony_ci /* RSS is not supported for these protocols */ 132562306a36Sopenharmony_ci if (info->data) { 132662306a36Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 132762306a36Sopenharmony_ci return -EINVAL; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci return 0; 133062306a36Sopenharmony_ci default: 133162306a36Sopenharmony_ci return -EINVAL; 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci /* No action is needed if there is no change in the rss capability */ 133562306a36Sopenharmony_ci if (edev->rss_caps == ((edev->rss_caps & ~clr_caps) | set_caps)) 133662306a36Sopenharmony_ci return 0; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci /* Update internal configuration */ 133962306a36Sopenharmony_ci edev->rss_caps = ((edev->rss_caps & ~clr_caps) | set_caps); 134062306a36Sopenharmony_ci edev->rss_params_inited |= QEDE_RSS_CAPS_INITED; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* Re-configure if possible */ 134362306a36Sopenharmony_ci __qede_lock(edev); 134462306a36Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 134562306a36Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 134662306a36Sopenharmony_ci if (!vport_update_params) { 134762306a36Sopenharmony_ci __qede_unlock(edev); 134862306a36Sopenharmony_ci return -ENOMEM; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci qede_fill_rss_params(edev, &vport_update_params->rss_params, 135162306a36Sopenharmony_ci &vport_update_params->update_rss_flg); 135262306a36Sopenharmony_ci rc = edev->ops->vport_update(edev->cdev, vport_update_params); 135362306a36Sopenharmony_ci vfree(vport_update_params); 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci __qede_unlock(edev); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci return rc; 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_cistatic int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info) 136162306a36Sopenharmony_ci{ 136262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 136362306a36Sopenharmony_ci int rc; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci switch (info->cmd) { 136662306a36Sopenharmony_ci case ETHTOOL_SRXFH: 136762306a36Sopenharmony_ci rc = qede_set_rss_flags(edev, info); 136862306a36Sopenharmony_ci break; 136962306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 137062306a36Sopenharmony_ci rc = qede_add_cls_rule(edev, info); 137162306a36Sopenharmony_ci break; 137262306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 137362306a36Sopenharmony_ci rc = qede_delete_flow_filter(edev, info->fs.location); 137462306a36Sopenharmony_ci break; 137562306a36Sopenharmony_ci default: 137662306a36Sopenharmony_ci DP_INFO(edev, "Command parameters not supported\n"); 137762306a36Sopenharmony_ci rc = -EOPNOTSUPP; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci return rc; 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic u32 qede_get_rxfh_indir_size(struct net_device *dev) 138462306a36Sopenharmony_ci{ 138562306a36Sopenharmony_ci return QED_RSS_IND_TABLE_SIZE; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cistatic u32 qede_get_rxfh_key_size(struct net_device *dev) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci return sizeof(edev->rss_key); 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_cistatic int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc) 139662306a36Sopenharmony_ci{ 139762306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 139862306a36Sopenharmony_ci int i; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (hfunc) 140162306a36Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (!indir) 140462306a36Sopenharmony_ci return 0; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) 140762306a36Sopenharmony_ci indir[i] = edev->rss_ind_table[i]; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci if (key) 141062306a36Sopenharmony_ci memcpy(key, edev->rss_key, qede_get_rxfh_key_size(dev)); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci return 0; 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic int qede_set_rxfh(struct net_device *dev, const u32 *indir, 141662306a36Sopenharmony_ci const u8 *key, const u8 hfunc) 141762306a36Sopenharmony_ci{ 141862306a36Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 141962306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 142062306a36Sopenharmony_ci int i, rc = 0; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (edev->dev_info.common.num_hwfns > 1) { 142362306a36Sopenharmony_ci DP_INFO(edev, 142462306a36Sopenharmony_ci "RSS configuration is not supported for 100G devices\n"); 142562306a36Sopenharmony_ci return -EOPNOTSUPP; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 142962306a36Sopenharmony_ci return -EOPNOTSUPP; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (!indir && !key) 143262306a36Sopenharmony_ci return 0; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (indir) { 143562306a36Sopenharmony_ci for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) 143662306a36Sopenharmony_ci edev->rss_ind_table[i] = indir[i]; 143762306a36Sopenharmony_ci edev->rss_params_inited |= QEDE_RSS_INDIR_INITED; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci if (key) { 144162306a36Sopenharmony_ci memcpy(&edev->rss_key, key, qede_get_rxfh_key_size(dev)); 144262306a36Sopenharmony_ci edev->rss_params_inited |= QEDE_RSS_KEY_INITED; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci __qede_lock(edev); 144662306a36Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 144762306a36Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 144862306a36Sopenharmony_ci if (!vport_update_params) { 144962306a36Sopenharmony_ci __qede_unlock(edev); 145062306a36Sopenharmony_ci return -ENOMEM; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci qede_fill_rss_params(edev, &vport_update_params->rss_params, 145362306a36Sopenharmony_ci &vport_update_params->update_rss_flg); 145462306a36Sopenharmony_ci rc = edev->ops->vport_update(edev->cdev, vport_update_params); 145562306a36Sopenharmony_ci vfree(vport_update_params); 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci __qede_unlock(edev); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci return rc; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci/* This function enables the interrupt generation and the NAPI on the device */ 146362306a36Sopenharmony_cistatic void qede_netif_start(struct qede_dev *edev) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci int i; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if (!netif_running(edev->ndev)) 146862306a36Sopenharmony_ci return; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci for_each_queue(i) { 147162306a36Sopenharmony_ci /* Update and reenable interrupts */ 147262306a36Sopenharmony_ci qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_ENABLE, 1); 147362306a36Sopenharmony_ci napi_enable(&edev->fp_array[i].napi); 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci/* This function disables the NAPI and the interrupt generation on the device */ 147862306a36Sopenharmony_cistatic void qede_netif_stop(struct qede_dev *edev) 147962306a36Sopenharmony_ci{ 148062306a36Sopenharmony_ci int i; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci for_each_queue(i) { 148362306a36Sopenharmony_ci napi_disable(&edev->fp_array[i].napi); 148462306a36Sopenharmony_ci /* Disable interrupts */ 148562306a36Sopenharmony_ci qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_DISABLE, 0); 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic int qede_selftest_transmit_traffic(struct qede_dev *edev, 149062306a36Sopenharmony_ci struct sk_buff *skb) 149162306a36Sopenharmony_ci{ 149262306a36Sopenharmony_ci struct qede_tx_queue *txq = NULL; 149362306a36Sopenharmony_ci struct eth_tx_1st_bd *first_bd; 149462306a36Sopenharmony_ci dma_addr_t mapping; 149562306a36Sopenharmony_ci int i, idx; 149662306a36Sopenharmony_ci u16 val; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci for_each_queue(i) { 149962306a36Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 150262306a36Sopenharmony_ci txq = QEDE_FP_TC0_TXQ(fp); 150362306a36Sopenharmony_ci break; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci if (!txq) { 150862306a36Sopenharmony_ci DP_NOTICE(edev, "Tx path is not available\n"); 150962306a36Sopenharmony_ci return -1; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci /* Fill the entry in the SW ring and the BDs in the FW ring */ 151362306a36Sopenharmony_ci idx = txq->sw_tx_prod; 151462306a36Sopenharmony_ci txq->sw_tx_ring.skbs[idx].skb = skb; 151562306a36Sopenharmony_ci first_bd = qed_chain_produce(&txq->tx_pbl); 151662306a36Sopenharmony_ci memset(first_bd, 0, sizeof(*first_bd)); 151762306a36Sopenharmony_ci val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT; 151862306a36Sopenharmony_ci first_bd->data.bd_flags.bitfields = val; 151962306a36Sopenharmony_ci val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK; 152062306a36Sopenharmony_ci val = val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; 152162306a36Sopenharmony_ci first_bd->data.bitfields |= cpu_to_le16(val); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* Map skb linear data for DMA and set in the first BD */ 152462306a36Sopenharmony_ci mapping = dma_map_single(&edev->pdev->dev, skb->data, 152562306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 152662306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) { 152762306a36Sopenharmony_ci DP_NOTICE(edev, "SKB mapping failed\n"); 152862306a36Sopenharmony_ci return -ENOMEM; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb)); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci /* update the first BD with the actual num BDs */ 153362306a36Sopenharmony_ci first_bd->data.nbds = 1; 153462306a36Sopenharmony_ci txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; 153562306a36Sopenharmony_ci /* 'next page' entries are counted in the producer value */ 153662306a36Sopenharmony_ci val = qed_chain_get_prod_idx(&txq->tx_pbl); 153762306a36Sopenharmony_ci txq->tx_db.data.bd_prod = cpu_to_le16(val); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* wmb makes sure that the BDs data is updated before updating the 154062306a36Sopenharmony_ci * producer, otherwise FW may read old data from the BDs. 154162306a36Sopenharmony_ci */ 154262306a36Sopenharmony_ci wmb(); 154362306a36Sopenharmony_ci barrier(); 154462306a36Sopenharmony_ci writel(txq->tx_db.raw, txq->doorbell_addr); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) { 154762306a36Sopenharmony_ci if (qede_txq_has_work(txq)) 154862306a36Sopenharmony_ci break; 154962306a36Sopenharmony_ci usleep_range(100, 200); 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (!qede_txq_has_work(txq)) { 155362306a36Sopenharmony_ci DP_NOTICE(edev, "Tx completion didn't happen\n"); 155462306a36Sopenharmony_ci return -1; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl); 155862306a36Sopenharmony_ci dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), 155962306a36Sopenharmony_ci BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); 156062306a36Sopenharmony_ci txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; 156162306a36Sopenharmony_ci txq->sw_tx_ring.skbs[idx].skb = NULL; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci return 0; 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic int qede_selftest_receive_traffic(struct qede_dev *edev) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci u16 sw_rx_index, len; 156962306a36Sopenharmony_ci struct eth_fast_path_rx_reg_cqe *fp_cqe; 157062306a36Sopenharmony_ci struct qede_rx_queue *rxq = NULL; 157162306a36Sopenharmony_ci struct sw_rx_data *sw_rx_data; 157262306a36Sopenharmony_ci union eth_rx_cqe *cqe; 157362306a36Sopenharmony_ci int i, iter, rc = 0; 157462306a36Sopenharmony_ci u8 *data_ptr; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci for_each_queue(i) { 157762306a36Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_RX) { 157862306a36Sopenharmony_ci rxq = edev->fp_array[i].rxq; 157962306a36Sopenharmony_ci break; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci if (!rxq) { 158462306a36Sopenharmony_ci DP_NOTICE(edev, "Rx path is not available\n"); 158562306a36Sopenharmony_ci return -1; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci /* The packet is expected to receive on rx-queue 0 even though RSS is 158962306a36Sopenharmony_ci * enabled. This is because the queue 0 is configured as the default 159062306a36Sopenharmony_ci * queue and that the loopback traffic is not IP. 159162306a36Sopenharmony_ci */ 159262306a36Sopenharmony_ci for (iter = 0; iter < QEDE_SELFTEST_POLL_COUNT; iter++) { 159362306a36Sopenharmony_ci if (!qede_has_rx_work(rxq)) { 159462306a36Sopenharmony_ci usleep_range(100, 200); 159562306a36Sopenharmony_ci continue; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci /* Get the CQE from the completion ring */ 159962306a36Sopenharmony_ci cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* Get the data from the SW ring */ 160262306a36Sopenharmony_ci sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX; 160362306a36Sopenharmony_ci sw_rx_data = &rxq->sw_rx_ring[sw_rx_index]; 160462306a36Sopenharmony_ci fp_cqe = &cqe->fast_path_regular; 160562306a36Sopenharmony_ci len = le16_to_cpu(fp_cqe->len_on_first_bd); 160662306a36Sopenharmony_ci data_ptr = (u8 *)(page_address(sw_rx_data->data) + 160762306a36Sopenharmony_ci fp_cqe->placement_offset + 160862306a36Sopenharmony_ci sw_rx_data->page_offset + 160962306a36Sopenharmony_ci rxq->rx_headroom); 161062306a36Sopenharmony_ci if (ether_addr_equal(data_ptr, edev->ndev->dev_addr) && 161162306a36Sopenharmony_ci ether_addr_equal(data_ptr + ETH_ALEN, 161262306a36Sopenharmony_ci edev->ndev->dev_addr)) { 161362306a36Sopenharmony_ci for (i = ETH_HLEN; i < len; i++) 161462306a36Sopenharmony_ci if (data_ptr[i] != (unsigned char)(i & 0xff)) { 161562306a36Sopenharmony_ci rc = -1; 161662306a36Sopenharmony_ci break; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci qede_recycle_rx_bd_ring(rxq, 1); 162062306a36Sopenharmony_ci qed_chain_recycle_consumed(&rxq->rx_comp_ring); 162162306a36Sopenharmony_ci break; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci DP_INFO(edev, "Not the transmitted packet\n"); 162562306a36Sopenharmony_ci qede_recycle_rx_bd_ring(rxq, 1); 162662306a36Sopenharmony_ci qed_chain_recycle_consumed(&rxq->rx_comp_ring); 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (iter == QEDE_SELFTEST_POLL_COUNT) { 163062306a36Sopenharmony_ci DP_NOTICE(edev, "Failed to receive the traffic\n"); 163162306a36Sopenharmony_ci return -1; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci qede_update_rx_prod(edev, rxq); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci return rc; 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cistatic int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode) 164062306a36Sopenharmony_ci{ 164162306a36Sopenharmony_ci struct qed_link_params link_params; 164262306a36Sopenharmony_ci struct sk_buff *skb = NULL; 164362306a36Sopenharmony_ci int rc = 0, i; 164462306a36Sopenharmony_ci u32 pkt_size; 164562306a36Sopenharmony_ci u8 *packet; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci if (!netif_running(edev->ndev)) { 164862306a36Sopenharmony_ci DP_NOTICE(edev, "Interface is down\n"); 164962306a36Sopenharmony_ci return -EINVAL; 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci qede_netif_stop(edev); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci /* Bring up the link in Loopback mode */ 165562306a36Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 165662306a36Sopenharmony_ci link_params.link_up = true; 165762306a36Sopenharmony_ci link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE; 165862306a36Sopenharmony_ci link_params.loopback_mode = loopback_mode; 165962306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci /* Wait for loopback configuration to apply */ 166262306a36Sopenharmony_ci msleep_interruptible(500); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci /* Setting max packet size to 1.5K to avoid data being split over 166562306a36Sopenharmony_ci * multiple BDs in cases where MTU > PAGE_SIZE. 166662306a36Sopenharmony_ci */ 166762306a36Sopenharmony_ci pkt_size = (((edev->ndev->mtu < ETH_DATA_LEN) ? 166862306a36Sopenharmony_ci edev->ndev->mtu : ETH_DATA_LEN) + ETH_HLEN); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci skb = netdev_alloc_skb(edev->ndev, pkt_size); 167162306a36Sopenharmony_ci if (!skb) { 167262306a36Sopenharmony_ci DP_INFO(edev, "Can't allocate skb\n"); 167362306a36Sopenharmony_ci rc = -ENOMEM; 167462306a36Sopenharmony_ci goto test_loopback_exit; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci packet = skb_put(skb, pkt_size); 167762306a36Sopenharmony_ci ether_addr_copy(packet, edev->ndev->dev_addr); 167862306a36Sopenharmony_ci ether_addr_copy(packet + ETH_ALEN, edev->ndev->dev_addr); 167962306a36Sopenharmony_ci memset(packet + (2 * ETH_ALEN), 0x77, (ETH_HLEN - (2 * ETH_ALEN))); 168062306a36Sopenharmony_ci for (i = ETH_HLEN; i < pkt_size; i++) 168162306a36Sopenharmony_ci packet[i] = (unsigned char)(i & 0xff); 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci rc = qede_selftest_transmit_traffic(edev, skb); 168462306a36Sopenharmony_ci if (rc) 168562306a36Sopenharmony_ci goto test_loopback_exit; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci rc = qede_selftest_receive_traffic(edev); 168862306a36Sopenharmony_ci if (rc) 168962306a36Sopenharmony_ci goto test_loopback_exit; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_RX_STATUS, "Loopback test successful\n"); 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_citest_loopback_exit: 169462306a36Sopenharmony_ci dev_kfree_skb(skb); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci /* Bring up the link in Normal mode */ 169762306a36Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 169862306a36Sopenharmony_ci link_params.link_up = true; 169962306a36Sopenharmony_ci link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE; 170062306a36Sopenharmony_ci link_params.loopback_mode = QED_LINK_LOOPBACK_NONE; 170162306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci /* Wait for loopback configuration to apply */ 170462306a36Sopenharmony_ci msleep_interruptible(500); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci qede_netif_start(edev); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci return rc; 170962306a36Sopenharmony_ci} 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic void qede_self_test(struct net_device *dev, 171262306a36Sopenharmony_ci struct ethtool_test *etest, u64 *buf) 171362306a36Sopenharmony_ci{ 171462306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 171762306a36Sopenharmony_ci "Self-test command parameters: offline = %d, external_lb = %d\n", 171862306a36Sopenharmony_ci (etest->flags & ETH_TEST_FL_OFFLINE), 171962306a36Sopenharmony_ci (etest->flags & ETH_TEST_FL_EXTERNAL_LB) >> 2); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci memset(buf, 0, sizeof(u64) * QEDE_ETHTOOL_TEST_MAX); 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci if (etest->flags & ETH_TEST_FL_OFFLINE) { 172462306a36Sopenharmony_ci if (qede_selftest_run_loopback(edev, 172562306a36Sopenharmony_ci QED_LINK_LOOPBACK_INT_PHY)) { 172662306a36Sopenharmony_ci buf[QEDE_ETHTOOL_INT_LOOPBACK] = 1; 172762306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (edev->ops->common->selftest->selftest_interrupt(edev->cdev)) { 173262306a36Sopenharmony_ci buf[QEDE_ETHTOOL_INTERRUPT_TEST] = 1; 173362306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if (edev->ops->common->selftest->selftest_memory(edev->cdev)) { 173762306a36Sopenharmony_ci buf[QEDE_ETHTOOL_MEMORY_TEST] = 1; 173862306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci if (edev->ops->common->selftest->selftest_register(edev->cdev)) { 174262306a36Sopenharmony_ci buf[QEDE_ETHTOOL_REGISTER_TEST] = 1; 174362306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci if (edev->ops->common->selftest->selftest_clock(edev->cdev)) { 174762306a36Sopenharmony_ci buf[QEDE_ETHTOOL_CLOCK_TEST] = 1; 174862306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci if (edev->ops->common->selftest->selftest_nvram(edev->cdev)) { 175262306a36Sopenharmony_ci buf[QEDE_ETHTOOL_NVRAM_TEST] = 1; 175362306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci} 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_cistatic int qede_set_tunable(struct net_device *dev, 175862306a36Sopenharmony_ci const struct ethtool_tunable *tuna, 175962306a36Sopenharmony_ci const void *data) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 176262306a36Sopenharmony_ci u32 val; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci switch (tuna->id) { 176562306a36Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 176662306a36Sopenharmony_ci val = *(u32 *)data; 176762306a36Sopenharmony_ci if (val < QEDE_MIN_PKT_LEN || val > QEDE_RX_HDR_SIZE) { 176862306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 176962306a36Sopenharmony_ci "Invalid rx copy break value, range is [%u, %u]", 177062306a36Sopenharmony_ci QEDE_MIN_PKT_LEN, QEDE_RX_HDR_SIZE); 177162306a36Sopenharmony_ci return -EINVAL; 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci edev->rx_copybreak = *(u32 *)data; 177562306a36Sopenharmony_ci break; 177662306a36Sopenharmony_ci default: 177762306a36Sopenharmony_ci return -EOPNOTSUPP; 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci return 0; 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_cistatic int qede_get_tunable(struct net_device *dev, 178462306a36Sopenharmony_ci const struct ethtool_tunable *tuna, void *data) 178562306a36Sopenharmony_ci{ 178662306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci switch (tuna->id) { 178962306a36Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 179062306a36Sopenharmony_ci *(u32 *)data = edev->rx_copybreak; 179162306a36Sopenharmony_ci break; 179262306a36Sopenharmony_ci default: 179362306a36Sopenharmony_ci return -EOPNOTSUPP; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci return 0; 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_cistatic int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 180262306a36Sopenharmony_ci struct qed_link_output current_link; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 180562306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (!current_link.eee_supported) { 180862306a36Sopenharmony_ci DP_INFO(edev, "EEE is not supported\n"); 180962306a36Sopenharmony_ci return -EOPNOTSUPP; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci if (current_link.eee.adv_caps & QED_EEE_1G_ADV) 181362306a36Sopenharmony_ci edata->advertised = ADVERTISED_1000baseT_Full; 181462306a36Sopenharmony_ci if (current_link.eee.adv_caps & QED_EEE_10G_ADV) 181562306a36Sopenharmony_ci edata->advertised |= ADVERTISED_10000baseT_Full; 181662306a36Sopenharmony_ci if (current_link.sup_caps & QED_EEE_1G_ADV) 181762306a36Sopenharmony_ci edata->supported = ADVERTISED_1000baseT_Full; 181862306a36Sopenharmony_ci if (current_link.sup_caps & QED_EEE_10G_ADV) 181962306a36Sopenharmony_ci edata->supported |= ADVERTISED_10000baseT_Full; 182062306a36Sopenharmony_ci if (current_link.eee.lp_adv_caps & QED_EEE_1G_ADV) 182162306a36Sopenharmony_ci edata->lp_advertised = ADVERTISED_1000baseT_Full; 182262306a36Sopenharmony_ci if (current_link.eee.lp_adv_caps & QED_EEE_10G_ADV) 182362306a36Sopenharmony_ci edata->lp_advertised |= ADVERTISED_10000baseT_Full; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci edata->tx_lpi_timer = current_link.eee.tx_lpi_timer; 182662306a36Sopenharmony_ci edata->eee_enabled = current_link.eee.enable; 182762306a36Sopenharmony_ci edata->tx_lpi_enabled = current_link.eee.tx_lpi_enable; 182862306a36Sopenharmony_ci edata->eee_active = current_link.eee_active; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci return 0; 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cistatic int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 183662306a36Sopenharmony_ci struct qed_link_output current_link; 183762306a36Sopenharmony_ci struct qed_link_params params; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci if (!edev->ops->common->can_link_change(edev->cdev)) { 184062306a36Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 184162306a36Sopenharmony_ci return -EOPNOTSUPP; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci memset(¤t_link, 0, sizeof(current_link)); 184562306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, ¤t_link); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci if (!current_link.eee_supported) { 184862306a36Sopenharmony_ci DP_INFO(edev, "EEE is not supported\n"); 184962306a36Sopenharmony_ci return -EOPNOTSUPP; 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 185362306a36Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_EEE_CONFIG; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci if (!(edata->advertised & (ADVERTISED_1000baseT_Full | 185662306a36Sopenharmony_ci ADVERTISED_10000baseT_Full)) || 185762306a36Sopenharmony_ci ((edata->advertised & (ADVERTISED_1000baseT_Full | 185862306a36Sopenharmony_ci ADVERTISED_10000baseT_Full)) != 185962306a36Sopenharmony_ci edata->advertised)) { 186062306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 186162306a36Sopenharmony_ci "Invalid advertised capabilities %d\n", 186262306a36Sopenharmony_ci edata->advertised); 186362306a36Sopenharmony_ci return -EINVAL; 186462306a36Sopenharmony_ci } 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci if (edata->advertised & ADVERTISED_1000baseT_Full) 186762306a36Sopenharmony_ci params.eee.adv_caps = QED_EEE_1G_ADV; 186862306a36Sopenharmony_ci if (edata->advertised & ADVERTISED_10000baseT_Full) 186962306a36Sopenharmony_ci params.eee.adv_caps |= QED_EEE_10G_ADV; 187062306a36Sopenharmony_ci params.eee.enable = edata->eee_enabled; 187162306a36Sopenharmony_ci params.eee.tx_lpi_enable = edata->tx_lpi_enabled; 187262306a36Sopenharmony_ci params.eee.tx_lpi_timer = edata->tx_lpi_timer; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci params.link_up = true; 187562306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci return 0; 187862306a36Sopenharmony_ci} 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_cistatic u32 qede_link_to_ethtool_fec(u32 link_fec) 188162306a36Sopenharmony_ci{ 188262306a36Sopenharmony_ci u32 eth_fec = 0; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci if (link_fec & QED_FEC_MODE_NONE) 188562306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_OFF; 188662306a36Sopenharmony_ci if (link_fec & QED_FEC_MODE_FIRECODE) 188762306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_BASER; 188862306a36Sopenharmony_ci if (link_fec & QED_FEC_MODE_RS) 188962306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_RS; 189062306a36Sopenharmony_ci if (link_fec & QED_FEC_MODE_AUTO) 189162306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_AUTO; 189262306a36Sopenharmony_ci if (link_fec & QED_FEC_MODE_UNSUPPORTED) 189362306a36Sopenharmony_ci eth_fec |= ETHTOOL_FEC_NONE; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci return eth_fec; 189662306a36Sopenharmony_ci} 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_cistatic u32 qede_ethtool_to_link_fec(u32 eth_fec) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci u32 link_fec = 0; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_OFF) 190362306a36Sopenharmony_ci link_fec |= QED_FEC_MODE_NONE; 190462306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_BASER) 190562306a36Sopenharmony_ci link_fec |= QED_FEC_MODE_FIRECODE; 190662306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_RS) 190762306a36Sopenharmony_ci link_fec |= QED_FEC_MODE_RS; 190862306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_AUTO) 190962306a36Sopenharmony_ci link_fec |= QED_FEC_MODE_AUTO; 191062306a36Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_NONE) 191162306a36Sopenharmony_ci link_fec |= QED_FEC_MODE_UNSUPPORTED; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci return link_fec; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic int qede_get_fecparam(struct net_device *dev, 191762306a36Sopenharmony_ci struct ethtool_fecparam *fecparam) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 192062306a36Sopenharmony_ci struct qed_link_output curr_link; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci memset(&curr_link, 0, sizeof(curr_link)); 192362306a36Sopenharmony_ci edev->ops->common->get_link(edev->cdev, &curr_link); 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci fecparam->active_fec = qede_link_to_ethtool_fec(curr_link.active_fec); 192662306a36Sopenharmony_ci fecparam->fec = qede_link_to_ethtool_fec(curr_link.sup_fec); 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci return 0; 192962306a36Sopenharmony_ci} 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_cistatic int qede_set_fecparam(struct net_device *dev, 193262306a36Sopenharmony_ci struct ethtool_fecparam *fecparam) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 193562306a36Sopenharmony_ci struct qed_link_params params; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 193862306a36Sopenharmony_ci DP_INFO(edev, "Link settings are not allowed to be changed\n"); 193962306a36Sopenharmony_ci return -EOPNOTSUPP; 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 194362306a36Sopenharmony_ci params.override_flags |= QED_LINK_OVERRIDE_FEC_CONFIG; 194462306a36Sopenharmony_ci params.fec = qede_ethtool_to_link_fec(fecparam->fec); 194562306a36Sopenharmony_ci params.link_up = true; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, ¶ms); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci return 0; 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_cistatic int qede_get_module_info(struct net_device *dev, 195362306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 195462306a36Sopenharmony_ci{ 195562306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 195662306a36Sopenharmony_ci u8 buf[4]; 195762306a36Sopenharmony_ci int rc; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci /* Read first 4 bytes to find the sfp type */ 196062306a36Sopenharmony_ci rc = edev->ops->common->read_module_eeprom(edev->cdev, buf, 196162306a36Sopenharmony_ci QED_I2C_DEV_ADDR_A0, 0, 4); 196262306a36Sopenharmony_ci if (rc) { 196362306a36Sopenharmony_ci DP_ERR(edev, "Failed reading EEPROM data %d\n", rc); 196462306a36Sopenharmony_ci return rc; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci switch (buf[0]) { 196862306a36Sopenharmony_ci case 0x3: /* SFP, SFP+, SFP-28 */ 196962306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 197062306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 197162306a36Sopenharmony_ci break; 197262306a36Sopenharmony_ci case 0xc: /* QSFP */ 197362306a36Sopenharmony_ci case 0xd: /* QSFP+ */ 197462306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 197562306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 197662306a36Sopenharmony_ci break; 197762306a36Sopenharmony_ci case 0x11: /* QSFP-28 */ 197862306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 197962306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 198062306a36Sopenharmony_ci break; 198162306a36Sopenharmony_ci default: 198262306a36Sopenharmony_ci DP_ERR(edev, "Unknown transceiver type 0x%x\n", buf[0]); 198362306a36Sopenharmony_ci return -EINVAL; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci return 0; 198762306a36Sopenharmony_ci} 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_cistatic int qede_get_module_eeprom(struct net_device *dev, 199062306a36Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 199162306a36Sopenharmony_ci{ 199262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 199362306a36Sopenharmony_ci u32 start_addr = ee->offset, size = 0; 199462306a36Sopenharmony_ci u8 *buf = data; 199562306a36Sopenharmony_ci int rc = 0; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci /* Read A0 section */ 199862306a36Sopenharmony_ci if (ee->offset < ETH_MODULE_SFF_8079_LEN) { 199962306a36Sopenharmony_ci /* Limit transfer size to the A0 section boundary */ 200062306a36Sopenharmony_ci if (ee->offset + ee->len > ETH_MODULE_SFF_8079_LEN) 200162306a36Sopenharmony_ci size = ETH_MODULE_SFF_8079_LEN - ee->offset; 200262306a36Sopenharmony_ci else 200362306a36Sopenharmony_ci size = ee->len; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci rc = edev->ops->common->read_module_eeprom(edev->cdev, buf, 200662306a36Sopenharmony_ci QED_I2C_DEV_ADDR_A0, 200762306a36Sopenharmony_ci start_addr, size); 200862306a36Sopenharmony_ci if (rc) { 200962306a36Sopenharmony_ci DP_ERR(edev, "Failed reading A0 section %d\n", rc); 201062306a36Sopenharmony_ci return rc; 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci buf += size; 201462306a36Sopenharmony_ci start_addr += size; 201562306a36Sopenharmony_ci } 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci /* Read A2 section */ 201862306a36Sopenharmony_ci if (start_addr >= ETH_MODULE_SFF_8079_LEN && 201962306a36Sopenharmony_ci start_addr < ETH_MODULE_SFF_8472_LEN) { 202062306a36Sopenharmony_ci size = ee->len - size; 202162306a36Sopenharmony_ci /* Limit transfer size to the A2 section boundary */ 202262306a36Sopenharmony_ci if (start_addr + size > ETH_MODULE_SFF_8472_LEN) 202362306a36Sopenharmony_ci size = ETH_MODULE_SFF_8472_LEN - start_addr; 202462306a36Sopenharmony_ci start_addr -= ETH_MODULE_SFF_8079_LEN; 202562306a36Sopenharmony_ci rc = edev->ops->common->read_module_eeprom(edev->cdev, buf, 202662306a36Sopenharmony_ci QED_I2C_DEV_ADDR_A2, 202762306a36Sopenharmony_ci start_addr, size); 202862306a36Sopenharmony_ci if (rc) { 202962306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 203062306a36Sopenharmony_ci "Failed reading A2 section %d\n", rc); 203162306a36Sopenharmony_ci return 0; 203262306a36Sopenharmony_ci } 203362306a36Sopenharmony_ci } 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci return rc; 203662306a36Sopenharmony_ci} 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_cistatic int qede_set_dump(struct net_device *dev, struct ethtool_dump *val) 203962306a36Sopenharmony_ci{ 204062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 204162306a36Sopenharmony_ci int rc = 0; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (edev->dump_info.cmd == QEDE_DUMP_CMD_NONE) { 204462306a36Sopenharmony_ci if (val->flag > QEDE_DUMP_CMD_MAX) { 204562306a36Sopenharmony_ci DP_ERR(edev, "Invalid command %d\n", val->flag); 204662306a36Sopenharmony_ci return -EINVAL; 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci edev->dump_info.cmd = val->flag; 204962306a36Sopenharmony_ci edev->dump_info.num_args = 0; 205062306a36Sopenharmony_ci return 0; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (edev->dump_info.num_args == QEDE_DUMP_MAX_ARGS) { 205462306a36Sopenharmony_ci DP_ERR(edev, "Arg count = %d\n", edev->dump_info.num_args); 205562306a36Sopenharmony_ci return -EINVAL; 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci switch (edev->dump_info.cmd) { 205962306a36Sopenharmony_ci case QEDE_DUMP_CMD_NVM_CFG: 206062306a36Sopenharmony_ci edev->dump_info.args[edev->dump_info.num_args] = val->flag; 206162306a36Sopenharmony_ci edev->dump_info.num_args++; 206262306a36Sopenharmony_ci break; 206362306a36Sopenharmony_ci case QEDE_DUMP_CMD_GRCDUMP: 206462306a36Sopenharmony_ci rc = edev->ops->common->set_grc_config(edev->cdev, 206562306a36Sopenharmony_ci val->flag, 1); 206662306a36Sopenharmony_ci break; 206762306a36Sopenharmony_ci default: 206862306a36Sopenharmony_ci break; 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci return rc; 207262306a36Sopenharmony_ci} 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_cistatic int qede_get_dump_flag(struct net_device *dev, 207562306a36Sopenharmony_ci struct ethtool_dump *dump) 207662306a36Sopenharmony_ci{ 207762306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci if (!edev->ops || !edev->ops->common) { 208062306a36Sopenharmony_ci DP_ERR(edev, "Edev ops not populated\n"); 208162306a36Sopenharmony_ci return -EINVAL; 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci dump->version = QEDE_DUMP_VERSION; 208562306a36Sopenharmony_ci switch (edev->dump_info.cmd) { 208662306a36Sopenharmony_ci case QEDE_DUMP_CMD_NVM_CFG: 208762306a36Sopenharmony_ci dump->flag = QEDE_DUMP_CMD_NVM_CFG; 208862306a36Sopenharmony_ci dump->len = edev->ops->common->read_nvm_cfg_len(edev->cdev, 208962306a36Sopenharmony_ci edev->dump_info.args[0]); 209062306a36Sopenharmony_ci break; 209162306a36Sopenharmony_ci case QEDE_DUMP_CMD_GRCDUMP: 209262306a36Sopenharmony_ci dump->flag = QEDE_DUMP_CMD_GRCDUMP; 209362306a36Sopenharmony_ci dump->len = edev->ops->common->dbg_all_data_size(edev->cdev); 209462306a36Sopenharmony_ci break; 209562306a36Sopenharmony_ci default: 209662306a36Sopenharmony_ci DP_ERR(edev, "Invalid cmd = %d\n", edev->dump_info.cmd); 209762306a36Sopenharmony_ci return -EINVAL; 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 210162306a36Sopenharmony_ci "dump->version = 0x%x dump->flag = %d dump->len = %d\n", 210262306a36Sopenharmony_ci dump->version, dump->flag, dump->len); 210362306a36Sopenharmony_ci return 0; 210462306a36Sopenharmony_ci} 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_cistatic int qede_get_dump_data(struct net_device *dev, 210762306a36Sopenharmony_ci struct ethtool_dump *dump, void *buf) 210862306a36Sopenharmony_ci{ 210962306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 211062306a36Sopenharmony_ci int rc = 0; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci if (!edev->ops || !edev->ops->common) { 211362306a36Sopenharmony_ci DP_ERR(edev, "Edev ops not populated\n"); 211462306a36Sopenharmony_ci rc = -EINVAL; 211562306a36Sopenharmony_ci goto err; 211662306a36Sopenharmony_ci } 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci switch (edev->dump_info.cmd) { 211962306a36Sopenharmony_ci case QEDE_DUMP_CMD_NVM_CFG: 212062306a36Sopenharmony_ci if (edev->dump_info.num_args != QEDE_DUMP_NVM_ARG_COUNT) { 212162306a36Sopenharmony_ci DP_ERR(edev, "Arg count = %d required = %d\n", 212262306a36Sopenharmony_ci edev->dump_info.num_args, 212362306a36Sopenharmony_ci QEDE_DUMP_NVM_ARG_COUNT); 212462306a36Sopenharmony_ci rc = -EINVAL; 212562306a36Sopenharmony_ci goto err; 212662306a36Sopenharmony_ci } 212762306a36Sopenharmony_ci rc = edev->ops->common->read_nvm_cfg(edev->cdev, (u8 **)&buf, 212862306a36Sopenharmony_ci edev->dump_info.args[0], 212962306a36Sopenharmony_ci edev->dump_info.args[1]); 213062306a36Sopenharmony_ci break; 213162306a36Sopenharmony_ci case QEDE_DUMP_CMD_GRCDUMP: 213262306a36Sopenharmony_ci memset(buf, 0, dump->len); 213362306a36Sopenharmony_ci rc = edev->ops->common->dbg_all_data(edev->cdev, buf); 213462306a36Sopenharmony_ci break; 213562306a36Sopenharmony_ci default: 213662306a36Sopenharmony_ci DP_ERR(edev, "Invalid cmd = %d\n", edev->dump_info.cmd); 213762306a36Sopenharmony_ci rc = -EINVAL; 213862306a36Sopenharmony_ci break; 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_cierr: 214262306a36Sopenharmony_ci edev->dump_info.cmd = QEDE_DUMP_CMD_NONE; 214362306a36Sopenharmony_ci edev->dump_info.num_args = 0; 214462306a36Sopenharmony_ci memset(edev->dump_info.args, 0, sizeof(edev->dump_info.args)); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci return rc; 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ciint qede_set_per_coalesce(struct net_device *dev, u32 queue, 215062306a36Sopenharmony_ci struct ethtool_coalesce *coal) 215162306a36Sopenharmony_ci{ 215262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 215362306a36Sopenharmony_ci struct qede_fastpath *fp; 215462306a36Sopenharmony_ci u16 rxc, txc; 215562306a36Sopenharmony_ci int rc = 0; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci if (coal->rx_coalesce_usecs > QED_COALESCE_MAX || 215862306a36Sopenharmony_ci coal->tx_coalesce_usecs > QED_COALESCE_MAX) { 215962306a36Sopenharmony_ci DP_INFO(edev, 216062306a36Sopenharmony_ci "Can't support requested %s coalesce value [max supported value %d]\n", 216162306a36Sopenharmony_ci coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx" 216262306a36Sopenharmony_ci : "tx", 216362306a36Sopenharmony_ci QED_COALESCE_MAX); 216462306a36Sopenharmony_ci return -EINVAL; 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci rxc = (u16)coal->rx_coalesce_usecs; 216862306a36Sopenharmony_ci txc = (u16)coal->tx_coalesce_usecs; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci __qede_lock(edev); 217162306a36Sopenharmony_ci if (queue >= edev->num_queues) { 217262306a36Sopenharmony_ci DP_INFO(edev, "Invalid queue\n"); 217362306a36Sopenharmony_ci rc = -EINVAL; 217462306a36Sopenharmony_ci goto out; 217562306a36Sopenharmony_ci } 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci if (edev->state != QEDE_STATE_OPEN) { 217862306a36Sopenharmony_ci rc = -EINVAL; 217962306a36Sopenharmony_ci goto out; 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci fp = &edev->fp_array[queue]; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci if (edev->fp_array[queue].type & QEDE_FASTPATH_RX) { 218562306a36Sopenharmony_ci rc = edev->ops->common->set_coalesce(edev->cdev, 218662306a36Sopenharmony_ci rxc, 0, 218762306a36Sopenharmony_ci fp->rxq->handle); 218862306a36Sopenharmony_ci if (rc) { 218962306a36Sopenharmony_ci DP_INFO(edev, 219062306a36Sopenharmony_ci "Set RX coalesce error, rc = %d\n", rc); 219162306a36Sopenharmony_ci goto out; 219262306a36Sopenharmony_ci } 219362306a36Sopenharmony_ci edev->coal_entry[queue].rxc = rxc; 219462306a36Sopenharmony_ci edev->coal_entry[queue].isvalid = true; 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci if (edev->fp_array[queue].type & QEDE_FASTPATH_TX) { 219862306a36Sopenharmony_ci rc = edev->ops->common->set_coalesce(edev->cdev, 219962306a36Sopenharmony_ci 0, txc, 220062306a36Sopenharmony_ci fp->txq->handle); 220162306a36Sopenharmony_ci if (rc) { 220262306a36Sopenharmony_ci DP_INFO(edev, 220362306a36Sopenharmony_ci "Set TX coalesce error, rc = %d\n", rc); 220462306a36Sopenharmony_ci goto out; 220562306a36Sopenharmony_ci } 220662306a36Sopenharmony_ci edev->coal_entry[queue].txc = txc; 220762306a36Sopenharmony_ci edev->coal_entry[queue].isvalid = true; 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ciout: 221062306a36Sopenharmony_ci __qede_unlock(edev); 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci return rc; 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_cistatic int qede_get_per_coalesce(struct net_device *dev, 221662306a36Sopenharmony_ci u32 queue, 221762306a36Sopenharmony_ci struct ethtool_coalesce *coal) 221862306a36Sopenharmony_ci{ 221962306a36Sopenharmony_ci void *rx_handle = NULL, *tx_handle = NULL; 222062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 222162306a36Sopenharmony_ci struct qede_fastpath *fp; 222262306a36Sopenharmony_ci u16 rx_coal, tx_coal; 222362306a36Sopenharmony_ci int rc = 0; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci rx_coal = QED_DEFAULT_RX_USECS; 222662306a36Sopenharmony_ci tx_coal = QED_DEFAULT_TX_USECS; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci memset(coal, 0, sizeof(struct ethtool_coalesce)); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci __qede_lock(edev); 223162306a36Sopenharmony_ci if (queue >= edev->num_queues) { 223262306a36Sopenharmony_ci DP_INFO(edev, "Invalid queue\n"); 223362306a36Sopenharmony_ci rc = -EINVAL; 223462306a36Sopenharmony_ci goto out; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci if (edev->state != QEDE_STATE_OPEN) { 223862306a36Sopenharmony_ci rc = -EINVAL; 223962306a36Sopenharmony_ci goto out; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci fp = &edev->fp_array[queue]; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) 224562306a36Sopenharmony_ci rx_handle = fp->rxq->handle; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci rc = edev->ops->get_coalesce(edev->cdev, &rx_coal, 224862306a36Sopenharmony_ci rx_handle); 224962306a36Sopenharmony_ci if (rc) { 225062306a36Sopenharmony_ci DP_INFO(edev, "Read Rx coalesce error\n"); 225162306a36Sopenharmony_ci goto out; 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci fp = &edev->fp_array[queue]; 225562306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) 225662306a36Sopenharmony_ci tx_handle = fp->txq->handle; 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci rc = edev->ops->get_coalesce(edev->cdev, &tx_coal, 225962306a36Sopenharmony_ci tx_handle); 226062306a36Sopenharmony_ci if (rc) 226162306a36Sopenharmony_ci DP_INFO(edev, "Read Tx coalesce error\n"); 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ciout: 226462306a36Sopenharmony_ci __qede_unlock(edev); 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci coal->rx_coalesce_usecs = rx_coal; 226762306a36Sopenharmony_ci coal->tx_coalesce_usecs = tx_coal; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci return rc; 227062306a36Sopenharmony_ci} 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_cistatic const struct ethtool_ops qede_ethtool_ops = { 227362306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 227462306a36Sopenharmony_ci ETHTOOL_COALESCE_STATS_BLOCK_USECS, 227562306a36Sopenharmony_ci .get_link_ksettings = qede_get_link_ksettings, 227662306a36Sopenharmony_ci .set_link_ksettings = qede_set_link_ksettings, 227762306a36Sopenharmony_ci .get_drvinfo = qede_get_drvinfo, 227862306a36Sopenharmony_ci .get_regs_len = qede_get_regs_len, 227962306a36Sopenharmony_ci .get_regs = qede_get_regs, 228062306a36Sopenharmony_ci .get_wol = qede_get_wol, 228162306a36Sopenharmony_ci .set_wol = qede_set_wol, 228262306a36Sopenharmony_ci .get_msglevel = qede_get_msglevel, 228362306a36Sopenharmony_ci .set_msglevel = qede_set_msglevel, 228462306a36Sopenharmony_ci .nway_reset = qede_nway_reset, 228562306a36Sopenharmony_ci .get_link = qede_get_link, 228662306a36Sopenharmony_ci .get_coalesce = qede_get_coalesce, 228762306a36Sopenharmony_ci .set_coalesce = qede_set_coalesce, 228862306a36Sopenharmony_ci .get_ringparam = qede_get_ringparam, 228962306a36Sopenharmony_ci .set_ringparam = qede_set_ringparam, 229062306a36Sopenharmony_ci .get_pauseparam = qede_get_pauseparam, 229162306a36Sopenharmony_ci .set_pauseparam = qede_set_pauseparam, 229262306a36Sopenharmony_ci .get_strings = qede_get_strings, 229362306a36Sopenharmony_ci .set_phys_id = qede_set_phys_id, 229462306a36Sopenharmony_ci .get_ethtool_stats = qede_get_ethtool_stats, 229562306a36Sopenharmony_ci .get_priv_flags = qede_get_priv_flags, 229662306a36Sopenharmony_ci .set_priv_flags = qede_set_priv_flags, 229762306a36Sopenharmony_ci .get_sset_count = qede_get_sset_count, 229862306a36Sopenharmony_ci .get_rxnfc = qede_get_rxnfc, 229962306a36Sopenharmony_ci .set_rxnfc = qede_set_rxnfc, 230062306a36Sopenharmony_ci .get_rxfh_indir_size = qede_get_rxfh_indir_size, 230162306a36Sopenharmony_ci .get_rxfh_key_size = qede_get_rxfh_key_size, 230262306a36Sopenharmony_ci .get_rxfh = qede_get_rxfh, 230362306a36Sopenharmony_ci .set_rxfh = qede_set_rxfh, 230462306a36Sopenharmony_ci .get_ts_info = qede_get_ts_info, 230562306a36Sopenharmony_ci .get_channels = qede_get_channels, 230662306a36Sopenharmony_ci .set_channels = qede_set_channels, 230762306a36Sopenharmony_ci .self_test = qede_self_test, 230862306a36Sopenharmony_ci .get_module_info = qede_get_module_info, 230962306a36Sopenharmony_ci .get_module_eeprom = qede_get_module_eeprom, 231062306a36Sopenharmony_ci .get_eee = qede_get_eee, 231162306a36Sopenharmony_ci .set_eee = qede_set_eee, 231262306a36Sopenharmony_ci .get_fecparam = qede_get_fecparam, 231362306a36Sopenharmony_ci .set_fecparam = qede_set_fecparam, 231462306a36Sopenharmony_ci .get_tunable = qede_get_tunable, 231562306a36Sopenharmony_ci .set_tunable = qede_set_tunable, 231662306a36Sopenharmony_ci .get_per_queue_coalesce = qede_get_per_coalesce, 231762306a36Sopenharmony_ci .set_per_queue_coalesce = qede_set_per_coalesce, 231862306a36Sopenharmony_ci .flash_device = qede_flash_device, 231962306a36Sopenharmony_ci .get_dump_flag = qede_get_dump_flag, 232062306a36Sopenharmony_ci .get_dump_data = qede_get_dump_data, 232162306a36Sopenharmony_ci .set_dump = qede_set_dump, 232262306a36Sopenharmony_ci}; 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_cistatic const struct ethtool_ops qede_vf_ethtool_ops = { 232562306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 232662306a36Sopenharmony_ci ETHTOOL_COALESCE_STATS_BLOCK_USECS, 232762306a36Sopenharmony_ci .get_link_ksettings = qede_get_link_ksettings, 232862306a36Sopenharmony_ci .get_drvinfo = qede_get_drvinfo, 232962306a36Sopenharmony_ci .get_msglevel = qede_get_msglevel, 233062306a36Sopenharmony_ci .set_msglevel = qede_set_msglevel, 233162306a36Sopenharmony_ci .get_link = qede_get_link, 233262306a36Sopenharmony_ci .get_coalesce = qede_get_coalesce, 233362306a36Sopenharmony_ci .set_coalesce = qede_set_coalesce, 233462306a36Sopenharmony_ci .get_ringparam = qede_get_ringparam, 233562306a36Sopenharmony_ci .set_ringparam = qede_set_ringparam, 233662306a36Sopenharmony_ci .get_strings = qede_get_strings, 233762306a36Sopenharmony_ci .get_ethtool_stats = qede_get_ethtool_stats, 233862306a36Sopenharmony_ci .get_priv_flags = qede_get_priv_flags, 233962306a36Sopenharmony_ci .get_sset_count = qede_get_sset_count, 234062306a36Sopenharmony_ci .get_rxnfc = qede_get_rxnfc, 234162306a36Sopenharmony_ci .set_rxnfc = qede_set_rxnfc, 234262306a36Sopenharmony_ci .get_rxfh_indir_size = qede_get_rxfh_indir_size, 234362306a36Sopenharmony_ci .get_rxfh_key_size = qede_get_rxfh_key_size, 234462306a36Sopenharmony_ci .get_rxfh = qede_get_rxfh, 234562306a36Sopenharmony_ci .set_rxfh = qede_set_rxfh, 234662306a36Sopenharmony_ci .get_channels = qede_get_channels, 234762306a36Sopenharmony_ci .set_channels = qede_set_channels, 234862306a36Sopenharmony_ci .get_per_queue_coalesce = qede_get_per_coalesce, 234962306a36Sopenharmony_ci .set_per_queue_coalesce = qede_set_per_coalesce, 235062306a36Sopenharmony_ci .get_tunable = qede_get_tunable, 235162306a36Sopenharmony_ci .set_tunable = qede_set_tunable, 235262306a36Sopenharmony_ci}; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_civoid qede_set_ethtool_ops(struct net_device *dev) 235562306a36Sopenharmony_ci{ 235662306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci if (IS_VF(edev)) 235962306a36Sopenharmony_ci dev->ethtool_ops = &qede_vf_ethtool_ops; 236062306a36Sopenharmony_ci else 236162306a36Sopenharmony_ci dev->ethtool_ops = &qede_ethtool_ops; 236262306a36Sopenharmony_ci} 2363