1133fac0eSSudarsana Kalluru /* QLogic qede NIC Driver
2e8f1cb50SMintz, Yuval  * Copyright (c) 2015-2017  QLogic Corporation
3133fac0eSSudarsana Kalluru  *
4e8f1cb50SMintz, Yuval  * This software is available to you under a choice of one of two
5e8f1cb50SMintz, Yuval  * licenses.  You may choose to be licensed under the terms of the GNU
6e8f1cb50SMintz, Yuval  * General Public License (GPL) Version 2, available from the file
7e8f1cb50SMintz, Yuval  * COPYING in the main directory of this source tree, or the
8e8f1cb50SMintz, Yuval  * OpenIB.org BSD license below:
9e8f1cb50SMintz, Yuval  *
10e8f1cb50SMintz, Yuval  *     Redistribution and use in source and binary forms, with or
11e8f1cb50SMintz, Yuval  *     without modification, are permitted provided that the following
12e8f1cb50SMintz, Yuval  *     conditions are met:
13e8f1cb50SMintz, Yuval  *
14e8f1cb50SMintz, Yuval  *      - Redistributions of source code must retain the above
15e8f1cb50SMintz, Yuval  *        copyright notice, this list of conditions and the following
16e8f1cb50SMintz, Yuval  *        disclaimer.
17e8f1cb50SMintz, Yuval  *
18e8f1cb50SMintz, Yuval  *      - Redistributions in binary form must reproduce the above
19e8f1cb50SMintz, Yuval  *        copyright notice, this list of conditions and the following
20e8f1cb50SMintz, Yuval  *        disclaimer in the documentation and /or other materials
21e8f1cb50SMintz, Yuval  *        provided with the distribution.
22e8f1cb50SMintz, Yuval  *
23e8f1cb50SMintz, Yuval  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24e8f1cb50SMintz, Yuval  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25e8f1cb50SMintz, Yuval  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26e8f1cb50SMintz, Yuval  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27e8f1cb50SMintz, Yuval  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28e8f1cb50SMintz, Yuval  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29e8f1cb50SMintz, Yuval  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30e8f1cb50SMintz, Yuval  * SOFTWARE.
31133fac0eSSudarsana Kalluru  */
32133fac0eSSudarsana Kalluru #include <linux/version.h>
33133fac0eSSudarsana Kalluru #include <linux/types.h>
34133fac0eSSudarsana Kalluru #include <linux/netdevice.h>
3516f46bf0SSudarsana Reddy Kalluru #include <linux/etherdevice.h>
36133fac0eSSudarsana Kalluru #include <linux/ethtool.h>
37133fac0eSSudarsana Kalluru #include <linux/string.h>
38133fac0eSSudarsana Kalluru #include <linux/pci.h>
39133fac0eSSudarsana Kalluru #include <linux/capability.h>
40f29ffdb6SMintz, Yuval #include <linux/vmalloc.h>
41133fac0eSSudarsana Kalluru #include "qede.h"
424c55215cSSudarsana Reddy Kalluru #include "qede_ptp.h"
43133fac0eSSudarsana Kalluru 
44133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_OFFSET(stat_name) \
45133fac0eSSudarsana Kalluru 	 (offsetof(struct qede_rx_queue, stat_name))
46133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_STRING(stat_name) (#stat_name)
47133fac0eSSudarsana Kalluru #define QEDE_RQSTAT(stat_name) \
48133fac0eSSudarsana Kalluru 	 {QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)}
4916f46bf0SSudarsana Reddy Kalluru 
5016f46bf0SSudarsana Reddy Kalluru #define QEDE_SELFTEST_POLL_COUNT 100
5116f46bf0SSudarsana Reddy Kalluru 
52133fac0eSSudarsana Kalluru static const struct {
53133fac0eSSudarsana Kalluru 	u64 offset;
54133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
55133fac0eSSudarsana Kalluru } qede_rqstats_arr[] = {
5668db9ec2SSudarsana Reddy Kalluru 	QEDE_RQSTAT(rcv_pkts),
57133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_hw_errors),
58133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_alloc_errors),
59c72a6125SManish Chopra 	QEDE_RQSTAT(rx_ip_frags),
60496e0517SMintz, Yuval 	QEDE_RQSTAT(xdp_no_pass),
61133fac0eSSudarsana Kalluru };
62133fac0eSSudarsana Kalluru 
63133fac0eSSudarsana Kalluru #define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr)
6468db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_OFFSET(stat_name) \
6568db9ec2SSudarsana Reddy Kalluru 	(offsetof(struct qede_tx_queue, stat_name))
6668db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_STRING(stat_name) (#stat_name)
6768db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT(stat_name) \
6868db9ec2SSudarsana Reddy Kalluru 	{QEDE_TQSTAT_OFFSET(stat_name), QEDE_TQSTAT_STRING(stat_name)}
6968db9ec2SSudarsana Reddy Kalluru #define QEDE_NUM_TQSTATS ARRAY_SIZE(qede_tqstats_arr)
7068db9ec2SSudarsana Reddy Kalluru static const struct {
7168db9ec2SSudarsana Reddy Kalluru 	u64 offset;
7268db9ec2SSudarsana Reddy Kalluru 	char string[ETH_GSTRING_LEN];
7368db9ec2SSudarsana Reddy Kalluru } qede_tqstats_arr[] = {
7468db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(xmit_pkts),
7568db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(stopped_cnt),
7668db9ec2SSudarsana Reddy Kalluru };
7768db9ec2SSudarsana Reddy Kalluru 
789c79ddaaSMintz, Yuval #define QEDE_STAT_OFFSET(stat_name, type, base) \
799c79ddaaSMintz, Yuval 	(offsetof(type, stat_name) + (base))
804dbcd640SMintz, Yuval #define QEDE_STAT_STRING(stat_name)	(#stat_name)
819c79ddaaSMintz, Yuval #define _QEDE_STAT(stat_name, type, base, attr) \
829c79ddaaSMintz, Yuval 	{QEDE_STAT_OFFSET(stat_name, type, base), \
839c79ddaaSMintz, Yuval 	 QEDE_STAT_STRING(stat_name), \
849c79ddaaSMintz, Yuval 	 attr}
859c79ddaaSMintz, Yuval #define QEDE_STAT(stat_name) \
869c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_common, 0, 0x0)
879c79ddaaSMintz, Yuval #define QEDE_PF_STAT(stat_name) \
889c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_common, 0, \
899c79ddaaSMintz, Yuval 		   BIT(QEDE_STAT_PF_ONLY))
909c79ddaaSMintz, Yuval #define QEDE_PF_BB_STAT(stat_name) \
919c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_bb, \
929c79ddaaSMintz, Yuval 		   offsetof(struct qede_stats, bb), \
939c79ddaaSMintz, Yuval 		   BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_BB_ONLY))
949c79ddaaSMintz, Yuval #define QEDE_PF_AH_STAT(stat_name) \
959c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_ah, \
969c79ddaaSMintz, Yuval 		   offsetof(struct qede_stats, ah), \
979c79ddaaSMintz, Yuval 		   BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_AH_ONLY))
98133fac0eSSudarsana Kalluru static const struct {
99133fac0eSSudarsana Kalluru 	u64 offset;
100133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
1019c79ddaaSMintz, Yuval 	unsigned long attr;
1029c79ddaaSMintz, Yuval #define QEDE_STAT_PF_ONLY	0
1039c79ddaaSMintz, Yuval #define QEDE_STAT_BB_ONLY	1
1049c79ddaaSMintz, Yuval #define QEDE_STAT_AH_ONLY	2
105133fac0eSSudarsana Kalluru } qede_stats_arr[] = {
106133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_bytes),
107133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_bytes),
108133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_bytes),
109133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_pkts),
110133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_pkts),
111133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_pkts),
112133fac0eSSudarsana Kalluru 
113133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_bytes),
114133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_bytes),
115133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_bytes),
116133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_pkts),
117133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_pkts),
118133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_pkts),
119133fac0eSSudarsana Kalluru 
120133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_64_byte_packets),
121d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_65_to_127_byte_packets),
122d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_128_to_255_byte_packets),
123d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_256_to_511_byte_packets),
124d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_512_to_1023_byte_packets),
125d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1024_to_1518_byte_packets),
1269c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_1519_to_1522_byte_packets),
1279c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_1519_to_2047_byte_packets),
1289c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_2048_to_4095_byte_packets),
1299c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_4096_to_9216_byte_packets),
1309c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_9217_to_16383_byte_packets),
1319c79ddaaSMintz, Yuval 	QEDE_PF_AH_STAT(rx_1519_to_max_byte_packets),
132133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_64_byte_packets),
133133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_65_to_127_byte_packets),
134133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_128_to_255_byte_packets),
135133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_256_to_511_byte_packets),
136133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_512_to_1023_byte_packets),
137133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_1024_to_1518_byte_packets),
1389c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_1519_to_2047_byte_packets),
1399c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_2048_to_4095_byte_packets),
1409c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_4096_to_9216_byte_packets),
1419c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_9217_to_16383_byte_packets),
1429c79ddaaSMintz, Yuval 	QEDE_PF_AH_STAT(tx_1519_to_max_byte_packets),
143133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_mac_crtl_frames),
144133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_mac_ctrl_frames),
145133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pause_frames),
146133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pause_frames),
147133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pfc_frames),
148133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pfc_frames),
149133fac0eSSudarsana Kalluru 
150133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_crc_errors),
151133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_align_errors),
152133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_carrier_errors),
153133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_oversize_packets),
154133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_jabbers),
155133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_undersize_packets),
156133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_fragments),
1579c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_lpi_entry_count),
1589c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_total_collisions),
159133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_truncates),
160133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_discards),
161133fac0eSSudarsana Kalluru 	QEDE_STAT(no_buff_discards),
162133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mftag_filter_discards),
163133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mac_filter_discards),
164133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_err_drop_pkts),
1651a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(ttl0_discard),
1661a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(packet_too_big_discard),
167133fac0eSSudarsana Kalluru 
168133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_pkts),
169133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_events),
170133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_aborts_num),
171133fac0eSSudarsana Kalluru 	QEDE_STAT(non_coalesced_pkts),
172133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_bytes),
173133fac0eSSudarsana Kalluru };
174133fac0eSSudarsana Kalluru 
175133fac0eSSudarsana Kalluru #define QEDE_NUM_STATS	ARRAY_SIZE(qede_stats_arr)
1769c79ddaaSMintz, Yuval #define QEDE_STAT_IS_PF_ONLY(i) \
1779c79ddaaSMintz, Yuval 	test_bit(QEDE_STAT_PF_ONLY, &qede_stats_arr[i].attr)
1789c79ddaaSMintz, Yuval #define QEDE_STAT_IS_BB_ONLY(i) \
1799c79ddaaSMintz, Yuval 	test_bit(QEDE_STAT_BB_ONLY, &qede_stats_arr[i].attr)
1809c79ddaaSMintz, Yuval #define QEDE_STAT_IS_AH_ONLY(i) \
1819c79ddaaSMintz, Yuval 	test_bit(QEDE_STAT_AH_ONLY, &qede_stats_arr[i].attr)
182133fac0eSSudarsana Kalluru 
183f3e72109SYuval Mintz enum {
184f3e72109SYuval Mintz 	QEDE_PRI_FLAG_CMT,
185f3e72109SYuval Mintz 	QEDE_PRI_FLAG_LEN,
186f3e72109SYuval Mintz };
187f3e72109SYuval Mintz 
188f3e72109SYuval Mintz static const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = {
189f3e72109SYuval Mintz 	"Coupled-Function",
190f3e72109SYuval Mintz };
191f3e72109SYuval Mintz 
1923044a02eSSudarsana Reddy Kalluru enum qede_ethtool_tests {
19316f46bf0SSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INT_LOOPBACK,
1943044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INTERRUPT_TEST,
1953044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_MEMORY_TEST,
1963044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_REGISTER_TEST,
1973044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_CLOCK_TEST,
1987a4b21b7SMintz, Yuval 	QEDE_ETHTOOL_NVRAM_TEST,
1993044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_TEST_MAX
2003044a02eSSudarsana Reddy Kalluru };
2013044a02eSSudarsana Reddy Kalluru 
2023044a02eSSudarsana Reddy Kalluru static const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = {
20316f46bf0SSudarsana Reddy Kalluru 	"Internal loopback (offline)",
2043044a02eSSudarsana Reddy Kalluru 	"Interrupt (online)\t",
2053044a02eSSudarsana Reddy Kalluru 	"Memory (online)\t\t",
2063044a02eSSudarsana Reddy Kalluru 	"Register (online)\t",
2073044a02eSSudarsana Reddy Kalluru 	"Clock (online)\t\t",
2087a4b21b7SMintz, Yuval 	"Nvram (online)\t\t",
2093044a02eSSudarsana Reddy Kalluru };
2103044a02eSSudarsana Reddy Kalluru 
2114dbcd640SMintz, Yuval static void qede_get_strings_stats_txq(struct qede_dev *edev,
2124dbcd640SMintz, Yuval 				       struct qede_tx_queue *txq, u8 **buf)
2134dbcd640SMintz, Yuval {
2144dbcd640SMintz, Yuval 	int i;
2154dbcd640SMintz, Yuval 
2164dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
217cb6aeb07SMintz, Yuval 		if (txq->is_xdp)
218cb6aeb07SMintz, Yuval 			sprintf(*buf, "%d [XDP]: %s",
219cb6aeb07SMintz, Yuval 				QEDE_TXQ_XDP_TO_IDX(edev, txq),
220cb6aeb07SMintz, Yuval 				qede_tqstats_arr[i].string);
221cb6aeb07SMintz, Yuval 		else
2224dbcd640SMintz, Yuval 			sprintf(*buf, "%d: %s", txq->index,
2234dbcd640SMintz, Yuval 				qede_tqstats_arr[i].string);
2244dbcd640SMintz, Yuval 		*buf += ETH_GSTRING_LEN;
2254dbcd640SMintz, Yuval 	}
2264dbcd640SMintz, Yuval }
2274dbcd640SMintz, Yuval 
2284dbcd640SMintz, Yuval static void qede_get_strings_stats_rxq(struct qede_dev *edev,
2294dbcd640SMintz, Yuval 				       struct qede_rx_queue *rxq, u8 **buf)
2304dbcd640SMintz, Yuval {
2314dbcd640SMintz, Yuval 	int i;
2324dbcd640SMintz, Yuval 
2334dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_RQSTATS; i++) {
2344dbcd640SMintz, Yuval 		sprintf(*buf, "%d: %s", rxq->rxq_id,
2354dbcd640SMintz, Yuval 			qede_rqstats_arr[i].string);
2364dbcd640SMintz, Yuval 		*buf += ETH_GSTRING_LEN;
2374dbcd640SMintz, Yuval 	}
2384dbcd640SMintz, Yuval }
2394dbcd640SMintz, Yuval 
2409c79ddaaSMintz, Yuval static bool qede_is_irrelevant_stat(struct qede_dev *edev, int stat_index)
2419c79ddaaSMintz, Yuval {
2429c79ddaaSMintz, Yuval 	return (IS_VF(edev) && QEDE_STAT_IS_PF_ONLY(stat_index)) ||
2439c79ddaaSMintz, Yuval 	       (QEDE_IS_BB(edev) && QEDE_STAT_IS_AH_ONLY(stat_index)) ||
2449c79ddaaSMintz, Yuval 	       (QEDE_IS_AH(edev) && QEDE_STAT_IS_BB_ONLY(stat_index));
2459c79ddaaSMintz, Yuval }
2469c79ddaaSMintz, Yuval 
247133fac0eSSudarsana Kalluru static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
248133fac0eSSudarsana Kalluru {
2494dbcd640SMintz, Yuval 	struct qede_fastpath *fp;
2504dbcd640SMintz, Yuval 	int i;
251133fac0eSSudarsana Kalluru 
2524dbcd640SMintz, Yuval 	/* Account for queue statistics */
2534dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) {
2544dbcd640SMintz, Yuval 		fp = &edev->fp_array[i];
25568db9ec2SSudarsana Reddy Kalluru 
2564dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_RX)
2574dbcd640SMintz, Yuval 			qede_get_strings_stats_rxq(edev, fp->rxq, &buf);
2584dbcd640SMintz, Yuval 
259cb6aeb07SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_XDP)
260cb6aeb07SMintz, Yuval 			qede_get_strings_stats_txq(edev, fp->xdp_tx, &buf);
261cb6aeb07SMintz, Yuval 
2624dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_TX)
2634dbcd640SMintz, Yuval 			qede_get_strings_stats_txq(edev, fp->txq, &buf);
264cbbf049aSMintz, Yuval 	}
265cbbf049aSMintz, Yuval 
2664dbcd640SMintz, Yuval 	/* Account for non-queue statistics */
2674dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_STATS; i++) {
2689c79ddaaSMintz, Yuval 		if (qede_is_irrelevant_stat(edev, i))
269fefb0202SYuval Mintz 			continue;
2704dbcd640SMintz, Yuval 		strcpy(buf, qede_stats_arr[i].string);
2714dbcd640SMintz, Yuval 		buf += ETH_GSTRING_LEN;
272133fac0eSSudarsana Kalluru 	}
273133fac0eSSudarsana Kalluru }
274133fac0eSSudarsana Kalluru 
275133fac0eSSudarsana Kalluru static void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
276133fac0eSSudarsana Kalluru {
277133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
278133fac0eSSudarsana Kalluru 
279133fac0eSSudarsana Kalluru 	switch (stringset) {
280133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
281133fac0eSSudarsana Kalluru 		qede_get_strings_stats(edev, buf);
282133fac0eSSudarsana Kalluru 		break;
283f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
284f3e72109SYuval Mintz 		memcpy(buf, qede_private_arr,
285f3e72109SYuval Mintz 		       ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN);
286f3e72109SYuval Mintz 		break;
2873044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
2883044a02eSSudarsana Reddy Kalluru 		memcpy(buf, qede_tests_str_arr,
2893044a02eSSudarsana Reddy Kalluru 		       ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX);
2903044a02eSSudarsana Reddy Kalluru 		break;
291133fac0eSSudarsana Kalluru 	default:
292133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
293133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
294133fac0eSSudarsana Kalluru 	}
295133fac0eSSudarsana Kalluru }
296133fac0eSSudarsana Kalluru 
2974dbcd640SMintz, Yuval static void qede_get_ethtool_stats_txq(struct qede_tx_queue *txq, u64 **buf)
2984dbcd640SMintz, Yuval {
2994dbcd640SMintz, Yuval 	int i;
3004dbcd640SMintz, Yuval 
3014dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
3024dbcd640SMintz, Yuval 		**buf = *((u64 *)(((void *)txq) + qede_tqstats_arr[i].offset));
3034dbcd640SMintz, Yuval 		(*buf)++;
3044dbcd640SMintz, Yuval 	}
3054dbcd640SMintz, Yuval }
3064dbcd640SMintz, Yuval 
3074dbcd640SMintz, Yuval static void qede_get_ethtool_stats_rxq(struct qede_rx_queue *rxq, u64 **buf)
3084dbcd640SMintz, Yuval {
3094dbcd640SMintz, Yuval 	int i;
3104dbcd640SMintz, Yuval 
3114dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_RQSTATS; i++) {
3124dbcd640SMintz, Yuval 		**buf = *((u64 *)(((void *)rxq) + qede_rqstats_arr[i].offset));
3134dbcd640SMintz, Yuval 		(*buf)++;
3144dbcd640SMintz, Yuval 	}
3154dbcd640SMintz, Yuval }
3164dbcd640SMintz, Yuval 
317133fac0eSSudarsana Kalluru static void qede_get_ethtool_stats(struct net_device *dev,
318133fac0eSSudarsana Kalluru 				   struct ethtool_stats *stats, u64 *buf)
319133fac0eSSudarsana Kalluru {
320133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
3214dbcd640SMintz, Yuval 	struct qede_fastpath *fp;
3224dbcd640SMintz, Yuval 	int i;
323133fac0eSSudarsana Kalluru 
324133fac0eSSudarsana Kalluru 	qede_fill_by_demand_stats(edev);
325133fac0eSSudarsana Kalluru 
326567b3c12SMintz, Yuval 	/* Need to protect the access to the fastpath array */
327567b3c12SMintz, Yuval 	__qede_lock(edev);
328567b3c12SMintz, Yuval 
3294dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) {
3304dbcd640SMintz, Yuval 		fp = &edev->fp_array[i];
331133fac0eSSudarsana Kalluru 
3324dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_RX)
3334dbcd640SMintz, Yuval 			qede_get_ethtool_stats_rxq(fp->rxq, &buf);
33468db9ec2SSudarsana Reddy Kalluru 
335cb6aeb07SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_XDP)
336cb6aeb07SMintz, Yuval 			qede_get_ethtool_stats_txq(fp->xdp_tx, &buf);
337cb6aeb07SMintz, Yuval 
3384dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_TX)
3394dbcd640SMintz, Yuval 			qede_get_ethtool_stats_txq(fp->txq, &buf);
34068db9ec2SSudarsana Reddy Kalluru 	}
34168db9ec2SSudarsana Reddy Kalluru 
3424dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_STATS; i++) {
3439c79ddaaSMintz, Yuval 		if (qede_is_irrelevant_stat(edev, i))
344fefb0202SYuval Mintz 			continue;
3454dbcd640SMintz, Yuval 		*buf = *((u64 *)(((void *)&edev->stats) +
3464dbcd640SMintz, Yuval 				 qede_stats_arr[i].offset));
3474dbcd640SMintz, Yuval 
3484dbcd640SMintz, Yuval 		buf++;
349fefb0202SYuval Mintz 	}
350133fac0eSSudarsana Kalluru 
351567b3c12SMintz, Yuval 	__qede_unlock(edev);
352133fac0eSSudarsana Kalluru }
353133fac0eSSudarsana Kalluru 
354133fac0eSSudarsana Kalluru static int qede_get_sset_count(struct net_device *dev, int stringset)
355133fac0eSSudarsana Kalluru {
356133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
3579c79ddaaSMintz, Yuval 	int num_stats = QEDE_NUM_STATS, i;
358133fac0eSSudarsana Kalluru 
359133fac0eSSudarsana Kalluru 	switch (stringset) {
360133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
361fefb0202SYuval Mintz 		for (i = 0; i < QEDE_NUM_STATS; i++)
3629c79ddaaSMintz, Yuval 			if (qede_is_irrelevant_stat(edev, i))
363fefb0202SYuval Mintz 				num_stats--;
3644dbcd640SMintz, Yuval 
3654dbcd640SMintz, Yuval 		/* Account for the Regular Tx statistics */
3664dbcd640SMintz, Yuval 		num_stats += QEDE_TSS_COUNT(edev) * QEDE_NUM_TQSTATS;
3674dbcd640SMintz, Yuval 
3684dbcd640SMintz, Yuval 		/* Account for the Regular Rx statistics */
3694dbcd640SMintz, Yuval 		num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS;
3704dbcd640SMintz, Yuval 
371cb6aeb07SMintz, Yuval 		/* Account for XDP statistics [if needed] */
372cb6aeb07SMintz, Yuval 		if (edev->xdp_prog)
373cb6aeb07SMintz, Yuval 			num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_TQSTATS;
3744dbcd640SMintz, Yuval 		return num_stats;
3754dbcd640SMintz, Yuval 
376f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
377f3e72109SYuval Mintz 		return QEDE_PRI_FLAG_LEN;
3783044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
3796ecb0a0cSYuval Mintz 		if (!IS_VF(edev))
3803044a02eSSudarsana Reddy Kalluru 			return QEDE_ETHTOOL_TEST_MAX;
3816ecb0a0cSYuval Mintz 		else
3826ecb0a0cSYuval Mintz 			return 0;
383133fac0eSSudarsana Kalluru 	default:
384133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
385133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
386133fac0eSSudarsana Kalluru 		return -EINVAL;
387133fac0eSSudarsana Kalluru 	}
388133fac0eSSudarsana Kalluru }
389133fac0eSSudarsana Kalluru 
390f3e72109SYuval Mintz static u32 qede_get_priv_flags(struct net_device *dev)
391f3e72109SYuval Mintz {
392f3e72109SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
393f3e72109SYuval Mintz 
394f3e72109SYuval Mintz 	return (!!(edev->dev_info.common.num_hwfns > 1)) << QEDE_PRI_FLAG_CMT;
395f3e72109SYuval Mintz }
396f3e72109SYuval Mintz 
397054c67d1SSudarsana Reddy Kalluru struct qede_link_mode_mapping {
398054c67d1SSudarsana Reddy Kalluru 	u32 qed_link_mode;
399054c67d1SSudarsana Reddy Kalluru 	u32 ethtool_link_mode;
400054c67d1SSudarsana Reddy Kalluru };
401054c67d1SSudarsana Reddy Kalluru 
402054c67d1SSudarsana Reddy Kalluru static const struct qede_link_mode_mapping qed_lm_map[] = {
403054c67d1SSudarsana Reddy Kalluru 	{QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
404054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
405054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT},
406054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
407054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT},
408054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
409054c67d1SSudarsana Reddy Kalluru 	{QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
410054c67d1SSudarsana Reddy Kalluru 	{QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
411054c67d1SSudarsana Reddy Kalluru 	{QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
412054c67d1SSudarsana Reddy Kalluru 	{QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT},
413054c67d1SSudarsana Reddy Kalluru 	{QED_LM_100000baseKR4_Full_BIT,
414054c67d1SSudarsana Reddy Kalluru 	 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
415054c67d1SSudarsana Reddy Kalluru };
416054c67d1SSudarsana Reddy Kalluru 
417054c67d1SSudarsana Reddy Kalluru #define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name)	\
418054c67d1SSudarsana Reddy Kalluru {								\
419054c67d1SSudarsana Reddy Kalluru 	int i;							\
420054c67d1SSudarsana Reddy Kalluru 								\
421d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
422054c67d1SSudarsana Reddy Kalluru 		if ((caps) & (qed_lm_map[i].qed_link_mode))	\
423054c67d1SSudarsana Reddy Kalluru 			__set_bit(qed_lm_map[i].ethtool_link_mode,\
424054c67d1SSudarsana Reddy Kalluru 				  lk_ksettings->link_modes.name); \
425054c67d1SSudarsana Reddy Kalluru 	}							\
426054c67d1SSudarsana Reddy Kalluru }
427054c67d1SSudarsana Reddy Kalluru 
428054c67d1SSudarsana Reddy Kalluru #define QEDE_ETHTOOL_TO_DRV_CAPS(caps, lk_ksettings, name)	\
429054c67d1SSudarsana Reddy Kalluru {								\
430054c67d1SSudarsana Reddy Kalluru 	int i;							\
431054c67d1SSudarsana Reddy Kalluru 								\
432d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
433054c67d1SSudarsana Reddy Kalluru 		if (test_bit(qed_lm_map[i].ethtool_link_mode,	\
434054c67d1SSudarsana Reddy Kalluru 			     lk_ksettings->link_modes.name))	\
435054c67d1SSudarsana Reddy Kalluru 			caps |= qed_lm_map[i].qed_link_mode;	\
436054c67d1SSudarsana Reddy Kalluru 	}							\
437054c67d1SSudarsana Reddy Kalluru }
438054c67d1SSudarsana Reddy Kalluru 
439054c67d1SSudarsana Reddy Kalluru static int qede_get_link_ksettings(struct net_device *dev,
440054c67d1SSudarsana Reddy Kalluru 				   struct ethtool_link_ksettings *cmd)
441133fac0eSSudarsana Kalluru {
442054c67d1SSudarsana Reddy Kalluru 	struct ethtool_link_settings *base = &cmd->base;
443133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
444133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
445133fac0eSSudarsana Kalluru 
446567b3c12SMintz, Yuval 	__qede_lock(edev);
447567b3c12SMintz, Yuval 
448133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
449133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
450133fac0eSSudarsana Kalluru 
451054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
452054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.supported_caps, cmd, supported)
453054c67d1SSudarsana Reddy Kalluru 
454054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
455054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.advertised_caps, cmd, advertising)
456054c67d1SSudarsana Reddy Kalluru 
457054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
458054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.lp_caps, cmd, lp_advertising)
459054c67d1SSudarsana Reddy Kalluru 
460133fac0eSSudarsana Kalluru 	if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) {
461054c67d1SSudarsana Reddy Kalluru 		base->speed = current_link.speed;
462054c67d1SSudarsana Reddy Kalluru 		base->duplex = current_link.duplex;
463133fac0eSSudarsana Kalluru 	} else {
464054c67d1SSudarsana Reddy Kalluru 		base->speed = SPEED_UNKNOWN;
465054c67d1SSudarsana Reddy Kalluru 		base->duplex = DUPLEX_UNKNOWN;
466133fac0eSSudarsana Kalluru 	}
467567b3c12SMintz, Yuval 
468567b3c12SMintz, Yuval 	__qede_unlock(edev);
469567b3c12SMintz, Yuval 
470054c67d1SSudarsana Reddy Kalluru 	base->port = current_link.port;
471054c67d1SSudarsana Reddy Kalluru 	base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE :
472133fac0eSSudarsana Kalluru 			AUTONEG_DISABLE;
473133fac0eSSudarsana Kalluru 
474133fac0eSSudarsana Kalluru 	return 0;
475133fac0eSSudarsana Kalluru }
476133fac0eSSudarsana Kalluru 
477054c67d1SSudarsana Reddy Kalluru static int qede_set_link_ksettings(struct net_device *dev,
478054c67d1SSudarsana Reddy Kalluru 				   const struct ethtool_link_ksettings *cmd)
479133fac0eSSudarsana Kalluru {
480054c67d1SSudarsana Reddy Kalluru 	const struct ethtool_link_settings *base = &cmd->base;
481133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
482133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
483133fac0eSSudarsana Kalluru 	struct qed_link_params params;
484133fac0eSSudarsana Kalluru 
485fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
486054c67d1SSudarsana Reddy Kalluru 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
487133fac0eSSudarsana Kalluru 		return -EOPNOTSUPP;
488133fac0eSSudarsana Kalluru 	}
489133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
490133fac0eSSudarsana Kalluru 	memset(&params, 0, sizeof(params));
491133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
492133fac0eSSudarsana Kalluru 
493133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS;
494133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG;
495054c67d1SSudarsana Reddy Kalluru 	if (base->autoneg == AUTONEG_ENABLE) {
496161adb04Ssudarsana.kalluru@cavium.com 		if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
497161adb04Ssudarsana.kalluru@cavium.com 			DP_INFO(edev, "Auto negotiation is not supported\n");
498161adb04Ssudarsana.kalluru@cavium.com 			return -EOPNOTSUPP;
499161adb04Ssudarsana.kalluru@cavium.com 		}
500161adb04Ssudarsana.kalluru@cavium.com 
501133fac0eSSudarsana Kalluru 		params.autoneg = true;
502133fac0eSSudarsana Kalluru 		params.forced_speed = 0;
503054c67d1SSudarsana Reddy Kalluru 		QEDE_ETHTOOL_TO_DRV_CAPS(params.adv_speeds, cmd, advertising)
504133fac0eSSudarsana Kalluru 	} else {		/* forced speed */
505133fac0eSSudarsana Kalluru 		params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED;
506133fac0eSSudarsana Kalluru 		params.autoneg = false;
507054c67d1SSudarsana Reddy Kalluru 		params.forced_speed = base->speed;
508054c67d1SSudarsana Reddy Kalluru 		switch (base->speed) {
5099ac4c546SSudarsana Reddy Kalluru 		case SPEED_1000:
5109ac4c546SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
5119ac4c546SSudarsana Reddy Kalluru 			      QED_LM_1000baseT_Full_BIT)) {
5129ac4c546SSudarsana Reddy Kalluru 				DP_INFO(edev, "1G speed not supported\n");
5139ac4c546SSudarsana Reddy Kalluru 				return -EINVAL;
5149ac4c546SSudarsana Reddy Kalluru 			}
5159ac4c546SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_1000baseT_Full_BIT;
5169ac4c546SSudarsana Reddy Kalluru 			break;
517133fac0eSSudarsana Kalluru 		case SPEED_10000:
518133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
519054c67d1SSudarsana Reddy Kalluru 			      QED_LM_10000baseKR_Full_BIT)) {
520133fac0eSSudarsana Kalluru 				DP_INFO(edev, "10G speed not supported\n");
521133fac0eSSudarsana Kalluru 				return -EINVAL;
522133fac0eSSudarsana Kalluru 			}
523054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_10000baseKR_Full_BIT;
524054c67d1SSudarsana Reddy Kalluru 			break;
525054c67d1SSudarsana Reddy Kalluru 		case SPEED_25000:
526054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
527054c67d1SSudarsana Reddy Kalluru 			      QED_LM_25000baseKR_Full_BIT)) {
528054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "25G speed not supported\n");
529054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
530054c67d1SSudarsana Reddy Kalluru 			}
531054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_25000baseKR_Full_BIT;
532133fac0eSSudarsana Kalluru 			break;
533133fac0eSSudarsana Kalluru 		case SPEED_40000:
534133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
535054c67d1SSudarsana Reddy Kalluru 			      QED_LM_40000baseLR4_Full_BIT)) {
536133fac0eSSudarsana Kalluru 				DP_INFO(edev, "40G speed not supported\n");
537133fac0eSSudarsana Kalluru 				return -EINVAL;
538133fac0eSSudarsana Kalluru 			}
539054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_40000baseLR4_Full_BIT;
540054c67d1SSudarsana Reddy Kalluru 			break;
54116d5946aSYuval Mintz 		case SPEED_50000:
542054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
543054c67d1SSudarsana Reddy Kalluru 			      QED_LM_50000baseKR2_Full_BIT)) {
544054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "50G speed not supported\n");
545054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
546054c67d1SSudarsana Reddy Kalluru 			}
547054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_50000baseKR2_Full_BIT;
548054c67d1SSudarsana Reddy Kalluru 			break;
54916d5946aSYuval Mintz 		case SPEED_100000:
550054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
551054c67d1SSudarsana Reddy Kalluru 			      QED_LM_100000baseKR4_Full_BIT)) {
552054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "100G speed not supported\n");
553054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
554054c67d1SSudarsana Reddy Kalluru 			}
555054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_100000baseKR4_Full_BIT;
556133fac0eSSudarsana Kalluru 			break;
557133fac0eSSudarsana Kalluru 		default:
558054c67d1SSudarsana Reddy Kalluru 			DP_INFO(edev, "Unsupported speed %u\n", base->speed);
559133fac0eSSudarsana Kalluru 			return -EINVAL;
560133fac0eSSudarsana Kalluru 		}
561133fac0eSSudarsana Kalluru 	}
562133fac0eSSudarsana Kalluru 
563133fac0eSSudarsana Kalluru 	params.link_up = true;
564133fac0eSSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
565133fac0eSSudarsana Kalluru 
566133fac0eSSudarsana Kalluru 	return 0;
567133fac0eSSudarsana Kalluru }
568133fac0eSSudarsana Kalluru 
569133fac0eSSudarsana Kalluru static void qede_get_drvinfo(struct net_device *ndev,
570133fac0eSSudarsana Kalluru 			     struct ethtool_drvinfo *info)
571133fac0eSSudarsana Kalluru {
572133fac0eSSudarsana Kalluru 	char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN];
573133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
574133fac0eSSudarsana Kalluru 
575133fac0eSSudarsana Kalluru 	strlcpy(info->driver, "qede", sizeof(info->driver));
576133fac0eSSudarsana Kalluru 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
577133fac0eSSudarsana Kalluru 
578133fac0eSSudarsana Kalluru 	snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
579133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_major,
580133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_minor,
581133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_rev,
582133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_eng);
583133fac0eSSudarsana Kalluru 
584133fac0eSSudarsana Kalluru 	snprintf(mfw, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
585133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 24) & 0xFF,
586133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 16) & 0xFF,
587133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 8) & 0xFF,
588133fac0eSSudarsana Kalluru 		 edev->dev_info.common.mfw_rev & 0xFF);
589133fac0eSSudarsana Kalluru 
590133fac0eSSudarsana Kalluru 	if ((strlen(storm) + strlen(mfw) + strlen("mfw storm  ")) <
591133fac0eSSudarsana Kalluru 	    sizeof(info->fw_version)) {
592133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
593133fac0eSSudarsana Kalluru 			 "mfw %s storm %s", mfw, storm);
594133fac0eSSudarsana Kalluru 	} else {
595133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
596133fac0eSSudarsana Kalluru 			 "%s %s", mfw, storm);
597133fac0eSSudarsana Kalluru 	}
598133fac0eSSudarsana Kalluru 
599133fac0eSSudarsana Kalluru 	strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info));
600133fac0eSSudarsana Kalluru }
601133fac0eSSudarsana Kalluru 
60214d39648SMintz, Yuval static void qede_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
60314d39648SMintz, Yuval {
60414d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
60514d39648SMintz, Yuval 
60614d39648SMintz, Yuval 	if (edev->dev_info.common.wol_support) {
60714d39648SMintz, Yuval 		wol->supported = WAKE_MAGIC;
60814d39648SMintz, Yuval 		wol->wolopts = edev->wol_enabled ? WAKE_MAGIC : 0;
60914d39648SMintz, Yuval 	}
61014d39648SMintz, Yuval }
61114d39648SMintz, Yuval 
61214d39648SMintz, Yuval static int qede_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
61314d39648SMintz, Yuval {
61414d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
61514d39648SMintz, Yuval 	bool wol_requested;
61614d39648SMintz, Yuval 	int rc;
61714d39648SMintz, Yuval 
61814d39648SMintz, Yuval 	if (wol->wolopts & ~WAKE_MAGIC) {
61914d39648SMintz, Yuval 		DP_INFO(edev,
62014d39648SMintz, Yuval 			"Can't support WoL options other than magic-packet\n");
62114d39648SMintz, Yuval 		return -EINVAL;
62214d39648SMintz, Yuval 	}
62314d39648SMintz, Yuval 
62414d39648SMintz, Yuval 	wol_requested = !!(wol->wolopts & WAKE_MAGIC);
62514d39648SMintz, Yuval 	if (wol_requested == edev->wol_enabled)
62614d39648SMintz, Yuval 		return 0;
62714d39648SMintz, Yuval 
62814d39648SMintz, Yuval 	/* Need to actually change configuration */
62914d39648SMintz, Yuval 	if (!edev->dev_info.common.wol_support) {
63014d39648SMintz, Yuval 		DP_INFO(edev, "Device doesn't support WoL\n");
63114d39648SMintz, Yuval 		return -EINVAL;
63214d39648SMintz, Yuval 	}
63314d39648SMintz, Yuval 
63414d39648SMintz, Yuval 	rc = edev->ops->common->update_wol(edev->cdev, wol_requested);
63514d39648SMintz, Yuval 	if (!rc)
63614d39648SMintz, Yuval 		edev->wol_enabled = wol_requested;
63714d39648SMintz, Yuval 
63814d39648SMintz, Yuval 	return rc;
63914d39648SMintz, Yuval }
64014d39648SMintz, Yuval 
641133fac0eSSudarsana Kalluru static u32 qede_get_msglevel(struct net_device *ndev)
642133fac0eSSudarsana Kalluru {
643133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
644133fac0eSSudarsana Kalluru 
6451a635e48SYuval Mintz 	return ((u32)edev->dp_level << QED_LOG_LEVEL_SHIFT) | edev->dp_module;
646133fac0eSSudarsana Kalluru }
647133fac0eSSudarsana Kalluru 
648133fac0eSSudarsana Kalluru static void qede_set_msglevel(struct net_device *ndev, u32 level)
649133fac0eSSudarsana Kalluru {
650133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
651133fac0eSSudarsana Kalluru 	u32 dp_module = 0;
652133fac0eSSudarsana Kalluru 	u8 dp_level = 0;
653133fac0eSSudarsana Kalluru 
654133fac0eSSudarsana Kalluru 	qede_config_debug(level, &dp_module, &dp_level);
655133fac0eSSudarsana Kalluru 
656133fac0eSSudarsana Kalluru 	edev->dp_level = dp_level;
657133fac0eSSudarsana Kalluru 	edev->dp_module = dp_module;
658133fac0eSSudarsana Kalluru 	edev->ops->common->update_msglvl(edev->cdev,
659133fac0eSSudarsana Kalluru 					 dp_module, dp_level);
660133fac0eSSudarsana Kalluru }
661133fac0eSSudarsana Kalluru 
66232a7a570SSudarsana Kalluru static int qede_nway_reset(struct net_device *dev)
66332a7a570SSudarsana Kalluru {
66432a7a570SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
66532a7a570SSudarsana Kalluru 	struct qed_link_output current_link;
66632a7a570SSudarsana Kalluru 	struct qed_link_params link_params;
66732a7a570SSudarsana Kalluru 
668fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
6691a635e48SYuval Mintz 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
670fe7cd2bfSYuval Mintz 		return -EOPNOTSUPP;
671fe7cd2bfSYuval Mintz 	}
672fe7cd2bfSYuval Mintz 
67332a7a570SSudarsana Kalluru 	if (!netif_running(dev))
67432a7a570SSudarsana Kalluru 		return 0;
67532a7a570SSudarsana Kalluru 
67632a7a570SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
67732a7a570SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
67832a7a570SSudarsana Kalluru 	if (!current_link.link_up)
67932a7a570SSudarsana Kalluru 		return 0;
68032a7a570SSudarsana Kalluru 
68132a7a570SSudarsana Kalluru 	/* Toggle the link */
68232a7a570SSudarsana Kalluru 	memset(&link_params, 0, sizeof(link_params));
68332a7a570SSudarsana Kalluru 	link_params.link_up = false;
68432a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
68532a7a570SSudarsana Kalluru 	link_params.link_up = true;
68632a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
68732a7a570SSudarsana Kalluru 
68832a7a570SSudarsana Kalluru 	return 0;
68932a7a570SSudarsana Kalluru }
69032a7a570SSudarsana Kalluru 
691133fac0eSSudarsana Kalluru static u32 qede_get_link(struct net_device *dev)
692133fac0eSSudarsana Kalluru {
693133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
694133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
695133fac0eSSudarsana Kalluru 
696133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
697133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
698133fac0eSSudarsana Kalluru 
699133fac0eSSudarsana Kalluru 	return current_link.link_up;
700133fac0eSSudarsana Kalluru }
701133fac0eSSudarsana Kalluru 
702d552fa84SSudarsana Reddy Kalluru static int qede_get_coalesce(struct net_device *dev,
703d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
704d552fa84SSudarsana Reddy Kalluru {
705d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
706d2890deaSSudarsana Reddy Kalluru 	u16 rxc, txc;
707d552fa84SSudarsana Reddy Kalluru 
708d552fa84SSudarsana Reddy Kalluru 	memset(coal, 0, sizeof(struct ethtool_coalesce));
709d2890deaSSudarsana Reddy Kalluru 	edev->ops->common->get_coalesce(edev->cdev, &rxc, &txc);
710d2890deaSSudarsana Reddy Kalluru 
711d2890deaSSudarsana Reddy Kalluru 	coal->rx_coalesce_usecs = rxc;
712d2890deaSSudarsana Reddy Kalluru 	coal->tx_coalesce_usecs = txc;
713d552fa84SSudarsana Reddy Kalluru 
714d552fa84SSudarsana Reddy Kalluru 	return 0;
715d552fa84SSudarsana Reddy Kalluru }
716d552fa84SSudarsana Reddy Kalluru 
717d552fa84SSudarsana Reddy Kalluru static int qede_set_coalesce(struct net_device *dev,
718d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
719d552fa84SSudarsana Reddy Kalluru {
720d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
721d552fa84SSudarsana Reddy Kalluru 	int i, rc = 0;
722f870a3c6Ssudarsana.kalluru@cavium.com 	u16 rxc, txc, sb_id;
723d552fa84SSudarsana Reddy Kalluru 
724d552fa84SSudarsana Reddy Kalluru 	if (!netif_running(dev)) {
725d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev, "Interface is down\n");
726d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
727d552fa84SSudarsana Reddy Kalluru 	}
728d552fa84SSudarsana Reddy Kalluru 
729d552fa84SSudarsana Reddy Kalluru 	if (coal->rx_coalesce_usecs > QED_COALESCE_MAX ||
730d552fa84SSudarsana Reddy Kalluru 	    coal->tx_coalesce_usecs > QED_COALESCE_MAX) {
731d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev,
732d552fa84SSudarsana Reddy Kalluru 			"Can't support requested %s coalesce value [max supported value %d]\n",
733d552fa84SSudarsana Reddy Kalluru 			coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx"
734d552fa84SSudarsana Reddy Kalluru 								   : "tx",
735d552fa84SSudarsana Reddy Kalluru 			QED_COALESCE_MAX);
736d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
737d552fa84SSudarsana Reddy Kalluru 	}
738d552fa84SSudarsana Reddy Kalluru 
739d552fa84SSudarsana Reddy Kalluru 	rxc = (u16)coal->rx_coalesce_usecs;
740d552fa84SSudarsana Reddy Kalluru 	txc = (u16)coal->tx_coalesce_usecs;
7419a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
742d552fa84SSudarsana Reddy Kalluru 		sb_id = edev->fp_array[i].sb_info->igu_sb_id;
743d552fa84SSudarsana Reddy Kalluru 		rc = edev->ops->common->set_coalesce(edev->cdev, rxc, txc,
744f870a3c6Ssudarsana.kalluru@cavium.com 						     (u16)i, sb_id);
745d552fa84SSudarsana Reddy Kalluru 		if (rc) {
746d552fa84SSudarsana Reddy Kalluru 			DP_INFO(edev, "Set coalesce error, rc = %d\n", rc);
747d552fa84SSudarsana Reddy Kalluru 			return rc;
748d552fa84SSudarsana Reddy Kalluru 		}
749d552fa84SSudarsana Reddy Kalluru 	}
750d552fa84SSudarsana Reddy Kalluru 
751d552fa84SSudarsana Reddy Kalluru 	return rc;
752d552fa84SSudarsana Reddy Kalluru }
753d552fa84SSudarsana Reddy Kalluru 
75401ef7e05SSudarsana Kalluru static void qede_get_ringparam(struct net_device *dev,
75501ef7e05SSudarsana Kalluru 			       struct ethtool_ringparam *ering)
75601ef7e05SSudarsana Kalluru {
75701ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
75801ef7e05SSudarsana Kalluru 
75901ef7e05SSudarsana Kalluru 	ering->rx_max_pending = NUM_RX_BDS_MAX;
76001ef7e05SSudarsana Kalluru 	ering->rx_pending = edev->q_num_rx_buffers;
76101ef7e05SSudarsana Kalluru 	ering->tx_max_pending = NUM_TX_BDS_MAX;
76201ef7e05SSudarsana Kalluru 	ering->tx_pending = edev->q_num_tx_buffers;
76301ef7e05SSudarsana Kalluru }
76401ef7e05SSudarsana Kalluru 
76501ef7e05SSudarsana Kalluru static int qede_set_ringparam(struct net_device *dev,
76601ef7e05SSudarsana Kalluru 			      struct ethtool_ringparam *ering)
76701ef7e05SSudarsana Kalluru {
76801ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
76901ef7e05SSudarsana Kalluru 
77001ef7e05SSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
77101ef7e05SSudarsana Kalluru 		   "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
77201ef7e05SSudarsana Kalluru 		   ering->rx_pending, ering->tx_pending);
77301ef7e05SSudarsana Kalluru 
77401ef7e05SSudarsana Kalluru 	/* Validate legality of configuration */
77501ef7e05SSudarsana Kalluru 	if (ering->rx_pending > NUM_RX_BDS_MAX ||
77601ef7e05SSudarsana Kalluru 	    ering->rx_pending < NUM_RX_BDS_MIN ||
77701ef7e05SSudarsana Kalluru 	    ering->tx_pending > NUM_TX_BDS_MAX ||
77801ef7e05SSudarsana Kalluru 	    ering->tx_pending < NUM_TX_BDS_MIN) {
77901ef7e05SSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
78001ef7e05SSudarsana Kalluru 			   "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n",
78101ef7e05SSudarsana Kalluru 			   NUM_RX_BDS_MIN, NUM_RX_BDS_MAX,
78201ef7e05SSudarsana Kalluru 			   NUM_TX_BDS_MIN, NUM_TX_BDS_MAX);
78301ef7e05SSudarsana Kalluru 		return -EINVAL;
78401ef7e05SSudarsana Kalluru 	}
78501ef7e05SSudarsana Kalluru 
78601ef7e05SSudarsana Kalluru 	/* Change ring size and re-load */
78701ef7e05SSudarsana Kalluru 	edev->q_num_rx_buffers = ering->rx_pending;
78801ef7e05SSudarsana Kalluru 	edev->q_num_tx_buffers = ering->tx_pending;
78901ef7e05SSudarsana Kalluru 
790567b3c12SMintz, Yuval 	qede_reload(edev, NULL, false);
79101ef7e05SSudarsana Kalluru 
79201ef7e05SSudarsana Kalluru 	return 0;
79301ef7e05SSudarsana Kalluru }
79401ef7e05SSudarsana Kalluru 
7950f7db144SSudarsana Kalluru static void qede_get_pauseparam(struct net_device *dev,
7960f7db144SSudarsana Kalluru 				struct ethtool_pauseparam *epause)
7970f7db144SSudarsana Kalluru {
7980f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
7990f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
8000f7db144SSudarsana Kalluru 
8010f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
8020f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
8030f7db144SSudarsana Kalluru 
8040f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE)
8050f7db144SSudarsana Kalluru 		epause->autoneg = true;
8060f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE)
8070f7db144SSudarsana Kalluru 		epause->rx_pause = true;
8080f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE)
8090f7db144SSudarsana Kalluru 		epause->tx_pause = true;
8100f7db144SSudarsana Kalluru 
8110f7db144SSudarsana Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
8120f7db144SSudarsana Kalluru 		   "ethtool_pauseparam: cmd %d  autoneg %d  rx_pause %d  tx_pause %d\n",
8130f7db144SSudarsana Kalluru 		   epause->cmd, epause->autoneg, epause->rx_pause,
8140f7db144SSudarsana Kalluru 		   epause->tx_pause);
8150f7db144SSudarsana Kalluru }
8160f7db144SSudarsana Kalluru 
8170f7db144SSudarsana Kalluru static int qede_set_pauseparam(struct net_device *dev,
8180f7db144SSudarsana Kalluru 			       struct ethtool_pauseparam *epause)
8190f7db144SSudarsana Kalluru {
8200f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
8210f7db144SSudarsana Kalluru 	struct qed_link_params params;
8220f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
8230f7db144SSudarsana Kalluru 
824fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
8250f7db144SSudarsana Kalluru 		DP_INFO(edev,
826fe7cd2bfSYuval Mintz 			"Pause settings are not allowed to be changed\n");
8270f7db144SSudarsana Kalluru 		return -EOPNOTSUPP;
8280f7db144SSudarsana Kalluru 	}
8290f7db144SSudarsana Kalluru 
8300f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
8310f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
8320f7db144SSudarsana Kalluru 
8330f7db144SSudarsana Kalluru 	memset(&params, 0, sizeof(params));
8340f7db144SSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG;
8350f7db144SSudarsana Kalluru 	if (epause->autoneg) {
836d194fd26SYuval Mintz 		if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
8370f7db144SSudarsana Kalluru 			DP_INFO(edev, "autoneg not supported\n");
8380f7db144SSudarsana Kalluru 			return -EINVAL;
8390f7db144SSudarsana Kalluru 		}
8400f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE;
8410f7db144SSudarsana Kalluru 	}
8420f7db144SSudarsana Kalluru 	if (epause->rx_pause)
8430f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_RX_ENABLE;
8440f7db144SSudarsana Kalluru 	if (epause->tx_pause)
8450f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_TX_ENABLE;
8460f7db144SSudarsana Kalluru 
8470f7db144SSudarsana Kalluru 	params.link_up = true;
8480f7db144SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
8490f7db144SSudarsana Kalluru 
8500f7db144SSudarsana Kalluru 	return 0;
8510f7db144SSudarsana Kalluru }
8520f7db144SSudarsana Kalluru 
853e0971c83STomer Tayar static void qede_get_regs(struct net_device *ndev,
854e0971c83STomer Tayar 			  struct ethtool_regs *regs, void *buffer)
855e0971c83STomer Tayar {
856e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
857e0971c83STomer Tayar 
858e0971c83STomer Tayar 	regs->version = 0;
859e0971c83STomer Tayar 	memset(buffer, 0, regs->len);
860e0971c83STomer Tayar 
861e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
862e0971c83STomer Tayar 		edev->ops->common->dbg_all_data(edev->cdev, buffer);
863e0971c83STomer Tayar }
864e0971c83STomer Tayar 
865e0971c83STomer Tayar static int qede_get_regs_len(struct net_device *ndev)
866e0971c83STomer Tayar {
867e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
868e0971c83STomer Tayar 
869e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
870e0971c83STomer Tayar 		return edev->ops->common->dbg_all_data_size(edev->cdev);
871e0971c83STomer Tayar 	else
872e0971c83STomer Tayar 		return -EINVAL;
873e0971c83STomer Tayar }
874e0971c83STomer Tayar 
875567b3c12SMintz, Yuval static void qede_update_mtu(struct qede_dev *edev,
876567b3c12SMintz, Yuval 			    struct qede_reload_args *args)
877133fac0eSSudarsana Kalluru {
878567b3c12SMintz, Yuval 	edev->ndev->mtu = args->u.mtu;
879133fac0eSSudarsana Kalluru }
880133fac0eSSudarsana Kalluru 
881133fac0eSSudarsana Kalluru /* Netdevice NDOs */
882133fac0eSSudarsana Kalluru int qede_change_mtu(struct net_device *ndev, int new_mtu)
883133fac0eSSudarsana Kalluru {
884133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
885567b3c12SMintz, Yuval 	struct qede_reload_args args;
886133fac0eSSudarsana Kalluru 
887133fac0eSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
888133fac0eSSudarsana Kalluru 		   "Configuring MTU size of %d\n", new_mtu);
889133fac0eSSudarsana Kalluru 
890133fac0eSSudarsana Kalluru 	/* Set the mtu field and re-start the interface if needed */
891567b3c12SMintz, Yuval 	args.u.mtu = new_mtu;
892567b3c12SMintz, Yuval 	args.func = &qede_update_mtu;
893567b3c12SMintz, Yuval 	qede_reload(edev, &args, false);
894133fac0eSSudarsana Kalluru 
895567b3c12SMintz, Yuval 	edev->ops->common->update_mtu(edev->cdev, new_mtu);
8960fefbfbaSSudarsana Kalluru 
897133fac0eSSudarsana Kalluru 	return 0;
898133fac0eSSudarsana Kalluru }
899133fac0eSSudarsana Kalluru 
9008edf049dSSudarsana Kalluru static void qede_get_channels(struct net_device *dev,
9018edf049dSSudarsana Kalluru 			      struct ethtool_channels *channels)
9028edf049dSSudarsana Kalluru {
9038edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
9048edf049dSSudarsana Kalluru 
9058edf049dSSudarsana Kalluru 	channels->max_combined = QEDE_MAX_RSS_CNT(edev);
906bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_rx = QEDE_MAX_RSS_CNT(edev);
907bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_tx = QEDE_MAX_RSS_CNT(edev);
9089a4d7e86SSudarsana Reddy Kalluru 	channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx -
9099a4d7e86SSudarsana Reddy Kalluru 					edev->fp_num_rx;
9109a4d7e86SSudarsana Reddy Kalluru 	channels->tx_count = edev->fp_num_tx;
9119a4d7e86SSudarsana Reddy Kalluru 	channels->rx_count = edev->fp_num_rx;
9128edf049dSSudarsana Kalluru }
9138edf049dSSudarsana Kalluru 
9148edf049dSSudarsana Kalluru static int qede_set_channels(struct net_device *dev,
9158edf049dSSudarsana Kalluru 			     struct ethtool_channels *channels)
9168edf049dSSudarsana Kalluru {
9178edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
9189a4d7e86SSudarsana Reddy Kalluru 	u32 count;
9198edf049dSSudarsana Kalluru 
9208edf049dSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
9218edf049dSSudarsana Kalluru 		   "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n",
9228edf049dSSudarsana Kalluru 		   channels->rx_count, channels->tx_count,
9238edf049dSSudarsana Kalluru 		   channels->other_count, channels->combined_count);
9248edf049dSSudarsana Kalluru 
9259a4d7e86SSudarsana Reddy Kalluru 	count = channels->rx_count + channels->tx_count +
9269a4d7e86SSudarsana Reddy Kalluru 			channels->combined_count;
9279a4d7e86SSudarsana Reddy Kalluru 
9289a4d7e86SSudarsana Reddy Kalluru 	/* We don't support `other' channels */
9299a4d7e86SSudarsana Reddy Kalluru 	if (channels->other_count) {
9308edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
9318edf049dSSudarsana Kalluru 			   "command parameters not supported\n");
9328edf049dSSudarsana Kalluru 		return -EINVAL;
9338edf049dSSudarsana Kalluru 	}
9348edf049dSSudarsana Kalluru 
9359a4d7e86SSudarsana Reddy Kalluru 	if (!(channels->combined_count || (channels->rx_count &&
9369a4d7e86SSudarsana Reddy Kalluru 					   channels->tx_count))) {
9379a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
9389a4d7e86SSudarsana Reddy Kalluru 			   "need to request at least one transmit and one receive channel\n");
9399a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
9409a4d7e86SSudarsana Reddy Kalluru 	}
9419a4d7e86SSudarsana Reddy Kalluru 
9429a4d7e86SSudarsana Reddy Kalluru 	if (count > QEDE_MAX_RSS_CNT(edev)) {
9439a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
9449a4d7e86SSudarsana Reddy Kalluru 			   "requested channels = %d max supported channels = %d\n",
9459a4d7e86SSudarsana Reddy Kalluru 			   count, QEDE_MAX_RSS_CNT(edev));
9469a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
9479a4d7e86SSudarsana Reddy Kalluru 	}
9489a4d7e86SSudarsana Reddy Kalluru 
9498edf049dSSudarsana Kalluru 	/* Check if there was a change in the active parameters */
9509a4d7e86SSudarsana Reddy Kalluru 	if ((count == QEDE_QUEUE_CNT(edev)) &&
9519a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count == edev->fp_num_tx) &&
9529a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count == edev->fp_num_rx)) {
9538edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
9548edf049dSSudarsana Kalluru 			   "No change in active parameters\n");
9558edf049dSSudarsana Kalluru 		return 0;
9568edf049dSSudarsana Kalluru 	}
9578edf049dSSudarsana Kalluru 
9588edf049dSSudarsana Kalluru 	/* We need the number of queues to be divisible between the hwfns */
9599a4d7e86SSudarsana Reddy Kalluru 	if ((count % edev->dev_info.common.num_hwfns) ||
9609a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count % edev->dev_info.common.num_hwfns) ||
9619a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count % edev->dev_info.common.num_hwfns)) {
9628edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
9639a4d7e86SSudarsana Reddy Kalluru 			   "Number of channels must be divisible by %04x\n",
9648edf049dSSudarsana Kalluru 			   edev->dev_info.common.num_hwfns);
9658edf049dSSudarsana Kalluru 		return -EINVAL;
9668edf049dSSudarsana Kalluru 	}
9678edf049dSSudarsana Kalluru 
9688edf049dSSudarsana Kalluru 	/* Set number of queues and reload if necessary */
9699a4d7e86SSudarsana Reddy Kalluru 	edev->req_queues = count;
9709a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_tx = channels->tx_count;
9719a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_rx = channels->rx_count;
972ed0dd915SSudarsana Reddy Kalluru 	/* Reset the indirection table if rx queue count is updated */
973ed0dd915SSudarsana Reddy Kalluru 	if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) {
974ed0dd915SSudarsana Reddy Kalluru 		edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED;
975f29ffdb6SMintz, Yuval 		memset(edev->rss_ind_table, 0, sizeof(edev->rss_ind_table));
976ed0dd915SSudarsana Reddy Kalluru 	}
977ed0dd915SSudarsana Reddy Kalluru 
978567b3c12SMintz, Yuval 	qede_reload(edev, NULL, false);
9798edf049dSSudarsana Kalluru 
9808edf049dSSudarsana Kalluru 	return 0;
9818edf049dSSudarsana Kalluru }
9828edf049dSSudarsana Kalluru 
9834c55215cSSudarsana Reddy Kalluru static int qede_get_ts_info(struct net_device *dev,
9844c55215cSSudarsana Reddy Kalluru 			    struct ethtool_ts_info *info)
9854c55215cSSudarsana Reddy Kalluru {
9864c55215cSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
9874c55215cSSudarsana Reddy Kalluru 
9884c55215cSSudarsana Reddy Kalluru 	return qede_ptp_get_ts_info(edev, info);
9894c55215cSSudarsana Reddy Kalluru }
9904c55215cSSudarsana Reddy Kalluru 
9913d971cbdSSudarsana Kalluru static int qede_set_phys_id(struct net_device *dev,
9923d971cbdSSudarsana Kalluru 			    enum ethtool_phys_id_state state)
9933d971cbdSSudarsana Kalluru {
9943d971cbdSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
9953d971cbdSSudarsana Kalluru 	u8 led_state = 0;
9963d971cbdSSudarsana Kalluru 
9973d971cbdSSudarsana Kalluru 	switch (state) {
9983d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ACTIVE:
9993d971cbdSSudarsana Kalluru 		return 1;	/* cycle on/off once per second */
10003d971cbdSSudarsana Kalluru 
10013d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ON:
10023d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_ON;
10033d971cbdSSudarsana Kalluru 		break;
10043d971cbdSSudarsana Kalluru 
10053d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_OFF:
10063d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_OFF;
10073d971cbdSSudarsana Kalluru 		break;
10083d971cbdSSudarsana Kalluru 
10093d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_INACTIVE:
10103d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_RESTORE;
10113d971cbdSSudarsana Kalluru 		break;
10123d971cbdSSudarsana Kalluru 	}
10133d971cbdSSudarsana Kalluru 
10143d971cbdSSudarsana Kalluru 	edev->ops->common->set_led(edev->cdev, led_state);
10153d971cbdSSudarsana Kalluru 
10163d971cbdSSudarsana Kalluru 	return 0;
10173d971cbdSSudarsana Kalluru }
10183d971cbdSSudarsana Kalluru 
1019961acdeaSSudarsana Reddy Kalluru static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
1020961acdeaSSudarsana Reddy Kalluru {
1021961acdeaSSudarsana Reddy Kalluru 	info->data = RXH_IP_SRC | RXH_IP_DST;
1022961acdeaSSudarsana Reddy Kalluru 
1023961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
1024961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
1025961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
1026961acdeaSSudarsana Reddy Kalluru 		info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
1027961acdeaSSudarsana Reddy Kalluru 		break;
1028961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
1029f29ffdb6SMintz, Yuval 		if (edev->rss_caps & QED_RSS_IPV4_UDP)
1030961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
1031961acdeaSSudarsana Reddy Kalluru 		break;
1032961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
1033f29ffdb6SMintz, Yuval 		if (edev->rss_caps & QED_RSS_IPV6_UDP)
1034961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
1035961acdeaSSudarsana Reddy Kalluru 		break;
1036961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
1037961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
1038961acdeaSSudarsana Reddy Kalluru 		break;
1039961acdeaSSudarsana Reddy Kalluru 	default:
1040961acdeaSSudarsana Reddy Kalluru 		info->data = 0;
1041961acdeaSSudarsana Reddy Kalluru 		break;
1042961acdeaSSudarsana Reddy Kalluru 	}
1043961acdeaSSudarsana Reddy Kalluru 
1044961acdeaSSudarsana Reddy Kalluru 	return 0;
1045961acdeaSSudarsana Reddy Kalluru }
1046961acdeaSSudarsana Reddy Kalluru 
1047961acdeaSSudarsana Reddy Kalluru static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
1048ec9b8dbdSChopra, Manish 			  u32 *rule_locs)
1049961acdeaSSudarsana Reddy Kalluru {
1050961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1051ec9b8dbdSChopra, Manish 	int rc = 0;
1052961acdeaSSudarsana Reddy Kalluru 
1053961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
1054961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXRINGS:
10559a4d7e86SSudarsana Reddy Kalluru 		info->data = QEDE_RSS_COUNT(edev);
1056ec9b8dbdSChopra, Manish 		break;
1057961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXFH:
1058ec9b8dbdSChopra, Manish 		rc = qede_get_rss_flags(edev, info);
1059ec9b8dbdSChopra, Manish 		break;
1060ec9b8dbdSChopra, Manish 	case ETHTOOL_GRXCLSRLCNT:
1061ec9b8dbdSChopra, Manish 		info->rule_cnt = qede_get_arfs_filter_count(edev);
1062ec9b8dbdSChopra, Manish 		info->data = QEDE_RFS_MAX_FLTR;
1063ec9b8dbdSChopra, Manish 		break;
1064ec9b8dbdSChopra, Manish 	case ETHTOOL_GRXCLSRULE:
1065ec9b8dbdSChopra, Manish 		rc = qede_get_cls_rule_entry(edev, info);
1066ec9b8dbdSChopra, Manish 		break;
1067ec9b8dbdSChopra, Manish 	case ETHTOOL_GRXCLSRLALL:
1068ec9b8dbdSChopra, Manish 		rc = qede_get_cls_rule_all(edev, info, rule_locs);
1069ec9b8dbdSChopra, Manish 		break;
1070961acdeaSSudarsana Reddy Kalluru 	default:
1071961acdeaSSudarsana Reddy Kalluru 		DP_ERR(edev, "Command parameters not supported\n");
1072ec9b8dbdSChopra, Manish 		rc = -EOPNOTSUPP;
1073961acdeaSSudarsana Reddy Kalluru 	}
1074ec9b8dbdSChopra, Manish 
1075ec9b8dbdSChopra, Manish 	return rc;
1076961acdeaSSudarsana Reddy Kalluru }
1077961acdeaSSudarsana Reddy Kalluru 
1078961acdeaSSudarsana Reddy Kalluru static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
1079961acdeaSSudarsana Reddy Kalluru {
1080f29ffdb6SMintz, Yuval 	struct qed_update_vport_params *vport_update_params;
1081961acdeaSSudarsana Reddy Kalluru 	u8 set_caps = 0, clr_caps = 0;
1082f29ffdb6SMintz, Yuval 	int rc = 0;
1083961acdeaSSudarsana Reddy Kalluru 
1084961acdeaSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
1085961acdeaSSudarsana Reddy Kalluru 		   "Set rss flags command parameters: flow type = %d, data = %llu\n",
1086961acdeaSSudarsana Reddy Kalluru 		   info->flow_type, info->data);
1087961acdeaSSudarsana Reddy Kalluru 
1088961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
1089961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
1090961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
1091961acdeaSSudarsana Reddy Kalluru 		/* For TCP only 4-tuple hash is supported */
1092961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
1093961acdeaSSudarsana Reddy Kalluru 				  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1094961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1095961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1096961acdeaSSudarsana Reddy Kalluru 		}
1097961acdeaSSudarsana Reddy Kalluru 		return 0;
1098961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
1099961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
1100961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
1101961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1102961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV4_UDP;
1103961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1104961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
1105961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
1106961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV4_UDP;
1107961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1108961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
1109961acdeaSSudarsana Reddy Kalluru 		} else {
1110961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1111961acdeaSSudarsana Reddy Kalluru 		}
1112961acdeaSSudarsana Reddy Kalluru 		break;
1113961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
1114961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
1115961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
1116961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1117961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV6_UDP;
1118961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1119961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
1120961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
1121961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV6_UDP;
1122961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1123961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
1124961acdeaSSudarsana Reddy Kalluru 		} else {
1125961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1126961acdeaSSudarsana Reddy Kalluru 		}
1127961acdeaSSudarsana Reddy Kalluru 		break;
1128961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
1129961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
1130961acdeaSSudarsana Reddy Kalluru 		/* For IP only 2-tuple hash is supported */
1131961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
1132961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1133961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1134961acdeaSSudarsana Reddy Kalluru 		}
1135961acdeaSSudarsana Reddy Kalluru 		return 0;
1136961acdeaSSudarsana Reddy Kalluru 	case SCTP_V4_FLOW:
1137961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V4_FLOW:
1138961acdeaSSudarsana Reddy Kalluru 	case AH_V4_FLOW:
1139961acdeaSSudarsana Reddy Kalluru 	case ESP_V4_FLOW:
1140961acdeaSSudarsana Reddy Kalluru 	case SCTP_V6_FLOW:
1141961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V6_FLOW:
1142961acdeaSSudarsana Reddy Kalluru 	case AH_V6_FLOW:
1143961acdeaSSudarsana Reddy Kalluru 	case ESP_V6_FLOW:
1144961acdeaSSudarsana Reddy Kalluru 	case IP_USER_FLOW:
1145961acdeaSSudarsana Reddy Kalluru 	case ETHER_FLOW:
1146961acdeaSSudarsana Reddy Kalluru 		/* RSS is not supported for these protocols */
1147961acdeaSSudarsana Reddy Kalluru 		if (info->data) {
1148961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1149961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1150961acdeaSSudarsana Reddy Kalluru 		}
1151961acdeaSSudarsana Reddy Kalluru 		return 0;
1152961acdeaSSudarsana Reddy Kalluru 	default:
1153961acdeaSSudarsana Reddy Kalluru 		return -EINVAL;
1154961acdeaSSudarsana Reddy Kalluru 	}
1155961acdeaSSudarsana Reddy Kalluru 
1156961acdeaSSudarsana Reddy Kalluru 	/* No action is needed if there is no change in the rss capability */
1157f29ffdb6SMintz, Yuval 	if (edev->rss_caps == ((edev->rss_caps & ~clr_caps) | set_caps))
1158961acdeaSSudarsana Reddy Kalluru 		return 0;
1159961acdeaSSudarsana Reddy Kalluru 
1160961acdeaSSudarsana Reddy Kalluru 	/* Update internal configuration */
1161f29ffdb6SMintz, Yuval 	edev->rss_caps = ((edev->rss_caps & ~clr_caps) | set_caps);
1162961acdeaSSudarsana Reddy Kalluru 	edev->rss_params_inited |= QEDE_RSS_CAPS_INITED;
1163961acdeaSSudarsana Reddy Kalluru 
1164961acdeaSSudarsana Reddy Kalluru 	/* Re-configure if possible */
1165f29ffdb6SMintz, Yuval 	__qede_lock(edev);
1166f29ffdb6SMintz, Yuval 	if (edev->state == QEDE_STATE_OPEN) {
1167f29ffdb6SMintz, Yuval 		vport_update_params = vzalloc(sizeof(*vport_update_params));
1168f29ffdb6SMintz, Yuval 		if (!vport_update_params) {
1169f29ffdb6SMintz, Yuval 			__qede_unlock(edev);
1170f29ffdb6SMintz, Yuval 			return -ENOMEM;
1171961acdeaSSudarsana Reddy Kalluru 		}
1172f29ffdb6SMintz, Yuval 		qede_fill_rss_params(edev, &vport_update_params->rss_params,
1173f29ffdb6SMintz, Yuval 				     &vport_update_params->update_rss_flg);
1174f29ffdb6SMintz, Yuval 		rc = edev->ops->vport_update(edev->cdev, vport_update_params);
1175f29ffdb6SMintz, Yuval 		vfree(vport_update_params);
1176f29ffdb6SMintz, Yuval 	}
1177f29ffdb6SMintz, Yuval 	__qede_unlock(edev);
1178961acdeaSSudarsana Reddy Kalluru 
1179f29ffdb6SMintz, Yuval 	return rc;
1180961acdeaSSudarsana Reddy Kalluru }
1181961acdeaSSudarsana Reddy Kalluru 
1182961acdeaSSudarsana Reddy Kalluru static int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
1183961acdeaSSudarsana Reddy Kalluru {
1184961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1185961acdeaSSudarsana Reddy Kalluru 
1186961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
1187961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_SRXFH:
1188961acdeaSSudarsana Reddy Kalluru 		return qede_set_rss_flags(edev, info);
1189961acdeaSSudarsana Reddy Kalluru 	default:
1190961acdeaSSudarsana Reddy Kalluru 		DP_INFO(edev, "Command parameters not supported\n");
1191961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1192961acdeaSSudarsana Reddy Kalluru 	}
1193961acdeaSSudarsana Reddy Kalluru }
1194961acdeaSSudarsana Reddy Kalluru 
1195961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_indir_size(struct net_device *dev)
1196961acdeaSSudarsana Reddy Kalluru {
1197961acdeaSSudarsana Reddy Kalluru 	return QED_RSS_IND_TABLE_SIZE;
1198961acdeaSSudarsana Reddy Kalluru }
1199961acdeaSSudarsana Reddy Kalluru 
1200961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_key_size(struct net_device *dev)
1201961acdeaSSudarsana Reddy Kalluru {
1202961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1203961acdeaSSudarsana Reddy Kalluru 
1204f29ffdb6SMintz, Yuval 	return sizeof(edev->rss_key);
1205961acdeaSSudarsana Reddy Kalluru }
1206961acdeaSSudarsana Reddy Kalluru 
1207961acdeaSSudarsana Reddy Kalluru static int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
1208961acdeaSSudarsana Reddy Kalluru {
1209961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1210961acdeaSSudarsana Reddy Kalluru 	int i;
1211961acdeaSSudarsana Reddy Kalluru 
1212961acdeaSSudarsana Reddy Kalluru 	if (hfunc)
1213961acdeaSSudarsana Reddy Kalluru 		*hfunc = ETH_RSS_HASH_TOP;
1214961acdeaSSudarsana Reddy Kalluru 
1215961acdeaSSudarsana Reddy Kalluru 	if (!indir)
1216961acdeaSSudarsana Reddy Kalluru 		return 0;
1217961acdeaSSudarsana Reddy Kalluru 
1218961acdeaSSudarsana Reddy Kalluru 	for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1219f29ffdb6SMintz, Yuval 		indir[i] = edev->rss_ind_table[i];
1220961acdeaSSudarsana Reddy Kalluru 
1221961acdeaSSudarsana Reddy Kalluru 	if (key)
1222f29ffdb6SMintz, Yuval 		memcpy(key, edev->rss_key, qede_get_rxfh_key_size(dev));
1223961acdeaSSudarsana Reddy Kalluru 
1224961acdeaSSudarsana Reddy Kalluru 	return 0;
1225961acdeaSSudarsana Reddy Kalluru }
1226961acdeaSSudarsana Reddy Kalluru 
1227961acdeaSSudarsana Reddy Kalluru static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
1228961acdeaSSudarsana Reddy Kalluru 			 const u8 *key, const u8 hfunc)
1229961acdeaSSudarsana Reddy Kalluru {
1230f29ffdb6SMintz, Yuval 	struct qed_update_vport_params *vport_update_params;
1231961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1232f29ffdb6SMintz, Yuval 	int i, rc = 0;
1233961acdeaSSudarsana Reddy Kalluru 
1234ba300ce3SSudarsana Reddy Kalluru 	if (edev->dev_info.common.num_hwfns > 1) {
1235ba300ce3SSudarsana Reddy Kalluru 		DP_INFO(edev,
1236ba300ce3SSudarsana Reddy Kalluru 			"RSS configuration is not supported for 100G devices\n");
1237ba300ce3SSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1238ba300ce3SSudarsana Reddy Kalluru 	}
1239ba300ce3SSudarsana Reddy Kalluru 
1240961acdeaSSudarsana Reddy Kalluru 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
1241961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1242961acdeaSSudarsana Reddy Kalluru 
1243961acdeaSSudarsana Reddy Kalluru 	if (!indir && !key)
1244961acdeaSSudarsana Reddy Kalluru 		return 0;
1245961acdeaSSudarsana Reddy Kalluru 
1246961acdeaSSudarsana Reddy Kalluru 	if (indir) {
1247961acdeaSSudarsana Reddy Kalluru 		for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1248f29ffdb6SMintz, Yuval 			edev->rss_ind_table[i] = indir[i];
1249961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_INDIR_INITED;
1250961acdeaSSudarsana Reddy Kalluru 	}
1251961acdeaSSudarsana Reddy Kalluru 
1252961acdeaSSudarsana Reddy Kalluru 	if (key) {
1253f29ffdb6SMintz, Yuval 		memcpy(&edev->rss_key, key, qede_get_rxfh_key_size(dev));
1254961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_KEY_INITED;
1255961acdeaSSudarsana Reddy Kalluru 	}
1256961acdeaSSudarsana Reddy Kalluru 
1257f29ffdb6SMintz, Yuval 	__qede_lock(edev);
1258f29ffdb6SMintz, Yuval 	if (edev->state == QEDE_STATE_OPEN) {
1259f29ffdb6SMintz, Yuval 		vport_update_params = vzalloc(sizeof(*vport_update_params));
1260f29ffdb6SMintz, Yuval 		if (!vport_update_params) {
1261f29ffdb6SMintz, Yuval 			__qede_unlock(edev);
1262f29ffdb6SMintz, Yuval 			return -ENOMEM;
1263961acdeaSSudarsana Reddy Kalluru 		}
1264f29ffdb6SMintz, Yuval 		qede_fill_rss_params(edev, &vport_update_params->rss_params,
1265f29ffdb6SMintz, Yuval 				     &vport_update_params->update_rss_flg);
1266f29ffdb6SMintz, Yuval 		rc = edev->ops->vport_update(edev->cdev, vport_update_params);
1267f29ffdb6SMintz, Yuval 		vfree(vport_update_params);
1268f29ffdb6SMintz, Yuval 	}
1269f29ffdb6SMintz, Yuval 	__qede_unlock(edev);
1270961acdeaSSudarsana Reddy Kalluru 
1271f29ffdb6SMintz, Yuval 	return rc;
1272961acdeaSSudarsana Reddy Kalluru }
1273961acdeaSSudarsana Reddy Kalluru 
127416f46bf0SSudarsana Reddy Kalluru /* This function enables the interrupt generation and the NAPI on the device */
127516f46bf0SSudarsana Reddy Kalluru static void qede_netif_start(struct qede_dev *edev)
127616f46bf0SSudarsana Reddy Kalluru {
127716f46bf0SSudarsana Reddy Kalluru 	int i;
127816f46bf0SSudarsana Reddy Kalluru 
127916f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev))
128016f46bf0SSudarsana Reddy Kalluru 		return;
128116f46bf0SSudarsana Reddy Kalluru 
12829a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
128316f46bf0SSudarsana Reddy Kalluru 		/* Update and reenable interrupts */
128416f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_ENABLE, 1);
128516f46bf0SSudarsana Reddy Kalluru 		napi_enable(&edev->fp_array[i].napi);
128616f46bf0SSudarsana Reddy Kalluru 	}
128716f46bf0SSudarsana Reddy Kalluru }
128816f46bf0SSudarsana Reddy Kalluru 
128916f46bf0SSudarsana Reddy Kalluru /* This function disables the NAPI and the interrupt generation on the device */
129016f46bf0SSudarsana Reddy Kalluru static void qede_netif_stop(struct qede_dev *edev)
129116f46bf0SSudarsana Reddy Kalluru {
129216f46bf0SSudarsana Reddy Kalluru 	int i;
129316f46bf0SSudarsana Reddy Kalluru 
12949a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
129516f46bf0SSudarsana Reddy Kalluru 		napi_disable(&edev->fp_array[i].napi);
129616f46bf0SSudarsana Reddy Kalluru 		/* Disable interrupts */
129716f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_DISABLE, 0);
129816f46bf0SSudarsana Reddy Kalluru 	}
129916f46bf0SSudarsana Reddy Kalluru }
130016f46bf0SSudarsana Reddy Kalluru 
130116f46bf0SSudarsana Reddy Kalluru static int qede_selftest_transmit_traffic(struct qede_dev *edev,
130216f46bf0SSudarsana Reddy Kalluru 					  struct sk_buff *skb)
130316f46bf0SSudarsana Reddy Kalluru {
13049a4d7e86SSudarsana Reddy Kalluru 	struct qede_tx_queue *txq = NULL;
130516f46bf0SSudarsana Reddy Kalluru 	struct eth_tx_1st_bd *first_bd;
130616f46bf0SSudarsana Reddy Kalluru 	dma_addr_t mapping;
130748848a06SManish Chopra 	int i, idx;
130848848a06SManish Chopra 	u16 val;
130916f46bf0SSudarsana Reddy Kalluru 
13109a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
13119a4d7e86SSudarsana Reddy Kalluru 		if (edev->fp_array[i].type & QEDE_FASTPATH_TX) {
131280439a17SMintz, Yuval 			txq = edev->fp_array[i].txq;
13139a4d7e86SSudarsana Reddy Kalluru 			break;
13149a4d7e86SSudarsana Reddy Kalluru 		}
13159a4d7e86SSudarsana Reddy Kalluru 	}
13169a4d7e86SSudarsana Reddy Kalluru 
13179a4d7e86SSudarsana Reddy Kalluru 	if (!txq) {
13189a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx path is not available\n");
13199a4d7e86SSudarsana Reddy Kalluru 		return -1;
13209a4d7e86SSudarsana Reddy Kalluru 	}
13219a4d7e86SSudarsana Reddy Kalluru 
132216f46bf0SSudarsana Reddy Kalluru 	/* Fill the entry in the SW ring and the BDs in the FW ring */
13235a052d62SSudarsana Reddy Kalluru 	idx = txq->sw_tx_prod;
1324cb6aeb07SMintz, Yuval 	txq->sw_tx_ring.skbs[idx].skb = skb;
132516f46bf0SSudarsana Reddy Kalluru 	first_bd = qed_chain_produce(&txq->tx_pbl);
132616f46bf0SSudarsana Reddy Kalluru 	memset(first_bd, 0, sizeof(*first_bd));
132716f46bf0SSudarsana Reddy Kalluru 	val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT;
132816f46bf0SSudarsana Reddy Kalluru 	first_bd->data.bd_flags.bitfields = val;
1329351a4dedSYuval Mintz 	val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK;
133048848a06SManish Chopra 	val = val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT;
133148848a06SManish Chopra 	first_bd->data.bitfields |= cpu_to_le16(val);
133216f46bf0SSudarsana Reddy Kalluru 
133316f46bf0SSudarsana Reddy Kalluru 	/* Map skb linear data for DMA and set in the first BD */
133416f46bf0SSudarsana Reddy Kalluru 	mapping = dma_map_single(&edev->pdev->dev, skb->data,
133516f46bf0SSudarsana Reddy Kalluru 				 skb_headlen(skb), DMA_TO_DEVICE);
133616f46bf0SSudarsana Reddy Kalluru 	if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) {
133716f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "SKB mapping failed\n");
133816f46bf0SSudarsana Reddy Kalluru 		return -ENOMEM;
133916f46bf0SSudarsana Reddy Kalluru 	}
134016f46bf0SSudarsana Reddy Kalluru 	BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb));
134116f46bf0SSudarsana Reddy Kalluru 
134216f46bf0SSudarsana Reddy Kalluru 	/* update the first BD with the actual num BDs */
134316f46bf0SSudarsana Reddy Kalluru 	first_bd->data.nbds = 1;
13445a052d62SSudarsana Reddy Kalluru 	txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers;
134516f46bf0SSudarsana Reddy Kalluru 	/* 'next page' entries are counted in the producer value */
134648848a06SManish Chopra 	val = qed_chain_get_prod_idx(&txq->tx_pbl);
134748848a06SManish Chopra 	txq->tx_db.data.bd_prod = cpu_to_le16(val);
134816f46bf0SSudarsana Reddy Kalluru 
134916f46bf0SSudarsana Reddy Kalluru 	/* wmb makes sure that the BDs data is updated before updating the
135016f46bf0SSudarsana Reddy Kalluru 	 * producer, otherwise FW may read old data from the BDs.
135116f46bf0SSudarsana Reddy Kalluru 	 */
135216f46bf0SSudarsana Reddy Kalluru 	wmb();
135316f46bf0SSudarsana Reddy Kalluru 	barrier();
135416f46bf0SSudarsana Reddy Kalluru 	writel(txq->tx_db.raw, txq->doorbell_addr);
135516f46bf0SSudarsana Reddy Kalluru 
135616f46bf0SSudarsana Reddy Kalluru 	/* mmiowb is needed to synchronize doorbell writes from more than one
135716f46bf0SSudarsana Reddy Kalluru 	 * processor. It guarantees that the write arrives to the device before
135816f46bf0SSudarsana Reddy Kalluru 	 * the queue lock is released and another start_xmit is called (possibly
135916f46bf0SSudarsana Reddy Kalluru 	 * on another CPU). Without this barrier, the next doorbell can bypass
136016f46bf0SSudarsana Reddy Kalluru 	 * this doorbell. This is applicable to IA64/Altix systems.
136116f46bf0SSudarsana Reddy Kalluru 	 */
136216f46bf0SSudarsana Reddy Kalluru 	mmiowb();
136316f46bf0SSudarsana Reddy Kalluru 
136416f46bf0SSudarsana Reddy Kalluru 	for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
136516f46bf0SSudarsana Reddy Kalluru 		if (qede_txq_has_work(txq))
136616f46bf0SSudarsana Reddy Kalluru 			break;
136716f46bf0SSudarsana Reddy Kalluru 		usleep_range(100, 200);
136816f46bf0SSudarsana Reddy Kalluru 	}
136916f46bf0SSudarsana Reddy Kalluru 
137016f46bf0SSudarsana Reddy Kalluru 	if (!qede_txq_has_work(txq)) {
137116f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx completion didn't happen\n");
137216f46bf0SSudarsana Reddy Kalluru 		return -1;
137316f46bf0SSudarsana Reddy Kalluru 	}
137416f46bf0SSudarsana Reddy Kalluru 
137516f46bf0SSudarsana Reddy Kalluru 	first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl);
1376fabd545cSManish Chopra 	dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
137716f46bf0SSudarsana Reddy Kalluru 			 BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE);
13785a052d62SSudarsana Reddy Kalluru 	txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers;
1379cb6aeb07SMintz, Yuval 	txq->sw_tx_ring.skbs[idx].skb = NULL;
138016f46bf0SSudarsana Reddy Kalluru 
138116f46bf0SSudarsana Reddy Kalluru 	return 0;
138216f46bf0SSudarsana Reddy Kalluru }
138316f46bf0SSudarsana Reddy Kalluru 
138416f46bf0SSudarsana Reddy Kalluru static int qede_selftest_receive_traffic(struct qede_dev *edev)
138516f46bf0SSudarsana Reddy Kalluru {
138616f46bf0SSudarsana Reddy Kalluru 	u16 hw_comp_cons, sw_comp_cons, sw_rx_index, len;
138716f46bf0SSudarsana Reddy Kalluru 	struct eth_fast_path_rx_reg_cqe *fp_cqe;
13889a4d7e86SSudarsana Reddy Kalluru 	struct qede_rx_queue *rxq = NULL;
138916f46bf0SSudarsana Reddy Kalluru 	struct sw_rx_data *sw_rx_data;
139016f46bf0SSudarsana Reddy Kalluru 	union eth_rx_cqe *cqe;
1391afe981d6SSudarsana Reddy Kalluru 	int i, iter, rc = 0;
139216f46bf0SSudarsana Reddy Kalluru 	u8 *data_ptr;
139316f46bf0SSudarsana Reddy Kalluru 
13949a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
13959a4d7e86SSudarsana Reddy Kalluru 		if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
13969a4d7e86SSudarsana Reddy Kalluru 			rxq = edev->fp_array[i].rxq;
13979a4d7e86SSudarsana Reddy Kalluru 			break;
13989a4d7e86SSudarsana Reddy Kalluru 		}
13999a4d7e86SSudarsana Reddy Kalluru 	}
14009a4d7e86SSudarsana Reddy Kalluru 
14019a4d7e86SSudarsana Reddy Kalluru 	if (!rxq) {
14029a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Rx path is not available\n");
14039a4d7e86SSudarsana Reddy Kalluru 		return -1;
14049a4d7e86SSudarsana Reddy Kalluru 	}
14059a4d7e86SSudarsana Reddy Kalluru 
140616f46bf0SSudarsana Reddy Kalluru 	/* The packet is expected to receive on rx-queue 0 even though RSS is
140716f46bf0SSudarsana Reddy Kalluru 	 * enabled. This is because the queue 0 is configured as the default
140816f46bf0SSudarsana Reddy Kalluru 	 * queue and that the loopback traffic is not IP.
140916f46bf0SSudarsana Reddy Kalluru 	 */
1410afe981d6SSudarsana Reddy Kalluru 	for (iter = 0; iter < QEDE_SELFTEST_POLL_COUNT; iter++) {
141116f46bf0SSudarsana Reddy Kalluru 		if (!qede_has_rx_work(rxq)) {
1412837d4eb6SSudarsana Reddy Kalluru 			usleep_range(100, 200);
1413837d4eb6SSudarsana Reddy Kalluru 			continue;
141416f46bf0SSudarsana Reddy Kalluru 		}
141516f46bf0SSudarsana Reddy Kalluru 
141616f46bf0SSudarsana Reddy Kalluru 		hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr);
141716f46bf0SSudarsana Reddy Kalluru 		sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
141816f46bf0SSudarsana Reddy Kalluru 
1419837d4eb6SSudarsana Reddy Kalluru 		/* Memory barrier to prevent the CPU from doing speculative
1420837d4eb6SSudarsana Reddy Kalluru 		 * reads of CQE/BD before reading hw_comp_cons. If the CQE is
1421837d4eb6SSudarsana Reddy Kalluru 		 * read before it is written by FW, then FW writes CQE and SB,
1422837d4eb6SSudarsana Reddy Kalluru 		 * and then the CPU reads the hw_comp_cons, it will use an old
1423837d4eb6SSudarsana Reddy Kalluru 		 * CQE.
142416f46bf0SSudarsana Reddy Kalluru 		 */
142516f46bf0SSudarsana Reddy Kalluru 		rmb();
142616f46bf0SSudarsana Reddy Kalluru 
142716f46bf0SSudarsana Reddy Kalluru 		/* Get the CQE from the completion ring */
142816f46bf0SSudarsana Reddy Kalluru 		cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring);
142916f46bf0SSudarsana Reddy Kalluru 
143016f46bf0SSudarsana Reddy Kalluru 		/* Get the data from the SW ring */
143116f46bf0SSudarsana Reddy Kalluru 		sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
143216f46bf0SSudarsana Reddy Kalluru 		sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
143316f46bf0SSudarsana Reddy Kalluru 		fp_cqe = &cqe->fast_path_regular;
143416f46bf0SSudarsana Reddy Kalluru 		len =  le16_to_cpu(fp_cqe->len_on_first_bd);
143516f46bf0SSudarsana Reddy Kalluru 		data_ptr = (u8 *)(page_address(sw_rx_data->data) +
1436837d4eb6SSudarsana Reddy Kalluru 				  fp_cqe->placement_offset +
1437837d4eb6SSudarsana Reddy Kalluru 				  sw_rx_data->page_offset);
1438837d4eb6SSudarsana Reddy Kalluru 		if (ether_addr_equal(data_ptr,  edev->ndev->dev_addr) &&
1439837d4eb6SSudarsana Reddy Kalluru 		    ether_addr_equal(data_ptr + ETH_ALEN,
1440837d4eb6SSudarsana Reddy Kalluru 				     edev->ndev->dev_addr)) {
144116f46bf0SSudarsana Reddy Kalluru 			for (i = ETH_HLEN; i < len; i++)
144216f46bf0SSudarsana Reddy Kalluru 				if (data_ptr[i] != (unsigned char)(i & 0xff)) {
1443837d4eb6SSudarsana Reddy Kalluru 					rc = -1;
1444837d4eb6SSudarsana Reddy Kalluru 					break;
144516f46bf0SSudarsana Reddy Kalluru 				}
144616f46bf0SSudarsana Reddy Kalluru 
14479eb22357SMintz, Yuval 			qede_recycle_rx_bd_ring(rxq, 1);
1448837d4eb6SSudarsana Reddy Kalluru 			qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1449837d4eb6SSudarsana Reddy Kalluru 			break;
1450837d4eb6SSudarsana Reddy Kalluru 		}
145116f46bf0SSudarsana Reddy Kalluru 
1452837d4eb6SSudarsana Reddy Kalluru 		DP_INFO(edev, "Not the transmitted packet\n");
14539eb22357SMintz, Yuval 		qede_recycle_rx_bd_ring(rxq, 1);
1454837d4eb6SSudarsana Reddy Kalluru 		qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1455837d4eb6SSudarsana Reddy Kalluru 	}
1456837d4eb6SSudarsana Reddy Kalluru 
1457afe981d6SSudarsana Reddy Kalluru 	if (iter == QEDE_SELFTEST_POLL_COUNT) {
1458837d4eb6SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Failed to receive the traffic\n");
1459837d4eb6SSudarsana Reddy Kalluru 		return -1;
1460837d4eb6SSudarsana Reddy Kalluru 	}
1461837d4eb6SSudarsana Reddy Kalluru 
1462837d4eb6SSudarsana Reddy Kalluru 	qede_update_rx_prod(edev, rxq);
1463837d4eb6SSudarsana Reddy Kalluru 
1464837d4eb6SSudarsana Reddy Kalluru 	return rc;
146516f46bf0SSudarsana Reddy Kalluru }
146616f46bf0SSudarsana Reddy Kalluru 
146716f46bf0SSudarsana Reddy Kalluru static int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode)
146816f46bf0SSudarsana Reddy Kalluru {
146916f46bf0SSudarsana Reddy Kalluru 	struct qed_link_params link_params;
147016f46bf0SSudarsana Reddy Kalluru 	struct sk_buff *skb = NULL;
147116f46bf0SSudarsana Reddy Kalluru 	int rc = 0, i;
147216f46bf0SSudarsana Reddy Kalluru 	u32 pkt_size;
147316f46bf0SSudarsana Reddy Kalluru 	u8 *packet;
147416f46bf0SSudarsana Reddy Kalluru 
147516f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev)) {
147616f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Interface is down\n");
147716f46bf0SSudarsana Reddy Kalluru 		return -EINVAL;
147816f46bf0SSudarsana Reddy Kalluru 	}
147916f46bf0SSudarsana Reddy Kalluru 
148016f46bf0SSudarsana Reddy Kalluru 	qede_netif_stop(edev);
148116f46bf0SSudarsana Reddy Kalluru 
148216f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Loopback mode */
148316f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
148416f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
148516f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
148616f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = loopback_mode;
148716f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
148816f46bf0SSudarsana Reddy Kalluru 
148916f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
149016f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
149116f46bf0SSudarsana Reddy Kalluru 
149216f46bf0SSudarsana Reddy Kalluru 	/* prepare the loopback packet */
149316f46bf0SSudarsana Reddy Kalluru 	pkt_size = edev->ndev->mtu + ETH_HLEN;
149416f46bf0SSudarsana Reddy Kalluru 
149516f46bf0SSudarsana Reddy Kalluru 	skb = netdev_alloc_skb(edev->ndev, pkt_size);
149616f46bf0SSudarsana Reddy Kalluru 	if (!skb) {
149716f46bf0SSudarsana Reddy Kalluru 		DP_INFO(edev, "Can't allocate skb\n");
149816f46bf0SSudarsana Reddy Kalluru 		rc = -ENOMEM;
149916f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
150016f46bf0SSudarsana Reddy Kalluru 	}
150116f46bf0SSudarsana Reddy Kalluru 	packet = skb_put(skb, pkt_size);
150216f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet, edev->ndev->dev_addr);
150316f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet + ETH_ALEN, edev->ndev->dev_addr);
150416f46bf0SSudarsana Reddy Kalluru 	memset(packet + (2 * ETH_ALEN), 0x77, (ETH_HLEN - (2 * ETH_ALEN)));
150516f46bf0SSudarsana Reddy Kalluru 	for (i = ETH_HLEN; i < pkt_size; i++)
150616f46bf0SSudarsana Reddy Kalluru 		packet[i] = (unsigned char)(i & 0xff);
150716f46bf0SSudarsana Reddy Kalluru 
150816f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_transmit_traffic(edev, skb);
150916f46bf0SSudarsana Reddy Kalluru 	if (rc)
151016f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
151116f46bf0SSudarsana Reddy Kalluru 
151216f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_receive_traffic(edev);
151316f46bf0SSudarsana Reddy Kalluru 	if (rc)
151416f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
151516f46bf0SSudarsana Reddy Kalluru 
151616f46bf0SSudarsana Reddy Kalluru 	DP_VERBOSE(edev, NETIF_MSG_RX_STATUS, "Loopback test successful\n");
151716f46bf0SSudarsana Reddy Kalluru 
151816f46bf0SSudarsana Reddy Kalluru test_loopback_exit:
151916f46bf0SSudarsana Reddy Kalluru 	dev_kfree_skb(skb);
152016f46bf0SSudarsana Reddy Kalluru 
152116f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Normal mode */
152216f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
152316f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
152416f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
152516f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = QED_LINK_LOOPBACK_NONE;
152616f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
152716f46bf0SSudarsana Reddy Kalluru 
152816f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
152916f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
153016f46bf0SSudarsana Reddy Kalluru 
153116f46bf0SSudarsana Reddy Kalluru 	qede_netif_start(edev);
153216f46bf0SSudarsana Reddy Kalluru 
153316f46bf0SSudarsana Reddy Kalluru 	return rc;
153416f46bf0SSudarsana Reddy Kalluru }
153516f46bf0SSudarsana Reddy Kalluru 
15363044a02eSSudarsana Reddy Kalluru static void qede_self_test(struct net_device *dev,
15373044a02eSSudarsana Reddy Kalluru 			   struct ethtool_test *etest, u64 *buf)
15383044a02eSSudarsana Reddy Kalluru {
15393044a02eSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
15403044a02eSSudarsana Reddy Kalluru 
15413044a02eSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
15423044a02eSSudarsana Reddy Kalluru 		   "Self-test command parameters: offline = %d, external_lb = %d\n",
15433044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_OFFLINE),
15443044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_EXTERNAL_LB) >> 2);
15453044a02eSSudarsana Reddy Kalluru 
15463044a02eSSudarsana Reddy Kalluru 	memset(buf, 0, sizeof(u64) * QEDE_ETHTOOL_TEST_MAX);
15473044a02eSSudarsana Reddy Kalluru 
154816f46bf0SSudarsana Reddy Kalluru 	if (etest->flags & ETH_TEST_FL_OFFLINE) {
154916f46bf0SSudarsana Reddy Kalluru 		if (qede_selftest_run_loopback(edev,
155016f46bf0SSudarsana Reddy Kalluru 					       QED_LINK_LOOPBACK_INT_PHY)) {
155116f46bf0SSudarsana Reddy Kalluru 			buf[QEDE_ETHTOOL_INT_LOOPBACK] = 1;
155216f46bf0SSudarsana Reddy Kalluru 			etest->flags |= ETH_TEST_FL_FAILED;
155316f46bf0SSudarsana Reddy Kalluru 		}
155416f46bf0SSudarsana Reddy Kalluru 	}
155516f46bf0SSudarsana Reddy Kalluru 
15563044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_interrupt(edev->cdev)) {
15573044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_INTERRUPT_TEST] = 1;
15583044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
15593044a02eSSudarsana Reddy Kalluru 	}
15603044a02eSSudarsana Reddy Kalluru 
15613044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_memory(edev->cdev)) {
15623044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_MEMORY_TEST] = 1;
15633044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
15643044a02eSSudarsana Reddy Kalluru 	}
15653044a02eSSudarsana Reddy Kalluru 
15663044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_register(edev->cdev)) {
15673044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_REGISTER_TEST] = 1;
15683044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
15693044a02eSSudarsana Reddy Kalluru 	}
15703044a02eSSudarsana Reddy Kalluru 
15713044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_clock(edev->cdev)) {
15723044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_CLOCK_TEST] = 1;
15733044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
15743044a02eSSudarsana Reddy Kalluru 	}
15757a4b21b7SMintz, Yuval 
15767a4b21b7SMintz, Yuval 	if (edev->ops->common->selftest->selftest_nvram(edev->cdev)) {
15777a4b21b7SMintz, Yuval 		buf[QEDE_ETHTOOL_NVRAM_TEST] = 1;
15787a4b21b7SMintz, Yuval 		etest->flags |= ETH_TEST_FL_FAILED;
15797a4b21b7SMintz, Yuval 	}
15803044a02eSSudarsana Reddy Kalluru }
15813044a02eSSudarsana Reddy Kalluru 
15823d789994SManish Chopra static int qede_set_tunable(struct net_device *dev,
15833d789994SManish Chopra 			    const struct ethtool_tunable *tuna,
15843d789994SManish Chopra 			    const void *data)
15853d789994SManish Chopra {
15863d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
15873d789994SManish Chopra 	u32 val;
15883d789994SManish Chopra 
15893d789994SManish Chopra 	switch (tuna->id) {
15903d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
15913d789994SManish Chopra 		val = *(u32 *)data;
15923d789994SManish Chopra 		if (val < QEDE_MIN_PKT_LEN || val > QEDE_RX_HDR_SIZE) {
15933d789994SManish Chopra 			DP_VERBOSE(edev, QED_MSG_DEBUG,
15943d789994SManish Chopra 				   "Invalid rx copy break value, range is [%u, %u]",
15953d789994SManish Chopra 				   QEDE_MIN_PKT_LEN, QEDE_RX_HDR_SIZE);
15963d789994SManish Chopra 			return -EINVAL;
15973d789994SManish Chopra 		}
15983d789994SManish Chopra 
15993d789994SManish Chopra 		edev->rx_copybreak = *(u32 *)data;
16003d789994SManish Chopra 		break;
16013d789994SManish Chopra 	default:
16023d789994SManish Chopra 		return -EOPNOTSUPP;
16033d789994SManish Chopra 	}
16043d789994SManish Chopra 
16053d789994SManish Chopra 	return 0;
16063d789994SManish Chopra }
16073d789994SManish Chopra 
16083d789994SManish Chopra static int qede_get_tunable(struct net_device *dev,
16093d789994SManish Chopra 			    const struct ethtool_tunable *tuna, void *data)
16103d789994SManish Chopra {
16113d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
16123d789994SManish Chopra 
16133d789994SManish Chopra 	switch (tuna->id) {
16143d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
16153d789994SManish Chopra 		*(u32 *)data = edev->rx_copybreak;
16163d789994SManish Chopra 		break;
16173d789994SManish Chopra 	default:
16183d789994SManish Chopra 		return -EOPNOTSUPP;
16193d789994SManish Chopra 	}
16203d789994SManish Chopra 
16213d789994SManish Chopra 	return 0;
16223d789994SManish Chopra }
16233d789994SManish Chopra 
1624133fac0eSSudarsana Kalluru static const struct ethtool_ops qede_ethtool_ops = {
1625054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1626054c67d1SSudarsana Reddy Kalluru 	.set_link_ksettings = qede_set_link_ksettings,
1627133fac0eSSudarsana Kalluru 	.get_drvinfo = qede_get_drvinfo,
1628e0971c83STomer Tayar 	.get_regs_len = qede_get_regs_len,
1629e0971c83STomer Tayar 	.get_regs = qede_get_regs,
163014d39648SMintz, Yuval 	.get_wol = qede_get_wol,
163114d39648SMintz, Yuval 	.set_wol = qede_set_wol,
1632133fac0eSSudarsana Kalluru 	.get_msglevel = qede_get_msglevel,
1633133fac0eSSudarsana Kalluru 	.set_msglevel = qede_set_msglevel,
163432a7a570SSudarsana Kalluru 	.nway_reset = qede_nway_reset,
1635133fac0eSSudarsana Kalluru 	.get_link = qede_get_link,
1636d552fa84SSudarsana Reddy Kalluru 	.get_coalesce = qede_get_coalesce,
1637d552fa84SSudarsana Reddy Kalluru 	.set_coalesce = qede_set_coalesce,
163801ef7e05SSudarsana Kalluru 	.get_ringparam = qede_get_ringparam,
163901ef7e05SSudarsana Kalluru 	.set_ringparam = qede_set_ringparam,
16400f7db144SSudarsana Kalluru 	.get_pauseparam = qede_get_pauseparam,
16410f7db144SSudarsana Kalluru 	.set_pauseparam = qede_set_pauseparam,
1642133fac0eSSudarsana Kalluru 	.get_strings = qede_get_strings,
16433d971cbdSSudarsana Kalluru 	.set_phys_id = qede_set_phys_id,
1644133fac0eSSudarsana Kalluru 	.get_ethtool_stats = qede_get_ethtool_stats,
1645f3e72109SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1646133fac0eSSudarsana Kalluru 	.get_sset_count = qede_get_sset_count,
1647961acdeaSSudarsana Reddy Kalluru 	.get_rxnfc = qede_get_rxnfc,
1648961acdeaSSudarsana Reddy Kalluru 	.set_rxnfc = qede_set_rxnfc,
1649961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1650961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1651961acdeaSSudarsana Reddy Kalluru 	.get_rxfh = qede_get_rxfh,
1652961acdeaSSudarsana Reddy Kalluru 	.set_rxfh = qede_set_rxfh,
16534c55215cSSudarsana Reddy Kalluru 	.get_ts_info = qede_get_ts_info,
16548edf049dSSudarsana Kalluru 	.get_channels = qede_get_channels,
16558edf049dSSudarsana Kalluru 	.set_channels = qede_set_channels,
16563044a02eSSudarsana Reddy Kalluru 	.self_test = qede_self_test,
16573d789994SManish Chopra 	.get_tunable = qede_get_tunable,
16583d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1659133fac0eSSudarsana Kalluru };
1660133fac0eSSudarsana Kalluru 
1661fefb0202SYuval Mintz static const struct ethtool_ops qede_vf_ethtool_ops = {
1662054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1663fefb0202SYuval Mintz 	.get_drvinfo = qede_get_drvinfo,
1664fefb0202SYuval Mintz 	.get_msglevel = qede_get_msglevel,
1665fefb0202SYuval Mintz 	.set_msglevel = qede_set_msglevel,
1666fefb0202SYuval Mintz 	.get_link = qede_get_link,
1667fefb0202SYuval Mintz 	.get_ringparam = qede_get_ringparam,
1668fefb0202SYuval Mintz 	.set_ringparam = qede_set_ringparam,
1669fefb0202SYuval Mintz 	.get_strings = qede_get_strings,
1670fefb0202SYuval Mintz 	.get_ethtool_stats = qede_get_ethtool_stats,
1671fefb0202SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1672fefb0202SYuval Mintz 	.get_sset_count = qede_get_sset_count,
1673fefb0202SYuval Mintz 	.get_rxnfc = qede_get_rxnfc,
1674fefb0202SYuval Mintz 	.set_rxnfc = qede_set_rxnfc,
1675fefb0202SYuval Mintz 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1676fefb0202SYuval Mintz 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1677fefb0202SYuval Mintz 	.get_rxfh = qede_get_rxfh,
1678fefb0202SYuval Mintz 	.set_rxfh = qede_set_rxfh,
1679fefb0202SYuval Mintz 	.get_channels = qede_get_channels,
1680fefb0202SYuval Mintz 	.set_channels = qede_set_channels,
16813d789994SManish Chopra 	.get_tunable = qede_get_tunable,
16823d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1683fefb0202SYuval Mintz };
1684fefb0202SYuval Mintz 
1685133fac0eSSudarsana Kalluru void qede_set_ethtool_ops(struct net_device *dev)
1686133fac0eSSudarsana Kalluru {
1687fefb0202SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
1688fefb0202SYuval Mintz 
1689fefb0202SYuval Mintz 	if (IS_VF(edev))
1690fefb0202SYuval Mintz 		dev->ethtool_ops = &qede_vf_ethtool_ops;
1691fefb0202SYuval Mintz 	else
1692133fac0eSSudarsana Kalluru 		dev->ethtool_ops = &qede_ethtool_ops;
1693133fac0eSSudarsana Kalluru }
1694