1133fac0eSSudarsana Kalluru /* QLogic qede NIC Driver
2133fac0eSSudarsana Kalluru * Copyright (c) 2015 QLogic Corporation
3133fac0eSSudarsana Kalluru *
4133fac0eSSudarsana Kalluru * This software is available under the terms of the GNU General Public License
5133fac0eSSudarsana Kalluru * (GPL) Version 2, available from the file COPYING in the main directory of
6133fac0eSSudarsana Kalluru * this source tree.
7133fac0eSSudarsana Kalluru */
8133fac0eSSudarsana Kalluru 
9133fac0eSSudarsana Kalluru #include <linux/version.h>
10133fac0eSSudarsana Kalluru #include <linux/types.h>
11133fac0eSSudarsana Kalluru #include <linux/netdevice.h>
1216f46bf0SSudarsana Reddy Kalluru #include <linux/etherdevice.h>
13133fac0eSSudarsana Kalluru #include <linux/ethtool.h>
14133fac0eSSudarsana Kalluru #include <linux/string.h>
15133fac0eSSudarsana Kalluru #include <linux/pci.h>
16133fac0eSSudarsana Kalluru #include <linux/capability.h>
17133fac0eSSudarsana Kalluru #include "qede.h"
18133fac0eSSudarsana Kalluru 
19133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_OFFSET(stat_name) \
20133fac0eSSudarsana Kalluru 	 (offsetof(struct qede_rx_queue, stat_name))
21133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_STRING(stat_name) (#stat_name)
22133fac0eSSudarsana Kalluru #define QEDE_RQSTAT(stat_name) \
23133fac0eSSudarsana Kalluru 	 {QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)}
2416f46bf0SSudarsana Reddy Kalluru 
2516f46bf0SSudarsana Reddy Kalluru #define QEDE_SELFTEST_POLL_COUNT 100
2616f46bf0SSudarsana Reddy Kalluru 
27133fac0eSSudarsana Kalluru static const struct {
28133fac0eSSudarsana Kalluru 	u64 offset;
29133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
30133fac0eSSudarsana Kalluru } qede_rqstats_arr[] = {
3168db9ec2SSudarsana Reddy Kalluru 	QEDE_RQSTAT(rcv_pkts),
32133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_hw_errors),
33133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_alloc_errors),
34c72a6125SManish Chopra 	QEDE_RQSTAT(rx_ip_frags),
35133fac0eSSudarsana Kalluru };
36133fac0eSSudarsana Kalluru 
37133fac0eSSudarsana Kalluru #define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr)
3868db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_OFFSET(stat_name) \
3968db9ec2SSudarsana Reddy Kalluru 	(offsetof(struct qede_tx_queue, stat_name))
4068db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_STRING(stat_name) (#stat_name)
4168db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT(stat_name) \
4268db9ec2SSudarsana Reddy Kalluru 	{QEDE_TQSTAT_OFFSET(stat_name), QEDE_TQSTAT_STRING(stat_name)}
4368db9ec2SSudarsana Reddy Kalluru #define QEDE_NUM_TQSTATS ARRAY_SIZE(qede_tqstats_arr)
4468db9ec2SSudarsana Reddy Kalluru static const struct {
4568db9ec2SSudarsana Reddy Kalluru 	u64 offset;
4668db9ec2SSudarsana Reddy Kalluru 	char string[ETH_GSTRING_LEN];
4768db9ec2SSudarsana Reddy Kalluru } qede_tqstats_arr[] = {
4868db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(xmit_pkts),
4968db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(stopped_cnt),
5068db9ec2SSudarsana Reddy Kalluru };
5168db9ec2SSudarsana Reddy Kalluru 
524dbcd640SMintz, Yuval #define QEDE_STAT_OFFSET(stat_name) (offsetof(struct qede_stats, stat_name))
534dbcd640SMintz, Yuval #define QEDE_STAT_STRING(stat_name) (#stat_name)
544dbcd640SMintz, Yuval #define _QEDE_STAT(stat_name, pf_only) \
554dbcd640SMintz, Yuval 	 {QEDE_STAT_OFFSET(stat_name), QEDE_STAT_STRING(stat_name), pf_only}
564dbcd640SMintz, Yuval #define QEDE_PF_STAT(stat_name)	_QEDE_STAT(stat_name, true)
574dbcd640SMintz, Yuval #define QEDE_STAT(stat_name)	_QEDE_STAT(stat_name, false)
58133fac0eSSudarsana Kalluru static const struct {
59133fac0eSSudarsana Kalluru 	u64 offset;
60133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
61133fac0eSSudarsana Kalluru 	bool pf_only;
62133fac0eSSudarsana Kalluru } qede_stats_arr[] = {
63133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_bytes),
64133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_bytes),
65133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_bytes),
66133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_pkts),
67133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_pkts),
68133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_pkts),
69133fac0eSSudarsana Kalluru 
70133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_bytes),
71133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_bytes),
72133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_bytes),
73133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_pkts),
74133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_pkts),
75133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_pkts),
76133fac0eSSudarsana Kalluru 
77133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_64_byte_packets),
78d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_65_to_127_byte_packets),
79d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_128_to_255_byte_packets),
80d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_256_to_511_byte_packets),
81d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_512_to_1023_byte_packets),
82d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1024_to_1518_byte_packets),
83d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1519_to_1522_byte_packets),
84d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1519_to_2047_byte_packets),
85d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_2048_to_4095_byte_packets),
86d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_4096_to_9216_byte_packets),
87d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_9217_to_16383_byte_packets),
88133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_64_byte_packets),
89133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_65_to_127_byte_packets),
90133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_128_to_255_byte_packets),
91133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_256_to_511_byte_packets),
92133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_512_to_1023_byte_packets),
93133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_1024_to_1518_byte_packets),
94133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_1519_to_2047_byte_packets),
95133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_2048_to_4095_byte_packets),
96133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_4096_to_9216_byte_packets),
97133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_9217_to_16383_byte_packets),
98133fac0eSSudarsana Kalluru 
99133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_mac_crtl_frames),
100133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_mac_ctrl_frames),
101133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pause_frames),
102133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pause_frames),
103133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pfc_frames),
104133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pfc_frames),
105133fac0eSSudarsana Kalluru 
106133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_crc_errors),
107133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_align_errors),
108133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_carrier_errors),
109133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_oversize_packets),
110133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_jabbers),
111133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_undersize_packets),
112133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_fragments),
113133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_lpi_entry_count),
114133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_total_collisions),
115133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_truncates),
116133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_discards),
117133fac0eSSudarsana Kalluru 	QEDE_STAT(no_buff_discards),
118133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mftag_filter_discards),
119133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mac_filter_discards),
120133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_err_drop_pkts),
1211a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(ttl0_discard),
1221a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(packet_too_big_discard),
123133fac0eSSudarsana Kalluru 
124133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_pkts),
125133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_events),
126133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_aborts_num),
127133fac0eSSudarsana Kalluru 	QEDE_STAT(non_coalesced_pkts),
128133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_bytes),
129133fac0eSSudarsana Kalluru };
130133fac0eSSudarsana Kalluru 
131133fac0eSSudarsana Kalluru #define QEDE_NUM_STATS	ARRAY_SIZE(qede_stats_arr)
132133fac0eSSudarsana Kalluru 
133f3e72109SYuval Mintz enum {
134f3e72109SYuval Mintz 	QEDE_PRI_FLAG_CMT,
135f3e72109SYuval Mintz 	QEDE_PRI_FLAG_LEN,
136f3e72109SYuval Mintz };
137f3e72109SYuval Mintz 
138f3e72109SYuval Mintz static const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = {
139f3e72109SYuval Mintz 	"Coupled-Function",
140f3e72109SYuval Mintz };
141f3e72109SYuval Mintz 
1423044a02eSSudarsana Reddy Kalluru enum qede_ethtool_tests {
14316f46bf0SSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INT_LOOPBACK,
1443044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INTERRUPT_TEST,
1453044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_MEMORY_TEST,
1463044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_REGISTER_TEST,
1473044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_CLOCK_TEST,
1487a4b21b7SMintz, Yuval 	QEDE_ETHTOOL_NVRAM_TEST,
1493044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_TEST_MAX
1503044a02eSSudarsana Reddy Kalluru };
1513044a02eSSudarsana Reddy Kalluru 
1523044a02eSSudarsana Reddy Kalluru static const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = {
15316f46bf0SSudarsana Reddy Kalluru 	"Internal loopback (offline)",
1543044a02eSSudarsana Reddy Kalluru 	"Interrupt (online)\t",
1553044a02eSSudarsana Reddy Kalluru 	"Memory (online)\t\t",
1563044a02eSSudarsana Reddy Kalluru 	"Register (online)\t",
1573044a02eSSudarsana Reddy Kalluru 	"Clock (online)\t\t",
1587a4b21b7SMintz, Yuval 	"Nvram (online)\t\t",
1593044a02eSSudarsana Reddy Kalluru };
1603044a02eSSudarsana Reddy Kalluru 
1614dbcd640SMintz, Yuval static void qede_get_strings_stats_txq(struct qede_dev *edev,
1624dbcd640SMintz, Yuval 				       struct qede_tx_queue *txq, u8 **buf)
1634dbcd640SMintz, Yuval {
1644dbcd640SMintz, Yuval 	int i;
1654dbcd640SMintz, Yuval 
1664dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
1674dbcd640SMintz, Yuval 		sprintf(*buf, "%d: %s", txq->index,
1684dbcd640SMintz, Yuval 			qede_tqstats_arr[i].string);
1694dbcd640SMintz, Yuval 		*buf += ETH_GSTRING_LEN;
1704dbcd640SMintz, Yuval 	}
1714dbcd640SMintz, Yuval }
1724dbcd640SMintz, Yuval 
1734dbcd640SMintz, Yuval static void qede_get_strings_stats_rxq(struct qede_dev *edev,
1744dbcd640SMintz, Yuval 				       struct qede_rx_queue *rxq, u8 **buf)
1754dbcd640SMintz, Yuval {
1764dbcd640SMintz, Yuval 	int i;
1774dbcd640SMintz, Yuval 
1784dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_RQSTATS; i++) {
1794dbcd640SMintz, Yuval 		sprintf(*buf, "%d: %s", rxq->rxq_id,
1804dbcd640SMintz, Yuval 			qede_rqstats_arr[i].string);
1814dbcd640SMintz, Yuval 		*buf += ETH_GSTRING_LEN;
1824dbcd640SMintz, Yuval 	}
1834dbcd640SMintz, Yuval }
1844dbcd640SMintz, Yuval 
185133fac0eSSudarsana Kalluru static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
186133fac0eSSudarsana Kalluru {
1874dbcd640SMintz, Yuval 	struct qede_fastpath *fp;
1884dbcd640SMintz, Yuval 	int i;
189133fac0eSSudarsana Kalluru 
1904dbcd640SMintz, Yuval 	/* Account for queue statistics */
1914dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) {
1924dbcd640SMintz, Yuval 		fp = &edev->fp_array[i];
19368db9ec2SSudarsana Reddy Kalluru 
1944dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_RX)
1954dbcd640SMintz, Yuval 			qede_get_strings_stats_rxq(edev, fp->rxq, &buf);
1964dbcd640SMintz, Yuval 
1974dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_TX)
1984dbcd640SMintz, Yuval 			qede_get_strings_stats_txq(edev, fp->txq, &buf);
199cbbf049aSMintz, Yuval 	}
200cbbf049aSMintz, Yuval 
2014dbcd640SMintz, Yuval 	/* Account for non-queue statistics */
2024dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_STATS; i++) {
203fefb0202SYuval Mintz 		if (IS_VF(edev) && qede_stats_arr[i].pf_only)
204fefb0202SYuval Mintz 			continue;
2054dbcd640SMintz, Yuval 		strcpy(buf, qede_stats_arr[i].string);
2064dbcd640SMintz, Yuval 		buf += ETH_GSTRING_LEN;
207133fac0eSSudarsana Kalluru 	}
208133fac0eSSudarsana Kalluru }
209133fac0eSSudarsana Kalluru 
210133fac0eSSudarsana Kalluru static void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
211133fac0eSSudarsana Kalluru {
212133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
213133fac0eSSudarsana Kalluru 
214133fac0eSSudarsana Kalluru 	switch (stringset) {
215133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
216133fac0eSSudarsana Kalluru 		qede_get_strings_stats(edev, buf);
217133fac0eSSudarsana Kalluru 		break;
218f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
219f3e72109SYuval Mintz 		memcpy(buf, qede_private_arr,
220f3e72109SYuval Mintz 		       ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN);
221f3e72109SYuval Mintz 		break;
2223044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
2233044a02eSSudarsana Reddy Kalluru 		memcpy(buf, qede_tests_str_arr,
2243044a02eSSudarsana Reddy Kalluru 		       ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX);
2253044a02eSSudarsana Reddy Kalluru 		break;
226133fac0eSSudarsana Kalluru 	default:
227133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
228133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
229133fac0eSSudarsana Kalluru 	}
230133fac0eSSudarsana Kalluru }
231133fac0eSSudarsana Kalluru 
2324dbcd640SMintz, Yuval static void qede_get_ethtool_stats_txq(struct qede_tx_queue *txq, u64 **buf)
2334dbcd640SMintz, Yuval {
2344dbcd640SMintz, Yuval 	int i;
2354dbcd640SMintz, Yuval 
2364dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
2374dbcd640SMintz, Yuval 		**buf = *((u64 *)(((void *)txq) + qede_tqstats_arr[i].offset));
2384dbcd640SMintz, Yuval 		(*buf)++;
2394dbcd640SMintz, Yuval 	}
2404dbcd640SMintz, Yuval }
2414dbcd640SMintz, Yuval 
2424dbcd640SMintz, Yuval static void qede_get_ethtool_stats_rxq(struct qede_rx_queue *rxq, u64 **buf)
2434dbcd640SMintz, Yuval {
2444dbcd640SMintz, Yuval 	int i;
2454dbcd640SMintz, Yuval 
2464dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_RQSTATS; i++) {
2474dbcd640SMintz, Yuval 		**buf = *((u64 *)(((void *)rxq) + qede_rqstats_arr[i].offset));
2484dbcd640SMintz, Yuval 		(*buf)++;
2494dbcd640SMintz, Yuval 	}
2504dbcd640SMintz, Yuval }
2514dbcd640SMintz, Yuval 
252133fac0eSSudarsana Kalluru static void qede_get_ethtool_stats(struct net_device *dev,
253133fac0eSSudarsana Kalluru 				   struct ethtool_stats *stats, u64 *buf)
254133fac0eSSudarsana Kalluru {
255133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
2564dbcd640SMintz, Yuval 	struct qede_fastpath *fp;
2574dbcd640SMintz, Yuval 	int i;
258133fac0eSSudarsana Kalluru 
259133fac0eSSudarsana Kalluru 	qede_fill_by_demand_stats(edev);
260133fac0eSSudarsana Kalluru 
261567b3c12SMintz, Yuval 	/* Need to protect the access to the fastpath array */
262567b3c12SMintz, Yuval 	__qede_lock(edev);
263567b3c12SMintz, Yuval 
2644dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) {
2654dbcd640SMintz, Yuval 		fp = &edev->fp_array[i];
266133fac0eSSudarsana Kalluru 
2674dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_RX)
2684dbcd640SMintz, Yuval 			qede_get_ethtool_stats_rxq(fp->rxq, &buf);
26968db9ec2SSudarsana Reddy Kalluru 
2704dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_TX)
2714dbcd640SMintz, Yuval 			qede_get_ethtool_stats_txq(fp->txq, &buf);
27268db9ec2SSudarsana Reddy Kalluru 	}
27368db9ec2SSudarsana Reddy Kalluru 
2744dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_STATS; i++) {
2754dbcd640SMintz, Yuval 		if (IS_VF(edev) && qede_stats_arr[i].pf_only)
276fefb0202SYuval Mintz 			continue;
2774dbcd640SMintz, Yuval 		*buf = *((u64 *)(((void *)&edev->stats) +
2784dbcd640SMintz, Yuval 				 qede_stats_arr[i].offset));
2794dbcd640SMintz, Yuval 
2804dbcd640SMintz, Yuval 		buf++;
281fefb0202SYuval Mintz 	}
282133fac0eSSudarsana Kalluru 
283567b3c12SMintz, Yuval 	__qede_unlock(edev);
284133fac0eSSudarsana Kalluru }
285133fac0eSSudarsana Kalluru 
286133fac0eSSudarsana Kalluru static int qede_get_sset_count(struct net_device *dev, int stringset)
287133fac0eSSudarsana Kalluru {
288133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
289133fac0eSSudarsana Kalluru 	int num_stats = QEDE_NUM_STATS;
290133fac0eSSudarsana Kalluru 
291133fac0eSSudarsana Kalluru 	switch (stringset) {
292133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
293fefb0202SYuval Mintz 		if (IS_VF(edev)) {
294fefb0202SYuval Mintz 			int i;
295fefb0202SYuval Mintz 
296fefb0202SYuval Mintz 			for (i = 0; i < QEDE_NUM_STATS; i++)
297fefb0202SYuval Mintz 				if (qede_stats_arr[i].pf_only)
298fefb0202SYuval Mintz 					num_stats--;
299fefb0202SYuval Mintz 		}
3004dbcd640SMintz, Yuval 
3014dbcd640SMintz, Yuval 		/* Account for the Regular Tx statistics */
3024dbcd640SMintz, Yuval 		num_stats += QEDE_TSS_COUNT(edev) * QEDE_NUM_TQSTATS;
3034dbcd640SMintz, Yuval 
3044dbcd640SMintz, Yuval 		/* Account for the Regular Rx statistics */
3054dbcd640SMintz, Yuval 		num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS;
3064dbcd640SMintz, Yuval 
3074dbcd640SMintz, Yuval 		return num_stats;
3084dbcd640SMintz, Yuval 
309f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
310f3e72109SYuval Mintz 		return QEDE_PRI_FLAG_LEN;
3113044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
3126ecb0a0cSYuval Mintz 		if (!IS_VF(edev))
3133044a02eSSudarsana Reddy Kalluru 			return QEDE_ETHTOOL_TEST_MAX;
3146ecb0a0cSYuval Mintz 		else
3156ecb0a0cSYuval Mintz 			return 0;
316133fac0eSSudarsana Kalluru 	default:
317133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
318133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
319133fac0eSSudarsana Kalluru 		return -EINVAL;
320133fac0eSSudarsana Kalluru 	}
321133fac0eSSudarsana Kalluru }
322133fac0eSSudarsana Kalluru 
323f3e72109SYuval Mintz static u32 qede_get_priv_flags(struct net_device *dev)
324f3e72109SYuval Mintz {
325f3e72109SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
326f3e72109SYuval Mintz 
327f3e72109SYuval Mintz 	return (!!(edev->dev_info.common.num_hwfns > 1)) << QEDE_PRI_FLAG_CMT;
328f3e72109SYuval Mintz }
329f3e72109SYuval Mintz 
330054c67d1SSudarsana Reddy Kalluru struct qede_link_mode_mapping {
331054c67d1SSudarsana Reddy Kalluru 	u32 qed_link_mode;
332054c67d1SSudarsana Reddy Kalluru 	u32 ethtool_link_mode;
333054c67d1SSudarsana Reddy Kalluru };
334054c67d1SSudarsana Reddy Kalluru 
335054c67d1SSudarsana Reddy Kalluru static const struct qede_link_mode_mapping qed_lm_map[] = {
336054c67d1SSudarsana Reddy Kalluru 	{QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
337054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
338054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT},
339054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
340054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT},
341054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
342054c67d1SSudarsana Reddy Kalluru 	{QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
343054c67d1SSudarsana Reddy Kalluru 	{QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
344054c67d1SSudarsana Reddy Kalluru 	{QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
345054c67d1SSudarsana Reddy Kalluru 	{QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT},
346054c67d1SSudarsana Reddy Kalluru 	{QED_LM_100000baseKR4_Full_BIT,
347054c67d1SSudarsana Reddy Kalluru 	 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
348054c67d1SSudarsana Reddy Kalluru };
349054c67d1SSudarsana Reddy Kalluru 
350054c67d1SSudarsana Reddy Kalluru #define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name)	\
351054c67d1SSudarsana Reddy Kalluru {								\
352054c67d1SSudarsana Reddy Kalluru 	int i;							\
353054c67d1SSudarsana Reddy Kalluru 								\
354d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
355054c67d1SSudarsana Reddy Kalluru 		if ((caps) & (qed_lm_map[i].qed_link_mode))	\
356054c67d1SSudarsana Reddy Kalluru 			__set_bit(qed_lm_map[i].ethtool_link_mode,\
357054c67d1SSudarsana Reddy Kalluru 				  lk_ksettings->link_modes.name); \
358054c67d1SSudarsana Reddy Kalluru 	}							\
359054c67d1SSudarsana Reddy Kalluru }
360054c67d1SSudarsana Reddy Kalluru 
361054c67d1SSudarsana Reddy Kalluru #define QEDE_ETHTOOL_TO_DRV_CAPS(caps, lk_ksettings, name)	\
362054c67d1SSudarsana Reddy Kalluru {								\
363054c67d1SSudarsana Reddy Kalluru 	int i;							\
364054c67d1SSudarsana Reddy Kalluru 								\
365d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
366054c67d1SSudarsana Reddy Kalluru 		if (test_bit(qed_lm_map[i].ethtool_link_mode,	\
367054c67d1SSudarsana Reddy Kalluru 			     lk_ksettings->link_modes.name))	\
368054c67d1SSudarsana Reddy Kalluru 			caps |= qed_lm_map[i].qed_link_mode;	\
369054c67d1SSudarsana Reddy Kalluru 	}							\
370054c67d1SSudarsana Reddy Kalluru }
371054c67d1SSudarsana Reddy Kalluru 
372054c67d1SSudarsana Reddy Kalluru static int qede_get_link_ksettings(struct net_device *dev,
373054c67d1SSudarsana Reddy Kalluru 				   struct ethtool_link_ksettings *cmd)
374133fac0eSSudarsana Kalluru {
375054c67d1SSudarsana Reddy Kalluru 	struct ethtool_link_settings *base = &cmd->base;
376133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
377133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
378133fac0eSSudarsana Kalluru 
379567b3c12SMintz, Yuval 	__qede_lock(edev);
380567b3c12SMintz, Yuval 
381133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
382133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
383133fac0eSSudarsana Kalluru 
384054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
385054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.supported_caps, cmd, supported)
386054c67d1SSudarsana Reddy Kalluru 
387054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
388054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.advertised_caps, cmd, advertising)
389054c67d1SSudarsana Reddy Kalluru 
390054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
391054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.lp_caps, cmd, lp_advertising)
392054c67d1SSudarsana Reddy Kalluru 
393133fac0eSSudarsana Kalluru 	if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) {
394054c67d1SSudarsana Reddy Kalluru 		base->speed = current_link.speed;
395054c67d1SSudarsana Reddy Kalluru 		base->duplex = current_link.duplex;
396133fac0eSSudarsana Kalluru 	} else {
397054c67d1SSudarsana Reddy Kalluru 		base->speed = SPEED_UNKNOWN;
398054c67d1SSudarsana Reddy Kalluru 		base->duplex = DUPLEX_UNKNOWN;
399133fac0eSSudarsana Kalluru 	}
400567b3c12SMintz, Yuval 
401567b3c12SMintz, Yuval 	__qede_unlock(edev);
402567b3c12SMintz, Yuval 
403054c67d1SSudarsana Reddy Kalluru 	base->port = current_link.port;
404054c67d1SSudarsana Reddy Kalluru 	base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE :
405133fac0eSSudarsana Kalluru 			AUTONEG_DISABLE;
406133fac0eSSudarsana Kalluru 
407133fac0eSSudarsana Kalluru 	return 0;
408133fac0eSSudarsana Kalluru }
409133fac0eSSudarsana Kalluru 
410054c67d1SSudarsana Reddy Kalluru static int qede_set_link_ksettings(struct net_device *dev,
411054c67d1SSudarsana Reddy Kalluru 				   const struct ethtool_link_ksettings *cmd)
412133fac0eSSudarsana Kalluru {
413054c67d1SSudarsana Reddy Kalluru 	const struct ethtool_link_settings *base = &cmd->base;
414133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
415133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
416133fac0eSSudarsana Kalluru 	struct qed_link_params params;
417133fac0eSSudarsana Kalluru 
418fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
419054c67d1SSudarsana Reddy Kalluru 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
420133fac0eSSudarsana Kalluru 		return -EOPNOTSUPP;
421133fac0eSSudarsana Kalluru 	}
422133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
423133fac0eSSudarsana Kalluru 	memset(&params, 0, sizeof(params));
424133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
425133fac0eSSudarsana Kalluru 
426133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS;
427133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG;
428054c67d1SSudarsana Reddy Kalluru 	if (base->autoneg == AUTONEG_ENABLE) {
429133fac0eSSudarsana Kalluru 		params.autoneg = true;
430133fac0eSSudarsana Kalluru 		params.forced_speed = 0;
431054c67d1SSudarsana Reddy Kalluru 		QEDE_ETHTOOL_TO_DRV_CAPS(params.adv_speeds, cmd, advertising)
432133fac0eSSudarsana Kalluru 	} else {		/* forced speed */
433133fac0eSSudarsana Kalluru 		params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED;
434133fac0eSSudarsana Kalluru 		params.autoneg = false;
435054c67d1SSudarsana Reddy Kalluru 		params.forced_speed = base->speed;
436054c67d1SSudarsana Reddy Kalluru 		switch (base->speed) {
437133fac0eSSudarsana Kalluru 		case SPEED_10000:
438133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
439054c67d1SSudarsana Reddy Kalluru 			      QED_LM_10000baseKR_Full_BIT)) {
440133fac0eSSudarsana Kalluru 				DP_INFO(edev, "10G speed not supported\n");
441133fac0eSSudarsana Kalluru 				return -EINVAL;
442133fac0eSSudarsana Kalluru 			}
443054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_10000baseKR_Full_BIT;
444054c67d1SSudarsana Reddy Kalluru 			break;
445054c67d1SSudarsana Reddy Kalluru 		case SPEED_25000:
446054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
447054c67d1SSudarsana Reddy Kalluru 			      QED_LM_25000baseKR_Full_BIT)) {
448054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "25G speed not supported\n");
449054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
450054c67d1SSudarsana Reddy Kalluru 			}
451054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_25000baseKR_Full_BIT;
452133fac0eSSudarsana Kalluru 			break;
453133fac0eSSudarsana Kalluru 		case SPEED_40000:
454133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
455054c67d1SSudarsana Reddy Kalluru 			      QED_LM_40000baseLR4_Full_BIT)) {
456133fac0eSSudarsana Kalluru 				DP_INFO(edev, "40G speed not supported\n");
457133fac0eSSudarsana Kalluru 				return -EINVAL;
458133fac0eSSudarsana Kalluru 			}
459054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_40000baseLR4_Full_BIT;
460054c67d1SSudarsana Reddy Kalluru 			break;
46116d5946aSYuval Mintz 		case SPEED_50000:
462054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
463054c67d1SSudarsana Reddy Kalluru 			      QED_LM_50000baseKR2_Full_BIT)) {
464054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "50G speed not supported\n");
465054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
466054c67d1SSudarsana Reddy Kalluru 			}
467054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_50000baseKR2_Full_BIT;
468054c67d1SSudarsana Reddy Kalluru 			break;
46916d5946aSYuval Mintz 		case SPEED_100000:
470054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
471054c67d1SSudarsana Reddy Kalluru 			      QED_LM_100000baseKR4_Full_BIT)) {
472054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "100G speed not supported\n");
473054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
474054c67d1SSudarsana Reddy Kalluru 			}
475054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_100000baseKR4_Full_BIT;
476133fac0eSSudarsana Kalluru 			break;
477133fac0eSSudarsana Kalluru 		default:
478054c67d1SSudarsana Reddy Kalluru 			DP_INFO(edev, "Unsupported speed %u\n", base->speed);
479133fac0eSSudarsana Kalluru 			return -EINVAL;
480133fac0eSSudarsana Kalluru 		}
481133fac0eSSudarsana Kalluru 	}
482133fac0eSSudarsana Kalluru 
483133fac0eSSudarsana Kalluru 	params.link_up = true;
484133fac0eSSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
485133fac0eSSudarsana Kalluru 
486133fac0eSSudarsana Kalluru 	return 0;
487133fac0eSSudarsana Kalluru }
488133fac0eSSudarsana Kalluru 
489133fac0eSSudarsana Kalluru static void qede_get_drvinfo(struct net_device *ndev,
490133fac0eSSudarsana Kalluru 			     struct ethtool_drvinfo *info)
491133fac0eSSudarsana Kalluru {
492133fac0eSSudarsana Kalluru 	char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN];
493133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
494133fac0eSSudarsana Kalluru 
495133fac0eSSudarsana Kalluru 	strlcpy(info->driver, "qede", sizeof(info->driver));
496133fac0eSSudarsana Kalluru 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
497133fac0eSSudarsana Kalluru 
498133fac0eSSudarsana Kalluru 	snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
499133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_major,
500133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_minor,
501133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_rev,
502133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_eng);
503133fac0eSSudarsana Kalluru 
504133fac0eSSudarsana Kalluru 	snprintf(mfw, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
505133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 24) & 0xFF,
506133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 16) & 0xFF,
507133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 8) & 0xFF,
508133fac0eSSudarsana Kalluru 		 edev->dev_info.common.mfw_rev & 0xFF);
509133fac0eSSudarsana Kalluru 
510133fac0eSSudarsana Kalluru 	if ((strlen(storm) + strlen(mfw) + strlen("mfw storm  ")) <
511133fac0eSSudarsana Kalluru 	    sizeof(info->fw_version)) {
512133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
513133fac0eSSudarsana Kalluru 			 "mfw %s storm %s", mfw, storm);
514133fac0eSSudarsana Kalluru 	} else {
515133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
516133fac0eSSudarsana Kalluru 			 "%s %s", mfw, storm);
517133fac0eSSudarsana Kalluru 	}
518133fac0eSSudarsana Kalluru 
519133fac0eSSudarsana Kalluru 	strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info));
520133fac0eSSudarsana Kalluru }
521133fac0eSSudarsana Kalluru 
52214d39648SMintz, Yuval static void qede_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
52314d39648SMintz, Yuval {
52414d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
52514d39648SMintz, Yuval 
52614d39648SMintz, Yuval 	if (edev->dev_info.common.wol_support) {
52714d39648SMintz, Yuval 		wol->supported = WAKE_MAGIC;
52814d39648SMintz, Yuval 		wol->wolopts = edev->wol_enabled ? WAKE_MAGIC : 0;
52914d39648SMintz, Yuval 	}
53014d39648SMintz, Yuval }
53114d39648SMintz, Yuval 
53214d39648SMintz, Yuval static int qede_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
53314d39648SMintz, Yuval {
53414d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
53514d39648SMintz, Yuval 	bool wol_requested;
53614d39648SMintz, Yuval 	int rc;
53714d39648SMintz, Yuval 
53814d39648SMintz, Yuval 	if (wol->wolopts & ~WAKE_MAGIC) {
53914d39648SMintz, Yuval 		DP_INFO(edev,
54014d39648SMintz, Yuval 			"Can't support WoL options other than magic-packet\n");
54114d39648SMintz, Yuval 		return -EINVAL;
54214d39648SMintz, Yuval 	}
54314d39648SMintz, Yuval 
54414d39648SMintz, Yuval 	wol_requested = !!(wol->wolopts & WAKE_MAGIC);
54514d39648SMintz, Yuval 	if (wol_requested == edev->wol_enabled)
54614d39648SMintz, Yuval 		return 0;
54714d39648SMintz, Yuval 
54814d39648SMintz, Yuval 	/* Need to actually change configuration */
54914d39648SMintz, Yuval 	if (!edev->dev_info.common.wol_support) {
55014d39648SMintz, Yuval 		DP_INFO(edev, "Device doesn't support WoL\n");
55114d39648SMintz, Yuval 		return -EINVAL;
55214d39648SMintz, Yuval 	}
55314d39648SMintz, Yuval 
55414d39648SMintz, Yuval 	rc = edev->ops->common->update_wol(edev->cdev, wol_requested);
55514d39648SMintz, Yuval 	if (!rc)
55614d39648SMintz, Yuval 		edev->wol_enabled = wol_requested;
55714d39648SMintz, Yuval 
55814d39648SMintz, Yuval 	return rc;
55914d39648SMintz, Yuval }
56014d39648SMintz, Yuval 
561133fac0eSSudarsana Kalluru static u32 qede_get_msglevel(struct net_device *ndev)
562133fac0eSSudarsana Kalluru {
563133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
564133fac0eSSudarsana Kalluru 
5651a635e48SYuval Mintz 	return ((u32)edev->dp_level << QED_LOG_LEVEL_SHIFT) | edev->dp_module;
566133fac0eSSudarsana Kalluru }
567133fac0eSSudarsana Kalluru 
568133fac0eSSudarsana Kalluru static void qede_set_msglevel(struct net_device *ndev, u32 level)
569133fac0eSSudarsana Kalluru {
570133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
571133fac0eSSudarsana Kalluru 	u32 dp_module = 0;
572133fac0eSSudarsana Kalluru 	u8 dp_level = 0;
573133fac0eSSudarsana Kalluru 
574133fac0eSSudarsana Kalluru 	qede_config_debug(level, &dp_module, &dp_level);
575133fac0eSSudarsana Kalluru 
576133fac0eSSudarsana Kalluru 	edev->dp_level = dp_level;
577133fac0eSSudarsana Kalluru 	edev->dp_module = dp_module;
578133fac0eSSudarsana Kalluru 	edev->ops->common->update_msglvl(edev->cdev,
579133fac0eSSudarsana Kalluru 					 dp_module, dp_level);
580133fac0eSSudarsana Kalluru }
581133fac0eSSudarsana Kalluru 
58232a7a570SSudarsana Kalluru static int qede_nway_reset(struct net_device *dev)
58332a7a570SSudarsana Kalluru {
58432a7a570SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
58532a7a570SSudarsana Kalluru 	struct qed_link_output current_link;
58632a7a570SSudarsana Kalluru 	struct qed_link_params link_params;
58732a7a570SSudarsana Kalluru 
588fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
5891a635e48SYuval Mintz 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
590fe7cd2bfSYuval Mintz 		return -EOPNOTSUPP;
591fe7cd2bfSYuval Mintz 	}
592fe7cd2bfSYuval Mintz 
59332a7a570SSudarsana Kalluru 	if (!netif_running(dev))
59432a7a570SSudarsana Kalluru 		return 0;
59532a7a570SSudarsana Kalluru 
59632a7a570SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
59732a7a570SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
59832a7a570SSudarsana Kalluru 	if (!current_link.link_up)
59932a7a570SSudarsana Kalluru 		return 0;
60032a7a570SSudarsana Kalluru 
60132a7a570SSudarsana Kalluru 	/* Toggle the link */
60232a7a570SSudarsana Kalluru 	memset(&link_params, 0, sizeof(link_params));
60332a7a570SSudarsana Kalluru 	link_params.link_up = false;
60432a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
60532a7a570SSudarsana Kalluru 	link_params.link_up = true;
60632a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
60732a7a570SSudarsana Kalluru 
60832a7a570SSudarsana Kalluru 	return 0;
60932a7a570SSudarsana Kalluru }
61032a7a570SSudarsana Kalluru 
611133fac0eSSudarsana Kalluru static u32 qede_get_link(struct net_device *dev)
612133fac0eSSudarsana Kalluru {
613133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
614133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
615133fac0eSSudarsana Kalluru 
616133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
617133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
618133fac0eSSudarsana Kalluru 
619133fac0eSSudarsana Kalluru 	return current_link.link_up;
620133fac0eSSudarsana Kalluru }
621133fac0eSSudarsana Kalluru 
622d552fa84SSudarsana Reddy Kalluru static int qede_get_coalesce(struct net_device *dev,
623d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
624d552fa84SSudarsana Reddy Kalluru {
625d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
626d2890deaSSudarsana Reddy Kalluru 	u16 rxc, txc;
627d552fa84SSudarsana Reddy Kalluru 
628d552fa84SSudarsana Reddy Kalluru 	memset(coal, 0, sizeof(struct ethtool_coalesce));
629d2890deaSSudarsana Reddy Kalluru 	edev->ops->common->get_coalesce(edev->cdev, &rxc, &txc);
630d2890deaSSudarsana Reddy Kalluru 
631d2890deaSSudarsana Reddy Kalluru 	coal->rx_coalesce_usecs = rxc;
632d2890deaSSudarsana Reddy Kalluru 	coal->tx_coalesce_usecs = txc;
633d552fa84SSudarsana Reddy Kalluru 
634d552fa84SSudarsana Reddy Kalluru 	return 0;
635d552fa84SSudarsana Reddy Kalluru }
636d552fa84SSudarsana Reddy Kalluru 
637d552fa84SSudarsana Reddy Kalluru static int qede_set_coalesce(struct net_device *dev,
638d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
639d552fa84SSudarsana Reddy Kalluru {
640d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
641d552fa84SSudarsana Reddy Kalluru 	int i, rc = 0;
642d552fa84SSudarsana Reddy Kalluru 	u16 rxc, txc;
643d552fa84SSudarsana Reddy Kalluru 	u8 sb_id;
644d552fa84SSudarsana Reddy Kalluru 
645d552fa84SSudarsana Reddy Kalluru 	if (!netif_running(dev)) {
646d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev, "Interface is down\n");
647d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
648d552fa84SSudarsana Reddy Kalluru 	}
649d552fa84SSudarsana Reddy Kalluru 
650d552fa84SSudarsana Reddy Kalluru 	if (coal->rx_coalesce_usecs > QED_COALESCE_MAX ||
651d552fa84SSudarsana Reddy Kalluru 	    coal->tx_coalesce_usecs > QED_COALESCE_MAX) {
652d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev,
653d552fa84SSudarsana Reddy Kalluru 			"Can't support requested %s coalesce value [max supported value %d]\n",
654d552fa84SSudarsana Reddy Kalluru 			coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx"
655d552fa84SSudarsana Reddy Kalluru 								   : "tx",
656d552fa84SSudarsana Reddy Kalluru 			QED_COALESCE_MAX);
657d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
658d552fa84SSudarsana Reddy Kalluru 	}
659d552fa84SSudarsana Reddy Kalluru 
660d552fa84SSudarsana Reddy Kalluru 	rxc = (u16)coal->rx_coalesce_usecs;
661d552fa84SSudarsana Reddy Kalluru 	txc = (u16)coal->tx_coalesce_usecs;
6629a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
663d552fa84SSudarsana Reddy Kalluru 		sb_id = edev->fp_array[i].sb_info->igu_sb_id;
664d552fa84SSudarsana Reddy Kalluru 		rc = edev->ops->common->set_coalesce(edev->cdev, rxc, txc,
665d552fa84SSudarsana Reddy Kalluru 						     (u8)i, sb_id);
666d552fa84SSudarsana Reddy Kalluru 		if (rc) {
667d552fa84SSudarsana Reddy Kalluru 			DP_INFO(edev, "Set coalesce error, rc = %d\n", rc);
668d552fa84SSudarsana Reddy Kalluru 			return rc;
669d552fa84SSudarsana Reddy Kalluru 		}
670d552fa84SSudarsana Reddy Kalluru 	}
671d552fa84SSudarsana Reddy Kalluru 
672d552fa84SSudarsana Reddy Kalluru 	return rc;
673d552fa84SSudarsana Reddy Kalluru }
674d552fa84SSudarsana Reddy Kalluru 
67501ef7e05SSudarsana Kalluru static void qede_get_ringparam(struct net_device *dev,
67601ef7e05SSudarsana Kalluru 			       struct ethtool_ringparam *ering)
67701ef7e05SSudarsana Kalluru {
67801ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
67901ef7e05SSudarsana Kalluru 
68001ef7e05SSudarsana Kalluru 	ering->rx_max_pending = NUM_RX_BDS_MAX;
68101ef7e05SSudarsana Kalluru 	ering->rx_pending = edev->q_num_rx_buffers;
68201ef7e05SSudarsana Kalluru 	ering->tx_max_pending = NUM_TX_BDS_MAX;
68301ef7e05SSudarsana Kalluru 	ering->tx_pending = edev->q_num_tx_buffers;
68401ef7e05SSudarsana Kalluru }
68501ef7e05SSudarsana Kalluru 
68601ef7e05SSudarsana Kalluru static int qede_set_ringparam(struct net_device *dev,
68701ef7e05SSudarsana Kalluru 			      struct ethtool_ringparam *ering)
68801ef7e05SSudarsana Kalluru {
68901ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
69001ef7e05SSudarsana Kalluru 
69101ef7e05SSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
69201ef7e05SSudarsana Kalluru 		   "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
69301ef7e05SSudarsana Kalluru 		   ering->rx_pending, ering->tx_pending);
69401ef7e05SSudarsana Kalluru 
69501ef7e05SSudarsana Kalluru 	/* Validate legality of configuration */
69601ef7e05SSudarsana Kalluru 	if (ering->rx_pending > NUM_RX_BDS_MAX ||
69701ef7e05SSudarsana Kalluru 	    ering->rx_pending < NUM_RX_BDS_MIN ||
69801ef7e05SSudarsana Kalluru 	    ering->tx_pending > NUM_TX_BDS_MAX ||
69901ef7e05SSudarsana Kalluru 	    ering->tx_pending < NUM_TX_BDS_MIN) {
70001ef7e05SSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
70101ef7e05SSudarsana Kalluru 			   "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n",
70201ef7e05SSudarsana Kalluru 			   NUM_RX_BDS_MIN, NUM_RX_BDS_MAX,
70301ef7e05SSudarsana Kalluru 			   NUM_TX_BDS_MIN, NUM_TX_BDS_MAX);
70401ef7e05SSudarsana Kalluru 		return -EINVAL;
70501ef7e05SSudarsana Kalluru 	}
70601ef7e05SSudarsana Kalluru 
70701ef7e05SSudarsana Kalluru 	/* Change ring size and re-load */
70801ef7e05SSudarsana Kalluru 	edev->q_num_rx_buffers = ering->rx_pending;
70901ef7e05SSudarsana Kalluru 	edev->q_num_tx_buffers = ering->tx_pending;
71001ef7e05SSudarsana Kalluru 
711567b3c12SMintz, Yuval 	qede_reload(edev, NULL, false);
71201ef7e05SSudarsana Kalluru 
71301ef7e05SSudarsana Kalluru 	return 0;
71401ef7e05SSudarsana Kalluru }
71501ef7e05SSudarsana Kalluru 
7160f7db144SSudarsana Kalluru static void qede_get_pauseparam(struct net_device *dev,
7170f7db144SSudarsana Kalluru 				struct ethtool_pauseparam *epause)
7180f7db144SSudarsana Kalluru {
7190f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
7200f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
7210f7db144SSudarsana Kalluru 
7220f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
7230f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
7240f7db144SSudarsana Kalluru 
7250f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE)
7260f7db144SSudarsana Kalluru 		epause->autoneg = true;
7270f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE)
7280f7db144SSudarsana Kalluru 		epause->rx_pause = true;
7290f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE)
7300f7db144SSudarsana Kalluru 		epause->tx_pause = true;
7310f7db144SSudarsana Kalluru 
7320f7db144SSudarsana Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
7330f7db144SSudarsana Kalluru 		   "ethtool_pauseparam: cmd %d  autoneg %d  rx_pause %d  tx_pause %d\n",
7340f7db144SSudarsana Kalluru 		   epause->cmd, epause->autoneg, epause->rx_pause,
7350f7db144SSudarsana Kalluru 		   epause->tx_pause);
7360f7db144SSudarsana Kalluru }
7370f7db144SSudarsana Kalluru 
7380f7db144SSudarsana Kalluru static int qede_set_pauseparam(struct net_device *dev,
7390f7db144SSudarsana Kalluru 			       struct ethtool_pauseparam *epause)
7400f7db144SSudarsana Kalluru {
7410f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
7420f7db144SSudarsana Kalluru 	struct qed_link_params params;
7430f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
7440f7db144SSudarsana Kalluru 
745fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
7460f7db144SSudarsana Kalluru 		DP_INFO(edev,
747fe7cd2bfSYuval Mintz 			"Pause settings are not allowed to be changed\n");
7480f7db144SSudarsana Kalluru 		return -EOPNOTSUPP;
7490f7db144SSudarsana Kalluru 	}
7500f7db144SSudarsana Kalluru 
7510f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
7520f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
7530f7db144SSudarsana Kalluru 
7540f7db144SSudarsana Kalluru 	memset(&params, 0, sizeof(params));
7550f7db144SSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG;
7560f7db144SSudarsana Kalluru 	if (epause->autoneg) {
757d194fd26SYuval Mintz 		if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
7580f7db144SSudarsana Kalluru 			DP_INFO(edev, "autoneg not supported\n");
7590f7db144SSudarsana Kalluru 			return -EINVAL;
7600f7db144SSudarsana Kalluru 		}
7610f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE;
7620f7db144SSudarsana Kalluru 	}
7630f7db144SSudarsana Kalluru 	if (epause->rx_pause)
7640f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_RX_ENABLE;
7650f7db144SSudarsana Kalluru 	if (epause->tx_pause)
7660f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_TX_ENABLE;
7670f7db144SSudarsana Kalluru 
7680f7db144SSudarsana Kalluru 	params.link_up = true;
7690f7db144SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
7700f7db144SSudarsana Kalluru 
7710f7db144SSudarsana Kalluru 	return 0;
7720f7db144SSudarsana Kalluru }
7730f7db144SSudarsana Kalluru 
774e0971c83STomer Tayar static void qede_get_regs(struct net_device *ndev,
775e0971c83STomer Tayar 			  struct ethtool_regs *regs, void *buffer)
776e0971c83STomer Tayar {
777e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
778e0971c83STomer Tayar 
779e0971c83STomer Tayar 	regs->version = 0;
780e0971c83STomer Tayar 	memset(buffer, 0, regs->len);
781e0971c83STomer Tayar 
782e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
783e0971c83STomer Tayar 		edev->ops->common->dbg_all_data(edev->cdev, buffer);
784e0971c83STomer Tayar }
785e0971c83STomer Tayar 
786e0971c83STomer Tayar static int qede_get_regs_len(struct net_device *ndev)
787e0971c83STomer Tayar {
788e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
789e0971c83STomer Tayar 
790e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
791e0971c83STomer Tayar 		return edev->ops->common->dbg_all_data_size(edev->cdev);
792e0971c83STomer Tayar 	else
793e0971c83STomer Tayar 		return -EINVAL;
794e0971c83STomer Tayar }
795e0971c83STomer Tayar 
796567b3c12SMintz, Yuval static void qede_update_mtu(struct qede_dev *edev,
797567b3c12SMintz, Yuval 			    struct qede_reload_args *args)
798133fac0eSSudarsana Kalluru {
799567b3c12SMintz, Yuval 	edev->ndev->mtu = args->u.mtu;
800133fac0eSSudarsana Kalluru }
801133fac0eSSudarsana Kalluru 
802133fac0eSSudarsana Kalluru /* Netdevice NDOs */
803133fac0eSSudarsana Kalluru int qede_change_mtu(struct net_device *ndev, int new_mtu)
804133fac0eSSudarsana Kalluru {
805133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
806567b3c12SMintz, Yuval 	struct qede_reload_args args;
807133fac0eSSudarsana Kalluru 
808133fac0eSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
809133fac0eSSudarsana Kalluru 		   "Configuring MTU size of %d\n", new_mtu);
810133fac0eSSudarsana Kalluru 
811133fac0eSSudarsana Kalluru 	/* Set the mtu field and re-start the interface if needed */
812567b3c12SMintz, Yuval 	args.u.mtu = new_mtu;
813567b3c12SMintz, Yuval 	args.func = &qede_update_mtu;
814567b3c12SMintz, Yuval 	qede_reload(edev, &args, false);
815133fac0eSSudarsana Kalluru 
816567b3c12SMintz, Yuval 	edev->ops->common->update_mtu(edev->cdev, new_mtu);
8170fefbfbaSSudarsana Kalluru 
818133fac0eSSudarsana Kalluru 	return 0;
819133fac0eSSudarsana Kalluru }
820133fac0eSSudarsana Kalluru 
8218edf049dSSudarsana Kalluru static void qede_get_channels(struct net_device *dev,
8228edf049dSSudarsana Kalluru 			      struct ethtool_channels *channels)
8238edf049dSSudarsana Kalluru {
8248edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
8258edf049dSSudarsana Kalluru 
8268edf049dSSudarsana Kalluru 	channels->max_combined = QEDE_MAX_RSS_CNT(edev);
827bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_rx = QEDE_MAX_RSS_CNT(edev);
828bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_tx = QEDE_MAX_RSS_CNT(edev);
8299a4d7e86SSudarsana Reddy Kalluru 	channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx -
8309a4d7e86SSudarsana Reddy Kalluru 					edev->fp_num_rx;
8319a4d7e86SSudarsana Reddy Kalluru 	channels->tx_count = edev->fp_num_tx;
8329a4d7e86SSudarsana Reddy Kalluru 	channels->rx_count = edev->fp_num_rx;
8338edf049dSSudarsana Kalluru }
8348edf049dSSudarsana Kalluru 
8358edf049dSSudarsana Kalluru static int qede_set_channels(struct net_device *dev,
8368edf049dSSudarsana Kalluru 			     struct ethtool_channels *channels)
8378edf049dSSudarsana Kalluru {
8388edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
8399a4d7e86SSudarsana Reddy Kalluru 	u32 count;
8408edf049dSSudarsana Kalluru 
8418edf049dSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8428edf049dSSudarsana Kalluru 		   "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n",
8438edf049dSSudarsana Kalluru 		   channels->rx_count, channels->tx_count,
8448edf049dSSudarsana Kalluru 		   channels->other_count, channels->combined_count);
8458edf049dSSudarsana Kalluru 
8469a4d7e86SSudarsana Reddy Kalluru 	count = channels->rx_count + channels->tx_count +
8479a4d7e86SSudarsana Reddy Kalluru 			channels->combined_count;
8489a4d7e86SSudarsana Reddy Kalluru 
8499a4d7e86SSudarsana Reddy Kalluru 	/* We don't support `other' channels */
8509a4d7e86SSudarsana Reddy Kalluru 	if (channels->other_count) {
8518edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8528edf049dSSudarsana Kalluru 			   "command parameters not supported\n");
8538edf049dSSudarsana Kalluru 		return -EINVAL;
8548edf049dSSudarsana Kalluru 	}
8558edf049dSSudarsana Kalluru 
8569a4d7e86SSudarsana Reddy Kalluru 	if (!(channels->combined_count || (channels->rx_count &&
8579a4d7e86SSudarsana Reddy Kalluru 					   channels->tx_count))) {
8589a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8599a4d7e86SSudarsana Reddy Kalluru 			   "need to request at least one transmit and one receive channel\n");
8609a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
8619a4d7e86SSudarsana Reddy Kalluru 	}
8629a4d7e86SSudarsana Reddy Kalluru 
8639a4d7e86SSudarsana Reddy Kalluru 	if (count > QEDE_MAX_RSS_CNT(edev)) {
8649a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8659a4d7e86SSudarsana Reddy Kalluru 			   "requested channels = %d max supported channels = %d\n",
8669a4d7e86SSudarsana Reddy Kalluru 			   count, QEDE_MAX_RSS_CNT(edev));
8679a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
8689a4d7e86SSudarsana Reddy Kalluru 	}
8699a4d7e86SSudarsana Reddy Kalluru 
8708edf049dSSudarsana Kalluru 	/* Check if there was a change in the active parameters */
8719a4d7e86SSudarsana Reddy Kalluru 	if ((count == QEDE_QUEUE_CNT(edev)) &&
8729a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count == edev->fp_num_tx) &&
8739a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count == edev->fp_num_rx)) {
8748edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8758edf049dSSudarsana Kalluru 			   "No change in active parameters\n");
8768edf049dSSudarsana Kalluru 		return 0;
8778edf049dSSudarsana Kalluru 	}
8788edf049dSSudarsana Kalluru 
8798edf049dSSudarsana Kalluru 	/* We need the number of queues to be divisible between the hwfns */
8809a4d7e86SSudarsana Reddy Kalluru 	if ((count % edev->dev_info.common.num_hwfns) ||
8819a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count % edev->dev_info.common.num_hwfns) ||
8829a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count % edev->dev_info.common.num_hwfns)) {
8838edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8849a4d7e86SSudarsana Reddy Kalluru 			   "Number of channels must be divisible by %04x\n",
8858edf049dSSudarsana Kalluru 			   edev->dev_info.common.num_hwfns);
8868edf049dSSudarsana Kalluru 		return -EINVAL;
8878edf049dSSudarsana Kalluru 	}
8888edf049dSSudarsana Kalluru 
8898edf049dSSudarsana Kalluru 	/* Set number of queues and reload if necessary */
8909a4d7e86SSudarsana Reddy Kalluru 	edev->req_queues = count;
8919a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_tx = channels->tx_count;
8929a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_rx = channels->rx_count;
893ed0dd915SSudarsana Reddy Kalluru 	/* Reset the indirection table if rx queue count is updated */
894ed0dd915SSudarsana Reddy Kalluru 	if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) {
895ed0dd915SSudarsana Reddy Kalluru 		edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED;
896ed0dd915SSudarsana Reddy Kalluru 		memset(&edev->rss_params.rss_ind_table, 0,
897ed0dd915SSudarsana Reddy Kalluru 		       sizeof(edev->rss_params.rss_ind_table));
898ed0dd915SSudarsana Reddy Kalluru 	}
899ed0dd915SSudarsana Reddy Kalluru 
900567b3c12SMintz, Yuval 	qede_reload(edev, NULL, false);
9018edf049dSSudarsana Kalluru 
9028edf049dSSudarsana Kalluru 	return 0;
9038edf049dSSudarsana Kalluru }
9048edf049dSSudarsana Kalluru 
9053d971cbdSSudarsana Kalluru static int qede_set_phys_id(struct net_device *dev,
9063d971cbdSSudarsana Kalluru 			    enum ethtool_phys_id_state state)
9073d971cbdSSudarsana Kalluru {
9083d971cbdSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
9093d971cbdSSudarsana Kalluru 	u8 led_state = 0;
9103d971cbdSSudarsana Kalluru 
9113d971cbdSSudarsana Kalluru 	switch (state) {
9123d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ACTIVE:
9133d971cbdSSudarsana Kalluru 		return 1;	/* cycle on/off once per second */
9143d971cbdSSudarsana Kalluru 
9153d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ON:
9163d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_ON;
9173d971cbdSSudarsana Kalluru 		break;
9183d971cbdSSudarsana Kalluru 
9193d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_OFF:
9203d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_OFF;
9213d971cbdSSudarsana Kalluru 		break;
9223d971cbdSSudarsana Kalluru 
9233d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_INACTIVE:
9243d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_RESTORE;
9253d971cbdSSudarsana Kalluru 		break;
9263d971cbdSSudarsana Kalluru 	}
9273d971cbdSSudarsana Kalluru 
9283d971cbdSSudarsana Kalluru 	edev->ops->common->set_led(edev->cdev, led_state);
9293d971cbdSSudarsana Kalluru 
9303d971cbdSSudarsana Kalluru 	return 0;
9313d971cbdSSudarsana Kalluru }
9323d971cbdSSudarsana Kalluru 
933961acdeaSSudarsana Reddy Kalluru static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
934961acdeaSSudarsana Reddy Kalluru {
935961acdeaSSudarsana Reddy Kalluru 	info->data = RXH_IP_SRC | RXH_IP_DST;
936961acdeaSSudarsana Reddy Kalluru 
937961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
938961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
939961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
940961acdeaSSudarsana Reddy Kalluru 		info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
941961acdeaSSudarsana Reddy Kalluru 		break;
942961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
943961acdeaSSudarsana Reddy Kalluru 		if (edev->rss_params.rss_caps & QED_RSS_IPV4_UDP)
944961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
945961acdeaSSudarsana Reddy Kalluru 		break;
946961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
947961acdeaSSudarsana Reddy Kalluru 		if (edev->rss_params.rss_caps & QED_RSS_IPV6_UDP)
948961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
949961acdeaSSudarsana Reddy Kalluru 		break;
950961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
951961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
952961acdeaSSudarsana Reddy Kalluru 		break;
953961acdeaSSudarsana Reddy Kalluru 	default:
954961acdeaSSudarsana Reddy Kalluru 		info->data = 0;
955961acdeaSSudarsana Reddy Kalluru 		break;
956961acdeaSSudarsana Reddy Kalluru 	}
957961acdeaSSudarsana Reddy Kalluru 
958961acdeaSSudarsana Reddy Kalluru 	return 0;
959961acdeaSSudarsana Reddy Kalluru }
960961acdeaSSudarsana Reddy Kalluru 
961961acdeaSSudarsana Reddy Kalluru static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
962961acdeaSSudarsana Reddy Kalluru 			  u32 *rules __always_unused)
963961acdeaSSudarsana Reddy Kalluru {
964961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
965961acdeaSSudarsana Reddy Kalluru 
966961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
967961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXRINGS:
9689a4d7e86SSudarsana Reddy Kalluru 		info->data = QEDE_RSS_COUNT(edev);
969961acdeaSSudarsana Reddy Kalluru 		return 0;
970961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXFH:
971961acdeaSSudarsana Reddy Kalluru 		return qede_get_rss_flags(edev, info);
972961acdeaSSudarsana Reddy Kalluru 	default:
973961acdeaSSudarsana Reddy Kalluru 		DP_ERR(edev, "Command parameters not supported\n");
974961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
975961acdeaSSudarsana Reddy Kalluru 	}
976961acdeaSSudarsana Reddy Kalluru }
977961acdeaSSudarsana Reddy Kalluru 
978961acdeaSSudarsana Reddy Kalluru static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
979961acdeaSSudarsana Reddy Kalluru {
980961acdeaSSudarsana Reddy Kalluru 	struct qed_update_vport_params vport_update_params;
981961acdeaSSudarsana Reddy Kalluru 	u8 set_caps = 0, clr_caps = 0;
982961acdeaSSudarsana Reddy Kalluru 
983961acdeaSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
984961acdeaSSudarsana Reddy Kalluru 		   "Set rss flags command parameters: flow type = %d, data = %llu\n",
985961acdeaSSudarsana Reddy Kalluru 		   info->flow_type, info->data);
986961acdeaSSudarsana Reddy Kalluru 
987961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
988961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
989961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
990961acdeaSSudarsana Reddy Kalluru 		/* For TCP only 4-tuple hash is supported */
991961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
992961acdeaSSudarsana Reddy Kalluru 				  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
993961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
994961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
995961acdeaSSudarsana Reddy Kalluru 		}
996961acdeaSSudarsana Reddy Kalluru 		return 0;
997961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
998961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
999961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
1000961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1001961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV4_UDP;
1002961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1003961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
1004961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
1005961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV4_UDP;
1006961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1007961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
1008961acdeaSSudarsana Reddy Kalluru 		} else {
1009961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1010961acdeaSSudarsana Reddy Kalluru 		}
1011961acdeaSSudarsana Reddy Kalluru 		break;
1012961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
1013961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
1014961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
1015961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1016961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV6_UDP;
1017961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1018961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
1019961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
1020961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV6_UDP;
1021961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1022961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
1023961acdeaSSudarsana Reddy Kalluru 		} else {
1024961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1025961acdeaSSudarsana Reddy Kalluru 		}
1026961acdeaSSudarsana Reddy Kalluru 		break;
1027961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
1028961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
1029961acdeaSSudarsana Reddy Kalluru 		/* For IP only 2-tuple hash is supported */
1030961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
1031961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1032961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1033961acdeaSSudarsana Reddy Kalluru 		}
1034961acdeaSSudarsana Reddy Kalluru 		return 0;
1035961acdeaSSudarsana Reddy Kalluru 	case SCTP_V4_FLOW:
1036961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V4_FLOW:
1037961acdeaSSudarsana Reddy Kalluru 	case AH_V4_FLOW:
1038961acdeaSSudarsana Reddy Kalluru 	case ESP_V4_FLOW:
1039961acdeaSSudarsana Reddy Kalluru 	case SCTP_V6_FLOW:
1040961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V6_FLOW:
1041961acdeaSSudarsana Reddy Kalluru 	case AH_V6_FLOW:
1042961acdeaSSudarsana Reddy Kalluru 	case ESP_V6_FLOW:
1043961acdeaSSudarsana Reddy Kalluru 	case IP_USER_FLOW:
1044961acdeaSSudarsana Reddy Kalluru 	case ETHER_FLOW:
1045961acdeaSSudarsana Reddy Kalluru 		/* RSS is not supported for these protocols */
1046961acdeaSSudarsana Reddy Kalluru 		if (info->data) {
1047961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1048961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1049961acdeaSSudarsana Reddy Kalluru 		}
1050961acdeaSSudarsana Reddy Kalluru 		return 0;
1051961acdeaSSudarsana Reddy Kalluru 	default:
1052961acdeaSSudarsana Reddy Kalluru 		return -EINVAL;
1053961acdeaSSudarsana Reddy Kalluru 	}
1054961acdeaSSudarsana Reddy Kalluru 
1055961acdeaSSudarsana Reddy Kalluru 	/* No action is needed if there is no change in the rss capability */
1056961acdeaSSudarsana Reddy Kalluru 	if (edev->rss_params.rss_caps == ((edev->rss_params.rss_caps &
1057961acdeaSSudarsana Reddy Kalluru 					   ~clr_caps) | set_caps))
1058961acdeaSSudarsana Reddy Kalluru 		return 0;
1059961acdeaSSudarsana Reddy Kalluru 
1060961acdeaSSudarsana Reddy Kalluru 	/* Update internal configuration */
1061961acdeaSSudarsana Reddy Kalluru 	edev->rss_params.rss_caps = (edev->rss_params.rss_caps & ~clr_caps) |
1062961acdeaSSudarsana Reddy Kalluru 				    set_caps;
1063961acdeaSSudarsana Reddy Kalluru 	edev->rss_params_inited |= QEDE_RSS_CAPS_INITED;
1064961acdeaSSudarsana Reddy Kalluru 
1065961acdeaSSudarsana Reddy Kalluru 	/* Re-configure if possible */
1066961acdeaSSudarsana Reddy Kalluru 	if (netif_running(edev->ndev)) {
1067961acdeaSSudarsana Reddy Kalluru 		memset(&vport_update_params, 0, sizeof(vport_update_params));
1068961acdeaSSudarsana Reddy Kalluru 		vport_update_params.update_rss_flg = 1;
1069961acdeaSSudarsana Reddy Kalluru 		vport_update_params.vport_id = 0;
1070961acdeaSSudarsana Reddy Kalluru 		memcpy(&vport_update_params.rss_params, &edev->rss_params,
1071961acdeaSSudarsana Reddy Kalluru 		       sizeof(vport_update_params.rss_params));
1072961acdeaSSudarsana Reddy Kalluru 		return edev->ops->vport_update(edev->cdev,
1073961acdeaSSudarsana Reddy Kalluru 					       &vport_update_params);
1074961acdeaSSudarsana Reddy Kalluru 	}
1075961acdeaSSudarsana Reddy Kalluru 
1076961acdeaSSudarsana Reddy Kalluru 	return 0;
1077961acdeaSSudarsana Reddy Kalluru }
1078961acdeaSSudarsana Reddy Kalluru 
1079961acdeaSSudarsana Reddy Kalluru static int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
1080961acdeaSSudarsana Reddy Kalluru {
1081961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1082961acdeaSSudarsana Reddy Kalluru 
1083961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
1084961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_SRXFH:
1085961acdeaSSudarsana Reddy Kalluru 		return qede_set_rss_flags(edev, info);
1086961acdeaSSudarsana Reddy Kalluru 	default:
1087961acdeaSSudarsana Reddy Kalluru 		DP_INFO(edev, "Command parameters not supported\n");
1088961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1089961acdeaSSudarsana Reddy Kalluru 	}
1090961acdeaSSudarsana Reddy Kalluru }
1091961acdeaSSudarsana Reddy Kalluru 
1092961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_indir_size(struct net_device *dev)
1093961acdeaSSudarsana Reddy Kalluru {
1094961acdeaSSudarsana Reddy Kalluru 	return QED_RSS_IND_TABLE_SIZE;
1095961acdeaSSudarsana Reddy Kalluru }
1096961acdeaSSudarsana Reddy Kalluru 
1097961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_key_size(struct net_device *dev)
1098961acdeaSSudarsana Reddy Kalluru {
1099961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1100961acdeaSSudarsana Reddy Kalluru 
1101961acdeaSSudarsana Reddy Kalluru 	return sizeof(edev->rss_params.rss_key);
1102961acdeaSSudarsana Reddy Kalluru }
1103961acdeaSSudarsana Reddy Kalluru 
1104961acdeaSSudarsana Reddy Kalluru static int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
1105961acdeaSSudarsana Reddy Kalluru {
1106961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1107961acdeaSSudarsana Reddy Kalluru 	int i;
1108961acdeaSSudarsana Reddy Kalluru 
1109961acdeaSSudarsana Reddy Kalluru 	if (hfunc)
1110961acdeaSSudarsana Reddy Kalluru 		*hfunc = ETH_RSS_HASH_TOP;
1111961acdeaSSudarsana Reddy Kalluru 
1112961acdeaSSudarsana Reddy Kalluru 	if (!indir)
1113961acdeaSSudarsana Reddy Kalluru 		return 0;
1114961acdeaSSudarsana Reddy Kalluru 
1115961acdeaSSudarsana Reddy Kalluru 	for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1116961acdeaSSudarsana Reddy Kalluru 		indir[i] = edev->rss_params.rss_ind_table[i];
1117961acdeaSSudarsana Reddy Kalluru 
1118961acdeaSSudarsana Reddy Kalluru 	if (key)
1119961acdeaSSudarsana Reddy Kalluru 		memcpy(key, edev->rss_params.rss_key,
1120961acdeaSSudarsana Reddy Kalluru 		       qede_get_rxfh_key_size(dev));
1121961acdeaSSudarsana Reddy Kalluru 
1122961acdeaSSudarsana Reddy Kalluru 	return 0;
1123961acdeaSSudarsana Reddy Kalluru }
1124961acdeaSSudarsana Reddy Kalluru 
1125961acdeaSSudarsana Reddy Kalluru static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
1126961acdeaSSudarsana Reddy Kalluru 			 const u8 *key, const u8 hfunc)
1127961acdeaSSudarsana Reddy Kalluru {
1128961acdeaSSudarsana Reddy Kalluru 	struct qed_update_vport_params vport_update_params;
1129961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1130961acdeaSSudarsana Reddy Kalluru 	int i;
1131961acdeaSSudarsana Reddy Kalluru 
1132ba300ce3SSudarsana Reddy Kalluru 	if (edev->dev_info.common.num_hwfns > 1) {
1133ba300ce3SSudarsana Reddy Kalluru 		DP_INFO(edev,
1134ba300ce3SSudarsana Reddy Kalluru 			"RSS configuration is not supported for 100G devices\n");
1135ba300ce3SSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1136ba300ce3SSudarsana Reddy Kalluru 	}
1137ba300ce3SSudarsana Reddy Kalluru 
1138961acdeaSSudarsana Reddy Kalluru 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
1139961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1140961acdeaSSudarsana Reddy Kalluru 
1141961acdeaSSudarsana Reddy Kalluru 	if (!indir && !key)
1142961acdeaSSudarsana Reddy Kalluru 		return 0;
1143961acdeaSSudarsana Reddy Kalluru 
1144961acdeaSSudarsana Reddy Kalluru 	if (indir) {
1145961acdeaSSudarsana Reddy Kalluru 		for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1146961acdeaSSudarsana Reddy Kalluru 			edev->rss_params.rss_ind_table[i] = indir[i];
1147961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_INDIR_INITED;
1148961acdeaSSudarsana Reddy Kalluru 	}
1149961acdeaSSudarsana Reddy Kalluru 
1150961acdeaSSudarsana Reddy Kalluru 	if (key) {
1151961acdeaSSudarsana Reddy Kalluru 		memcpy(&edev->rss_params.rss_key, key,
1152961acdeaSSudarsana Reddy Kalluru 		       qede_get_rxfh_key_size(dev));
1153961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_KEY_INITED;
1154961acdeaSSudarsana Reddy Kalluru 	}
1155961acdeaSSudarsana Reddy Kalluru 
1156961acdeaSSudarsana Reddy Kalluru 	if (netif_running(edev->ndev)) {
1157961acdeaSSudarsana Reddy Kalluru 		memset(&vport_update_params, 0, sizeof(vport_update_params));
1158961acdeaSSudarsana Reddy Kalluru 		vport_update_params.update_rss_flg = 1;
1159961acdeaSSudarsana Reddy Kalluru 		vport_update_params.vport_id = 0;
1160961acdeaSSudarsana Reddy Kalluru 		memcpy(&vport_update_params.rss_params, &edev->rss_params,
1161961acdeaSSudarsana Reddy Kalluru 		       sizeof(vport_update_params.rss_params));
1162961acdeaSSudarsana Reddy Kalluru 		return edev->ops->vport_update(edev->cdev,
1163961acdeaSSudarsana Reddy Kalluru 					       &vport_update_params);
1164961acdeaSSudarsana Reddy Kalluru 	}
1165961acdeaSSudarsana Reddy Kalluru 
1166961acdeaSSudarsana Reddy Kalluru 	return 0;
1167961acdeaSSudarsana Reddy Kalluru }
1168961acdeaSSudarsana Reddy Kalluru 
116916f46bf0SSudarsana Reddy Kalluru /* This function enables the interrupt generation and the NAPI on the device */
117016f46bf0SSudarsana Reddy Kalluru static void qede_netif_start(struct qede_dev *edev)
117116f46bf0SSudarsana Reddy Kalluru {
117216f46bf0SSudarsana Reddy Kalluru 	int i;
117316f46bf0SSudarsana Reddy Kalluru 
117416f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev))
117516f46bf0SSudarsana Reddy Kalluru 		return;
117616f46bf0SSudarsana Reddy Kalluru 
11779a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
117816f46bf0SSudarsana Reddy Kalluru 		/* Update and reenable interrupts */
117916f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_ENABLE, 1);
118016f46bf0SSudarsana Reddy Kalluru 		napi_enable(&edev->fp_array[i].napi);
118116f46bf0SSudarsana Reddy Kalluru 	}
118216f46bf0SSudarsana Reddy Kalluru }
118316f46bf0SSudarsana Reddy Kalluru 
118416f46bf0SSudarsana Reddy Kalluru /* This function disables the NAPI and the interrupt generation on the device */
118516f46bf0SSudarsana Reddy Kalluru static void qede_netif_stop(struct qede_dev *edev)
118616f46bf0SSudarsana Reddy Kalluru {
118716f46bf0SSudarsana Reddy Kalluru 	int i;
118816f46bf0SSudarsana Reddy Kalluru 
11899a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
119016f46bf0SSudarsana Reddy Kalluru 		napi_disable(&edev->fp_array[i].napi);
119116f46bf0SSudarsana Reddy Kalluru 		/* Disable interrupts */
119216f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_DISABLE, 0);
119316f46bf0SSudarsana Reddy Kalluru 	}
119416f46bf0SSudarsana Reddy Kalluru }
119516f46bf0SSudarsana Reddy Kalluru 
119616f46bf0SSudarsana Reddy Kalluru static int qede_selftest_transmit_traffic(struct qede_dev *edev,
119716f46bf0SSudarsana Reddy Kalluru 					  struct sk_buff *skb)
119816f46bf0SSudarsana Reddy Kalluru {
11999a4d7e86SSudarsana Reddy Kalluru 	struct qede_tx_queue *txq = NULL;
120016f46bf0SSudarsana Reddy Kalluru 	struct eth_tx_1st_bd *first_bd;
120116f46bf0SSudarsana Reddy Kalluru 	dma_addr_t mapping;
120216f46bf0SSudarsana Reddy Kalluru 	int i, idx, val;
120316f46bf0SSudarsana Reddy Kalluru 
12049a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
12059a4d7e86SSudarsana Reddy Kalluru 		if (edev->fp_array[i].type & QEDE_FASTPATH_TX) {
120680439a17SMintz, Yuval 			txq = edev->fp_array[i].txq;
12079a4d7e86SSudarsana Reddy Kalluru 			break;
12089a4d7e86SSudarsana Reddy Kalluru 		}
12099a4d7e86SSudarsana Reddy Kalluru 	}
12109a4d7e86SSudarsana Reddy Kalluru 
12119a4d7e86SSudarsana Reddy Kalluru 	if (!txq) {
12129a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx path is not available\n");
12139a4d7e86SSudarsana Reddy Kalluru 		return -1;
12149a4d7e86SSudarsana Reddy Kalluru 	}
12159a4d7e86SSudarsana Reddy Kalluru 
121616f46bf0SSudarsana Reddy Kalluru 	/* Fill the entry in the SW ring and the BDs in the FW ring */
121716f46bf0SSudarsana Reddy Kalluru 	idx = txq->sw_tx_prod & NUM_TX_BDS_MAX;
121816f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_ring[idx].skb = skb;
121916f46bf0SSudarsana Reddy Kalluru 	first_bd = qed_chain_produce(&txq->tx_pbl);
122016f46bf0SSudarsana Reddy Kalluru 	memset(first_bd, 0, sizeof(*first_bd));
122116f46bf0SSudarsana Reddy Kalluru 	val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT;
122216f46bf0SSudarsana Reddy Kalluru 	first_bd->data.bd_flags.bitfields = val;
1223351a4dedSYuval Mintz 	val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK;
1224351a4dedSYuval Mintz 	first_bd->data.bitfields |= (val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT);
122516f46bf0SSudarsana Reddy Kalluru 
122616f46bf0SSudarsana Reddy Kalluru 	/* Map skb linear data for DMA and set in the first BD */
122716f46bf0SSudarsana Reddy Kalluru 	mapping = dma_map_single(&edev->pdev->dev, skb->data,
122816f46bf0SSudarsana Reddy Kalluru 				 skb_headlen(skb), DMA_TO_DEVICE);
122916f46bf0SSudarsana Reddy Kalluru 	if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) {
123016f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "SKB mapping failed\n");
123116f46bf0SSudarsana Reddy Kalluru 		return -ENOMEM;
123216f46bf0SSudarsana Reddy Kalluru 	}
123316f46bf0SSudarsana Reddy Kalluru 	BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb));
123416f46bf0SSudarsana Reddy Kalluru 
123516f46bf0SSudarsana Reddy Kalluru 	/* update the first BD with the actual num BDs */
123616f46bf0SSudarsana Reddy Kalluru 	first_bd->data.nbds = 1;
123716f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_prod++;
123816f46bf0SSudarsana Reddy Kalluru 	/* 'next page' entries are counted in the producer value */
123916f46bf0SSudarsana Reddy Kalluru 	val = cpu_to_le16(qed_chain_get_prod_idx(&txq->tx_pbl));
124016f46bf0SSudarsana Reddy Kalluru 	txq->tx_db.data.bd_prod = val;
124116f46bf0SSudarsana Reddy Kalluru 
124216f46bf0SSudarsana Reddy Kalluru 	/* wmb makes sure that the BDs data is updated before updating the
124316f46bf0SSudarsana Reddy Kalluru 	 * producer, otherwise FW may read old data from the BDs.
124416f46bf0SSudarsana Reddy Kalluru 	 */
124516f46bf0SSudarsana Reddy Kalluru 	wmb();
124616f46bf0SSudarsana Reddy Kalluru 	barrier();
124716f46bf0SSudarsana Reddy Kalluru 	writel(txq->tx_db.raw, txq->doorbell_addr);
124816f46bf0SSudarsana Reddy Kalluru 
124916f46bf0SSudarsana Reddy Kalluru 	/* mmiowb is needed to synchronize doorbell writes from more than one
125016f46bf0SSudarsana Reddy Kalluru 	 * processor. It guarantees that the write arrives to the device before
125116f46bf0SSudarsana Reddy Kalluru 	 * the queue lock is released and another start_xmit is called (possibly
125216f46bf0SSudarsana Reddy Kalluru 	 * on another CPU). Without this barrier, the next doorbell can bypass
125316f46bf0SSudarsana Reddy Kalluru 	 * this doorbell. This is applicable to IA64/Altix systems.
125416f46bf0SSudarsana Reddy Kalluru 	 */
125516f46bf0SSudarsana Reddy Kalluru 	mmiowb();
125616f46bf0SSudarsana Reddy Kalluru 
125716f46bf0SSudarsana Reddy Kalluru 	for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
125816f46bf0SSudarsana Reddy Kalluru 		if (qede_txq_has_work(txq))
125916f46bf0SSudarsana Reddy Kalluru 			break;
126016f46bf0SSudarsana Reddy Kalluru 		usleep_range(100, 200);
126116f46bf0SSudarsana Reddy Kalluru 	}
126216f46bf0SSudarsana Reddy Kalluru 
126316f46bf0SSudarsana Reddy Kalluru 	if (!qede_txq_has_work(txq)) {
126416f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx completion didn't happen\n");
126516f46bf0SSudarsana Reddy Kalluru 		return -1;
126616f46bf0SSudarsana Reddy Kalluru 	}
126716f46bf0SSudarsana Reddy Kalluru 
126816f46bf0SSudarsana Reddy Kalluru 	first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl);
1269fabd545cSManish Chopra 	dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
127016f46bf0SSudarsana Reddy Kalluru 			 BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE);
127116f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_cons++;
127216f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_ring[idx].skb = NULL;
127316f46bf0SSudarsana Reddy Kalluru 
127416f46bf0SSudarsana Reddy Kalluru 	return 0;
127516f46bf0SSudarsana Reddy Kalluru }
127616f46bf0SSudarsana Reddy Kalluru 
127716f46bf0SSudarsana Reddy Kalluru static int qede_selftest_receive_traffic(struct qede_dev *edev)
127816f46bf0SSudarsana Reddy Kalluru {
127916f46bf0SSudarsana Reddy Kalluru 	u16 hw_comp_cons, sw_comp_cons, sw_rx_index, len;
128016f46bf0SSudarsana Reddy Kalluru 	struct eth_fast_path_rx_reg_cqe *fp_cqe;
12819a4d7e86SSudarsana Reddy Kalluru 	struct qede_rx_queue *rxq = NULL;
128216f46bf0SSudarsana Reddy Kalluru 	struct sw_rx_data *sw_rx_data;
128316f46bf0SSudarsana Reddy Kalluru 	union eth_rx_cqe *cqe;
1284837d4eb6SSudarsana Reddy Kalluru 	int i, rc = 0;
128516f46bf0SSudarsana Reddy Kalluru 	u8 *data_ptr;
128616f46bf0SSudarsana Reddy Kalluru 
12879a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
12889a4d7e86SSudarsana Reddy Kalluru 		if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
12899a4d7e86SSudarsana Reddy Kalluru 			rxq = edev->fp_array[i].rxq;
12909a4d7e86SSudarsana Reddy Kalluru 			break;
12919a4d7e86SSudarsana Reddy Kalluru 		}
12929a4d7e86SSudarsana Reddy Kalluru 	}
12939a4d7e86SSudarsana Reddy Kalluru 
12949a4d7e86SSudarsana Reddy Kalluru 	if (!rxq) {
12959a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Rx path is not available\n");
12969a4d7e86SSudarsana Reddy Kalluru 		return -1;
12979a4d7e86SSudarsana Reddy Kalluru 	}
12989a4d7e86SSudarsana Reddy Kalluru 
129916f46bf0SSudarsana Reddy Kalluru 	/* The packet is expected to receive on rx-queue 0 even though RSS is
130016f46bf0SSudarsana Reddy Kalluru 	 * enabled. This is because the queue 0 is configured as the default
130116f46bf0SSudarsana Reddy Kalluru 	 * queue and that the loopback traffic is not IP.
130216f46bf0SSudarsana Reddy Kalluru 	 */
130316f46bf0SSudarsana Reddy Kalluru 	for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
130416f46bf0SSudarsana Reddy Kalluru 		if (!qede_has_rx_work(rxq)) {
1305837d4eb6SSudarsana Reddy Kalluru 			usleep_range(100, 200);
1306837d4eb6SSudarsana Reddy Kalluru 			continue;
130716f46bf0SSudarsana Reddy Kalluru 		}
130816f46bf0SSudarsana Reddy Kalluru 
130916f46bf0SSudarsana Reddy Kalluru 		hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr);
131016f46bf0SSudarsana Reddy Kalluru 		sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
131116f46bf0SSudarsana Reddy Kalluru 
1312837d4eb6SSudarsana Reddy Kalluru 		/* Memory barrier to prevent the CPU from doing speculative
1313837d4eb6SSudarsana Reddy Kalluru 		 * reads of CQE/BD before reading hw_comp_cons. If the CQE is
1314837d4eb6SSudarsana Reddy Kalluru 		 * read before it is written by FW, then FW writes CQE and SB,
1315837d4eb6SSudarsana Reddy Kalluru 		 * and then the CPU reads the hw_comp_cons, it will use an old
1316837d4eb6SSudarsana Reddy Kalluru 		 * CQE.
131716f46bf0SSudarsana Reddy Kalluru 		 */
131816f46bf0SSudarsana Reddy Kalluru 		rmb();
131916f46bf0SSudarsana Reddy Kalluru 
132016f46bf0SSudarsana Reddy Kalluru 		/* Get the CQE from the completion ring */
132116f46bf0SSudarsana Reddy Kalluru 		cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring);
132216f46bf0SSudarsana Reddy Kalluru 
132316f46bf0SSudarsana Reddy Kalluru 		/* Get the data from the SW ring */
132416f46bf0SSudarsana Reddy Kalluru 		sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
132516f46bf0SSudarsana Reddy Kalluru 		sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
132616f46bf0SSudarsana Reddy Kalluru 		fp_cqe = &cqe->fast_path_regular;
132716f46bf0SSudarsana Reddy Kalluru 		len =  le16_to_cpu(fp_cqe->len_on_first_bd);
132816f46bf0SSudarsana Reddy Kalluru 		data_ptr = (u8 *)(page_address(sw_rx_data->data) +
1329837d4eb6SSudarsana Reddy Kalluru 				  fp_cqe->placement_offset +
1330837d4eb6SSudarsana Reddy Kalluru 				  sw_rx_data->page_offset);
1331837d4eb6SSudarsana Reddy Kalluru 		if (ether_addr_equal(data_ptr,  edev->ndev->dev_addr) &&
1332837d4eb6SSudarsana Reddy Kalluru 		    ether_addr_equal(data_ptr + ETH_ALEN,
1333837d4eb6SSudarsana Reddy Kalluru 				     edev->ndev->dev_addr)) {
133416f46bf0SSudarsana Reddy Kalluru 			for (i = ETH_HLEN; i < len; i++)
133516f46bf0SSudarsana Reddy Kalluru 				if (data_ptr[i] != (unsigned char)(i & 0xff)) {
1336837d4eb6SSudarsana Reddy Kalluru 					rc = -1;
1337837d4eb6SSudarsana Reddy Kalluru 					break;
133816f46bf0SSudarsana Reddy Kalluru 				}
133916f46bf0SSudarsana Reddy Kalluru 
13409eb22357SMintz, Yuval 			qede_recycle_rx_bd_ring(rxq, 1);
1341837d4eb6SSudarsana Reddy Kalluru 			qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1342837d4eb6SSudarsana Reddy Kalluru 			break;
1343837d4eb6SSudarsana Reddy Kalluru 		}
134416f46bf0SSudarsana Reddy Kalluru 
1345837d4eb6SSudarsana Reddy Kalluru 		DP_INFO(edev, "Not the transmitted packet\n");
13469eb22357SMintz, Yuval 		qede_recycle_rx_bd_ring(rxq, 1);
1347837d4eb6SSudarsana Reddy Kalluru 		qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1348837d4eb6SSudarsana Reddy Kalluru 	}
1349837d4eb6SSudarsana Reddy Kalluru 
1350837d4eb6SSudarsana Reddy Kalluru 	if (i == QEDE_SELFTEST_POLL_COUNT) {
1351837d4eb6SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Failed to receive the traffic\n");
1352837d4eb6SSudarsana Reddy Kalluru 		return -1;
1353837d4eb6SSudarsana Reddy Kalluru 	}
1354837d4eb6SSudarsana Reddy Kalluru 
1355837d4eb6SSudarsana Reddy Kalluru 	qede_update_rx_prod(edev, rxq);
1356837d4eb6SSudarsana Reddy Kalluru 
1357837d4eb6SSudarsana Reddy Kalluru 	return rc;
135816f46bf0SSudarsana Reddy Kalluru }
135916f46bf0SSudarsana Reddy Kalluru 
136016f46bf0SSudarsana Reddy Kalluru static int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode)
136116f46bf0SSudarsana Reddy Kalluru {
136216f46bf0SSudarsana Reddy Kalluru 	struct qed_link_params link_params;
136316f46bf0SSudarsana Reddy Kalluru 	struct sk_buff *skb = NULL;
136416f46bf0SSudarsana Reddy Kalluru 	int rc = 0, i;
136516f46bf0SSudarsana Reddy Kalluru 	u32 pkt_size;
136616f46bf0SSudarsana Reddy Kalluru 	u8 *packet;
136716f46bf0SSudarsana Reddy Kalluru 
136816f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev)) {
136916f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Interface is down\n");
137016f46bf0SSudarsana Reddy Kalluru 		return -EINVAL;
137116f46bf0SSudarsana Reddy Kalluru 	}
137216f46bf0SSudarsana Reddy Kalluru 
137316f46bf0SSudarsana Reddy Kalluru 	qede_netif_stop(edev);
137416f46bf0SSudarsana Reddy Kalluru 
137516f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Loopback mode */
137616f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
137716f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
137816f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
137916f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = loopback_mode;
138016f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
138116f46bf0SSudarsana Reddy Kalluru 
138216f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
138316f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
138416f46bf0SSudarsana Reddy Kalluru 
138516f46bf0SSudarsana Reddy Kalluru 	/* prepare the loopback packet */
138616f46bf0SSudarsana Reddy Kalluru 	pkt_size = edev->ndev->mtu + ETH_HLEN;
138716f46bf0SSudarsana Reddy Kalluru 
138816f46bf0SSudarsana Reddy Kalluru 	skb = netdev_alloc_skb(edev->ndev, pkt_size);
138916f46bf0SSudarsana Reddy Kalluru 	if (!skb) {
139016f46bf0SSudarsana Reddy Kalluru 		DP_INFO(edev, "Can't allocate skb\n");
139116f46bf0SSudarsana Reddy Kalluru 		rc = -ENOMEM;
139216f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
139316f46bf0SSudarsana Reddy Kalluru 	}
139416f46bf0SSudarsana Reddy Kalluru 	packet = skb_put(skb, pkt_size);
139516f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet, edev->ndev->dev_addr);
139616f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet + ETH_ALEN, edev->ndev->dev_addr);
139716f46bf0SSudarsana Reddy Kalluru 	memset(packet + (2 * ETH_ALEN), 0x77, (ETH_HLEN - (2 * ETH_ALEN)));
139816f46bf0SSudarsana Reddy Kalluru 	for (i = ETH_HLEN; i < pkt_size; i++)
139916f46bf0SSudarsana Reddy Kalluru 		packet[i] = (unsigned char)(i & 0xff);
140016f46bf0SSudarsana Reddy Kalluru 
140116f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_transmit_traffic(edev, skb);
140216f46bf0SSudarsana Reddy Kalluru 	if (rc)
140316f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
140416f46bf0SSudarsana Reddy Kalluru 
140516f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_receive_traffic(edev);
140616f46bf0SSudarsana Reddy Kalluru 	if (rc)
140716f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
140816f46bf0SSudarsana Reddy Kalluru 
140916f46bf0SSudarsana Reddy Kalluru 	DP_VERBOSE(edev, NETIF_MSG_RX_STATUS, "Loopback test successful\n");
141016f46bf0SSudarsana Reddy Kalluru 
141116f46bf0SSudarsana Reddy Kalluru test_loopback_exit:
141216f46bf0SSudarsana Reddy Kalluru 	dev_kfree_skb(skb);
141316f46bf0SSudarsana Reddy Kalluru 
141416f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Normal mode */
141516f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
141616f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
141716f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
141816f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = QED_LINK_LOOPBACK_NONE;
141916f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
142016f46bf0SSudarsana Reddy Kalluru 
142116f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
142216f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
142316f46bf0SSudarsana Reddy Kalluru 
142416f46bf0SSudarsana Reddy Kalluru 	qede_netif_start(edev);
142516f46bf0SSudarsana Reddy Kalluru 
142616f46bf0SSudarsana Reddy Kalluru 	return rc;
142716f46bf0SSudarsana Reddy Kalluru }
142816f46bf0SSudarsana Reddy Kalluru 
14293044a02eSSudarsana Reddy Kalluru static void qede_self_test(struct net_device *dev,
14303044a02eSSudarsana Reddy Kalluru 			   struct ethtool_test *etest, u64 *buf)
14313044a02eSSudarsana Reddy Kalluru {
14323044a02eSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
14333044a02eSSudarsana Reddy Kalluru 
14343044a02eSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
14353044a02eSSudarsana Reddy Kalluru 		   "Self-test command parameters: offline = %d, external_lb = %d\n",
14363044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_OFFLINE),
14373044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_EXTERNAL_LB) >> 2);
14383044a02eSSudarsana Reddy Kalluru 
14393044a02eSSudarsana Reddy Kalluru 	memset(buf, 0, sizeof(u64) * QEDE_ETHTOOL_TEST_MAX);
14403044a02eSSudarsana Reddy Kalluru 
144116f46bf0SSudarsana Reddy Kalluru 	if (etest->flags & ETH_TEST_FL_OFFLINE) {
144216f46bf0SSudarsana Reddy Kalluru 		if (qede_selftest_run_loopback(edev,
144316f46bf0SSudarsana Reddy Kalluru 					       QED_LINK_LOOPBACK_INT_PHY)) {
144416f46bf0SSudarsana Reddy Kalluru 			buf[QEDE_ETHTOOL_INT_LOOPBACK] = 1;
144516f46bf0SSudarsana Reddy Kalluru 			etest->flags |= ETH_TEST_FL_FAILED;
144616f46bf0SSudarsana Reddy Kalluru 		}
144716f46bf0SSudarsana Reddy Kalluru 	}
144816f46bf0SSudarsana Reddy Kalluru 
14493044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_interrupt(edev->cdev)) {
14503044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_INTERRUPT_TEST] = 1;
14513044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14523044a02eSSudarsana Reddy Kalluru 	}
14533044a02eSSudarsana Reddy Kalluru 
14543044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_memory(edev->cdev)) {
14553044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_MEMORY_TEST] = 1;
14563044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14573044a02eSSudarsana Reddy Kalluru 	}
14583044a02eSSudarsana Reddy Kalluru 
14593044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_register(edev->cdev)) {
14603044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_REGISTER_TEST] = 1;
14613044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14623044a02eSSudarsana Reddy Kalluru 	}
14633044a02eSSudarsana Reddy Kalluru 
14643044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_clock(edev->cdev)) {
14653044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_CLOCK_TEST] = 1;
14663044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14673044a02eSSudarsana Reddy Kalluru 	}
14687a4b21b7SMintz, Yuval 
14697a4b21b7SMintz, Yuval 	if (edev->ops->common->selftest->selftest_nvram(edev->cdev)) {
14707a4b21b7SMintz, Yuval 		buf[QEDE_ETHTOOL_NVRAM_TEST] = 1;
14717a4b21b7SMintz, Yuval 		etest->flags |= ETH_TEST_FL_FAILED;
14727a4b21b7SMintz, Yuval 	}
14733044a02eSSudarsana Reddy Kalluru }
14743044a02eSSudarsana Reddy Kalluru 
14753d789994SManish Chopra static int qede_set_tunable(struct net_device *dev,
14763d789994SManish Chopra 			    const struct ethtool_tunable *tuna,
14773d789994SManish Chopra 			    const void *data)
14783d789994SManish Chopra {
14793d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
14803d789994SManish Chopra 	u32 val;
14813d789994SManish Chopra 
14823d789994SManish Chopra 	switch (tuna->id) {
14833d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
14843d789994SManish Chopra 		val = *(u32 *)data;
14853d789994SManish Chopra 		if (val < QEDE_MIN_PKT_LEN || val > QEDE_RX_HDR_SIZE) {
14863d789994SManish Chopra 			DP_VERBOSE(edev, QED_MSG_DEBUG,
14873d789994SManish Chopra 				   "Invalid rx copy break value, range is [%u, %u]",
14883d789994SManish Chopra 				   QEDE_MIN_PKT_LEN, QEDE_RX_HDR_SIZE);
14893d789994SManish Chopra 			return -EINVAL;
14903d789994SManish Chopra 		}
14913d789994SManish Chopra 
14923d789994SManish Chopra 		edev->rx_copybreak = *(u32 *)data;
14933d789994SManish Chopra 		break;
14943d789994SManish Chopra 	default:
14953d789994SManish Chopra 		return -EOPNOTSUPP;
14963d789994SManish Chopra 	}
14973d789994SManish Chopra 
14983d789994SManish Chopra 	return 0;
14993d789994SManish Chopra }
15003d789994SManish Chopra 
15013d789994SManish Chopra static int qede_get_tunable(struct net_device *dev,
15023d789994SManish Chopra 			    const struct ethtool_tunable *tuna, void *data)
15033d789994SManish Chopra {
15043d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
15053d789994SManish Chopra 
15063d789994SManish Chopra 	switch (tuna->id) {
15073d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
15083d789994SManish Chopra 		*(u32 *)data = edev->rx_copybreak;
15093d789994SManish Chopra 		break;
15103d789994SManish Chopra 	default:
15113d789994SManish Chopra 		return -EOPNOTSUPP;
15123d789994SManish Chopra 	}
15133d789994SManish Chopra 
15143d789994SManish Chopra 	return 0;
15153d789994SManish Chopra }
15163d789994SManish Chopra 
1517133fac0eSSudarsana Kalluru static const struct ethtool_ops qede_ethtool_ops = {
1518054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1519054c67d1SSudarsana Reddy Kalluru 	.set_link_ksettings = qede_set_link_ksettings,
1520133fac0eSSudarsana Kalluru 	.get_drvinfo = qede_get_drvinfo,
1521e0971c83STomer Tayar 	.get_regs_len = qede_get_regs_len,
1522e0971c83STomer Tayar 	.get_regs = qede_get_regs,
152314d39648SMintz, Yuval 	.get_wol = qede_get_wol,
152414d39648SMintz, Yuval 	.set_wol = qede_set_wol,
1525133fac0eSSudarsana Kalluru 	.get_msglevel = qede_get_msglevel,
1526133fac0eSSudarsana Kalluru 	.set_msglevel = qede_set_msglevel,
152732a7a570SSudarsana Kalluru 	.nway_reset = qede_nway_reset,
1528133fac0eSSudarsana Kalluru 	.get_link = qede_get_link,
1529d552fa84SSudarsana Reddy Kalluru 	.get_coalesce = qede_get_coalesce,
1530d552fa84SSudarsana Reddy Kalluru 	.set_coalesce = qede_set_coalesce,
153101ef7e05SSudarsana Kalluru 	.get_ringparam = qede_get_ringparam,
153201ef7e05SSudarsana Kalluru 	.set_ringparam = qede_set_ringparam,
15330f7db144SSudarsana Kalluru 	.get_pauseparam = qede_get_pauseparam,
15340f7db144SSudarsana Kalluru 	.set_pauseparam = qede_set_pauseparam,
1535133fac0eSSudarsana Kalluru 	.get_strings = qede_get_strings,
15363d971cbdSSudarsana Kalluru 	.set_phys_id = qede_set_phys_id,
1537133fac0eSSudarsana Kalluru 	.get_ethtool_stats = qede_get_ethtool_stats,
1538f3e72109SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1539133fac0eSSudarsana Kalluru 	.get_sset_count = qede_get_sset_count,
1540961acdeaSSudarsana Reddy Kalluru 	.get_rxnfc = qede_get_rxnfc,
1541961acdeaSSudarsana Reddy Kalluru 	.set_rxnfc = qede_set_rxnfc,
1542961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1543961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1544961acdeaSSudarsana Reddy Kalluru 	.get_rxfh = qede_get_rxfh,
1545961acdeaSSudarsana Reddy Kalluru 	.set_rxfh = qede_set_rxfh,
15468edf049dSSudarsana Kalluru 	.get_channels = qede_get_channels,
15478edf049dSSudarsana Kalluru 	.set_channels = qede_set_channels,
15483044a02eSSudarsana Reddy Kalluru 	.self_test = qede_self_test,
15493d789994SManish Chopra 	.get_tunable = qede_get_tunable,
15503d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1551133fac0eSSudarsana Kalluru };
1552133fac0eSSudarsana Kalluru 
1553fefb0202SYuval Mintz static const struct ethtool_ops qede_vf_ethtool_ops = {
1554054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1555fefb0202SYuval Mintz 	.get_drvinfo = qede_get_drvinfo,
1556fefb0202SYuval Mintz 	.get_msglevel = qede_get_msglevel,
1557fefb0202SYuval Mintz 	.set_msglevel = qede_set_msglevel,
1558fefb0202SYuval Mintz 	.get_link = qede_get_link,
1559fefb0202SYuval Mintz 	.get_ringparam = qede_get_ringparam,
1560fefb0202SYuval Mintz 	.set_ringparam = qede_set_ringparam,
1561fefb0202SYuval Mintz 	.get_strings = qede_get_strings,
1562fefb0202SYuval Mintz 	.get_ethtool_stats = qede_get_ethtool_stats,
1563fefb0202SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1564fefb0202SYuval Mintz 	.get_sset_count = qede_get_sset_count,
1565fefb0202SYuval Mintz 	.get_rxnfc = qede_get_rxnfc,
1566fefb0202SYuval Mintz 	.set_rxnfc = qede_set_rxnfc,
1567fefb0202SYuval Mintz 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1568fefb0202SYuval Mintz 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1569fefb0202SYuval Mintz 	.get_rxfh = qede_get_rxfh,
1570fefb0202SYuval Mintz 	.set_rxfh = qede_set_rxfh,
1571fefb0202SYuval Mintz 	.get_channels = qede_get_channels,
1572fefb0202SYuval Mintz 	.set_channels = qede_set_channels,
15733d789994SManish Chopra 	.get_tunable = qede_get_tunable,
15743d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1575fefb0202SYuval Mintz };
1576fefb0202SYuval Mintz 
1577133fac0eSSudarsana Kalluru void qede_set_ethtool_ops(struct net_device *dev)
1578133fac0eSSudarsana Kalluru {
1579fefb0202SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
1580fefb0202SYuval Mintz 
1581fefb0202SYuval Mintz 	if (IS_VF(edev))
1582fefb0202SYuval Mintz 		dev->ethtool_ops = &qede_vf_ethtool_ops;
1583fefb0202SYuval Mintz 	else
1584133fac0eSSudarsana Kalluru 		dev->ethtool_ops = &qede_ethtool_ops;
1585133fac0eSSudarsana Kalluru }
1586