1133fac0eSSudarsana Kalluru /* QLogic qede NIC Driver
2133fac0eSSudarsana Kalluru * Copyright (c) 2015 QLogic Corporation
3133fac0eSSudarsana Kalluru *
4133fac0eSSudarsana Kalluru * This software is available under the terms of the GNU General Public License
5133fac0eSSudarsana Kalluru * (GPL) Version 2, available from the file COPYING in the main directory of
6133fac0eSSudarsana Kalluru * this source tree.
7133fac0eSSudarsana Kalluru */
8133fac0eSSudarsana Kalluru 
9133fac0eSSudarsana Kalluru #include <linux/version.h>
10133fac0eSSudarsana Kalluru #include <linux/types.h>
11133fac0eSSudarsana Kalluru #include <linux/netdevice.h>
1216f46bf0SSudarsana Reddy Kalluru #include <linux/etherdevice.h>
13133fac0eSSudarsana Kalluru #include <linux/ethtool.h>
14133fac0eSSudarsana Kalluru #include <linux/string.h>
15133fac0eSSudarsana Kalluru #include <linux/pci.h>
16133fac0eSSudarsana Kalluru #include <linux/capability.h>
17133fac0eSSudarsana Kalluru #include "qede.h"
18133fac0eSSudarsana Kalluru 
19133fac0eSSudarsana Kalluru #define QEDE_STAT_OFFSET(stat_name) (offsetof(struct qede_stats, stat_name))
20133fac0eSSudarsana Kalluru #define QEDE_STAT_STRING(stat_name) (#stat_name)
21133fac0eSSudarsana Kalluru #define _QEDE_STAT(stat_name, pf_only) \
22133fac0eSSudarsana Kalluru 	 {QEDE_STAT_OFFSET(stat_name), QEDE_STAT_STRING(stat_name), pf_only}
23133fac0eSSudarsana Kalluru #define QEDE_PF_STAT(stat_name)		_QEDE_STAT(stat_name, true)
24133fac0eSSudarsana Kalluru #define QEDE_STAT(stat_name)		_QEDE_STAT(stat_name, false)
25133fac0eSSudarsana Kalluru 
26133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_OFFSET(stat_name) \
27133fac0eSSudarsana Kalluru 	 (offsetof(struct qede_rx_queue, stat_name))
28133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_STRING(stat_name) (#stat_name)
29133fac0eSSudarsana Kalluru #define QEDE_RQSTAT(stat_name) \
30133fac0eSSudarsana Kalluru 	 {QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)}
3116f46bf0SSudarsana Reddy Kalluru 
3216f46bf0SSudarsana Reddy Kalluru #define QEDE_SELFTEST_POLL_COUNT 100
3316f46bf0SSudarsana Reddy Kalluru 
34133fac0eSSudarsana Kalluru static const struct {
35133fac0eSSudarsana Kalluru 	u64 offset;
36133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
37133fac0eSSudarsana Kalluru } qede_rqstats_arr[] = {
3868db9ec2SSudarsana Reddy Kalluru 	QEDE_RQSTAT(rcv_pkts),
39133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_hw_errors),
40133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_alloc_errors),
41c72a6125SManish Chopra 	QEDE_RQSTAT(rx_ip_frags),
42133fac0eSSudarsana Kalluru };
43133fac0eSSudarsana Kalluru 
44133fac0eSSudarsana Kalluru #define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr)
45133fac0eSSudarsana Kalluru #define QEDE_RQSTATS_DATA(dev, sindex, rqindex) \
46133fac0eSSudarsana Kalluru 	(*((u64 *)(((char *)(dev->fp_array[(rqindex)].rxq)) +\
47133fac0eSSudarsana Kalluru 		    qede_rqstats_arr[(sindex)].offset)))
4868db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_OFFSET(stat_name) \
4968db9ec2SSudarsana Reddy Kalluru 	(offsetof(struct qede_tx_queue, stat_name))
5068db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_STRING(stat_name) (#stat_name)
5168db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT(stat_name) \
5268db9ec2SSudarsana Reddy Kalluru 	{QEDE_TQSTAT_OFFSET(stat_name), QEDE_TQSTAT_STRING(stat_name)}
5368db9ec2SSudarsana Reddy Kalluru #define QEDE_NUM_TQSTATS ARRAY_SIZE(qede_tqstats_arr)
5468db9ec2SSudarsana Reddy Kalluru static const struct {
5568db9ec2SSudarsana Reddy Kalluru 	u64 offset;
5668db9ec2SSudarsana Reddy Kalluru 	char string[ETH_GSTRING_LEN];
5768db9ec2SSudarsana Reddy Kalluru } qede_tqstats_arr[] = {
5868db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(xmit_pkts),
5968db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(stopped_cnt),
6068db9ec2SSudarsana Reddy Kalluru };
6168db9ec2SSudarsana Reddy Kalluru 
6280439a17SMintz, Yuval #define QEDE_TQSTATS_DATA(dev, sindex, tssid) \
6380439a17SMintz, Yuval 	(*((u64 *)(((void *)((dev)->fp_array[tssid].txq)) + \
6468db9ec2SSudarsana Reddy Kalluru 		   qede_tqstats_arr[(sindex)].offset)))
6568db9ec2SSudarsana Reddy Kalluru 
66133fac0eSSudarsana Kalluru static const struct {
67133fac0eSSudarsana Kalluru 	u64 offset;
68133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
69133fac0eSSudarsana Kalluru 	bool pf_only;
70133fac0eSSudarsana Kalluru } qede_stats_arr[] = {
71133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_bytes),
72133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_bytes),
73133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_bytes),
74133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_pkts),
75133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_pkts),
76133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_pkts),
77133fac0eSSudarsana Kalluru 
78133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_bytes),
79133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_bytes),
80133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_bytes),
81133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_pkts),
82133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_pkts),
83133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_pkts),
84133fac0eSSudarsana Kalluru 
85133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_64_byte_packets),
86d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_65_to_127_byte_packets),
87d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_128_to_255_byte_packets),
88d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_256_to_511_byte_packets),
89d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_512_to_1023_byte_packets),
90d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1024_to_1518_byte_packets),
91d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1519_to_1522_byte_packets),
92d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1519_to_2047_byte_packets),
93d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_2048_to_4095_byte_packets),
94d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_4096_to_9216_byte_packets),
95d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_9217_to_16383_byte_packets),
96133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_64_byte_packets),
97133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_65_to_127_byte_packets),
98133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_128_to_255_byte_packets),
99133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_256_to_511_byte_packets),
100133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_512_to_1023_byte_packets),
101133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_1024_to_1518_byte_packets),
102133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_1519_to_2047_byte_packets),
103133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_2048_to_4095_byte_packets),
104133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_4096_to_9216_byte_packets),
105133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_9217_to_16383_byte_packets),
106133fac0eSSudarsana Kalluru 
107133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_mac_crtl_frames),
108133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_mac_ctrl_frames),
109133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pause_frames),
110133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pause_frames),
111133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pfc_frames),
112133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pfc_frames),
113133fac0eSSudarsana Kalluru 
114133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_crc_errors),
115133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_align_errors),
116133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_carrier_errors),
117133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_oversize_packets),
118133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_jabbers),
119133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_undersize_packets),
120133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_fragments),
121133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_lpi_entry_count),
122133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_total_collisions),
123133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_truncates),
124133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_discards),
125133fac0eSSudarsana Kalluru 	QEDE_STAT(no_buff_discards),
126133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mftag_filter_discards),
127133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mac_filter_discards),
128133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_err_drop_pkts),
1291a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(ttl0_discard),
1301a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(packet_too_big_discard),
131133fac0eSSudarsana Kalluru 
132133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_pkts),
133133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_events),
134133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_aborts_num),
135133fac0eSSudarsana Kalluru 	QEDE_STAT(non_coalesced_pkts),
136133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_bytes),
137133fac0eSSudarsana Kalluru };
138133fac0eSSudarsana Kalluru 
139133fac0eSSudarsana Kalluru #define QEDE_STATS_DATA(dev, index) \
140133fac0eSSudarsana Kalluru 	(*((u64 *)(((char *)(dev)) + offsetof(struct qede_dev, stats) \
141133fac0eSSudarsana Kalluru 			+ qede_stats_arr[(index)].offset)))
142133fac0eSSudarsana Kalluru 
143133fac0eSSudarsana Kalluru #define QEDE_NUM_STATS	ARRAY_SIZE(qede_stats_arr)
144133fac0eSSudarsana Kalluru 
145f3e72109SYuval Mintz enum {
146f3e72109SYuval Mintz 	QEDE_PRI_FLAG_CMT,
147f3e72109SYuval Mintz 	QEDE_PRI_FLAG_LEN,
148f3e72109SYuval Mintz };
149f3e72109SYuval Mintz 
150f3e72109SYuval Mintz static const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = {
151f3e72109SYuval Mintz 	"Coupled-Function",
152f3e72109SYuval Mintz };
153f3e72109SYuval Mintz 
1543044a02eSSudarsana Reddy Kalluru enum qede_ethtool_tests {
15516f46bf0SSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INT_LOOPBACK,
1563044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INTERRUPT_TEST,
1573044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_MEMORY_TEST,
1583044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_REGISTER_TEST,
1593044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_CLOCK_TEST,
1607a4b21b7SMintz, Yuval 	QEDE_ETHTOOL_NVRAM_TEST,
1613044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_TEST_MAX
1623044a02eSSudarsana Reddy Kalluru };
1633044a02eSSudarsana Reddy Kalluru 
1643044a02eSSudarsana Reddy Kalluru static const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = {
16516f46bf0SSudarsana Reddy Kalluru 	"Internal loopback (offline)",
1663044a02eSSudarsana Reddy Kalluru 	"Interrupt (online)\t",
1673044a02eSSudarsana Reddy Kalluru 	"Memory (online)\t\t",
1683044a02eSSudarsana Reddy Kalluru 	"Register (online)\t",
1693044a02eSSudarsana Reddy Kalluru 	"Clock (online)\t\t",
1707a4b21b7SMintz, Yuval 	"Nvram (online)\t\t",
1713044a02eSSudarsana Reddy Kalluru };
1723044a02eSSudarsana Reddy Kalluru 
173133fac0eSSudarsana Kalluru static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
174133fac0eSSudarsana Kalluru {
175133fac0eSSudarsana Kalluru 	int i, j, k;
176133fac0eSSudarsana Kalluru 
1779a4d7e86SSudarsana Reddy Kalluru 	for (i = 0, k = 0; i < QEDE_QUEUE_CNT(edev); i++) {
17868db9ec2SSudarsana Reddy Kalluru 
179cbbf049aSMintz, Yuval 		if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
18068db9ec2SSudarsana Reddy Kalluru 			for (j = 0; j < QEDE_NUM_RQSTATS; j++)
18168db9ec2SSudarsana Reddy Kalluru 				sprintf(buf + (k + j) * ETH_GSTRING_LEN,
182cbbf049aSMintz, Yuval 					"%d:   %s", i,
183cbbf049aSMintz, Yuval 					qede_rqstats_arr[j].string);
18468db9ec2SSudarsana Reddy Kalluru 			k += QEDE_NUM_RQSTATS;
185cbbf049aSMintz, Yuval 		}
186cbbf049aSMintz, Yuval 
187cbbf049aSMintz, Yuval 		if (edev->fp_array[i].type & QEDE_FASTPATH_TX) {
18868db9ec2SSudarsana Reddy Kalluru 			for (j = 0; j < QEDE_NUM_TQSTATS; j++)
189cbbf049aSMintz, Yuval 				sprintf(buf + (k + j) *
190cbbf049aSMintz, Yuval 					ETH_GSTRING_LEN,
19180439a17SMintz, Yuval 					"%d: %s", i,
19268db9ec2SSudarsana Reddy Kalluru 					qede_tqstats_arr[j].string);
19368db9ec2SSudarsana Reddy Kalluru 			k += QEDE_NUM_TQSTATS;
19468db9ec2SSudarsana Reddy Kalluru 		}
19568db9ec2SSudarsana Reddy Kalluru 	}
19668db9ec2SSudarsana Reddy Kalluru 
197133fac0eSSudarsana Kalluru 	for (i = 0, j = 0; i < QEDE_NUM_STATS; i++) {
198fefb0202SYuval Mintz 		if (IS_VF(edev) && qede_stats_arr[i].pf_only)
199fefb0202SYuval Mintz 			continue;
20068db9ec2SSudarsana Reddy Kalluru 		strcpy(buf + (k + j) * ETH_GSTRING_LEN,
201133fac0eSSudarsana Kalluru 		       qede_stats_arr[i].string);
202133fac0eSSudarsana Kalluru 		j++;
203133fac0eSSudarsana Kalluru 	}
204133fac0eSSudarsana Kalluru }
205133fac0eSSudarsana Kalluru 
206133fac0eSSudarsana Kalluru static void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
207133fac0eSSudarsana Kalluru {
208133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
209133fac0eSSudarsana Kalluru 
210133fac0eSSudarsana Kalluru 	switch (stringset) {
211133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
212133fac0eSSudarsana Kalluru 		qede_get_strings_stats(edev, buf);
213133fac0eSSudarsana Kalluru 		break;
214f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
215f3e72109SYuval Mintz 		memcpy(buf, qede_private_arr,
216f3e72109SYuval Mintz 		       ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN);
217f3e72109SYuval Mintz 		break;
2183044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
2193044a02eSSudarsana Reddy Kalluru 		memcpy(buf, qede_tests_str_arr,
2203044a02eSSudarsana Reddy Kalluru 		       ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX);
2213044a02eSSudarsana Reddy Kalluru 		break;
222133fac0eSSudarsana Kalluru 	default:
223133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
224133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
225133fac0eSSudarsana Kalluru 	}
226133fac0eSSudarsana Kalluru }
227133fac0eSSudarsana Kalluru 
228133fac0eSSudarsana Kalluru static void qede_get_ethtool_stats(struct net_device *dev,
229133fac0eSSudarsana Kalluru 				   struct ethtool_stats *stats, u64 *buf)
230133fac0eSSudarsana Kalluru {
231133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
232133fac0eSSudarsana Kalluru 	int sidx, cnt = 0;
233133fac0eSSudarsana Kalluru 	int qid;
234133fac0eSSudarsana Kalluru 
235133fac0eSSudarsana Kalluru 	qede_fill_by_demand_stats(edev);
236133fac0eSSudarsana Kalluru 
237133fac0eSSudarsana Kalluru 	mutex_lock(&edev->qede_lock);
238133fac0eSSudarsana Kalluru 
2399a4d7e86SSudarsana Reddy Kalluru 	for (qid = 0; qid < QEDE_QUEUE_CNT(edev); qid++) {
24068db9ec2SSudarsana Reddy Kalluru 
24180439a17SMintz, Yuval 		if (edev->fp_array[qid].type & QEDE_FASTPATH_RX)
24268db9ec2SSudarsana Reddy Kalluru 			for (sidx = 0; sidx < QEDE_NUM_RQSTATS; sidx++)
24368db9ec2SSudarsana Reddy Kalluru 				buf[cnt++] = QEDE_RQSTATS_DATA(edev, sidx, qid);
2449a4d7e86SSudarsana Reddy Kalluru 
24580439a17SMintz, Yuval 		if (edev->fp_array[qid].type & QEDE_FASTPATH_TX)
24668db9ec2SSudarsana Reddy Kalluru 			for (sidx = 0; sidx < QEDE_NUM_TQSTATS; sidx++)
2479a4d7e86SSudarsana Reddy Kalluru 				buf[cnt++] = QEDE_TQSTATS_DATA(edev,
2489a4d7e86SSudarsana Reddy Kalluru 							       sidx,
24980439a17SMintz, Yuval 							       qid);
25068db9ec2SSudarsana Reddy Kalluru 	}
25168db9ec2SSudarsana Reddy Kalluru 
252fefb0202SYuval Mintz 	for (sidx = 0; sidx < QEDE_NUM_STATS; sidx++) {
253fefb0202SYuval Mintz 		if (IS_VF(edev) && qede_stats_arr[sidx].pf_only)
254fefb0202SYuval Mintz 			continue;
255133fac0eSSudarsana Kalluru 		buf[cnt++] = QEDE_STATS_DATA(edev, sidx);
256fefb0202SYuval Mintz 	}
257133fac0eSSudarsana Kalluru 
258133fac0eSSudarsana Kalluru 	mutex_unlock(&edev->qede_lock);
259133fac0eSSudarsana Kalluru }
260133fac0eSSudarsana Kalluru 
261133fac0eSSudarsana Kalluru static int qede_get_sset_count(struct net_device *dev, int stringset)
262133fac0eSSudarsana Kalluru {
263133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
264133fac0eSSudarsana Kalluru 	int num_stats = QEDE_NUM_STATS;
265133fac0eSSudarsana Kalluru 
266133fac0eSSudarsana Kalluru 	switch (stringset) {
267133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
268fefb0202SYuval Mintz 		if (IS_VF(edev)) {
269fefb0202SYuval Mintz 			int i;
270fefb0202SYuval Mintz 
271fefb0202SYuval Mintz 			for (i = 0; i < QEDE_NUM_STATS; i++)
272fefb0202SYuval Mintz 				if (qede_stats_arr[i].pf_only)
273fefb0202SYuval Mintz 					num_stats--;
274fefb0202SYuval Mintz 		}
2759a4d7e86SSudarsana Reddy Kalluru 		return num_stats + QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS +
27680439a17SMintz, Yuval 		       QEDE_TSS_COUNT(edev) * QEDE_NUM_TQSTATS;
277f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
278f3e72109SYuval Mintz 		return QEDE_PRI_FLAG_LEN;
2793044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
2806ecb0a0cSYuval Mintz 		if (!IS_VF(edev))
2813044a02eSSudarsana Reddy Kalluru 			return QEDE_ETHTOOL_TEST_MAX;
2826ecb0a0cSYuval Mintz 		else
2836ecb0a0cSYuval Mintz 			return 0;
284133fac0eSSudarsana Kalluru 	default:
285133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
286133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
287133fac0eSSudarsana Kalluru 		return -EINVAL;
288133fac0eSSudarsana Kalluru 	}
289133fac0eSSudarsana Kalluru }
290133fac0eSSudarsana Kalluru 
291f3e72109SYuval Mintz static u32 qede_get_priv_flags(struct net_device *dev)
292f3e72109SYuval Mintz {
293f3e72109SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
294f3e72109SYuval Mintz 
295f3e72109SYuval Mintz 	return (!!(edev->dev_info.common.num_hwfns > 1)) << QEDE_PRI_FLAG_CMT;
296f3e72109SYuval Mintz }
297f3e72109SYuval Mintz 
298054c67d1SSudarsana Reddy Kalluru struct qede_link_mode_mapping {
299054c67d1SSudarsana Reddy Kalluru 	u32 qed_link_mode;
300054c67d1SSudarsana Reddy Kalluru 	u32 ethtool_link_mode;
301054c67d1SSudarsana Reddy Kalluru };
302054c67d1SSudarsana Reddy Kalluru 
303054c67d1SSudarsana Reddy Kalluru static const struct qede_link_mode_mapping qed_lm_map[] = {
304054c67d1SSudarsana Reddy Kalluru 	{QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
305054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
306054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT},
307054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
308054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT},
309054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
310054c67d1SSudarsana Reddy Kalluru 	{QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
311054c67d1SSudarsana Reddy Kalluru 	{QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
312054c67d1SSudarsana Reddy Kalluru 	{QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
313054c67d1SSudarsana Reddy Kalluru 	{QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT},
314054c67d1SSudarsana Reddy Kalluru 	{QED_LM_100000baseKR4_Full_BIT,
315054c67d1SSudarsana Reddy Kalluru 	 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
316054c67d1SSudarsana Reddy Kalluru };
317054c67d1SSudarsana Reddy Kalluru 
318054c67d1SSudarsana Reddy Kalluru #define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name)	\
319054c67d1SSudarsana Reddy Kalluru {								\
320054c67d1SSudarsana Reddy Kalluru 	int i;							\
321054c67d1SSudarsana Reddy Kalluru 								\
322d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
323054c67d1SSudarsana Reddy Kalluru 		if ((caps) & (qed_lm_map[i].qed_link_mode))	\
324054c67d1SSudarsana Reddy Kalluru 			__set_bit(qed_lm_map[i].ethtool_link_mode,\
325054c67d1SSudarsana Reddy Kalluru 				  lk_ksettings->link_modes.name); \
326054c67d1SSudarsana Reddy Kalluru 	}							\
327054c67d1SSudarsana Reddy Kalluru }
328054c67d1SSudarsana Reddy Kalluru 
329054c67d1SSudarsana Reddy Kalluru #define QEDE_ETHTOOL_TO_DRV_CAPS(caps, lk_ksettings, name)	\
330054c67d1SSudarsana Reddy Kalluru {								\
331054c67d1SSudarsana Reddy Kalluru 	int i;							\
332054c67d1SSudarsana Reddy Kalluru 								\
333d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
334054c67d1SSudarsana Reddy Kalluru 		if (test_bit(qed_lm_map[i].ethtool_link_mode,	\
335054c67d1SSudarsana Reddy Kalluru 			     lk_ksettings->link_modes.name))	\
336054c67d1SSudarsana Reddy Kalluru 			caps |= qed_lm_map[i].qed_link_mode;	\
337054c67d1SSudarsana Reddy Kalluru 	}							\
338054c67d1SSudarsana Reddy Kalluru }
339054c67d1SSudarsana Reddy Kalluru 
340054c67d1SSudarsana Reddy Kalluru static int qede_get_link_ksettings(struct net_device *dev,
341054c67d1SSudarsana Reddy Kalluru 				   struct ethtool_link_ksettings *cmd)
342133fac0eSSudarsana Kalluru {
343054c67d1SSudarsana Reddy Kalluru 	struct ethtool_link_settings *base = &cmd->base;
344133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
345133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
346133fac0eSSudarsana Kalluru 
347133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
348133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
349133fac0eSSudarsana Kalluru 
350054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
351054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.supported_caps, cmd, supported)
352054c67d1SSudarsana Reddy Kalluru 
353054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
354054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.advertised_caps, cmd, advertising)
355054c67d1SSudarsana Reddy Kalluru 
356054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
357054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.lp_caps, cmd, lp_advertising)
358054c67d1SSudarsana Reddy Kalluru 
359133fac0eSSudarsana Kalluru 	if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) {
360054c67d1SSudarsana Reddy Kalluru 		base->speed = current_link.speed;
361054c67d1SSudarsana Reddy Kalluru 		base->duplex = current_link.duplex;
362133fac0eSSudarsana Kalluru 	} else {
363054c67d1SSudarsana Reddy Kalluru 		base->speed = SPEED_UNKNOWN;
364054c67d1SSudarsana Reddy Kalluru 		base->duplex = DUPLEX_UNKNOWN;
365133fac0eSSudarsana Kalluru 	}
366054c67d1SSudarsana Reddy Kalluru 	base->port = current_link.port;
367054c67d1SSudarsana Reddy Kalluru 	base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE :
368133fac0eSSudarsana Kalluru 			AUTONEG_DISABLE;
369133fac0eSSudarsana Kalluru 
370133fac0eSSudarsana Kalluru 	return 0;
371133fac0eSSudarsana Kalluru }
372133fac0eSSudarsana Kalluru 
373054c67d1SSudarsana Reddy Kalluru static int qede_set_link_ksettings(struct net_device *dev,
374054c67d1SSudarsana Reddy Kalluru 				   const struct ethtool_link_ksettings *cmd)
375133fac0eSSudarsana Kalluru {
376054c67d1SSudarsana Reddy Kalluru 	const struct ethtool_link_settings *base = &cmd->base;
377133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
378133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
379133fac0eSSudarsana Kalluru 	struct qed_link_params params;
380133fac0eSSudarsana Kalluru 
381fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
382054c67d1SSudarsana Reddy Kalluru 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
383133fac0eSSudarsana Kalluru 		return -EOPNOTSUPP;
384133fac0eSSudarsana Kalluru 	}
385133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
386133fac0eSSudarsana Kalluru 	memset(&params, 0, sizeof(params));
387133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
388133fac0eSSudarsana Kalluru 
389133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS;
390133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG;
391054c67d1SSudarsana Reddy Kalluru 	if (base->autoneg == AUTONEG_ENABLE) {
392133fac0eSSudarsana Kalluru 		params.autoneg = true;
393133fac0eSSudarsana Kalluru 		params.forced_speed = 0;
394054c67d1SSudarsana Reddy Kalluru 		QEDE_ETHTOOL_TO_DRV_CAPS(params.adv_speeds, cmd, advertising)
395133fac0eSSudarsana Kalluru 	} else {		/* forced speed */
396133fac0eSSudarsana Kalluru 		params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED;
397133fac0eSSudarsana Kalluru 		params.autoneg = false;
398054c67d1SSudarsana Reddy Kalluru 		params.forced_speed = base->speed;
399054c67d1SSudarsana Reddy Kalluru 		switch (base->speed) {
400133fac0eSSudarsana Kalluru 		case SPEED_10000:
401133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
402054c67d1SSudarsana Reddy Kalluru 			      QED_LM_10000baseKR_Full_BIT)) {
403133fac0eSSudarsana Kalluru 				DP_INFO(edev, "10G speed not supported\n");
404133fac0eSSudarsana Kalluru 				return -EINVAL;
405133fac0eSSudarsana Kalluru 			}
406054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_10000baseKR_Full_BIT;
407054c67d1SSudarsana Reddy Kalluru 			break;
408054c67d1SSudarsana Reddy Kalluru 		case SPEED_25000:
409054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
410054c67d1SSudarsana Reddy Kalluru 			      QED_LM_25000baseKR_Full_BIT)) {
411054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "25G speed not supported\n");
412054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
413054c67d1SSudarsana Reddy Kalluru 			}
414054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_25000baseKR_Full_BIT;
415133fac0eSSudarsana Kalluru 			break;
416133fac0eSSudarsana Kalluru 		case SPEED_40000:
417133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
418054c67d1SSudarsana Reddy Kalluru 			      QED_LM_40000baseLR4_Full_BIT)) {
419133fac0eSSudarsana Kalluru 				DP_INFO(edev, "40G speed not supported\n");
420133fac0eSSudarsana Kalluru 				return -EINVAL;
421133fac0eSSudarsana Kalluru 			}
422054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_40000baseLR4_Full_BIT;
423054c67d1SSudarsana Reddy Kalluru 			break;
42416d5946aSYuval Mintz 		case SPEED_50000:
425054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
426054c67d1SSudarsana Reddy Kalluru 			      QED_LM_50000baseKR2_Full_BIT)) {
427054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "50G speed not supported\n");
428054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
429054c67d1SSudarsana Reddy Kalluru 			}
430054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_50000baseKR2_Full_BIT;
431054c67d1SSudarsana Reddy Kalluru 			break;
43216d5946aSYuval Mintz 		case SPEED_100000:
433054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
434054c67d1SSudarsana Reddy Kalluru 			      QED_LM_100000baseKR4_Full_BIT)) {
435054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "100G speed not supported\n");
436054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
437054c67d1SSudarsana Reddy Kalluru 			}
438054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_100000baseKR4_Full_BIT;
439133fac0eSSudarsana Kalluru 			break;
440133fac0eSSudarsana Kalluru 		default:
441054c67d1SSudarsana Reddy Kalluru 			DP_INFO(edev, "Unsupported speed %u\n", base->speed);
442133fac0eSSudarsana Kalluru 			return -EINVAL;
443133fac0eSSudarsana Kalluru 		}
444133fac0eSSudarsana Kalluru 	}
445133fac0eSSudarsana Kalluru 
446133fac0eSSudarsana Kalluru 	params.link_up = true;
447133fac0eSSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
448133fac0eSSudarsana Kalluru 
449133fac0eSSudarsana Kalluru 	return 0;
450133fac0eSSudarsana Kalluru }
451133fac0eSSudarsana Kalluru 
452133fac0eSSudarsana Kalluru static void qede_get_drvinfo(struct net_device *ndev,
453133fac0eSSudarsana Kalluru 			     struct ethtool_drvinfo *info)
454133fac0eSSudarsana Kalluru {
455133fac0eSSudarsana Kalluru 	char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN];
456133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
457133fac0eSSudarsana Kalluru 
458133fac0eSSudarsana Kalluru 	strlcpy(info->driver, "qede", sizeof(info->driver));
459133fac0eSSudarsana Kalluru 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
460133fac0eSSudarsana Kalluru 
461133fac0eSSudarsana Kalluru 	snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
462133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_major,
463133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_minor,
464133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_rev,
465133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_eng);
466133fac0eSSudarsana Kalluru 
467133fac0eSSudarsana Kalluru 	snprintf(mfw, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
468133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 24) & 0xFF,
469133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 16) & 0xFF,
470133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 8) & 0xFF,
471133fac0eSSudarsana Kalluru 		 edev->dev_info.common.mfw_rev & 0xFF);
472133fac0eSSudarsana Kalluru 
473133fac0eSSudarsana Kalluru 	if ((strlen(storm) + strlen(mfw) + strlen("mfw storm  ")) <
474133fac0eSSudarsana Kalluru 	    sizeof(info->fw_version)) {
475133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
476133fac0eSSudarsana Kalluru 			 "mfw %s storm %s", mfw, storm);
477133fac0eSSudarsana Kalluru 	} else {
478133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
479133fac0eSSudarsana Kalluru 			 "%s %s", mfw, storm);
480133fac0eSSudarsana Kalluru 	}
481133fac0eSSudarsana Kalluru 
482133fac0eSSudarsana Kalluru 	strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info));
483133fac0eSSudarsana Kalluru }
484133fac0eSSudarsana Kalluru 
48514d39648SMintz, Yuval static void qede_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
48614d39648SMintz, Yuval {
48714d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
48814d39648SMintz, Yuval 
48914d39648SMintz, Yuval 	if (edev->dev_info.common.wol_support) {
49014d39648SMintz, Yuval 		wol->supported = WAKE_MAGIC;
49114d39648SMintz, Yuval 		wol->wolopts = edev->wol_enabled ? WAKE_MAGIC : 0;
49214d39648SMintz, Yuval 	}
49314d39648SMintz, Yuval }
49414d39648SMintz, Yuval 
49514d39648SMintz, Yuval static int qede_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
49614d39648SMintz, Yuval {
49714d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
49814d39648SMintz, Yuval 	bool wol_requested;
49914d39648SMintz, Yuval 	int rc;
50014d39648SMintz, Yuval 
50114d39648SMintz, Yuval 	if (wol->wolopts & ~WAKE_MAGIC) {
50214d39648SMintz, Yuval 		DP_INFO(edev,
50314d39648SMintz, Yuval 			"Can't support WoL options other than magic-packet\n");
50414d39648SMintz, Yuval 		return -EINVAL;
50514d39648SMintz, Yuval 	}
50614d39648SMintz, Yuval 
50714d39648SMintz, Yuval 	wol_requested = !!(wol->wolopts & WAKE_MAGIC);
50814d39648SMintz, Yuval 	if (wol_requested == edev->wol_enabled)
50914d39648SMintz, Yuval 		return 0;
51014d39648SMintz, Yuval 
51114d39648SMintz, Yuval 	/* Need to actually change configuration */
51214d39648SMintz, Yuval 	if (!edev->dev_info.common.wol_support) {
51314d39648SMintz, Yuval 		DP_INFO(edev, "Device doesn't support WoL\n");
51414d39648SMintz, Yuval 		return -EINVAL;
51514d39648SMintz, Yuval 	}
51614d39648SMintz, Yuval 
51714d39648SMintz, Yuval 	rc = edev->ops->common->update_wol(edev->cdev, wol_requested);
51814d39648SMintz, Yuval 	if (!rc)
51914d39648SMintz, Yuval 		edev->wol_enabled = wol_requested;
52014d39648SMintz, Yuval 
52114d39648SMintz, Yuval 	return rc;
52214d39648SMintz, Yuval }
52314d39648SMintz, Yuval 
524133fac0eSSudarsana Kalluru static u32 qede_get_msglevel(struct net_device *ndev)
525133fac0eSSudarsana Kalluru {
526133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
527133fac0eSSudarsana Kalluru 
5281a635e48SYuval Mintz 	return ((u32)edev->dp_level << QED_LOG_LEVEL_SHIFT) | edev->dp_module;
529133fac0eSSudarsana Kalluru }
530133fac0eSSudarsana Kalluru 
531133fac0eSSudarsana Kalluru static void qede_set_msglevel(struct net_device *ndev, u32 level)
532133fac0eSSudarsana Kalluru {
533133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
534133fac0eSSudarsana Kalluru 	u32 dp_module = 0;
535133fac0eSSudarsana Kalluru 	u8 dp_level = 0;
536133fac0eSSudarsana Kalluru 
537133fac0eSSudarsana Kalluru 	qede_config_debug(level, &dp_module, &dp_level);
538133fac0eSSudarsana Kalluru 
539133fac0eSSudarsana Kalluru 	edev->dp_level = dp_level;
540133fac0eSSudarsana Kalluru 	edev->dp_module = dp_module;
541133fac0eSSudarsana Kalluru 	edev->ops->common->update_msglvl(edev->cdev,
542133fac0eSSudarsana Kalluru 					 dp_module, dp_level);
543133fac0eSSudarsana Kalluru }
544133fac0eSSudarsana Kalluru 
54532a7a570SSudarsana Kalluru static int qede_nway_reset(struct net_device *dev)
54632a7a570SSudarsana Kalluru {
54732a7a570SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
54832a7a570SSudarsana Kalluru 	struct qed_link_output current_link;
54932a7a570SSudarsana Kalluru 	struct qed_link_params link_params;
55032a7a570SSudarsana Kalluru 
551fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
5521a635e48SYuval Mintz 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
553fe7cd2bfSYuval Mintz 		return -EOPNOTSUPP;
554fe7cd2bfSYuval Mintz 	}
555fe7cd2bfSYuval Mintz 
55632a7a570SSudarsana Kalluru 	if (!netif_running(dev))
55732a7a570SSudarsana Kalluru 		return 0;
55832a7a570SSudarsana Kalluru 
55932a7a570SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
56032a7a570SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
56132a7a570SSudarsana Kalluru 	if (!current_link.link_up)
56232a7a570SSudarsana Kalluru 		return 0;
56332a7a570SSudarsana Kalluru 
56432a7a570SSudarsana Kalluru 	/* Toggle the link */
56532a7a570SSudarsana Kalluru 	memset(&link_params, 0, sizeof(link_params));
56632a7a570SSudarsana Kalluru 	link_params.link_up = false;
56732a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
56832a7a570SSudarsana Kalluru 	link_params.link_up = true;
56932a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
57032a7a570SSudarsana Kalluru 
57132a7a570SSudarsana Kalluru 	return 0;
57232a7a570SSudarsana Kalluru }
57332a7a570SSudarsana Kalluru 
574133fac0eSSudarsana Kalluru static u32 qede_get_link(struct net_device *dev)
575133fac0eSSudarsana Kalluru {
576133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
577133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
578133fac0eSSudarsana Kalluru 
579133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
580133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
581133fac0eSSudarsana Kalluru 
582133fac0eSSudarsana Kalluru 	return current_link.link_up;
583133fac0eSSudarsana Kalluru }
584133fac0eSSudarsana Kalluru 
585d552fa84SSudarsana Reddy Kalluru static int qede_get_coalesce(struct net_device *dev,
586d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
587d552fa84SSudarsana Reddy Kalluru {
588d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
589d2890deaSSudarsana Reddy Kalluru 	u16 rxc, txc;
590d552fa84SSudarsana Reddy Kalluru 
591d552fa84SSudarsana Reddy Kalluru 	memset(coal, 0, sizeof(struct ethtool_coalesce));
592d2890deaSSudarsana Reddy Kalluru 	edev->ops->common->get_coalesce(edev->cdev, &rxc, &txc);
593d2890deaSSudarsana Reddy Kalluru 
594d2890deaSSudarsana Reddy Kalluru 	coal->rx_coalesce_usecs = rxc;
595d2890deaSSudarsana Reddy Kalluru 	coal->tx_coalesce_usecs = txc;
596d552fa84SSudarsana Reddy Kalluru 
597d552fa84SSudarsana Reddy Kalluru 	return 0;
598d552fa84SSudarsana Reddy Kalluru }
599d552fa84SSudarsana Reddy Kalluru 
600d552fa84SSudarsana Reddy Kalluru static int qede_set_coalesce(struct net_device *dev,
601d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
602d552fa84SSudarsana Reddy Kalluru {
603d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
604d552fa84SSudarsana Reddy Kalluru 	int i, rc = 0;
605d552fa84SSudarsana Reddy Kalluru 	u16 rxc, txc;
606d552fa84SSudarsana Reddy Kalluru 	u8 sb_id;
607d552fa84SSudarsana Reddy Kalluru 
608d552fa84SSudarsana Reddy Kalluru 	if (!netif_running(dev)) {
609d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev, "Interface is down\n");
610d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
611d552fa84SSudarsana Reddy Kalluru 	}
612d552fa84SSudarsana Reddy Kalluru 
613d552fa84SSudarsana Reddy Kalluru 	if (coal->rx_coalesce_usecs > QED_COALESCE_MAX ||
614d552fa84SSudarsana Reddy Kalluru 	    coal->tx_coalesce_usecs > QED_COALESCE_MAX) {
615d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev,
616d552fa84SSudarsana Reddy Kalluru 			"Can't support requested %s coalesce value [max supported value %d]\n",
617d552fa84SSudarsana Reddy Kalluru 			coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx"
618d552fa84SSudarsana Reddy Kalluru 								   : "tx",
619d552fa84SSudarsana Reddy Kalluru 			QED_COALESCE_MAX);
620d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
621d552fa84SSudarsana Reddy Kalluru 	}
622d552fa84SSudarsana Reddy Kalluru 
623d552fa84SSudarsana Reddy Kalluru 	rxc = (u16)coal->rx_coalesce_usecs;
624d552fa84SSudarsana Reddy Kalluru 	txc = (u16)coal->tx_coalesce_usecs;
6259a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
626d552fa84SSudarsana Reddy Kalluru 		sb_id = edev->fp_array[i].sb_info->igu_sb_id;
627d552fa84SSudarsana Reddy Kalluru 		rc = edev->ops->common->set_coalesce(edev->cdev, rxc, txc,
628d552fa84SSudarsana Reddy Kalluru 						     (u8)i, sb_id);
629d552fa84SSudarsana Reddy Kalluru 		if (rc) {
630d552fa84SSudarsana Reddy Kalluru 			DP_INFO(edev, "Set coalesce error, rc = %d\n", rc);
631d552fa84SSudarsana Reddy Kalluru 			return rc;
632d552fa84SSudarsana Reddy Kalluru 		}
633d552fa84SSudarsana Reddy Kalluru 	}
634d552fa84SSudarsana Reddy Kalluru 
635d552fa84SSudarsana Reddy Kalluru 	return rc;
636d552fa84SSudarsana Reddy Kalluru }
637d552fa84SSudarsana Reddy Kalluru 
63801ef7e05SSudarsana Kalluru static void qede_get_ringparam(struct net_device *dev,
63901ef7e05SSudarsana Kalluru 			       struct ethtool_ringparam *ering)
64001ef7e05SSudarsana Kalluru {
64101ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
64201ef7e05SSudarsana Kalluru 
64301ef7e05SSudarsana Kalluru 	ering->rx_max_pending = NUM_RX_BDS_MAX;
64401ef7e05SSudarsana Kalluru 	ering->rx_pending = edev->q_num_rx_buffers;
64501ef7e05SSudarsana Kalluru 	ering->tx_max_pending = NUM_TX_BDS_MAX;
64601ef7e05SSudarsana Kalluru 	ering->tx_pending = edev->q_num_tx_buffers;
64701ef7e05SSudarsana Kalluru }
64801ef7e05SSudarsana Kalluru 
64901ef7e05SSudarsana Kalluru static int qede_set_ringparam(struct net_device *dev,
65001ef7e05SSudarsana Kalluru 			      struct ethtool_ringparam *ering)
65101ef7e05SSudarsana Kalluru {
65201ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
65301ef7e05SSudarsana Kalluru 
65401ef7e05SSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
65501ef7e05SSudarsana Kalluru 		   "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
65601ef7e05SSudarsana Kalluru 		   ering->rx_pending, ering->tx_pending);
65701ef7e05SSudarsana Kalluru 
65801ef7e05SSudarsana Kalluru 	/* Validate legality of configuration */
65901ef7e05SSudarsana Kalluru 	if (ering->rx_pending > NUM_RX_BDS_MAX ||
66001ef7e05SSudarsana Kalluru 	    ering->rx_pending < NUM_RX_BDS_MIN ||
66101ef7e05SSudarsana Kalluru 	    ering->tx_pending > NUM_TX_BDS_MAX ||
66201ef7e05SSudarsana Kalluru 	    ering->tx_pending < NUM_TX_BDS_MIN) {
66301ef7e05SSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
66401ef7e05SSudarsana Kalluru 			   "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n",
66501ef7e05SSudarsana Kalluru 			   NUM_RX_BDS_MIN, NUM_RX_BDS_MAX,
66601ef7e05SSudarsana Kalluru 			   NUM_TX_BDS_MIN, NUM_TX_BDS_MAX);
66701ef7e05SSudarsana Kalluru 		return -EINVAL;
66801ef7e05SSudarsana Kalluru 	}
66901ef7e05SSudarsana Kalluru 
67001ef7e05SSudarsana Kalluru 	/* Change ring size and re-load */
67101ef7e05SSudarsana Kalluru 	edev->q_num_rx_buffers = ering->rx_pending;
67201ef7e05SSudarsana Kalluru 	edev->q_num_tx_buffers = ering->tx_pending;
67301ef7e05SSudarsana Kalluru 
67401ef7e05SSudarsana Kalluru 	if (netif_running(edev->ndev))
67501ef7e05SSudarsana Kalluru 		qede_reload(edev, NULL, NULL);
67601ef7e05SSudarsana Kalluru 
67701ef7e05SSudarsana Kalluru 	return 0;
67801ef7e05SSudarsana Kalluru }
67901ef7e05SSudarsana Kalluru 
6800f7db144SSudarsana Kalluru static void qede_get_pauseparam(struct net_device *dev,
6810f7db144SSudarsana Kalluru 				struct ethtool_pauseparam *epause)
6820f7db144SSudarsana Kalluru {
6830f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
6840f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
6850f7db144SSudarsana Kalluru 
6860f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
6870f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
6880f7db144SSudarsana Kalluru 
6890f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE)
6900f7db144SSudarsana Kalluru 		epause->autoneg = true;
6910f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE)
6920f7db144SSudarsana Kalluru 		epause->rx_pause = true;
6930f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE)
6940f7db144SSudarsana Kalluru 		epause->tx_pause = true;
6950f7db144SSudarsana Kalluru 
6960f7db144SSudarsana Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
6970f7db144SSudarsana Kalluru 		   "ethtool_pauseparam: cmd %d  autoneg %d  rx_pause %d  tx_pause %d\n",
6980f7db144SSudarsana Kalluru 		   epause->cmd, epause->autoneg, epause->rx_pause,
6990f7db144SSudarsana Kalluru 		   epause->tx_pause);
7000f7db144SSudarsana Kalluru }
7010f7db144SSudarsana Kalluru 
7020f7db144SSudarsana Kalluru static int qede_set_pauseparam(struct net_device *dev,
7030f7db144SSudarsana Kalluru 			       struct ethtool_pauseparam *epause)
7040f7db144SSudarsana Kalluru {
7050f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
7060f7db144SSudarsana Kalluru 	struct qed_link_params params;
7070f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
7080f7db144SSudarsana Kalluru 
709fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
7100f7db144SSudarsana Kalluru 		DP_INFO(edev,
711fe7cd2bfSYuval Mintz 			"Pause settings are not allowed to be changed\n");
7120f7db144SSudarsana Kalluru 		return -EOPNOTSUPP;
7130f7db144SSudarsana Kalluru 	}
7140f7db144SSudarsana Kalluru 
7150f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
7160f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
7170f7db144SSudarsana Kalluru 
7180f7db144SSudarsana Kalluru 	memset(&params, 0, sizeof(params));
7190f7db144SSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG;
7200f7db144SSudarsana Kalluru 	if (epause->autoneg) {
721d194fd26SYuval Mintz 		if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
7220f7db144SSudarsana Kalluru 			DP_INFO(edev, "autoneg not supported\n");
7230f7db144SSudarsana Kalluru 			return -EINVAL;
7240f7db144SSudarsana Kalluru 		}
7250f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE;
7260f7db144SSudarsana Kalluru 	}
7270f7db144SSudarsana Kalluru 	if (epause->rx_pause)
7280f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_RX_ENABLE;
7290f7db144SSudarsana Kalluru 	if (epause->tx_pause)
7300f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_TX_ENABLE;
7310f7db144SSudarsana Kalluru 
7320f7db144SSudarsana Kalluru 	params.link_up = true;
7330f7db144SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
7340f7db144SSudarsana Kalluru 
7350f7db144SSudarsana Kalluru 	return 0;
7360f7db144SSudarsana Kalluru }
7370f7db144SSudarsana Kalluru 
738e0971c83STomer Tayar static void qede_get_regs(struct net_device *ndev,
739e0971c83STomer Tayar 			  struct ethtool_regs *regs, void *buffer)
740e0971c83STomer Tayar {
741e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
742e0971c83STomer Tayar 
743e0971c83STomer Tayar 	regs->version = 0;
744e0971c83STomer Tayar 	memset(buffer, 0, regs->len);
745e0971c83STomer Tayar 
746e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
747e0971c83STomer Tayar 		edev->ops->common->dbg_all_data(edev->cdev, buffer);
748e0971c83STomer Tayar }
749e0971c83STomer Tayar 
750e0971c83STomer Tayar static int qede_get_regs_len(struct net_device *ndev)
751e0971c83STomer Tayar {
752e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
753e0971c83STomer Tayar 
754e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
755e0971c83STomer Tayar 		return edev->ops->common->dbg_all_data_size(edev->cdev);
756e0971c83STomer Tayar 	else
757e0971c83STomer Tayar 		return -EINVAL;
758e0971c83STomer Tayar }
759e0971c83STomer Tayar 
760133fac0eSSudarsana Kalluru static void qede_update_mtu(struct qede_dev *edev, union qede_reload_args *args)
761133fac0eSSudarsana Kalluru {
762133fac0eSSudarsana Kalluru 	edev->ndev->mtu = args->mtu;
763133fac0eSSudarsana Kalluru }
764133fac0eSSudarsana Kalluru 
765133fac0eSSudarsana Kalluru /* Netdevice NDOs */
766133fac0eSSudarsana Kalluru int qede_change_mtu(struct net_device *ndev, int new_mtu)
767133fac0eSSudarsana Kalluru {
768133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
769133fac0eSSudarsana Kalluru 	union qede_reload_args args;
770133fac0eSSudarsana Kalluru 
771133fac0eSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
772133fac0eSSudarsana Kalluru 		   "Configuring MTU size of %d\n", new_mtu);
773133fac0eSSudarsana Kalluru 
774133fac0eSSudarsana Kalluru 	/* Set the mtu field and re-start the interface if needed*/
775133fac0eSSudarsana Kalluru 	args.mtu = new_mtu;
776133fac0eSSudarsana Kalluru 
777133fac0eSSudarsana Kalluru 	if (netif_running(edev->ndev))
778133fac0eSSudarsana Kalluru 		qede_reload(edev, &qede_update_mtu, &args);
779133fac0eSSudarsana Kalluru 
780133fac0eSSudarsana Kalluru 	qede_update_mtu(edev, &args);
781133fac0eSSudarsana Kalluru 
7820fefbfbaSSudarsana Kalluru 	edev->ops->common->update_mtu(edev->cdev, args.mtu);
7830fefbfbaSSudarsana Kalluru 
784133fac0eSSudarsana Kalluru 	return 0;
785133fac0eSSudarsana Kalluru }
786133fac0eSSudarsana Kalluru 
7878edf049dSSudarsana Kalluru static void qede_get_channels(struct net_device *dev,
7888edf049dSSudarsana Kalluru 			      struct ethtool_channels *channels)
7898edf049dSSudarsana Kalluru {
7908edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
7918edf049dSSudarsana Kalluru 
7928edf049dSSudarsana Kalluru 	channels->max_combined = QEDE_MAX_RSS_CNT(edev);
793bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_rx = QEDE_MAX_RSS_CNT(edev);
794bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_tx = QEDE_MAX_RSS_CNT(edev);
7959a4d7e86SSudarsana Reddy Kalluru 	channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx -
7969a4d7e86SSudarsana Reddy Kalluru 					edev->fp_num_rx;
7979a4d7e86SSudarsana Reddy Kalluru 	channels->tx_count = edev->fp_num_tx;
7989a4d7e86SSudarsana Reddy Kalluru 	channels->rx_count = edev->fp_num_rx;
7998edf049dSSudarsana Kalluru }
8008edf049dSSudarsana Kalluru 
8018edf049dSSudarsana Kalluru static int qede_set_channels(struct net_device *dev,
8028edf049dSSudarsana Kalluru 			     struct ethtool_channels *channels)
8038edf049dSSudarsana Kalluru {
8048edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
8059a4d7e86SSudarsana Reddy Kalluru 	u32 count;
8068edf049dSSudarsana Kalluru 
8078edf049dSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8088edf049dSSudarsana Kalluru 		   "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n",
8098edf049dSSudarsana Kalluru 		   channels->rx_count, channels->tx_count,
8108edf049dSSudarsana Kalluru 		   channels->other_count, channels->combined_count);
8118edf049dSSudarsana Kalluru 
8129a4d7e86SSudarsana Reddy Kalluru 	count = channels->rx_count + channels->tx_count +
8139a4d7e86SSudarsana Reddy Kalluru 			channels->combined_count;
8149a4d7e86SSudarsana Reddy Kalluru 
8159a4d7e86SSudarsana Reddy Kalluru 	/* We don't support `other' channels */
8169a4d7e86SSudarsana Reddy Kalluru 	if (channels->other_count) {
8178edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8188edf049dSSudarsana Kalluru 			   "command parameters not supported\n");
8198edf049dSSudarsana Kalluru 		return -EINVAL;
8208edf049dSSudarsana Kalluru 	}
8218edf049dSSudarsana Kalluru 
8229a4d7e86SSudarsana Reddy Kalluru 	if (!(channels->combined_count || (channels->rx_count &&
8239a4d7e86SSudarsana Reddy Kalluru 					   channels->tx_count))) {
8249a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8259a4d7e86SSudarsana Reddy Kalluru 			   "need to request at least one transmit and one receive channel\n");
8269a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
8279a4d7e86SSudarsana Reddy Kalluru 	}
8289a4d7e86SSudarsana Reddy Kalluru 
8299a4d7e86SSudarsana Reddy Kalluru 	if (count > QEDE_MAX_RSS_CNT(edev)) {
8309a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8319a4d7e86SSudarsana Reddy Kalluru 			   "requested channels = %d max supported channels = %d\n",
8329a4d7e86SSudarsana Reddy Kalluru 			   count, QEDE_MAX_RSS_CNT(edev));
8339a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
8349a4d7e86SSudarsana Reddy Kalluru 	}
8359a4d7e86SSudarsana Reddy Kalluru 
8368edf049dSSudarsana Kalluru 	/* Check if there was a change in the active parameters */
8379a4d7e86SSudarsana Reddy Kalluru 	if ((count == QEDE_QUEUE_CNT(edev)) &&
8389a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count == edev->fp_num_tx) &&
8399a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count == edev->fp_num_rx)) {
8408edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8418edf049dSSudarsana Kalluru 			   "No change in active parameters\n");
8428edf049dSSudarsana Kalluru 		return 0;
8438edf049dSSudarsana Kalluru 	}
8448edf049dSSudarsana Kalluru 
8458edf049dSSudarsana Kalluru 	/* We need the number of queues to be divisible between the hwfns */
8469a4d7e86SSudarsana Reddy Kalluru 	if ((count % edev->dev_info.common.num_hwfns) ||
8479a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count % edev->dev_info.common.num_hwfns) ||
8489a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count % edev->dev_info.common.num_hwfns)) {
8498edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
8509a4d7e86SSudarsana Reddy Kalluru 			   "Number of channels must be divisible by %04x\n",
8518edf049dSSudarsana Kalluru 			   edev->dev_info.common.num_hwfns);
8528edf049dSSudarsana Kalluru 		return -EINVAL;
8538edf049dSSudarsana Kalluru 	}
8548edf049dSSudarsana Kalluru 
8558edf049dSSudarsana Kalluru 	/* Set number of queues and reload if necessary */
8569a4d7e86SSudarsana Reddy Kalluru 	edev->req_queues = count;
8579a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_tx = channels->tx_count;
8589a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_rx = channels->rx_count;
859ed0dd915SSudarsana Reddy Kalluru 	/* Reset the indirection table if rx queue count is updated */
860ed0dd915SSudarsana Reddy Kalluru 	if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) {
861ed0dd915SSudarsana Reddy Kalluru 		edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED;
862ed0dd915SSudarsana Reddy Kalluru 		memset(&edev->rss_params.rss_ind_table, 0,
863ed0dd915SSudarsana Reddy Kalluru 		       sizeof(edev->rss_params.rss_ind_table));
864ed0dd915SSudarsana Reddy Kalluru 	}
865ed0dd915SSudarsana Reddy Kalluru 
8668edf049dSSudarsana Kalluru 	if (netif_running(dev))
8678edf049dSSudarsana Kalluru 		qede_reload(edev, NULL, NULL);
8688edf049dSSudarsana Kalluru 
8698edf049dSSudarsana Kalluru 	return 0;
8708edf049dSSudarsana Kalluru }
8718edf049dSSudarsana Kalluru 
8723d971cbdSSudarsana Kalluru static int qede_set_phys_id(struct net_device *dev,
8733d971cbdSSudarsana Kalluru 			    enum ethtool_phys_id_state state)
8743d971cbdSSudarsana Kalluru {
8753d971cbdSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
8763d971cbdSSudarsana Kalluru 	u8 led_state = 0;
8773d971cbdSSudarsana Kalluru 
8783d971cbdSSudarsana Kalluru 	switch (state) {
8793d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ACTIVE:
8803d971cbdSSudarsana Kalluru 		return 1;	/* cycle on/off once per second */
8813d971cbdSSudarsana Kalluru 
8823d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ON:
8833d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_ON;
8843d971cbdSSudarsana Kalluru 		break;
8853d971cbdSSudarsana Kalluru 
8863d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_OFF:
8873d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_OFF;
8883d971cbdSSudarsana Kalluru 		break;
8893d971cbdSSudarsana Kalluru 
8903d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_INACTIVE:
8913d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_RESTORE;
8923d971cbdSSudarsana Kalluru 		break;
8933d971cbdSSudarsana Kalluru 	}
8943d971cbdSSudarsana Kalluru 
8953d971cbdSSudarsana Kalluru 	edev->ops->common->set_led(edev->cdev, led_state);
8963d971cbdSSudarsana Kalluru 
8973d971cbdSSudarsana Kalluru 	return 0;
8983d971cbdSSudarsana Kalluru }
8993d971cbdSSudarsana Kalluru 
900961acdeaSSudarsana Reddy Kalluru static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
901961acdeaSSudarsana Reddy Kalluru {
902961acdeaSSudarsana Reddy Kalluru 	info->data = RXH_IP_SRC | RXH_IP_DST;
903961acdeaSSudarsana Reddy Kalluru 
904961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
905961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
906961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
907961acdeaSSudarsana Reddy Kalluru 		info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
908961acdeaSSudarsana Reddy Kalluru 		break;
909961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
910961acdeaSSudarsana Reddy Kalluru 		if (edev->rss_params.rss_caps & QED_RSS_IPV4_UDP)
911961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
912961acdeaSSudarsana Reddy Kalluru 		break;
913961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
914961acdeaSSudarsana Reddy Kalluru 		if (edev->rss_params.rss_caps & QED_RSS_IPV6_UDP)
915961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
916961acdeaSSudarsana Reddy Kalluru 		break;
917961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
918961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
919961acdeaSSudarsana Reddy Kalluru 		break;
920961acdeaSSudarsana Reddy Kalluru 	default:
921961acdeaSSudarsana Reddy Kalluru 		info->data = 0;
922961acdeaSSudarsana Reddy Kalluru 		break;
923961acdeaSSudarsana Reddy Kalluru 	}
924961acdeaSSudarsana Reddy Kalluru 
925961acdeaSSudarsana Reddy Kalluru 	return 0;
926961acdeaSSudarsana Reddy Kalluru }
927961acdeaSSudarsana Reddy Kalluru 
928961acdeaSSudarsana Reddy Kalluru static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
929961acdeaSSudarsana Reddy Kalluru 			  u32 *rules __always_unused)
930961acdeaSSudarsana Reddy Kalluru {
931961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
932961acdeaSSudarsana Reddy Kalluru 
933961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
934961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXRINGS:
9359a4d7e86SSudarsana Reddy Kalluru 		info->data = QEDE_RSS_COUNT(edev);
936961acdeaSSudarsana Reddy Kalluru 		return 0;
937961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXFH:
938961acdeaSSudarsana Reddy Kalluru 		return qede_get_rss_flags(edev, info);
939961acdeaSSudarsana Reddy Kalluru 	default:
940961acdeaSSudarsana Reddy Kalluru 		DP_ERR(edev, "Command parameters not supported\n");
941961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
942961acdeaSSudarsana Reddy Kalluru 	}
943961acdeaSSudarsana Reddy Kalluru }
944961acdeaSSudarsana Reddy Kalluru 
945961acdeaSSudarsana Reddy Kalluru static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
946961acdeaSSudarsana Reddy Kalluru {
947961acdeaSSudarsana Reddy Kalluru 	struct qed_update_vport_params vport_update_params;
948961acdeaSSudarsana Reddy Kalluru 	u8 set_caps = 0, clr_caps = 0;
949961acdeaSSudarsana Reddy Kalluru 
950961acdeaSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
951961acdeaSSudarsana Reddy Kalluru 		   "Set rss flags command parameters: flow type = %d, data = %llu\n",
952961acdeaSSudarsana Reddy Kalluru 		   info->flow_type, info->data);
953961acdeaSSudarsana Reddy Kalluru 
954961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
955961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
956961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
957961acdeaSSudarsana Reddy Kalluru 		/* For TCP only 4-tuple hash is supported */
958961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
959961acdeaSSudarsana Reddy Kalluru 				  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
960961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
961961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
962961acdeaSSudarsana Reddy Kalluru 		}
963961acdeaSSudarsana Reddy Kalluru 		return 0;
964961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
965961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
966961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
967961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
968961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV4_UDP;
969961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
970961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
971961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
972961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV4_UDP;
973961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
974961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
975961acdeaSSudarsana Reddy Kalluru 		} else {
976961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
977961acdeaSSudarsana Reddy Kalluru 		}
978961acdeaSSudarsana Reddy Kalluru 		break;
979961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
980961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
981961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
982961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
983961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV6_UDP;
984961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
985961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
986961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
987961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV6_UDP;
988961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
989961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
990961acdeaSSudarsana Reddy Kalluru 		} else {
991961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
992961acdeaSSudarsana Reddy Kalluru 		}
993961acdeaSSudarsana Reddy Kalluru 		break;
994961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
995961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
996961acdeaSSudarsana Reddy Kalluru 		/* For IP only 2-tuple hash is supported */
997961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
998961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
999961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1000961acdeaSSudarsana Reddy Kalluru 		}
1001961acdeaSSudarsana Reddy Kalluru 		return 0;
1002961acdeaSSudarsana Reddy Kalluru 	case SCTP_V4_FLOW:
1003961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V4_FLOW:
1004961acdeaSSudarsana Reddy Kalluru 	case AH_V4_FLOW:
1005961acdeaSSudarsana Reddy Kalluru 	case ESP_V4_FLOW:
1006961acdeaSSudarsana Reddy Kalluru 	case SCTP_V6_FLOW:
1007961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V6_FLOW:
1008961acdeaSSudarsana Reddy Kalluru 	case AH_V6_FLOW:
1009961acdeaSSudarsana Reddy Kalluru 	case ESP_V6_FLOW:
1010961acdeaSSudarsana Reddy Kalluru 	case IP_USER_FLOW:
1011961acdeaSSudarsana Reddy Kalluru 	case ETHER_FLOW:
1012961acdeaSSudarsana Reddy Kalluru 		/* RSS is not supported for these protocols */
1013961acdeaSSudarsana Reddy Kalluru 		if (info->data) {
1014961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1015961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1016961acdeaSSudarsana Reddy Kalluru 		}
1017961acdeaSSudarsana Reddy Kalluru 		return 0;
1018961acdeaSSudarsana Reddy Kalluru 	default:
1019961acdeaSSudarsana Reddy Kalluru 		return -EINVAL;
1020961acdeaSSudarsana Reddy Kalluru 	}
1021961acdeaSSudarsana Reddy Kalluru 
1022961acdeaSSudarsana Reddy Kalluru 	/* No action is needed if there is no change in the rss capability */
1023961acdeaSSudarsana Reddy Kalluru 	if (edev->rss_params.rss_caps == ((edev->rss_params.rss_caps &
1024961acdeaSSudarsana Reddy Kalluru 					   ~clr_caps) | set_caps))
1025961acdeaSSudarsana Reddy Kalluru 		return 0;
1026961acdeaSSudarsana Reddy Kalluru 
1027961acdeaSSudarsana Reddy Kalluru 	/* Update internal configuration */
1028961acdeaSSudarsana Reddy Kalluru 	edev->rss_params.rss_caps = (edev->rss_params.rss_caps & ~clr_caps) |
1029961acdeaSSudarsana Reddy Kalluru 				    set_caps;
1030961acdeaSSudarsana Reddy Kalluru 	edev->rss_params_inited |= QEDE_RSS_CAPS_INITED;
1031961acdeaSSudarsana Reddy Kalluru 
1032961acdeaSSudarsana Reddy Kalluru 	/* Re-configure if possible */
1033961acdeaSSudarsana Reddy Kalluru 	if (netif_running(edev->ndev)) {
1034961acdeaSSudarsana Reddy Kalluru 		memset(&vport_update_params, 0, sizeof(vport_update_params));
1035961acdeaSSudarsana Reddy Kalluru 		vport_update_params.update_rss_flg = 1;
1036961acdeaSSudarsana Reddy Kalluru 		vport_update_params.vport_id = 0;
1037961acdeaSSudarsana Reddy Kalluru 		memcpy(&vport_update_params.rss_params, &edev->rss_params,
1038961acdeaSSudarsana Reddy Kalluru 		       sizeof(vport_update_params.rss_params));
1039961acdeaSSudarsana Reddy Kalluru 		return edev->ops->vport_update(edev->cdev,
1040961acdeaSSudarsana Reddy Kalluru 					       &vport_update_params);
1041961acdeaSSudarsana Reddy Kalluru 	}
1042961acdeaSSudarsana Reddy Kalluru 
1043961acdeaSSudarsana Reddy Kalluru 	return 0;
1044961acdeaSSudarsana Reddy Kalluru }
1045961acdeaSSudarsana Reddy Kalluru 
1046961acdeaSSudarsana Reddy Kalluru static int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
1047961acdeaSSudarsana Reddy Kalluru {
1048961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1049961acdeaSSudarsana Reddy Kalluru 
1050961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
1051961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_SRXFH:
1052961acdeaSSudarsana Reddy Kalluru 		return qede_set_rss_flags(edev, info);
1053961acdeaSSudarsana Reddy Kalluru 	default:
1054961acdeaSSudarsana Reddy Kalluru 		DP_INFO(edev, "Command parameters not supported\n");
1055961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1056961acdeaSSudarsana Reddy Kalluru 	}
1057961acdeaSSudarsana Reddy Kalluru }
1058961acdeaSSudarsana Reddy Kalluru 
1059961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_indir_size(struct net_device *dev)
1060961acdeaSSudarsana Reddy Kalluru {
1061961acdeaSSudarsana Reddy Kalluru 	return QED_RSS_IND_TABLE_SIZE;
1062961acdeaSSudarsana Reddy Kalluru }
1063961acdeaSSudarsana Reddy Kalluru 
1064961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_key_size(struct net_device *dev)
1065961acdeaSSudarsana Reddy Kalluru {
1066961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1067961acdeaSSudarsana Reddy Kalluru 
1068961acdeaSSudarsana Reddy Kalluru 	return sizeof(edev->rss_params.rss_key);
1069961acdeaSSudarsana Reddy Kalluru }
1070961acdeaSSudarsana Reddy Kalluru 
1071961acdeaSSudarsana Reddy Kalluru static int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
1072961acdeaSSudarsana Reddy Kalluru {
1073961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1074961acdeaSSudarsana Reddy Kalluru 	int i;
1075961acdeaSSudarsana Reddy Kalluru 
1076961acdeaSSudarsana Reddy Kalluru 	if (hfunc)
1077961acdeaSSudarsana Reddy Kalluru 		*hfunc = ETH_RSS_HASH_TOP;
1078961acdeaSSudarsana Reddy Kalluru 
1079961acdeaSSudarsana Reddy Kalluru 	if (!indir)
1080961acdeaSSudarsana Reddy Kalluru 		return 0;
1081961acdeaSSudarsana Reddy Kalluru 
1082961acdeaSSudarsana Reddy Kalluru 	for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1083961acdeaSSudarsana Reddy Kalluru 		indir[i] = edev->rss_params.rss_ind_table[i];
1084961acdeaSSudarsana Reddy Kalluru 
1085961acdeaSSudarsana Reddy Kalluru 	if (key)
1086961acdeaSSudarsana Reddy Kalluru 		memcpy(key, edev->rss_params.rss_key,
1087961acdeaSSudarsana Reddy Kalluru 		       qede_get_rxfh_key_size(dev));
1088961acdeaSSudarsana Reddy Kalluru 
1089961acdeaSSudarsana Reddy Kalluru 	return 0;
1090961acdeaSSudarsana Reddy Kalluru }
1091961acdeaSSudarsana Reddy Kalluru 
1092961acdeaSSudarsana Reddy Kalluru static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
1093961acdeaSSudarsana Reddy Kalluru 			 const u8 *key, const u8 hfunc)
1094961acdeaSSudarsana Reddy Kalluru {
1095961acdeaSSudarsana Reddy Kalluru 	struct qed_update_vport_params vport_update_params;
1096961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1097961acdeaSSudarsana Reddy Kalluru 	int i;
1098961acdeaSSudarsana Reddy Kalluru 
1099ba300ce3SSudarsana Reddy Kalluru 	if (edev->dev_info.common.num_hwfns > 1) {
1100ba300ce3SSudarsana Reddy Kalluru 		DP_INFO(edev,
1101ba300ce3SSudarsana Reddy Kalluru 			"RSS configuration is not supported for 100G devices\n");
1102ba300ce3SSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1103ba300ce3SSudarsana Reddy Kalluru 	}
1104ba300ce3SSudarsana Reddy Kalluru 
1105961acdeaSSudarsana Reddy Kalluru 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
1106961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1107961acdeaSSudarsana Reddy Kalluru 
1108961acdeaSSudarsana Reddy Kalluru 	if (!indir && !key)
1109961acdeaSSudarsana Reddy Kalluru 		return 0;
1110961acdeaSSudarsana Reddy Kalluru 
1111961acdeaSSudarsana Reddy Kalluru 	if (indir) {
1112961acdeaSSudarsana Reddy Kalluru 		for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1113961acdeaSSudarsana Reddy Kalluru 			edev->rss_params.rss_ind_table[i] = indir[i];
1114961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_INDIR_INITED;
1115961acdeaSSudarsana Reddy Kalluru 	}
1116961acdeaSSudarsana Reddy Kalluru 
1117961acdeaSSudarsana Reddy Kalluru 	if (key) {
1118961acdeaSSudarsana Reddy Kalluru 		memcpy(&edev->rss_params.rss_key, key,
1119961acdeaSSudarsana Reddy Kalluru 		       qede_get_rxfh_key_size(dev));
1120961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_KEY_INITED;
1121961acdeaSSudarsana Reddy Kalluru 	}
1122961acdeaSSudarsana Reddy Kalluru 
1123961acdeaSSudarsana Reddy Kalluru 	if (netif_running(edev->ndev)) {
1124961acdeaSSudarsana Reddy Kalluru 		memset(&vport_update_params, 0, sizeof(vport_update_params));
1125961acdeaSSudarsana Reddy Kalluru 		vport_update_params.update_rss_flg = 1;
1126961acdeaSSudarsana Reddy Kalluru 		vport_update_params.vport_id = 0;
1127961acdeaSSudarsana Reddy Kalluru 		memcpy(&vport_update_params.rss_params, &edev->rss_params,
1128961acdeaSSudarsana Reddy Kalluru 		       sizeof(vport_update_params.rss_params));
1129961acdeaSSudarsana Reddy Kalluru 		return edev->ops->vport_update(edev->cdev,
1130961acdeaSSudarsana Reddy Kalluru 					       &vport_update_params);
1131961acdeaSSudarsana Reddy Kalluru 	}
1132961acdeaSSudarsana Reddy Kalluru 
1133961acdeaSSudarsana Reddy Kalluru 	return 0;
1134961acdeaSSudarsana Reddy Kalluru }
1135961acdeaSSudarsana Reddy Kalluru 
113616f46bf0SSudarsana Reddy Kalluru /* This function enables the interrupt generation and the NAPI on the device */
113716f46bf0SSudarsana Reddy Kalluru static void qede_netif_start(struct qede_dev *edev)
113816f46bf0SSudarsana Reddy Kalluru {
113916f46bf0SSudarsana Reddy Kalluru 	int i;
114016f46bf0SSudarsana Reddy Kalluru 
114116f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev))
114216f46bf0SSudarsana Reddy Kalluru 		return;
114316f46bf0SSudarsana Reddy Kalluru 
11449a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
114516f46bf0SSudarsana Reddy Kalluru 		/* Update and reenable interrupts */
114616f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_ENABLE, 1);
114716f46bf0SSudarsana Reddy Kalluru 		napi_enable(&edev->fp_array[i].napi);
114816f46bf0SSudarsana Reddy Kalluru 	}
114916f46bf0SSudarsana Reddy Kalluru }
115016f46bf0SSudarsana Reddy Kalluru 
115116f46bf0SSudarsana Reddy Kalluru /* This function disables the NAPI and the interrupt generation on the device */
115216f46bf0SSudarsana Reddy Kalluru static void qede_netif_stop(struct qede_dev *edev)
115316f46bf0SSudarsana Reddy Kalluru {
115416f46bf0SSudarsana Reddy Kalluru 	int i;
115516f46bf0SSudarsana Reddy Kalluru 
11569a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
115716f46bf0SSudarsana Reddy Kalluru 		napi_disable(&edev->fp_array[i].napi);
115816f46bf0SSudarsana Reddy Kalluru 		/* Disable interrupts */
115916f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_DISABLE, 0);
116016f46bf0SSudarsana Reddy Kalluru 	}
116116f46bf0SSudarsana Reddy Kalluru }
116216f46bf0SSudarsana Reddy Kalluru 
116316f46bf0SSudarsana Reddy Kalluru static int qede_selftest_transmit_traffic(struct qede_dev *edev,
116416f46bf0SSudarsana Reddy Kalluru 					  struct sk_buff *skb)
116516f46bf0SSudarsana Reddy Kalluru {
11669a4d7e86SSudarsana Reddy Kalluru 	struct qede_tx_queue *txq = NULL;
116716f46bf0SSudarsana Reddy Kalluru 	struct eth_tx_1st_bd *first_bd;
116816f46bf0SSudarsana Reddy Kalluru 	dma_addr_t mapping;
116916f46bf0SSudarsana Reddy Kalluru 	int i, idx, val;
117016f46bf0SSudarsana Reddy Kalluru 
11719a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
11729a4d7e86SSudarsana Reddy Kalluru 		if (edev->fp_array[i].type & QEDE_FASTPATH_TX) {
117380439a17SMintz, Yuval 			txq = edev->fp_array[i].txq;
11749a4d7e86SSudarsana Reddy Kalluru 			break;
11759a4d7e86SSudarsana Reddy Kalluru 		}
11769a4d7e86SSudarsana Reddy Kalluru 	}
11779a4d7e86SSudarsana Reddy Kalluru 
11789a4d7e86SSudarsana Reddy Kalluru 	if (!txq) {
11799a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx path is not available\n");
11809a4d7e86SSudarsana Reddy Kalluru 		return -1;
11819a4d7e86SSudarsana Reddy Kalluru 	}
11829a4d7e86SSudarsana Reddy Kalluru 
118316f46bf0SSudarsana Reddy Kalluru 	/* Fill the entry in the SW ring and the BDs in the FW ring */
118416f46bf0SSudarsana Reddy Kalluru 	idx = txq->sw_tx_prod & NUM_TX_BDS_MAX;
118516f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_ring[idx].skb = skb;
118616f46bf0SSudarsana Reddy Kalluru 	first_bd = qed_chain_produce(&txq->tx_pbl);
118716f46bf0SSudarsana Reddy Kalluru 	memset(first_bd, 0, sizeof(*first_bd));
118816f46bf0SSudarsana Reddy Kalluru 	val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT;
118916f46bf0SSudarsana Reddy Kalluru 	first_bd->data.bd_flags.bitfields = val;
1190351a4dedSYuval Mintz 	val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK;
1191351a4dedSYuval Mintz 	first_bd->data.bitfields |= (val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT);
119216f46bf0SSudarsana Reddy Kalluru 
119316f46bf0SSudarsana Reddy Kalluru 	/* Map skb linear data for DMA and set in the first BD */
119416f46bf0SSudarsana Reddy Kalluru 	mapping = dma_map_single(&edev->pdev->dev, skb->data,
119516f46bf0SSudarsana Reddy Kalluru 				 skb_headlen(skb), DMA_TO_DEVICE);
119616f46bf0SSudarsana Reddy Kalluru 	if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) {
119716f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "SKB mapping failed\n");
119816f46bf0SSudarsana Reddy Kalluru 		return -ENOMEM;
119916f46bf0SSudarsana Reddy Kalluru 	}
120016f46bf0SSudarsana Reddy Kalluru 	BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb));
120116f46bf0SSudarsana Reddy Kalluru 
120216f46bf0SSudarsana Reddy Kalluru 	/* update the first BD with the actual num BDs */
120316f46bf0SSudarsana Reddy Kalluru 	first_bd->data.nbds = 1;
120416f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_prod++;
120516f46bf0SSudarsana Reddy Kalluru 	/* 'next page' entries are counted in the producer value */
120616f46bf0SSudarsana Reddy Kalluru 	val = cpu_to_le16(qed_chain_get_prod_idx(&txq->tx_pbl));
120716f46bf0SSudarsana Reddy Kalluru 	txq->tx_db.data.bd_prod = val;
120816f46bf0SSudarsana Reddy Kalluru 
120916f46bf0SSudarsana Reddy Kalluru 	/* wmb makes sure that the BDs data is updated before updating the
121016f46bf0SSudarsana Reddy Kalluru 	 * producer, otherwise FW may read old data from the BDs.
121116f46bf0SSudarsana Reddy Kalluru 	 */
121216f46bf0SSudarsana Reddy Kalluru 	wmb();
121316f46bf0SSudarsana Reddy Kalluru 	barrier();
121416f46bf0SSudarsana Reddy Kalluru 	writel(txq->tx_db.raw, txq->doorbell_addr);
121516f46bf0SSudarsana Reddy Kalluru 
121616f46bf0SSudarsana Reddy Kalluru 	/* mmiowb is needed to synchronize doorbell writes from more than one
121716f46bf0SSudarsana Reddy Kalluru 	 * processor. It guarantees that the write arrives to the device before
121816f46bf0SSudarsana Reddy Kalluru 	 * the queue lock is released and another start_xmit is called (possibly
121916f46bf0SSudarsana Reddy Kalluru 	 * on another CPU). Without this barrier, the next doorbell can bypass
122016f46bf0SSudarsana Reddy Kalluru 	 * this doorbell. This is applicable to IA64/Altix systems.
122116f46bf0SSudarsana Reddy Kalluru 	 */
122216f46bf0SSudarsana Reddy Kalluru 	mmiowb();
122316f46bf0SSudarsana Reddy Kalluru 
122416f46bf0SSudarsana Reddy Kalluru 	for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
122516f46bf0SSudarsana Reddy Kalluru 		if (qede_txq_has_work(txq))
122616f46bf0SSudarsana Reddy Kalluru 			break;
122716f46bf0SSudarsana Reddy Kalluru 		usleep_range(100, 200);
122816f46bf0SSudarsana Reddy Kalluru 	}
122916f46bf0SSudarsana Reddy Kalluru 
123016f46bf0SSudarsana Reddy Kalluru 	if (!qede_txq_has_work(txq)) {
123116f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx completion didn't happen\n");
123216f46bf0SSudarsana Reddy Kalluru 		return -1;
123316f46bf0SSudarsana Reddy Kalluru 	}
123416f46bf0SSudarsana Reddy Kalluru 
123516f46bf0SSudarsana Reddy Kalluru 	first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl);
1236fabd545cSManish Chopra 	dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
123716f46bf0SSudarsana Reddy Kalluru 			 BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE);
123816f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_cons++;
123916f46bf0SSudarsana Reddy Kalluru 	txq->sw_tx_ring[idx].skb = NULL;
124016f46bf0SSudarsana Reddy Kalluru 
124116f46bf0SSudarsana Reddy Kalluru 	return 0;
124216f46bf0SSudarsana Reddy Kalluru }
124316f46bf0SSudarsana Reddy Kalluru 
124416f46bf0SSudarsana Reddy Kalluru static int qede_selftest_receive_traffic(struct qede_dev *edev)
124516f46bf0SSudarsana Reddy Kalluru {
124616f46bf0SSudarsana Reddy Kalluru 	u16 hw_comp_cons, sw_comp_cons, sw_rx_index, len;
124716f46bf0SSudarsana Reddy Kalluru 	struct eth_fast_path_rx_reg_cqe *fp_cqe;
12489a4d7e86SSudarsana Reddy Kalluru 	struct qede_rx_queue *rxq = NULL;
124916f46bf0SSudarsana Reddy Kalluru 	struct sw_rx_data *sw_rx_data;
125016f46bf0SSudarsana Reddy Kalluru 	union eth_rx_cqe *cqe;
1251837d4eb6SSudarsana Reddy Kalluru 	int i, rc = 0;
125216f46bf0SSudarsana Reddy Kalluru 	u8 *data_ptr;
125316f46bf0SSudarsana Reddy Kalluru 
12549a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
12559a4d7e86SSudarsana Reddy Kalluru 		if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
12569a4d7e86SSudarsana Reddy Kalluru 			rxq = edev->fp_array[i].rxq;
12579a4d7e86SSudarsana Reddy Kalluru 			break;
12589a4d7e86SSudarsana Reddy Kalluru 		}
12599a4d7e86SSudarsana Reddy Kalluru 	}
12609a4d7e86SSudarsana Reddy Kalluru 
12619a4d7e86SSudarsana Reddy Kalluru 	if (!rxq) {
12629a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Rx path is not available\n");
12639a4d7e86SSudarsana Reddy Kalluru 		return -1;
12649a4d7e86SSudarsana Reddy Kalluru 	}
12659a4d7e86SSudarsana Reddy Kalluru 
126616f46bf0SSudarsana Reddy Kalluru 	/* The packet is expected to receive on rx-queue 0 even though RSS is
126716f46bf0SSudarsana Reddy Kalluru 	 * enabled. This is because the queue 0 is configured as the default
126816f46bf0SSudarsana Reddy Kalluru 	 * queue and that the loopback traffic is not IP.
126916f46bf0SSudarsana Reddy Kalluru 	 */
127016f46bf0SSudarsana Reddy Kalluru 	for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
127116f46bf0SSudarsana Reddy Kalluru 		if (!qede_has_rx_work(rxq)) {
1272837d4eb6SSudarsana Reddy Kalluru 			usleep_range(100, 200);
1273837d4eb6SSudarsana Reddy Kalluru 			continue;
127416f46bf0SSudarsana Reddy Kalluru 		}
127516f46bf0SSudarsana Reddy Kalluru 
127616f46bf0SSudarsana Reddy Kalluru 		hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr);
127716f46bf0SSudarsana Reddy Kalluru 		sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
127816f46bf0SSudarsana Reddy Kalluru 
1279837d4eb6SSudarsana Reddy Kalluru 		/* Memory barrier to prevent the CPU from doing speculative
1280837d4eb6SSudarsana Reddy Kalluru 		 * reads of CQE/BD before reading hw_comp_cons. If the CQE is
1281837d4eb6SSudarsana Reddy Kalluru 		 * read before it is written by FW, then FW writes CQE and SB,
1282837d4eb6SSudarsana Reddy Kalluru 		 * and then the CPU reads the hw_comp_cons, it will use an old
1283837d4eb6SSudarsana Reddy Kalluru 		 * CQE.
128416f46bf0SSudarsana Reddy Kalluru 		 */
128516f46bf0SSudarsana Reddy Kalluru 		rmb();
128616f46bf0SSudarsana Reddy Kalluru 
128716f46bf0SSudarsana Reddy Kalluru 		/* Get the CQE from the completion ring */
128816f46bf0SSudarsana Reddy Kalluru 		cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring);
128916f46bf0SSudarsana Reddy Kalluru 
129016f46bf0SSudarsana Reddy Kalluru 		/* Get the data from the SW ring */
129116f46bf0SSudarsana Reddy Kalluru 		sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
129216f46bf0SSudarsana Reddy Kalluru 		sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
129316f46bf0SSudarsana Reddy Kalluru 		fp_cqe = &cqe->fast_path_regular;
129416f46bf0SSudarsana Reddy Kalluru 		len =  le16_to_cpu(fp_cqe->len_on_first_bd);
129516f46bf0SSudarsana Reddy Kalluru 		data_ptr = (u8 *)(page_address(sw_rx_data->data) +
1296837d4eb6SSudarsana Reddy Kalluru 				  fp_cqe->placement_offset +
1297837d4eb6SSudarsana Reddy Kalluru 				  sw_rx_data->page_offset);
1298837d4eb6SSudarsana Reddy Kalluru 		if (ether_addr_equal(data_ptr,  edev->ndev->dev_addr) &&
1299837d4eb6SSudarsana Reddy Kalluru 		    ether_addr_equal(data_ptr + ETH_ALEN,
1300837d4eb6SSudarsana Reddy Kalluru 				     edev->ndev->dev_addr)) {
130116f46bf0SSudarsana Reddy Kalluru 			for (i = ETH_HLEN; i < len; i++)
130216f46bf0SSudarsana Reddy Kalluru 				if (data_ptr[i] != (unsigned char)(i & 0xff)) {
1303837d4eb6SSudarsana Reddy Kalluru 					rc = -1;
1304837d4eb6SSudarsana Reddy Kalluru 					break;
130516f46bf0SSudarsana Reddy Kalluru 				}
130616f46bf0SSudarsana Reddy Kalluru 
130716f46bf0SSudarsana Reddy Kalluru 			qede_recycle_rx_bd_ring(rxq, edev, 1);
1308837d4eb6SSudarsana Reddy Kalluru 			qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1309837d4eb6SSudarsana Reddy Kalluru 			break;
1310837d4eb6SSudarsana Reddy Kalluru 		}
131116f46bf0SSudarsana Reddy Kalluru 
1312837d4eb6SSudarsana Reddy Kalluru 		DP_INFO(edev, "Not the transmitted packet\n");
1313837d4eb6SSudarsana Reddy Kalluru 		qede_recycle_rx_bd_ring(rxq, edev, 1);
1314837d4eb6SSudarsana Reddy Kalluru 		qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1315837d4eb6SSudarsana Reddy Kalluru 	}
1316837d4eb6SSudarsana Reddy Kalluru 
1317837d4eb6SSudarsana Reddy Kalluru 	if (i == QEDE_SELFTEST_POLL_COUNT) {
1318837d4eb6SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Failed to receive the traffic\n");
1319837d4eb6SSudarsana Reddy Kalluru 		return -1;
1320837d4eb6SSudarsana Reddy Kalluru 	}
1321837d4eb6SSudarsana Reddy Kalluru 
1322837d4eb6SSudarsana Reddy Kalluru 	qede_update_rx_prod(edev, rxq);
1323837d4eb6SSudarsana Reddy Kalluru 
1324837d4eb6SSudarsana Reddy Kalluru 	return rc;
132516f46bf0SSudarsana Reddy Kalluru }
132616f46bf0SSudarsana Reddy Kalluru 
132716f46bf0SSudarsana Reddy Kalluru static int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode)
132816f46bf0SSudarsana Reddy Kalluru {
132916f46bf0SSudarsana Reddy Kalluru 	struct qed_link_params link_params;
133016f46bf0SSudarsana Reddy Kalluru 	struct sk_buff *skb = NULL;
133116f46bf0SSudarsana Reddy Kalluru 	int rc = 0, i;
133216f46bf0SSudarsana Reddy Kalluru 	u32 pkt_size;
133316f46bf0SSudarsana Reddy Kalluru 	u8 *packet;
133416f46bf0SSudarsana Reddy Kalluru 
133516f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev)) {
133616f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Interface is down\n");
133716f46bf0SSudarsana Reddy Kalluru 		return -EINVAL;
133816f46bf0SSudarsana Reddy Kalluru 	}
133916f46bf0SSudarsana Reddy Kalluru 
134016f46bf0SSudarsana Reddy Kalluru 	qede_netif_stop(edev);
134116f46bf0SSudarsana Reddy Kalluru 
134216f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Loopback mode */
134316f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
134416f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
134516f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
134616f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = loopback_mode;
134716f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
134816f46bf0SSudarsana Reddy Kalluru 
134916f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
135016f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
135116f46bf0SSudarsana Reddy Kalluru 
135216f46bf0SSudarsana Reddy Kalluru 	/* prepare the loopback packet */
135316f46bf0SSudarsana Reddy Kalluru 	pkt_size = edev->ndev->mtu + ETH_HLEN;
135416f46bf0SSudarsana Reddy Kalluru 
135516f46bf0SSudarsana Reddy Kalluru 	skb = netdev_alloc_skb(edev->ndev, pkt_size);
135616f46bf0SSudarsana Reddy Kalluru 	if (!skb) {
135716f46bf0SSudarsana Reddy Kalluru 		DP_INFO(edev, "Can't allocate skb\n");
135816f46bf0SSudarsana Reddy Kalluru 		rc = -ENOMEM;
135916f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
136016f46bf0SSudarsana Reddy Kalluru 	}
136116f46bf0SSudarsana Reddy Kalluru 	packet = skb_put(skb, pkt_size);
136216f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet, edev->ndev->dev_addr);
136316f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet + ETH_ALEN, edev->ndev->dev_addr);
136416f46bf0SSudarsana Reddy Kalluru 	memset(packet + (2 * ETH_ALEN), 0x77, (ETH_HLEN - (2 * ETH_ALEN)));
136516f46bf0SSudarsana Reddy Kalluru 	for (i = ETH_HLEN; i < pkt_size; i++)
136616f46bf0SSudarsana Reddy Kalluru 		packet[i] = (unsigned char)(i & 0xff);
136716f46bf0SSudarsana Reddy Kalluru 
136816f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_transmit_traffic(edev, skb);
136916f46bf0SSudarsana Reddy Kalluru 	if (rc)
137016f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
137116f46bf0SSudarsana Reddy Kalluru 
137216f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_receive_traffic(edev);
137316f46bf0SSudarsana Reddy Kalluru 	if (rc)
137416f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
137516f46bf0SSudarsana Reddy Kalluru 
137616f46bf0SSudarsana Reddy Kalluru 	DP_VERBOSE(edev, NETIF_MSG_RX_STATUS, "Loopback test successful\n");
137716f46bf0SSudarsana Reddy Kalluru 
137816f46bf0SSudarsana Reddy Kalluru test_loopback_exit:
137916f46bf0SSudarsana Reddy Kalluru 	dev_kfree_skb(skb);
138016f46bf0SSudarsana Reddy Kalluru 
138116f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Normal mode */
138216f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
138316f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
138416f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
138516f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = QED_LINK_LOOPBACK_NONE;
138616f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
138716f46bf0SSudarsana Reddy Kalluru 
138816f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
138916f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
139016f46bf0SSudarsana Reddy Kalluru 
139116f46bf0SSudarsana Reddy Kalluru 	qede_netif_start(edev);
139216f46bf0SSudarsana Reddy Kalluru 
139316f46bf0SSudarsana Reddy Kalluru 	return rc;
139416f46bf0SSudarsana Reddy Kalluru }
139516f46bf0SSudarsana Reddy Kalluru 
13963044a02eSSudarsana Reddy Kalluru static void qede_self_test(struct net_device *dev,
13973044a02eSSudarsana Reddy Kalluru 			   struct ethtool_test *etest, u64 *buf)
13983044a02eSSudarsana Reddy Kalluru {
13993044a02eSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
14003044a02eSSudarsana Reddy Kalluru 
14013044a02eSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
14023044a02eSSudarsana Reddy Kalluru 		   "Self-test command parameters: offline = %d, external_lb = %d\n",
14033044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_OFFLINE),
14043044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_EXTERNAL_LB) >> 2);
14053044a02eSSudarsana Reddy Kalluru 
14063044a02eSSudarsana Reddy Kalluru 	memset(buf, 0, sizeof(u64) * QEDE_ETHTOOL_TEST_MAX);
14073044a02eSSudarsana Reddy Kalluru 
140816f46bf0SSudarsana Reddy Kalluru 	if (etest->flags & ETH_TEST_FL_OFFLINE) {
140916f46bf0SSudarsana Reddy Kalluru 		if (qede_selftest_run_loopback(edev,
141016f46bf0SSudarsana Reddy Kalluru 					       QED_LINK_LOOPBACK_INT_PHY)) {
141116f46bf0SSudarsana Reddy Kalluru 			buf[QEDE_ETHTOOL_INT_LOOPBACK] = 1;
141216f46bf0SSudarsana Reddy Kalluru 			etest->flags |= ETH_TEST_FL_FAILED;
141316f46bf0SSudarsana Reddy Kalluru 		}
141416f46bf0SSudarsana Reddy Kalluru 	}
141516f46bf0SSudarsana Reddy Kalluru 
14163044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_interrupt(edev->cdev)) {
14173044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_INTERRUPT_TEST] = 1;
14183044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14193044a02eSSudarsana Reddy Kalluru 	}
14203044a02eSSudarsana Reddy Kalluru 
14213044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_memory(edev->cdev)) {
14223044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_MEMORY_TEST] = 1;
14233044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14243044a02eSSudarsana Reddy Kalluru 	}
14253044a02eSSudarsana Reddy Kalluru 
14263044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_register(edev->cdev)) {
14273044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_REGISTER_TEST] = 1;
14283044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14293044a02eSSudarsana Reddy Kalluru 	}
14303044a02eSSudarsana Reddy Kalluru 
14313044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_clock(edev->cdev)) {
14323044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_CLOCK_TEST] = 1;
14333044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
14343044a02eSSudarsana Reddy Kalluru 	}
14357a4b21b7SMintz, Yuval 
14367a4b21b7SMintz, Yuval 	if (edev->ops->common->selftest->selftest_nvram(edev->cdev)) {
14377a4b21b7SMintz, Yuval 		buf[QEDE_ETHTOOL_NVRAM_TEST] = 1;
14387a4b21b7SMintz, Yuval 		etest->flags |= ETH_TEST_FL_FAILED;
14397a4b21b7SMintz, Yuval 	}
14403044a02eSSudarsana Reddy Kalluru }
14413044a02eSSudarsana Reddy Kalluru 
14423d789994SManish Chopra static int qede_set_tunable(struct net_device *dev,
14433d789994SManish Chopra 			    const struct ethtool_tunable *tuna,
14443d789994SManish Chopra 			    const void *data)
14453d789994SManish Chopra {
14463d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
14473d789994SManish Chopra 	u32 val;
14483d789994SManish Chopra 
14493d789994SManish Chopra 	switch (tuna->id) {
14503d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
14513d789994SManish Chopra 		val = *(u32 *)data;
14523d789994SManish Chopra 		if (val < QEDE_MIN_PKT_LEN || val > QEDE_RX_HDR_SIZE) {
14533d789994SManish Chopra 			DP_VERBOSE(edev, QED_MSG_DEBUG,
14543d789994SManish Chopra 				   "Invalid rx copy break value, range is [%u, %u]",
14553d789994SManish Chopra 				   QEDE_MIN_PKT_LEN, QEDE_RX_HDR_SIZE);
14563d789994SManish Chopra 			return -EINVAL;
14573d789994SManish Chopra 		}
14583d789994SManish Chopra 
14593d789994SManish Chopra 		edev->rx_copybreak = *(u32 *)data;
14603d789994SManish Chopra 		break;
14613d789994SManish Chopra 	default:
14623d789994SManish Chopra 		return -EOPNOTSUPP;
14633d789994SManish Chopra 	}
14643d789994SManish Chopra 
14653d789994SManish Chopra 	return 0;
14663d789994SManish Chopra }
14673d789994SManish Chopra 
14683d789994SManish Chopra static int qede_get_tunable(struct net_device *dev,
14693d789994SManish Chopra 			    const struct ethtool_tunable *tuna, void *data)
14703d789994SManish Chopra {
14713d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
14723d789994SManish Chopra 
14733d789994SManish Chopra 	switch (tuna->id) {
14743d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
14753d789994SManish Chopra 		*(u32 *)data = edev->rx_copybreak;
14763d789994SManish Chopra 		break;
14773d789994SManish Chopra 	default:
14783d789994SManish Chopra 		return -EOPNOTSUPP;
14793d789994SManish Chopra 	}
14803d789994SManish Chopra 
14813d789994SManish Chopra 	return 0;
14823d789994SManish Chopra }
14833d789994SManish Chopra 
1484133fac0eSSudarsana Kalluru static const struct ethtool_ops qede_ethtool_ops = {
1485054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1486054c67d1SSudarsana Reddy Kalluru 	.set_link_ksettings = qede_set_link_ksettings,
1487133fac0eSSudarsana Kalluru 	.get_drvinfo = qede_get_drvinfo,
1488e0971c83STomer Tayar 	.get_regs_len = qede_get_regs_len,
1489e0971c83STomer Tayar 	.get_regs = qede_get_regs,
149014d39648SMintz, Yuval 	.get_wol = qede_get_wol,
149114d39648SMintz, Yuval 	.set_wol = qede_set_wol,
1492133fac0eSSudarsana Kalluru 	.get_msglevel = qede_get_msglevel,
1493133fac0eSSudarsana Kalluru 	.set_msglevel = qede_set_msglevel,
149432a7a570SSudarsana Kalluru 	.nway_reset = qede_nway_reset,
1495133fac0eSSudarsana Kalluru 	.get_link = qede_get_link,
1496d552fa84SSudarsana Reddy Kalluru 	.get_coalesce = qede_get_coalesce,
1497d552fa84SSudarsana Reddy Kalluru 	.set_coalesce = qede_set_coalesce,
149801ef7e05SSudarsana Kalluru 	.get_ringparam = qede_get_ringparam,
149901ef7e05SSudarsana Kalluru 	.set_ringparam = qede_set_ringparam,
15000f7db144SSudarsana Kalluru 	.get_pauseparam = qede_get_pauseparam,
15010f7db144SSudarsana Kalluru 	.set_pauseparam = qede_set_pauseparam,
1502133fac0eSSudarsana Kalluru 	.get_strings = qede_get_strings,
15033d971cbdSSudarsana Kalluru 	.set_phys_id = qede_set_phys_id,
1504133fac0eSSudarsana Kalluru 	.get_ethtool_stats = qede_get_ethtool_stats,
1505f3e72109SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1506133fac0eSSudarsana Kalluru 	.get_sset_count = qede_get_sset_count,
1507961acdeaSSudarsana Reddy Kalluru 	.get_rxnfc = qede_get_rxnfc,
1508961acdeaSSudarsana Reddy Kalluru 	.set_rxnfc = qede_set_rxnfc,
1509961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1510961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1511961acdeaSSudarsana Reddy Kalluru 	.get_rxfh = qede_get_rxfh,
1512961acdeaSSudarsana Reddy Kalluru 	.set_rxfh = qede_set_rxfh,
15138edf049dSSudarsana Kalluru 	.get_channels = qede_get_channels,
15148edf049dSSudarsana Kalluru 	.set_channels = qede_set_channels,
15153044a02eSSudarsana Reddy Kalluru 	.self_test = qede_self_test,
15163d789994SManish Chopra 	.get_tunable = qede_get_tunable,
15173d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1518133fac0eSSudarsana Kalluru };
1519133fac0eSSudarsana Kalluru 
1520fefb0202SYuval Mintz static const struct ethtool_ops qede_vf_ethtool_ops = {
1521054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1522fefb0202SYuval Mintz 	.get_drvinfo = qede_get_drvinfo,
1523fefb0202SYuval Mintz 	.get_msglevel = qede_get_msglevel,
1524fefb0202SYuval Mintz 	.set_msglevel = qede_set_msglevel,
1525fefb0202SYuval Mintz 	.get_link = qede_get_link,
1526fefb0202SYuval Mintz 	.get_ringparam = qede_get_ringparam,
1527fefb0202SYuval Mintz 	.set_ringparam = qede_set_ringparam,
1528fefb0202SYuval Mintz 	.get_strings = qede_get_strings,
1529fefb0202SYuval Mintz 	.get_ethtool_stats = qede_get_ethtool_stats,
1530fefb0202SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1531fefb0202SYuval Mintz 	.get_sset_count = qede_get_sset_count,
1532fefb0202SYuval Mintz 	.get_rxnfc = qede_get_rxnfc,
1533fefb0202SYuval Mintz 	.set_rxnfc = qede_set_rxnfc,
1534fefb0202SYuval Mintz 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1535fefb0202SYuval Mintz 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1536fefb0202SYuval Mintz 	.get_rxfh = qede_get_rxfh,
1537fefb0202SYuval Mintz 	.set_rxfh = qede_set_rxfh,
1538fefb0202SYuval Mintz 	.get_channels = qede_get_channels,
1539fefb0202SYuval Mintz 	.set_channels = qede_set_channels,
15403d789994SManish Chopra 	.get_tunable = qede_get_tunable,
15413d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1542fefb0202SYuval Mintz };
1543fefb0202SYuval Mintz 
1544133fac0eSSudarsana Kalluru void qede_set_ethtool_ops(struct net_device *dev)
1545133fac0eSSudarsana Kalluru {
1546fefb0202SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
1547fefb0202SYuval Mintz 
1548fefb0202SYuval Mintz 	if (IS_VF(edev))
1549fefb0202SYuval Mintz 		dev->ethtool_ops = &qede_vf_ethtool_ops;
1550fefb0202SYuval Mintz 	else
1551133fac0eSSudarsana Kalluru 		dev->ethtool_ops = &qede_ethtool_ops;
1552133fac0eSSudarsana Kalluru }
1553