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(&current_link, 0, sizeof(current_link));
54062306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_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(&current_link, 0, sizeof(current_link));
57862306a36Sopenharmony_ci	memset(&params, 0, sizeof(params));
57962306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_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, &params);
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(&current_link, 0, sizeof(current_link));
74562306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_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(&current_link, 0, sizeof(current_link));
76562306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_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(&current_link, 0, sizeof(current_link));
97262306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_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(&current_link, 0, sizeof(current_link));
100162306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_link);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	memset(&params, 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, &params);
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(&current_link, 0, sizeof(current_link));
180562306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_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(&current_link, 0, sizeof(current_link));
184562306a36Sopenharmony_ci	edev->ops->common->get_link(edev->cdev, &current_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(&params, 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, &params);
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(&params, 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, &params);
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